ruby-saml 0.8.9 → 0.8.14
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.
- data/Gemfile +11 -1
- data/Rakefile +0 -14
- data/lib/onelogin/ruby-saml/authrequest.rb +84 -18
- data/lib/onelogin/ruby-saml/logoutrequest.rb +93 -18
- data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -24
- data/lib/onelogin/ruby-saml/response.rb +206 -11
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +73 -12
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
- data/lib/onelogin/ruby-saml/utils.rb +169 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +2 -1
- data/lib/xml_security.rb +332 -78
- data/test/certificates/ruby-saml-2.crt +15 -0
- data/test/certificates/ruby-saml.crt +14 -0
- data/test/certificates/ruby-saml.key +15 -0
- data/test/logoutrequest_test.rb +177 -44
- data/test/logoutresponse_test.rb +23 -28
- data/test/request_test.rb +100 -37
- data/test/response_test.rb +337 -129
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/encrypted_new_attack.xml.base64 +1 -0
- data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
- data/test/responses/invalids/no_signature.xml.base64 +1 -0
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
- data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/response_with_signed_assertion_3.xml +30 -0
- data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
- data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
- data/test/responses/response_wrapped.xml.base64 +150 -0
- data/test/responses/valid_response.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +5 -5
- data/test/slo_logoutresponse_test.rb +226 -0
- data/test/test_helper.rb +117 -12
- data/test/utils_test.rb +10 -10
- data/test/xml_security_test.rb +354 -68
- metadata +64 -18
- checksums.yaml +0 -7
data/test/request_test.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
2
|
|
3
|
-
class RequestTest < Test
|
3
|
+
class RequestTest < Minitest::Test
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
147
|
-
|
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
|
-
|
157
|
-
|
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
|
data/test/response_test.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
2
|
|
3
|
-
class
|
3
|
+
class ResponseTest < Minitest::Test
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
assert_raises(ArgumentError)
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
48
|
-
|
50
|
+
describe "#validate!" do
|
51
|
+
it "raise when settings not initialized" do
|
49
52
|
response = OneLogin::RubySaml::Response.new(response_document)
|
50
|
-
|
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
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
68
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
76
|
-
|
147
|
+
response.settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
148
|
+
response.validate!
|
77
149
|
end
|
78
150
|
|
79
|
-
|
80
|
-
response = OneLogin::RubySaml::Response.new(
|
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
|
-
|
89
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
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
|
-
|
99
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
185
|
+
settings.idp_cert = valid_cert
|
104
186
|
assert response.is_valid?
|
105
187
|
end
|
106
188
|
|
107
|
-
|
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
|
-
|
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
|
-
|
128
|
-
response = OneLogin::RubySaml::Response.new(
|
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
|
-
|
137
|
-
response = OneLogin::RubySaml::Response.new(
|
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
|
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
|
-
|
146
|
-
|
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.
|
268
|
+
settings.idp_cert = Base64.decode64(r1_signature_2)
|
151
269
|
response.settings = settings
|
152
|
-
|
270
|
+
assert response.validate!
|
153
271
|
end
|
154
272
|
|
155
|
-
|
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
|
-
|
164
|
-
|
165
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
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
|
-
|
176
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
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
|
-
|
186
|
-
response = OneLogin::RubySaml::Response.new(
|
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 =
|
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
|
-
|
198
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
218
|
-
|
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
|
-
|
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.
|
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.
|
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
|
-
|
242
|
-
|
243
|
-
response = OneLogin::RubySaml::Response.new(
|
244
|
-
|
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
|
-
|
248
|
-
response = OneLogin::RubySaml::Response.new(
|
249
|
-
|
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
|
-
|
253
|
-
response = OneLogin::RubySaml::Response.new(
|
254
|
-
|
255
|
-
|
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
|
-
|
259
|
-
|
260
|
-
|
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
|
-
|
264
|
-
|
265
|
-
|
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
|
-
|
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
|
-
|
274
|
-
response
|
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
|
-
|
279
|
-
response
|
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
|
-
|
284
|
-
response
|
285
|
-
response.attributes
|
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
|
-
|
290
|
-
|
291
|
-
|
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
|
-
|
297
|
-
|
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
|
-
|
307
|
-
|
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
|
-
|
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
|
-
|
319
|
-
|
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
|
-
|
326
|
-
|
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
|
-
|
495
|
+
assert_nil $evalled
|
331
496
|
end
|
332
497
|
end
|
333
498
|
|
334
|
-
|
335
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
561
|
+
it "return nil value correctly when not in compatibility mode off" do
|
397
562
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
398
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
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
|
-
|
420
|
-
|
421
|
-
|
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
|