dynamics_crm 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/dynamics_crm/client.rb +82 -24
- data/lib/dynamics_crm/version.rb +1 -1
- data/lib/dynamics_crm/xml/message_builder.rb +101 -3
- data/spec/fixtures/request_security_token_response_onpremise.xml +78 -0
- data/spec/lib/client_spec.rb +41 -19
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbd8933df47587a12b12a2115afbb57d2e8d2b1c
|
4
|
+
data.tar.gz: 8343d6d884713b0956e71a9ffcde12c6364302b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dec2cf3cd88e6bfbba5ec88fb0d7cf237539de43c2b1102ed3e736df9e20d41dab7713e519ffba54299e8e2c2cb3bd259794f49d37c0f5fbf62d8681cb86f5d0
|
7
|
+
data.tar.gz: 9cc80f8452b8dd72280ef9ac1ca5900bd96f77676ae2f905923e1ea18cc04fed3c338a4a4ce8bf16b7c3e520cf66af7e60d67a0f43733ce1b2fd1265c41e6690
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.5.0 (December 19, 2014)
|
2
|
+
|
3
|
+
* Adds On-Premise Authenticate support with specified hostname. PR #18
|
4
|
+
|
5
|
+
## 0.4.1 (November 23)
|
6
|
+
|
7
|
+
* Switch to TLS. SSLv3 has been disabled. PR #19
|
8
|
+
|
1
9
|
## 0.4.0 (October 11, 2014)
|
2
10
|
|
3
11
|
* Adds FetchXml module (Builder, Entity, LinkEntity) for building Xml document. (New dependency on builder)
|
data/lib/dynamics_crm/client.rb
CHANGED
@@ -8,6 +8,9 @@
|
|
8
8
|
# https://community.dynamics.com/crm/b/crmgirishraja/archive/2012/09/04/authentication-with-dynamics-crm-online-on-ocp-office-365.aspx
|
9
9
|
|
10
10
|
require 'forwardable'
|
11
|
+
require 'digest/sha1'
|
12
|
+
require 'openssl'
|
13
|
+
require 'open-uri'
|
11
14
|
|
12
15
|
module DynamicsCRM
|
13
16
|
|
@@ -16,26 +19,28 @@ module DynamicsCRM
|
|
16
19
|
include XML::MessageBuilder
|
17
20
|
|
18
21
|
attr_accessor :logger, :caller_id
|
22
|
+
attr_reader :hostname, :region, :organization_endpoint, :login_url
|
23
|
+
|
24
|
+
OCP_LOGIN_URL = 'https://login.microsoftonline.com/RST2.srf'
|
19
25
|
|
20
26
|
# Initializes Client instance.
|
21
27
|
# Requires: organization_name
|
22
28
|
# Optional: hostname
|
23
29
|
def initialize(config={organization_name: nil, hostname: nil, caller_id: nil, login_url: nil, region: nil})
|
24
|
-
raise RuntimeError.new("organization_name is required") if config[:organization_name].nil?
|
30
|
+
raise RuntimeError.new("organization_name or hostname is required") if config[:organization_name].nil? && config[:hostname].nil?
|
25
31
|
|
26
32
|
@organization_name = config[:organization_name]
|
27
33
|
@hostname = config[:hostname] || "#{@organization_name}.api.crm.dynamics.com"
|
28
34
|
@organization_endpoint = "https://#{@hostname}/XRMServices/2011/Organization.svc"
|
29
35
|
@caller_id = config[:caller_id]
|
30
36
|
|
31
|
-
|
32
37
|
# The Login URL and Region are located in the client's Organization WSDL.
|
33
38
|
# https://tinderboxdev.api.crm.dynamics.com/XRMServices/2011/Organization.svc?wsdl=wsdl0
|
34
39
|
#
|
35
40
|
# Login URL: Policy -> Issuer -> Address
|
36
41
|
# Region: SecureTokenService -> AppliesTo
|
37
|
-
@login_url = config[:login_url]
|
38
|
-
@region = config[:region] ||
|
42
|
+
@login_url = config[:login_url]
|
43
|
+
@region = config[:region] || determine_region
|
39
44
|
end
|
40
45
|
|
41
46
|
# Public: Authenticate User
|
@@ -51,24 +56,47 @@ module DynamicsCRM
|
|
51
56
|
@username = username
|
52
57
|
@password = password
|
53
58
|
|
54
|
-
|
59
|
+
auth_request = if on_premise?
|
60
|
+
build_on_premise_request(username, password, region, login_url)
|
61
|
+
else
|
62
|
+
build_ocp_request(username, password, region, login_url)
|
63
|
+
end
|
64
|
+
|
65
|
+
soap_response = post(login_url, auth_request)
|
55
66
|
|
56
67
|
document = REXML::Document.new(soap_response)
|
57
68
|
# Check for Fault
|
58
69
|
fault_xml = document.get_elements("//[local-name() = 'Fault']")
|
59
70
|
raise XML::Fault.new(fault_xml) if fault_xml.any?
|
60
71
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@
|
65
|
-
@
|
66
|
-
|
67
|
-
@
|
72
|
+
if on_premise?
|
73
|
+
@security_token0 = document.get_elements("//e:CipherValue").first.text.to_s
|
74
|
+
@security_token1 = document.get_elements("//xenc:CipherValue").last.text.to_s
|
75
|
+
@key_identifier = document.get_elements("//o:KeyIdentifier").first.text
|
76
|
+
@cert_issuer_name = document.get_elements("//X509IssuerName").first.text
|
77
|
+
@cert_serial_number = document.get_elements("//X509SerialNumber").first.text
|
78
|
+
@server_secret = document.get_elements("//trust:BinarySecret").first.text
|
79
|
+
|
80
|
+
@header_current_time = get_current_time
|
81
|
+
@header_expires_time = get_current_time_plus_hour
|
82
|
+
@timestamp = '<u:Timestamp xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="_0"><u:Created>' + @header_current_time + '</u:Created><u:Expires>' + @header_expires_time + '</u:Expires></u:Timestamp>'
|
83
|
+
@digest_value = Digest::SHA1.base64digest @timestamp
|
84
|
+
@signature = '<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></SignatureMethod><Reference URI="#_0"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>' + @digest_value + '</DigestValue></Reference></SignedInfo>'
|
85
|
+
@signature_value = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), Base64.decode64(@server_secret), @signature)).chomp
|
68
86
|
else
|
69
|
-
|
87
|
+
cipher_values = document.get_elements("//CipherValue")
|
88
|
+
|
89
|
+
if cipher_values && cipher_values.length > 0
|
90
|
+
@security_token0 = cipher_values[0].text
|
91
|
+
@security_token1 = cipher_values[1].text
|
92
|
+
# Use local-name() to ignore namespace.
|
93
|
+
@key_identifier = document.get_elements("//[local-name() = 'KeyIdentifier']").first.text
|
94
|
+
else
|
95
|
+
raise RuntimeError.new(soap_response)
|
96
|
+
end
|
70
97
|
end
|
71
98
|
|
99
|
+
|
72
100
|
true
|
73
101
|
end
|
74
102
|
|
@@ -79,7 +107,7 @@ module DynamicsCRM
|
|
79
107
|
entity = XML::Entity.new(entity_name)
|
80
108
|
entity.attributes = XML::Attributes.new(attributes)
|
81
109
|
|
82
|
-
xml_response = post(
|
110
|
+
xml_response = post(organization_endpoint, create_request(entity))
|
83
111
|
return Response::CreateResult.new(xml_response)
|
84
112
|
end
|
85
113
|
|
@@ -89,7 +117,7 @@ module DynamicsCRM
|
|
89
117
|
column_set = XML::ColumnSet.new(columns)
|
90
118
|
request = retrieve_request(entity_name, guid, column_set)
|
91
119
|
|
92
|
-
xml_response = post(
|
120
|
+
xml_response = post(organization_endpoint, request)
|
93
121
|
return Response::RetrieveResult.new(xml_response)
|
94
122
|
end
|
95
123
|
|
@@ -108,7 +136,7 @@ module DynamicsCRM
|
|
108
136
|
query.criteria = XML::Criteria.new(criteria)
|
109
137
|
|
110
138
|
request = retrieve_multiple_request(query)
|
111
|
-
xml_response = post(
|
139
|
+
xml_response = post(organization_endpoint, request)
|
112
140
|
return Response::RetrieveMultipleResult.new(xml_response)
|
113
141
|
end
|
114
142
|
|
@@ -127,20 +155,20 @@ module DynamicsCRM
|
|
127
155
|
entity.attributes = XML::Attributes.new(attributes)
|
128
156
|
|
129
157
|
request = update_request(entity)
|
130
|
-
xml_response = post(
|
158
|
+
xml_response = post(organization_endpoint, request)
|
131
159
|
return Response::UpdateResponse.new(xml_response)
|
132
160
|
end
|
133
161
|
|
134
162
|
def delete(entity_name, guid)
|
135
163
|
request = delete_request(entity_name, guid)
|
136
164
|
|
137
|
-
xml_response = post(
|
165
|
+
xml_response = post(organization_endpoint, request)
|
138
166
|
return Response::DeleteResponse.new(xml_response)
|
139
167
|
end
|
140
168
|
|
141
169
|
def execute(action, parameters={}, response_class=nil)
|
142
170
|
request = execute_request(action, parameters)
|
143
|
-
xml_response = post(
|
171
|
+
xml_response = post(organization_endpoint, request)
|
144
172
|
|
145
173
|
response_class ||= Response::ExecuteResult
|
146
174
|
return response_class.new(xml_response)
|
@@ -148,13 +176,13 @@ module DynamicsCRM
|
|
148
176
|
|
149
177
|
def associate(entity_name, guid, relationship, related_entities)
|
150
178
|
request = associate_request(entity_name, guid, relationship, related_entities)
|
151
|
-
xml_response = post(
|
179
|
+
xml_response = post(organization_endpoint, request)
|
152
180
|
return Response::AssociateResponse.new(xml_response)
|
153
181
|
end
|
154
182
|
|
155
183
|
def disassociate(entity_name, guid, relationship, related_entities)
|
156
184
|
request = disassociate_request(entity_name, guid, relationship, related_entities)
|
157
|
-
xml_response = post(
|
185
|
+
xml_response = post(organization_endpoint, request)
|
158
186
|
return Response::DisassociateResponse.new(xml_response)
|
159
187
|
end
|
160
188
|
|
@@ -250,8 +278,37 @@ module DynamicsCRM
|
|
250
278
|
|
251
279
|
protected
|
252
280
|
|
253
|
-
def
|
281
|
+
def on_premise?
|
282
|
+
@on_premise ||= !(hostname =~ /\.dynamics\.com/i)
|
283
|
+
end
|
284
|
+
|
285
|
+
def organization_wsdl
|
286
|
+
wsdl = open(organization_endpoint + "?wsdl=wsdl0").read
|
287
|
+
@organization_wsdl ||= REXML::Document.new(wsdl)
|
288
|
+
end
|
254
289
|
|
290
|
+
def login_url
|
291
|
+
@login_url ||= if on_premise?
|
292
|
+
(organization_wsdl.document.get_elements("//ms-xrm:Identifier").first.text + "/13/usernamemixed").gsub("http://", "https://")
|
293
|
+
else
|
294
|
+
OCP_LOGIN_URL
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def determine_region
|
299
|
+
case hostname
|
300
|
+
when /crm5\.dynamics\.com/
|
301
|
+
"urn:crmapac:dynamics.com"
|
302
|
+
when /crm4\.dynamics\.com/
|
303
|
+
"urn:crmemea:dynamics.com"
|
304
|
+
when /\.dynamics\.com/
|
305
|
+
"urn:crmna:dynamics.com"
|
306
|
+
else
|
307
|
+
organization_endpoint
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def post(url, request)
|
255
312
|
log_xml("REQUEST", request)
|
256
313
|
|
257
314
|
c = Curl::Easy.new(url) do |http|
|
@@ -261,7 +318,7 @@ module DynamicsCRM
|
|
261
318
|
http.headers["Content-length"] = request.length
|
262
319
|
|
263
320
|
http.ssl_verify_peer = false
|
264
|
-
http.timeout =
|
321
|
+
http.timeout = 120
|
265
322
|
http.follow_location = true
|
266
323
|
http.ssl_version = 1
|
267
324
|
# http.verbose = 1
|
@@ -270,8 +327,9 @@ module DynamicsCRM
|
|
270
327
|
if c.http_post(request)
|
271
328
|
response = c.body_str
|
272
329
|
else
|
273
|
-
|
330
|
+
# Do something here on error.
|
274
331
|
end
|
332
|
+
c.close
|
275
333
|
|
276
334
|
log_xml("RESPONSE", response)
|
277
335
|
|
data/lib/dynamics_crm/version.rb
CHANGED
@@ -6,8 +6,14 @@ module DynamicsCRM
|
|
6
6
|
SecureRandom.uuid
|
7
7
|
end
|
8
8
|
|
9
|
+
# have a bit of flexiblity in the create time to handle when system clocks are out of sync
|
9
10
|
def get_current_time
|
10
|
-
|
11
|
+
# 5.minutes = 5 * 60
|
12
|
+
(Time.now - (5 * 60)).utc.strftime '%Y-%m-%dT%H:%M:%SZ'
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_current_time_plus_hour
|
16
|
+
(Time.now.utc + (60*60)).strftime '%Y-%m-%dT%H:%M:%SZ'
|
11
17
|
end
|
12
18
|
|
13
19
|
def get_tomorrow_time
|
@@ -20,7 +26,7 @@ module DynamicsCRM
|
|
20
26
|
# urn:crmna:dynamics.com - North America
|
21
27
|
# urn:crmemea:dynamics.com - Europe, the Middle East and Africa
|
22
28
|
# urn:crmapac:dynamics.com - Asia Pacific
|
23
|
-
def build_ocp_request(username, password,
|
29
|
+
def build_ocp_request(username, password, region = "urn:crmna:dynamics.com", login_url = Client::OCP_LOGIN_URL)
|
24
30
|
%Q{
|
25
31
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
26
32
|
xmlns:a="http://www.w3.org/2005/08/addressing"
|
@@ -59,6 +65,41 @@ module DynamicsCRM
|
|
59
65
|
}
|
60
66
|
end
|
61
67
|
|
68
|
+
def build_on_premise_request(username, password, region = "", login_url = nil)
|
69
|
+
%Q{
|
70
|
+
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
71
|
+
xmlns:a="http://www.w3.org/2005/08/addressing">
|
72
|
+
<s:Header>
|
73
|
+
<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
|
74
|
+
<a:MessageID>urn:uuid:#{uuid()}</a:MessageID>
|
75
|
+
<a:ReplyTo>
|
76
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
77
|
+
</a:ReplyTo>
|
78
|
+
<Security s:mustUnderstand="1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
79
|
+
<u:Timestamp u:Id="#{uuid()}">
|
80
|
+
<u:Created>#{get_current_time}</u:Created>
|
81
|
+
<u:Expires>#{get_current_time_plus_hour}</u:Expires>
|
82
|
+
</u:Timestamp>
|
83
|
+
<UsernameToken u:Id="#{uuid()}">
|
84
|
+
<Username>#{REXML::Text.new(username).to_s}</Username>
|
85
|
+
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">#{REXML::Text.new(password).to_s}</Password>
|
86
|
+
</UsernameToken>
|
87
|
+
</Security>
|
88
|
+
<a:To s:mustUnderstand="1">#{login_url}</a:To>
|
89
|
+
</s:Header>
|
90
|
+
<s:Body>
|
91
|
+
<trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
|
92
|
+
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
|
93
|
+
<a:EndpointReference>
|
94
|
+
<a:Address>#{region}</a:Address>
|
95
|
+
</a:EndpointReference>
|
96
|
+
</wsp:AppliesTo>
|
97
|
+
<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
|
98
|
+
</trust:RequestSecurityToken>
|
99
|
+
</s:Body>
|
100
|
+
</s:Envelope>
|
101
|
+
}
|
102
|
+
end
|
62
103
|
|
63
104
|
def build_envelope(action, &block)
|
64
105
|
%Q{
|
@@ -72,9 +113,66 @@ module DynamicsCRM
|
|
72
113
|
end
|
73
114
|
|
74
115
|
def build_header(action)
|
116
|
+
if @on_premise
|
117
|
+
build_on_premise_header(action)
|
118
|
+
else
|
119
|
+
build_ocp_header(action)
|
120
|
+
end
|
121
|
+
end
|
75
122
|
|
76
|
-
|
123
|
+
def build_on_premise_header(action)
|
124
|
+
%Q{
|
125
|
+
<s:Header>
|
126
|
+
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/#{action}</a:Action>
|
127
|
+
<a:MessageID>urn:uuid:#{uuid()}</a:MessageID>
|
128
|
+
<a:ReplyTo>
|
129
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
130
|
+
</a:ReplyTo>
|
131
|
+
<a:To s:mustUnderstand="1">#{@organization_endpoint}</a:To>
|
132
|
+
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
133
|
+
#{@timestamp}
|
134
|
+
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
|
135
|
+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
|
136
|
+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
|
137
|
+
<e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
|
138
|
+
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
|
139
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
140
|
+
</e:EncryptionMethod>
|
141
|
+
<KeyInfo>
|
142
|
+
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
143
|
+
<X509Data>
|
144
|
+
<X509IssuerSerial>
|
145
|
+
<X509IssuerName>#{@cert_issuer_name}</X509IssuerName>
|
146
|
+
<X509SerialNumber>#{@cert_serial_number}</X509SerialNumber>
|
147
|
+
</X509IssuerSerial>
|
148
|
+
</X509Data>
|
149
|
+
</o:SecurityTokenReference>
|
150
|
+
</KeyInfo>
|
151
|
+
<e:CipherData>
|
152
|
+
<e:CipherValue>#{@security_token0}</e:CipherValue>
|
153
|
+
</e:CipherData>
|
154
|
+
</e:EncryptedKey>
|
155
|
+
</KeyInfo>
|
156
|
+
<xenc:CipherData>
|
157
|
+
<xenc:CipherValue>#{@security_token1}</xenc:CipherValue>
|
158
|
+
</xenc:CipherData>
|
159
|
+
</xenc:EncryptedData>
|
160
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
161
|
+
#{@signature}
|
162
|
+
<SignatureValue>#{@signature_value}</SignatureValue>
|
163
|
+
<KeyInfo>
|
164
|
+
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
165
|
+
<o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">#{@key_identifier}</o:KeyIdentifier>
|
166
|
+
</o:SecurityTokenReference>
|
167
|
+
</KeyInfo>
|
168
|
+
</Signature>
|
169
|
+
</o:Security>
|
170
|
+
</s:Header>
|
171
|
+
}
|
172
|
+
end
|
77
173
|
|
174
|
+
def build_ocp_header(action)
|
175
|
+
caller_id = @caller_id ? %Q{<CallerId xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">#{@caller_id}</CallerId>} : ""
|
78
176
|
%Q{
|
79
177
|
<s:Header>
|
80
178
|
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/#{action}</a:Action>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:a='http://www.w3.org/2005/08/addressing' xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
|
2
|
+
<s:Header>
|
3
|
+
<a:Action s:mustUnderstand='1'>http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal</a:Action>
|
4
|
+
<a:RelatesTo>urn:uuid:f07eb8c1-cda5-4998-a38d-94f95be07204</a:RelatesTo>
|
5
|
+
<o:Security s:mustUnderstand='1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>
|
6
|
+
<u:Timestamp u:Id='_0'>
|
7
|
+
<u:Created>2014-11-18T19:46:16.557Z</u:Created>
|
8
|
+
<u:Expires>2014-11-18T19:51:16.557Z</u:Expires>
|
9
|
+
</u:Timestamp>
|
10
|
+
</o:Security>
|
11
|
+
</s:Header>
|
12
|
+
<s:Body>
|
13
|
+
<trust:RequestSecurityTokenResponseCollection xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>
|
14
|
+
<trust:RequestSecurityTokenResponse>
|
15
|
+
<trust:Lifetime>
|
16
|
+
<wsu:Created xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>2014-11-18T19:46:16.542Z</wsu:Created>
|
17
|
+
<wsu:Expires xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>2014-11-25T19:46:16.542Z</wsu:Expires>
|
18
|
+
</trust:Lifetime>
|
19
|
+
<wsp:AppliesTo xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'>
|
20
|
+
<wsa:EndpointReference xmlns:wsa='http://www.w3.org/2005/08/addressing'>
|
21
|
+
<wsa:Address>https://psavtest.crm.powerobjects.net/</wsa:Address>
|
22
|
+
</wsa:EndpointReference>
|
23
|
+
</wsp:AppliesTo>
|
24
|
+
<trust:RequestedSecurityToken>
|
25
|
+
<xenc:EncryptedData Type='http://www.w3.org/2001/04/xmlenc#Element' xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'>
|
26
|
+
<xenc:EncryptionMethod Algorithm='http://www.w3.org/2001/04/xmlenc#aes256-cbc'/>
|
27
|
+
<KeyInfo xmlns='http://www.w3.org/2000/09/xmldsig#'>
|
28
|
+
<e:EncryptedKey xmlns:e='http://www.w3.org/2001/04/xmlenc#'>
|
29
|
+
<e:EncryptionMethod Algorithm='http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'>
|
30
|
+
<DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>
|
31
|
+
</e:EncryptionMethod>
|
32
|
+
<KeyInfo>
|
33
|
+
<o:SecurityTokenReference xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>
|
34
|
+
<X509Data>
|
35
|
+
<X509IssuerSerial>
|
36
|
+
<X509IssuerName>
|
37
|
+
SERIALNUMBER=12369287, CN=Go Daddy Secure
|
38
|
+
Certification Authority,
|
39
|
+
OU=http://certificates.godaddy.com/repository,
|
40
|
+
O="GoDaddy.com, Inc.", L=Scottsdale, S=Arizona, C=US
|
41
|
+
</X509IssuerName>
|
42
|
+
<X509SerialNumber>112094107365XXXXX</X509SerialNumber>
|
43
|
+
</X509IssuerSerial>
|
44
|
+
</X509Data>
|
45
|
+
</o:SecurityTokenReference>
|
46
|
+
</KeyInfo>
|
47
|
+
<e:CipherData>
|
48
|
+
<e:CipherValue>ydfdQsDU9ow4XhoBi+0+n+/9Z7DvfivMKlKR8wpPnMeY5fgfmmHPAWfnGhYNYPAXCaGleY7mCqqzLe2BlDQjMKUJ5f4jI3zfoy/3vSZwoJLxIOkklFbtku1ammaKAp+Om6PTqOySbpVWcaI3herX56EzF
|
49
|
+
</e:CipherValue>
|
50
|
+
</e:CipherData>
|
51
|
+
</e:EncryptedKey>
|
52
|
+
</KeyInfo>
|
53
|
+
<xenc:CipherData>
|
54
|
+
<xenc:CipherValue>GcCk8ivhLAAPEbQI8qScynWLReTWE0AC5NGXVGMdaoHTBSSyRUgSPpgZnCNWIqb+8rRI7l7aQNXn6L2ysxTZp+DvxontZc1uarKQWtKDskpfctdrRLfGhcfOb4NtyP9QbKQcdxYSCoQDVCQqrpYLIDHoV+0WLbI4hBQ1u+UzUxr99z+pNMKW6Z2uui+EY21dVX33HZpMWgB7bkzim8KjRulB7/WD1wBarVSIzYuxJdxXP1HcKiz7j/
|
55
|
+
</xenc:CipherValue>
|
56
|
+
</xenc:CipherData>
|
57
|
+
</xenc:EncryptedData>
|
58
|
+
</trust:RequestedSecurityToken>
|
59
|
+
<trust:RequestedProofToken>
|
60
|
+
<trust:BinarySecret>XZwQpJKfAy00NNWU1RwdtDpVyW/nfabuCq4H38GgKrM=</trust:BinarySecret>
|
61
|
+
</trust:RequestedProofToken>
|
62
|
+
<trust:RequestedAttachedReference>
|
63
|
+
<o:SecurityTokenReference k:TokenType='http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:k='http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd'>
|
64
|
+
<o:KeyIdentifier ValueType='http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID'>_ed121435-64ea-45b0-9b15-e5769afdb746</o:KeyIdentifier>
|
65
|
+
</o:SecurityTokenReference>
|
66
|
+
</trust:RequestedAttachedReference>
|
67
|
+
<trust:RequestedUnattachedReference>
|
68
|
+
<o:SecurityTokenReference k:TokenType='http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:k='http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd'>
|
69
|
+
<o:KeyIdentifier ValueType='http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID'>_ed121435-64ea-45b0-9b15-e5769afdb746</o:KeyIdentifier>
|
70
|
+
</o:SecurityTokenReference>
|
71
|
+
</trust:RequestedUnattachedReference>
|
72
|
+
<trust:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</trust:TokenType>
|
73
|
+
<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
|
74
|
+
<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
|
75
|
+
</trust:RequestSecurityTokenResponse>
|
76
|
+
</trust:RequestSecurityTokenResponseCollection>
|
77
|
+
</s:Body>
|
78
|
+
</s:Envelope>
|
data/spec/lib/client_spec.rb
CHANGED
@@ -5,33 +5,55 @@ describe DynamicsCRM::Client do
|
|
5
5
|
let(:subject) { DynamicsCRM::Client.new(organization_name: "tinderboxdev")}
|
6
6
|
|
7
7
|
describe "#authenticate" do
|
8
|
-
it "
|
8
|
+
it "raises arugment error when no parameters are passed" do
|
9
|
+
expect { subject.authenticate() }.to raise_error(ArgumentError)
|
10
|
+
end
|
9
11
|
|
10
|
-
|
12
|
+
context "Online" do
|
13
|
+
it "authenticates with username and password" do
|
11
14
|
|
12
|
-
|
15
|
+
subject.stub(:post).and_return(fixture("request_security_token_response"))
|
13
16
|
|
14
|
-
|
15
|
-
subject.instance_variable_get("@security_token1").should start_with("CX7BFgRnW75tE6GiuRICjeVDV+6q4KDMKLyKmKe9A8U")
|
16
|
-
subject.instance_variable_get("@key_identifier").should == "D3xjUG3HGaQuKyuGdTWuf6547Lo="
|
17
|
-
end
|
17
|
+
subject.authenticate('testing', 'password')
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
subject.instance_variable_get("@security_token0").should start_with("tMFpDJbJHcZnRVuby5cYmRbCJo2OgOFLEOrUHj+wz")
|
20
|
+
subject.instance_variable_get("@security_token1").should start_with("CX7BFgRnW75tE6GiuRICjeVDV+6q4KDMKLyKmKe9A8U")
|
21
|
+
subject.instance_variable_get("@key_identifier").should == "D3xjUG3HGaQuKyuGdTWuf6547Lo="
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is only method in this suite that actually sends a POST message to Dynamics.
|
25
|
+
# This covers the post() and fault parsing logic.
|
26
|
+
it "fails to authenticate with invalid credentials" do
|
27
|
+
begin
|
28
|
+
subject.authenticate('testuser@orgnam.onmicrosoft.com', 'qwerty')
|
29
|
+
fail("Expected Fault to be raised")
|
30
|
+
rescue DynamicsCRM::XML::Fault => f
|
31
|
+
f.code.should == "S:Sender"
|
32
|
+
f.subcode.should == "wst:FailedAuthentication"
|
33
|
+
f.reason.should == "Authentication Failure"
|
34
|
+
end
|
35
|
+
end
|
21
36
|
end
|
22
37
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
38
|
+
context "On-Premise" do
|
39
|
+
let(:subject) { DynamicsCRM::Client.new(organization_name: "psavtest", hostname: "psavtest.crm.powerobjects.net")}
|
40
|
+
|
41
|
+
it "authenticates with username and password" do
|
42
|
+
|
43
|
+
subject.stub(:post).and_return(fixture("request_security_token_response_onpremise"))
|
44
|
+
|
45
|
+
subject.authenticate('testing', 'password')
|
46
|
+
|
47
|
+
subject.instance_variable_get("@security_token0").should start_with("ydfdQsDU9ow4XhoBi+0+n+/9Z7Dvfi")
|
48
|
+
subject.instance_variable_get("@security_token1").should start_with("GcCk8ivhLAAPEbQI8qScynWLReTWE0AC5")
|
49
|
+
subject.instance_variable_get("@key_identifier").should == "_ed121435-64ea-45b0-9b15-e5769afdb746"
|
50
|
+
|
51
|
+
subject.instance_variable_get("@cert_issuer_name").strip.should start_with("SERIALNUMBER=12369287, CN=Go Daddy Secure")
|
52
|
+
subject.instance_variable_get("@cert_serial_number").should == "112094107365XXXXX"
|
53
|
+
subject.instance_variable_get("@server_secret").should == "XZwQpJKfAy00NNWU1RwdtDpVyW/nfabuCq4H38GgKrM="
|
33
54
|
end
|
34
55
|
end
|
56
|
+
|
35
57
|
end
|
36
58
|
|
37
59
|
describe "#retrieve" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamics_crm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Heth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curb
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- spec/fixtures/lose_opportunity_response.xml
|
183
183
|
- spec/fixtures/receiver_fault.xml
|
184
184
|
- spec/fixtures/request_security_token_response.xml
|
185
|
+
- spec/fixtures/request_security_token_response_onpremise.xml
|
185
186
|
- spec/fixtures/retrieve_account_all_columns.xml
|
186
187
|
- spec/fixtures/retrieve_all_entities.xml
|
187
188
|
- spec/fixtures/retrieve_attribute_identifier_response.xml
|
@@ -232,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
232
233
|
version: '0'
|
233
234
|
requirements: []
|
234
235
|
rubyforge_project:
|
235
|
-
rubygems_version: 2.
|
236
|
+
rubygems_version: 2.4.5
|
236
237
|
signing_key:
|
237
238
|
specification_version: 4
|
238
239
|
summary: Ruby gem for integrating with MS Dynamics 2011/2013 SOAP API
|
@@ -245,6 +246,7 @@ test_files:
|
|
245
246
|
- spec/fixtures/lose_opportunity_response.xml
|
246
247
|
- spec/fixtures/receiver_fault.xml
|
247
248
|
- spec/fixtures/request_security_token_response.xml
|
249
|
+
- spec/fixtures/request_security_token_response_onpremise.xml
|
248
250
|
- spec/fixtures/retrieve_account_all_columns.xml
|
249
251
|
- spec/fixtures/retrieve_all_entities.xml
|
250
252
|
- spec/fixtures/retrieve_attribute_identifier_response.xml
|