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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b36fe4188ed46fabe0f74049683a5ba9498e1842
4
- data.tar.gz: 616ab5e8a0d26d6a91b99f7dfeb8033852c80edf
3
+ metadata.gz: dbd8933df47587a12b12a2115afbb57d2e8d2b1c
4
+ data.tar.gz: 8343d6d884713b0956e71a9ffcde12c6364302b3
5
5
  SHA512:
6
- metadata.gz: 43a30dd93693e0a8b4fe60ae61046560d0ec2c9ce50e158e297e6000e4e311579518df3f6ff0eddd07a40f2bd85488c72328d0cd12ec36536388f51f2f3a5f11
7
- data.tar.gz: d3055f511ad34189d3451e9b81f71584e7d3ee4e3be73e577c7d220ff98d4777a18a1416feb7d13430df65946c1ba8b7a04f3d3359b6800b9dc00c2000510270
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)
@@ -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] || 'https://login.microsoftonline.com/RST2.srf'
38
- @region = config[:region] || 'urn:crmna:dynamics.com'
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
- soap_response = post(@login_url, build_ocp_request(username, password, @login_url, @region))
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
- cipher_values = document.get_elements("//CipherValue")
62
-
63
- if cipher_values && cipher_values.length > 0
64
- @security_token0 = cipher_values[0].text
65
- @security_token1 = cipher_values[1].text
66
- # Use local-name() to ignore namespace.
67
- @key_identifier = document.get_elements("//[local-name() = 'KeyIdentifier']").first.text
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
- raise RuntimeError.new(soap_response)
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(@organization_endpoint, create_request(entity))
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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(@organization_endpoint, request)
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 post(url, request)
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 = 60
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
 
@@ -1,3 +1,3 @@
1
1
  module DynamicsCRM
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -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
- Time.now.utc.strftime '%Y-%m-%dT%H:%M:%SZ'
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, login_url, region)
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
- caller_id = @caller_id ? %Q{<CallerId xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">#{@caller_id}</CallerId>} : ""
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>
@@ -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 "authenticates with username and password" do
8
+ it "raises arugment error when no parameters are passed" do
9
+ expect { subject.authenticate() }.to raise_error(ArgumentError)
10
+ end
9
11
 
10
- subject.stub(:post).and_return(fixture("request_security_token_response"))
12
+ context "Online" do
13
+ it "authenticates with username and password" do
11
14
 
12
- subject.authenticate('testing', 'password')
15
+ subject.stub(:post).and_return(fixture("request_security_token_response"))
13
16
 
14
- subject.instance_variable_get("@security_token0").should start_with("tMFpDJbJHcZnRVuby5cYmRbCJo2OgOFLEOrUHj+wz")
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
- it "raises arugment error when no parameters are passed" do
20
- expect { subject.authenticate() }.to raise_error(ArgumentError)
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
- # This is only method in this suite that actually sends a POST message to Dynamics.
24
- # This covers the post() and fault parsing logic.
25
- it "fails to authenticate with invalid credentials" do
26
- begin
27
- subject.authenticate('testuser@orgnam.onmicrosoft.com', 'qwerty')
28
- fail("Expected Fault to be raised")
29
- rescue DynamicsCRM::XML::Fault => f
30
- f.code.should == "S:Sender"
31
- f.subcode.should == "wst:FailedAuthentication"
32
- f.reason.should == "Authentication Failure"
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.1
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-24 00:00:00.000000000 Z
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.2.1
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