dynamics_crm 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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