ruby-saml 1.4.3 → 1.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.

Potentially problematic release.


This version of ruby-saml might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 455ea502cffeb8d8b1c0bc673de3495e0e1b070a
4
- data.tar.gz: f5327bfb4d61922b77444f397a8347910a6bab33
3
+ metadata.gz: d6958524060034d6eaaf5c0f968711ecdc45e2bd
4
+ data.tar.gz: f1714aa26982ce596b8e07f2e20a8637611d7523
5
5
  SHA512:
6
- metadata.gz: a3842b07e3f0da562c0302a7a399f63901bbe0a7ae88a68f60dce296fc0d7a9eebed08544db2cfcea2857a76dfed58cc158d6dacba10671135a804d899d8edad
7
- data.tar.gz: 0ce3cc58921b2d384983cca9a29a75890e39a25e0b62da97e27f3a4c32baabf15b338ff9cd83b5aeb8d980ff69f10f094b72afab8a047c917ac775b7f4a1b896
6
+ metadata.gz: 1cb2ee3fefaec17210a0087dbadc68698b4fa9969d20c81512c9d1904bf941a59179a73b2d46ed52c38867f0c201b82e9f8cdd0f50b114103b7fe72cfcbb7bdc
7
+ data.tar.gz: ed45f61f08919d846edb627699ed1679f5d7e8c1c5136a4703d3c9129bc7259e9f761a1a8fc12bb439bd5e96128069c5c0b3b9115e1f8d38e55a874523793cec
data/README.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.svg)](http://travis-ci.org/onelogin/ruby-saml) [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master%0A)](https://coveralls.io/r/onelogin/ruby-saml?branch=master%0A) [![Gem Version](https://badge.fury.io/rb/ruby-saml.svg)](http://badge.fury.io/rb/ruby-saml)
2
2
 
3
+ ## Updating from 1.4.2 to 1.4.3
4
+
5
+ Version `1.4.3` introduces Recipient validation of SubjectConfirmation elements.
6
+ The 'Recipient' value is compared with the settings.assertion_consumer_service_url
7
+ value.
8
+ If you want to skip that validation, add the :skip_recipient_check option to the
9
+ initialize method of the Response object.
10
+
3
11
  ## Updating from 1.3.x to 1.4.X
4
12
 
5
13
  Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
@@ -169,7 +177,6 @@ def saml_settings
169
177
 
170
178
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
171
179
  settings.issuer = "http://#{request.host}/saml/metadata"
172
- settings.idp_sso_target_url = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
173
180
  settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
174
181
  settings.idp_sso_target_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
175
182
  settings.idp_slo_target_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
@@ -1,4 +1,13 @@
1
1
  # RubySaml Changelog
2
+ ### 1.5.0 (August 31, 2017)
3
+ * [#400](https://github.com/onelogin/ruby-saml/pull/400) When validating Signature use stored IdP certficate if Signature contains no info about Certificate
4
+ * [#402](https://github.com/onelogin/ruby-saml/pull/402) Fix validate_response_state method that rejected SAMLResponses when using idp_cert_multi and idp_cert and idp_cert_fingerprint were not provided.
5
+ * [#411](https://github.com/onelogin/ruby-saml/pull/411) Allow space in Base64 string
6
+ * [#407](https://github.com/onelogin/ruby-saml/issues/407) Improve IdpMetadataParser raising an ArgumentError when parser method receive a metadata string with no IDPSSODescriptor element.
7
+ * [#374](https://github.com/onelogin/ruby-saml/issues/374) Support more than one level of StatusCode
8
+ * [#405](https://github.com/onelogin/ruby-saml/pull/405) Support ADFS encrypted key (Accept KeyInfo nodes with no ds namespace)
9
+
10
+
2
11
  ### 1.4.3 (May 18, 2017)
3
12
  * Added SubjectConfirmation Recipient validation
4
13
  * [#393](https://github.com/onelogin/ruby-saml/pull/393) Implement IdpMetadataParser#parse_to_hash
@@ -102,6 +102,10 @@ module OneLogin
102
102
  @options = options
103
103
  @entity_descriptor = nil
104
104
 
105
+ if idpsso_descriptor.nil?
106
+ raise ArgumentError.new("idp_metadata may contain an IDPSSODescriptor element")
107
+ end
108
+
105
109
  {
106
110
  :idp_entity_id => idp_entity_id,
107
111
  :name_identifier_format => idp_name_id_format,
@@ -164,6 +168,16 @@ module OneLogin
164
168
  path << "[@entityID=\"#{entity_id}\"]"
165
169
  end
166
170
 
171
+ def idpsso_descriptor
172
+ unless entity_descriptor.nil?
173
+ return REXML::XPath.first(
174
+ entity_descriptor,
175
+ "md:IDPSSODescriptor",
176
+ namespace
177
+ )
178
+ end
179
+ end
180
+
167
181
  # @return [String|nil] IdP Entity ID value if exists
168
182
  #
169
183
  def idp_entity_id
@@ -335,7 +349,8 @@ module OneLogin
335
349
  )
336
350
  end
337
351
  else
338
- parsed_metadata[:idp_cert_multi] = certificates
352
+ # symbolize keys of certificates and pass it on
353
+ parsed_metadata[:idp_cert_multi] = Hash[certificates.map { |k, v| [k.to_sym, v] }]
339
354
  end
340
355
  end
341
356
 
@@ -168,7 +168,7 @@ module OneLogin
168
168
 
169
169
  return append_error("No issuer in settings of the logout response") if settings.issuer.nil?
170
170
 
171
- if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
171
+ if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil? && settings.idp_cert_multi.nil?
172
172
  return append_error("No fingerprint or certificate on settings of the logout response")
173
173
  end
174
174
 
@@ -37,6 +37,7 @@ module OneLogin
37
37
  # with the :skip_conditions, or allow a clock_drift when checking dates with :allowed_clock_drift
38
38
  # or :matches_request_id that will validate that the response matches the ID of the request,
39
39
  # or skip the subject confirmation validation with the :skip_subject_confirmation option
40
+ # or skip the recipient validation of the subject confirmation element with :skip_recipient_check option
40
41
  def initialize(response, options = {})
41
42
  raise ArgumentError.new("Response cannot be nil") if response.nil?
42
43
 
@@ -206,7 +207,23 @@ module OneLogin
206
207
  )
207
208
  if nodes.size == 1
208
209
  node = nodes[0]
209
- node.attributes["Value"] if node && node.attributes
210
+ code = node.attributes["Value"] if node && node.attributes
211
+
212
+ unless code == "urn:oasis:names:tc:SAML:2.0:status:Success"
213
+ nodes = REXML::XPath.match(
214
+ document,
215
+ "/p:Response/p:Status/p:StatusCode/p:StatusCode",
216
+ { "p" => PROTOCOL }
217
+ )
218
+ statuses = nodes.collect do |node|
219
+ node.attributes["Value"]
220
+ end
221
+ extra_code = statuses.join(" | ")
222
+ if extra_code
223
+ code = "#{code} | #{extra_code}"
224
+ end
225
+ end
226
+ code
210
227
  end
211
228
  end
212
229
  end
@@ -411,7 +428,7 @@ module OneLogin
411
428
 
412
429
  return append_error("No settings on response") if settings.nil?
413
430
 
414
- if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
431
+ if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil? && settings.idp_cert_multi.nil?
415
432
  return append_error("No fingerprint or certificate on settings")
416
433
  end
417
434
 
@@ -650,13 +667,13 @@ module OneLogin
650
667
 
651
668
  now = Time.now.utc
652
669
 
653
- if not_before && (now + allowed_clock_drift) < not_before
654
- error_msg = "Current time is earlier than NotBefore condition #{(now + allowed_clock_drift)} < #{not_before})"
670
+ if not_before && (now_with_drift = now + allowed_clock_drift) < not_before
671
+ error_msg = "Current time is earlier than NotBefore condition (#{now_with_drift} < #{not_before})"
655
672
  return append_error(error_msg)
656
673
  end
657
674
 
658
- if not_on_or_after && now >= (not_on_or_after + allowed_clock_drift)
659
- error_msg = "Current time is on or after NotOnOrAfter condition (#{now} >= #{not_on_or_after + allowed_clock_drift})"
675
+ if not_on_or_after && now >= (not_on_or_after_with_drift = not_on_or_after + allowed_clock_drift)
676
+ error_msg = "Current time is on or after NotOnOrAfter condition (#{now} >= #{not_on_or_after_with_drift})"
660
677
  return append_error(error_msg)
661
678
  end
662
679
 
@@ -813,7 +830,7 @@ module OneLogin
813
830
  opts[:cert] = settings.get_idp_cert
814
831
  fingerprint = settings.get_fingerprint
815
832
 
816
- unless fingerprint && doc.validate_document(fingerprint, @soft, opts)
833
+ unless fingerprint && doc.validate_document(fingerprint, @soft, opts)
817
834
  return append_error(error_msg)
818
835
  end
819
836
  else
@@ -129,7 +129,7 @@ module OneLogin
129
129
  # @return [true, false] whether or not the string is base64 encoded
130
130
  #
131
131
  def base64_encoded?(string)
132
- !!string.gsub(/[\r\n]|\\r|\\n/, "").match(BASE64_FORMAT)
132
+ !!string.gsub(/[\r\n]|\\r|\\n|\s/, "").match(BASE64_FORMAT)
133
133
  end
134
134
 
135
135
  # Inflate method
@@ -87,7 +87,15 @@ module OneLogin
87
87
  # @return [String] The status error message
88
88
  def self.status_error_msg(error_msg, status_code = nil, status_message = nil)
89
89
  unless status_code.nil?
90
- printable_code = status_code.split(':').last
90
+ if status_code.include? "|"
91
+ status_codes = status_code.split(' | ')
92
+ values = status_codes.collect do |status_code|
93
+ status_code.split(':').last
94
+ end
95
+ printable_code = values.join(" => ")
96
+ else
97
+ printable_code = status_code.split(':').last
98
+ end
91
99
  error_msg << ', was ' + printable_code
92
100
  end
93
101
 
@@ -131,23 +139,25 @@ module OneLogin
131
139
  def self.retrieve_symmetric_key(encrypt_data, private_key)
132
140
  encrypted_key = REXML::XPath.first(
133
141
  encrypt_data,
134
- "./ds:KeyInfo/xenc:EncryptedKey or \
135
- //xenc:EncryptedKey[@Id=$id]",
142
+ "./ds:KeyInfo/xenc:EncryptedKey | ./KeyInfo/xenc:EncryptedKey | //xenc:EncryptedKey[@Id=$id]",
136
143
  { "ds" => DSIG, "xenc" => XENC },
137
- { "id" => self.retrieve_symetric_key_reference(encrypt_data) }
144
+ { "id" => self.retrieve_symetric_key_reference(encrypt_data) }
138
145
  )
139
146
 
140
147
  encrypted_symmetric_key_element = REXML::XPath.first(
141
148
  encrypted_key,
142
149
  "./xenc:CipherData/xenc:CipherValue",
143
- { "ds" => DSIG, "xenc" => XENC }
150
+ "xenc" => XENC
144
151
  )
152
+
145
153
  cipher_text = Base64.decode64(encrypted_symmetric_key_element.text)
154
+
146
155
  encrypt_method = REXML::XPath.first(
147
156
  encrypted_key,
148
157
  "./xenc:EncryptionMethod",
149
- {"ds" => DSIG, "xenc" => XENC }
158
+ "xenc" => XENC
150
159
  )
160
+
151
161
  algorithm = encrypt_method.attributes['Algorithm']
152
162
  retrieve_plaintext(cipher_text, private_key, algorithm)
153
163
  end
@@ -1,5 +1,5 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
- VERSION = '1.4.3'
3
+ VERSION = '1.5.0'
4
4
  end
5
5
  end
@@ -260,9 +260,11 @@ module XMLSecurity
260
260
  # check saml response cert matches provided idp cert
261
261
  if idp_cert.to_pem != cert.to_pem
262
262
  return false
263
+ end
264
+ else
265
+ base64_cert = Base64.encode64(idp_cert.to_pem)
263
266
  end
264
- validate_signature(base64_cert, true)
265
- end
267
+ validate_signature(base64_cert, true)
266
268
  end
267
269
 
268
270
  def validate_signature(base64_cert, soft = true)
@@ -202,10 +202,10 @@ class IdpMetadataParserTest < Minitest::Test
202
202
  assert_nil settings.idp_cert_fingerprint
203
203
  assert_nil settings.idp_cert
204
204
  assert_equal 2, settings.idp_cert_multi.size
205
- assert settings.idp_cert_multi.key?("signing")
206
- assert_equal 2, settings.idp_cert_multi["signing"].size
207
- assert settings.idp_cert_multi.key?("encryption")
208
- assert_equal 1, settings.idp_cert_multi["encryption"].size
205
+ assert settings.idp_cert_multi.key?(:signing)
206
+ assert_equal 2, settings.idp_cert_multi[:signing].size
207
+ assert settings.idp_cert_multi.key?(:encryption)
208
+ assert_equal 1, settings.idp_cert_multi[:encryption].size
209
209
  end
210
210
  end
211
211
 
@@ -332,4 +332,15 @@ class IdpMetadataParserTest < Minitest::Test
332
332
  assert_equal ["AuthToken", "SSOStartPage"], @settings.idp_attribute_names
333
333
  end
334
334
  end
335
+
336
+ describe "parsing metadata with no IDPSSODescriptor element" do
337
+ before do
338
+ @idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
339
+ @idp_metadata = no_idp_metadata_descriptor
340
+ end
341
+
342
+ it "raise due no IDPSSODescriptor element" do
343
+ assert_raises(ArgumentError) { @idp_metadata_parser.parse(@idp_metadata) }
344
+ end
345
+ end
335
346
  end
@@ -90,6 +90,7 @@ class RubySamlTest < Minitest::Test
90
90
  it "invalidate logout response when initiated with no idp cert or fingerprint" do
91
91
  settings.idp_cert_fingerprint = nil
92
92
  settings.idp_cert = nil
93
+ settings.idp_cert_multi = nil
93
94
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings)
94
95
  assert !logoutresponse.validate
95
96
  assert_includes logoutresponse.errors, "No fingerprint or certificate on settings of the logout response"
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <md:EntityDescriptor entityID="https://sp.example.com/sp.xml" validUntil="2014-04-17T18:02:33.910Z" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
3
+ <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol" AuthnRequestsSigned="true">
4
+ <md:KeyDescriptor use="signing">
5
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
6
+ <ds:X509Data>
7
+ <ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=</ds:X509Certificate>
8
+ </ds:X509Data>
9
+ </ds:KeyInfo>
10
+ </md:KeyDescriptor>
11
+ <md:KeyDescriptor use="encryption">
12
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
13
+ <ds:X509Data>
14
+ <ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=</ds:X509Certificate>
15
+ </ds:X509Data>
16
+ </ds:KeyInfo>
17
+ </md:KeyDescriptor>
18
+ <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sp.example.com/saml2-logout.php/default-sp"/>
19
+ <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.example.com/saml2-acs.php/default-sp" index="0"/>
20
+ </md:SPSSODescriptor>
21
+ </md:EntityDescriptor>
@@ -30,6 +30,7 @@ class RubySamlTest < Minitest::Test
30
30
  let(:response_no_statuscode) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status_code.xml.base64")) }
31
31
  let(:response_statuscode_responder) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responder.xml.base64")) }
32
32
  let(:response_statuscode_responder_and_msg) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responer_and_msg.xml.base64")) }
33
+ let(:response_double_statuscode) { OneLogin::RubySaml::Response.new(response_document_double_status_code) }
33
34
  let(:response_encrypted_attrs) { OneLogin::RubySaml::Response.new(response_document_encrypted_attrs) }
34
35
  let(:response_no_signed_elements) { OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64")) }
35
36
  let(:response_multiple_signed) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_signed.xml.base64")) }
@@ -138,6 +139,7 @@ class RubySamlTest < Minitest::Test
138
139
  it "raise when No fingerprint or certificate on settings" do
139
140
  settings.idp_cert_fingerprint = nil
140
141
  settings.idp_cert = nil
142
+ settings.idp_cert_multi = nil
141
143
  response.settings = settings
142
144
  error_msg = "No fingerprint or certificate on settings"
143
145
  assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
@@ -516,12 +518,12 @@ class RubySamlTest < Minitest::Test
516
518
  assert_empty response.errors
517
519
  end
518
520
 
519
- it "return false when the status if no Status provided" do
521
+ it "return false when no Status provided" do
520
522
  assert !response_no_status.send(:validate_success_status)
521
523
  assert_includes response_no_status.errors, "The status code of the Response was not Success"
522
524
  end
523
525
 
524
- it "return false when the status if no StatusCode provided" do
526
+ it "return false when no StatusCode provided" do
525
527
  assert !response_no_statuscode.send(:validate_success_status)
526
528
  assert_includes response_no_statuscode.errors, "The status code of the Response was not Success"
527
529
  end
@@ -535,6 +537,11 @@ class RubySamlTest < Minitest::Test
535
537
  assert !response_statuscode_responder_and_msg.send(:validate_success_status)
536
538
  assert_includes response_statuscode_responder_and_msg.errors, "The status code of the Response was not Success, was Responder -> something_is_wrong"
537
539
  end
540
+
541
+ it "return false when the status is not 'Success'" do
542
+ assert !response_double_statuscode.send(:validate_success_status)
543
+ assert_includes response_double_statuscode.errors, "The status code of the Response was not Success, was Requester => UnsupportedBinding"
544
+ end
538
545
  end
539
546
 
540
547
  describe "#validate_structure" do
@@ -1271,6 +1278,11 @@ class RubySamlTest < Minitest::Test
1271
1278
 
1272
1279
  response4 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
1273
1280
  assert response4.decrypted_document
1281
+
1282
+ assert OneLogin::RubySaml::Response.new(
1283
+ Base64.encode64(File.read('test/responses/unsigned_encrypted_adfs.xml')),
1284
+ :settings => settings
1285
+ ).decrypted_document
1274
1286
  end
1275
1287
  end
1276
1288
 
@@ -0,0 +1 @@
1
+ PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9InBmeGJjODI2YWZkLWU5ZmUtZDNmYi1kODc0LWM0NzAwYzNlZjBjOCIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIiBEZXN0aW5hdGlvbj0iaHR0cDovL2FwcC5tdWRhLm5vL3Nzby9jb25zdW1lIiBJblJlc3BvbnNlVG89Il9mYzRhMzRiMC03ZWZiLTAxMmUtY2FhZS03ODJiY2IxM2JiMzgiPjxzYW1sOklzc3Vlcj5odHRwczovL2FwcC5vbmVsb2dpbi5jb20vc2FtbDI8L3NhbWw6SXNzdWVyPjxzYW1scDpTdGF0dXM+PHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6UmVxdWVzdGVyIj4gIDxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlVuc3VwcG9ydGVkQmluZGluZyIgLz48L3NhbWxwOlN0YXR1c0NvZGU+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgVmVyc2lvbj0iMi4wIiBJRD0icGZ4OTUxNmIwZjMtNDUzNi0xMGY2LWM2ZmEtOWRkNTIzZTE0OThjIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9hcHAub25lbG9naW4uY29tL3NhbWwyPC9zYW1sOklzc3Vlcj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+dGVzdEBvbmVsb2dpbi5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwOTAtMDYtMDRUMDI6Mjc6MDJaIiBSZWNpcGllbnQ9InJlY2lwaWVudCIvPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDExLTA2LTA0VDAyOjE3OjAyWiIgTm90T25PckFmdGVyPSIyMDkwLTA2LTA0VDAyOjI3OjAyWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL3NvbWVvbmUuZXhhbXBsZS5jb20vYXVkaWVuY2U8L3NhbWw6QXVkaWVuY2U+PC9zYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PC9zYW1sOkNvbmRpdGlvbnM+PHNhbWw6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTA2LTA0VDAyOjIyOjAyWiIgU2Vzc2lvbk5vdE9uT3JBZnRlcj0iMjA5MC0wNi0wNVQwMjoyMjowMloiIFNlc3Npb25JbmRleD0iXzE2ZjU3MGZiYzAzMTUwMDdhMDM1NWRmZWE2YjNjNDZjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0"?>
2
+ <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_9365faa3a6f6a23b5cd75a74cb0786dc19e845200e" Version="2.0" IssueInstant="2015-03-19T14:00:31Z" Destination="http://rubysaml.com:3000/saml/acs" InResponseTo="_3ab7adb0-b06e-0132-5c3b-0090f5dedd77">
3
+ <saml:Issuer>https://idp.example.com/simplesaml/saml2/idp/metadata.php</saml:Issuer>
4
+ <samlp:Status>
5
+ <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
6
+ </samlp:Status>
7
+ <EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
8
+ <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element">
9
+ <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
10
+ <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
11
+ <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
12
+ <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
13
+ <e:CipherData>
14
+ <e:CipherValue>xkJn7LQHrTZzLdrNec33hMSC5dc8B0uM4fw8HKhwpkWINwC9deaj0QVz4fZ82Zv2QdP3v6r0wJ/8VrUIF8puJTHSU0u2EUU+XqBJxvivGp2UhUPCyWmirSi6efBnWqMKhOz5YJoaLEu17yw+kOnavLZPv2bB8b5bo2mZPiaPG6s=</e:CipherValue>
15
+ </e:CipherData>
16
+ </e:EncryptedKey>
17
+ </KeyInfo>
18
+ <xenc:CipherData>
19
+ <xenc:CipherValue>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</xenc:CipherValue>
20
+ </xenc:CipherData>
21
+ </xenc:EncryptedData>
22
+ </EncryptedAssertion>
23
+ </samlp:Response>
@@ -136,6 +136,10 @@ class Minitest::Test
136
136
  @response_document_encrypted_attrs ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response_encrypted_attrs.xml.base64'))
137
137
  end
138
138
 
139
+ def response_document_double_status_code
140
+ @response_document_double_status_code ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response_double_status_code.xml.base64'))
141
+ end
142
+
139
143
  def signature_fingerprint_1
140
144
  @signature_fingerprint1 ||= "C5:19:85:D9:47:F1:BE:57:08:20:25:05:08:46:EB:27:F6:CA:B7:83"
141
145
  end
@@ -162,6 +166,10 @@ class Minitest::Test
162
166
  @idp_metadata_descriptor3 ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'idp_descriptor_3.xml'))
163
167
  end
164
168
 
169
+ def no_idp_metadata_descriptor
170
+ @no_idp_metadata_descriptor ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'no_idp_descriptor.xml'))
171
+ end
172
+
165
173
  def idp_metadata_multiple_descriptors
166
174
  @idp_metadata_multiple_descriptors ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'idp_multiple_descriptors.xml'))
167
175
  end
@@ -106,7 +106,7 @@ class XmlSecurityTest < Minitest::Test
106
106
  end
107
107
  end
108
108
 
109
- describe "#algorithm" do
109
+ describe "#algorithm" do
110
110
  it "SHA1" do
111
111
  alg = OpenSSL::Digest::SHA1
112
112
  assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha1")
@@ -130,7 +130,7 @@ class XmlSecurityTest < Minitest::Test
130
130
  alg = OpenSSL::Digest::SHA512
131
131
  assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512")
132
132
  assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#sha512")
133
- end
133
+ end
134
134
  end
135
135
 
136
136
  describe "Fingerprint Algorithms" do
@@ -278,7 +278,7 @@ class XmlSecurityTest < Minitest::Test
278
278
  logout_request2.sign_document(ruby_saml_key, ruby_saml_cert_text)
279
279
  # verify our signature
280
280
  signed_doc2 = XMLSecurity::SignedDocument.new(logout_request2.to_s)
281
- signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
281
+ signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
282
282
  assert signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
283
283
  end
284
284
 
@@ -293,7 +293,7 @@ class XmlSecurityTest < Minitest::Test
293
293
  logout_response2.sign_document(ruby_saml_key, ruby_saml_cert_text)
294
294
  # verify our signature
295
295
  signed_doc2 = XMLSecurity::SignedDocument.new(logout_response2.to_s)
296
- signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
296
+ signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
297
297
  assert signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
298
298
  end
299
299
  end
@@ -316,9 +316,14 @@ class XmlSecurityTest < Minitest::Test
316
316
  Timecop.freeze Time.parse('2012-11-20 17:55:00 UTC') do
317
317
  assert !response.is_valid?
318
318
 
319
- contains_expected_error = response.errors.include? "Current time is earlier than NotBefore condition 2012-11-20 17:55:00 UTC < 2012-11-28 17:53:45 UTC)"
320
- contains_expected_error ||= response.errors.include? "Current time is earlier than NotBefore condition Tue Nov 20 17:55:00 UTC 2012 < Wed Nov 28 17:53:45 UTC 2012)"
321
- assert contains_expected_error
319
+ time_1 = '2012-11-20 17:55:00 UTC < 2012-11-28 17:53:45 UTC'
320
+ time_2 = 'Tue Nov 20 17:55:00 UTC 2012 < Wed Nov 28 17:53:45 UTC 2012'
321
+
322
+ errors = [time_1, time_2].map do |time|
323
+ "Current time is earlier than NotBefore condition (#{time})"
324
+ end
325
+
326
+ assert_predicate response.errors & errors, :any?
322
327
  end
323
328
  end
324
329
 
@@ -344,7 +349,7 @@ class XmlSecurityTest < Minitest::Test
344
349
  assert document.validate_document(fingerprint, true), 'Document should be valid'
345
350
  end
346
351
  end
347
-
352
+
348
353
  describe 'when response has signed assertion' do
349
354
  let(:document_data) { read_response('response_with_signed_assertion_3.xml') }
350
355
  let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
@@ -388,5 +393,29 @@ class XmlSecurityTest < Minitest::Test
388
393
  end
389
394
  end
390
395
  end
396
+
397
+ describe '#validate_document_with_cert' do
398
+ describe 'with valid document ' do
399
+ describe 'when response has cert' do
400
+ let(:document_data) { read_response('response_with_signed_message_and_assertion.xml') }
401
+ let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
402
+ let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
403
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
404
+
405
+ it 'is valid' do
406
+ assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
407
+ end
408
+ end
409
+
410
+ describe 'when response has no cert but you have local cert' do
411
+ let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
412
+ let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
413
+
414
+ it 'is valid' do
415
+ assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
416
+ end
417
+ end
418
+ end
419
+ end
391
420
  end
392
421
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-saml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OneLogin LLC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-18 00:00:00.000000000 Z
11
+ date: 2017-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -218,6 +218,7 @@ files:
218
218
  - test/metadata/idp_descriptor_2.xml
219
219
  - test/metadata/idp_descriptor_3.xml
220
220
  - test/metadata/idp_multiple_descriptors.xml
221
+ - test/metadata/no_idp_descriptor.xml
221
222
  - test/metadata_test.rb
222
223
  - test/request_test.rb
223
224
  - test/response_test.rb
@@ -263,6 +264,7 @@ files:
263
264
  - test/responses/no_signature_ns.xml
264
265
  - test/responses/open_saml_response.xml
265
266
  - test/responses/response_assertion_wrapped.xml.base64
267
+ - test/responses/response_double_status_code.xml.base64
266
268
  - test/responses/response_encrypted_attrs.xml.base64
267
269
  - test/responses/response_encrypted_nameid.xml.base64
268
270
  - test/responses/response_eval.xml
@@ -290,6 +292,7 @@ files:
290
292
  - test/responses/simple_saml_php.xml
291
293
  - test/responses/starfield_response.xml.base64
292
294
  - test/responses/test_sign.xml
295
+ - test/responses/unsigned_encrypted_adfs.xml
293
296
  - test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64
294
297
  - test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64
295
298
  - test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64
@@ -327,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
327
330
  version: '0'
328
331
  requirements: []
329
332
  rubyforge_project: http://www.rubygems.org/gems/ruby-saml
330
- rubygems_version: 2.4.8
333
+ rubygems_version: 2.5.1
331
334
  signing_key:
332
335
  specification_version: 4
333
336
  summary: SAML Ruby Tookit
@@ -363,6 +366,7 @@ test_files:
363
366
  - test/metadata/idp_descriptor_2.xml
364
367
  - test/metadata/idp_descriptor_3.xml
365
368
  - test/metadata/idp_multiple_descriptors.xml
369
+ - test/metadata/no_idp_descriptor.xml
366
370
  - test/metadata_test.rb
367
371
  - test/request_test.rb
368
372
  - test/response_test.rb
@@ -408,6 +412,7 @@ test_files:
408
412
  - test/responses/no_signature_ns.xml
409
413
  - test/responses/open_saml_response.xml
410
414
  - test/responses/response_assertion_wrapped.xml.base64
415
+ - test/responses/response_double_status_code.xml.base64
411
416
  - test/responses/response_encrypted_attrs.xml.base64
412
417
  - test/responses/response_encrypted_nameid.xml.base64
413
418
  - test/responses/response_eval.xml
@@ -435,6 +440,7 @@ test_files:
435
440
  - test/responses/simple_saml_php.xml
436
441
  - test/responses/starfield_response.xml.base64
437
442
  - test/responses/test_sign.xml
443
+ - test/responses/unsigned_encrypted_adfs.xml
438
444
  - test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64
439
445
  - test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64
440
446
  - test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64