ruby-saml 0.8.9 → 0.8.14

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (42) hide show
  1. data/Gemfile +11 -1
  2. data/Rakefile +0 -14
  3. data/lib/onelogin/ruby-saml/authrequest.rb +84 -18
  4. data/lib/onelogin/ruby-saml/logoutrequest.rb +93 -18
  5. data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -24
  6. data/lib/onelogin/ruby-saml/response.rb +206 -11
  7. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  8. data/lib/onelogin/ruby-saml/settings.rb +73 -12
  9. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
  10. data/lib/onelogin/ruby-saml/utils.rb +169 -0
  11. data/lib/onelogin/ruby-saml/version.rb +1 -1
  12. data/lib/ruby-saml.rb +2 -1
  13. data/lib/xml_security.rb +332 -78
  14. data/test/certificates/ruby-saml-2.crt +15 -0
  15. data/test/certificates/ruby-saml.crt +14 -0
  16. data/test/certificates/ruby-saml.key +15 -0
  17. data/test/logoutrequest_test.rb +177 -44
  18. data/test/logoutresponse_test.rb +23 -28
  19. data/test/request_test.rb +100 -37
  20. data/test/response_test.rb +337 -129
  21. data/test/responses/adfs_response_xmlns.xml +45 -0
  22. data/test/responses/encrypted_new_attack.xml.base64 +1 -0
  23. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  24. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  25. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
  26. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
  27. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
  28. data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
  29. data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
  30. data/test/responses/response_with_signed_assertion_3.xml +30 -0
  31. data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
  32. data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
  33. data/test/responses/response_wrapped.xml.base64 +150 -0
  34. data/test/responses/valid_response.xml.base64 +1 -0
  35. data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
  36. data/test/settings_test.rb +5 -5
  37. data/test/slo_logoutresponse_test.rb +226 -0
  38. data/test/test_helper.rb +117 -12
  39. data/test/utils_test.rb +10 -10
  40. data/test/xml_security_test.rb +354 -68
  41. metadata +64 -18
  42. checksums.yaml +0 -7
@@ -1,11 +1,15 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class RequestTest < Test::Unit::TestCase
3
+ class RequestTest < Minitest::Test
4
4
 
5
- context "Authrequest" do
6
- should "create the deflated SAMLRequest URL parameter" do
7
- settings = OneLogin::RubySaml::Settings.new
5
+ describe "Authrequest" do
6
+ let(:settings) { OneLogin::RubySaml::Settings.new }
7
+
8
+ before do
8
9
  settings.idp_sso_target_url = "http://example.com"
10
+ end
11
+
12
+ it "create the deflated SAMLRequest URL parameter" do
9
13
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
10
14
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
11
15
  payload = CGI.unescape(auth_url.split("=").last)
@@ -19,9 +23,7 @@ class RequestTest < Test::Unit::TestCase
19
23
  assert_match /^<samlp:AuthnRequest/, inflated
20
24
  end
21
25
 
22
- should "create the deflated SAMLRequest URL parameter including the Destination" do
23
- settings = OneLogin::RubySaml::Settings.new
24
- settings.idp_sso_target_url = "http://example.com"
26
+ it "create the deflated SAMLRequest URL parameter including the Destination" do
25
27
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
26
28
  payload = CGI.unescape(auth_url.split("=").last)
27
29
  decoded = Base64.decode64(payload)
@@ -34,10 +36,8 @@ class RequestTest < Test::Unit::TestCase
34
36
  assert_match /<samlp:AuthnRequest[^<]* Destination='http:\/\/example.com'/, inflated
35
37
  end
36
38
 
37
- should "create the SAMLRequest URL parameter without deflating" do
38
- settings = OneLogin::RubySaml::Settings.new
39
+ it "create the SAMLRequest URL parameter without deflating" do
39
40
  settings.compress_request = false
40
- settings.idp_sso_target_url = "http://example.com"
41
41
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
42
42
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
43
43
  payload = CGI.unescape(auth_url.split("=").last)
@@ -46,9 +46,7 @@ class RequestTest < Test::Unit::TestCase
46
46
  assert_match /^<samlp:AuthnRequest/, decoded
47
47
  end
48
48
 
49
- should "create the SAMLRequest URL parameter with IsPassive" do
50
- settings = OneLogin::RubySaml::Settings.new
51
- settings.idp_sso_target_url = "http://example.com"
49
+ it "create the SAMLRequest URL parameter with IsPassive" do
52
50
  settings.passive = true
53
51
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
54
52
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
@@ -63,9 +61,7 @@ class RequestTest < Test::Unit::TestCase
63
61
  assert_match /<samlp:AuthnRequest[^<]* IsPassive='true'/, inflated
64
62
  end
65
63
 
66
- should "create the SAMLRequest URL parameter with ProtocolBinding" do
67
- settings = OneLogin::RubySaml::Settings.new
68
- settings.idp_sso_target_url = "http://example.com"
64
+ it "create the SAMLRequest URL parameter with ProtocolBinding" do
69
65
  settings.protocol_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
70
66
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
71
67
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
@@ -80,9 +76,7 @@ class RequestTest < Test::Unit::TestCase
80
76
  assert_match /<samlp:AuthnRequest[^<]* ProtocolBinding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'/, inflated
81
77
  end
82
78
 
83
- should "create the SAMLRequest URL parameter with ForceAuthn" do
84
- settings = OneLogin::RubySaml::Settings.new
85
- settings.idp_sso_target_url = "http://example.com"
79
+ it "create the SAMLRequest URL parameter with ForceAuthn" do
86
80
  settings.force_authn = true
87
81
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
88
82
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
@@ -96,9 +90,7 @@ class RequestTest < Test::Unit::TestCase
96
90
  assert_match /<samlp:AuthnRequest[^<]* ForceAuthn='true'/, inflated
97
91
  end
98
92
 
99
- should "create the SAMLRequest URL parameter with NameID Format" do
100
- settings = OneLogin::RubySaml::Settings.new
101
- settings.idp_sso_target_url = "http://example.com"
93
+ it "create the SAMLRequest URL parameter with NameID Format" do
102
94
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
103
95
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
104
96
  assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
@@ -113,9 +105,7 @@ class RequestTest < Test::Unit::TestCase
113
105
  assert_match /<samlp:NameIDPolicy[^<]* Format='urn:oasis:names:tc:SAML:2.0:nameid-format:transient'/, inflated
114
106
  end
115
107
 
116
- should "create the SAMLRequest URL parameter with Subject" do
117
- settings = OneLogin::RubySaml::Settings.new
118
- settings.idp_sso_target_url = "http://example.com"
108
+ it "create the SAMLRequest URL parameter with Subject" do
119
109
  settings.name_identifier_value_requested = "testuser@example.com"
120
110
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
121
111
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
@@ -132,10 +122,7 @@ class RequestTest < Test::Unit::TestCase
132
122
  assert inflated.include?("<saml:SubjectConfirmation Method='urn:oasis:names:tc:SAML:2.0:cm:bearer'/>")
133
123
  end
134
124
 
135
- should "accept extra parameters" do
136
- settings = OneLogin::RubySaml::Settings.new
137
- settings.idp_sso_target_url = "http://example.com"
138
-
125
+ it "accept extra parameters" do
139
126
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :hello => "there" })
140
127
  assert auth_url =~ /&hello=there$/
141
128
 
@@ -143,24 +130,100 @@ class RequestTest < Test::Unit::TestCase
143
130
  assert auth_url =~ /&hello=$/
144
131
  end
145
132
 
146
- context "when the target url doesn't contain a query string" do
147
- should "create the SAMLRequest parameter correctly" do
148
- settings = OneLogin::RubySaml::Settings.new
149
- settings.idp_sso_target_url = "http://example.com"
150
-
133
+ describe "when the target url doesn't contain a query string" do
134
+ it "create the SAMLRequest parameter correctly" do
151
135
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
152
136
  assert auth_url =~ /^http:\/\/example.com\?SAMLRequest/
153
137
  end
154
138
  end
155
139
 
156
- context "when the target url contains a query string" do
157
- should "create the SAMLRequest parameter correctly" do
158
- settings = OneLogin::RubySaml::Settings.new
140
+ describe "when the target url contains a query string" do
141
+ it "create the SAMLRequest parameter correctly" do
159
142
  settings.idp_sso_target_url = "http://example.com?field=value"
160
143
 
161
144
  auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
162
145
  assert auth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
163
146
  end
164
147
  end
148
+
149
+ describe "#create_params when the settings indicate to sign (embebed) the request" do
150
+ before do
151
+ settings.compress_request = false
152
+ settings.idp_sso_target_url = "http://example.com?field=value"
153
+ settings.security[:authn_requests_signed] = true
154
+ settings.security[:embed_sign] = true
155
+ settings.certificate = ruby_saml_cert_text
156
+ settings.private_key = ruby_saml_key_text
157
+ end
158
+
159
+ it "create a signed request" do
160
+ params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
161
+ request_xml = Base64.decode64(params["SAMLRequest"])
162
+ assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
163
+ assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], request_xml
164
+ end
165
+
166
+ it "create a signed request with 256 digest and signature methods" do
167
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
168
+ settings.security[:digest_method] = XMLSecurity::Document::SHA512
169
+
170
+ params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
171
+
172
+ request_xml = Base64.decode64(params["SAMLRequest"])
173
+ assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
174
+ assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
175
+ assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha512'/>], request_xml
176
+ end
177
+ end
178
+
179
+ describe "#create_params when the settings indicate to sign the request" do
180
+ let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
181
+
182
+ before do
183
+ settings.compress_request = false
184
+ settings.idp_sso_target_url = "http://example.com?field=value"
185
+ settings.security[:authn_requests_signed] = true
186
+ settings.security[:embed_sign] = false
187
+ settings.certificate = ruby_saml_cert_text
188
+ settings.private_key = ruby_saml_key_text
189
+ end
190
+
191
+ it "create a signature parameter with RSA_SHA1 and validate it" do
192
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
193
+
194
+ params = OneLogin::RubySaml::Authrequest.new.create_params(settings, :RelayState => 'http://example.com')
195
+ assert params['SAMLRequest']
196
+ assert params[:RelayState]
197
+ assert params['Signature']
198
+ assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
199
+
200
+ query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
201
+ query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
202
+ query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
203
+
204
+ signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
205
+ assert_equal signature_algorithm, OpenSSL::Digest::SHA1
206
+
207
+ assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
208
+ end
209
+
210
+ it "create a signature parameter with RSA_SHA256 and validate it" do
211
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
212
+
213
+ params = OneLogin::RubySaml::Authrequest.new.create_params(settings, :RelayState => 'http://example.com')
214
+ assert params['Signature']
215
+ assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
216
+
217
+ query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
218
+ query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
219
+ query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
220
+
221
+ signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
222
+ assert_equal signature_algorithm, OpenSSL::Digest::SHA256
223
+ assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
224
+ end
225
+ end
226
+
165
227
  end
228
+
166
229
  end
@@ -1,13 +1,16 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class RubySamlTest < Test::Unit::TestCase
3
+ class ResponseTest < Minitest::Test
4
4
 
5
- context "Response" do
6
- should "raise an exception when response is initialized with nil" do
7
- assert_raises(ArgumentError) { OneLogin::RubySaml::Response.new(nil) }
5
+ describe "Response" do
6
+ it "raise an exception when response is initialized with nil" do
7
+ err = assert_raises(ArgumentError) do
8
+ OneLogin::RubySaml::Response.new(nil)
9
+ end
10
+ assert_equal "Response cannot be nil", err.message
8
11
  end
9
12
 
10
- should "be able to parse a document which contains ampersands" do
13
+ it "be able to parse a document which contains ampersands" do
11
14
  XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
12
15
  OneLogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
13
16
 
@@ -18,7 +21,7 @@ class RubySamlTest < Test::Unit::TestCase
18
21
  response.validate!
19
22
  end
20
23
 
21
- should "adapt namespace" do
24
+ it "adapt namespace" do
22
25
  response = OneLogin::RubySaml::Response.new(response_document)
23
26
  assert !response.name_id.nil?
24
27
  response = OneLogin::RubySaml::Response.new(response_document_2)
@@ -27,14 +30,14 @@ class RubySamlTest < Test::Unit::TestCase
27
30
  assert !response.name_id.nil?
28
31
  end
29
32
 
30
- should "default to raw input when a response is not Base64 encoded" do
33
+ it "default to raw input when a response is not Base64 encoded" do
31
34
  decoded = Base64.decode64(response_document_2)
32
35
  response = OneLogin::RubySaml::Response.new(decoded)
33
36
  assert response.document
34
37
  end
35
38
 
36
- context "Assertion" do
37
- should "only retreive an assertion with an ID that matches the signature's reference URI" do
39
+ describe "Assertion" do
40
+ it "only retreive an assertion with an ID that matches the signature's reference URI" do
38
41
  response = OneLogin::RubySaml::Response.new(wrapped_response_2)
39
42
  response.stubs(:conditions).returns(nil)
40
43
  settings = OneLogin::RubySaml::Settings.new
@@ -44,40 +47,109 @@ class RubySamlTest < Test::Unit::TestCase
44
47
  end
45
48
  end
46
49
 
47
- context "#validate!" do
48
- should "raise when encountering a condition that prevents the document from being valid" do
50
+ describe "#validate!" do
51
+ it "raise when settings not initialized" do
49
52
  response = OneLogin::RubySaml::Response.new(response_document)
50
- assert_raise(OneLogin::RubySaml::ValidationError) do
53
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
51
54
  response.validate!
52
55
  end
56
+ assert_equal "No settings on response", err.message
53
57
  end
58
+
59
+ it "raise when encountering a condition that prevents the document from being valid" do
60
+ response = OneLogin::RubySaml::Response.new(response_document)
61
+ response.settings = settings
62
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
63
+ response.validate!
64
+ end
65
+ assert_equal "Current time is on or after NotOnOrAfter condition", err.message
66
+ end
67
+
68
+ it "raises an exception when no cert or fingerprint provided" do
69
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
70
+ response.stubs(:conditions).returns(nil)
71
+ settings = OneLogin::RubySaml::Settings.new
72
+ response.settings = settings
73
+ settings.idp_cert = nil
74
+ settings.idp_cert_fingerprint = nil
75
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
76
+ response.validate!
77
+ end
78
+ assert_equal "No fingerprint or certificate on settings", err.message
79
+ end
80
+
81
+ it "raise when no signature" do
82
+ response_no_signed_elements = OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64"))
83
+ settings.idp_cert_fingerprint = signature_fingerprint_1
84
+ response_no_signed_elements.settings = settings
85
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
86
+ response_no_signed_elements.validate!
87
+ end
88
+ assert_equal "Found an unexpected number of Signature Element. SAML Response rejected", err.message
89
+ end
90
+
91
+ it "raise when multiple signatures" do
92
+ response_multiple_signed = OneLogin::RubySaml::Response.new(read_invalid_response("multiple_signed.xml.base64"))
93
+ settings.idp_cert_fingerprint = signature_fingerprint_1
94
+ response_multiple_signed.settings = settings
95
+ response_multiple_signed.stubs(:validate_structure).returns(true)
96
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
97
+ response_multiple_signed.validate!
98
+ end
99
+ assert_equal "Duplicated ID. SAML Response rejected", err.message
100
+ end
101
+
102
+ it "raise when fingerprint missmatch" do
103
+ resp_xml = Base64.decode64(response_document_valid_signed)
104
+ response = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
105
+ response.stubs(:conditions).returns(nil)
106
+ settings = OneLogin::RubySaml::Settings.new
107
+ settings.idp_cert_fingerprint = signature_fingerprint_1
108
+ response.settings = settings
109
+
110
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
111
+ response.validate!
112
+ end
113
+ assert_equal 'Fingerprint mismatch', err.message
114
+ end
115
+
54
116
  end
55
117
 
56
- context "#is_valid?" do
57
- should "return false when response is initialized with blank data" do
118
+ describe "#is_valid?" do
119
+ it "return false when response is initialized with blank data" do
58
120
  response = OneLogin::RubySaml::Response.new('')
59
121
  assert !response.is_valid?
60
122
  end
61
123
 
62
- should "return false if settings have not been set" do
124
+ it "return false if settings have not been set" do
63
125
  response = OneLogin::RubySaml::Response.new(response_document)
64
126
  assert !response.is_valid?
65
127
  end
66
128
 
67
- should "return true when the response is initialized with valid data" do
68
- response = OneLogin::RubySaml::Response.new(response_document_4)
129
+ it "return false when no cert or fingerprint provided" do
130
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
131
+ response.stubs(:conditions).returns(nil)
132
+ settings = OneLogin::RubySaml::Settings.new
133
+ response.settings = settings
134
+ settings.idp_cert = nil
135
+ settings.idp_cert_fingerprint = nil
136
+ assert !response.is_valid?
137
+ end
138
+
139
+ it "return true when the response is initialized with valid data" do
140
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
69
141
  response.stubs(:conditions).returns(nil)
70
142
  assert !response.is_valid?
71
143
  settings = OneLogin::RubySaml::Settings.new
72
144
  assert !response.is_valid?
73
145
  response.settings = settings
74
146
  assert !response.is_valid?
75
- settings.idp_cert_fingerprint = signature_fingerprint_1
76
- assert response.is_valid?
147
+ response.settings.idp_cert_fingerprint = signature_fingerprint_valid_res
148
+ response.validate!
77
149
  end
78
150
 
79
- should "should be idempotent when the response is initialized with invalid data" do
80
- response = OneLogin::RubySaml::Response.new(response_document_4)
151
+ it "should be idempotent when the response is initialized with invalid data" do
152
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
81
153
  response.stubs(:conditions).returns(nil)
82
154
  settings = OneLogin::RubySaml::Settings.new
83
155
  response.settings = settings
@@ -85,36 +157,58 @@ class RubySamlTest < Test::Unit::TestCase
85
157
  assert !response.is_valid?
86
158
  end
87
159
 
88
- should "should be idempotent when the response is initialized with valid data" do
89
- response = OneLogin::RubySaml::Response.new(response_document_4)
160
+ it "should be idempotent when the response is initialized with valid data" do
161
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
90
162
  response.stubs(:conditions).returns(nil)
91
163
  settings = OneLogin::RubySaml::Settings.new
92
164
  response.settings = settings
93
- settings.idp_cert_fingerprint = signature_fingerprint_1
165
+ response.settings.idp_cert_fingerprint = signature_fingerprint_valid_res
94
166
  assert response.is_valid?
95
167
  assert response.is_valid?
96
168
  end
97
169
 
98
- should "return true when using certificate instead of fingerprint" do
99
- response = OneLogin::RubySaml::Response.new(response_document_4)
170
+ it "return true when valid response and using fingerprint" do
171
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
172
+ response.stubs(:conditions).returns(nil)
173
+ settings = OneLogin::RubySaml::Settings.new
174
+ response.settings = settings
175
+ settings.idp_cert = nil
176
+ settings.idp_cert_fingerprint = "4B:68:C4:53:C7:D9:94:AA:D9:02:5C:99:D5:EF:CF:56:62:87:FE:8D"
177
+ assert response.is_valid?
178
+ end
179
+
180
+ it "return true when valid response using certificate" do
181
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
100
182
  response.stubs(:conditions).returns(nil)
101
183
  settings = OneLogin::RubySaml::Settings.new
102
184
  response.settings = settings
103
- settings.idp_cert = signature_1
185
+ settings.idp_cert = valid_cert
104
186
  assert response.is_valid?
105
187
  end
106
188
 
107
- should "not allow signature wrapping attack" do
189
+ it "not allow signature wrapping attack" do
108
190
  response = OneLogin::RubySaml::Response.new(response_document_4)
109
191
  response.stubs(:conditions).returns(nil)
110
192
  settings = OneLogin::RubySaml::Settings.new
111
193
  settings.idp_cert_fingerprint = signature_fingerprint_1
112
194
  response.settings = settings
113
- assert response.is_valid?
195
+ assert !response.is_valid?
114
196
  assert response.name_id == "test@onelogin.com"
115
197
  end
116
198
 
117
- should "support dynamic namespace resolution on signature elements" do
199
+ it "not allow element wrapping attack" do
200
+ response_wrapped = OneLogin::RubySaml::Response.new(response_document_wrapped)
201
+ response_wrapped.stubs(:conditions).returns(nil)
202
+ response_wrapped.stubs(:validate_subject_confirmation).returns(true)
203
+ settings = OneLogin::RubySaml::Settings.new
204
+ response_wrapped.settings = settings
205
+ response_wrapped.settings.idp_cert_fingerprint = signature_fingerprint_1
206
+
207
+ assert !response_wrapped.is_valid?
208
+ assert_nil response_wrapped.name_id
209
+ end
210
+
211
+ it "support dynamic namespace resolution on signature elements" do
118
212
  response = OneLogin::RubySaml::Response.new(fixture("no_signature_ns.xml"))
119
213
  response.stubs(:conditions).returns(nil)
120
214
  settings = OneLogin::RubySaml::Settings.new
@@ -124,35 +218,59 @@ class RubySamlTest < Test::Unit::TestCase
124
218
  assert response.validate!
125
219
  end
126
220
 
127
- should "validate ADFS assertions" do
128
- response = OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
221
+ it "support signature elements with no KeyInfo if cert provided" do
222
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
129
223
  response.stubs(:conditions).returns(nil)
130
224
  settings = OneLogin::RubySaml::Settings.new
131
- settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
132
225
  response.settings = settings
226
+ settings.idp_cert = ruby_saml_cert
227
+ settings.idp_cert_fingerprint = nil
228
+ XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
133
229
  assert response.validate!
134
230
  end
135
231
 
136
- should "validate the digest" do
137
- response = OneLogin::RubySaml::Response.new(r1_response_document_6)
232
+ it "returns an error if the signature contains no KeyInfo, cert is not provided and soft" do
233
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
234
+ response.stubs(:conditions).returns(nil)
235
+ settings = OneLogin::RubySaml::Settings.new
236
+ response.settings = settings
237
+ settings.idp_cert = nil
238
+ settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
239
+ assert !response.is_valid?
240
+ end
241
+
242
+ it "raises an exception if the signature contains no KeyInfo, cert is not provided and no soft" do
243
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
138
244
  response.stubs(:conditions).returns(nil)
139
245
  settings = OneLogin::RubySaml::Settings.new
140
- settings.idp_cert = Base64.decode64(r1_signature_2)
246
+ response.settings = settings
247
+ settings.idp_cert = nil
248
+ settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
249
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
250
+ response.validate!
251
+ end
252
+ assert_equal "Certificate element missing in response (ds:X509Certificate) and not cert provided at settings", err.message
253
+ end
254
+
255
+ it "validate ADFS assertions" do
256
+ response = OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
257
+ response.stubs(:conditions).returns(nil)
258
+ settings = OneLogin::RubySaml::Settings.new
259
+ settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
141
260
  response.settings = settings
142
261
  assert response.validate!
143
262
  end
144
263
 
145
- should "validate SAML 2.0 XML structure" do
146
- resp_xml = Base64.decode64(response_document_4).gsub(/emailAddress/,'test')
147
- response = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
264
+ it "validate the digest" do
265
+ response = OneLogin::RubySaml::Response.new(r1_response_document_6)
148
266
  response.stubs(:conditions).returns(nil)
149
267
  settings = OneLogin::RubySaml::Settings.new
150
- settings.idp_cert_fingerprint = signature_fingerprint_1
268
+ settings.idp_cert = Base64.decode64(r1_signature_2)
151
269
  response.settings = settings
152
- assert_raises(OneLogin::RubySaml::ValidationError, 'Digest mismatch'){ response.validate! }
270
+ assert response.validate!
153
271
  end
154
272
 
155
- should "Prevent node text with comment (VU#475445) attack" do
273
+ it "Prevent node text with comment (VU#475445) attack" do
156
274
  response_doc = File.read(File.join(File.dirname(__FILE__), "responses", 'response_node_text_attack.xml.base64'))
157
275
  response = OneLogin::RubySaml::Response.new(response_doc)
158
276
 
@@ -160,42 +278,42 @@ class RubySamlTest < Test::Unit::TestCase
160
278
  assert_equal "smith", response.attributes["surname"]
161
279
  end
162
280
 
163
- context '#validate_audience' do
164
- should "return true when sp_entity_id not set or empty" do
165
- response = OneLogin::RubySaml::Response.new(response_document_4)
281
+ describe '#validate_audience' do
282
+ it "return true when sp_entity_id not set or empty" do
283
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
166
284
  response.stubs(:conditions).returns(nil)
167
285
  settings = OneLogin::RubySaml::Settings.new
168
286
  response.settings = settings
169
- settings.idp_cert_fingerprint = signature_fingerprint_1
287
+ settings.idp_cert_fingerprint = signature_fingerprint_valid_res
170
288
  assert response.is_valid?
171
289
  settings.sp_entity_id = ''
172
290
  assert response.is_valid?
173
291
  end
174
292
 
175
- should "return false when sp_entity_id set to incorrectly" do
176
- response = OneLogin::RubySaml::Response.new(response_document_4)
293
+ it "return false when sp_entity_id set to incorrectly" do
294
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
177
295
  response.stubs(:conditions).returns(nil)
178
296
  settings = OneLogin::RubySaml::Settings.new
179
297
  response.settings = settings
180
- settings.idp_cert_fingerprint = signature_fingerprint_1
298
+ settings.idp_cert_fingerprint = signature_fingerprint_valid_res
181
299
  settings.sp_entity_id = 'wrong_audience'
182
300
  assert !response.is_valid?
183
301
  end
184
302
 
185
- should "return true when sp_entity_id set to correctly" do
186
- response = OneLogin::RubySaml::Response.new(response_document_4)
303
+ it "return true when sp_entity_id set to correctly" do
304
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
187
305
  response.stubs(:conditions).returns(nil)
188
306
  settings = OneLogin::RubySaml::Settings.new
189
307
  response.settings = settings
190
- settings.idp_cert_fingerprint = signature_fingerprint_1
191
- settings.sp_entity_id = 'audience'
308
+ settings.idp_cert_fingerprint = signature_fingerprint_valid_res
309
+ settings.sp_entity_id = 'https://someone.example.com/audience'
192
310
  assert response.is_valid?
193
311
  end
194
312
  end
195
313
  end
196
314
 
197
- context "#name_id" do
198
- should "extract the value of the name id element" do
315
+ describe "#name_id" do
316
+ it "extract the value of the name id element" do
199
317
  response = OneLogin::RubySaml::Response.new(response_document)
200
318
  assert_equal "support@onelogin.com", response.name_id
201
319
 
@@ -203,19 +321,19 @@ class RubySamlTest < Test::Unit::TestCase
203
321
  assert_equal "someone@example.com", response.name_id
204
322
  end
205
323
 
206
- should "be extractable from an OpenSAML response" do
324
+ it "be extractable from an OpenSAML response" do
207
325
  response = OneLogin::RubySaml::Response.new(fixture(:open_saml))
208
326
  assert_equal "someone@example.org", response.name_id
209
327
  end
210
328
 
211
- should "be extractable from a Simple SAML PHP response" do
329
+ it "be extractable from a Simple SAML PHP response" do
212
330
  response = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
213
331
  assert_equal "someone@example.com", response.name_id
214
332
  end
215
333
  end
216
334
 
217
- context "#check_conditions" do
218
- should "check time conditions" do
335
+ describe "#check_conditions" do
336
+ it "check time conditions" do
219
337
  response = OneLogin::RubySaml::Response.new(response_document)
220
338
  assert !response.send(:validate_conditions, true)
221
339
  response = OneLogin::RubySaml::Response.new(response_document_6)
@@ -226,75 +344,122 @@ class RubySamlTest < Test::Unit::TestCase
226
344
  assert response.send(:validate_conditions, true)
227
345
  end
228
346
 
229
- should "optionally allow for clock drift" do
347
+ it "optionally allow for clock drift" do
230
348
  # The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
231
- Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
349
+ expected_time = Time.parse("2011-06-14T18:21:01Z")
350
+ Time.stubs(:now).returns(expected_time)
232
351
  response = OneLogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.515)
233
352
  assert !response.send(:validate_conditions, true)
234
353
 
235
- Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
354
+ expected_time = Time.parse("2011-06-14T18:21:01Z")
355
+ Time.stubs(:now).returns(expected_time)
236
356
  response = OneLogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.516)
237
357
  assert response.send(:validate_conditions, true)
238
358
  end
239
359
  end
240
360
 
241
- context "#attributes" do
242
- should "extract the first attribute in a hash accessed via its symbol" do
243
- response = OneLogin::RubySaml::Response.new(response_document)
244
- assert_equal "demo", response.attributes[:uid]
361
+ describe "validate_signature" do
362
+ it "raises an exception when no cert or fingerprint provided" do
363
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
364
+ settings = OneLogin::RubySaml::Settings.new
365
+ response.settings = settings
366
+ settings.idp_cert = nil
367
+ settings.idp_cert_fingerprint = nil
368
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
369
+ response.send(:validate_signature, false)
370
+ end
371
+ assert_equal "No fingerprint or certificate on settings", err.message
245
372
  end
246
373
 
247
- should "extract the first attribute in a hash accessed via its name" do
248
- response = OneLogin::RubySaml::Response.new(response_document)
249
- assert_equal "demo", response.attributes["uid"]
374
+ it "raises an exception when wrong cert provided" do
375
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
376
+ settings = OneLogin::RubySaml::Settings.new
377
+ response.settings = settings
378
+ settings.idp_cert = ruby_saml_cert2
379
+ settings.idp_cert_fingerprint = nil
380
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
381
+ response.send(:validate_signature, false)
382
+ end
383
+ assert_equal "Fingerprint mismatch", err.message
250
384
  end
251
385
 
252
- should "extract all attributes" do
253
- response = OneLogin::RubySaml::Response.new(response_document)
254
- assert_equal "demo", response.attributes[:uid]
255
- assert_equal "value", response.attributes[:another_value]
386
+ it "raises an exception when wrong fingerprint provided" do
387
+ response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
388
+ settings = OneLogin::RubySaml::Settings.new
389
+ response.settings = settings
390
+ settings.idp_cert = nil
391
+ settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
392
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
393
+ response.send(:validate_signature, false)
394
+ end
395
+ assert_equal "Fingerprint mismatch", err.message
256
396
  end
257
397
 
258
- should "work for implicit namespaces" do
259
- response = OneLogin::RubySaml::Response.new(response_document_3)
260
- assert_equal "someone@example.com", response.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
398
+ it "raises an exception when no signature" do
399
+ response_no_signed_elements = OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64"))
400
+ settings.idp_cert_fingerprint = signature_fingerprint_1
401
+ response_no_signed_elements.settings = settings
402
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
403
+ response_no_signed_elements.validate!
404
+ end
405
+ assert_equal "Found an unexpected number of Signature Element. SAML Response rejected", err.message
406
+ end
407
+ end
408
+
409
+ describe "#attributes" do
410
+ before do
411
+ @response = OneLogin::RubySaml::Response.new(response_document)
261
412
  end
262
413
 
263
- should "not raise on responses without attributes" do
264
- response = OneLogin::RubySaml::Response.new(response_document_4)
265
- assert_equal OneLogin::RubySaml::Attributes.new, response.attributes
414
+ it "extract the first attribute in a hash accessed via its symbol" do
415
+ assert_equal "demo", @response.attributes[:uid]
416
+ end
417
+
418
+ it "extract the first attribute in a hash accessed via its name" do
419
+ assert_equal "demo", @response.attributes["uid"]
420
+ end
421
+
422
+ it "extract all attributes" do
423
+ assert_equal "demo", @response.attributes[:uid]
424
+ assert_equal "value", @response.attributes[:another_value]
425
+ end
426
+
427
+ it "work for implicit namespaces" do
428
+ response_3 = OneLogin::RubySaml::Response.new(response_document_3)
429
+ assert_equal "someone@example.com", response_3.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
430
+ end
431
+
432
+ it "not raise on responses without attributes" do
433
+ response_4 = OneLogin::RubySaml::Response.new(response_document_4)
434
+ assert_equal OneLogin::RubySaml::Attributes.new, response_4.attributes
266
435
  end
267
436
 
268
- should "extract attributes from all AttributeStatement tags" do
437
+ it "extract attributes from all AttributeStatement tags" do
269
438
  assert_equal "smith", response_with_multiple_attribute_statements.attributes[:surname]
270
439
  assert_equal "bob", response_with_multiple_attribute_statements.attributes[:firstname]
271
440
  end
272
441
 
273
- should "be manipulable by hash methods such as #merge and not raise an exception" do
274
- response = OneLogin::RubySaml::Response.new(response_document)
275
- response.attributes.merge({ :testing_attribute => "test" })
442
+ it "be manipulable by hash methods such as #merge and not raise an exception" do
443
+ @response.attributes.merge({ :testing_attribute => "test" })
276
444
  end
277
445
 
278
- should "be manipulable by hash methods such as #shift and not raise an exception" do
279
- response = OneLogin::RubySaml::Response.new(response_document)
280
- response.attributes.shift
446
+ it "be manipulable by hash methods such as #shift and not raise an exception" do
447
+ @response.attributes.shift
281
448
  end
282
449
 
283
- should "be manipulable by hash methods such as #merge! and actually contain the value" do
284
- response = OneLogin::RubySaml::Response.new(response_document)
285
- response.attributes.merge!({ :testing_attribute => "test" })
286
- assert response.attributes[:testing_attribute]
450
+ it "be manipulable by hash methods such as #merge! and actually contain the value" do
451
+ @response.attributes.merge!({ :testing_attribute => "test" })
452
+ assert @response.attributes[:testing_attribute]
287
453
  end
288
454
 
289
- should "be manipulable by hash methods such as #shift and actually remove the value" do
290
- response = OneLogin::RubySaml::Response.new(response_document)
291
- removed_value = response.attributes.shift
292
- assert_nil response.attributes[removed_value[0]]
455
+ it "be manipulable by hash methods such as #shift and actually remove the value" do
456
+ removed_value = @response.attributes.shift
457
+ assert_nil @response.attributes[removed_value[0]]
293
458
  end
294
459
  end
295
460
 
296
- context "#session_expires_at" do
297
- should "extract the value of the SessionNotOnOrAfter attribute" do
461
+ describe "#session_expires_at" do
462
+ it "extract the value of the SessionNotOnOrAfter attribute" do
298
463
  response = OneLogin::RubySaml::Response.new(response_document)
299
464
  assert response.session_expires_at.is_a?(Time)
300
465
 
@@ -303,124 +468,167 @@ class RubySamlTest < Test::Unit::TestCase
303
468
  end
304
469
  end
305
470
 
306
- context "#issuer" do
307
- should "return the issuer inside the response assertion" do
471
+ describe "#issuer" do
472
+ it "return the issuer inside the response assertion" do
308
473
  response = OneLogin::RubySaml::Response.new(response_document)
309
474
  assert_equal "https://app.onelogin.com/saml/metadata/13590", response.issuer
310
475
  end
311
476
 
312
- should "return the issuer inside the response" do
477
+ it "return the issuer inside the response" do
313
478
  response = OneLogin::RubySaml::Response.new(response_document_2)
314
479
  assert_equal "wibble", response.issuer
315
480
  end
316
481
  end
317
482
 
318
- context "#success" do
319
- should "find a status code that says success" do
483
+ describe "#success" do
484
+ it "find a status code that says success" do
320
485
  response = OneLogin::RubySaml::Response.new(response_document)
321
- response.success?
486
+ assert response.send(:success?)
322
487
  end
323
488
  end
324
489
 
325
- context '#xpath_first_from_signed_assertion' do
326
- should 'not allow arbitrary code execution' do
490
+ describe '#xpath_first_from_signed_assertion' do
491
+ it 'not allow arbitrary code execution' do
327
492
  malicious_response_document = fixture('response_eval', false)
328
493
  response = OneLogin::RubySaml::Response.new(malicious_response_document)
329
494
  response.send(:xpath_first_from_signed_assertion)
330
- assert_equal($evalled, nil)
495
+ assert_nil $evalled
331
496
  end
332
497
  end
333
498
 
334
- context "#multiple values" do
335
- should "extract single value as string" do
499
+ describe "#multiple values" do
500
+ it "extract single value as string" do
336
501
  assert_equal "demo", response_multiple_attr_values.attributes[:uid]
337
502
  end
338
503
 
339
- should "extract single value as string in compatibility mode off" do
504
+ it "extract single value as string in compatibility mode off" do
340
505
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
341
506
  assert_equal ["demo"], response_multiple_attr_values.attributes[:uid]
342
507
  # classes are not reloaded between tests so restore default
343
508
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
344
509
  end
345
510
 
346
- should "extract first of multiple values as string for b/w compatibility" do
511
+ it "extract first of multiple values as string for b/w compatibility" do
347
512
  assert_equal 'value1', response_multiple_attr_values.attributes[:another_value]
348
513
  end
349
514
 
350
- should "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
515
+ it "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
351
516
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
352
517
  assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes[:another_value]
353
518
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
354
519
  end
355
520
 
356
- should "return array with all attributes when asked in XML order" do
521
+ it "return array with all attributes when asked in XML order" do
357
522
  assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
358
523
  end
359
524
 
360
- should "return array with all attributes when asked in XML order in compatibility mode off" do
525
+ it "return array with all attributes when asked in XML order in compatibility mode off" do
361
526
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
362
527
  assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
363
528
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
364
529
  end
365
530
 
366
- should "return first of multiple values when multiple Attribute tags in XML" do
531
+ it "return first of multiple values when multiple Attribute tags in XML" do
367
532
  assert_equal 'role1', response_multiple_attr_values.attributes[:role]
368
533
  end
369
534
 
370
- should "return first of multiple values when multiple Attribute tags in XML in compatibility mode off" do
535
+ it "return first of multiple values when multiple Attribute tags in XML in compatibility mode off" do
371
536
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
372
537
  assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes[:role]
373
538
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
374
539
  end
375
540
 
376
- should "return all of multiple values in reverse order when multiple Attribute tags in XML" do
541
+ it "return all of multiple values in reverse order when multiple Attribute tags in XML" do
377
542
  assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
378
543
  end
379
544
 
380
- should "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
545
+ it "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
381
546
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
382
547
  assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
383
548
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
384
549
  end
385
550
 
386
- should "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
551
+ it "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
387
552
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
388
553
  assert_equal ['role1', 'role2', 'role3'], response_with_multiple_attribute_statements.attributes.multi(:role)
389
554
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
390
555
  end
391
556
 
392
- should "return nil value correctly" do
557
+ it "return nil value correctly" do
393
558
  assert_nil response_multiple_attr_values.attributes[:attribute_with_nil_value]
394
559
  end
395
560
 
396
- should "return nil value correctly when not in compatibility mode off" do
561
+ it "return nil value correctly when not in compatibility mode off" do
397
562
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
398
- assert_equal [nil], response_multiple_attr_values.attributes[:attribute_with_nil_value]
563
+ assert [nil] == response_multiple_attr_values.attributes[:attribute_with_nil_value]
399
564
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
400
565
  end
401
566
 
402
- should "return multiple values including nil and empty string" do
567
+ it "return multiple values including nil and empty string" do
403
568
  response = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
404
569
  assert_equal ["", "valuePresent", nil, nil], response.attributes.multi(:attribute_with_nils_and_empty_strings)
405
570
  end
406
571
 
407
- should "return multiple values from [] when not in compatibility mode off" do
572
+ it "return multiple values from [] when not in compatibility mode off" do
408
573
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
409
574
  assert_equal ["", "valuePresent", nil, nil], response_multiple_attr_values.attributes[:attribute_with_nils_and_empty_strings]
410
575
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
411
576
  end
412
577
 
413
- should "check what happens when trying retrieve attribute that does not exists" do
414
- assert_equal nil, response_multiple_attr_values.attributes[:attribute_not_exists]
415
- assert_equal nil, response_multiple_attr_values.attributes.single(:attribute_not_exists)
416
- assert_equal nil, response_multiple_attr_values.attributes.multi(:attribute_not_exists)
578
+ it "check what happens when trying retrieve attribute that does not exists" do
579
+ assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
580
+ assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
581
+ assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
417
582
 
418
583
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
419
- assert_equal nil, response_multiple_attr_values.attributes[:attribute_not_exists]
420
- assert_equal nil, response_multiple_attr_values.attributes.single(:attribute_not_exists)
421
- assert_equal nil, response_multiple_attr_values.attributes.multi(:attribute_not_exists)
584
+ assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
585
+ assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
586
+ assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
422
587
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
423
588
  end
424
589
  end
590
+
591
+ describe "signature wrapping attack with encrypted assertion" do
592
+ it "should not be valid" do
593
+ settings = OneLogin::RubySaml::Settings.new
594
+ settings.private_key = valid_key
595
+ signature_wrapping_attack = read_response("encrypted_new_attack.xml.base64")
596
+ response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
597
+ response_wrapped.stubs(:conditions).returns(nil)
598
+ response_wrapped.stubs(:validate_subject_confirmation).returns(true)
599
+ settings.idp_cert_fingerprint = "385b1eec71143f00db6af936e2ea12a28771d72c"
600
+ assert !response_wrapped.is_valid?
601
+ err = assert_raises(OneLogin::RubySaml::ValidationError) do
602
+ response_wrapped.validate!
603
+ end
604
+ assert_equal "Found an invalid Signed Element. SAML Response rejected", err.message
605
+ end
606
+ end
607
+
608
+ describe "signature wrapping attack - concealed SAML response body" do
609
+ it "should not be valid" do
610
+ settings = OneLogin::RubySaml::Settings.new
611
+ signature_wrapping_attack = read_response("response_with_concealed_signed_assertion.xml")
612
+ response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
613
+ settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
614
+ response_wrapped.stubs(:conditions).returns(nil)
615
+ response_wrapped.stubs(:validate_subject_confirmation).returns(true)
616
+ response_wrapped.stubs(:validate_structure).returns(true)
617
+ assert !response_wrapped.is_valid?
618
+ assert !response_wrapped.validate!
619
+ end
620
+ end
621
+
622
+ describe "signature wrapping attack - doubled signed assertion SAML response" do
623
+ it "should not be valid" do
624
+ settings = OneLogin::RubySaml::Settings.new
625
+ signature_wrapping_attack = read_response("response_with_doubled_signed_assertion.xml")
626
+ response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
627
+ settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
628
+ response_wrapped.stubs(:conditions).returns(nil)
629
+ response_wrapped.stubs(:validate_subject_confirmation).returns(true)
630
+ assert !response_wrapped.is_valid?
631
+ end
632
+ end
425
633
  end
426
634
  end