ruby-saml 1.10.0 → 1.12.1
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.
- checksums.yaml +5 -5
- data/.travis.yml +28 -14
- data/README.md +96 -26
- data/changelog.md +37 -0
- data/lib/onelogin/ruby-saml/attributes.rb +24 -1
- data/lib/onelogin/ruby-saml/authrequest.rb +11 -6
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +71 -22
- data/lib/onelogin/ruby-saml/logging.rb +3 -3
- data/lib/onelogin/ruby-saml/logoutrequest.rb +9 -3
- data/lib/onelogin/ruby-saml/logoutresponse.rb +21 -2
- data/lib/onelogin/ruby-saml/metadata.rb +11 -3
- data/lib/onelogin/ruby-saml/response.rb +68 -22
- data/lib/onelogin/ruby-saml/saml_message.rb +6 -0
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +72 -7
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +20 -1
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +29 -16
- data/lib/onelogin/ruby-saml/utils.rb +74 -1
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +34 -6
- data/ruby-saml.gemspec +9 -5
- metadata +36 -282
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/certificate1 +0 -12
- data/test/certificates/certificate_without_head_foot +0 -1
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/certificates/ruby-saml.crt +0 -14
- data/test/certificates/ruby-saml.key +0 -15
- data/test/idp_metadata_parser_test.rb +0 -587
- data/test/logging_test.rb +0 -62
- data/test/logout_requests/invalid_slo_request.xml +0 -6
- data/test/logout_requests/slo_request.xml +0 -4
- data/test/logout_requests/slo_request.xml.base64 +0 -1
- data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
- data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
- data/test/logout_requests/slo_request_with_session_index.xml +0 -5
- data/test/logout_responses/logoutresponse_fixtures.rb +0 -86
- data/test/logoutrequest_test.rb +0 -260
- data/test/logoutresponse_test.rb +0 -409
- data/test/metadata/idp_descriptor.xml +0 -26
- data/test/metadata/idp_descriptor_2.xml +0 -56
- data/test/metadata/idp_descriptor_3.xml +0 -14
- data/test/metadata/idp_descriptor_4.xml +0 -72
- data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
- data/test/metadata/idp_metadata_multi_certs.xml +0 -75
- data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
- data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
- data/test/metadata/idp_multiple_descriptors.xml +0 -59
- data/test/metadata/idp_multiple_descriptors_2.xml +0 -59
- data/test/metadata/no_idp_descriptor.xml +0 -21
- data/test/metadata_test.rb +0 -331
- data/test/request_test.rb +0 -340
- data/test/response_test.rb +0 -1619
- data/test/responses/adfs_response_sha1.xml +0 -46
- data/test/responses/adfs_response_sha256.xml +0 -46
- data/test/responses/adfs_response_sha384.xml +0 -46
- data/test/responses/adfs_response_sha512.xml +0 -46
- data/test/responses/adfs_response_xmlns.xml +0 -45
- data/test/responses/attackxee.xml +0 -13
- data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
- data/test/responses/invalids/empty_destination.xml.base64 +0 -1
- data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
- data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
- data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
- data/test/responses/invalids/no_conditions.xml.base64 +0 -1
- data/test/responses/invalids/no_id.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
- data/test/responses/invalids/no_nameid.xml.base64 +0 -1
- data/test/responses/invalids/no_saml2.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/no_status.xml.base64 +0 -1
- data/test/responses/invalids/no_status_code.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
- data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
- data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
- data/test/responses/no_signature_ns.xml +0 -48
- data/test/responses/open_saml_response.xml +0 -56
- data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
- data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
- data/test/responses/response_double_status_code.xml.base64 +0 -1
- data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
- data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
- data/test/responses/response_eval.xml +0 -7
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack2.xml.base64 +0 -1
- data/test/responses/response_node_text_attack3.xml.base64 +0 -1
- data/test/responses/response_unsigned_xml_base64 +0 -1
- data/test/responses/response_with_ampersands.xml +0 -139
- data/test/responses/response_with_ampersands.xml.base64 +0 -93
- data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_multiple_attribute_values.xml +0 -67
- data/test/responses/response_with_retrieval_method.xml +0 -26
- data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
- data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
- data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_without_attributes.xml.base64 +0 -79
- data/test/responses/response_without_reference_uri.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/signed_nameid_in_atts.xml +0 -47
- data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
- data/test/responses/simple_saml_php.xml +0 -71
- data/test/responses/starfield_response.xml.base64 +0 -1
- data/test/responses/test_sign.xml +0 -43
- data/test/responses/unsigned_encrypted_adfs.xml +0 -23
- data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- data/test/saml_message_test.rb +0 -56
- data/test/settings_test.rb +0 -329
- data/test/slo_logoutrequest_test.rb +0 -448
- data/test/slo_logoutresponse_test.rb +0 -233
- data/test/test_helper.rb +0 -331
- data/test/utils_test.rb +0 -259
- data/test/xml_security_test.rb +0 -421
data/test/request_test.rb
DELETED
@@ -1,340 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
-
|
3
|
-
require 'onelogin/ruby-saml/authrequest'
|
4
|
-
|
5
|
-
class RequestTest < Minitest::Test
|
6
|
-
|
7
|
-
describe "Authrequest" do
|
8
|
-
let(:settings) { OneLogin::RubySaml::Settings.new }
|
9
|
-
|
10
|
-
before do
|
11
|
-
settings.idp_sso_target_url = "http://example.com"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "create the deflated SAMLRequest URL parameter" do
|
15
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
16
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
17
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
18
|
-
decoded = Base64.decode64(payload)
|
19
|
-
|
20
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
21
|
-
inflated = zstream.inflate(decoded)
|
22
|
-
zstream.finish
|
23
|
-
zstream.close
|
24
|
-
|
25
|
-
assert_match /^<samlp:AuthnRequest/, inflated
|
26
|
-
end
|
27
|
-
|
28
|
-
it "create the deflated SAMLRequest URL parameter including the Destination" do
|
29
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
30
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
31
|
-
decoded = Base64.decode64(payload)
|
32
|
-
|
33
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
34
|
-
inflated = zstream.inflate(decoded)
|
35
|
-
zstream.finish
|
36
|
-
zstream.close
|
37
|
-
|
38
|
-
assert_match /<samlp:AuthnRequest[^<]* Destination='http:\/\/example.com'/, inflated
|
39
|
-
end
|
40
|
-
|
41
|
-
it "create the SAMLRequest URL parameter without deflating" do
|
42
|
-
settings.compress_request = false
|
43
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
44
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
45
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
46
|
-
decoded = Base64.decode64(payload)
|
47
|
-
|
48
|
-
assert_match /^<samlp:AuthnRequest/, decoded
|
49
|
-
end
|
50
|
-
|
51
|
-
it "create the SAMLRequest URL parameter with IsPassive" do
|
52
|
-
settings.passive = true
|
53
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
54
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
55
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
56
|
-
decoded = Base64.decode64(payload)
|
57
|
-
|
58
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
59
|
-
inflated = zstream.inflate(decoded)
|
60
|
-
zstream.finish
|
61
|
-
zstream.close
|
62
|
-
|
63
|
-
assert_match /<samlp:AuthnRequest[^<]* IsPassive='true'/, inflated
|
64
|
-
end
|
65
|
-
|
66
|
-
it "create the SAMLRequest URL parameter with ProtocolBinding" do
|
67
|
-
settings.protocol_binding = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
|
68
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
69
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
70
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
71
|
-
decoded = Base64.decode64(payload)
|
72
|
-
|
73
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
74
|
-
inflated = zstream.inflate(decoded)
|
75
|
-
zstream.finish
|
76
|
-
zstream.close
|
77
|
-
|
78
|
-
assert_match /<samlp:AuthnRequest[^<]* ProtocolBinding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'/, inflated
|
79
|
-
end
|
80
|
-
|
81
|
-
it "create the SAMLRequest URL parameter with AttributeConsumingServiceIndex" do
|
82
|
-
settings.attributes_index = 30
|
83
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
84
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
85
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
86
|
-
decoded = Base64.decode64(payload)
|
87
|
-
|
88
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
89
|
-
inflated = zstream.inflate(decoded)
|
90
|
-
zstream.finish
|
91
|
-
zstream.close
|
92
|
-
assert_match /<samlp:AuthnRequest[^<]* AttributeConsumingServiceIndex='30'/, inflated
|
93
|
-
end
|
94
|
-
|
95
|
-
it "create the SAMLRequest URL parameter with ForceAuthn" do
|
96
|
-
settings.force_authn = true
|
97
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
98
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
99
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
100
|
-
decoded = Base64.decode64(payload)
|
101
|
-
|
102
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
103
|
-
inflated = zstream.inflate(decoded)
|
104
|
-
zstream.finish
|
105
|
-
zstream.close
|
106
|
-
assert_match /<samlp:AuthnRequest[^<]* ForceAuthn='true'/, inflated
|
107
|
-
end
|
108
|
-
|
109
|
-
it "create the SAMLRequest URL parameter with NameID Format" do
|
110
|
-
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
111
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
112
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
113
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
114
|
-
decoded = Base64.decode64(payload)
|
115
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
116
|
-
inflated = zstream.inflate(decoded)
|
117
|
-
zstream.finish
|
118
|
-
zstream.close
|
119
|
-
|
120
|
-
assert_match /<samlp:NameIDPolicy[^<]* AllowCreate='true'/, inflated
|
121
|
-
assert_match /<samlp:NameIDPolicy[^<]* Format='urn:oasis:names:tc:SAML:2.0:nameid-format:transient'/, inflated
|
122
|
-
end
|
123
|
-
|
124
|
-
it "create the SAMLRequest URL parameter with Subject" do
|
125
|
-
settings.name_identifier_value_requested = "testuser@example.com"
|
126
|
-
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
127
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
128
|
-
assert_match /^http:\/\/example\.com\?SAMLRequest=/, auth_url
|
129
|
-
payload = CGI.unescape(auth_url.split("=").last)
|
130
|
-
decoded = Base64.decode64(payload)
|
131
|
-
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
132
|
-
inflated = zstream.inflate(decoded)
|
133
|
-
zstream.finish
|
134
|
-
zstream.close
|
135
|
-
|
136
|
-
assert inflated.include?('<saml:Subject>')
|
137
|
-
assert inflated.include?("<saml:NameID Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'>testuser@example.com</saml:NameID>")
|
138
|
-
assert inflated.include?("<saml:SubjectConfirmation Method='urn:oasis:names:tc:SAML:2.0:cm:bearer'/>")
|
139
|
-
end
|
140
|
-
|
141
|
-
it "accept extra parameters" do
|
142
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :hello => "there" })
|
143
|
-
assert_match /&hello=there$/, auth_url
|
144
|
-
|
145
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :hello => nil })
|
146
|
-
assert_match /&hello=$/, auth_url
|
147
|
-
end
|
148
|
-
|
149
|
-
it "RelayState cases" do
|
150
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => nil })
|
151
|
-
assert !auth_url.include?('RelayState')
|
152
|
-
|
153
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => "http://example.com" })
|
154
|
-
assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
155
|
-
|
156
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => nil })
|
157
|
-
assert !auth_url.include?('RelayState')
|
158
|
-
|
159
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => "http://example.com" })
|
160
|
-
assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
161
|
-
end
|
162
|
-
|
163
|
-
describe "when the target url is not set" do
|
164
|
-
before do
|
165
|
-
settings.idp_sso_target_url = nil
|
166
|
-
end
|
167
|
-
|
168
|
-
it "raises an error with a descriptive message" do
|
169
|
-
err = assert_raises RuntimeError do
|
170
|
-
OneLogin::RubySaml::Authrequest.new.create(settings)
|
171
|
-
end
|
172
|
-
assert_match /idp_sso_target_url is not set/, err.message
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
describe "when the target url doesn't contain a query string" do
|
177
|
-
it "create the SAMLRequest parameter correctly" do
|
178
|
-
|
179
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
180
|
-
assert_match /^http:\/\/example.com\?SAMLRequest/, auth_url
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
describe "when the target url contains a query string" do
|
185
|
-
it "create the SAMLRequest parameter correctly" do
|
186
|
-
settings.idp_sso_target_url = "http://example.com?field=value"
|
187
|
-
|
188
|
-
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings)
|
189
|
-
assert_match /^http:\/\/example.com\?field=value&SAMLRequest/, auth_url
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
it "create the saml:AuthnContextClassRef element correctly" do
|
194
|
-
settings.authn_context = 'secure/name/password/uri'
|
195
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
196
|
-
assert_match /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s
|
197
|
-
end
|
198
|
-
|
199
|
-
it "create multiple saml:AuthnContextClassRef elements correctly" do
|
200
|
-
settings.authn_context = ['secure/name/password/uri', 'secure/email/password/uri']
|
201
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
202
|
-
assert_match /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s
|
203
|
-
assert_match /<saml:AuthnContextClassRef>secure\/email\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s
|
204
|
-
end
|
205
|
-
|
206
|
-
it "create the saml:AuthnContextClassRef with comparison exact" do
|
207
|
-
settings.authn_context = 'secure/name/password/uri'
|
208
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
209
|
-
assert_match /<samlp:RequestedAuthnContext[\S ]+Comparison='exact'/, auth_doc.to_s
|
210
|
-
assert_match /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s
|
211
|
-
end
|
212
|
-
|
213
|
-
it "create the saml:AuthnContextClassRef with comparison minimun" do
|
214
|
-
settings.authn_context = 'secure/name/password/uri'
|
215
|
-
settings.authn_context_comparison = 'minimun'
|
216
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
217
|
-
assert_match /<samlp:RequestedAuthnContext[\S ]+Comparison='minimun'/, auth_doc.to_s
|
218
|
-
assert_match /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/, auth_doc.to_s
|
219
|
-
end
|
220
|
-
|
221
|
-
it "create the saml:AuthnContextDeclRef element correctly" do
|
222
|
-
settings.authn_context_decl_ref = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
223
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
224
|
-
assert_match /<saml:AuthnContextDeclRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport<\/saml:AuthnContextDeclRef>/, auth_doc.to_s
|
225
|
-
end
|
226
|
-
|
227
|
-
describe "#create_params when the settings indicate to sign (embebed) the request" do
|
228
|
-
before do
|
229
|
-
settings.compress_request = false
|
230
|
-
settings.idp_sso_target_url = "http://example.com?field=value"
|
231
|
-
settings.security[:authn_requests_signed] = true
|
232
|
-
settings.security[:embed_sign] = true
|
233
|
-
settings.certificate = ruby_saml_cert_text
|
234
|
-
settings.private_key = ruby_saml_key_text
|
235
|
-
end
|
236
|
-
|
237
|
-
it "create a signed request" do
|
238
|
-
params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
|
239
|
-
request_xml = Base64.decode64(params["SAMLRequest"])
|
240
|
-
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
|
241
|
-
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], request_xml
|
242
|
-
end
|
243
|
-
|
244
|
-
it "create a signed request with 256 digest and signature methods" do
|
245
|
-
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
|
246
|
-
settings.security[:digest_method] = XMLSecurity::Document::SHA512
|
247
|
-
|
248
|
-
params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
|
249
|
-
|
250
|
-
request_xml = Base64.decode64(params["SAMLRequest"])
|
251
|
-
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
|
252
|
-
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
|
253
|
-
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha512'/>], request_xml
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
describe "#create_params when the settings indicate to sign the request" do
|
258
|
-
let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
|
259
|
-
|
260
|
-
before do
|
261
|
-
settings.compress_request = false
|
262
|
-
settings.idp_sso_target_url = "http://example.com?field=value"
|
263
|
-
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
|
264
|
-
settings.security[:authn_requests_signed] = true
|
265
|
-
settings.security[:embed_sign] = false
|
266
|
-
settings.certificate = ruby_saml_cert_text
|
267
|
-
settings.private_key = ruby_saml_key_text
|
268
|
-
end
|
269
|
-
|
270
|
-
it "create a signature parameter with RSA_SHA1 and validate it" do
|
271
|
-
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
272
|
-
|
273
|
-
params = OneLogin::RubySaml::Authrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
274
|
-
assert params['SAMLRequest']
|
275
|
-
assert params[:RelayState]
|
276
|
-
assert params['Signature']
|
277
|
-
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
|
278
|
-
|
279
|
-
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
280
|
-
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
281
|
-
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
282
|
-
|
283
|
-
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
284
|
-
assert_equal signature_algorithm, OpenSSL::Digest::SHA1
|
285
|
-
|
286
|
-
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
287
|
-
end
|
288
|
-
|
289
|
-
it "create a signature parameter with RSA_SHA256 and validate it" do
|
290
|
-
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
|
291
|
-
|
292
|
-
params = OneLogin::RubySaml::Authrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
293
|
-
assert params['Signature']
|
294
|
-
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
|
295
|
-
|
296
|
-
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
297
|
-
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
298
|
-
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
299
|
-
|
300
|
-
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
301
|
-
assert_equal signature_algorithm, OpenSSL::Digest::SHA256
|
302
|
-
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
it "create the saml:AuthnContextClassRef element correctly" do
|
307
|
-
settings.authn_context = 'secure/name/password/uri'
|
308
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
309
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/
|
310
|
-
end
|
311
|
-
|
312
|
-
it "create the saml:AuthnContextClassRef with comparison exact" do
|
313
|
-
settings.authn_context = 'secure/name/password/uri'
|
314
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
315
|
-
assert auth_doc.to_s =~ /<samlp:RequestedAuthnContext[\S ]+Comparison='exact'/
|
316
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/
|
317
|
-
end
|
318
|
-
|
319
|
-
it "create the saml:AuthnContextClassRef with comparison minimun" do
|
320
|
-
settings.authn_context = 'secure/name/password/uri'
|
321
|
-
settings.authn_context_comparison = 'minimun'
|
322
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
323
|
-
assert auth_doc.to_s =~ /<samlp:RequestedAuthnContext[\S ]+Comparison='minimun'/
|
324
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextClassRef>secure\/name\/password\/uri<\/saml:AuthnContextClassRef>/
|
325
|
-
end
|
326
|
-
|
327
|
-
it "create the saml:AuthnContextDeclRef element correctly" do
|
328
|
-
settings.authn_context_decl_ref = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
329
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
330
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextDeclRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport<\/saml:AuthnContextDeclRef>/
|
331
|
-
end
|
332
|
-
|
333
|
-
it "create multiple saml:AuthnContextDeclRef elements correctly " do
|
334
|
-
settings.authn_context_decl_ref = ['name/password/uri', 'example/decl/ref']
|
335
|
-
auth_doc = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
|
336
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextDeclRef>name\/password\/uri<\/saml:AuthnContextDeclRef>/
|
337
|
-
assert auth_doc.to_s =~ /<saml:AuthnContextDeclRef>example\/decl\/ref<\/saml:AuthnContextDeclRef>/
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
data/test/response_test.rb
DELETED
@@ -1,1619 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
-
|
3
|
-
require 'onelogin/ruby-saml/response'
|
4
|
-
|
5
|
-
class RubySamlTest < Minitest::Test
|
6
|
-
|
7
|
-
describe "Response" do
|
8
|
-
|
9
|
-
let(:settings) { OneLogin::RubySaml::Settings.new }
|
10
|
-
let(:response) { OneLogin::RubySaml::Response.new(response_document_without_recipient) }
|
11
|
-
let(:response_without_attributes) { OneLogin::RubySaml::Response.new(response_document_without_attributes) }
|
12
|
-
let(:response_with_multiple_attribute_statements) { OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_statements)) }
|
13
|
-
let(:response_without_reference_uri) { OneLogin::RubySaml::Response.new(response_document_without_reference_uri) }
|
14
|
-
let(:response_with_signed_assertion) { OneLogin::RubySaml::Response.new(response_document_with_signed_assertion) }
|
15
|
-
let(:response_with_ds_namespace_at_the_root) { OneLogin::RubySaml::Response.new(response_document_with_ds_namespace_at_the_root)}
|
16
|
-
let(:response_unsigned) { OneLogin::RubySaml::Response.new(response_document_unsigned) }
|
17
|
-
let(:response_wrapped) { OneLogin::RubySaml::Response.new(response_document_wrapped) }
|
18
|
-
let(:response_multiple_attr_values) { OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values)) }
|
19
|
-
let(:response_valid_signed) { OneLogin::RubySaml::Response.new(response_document_valid_signed) }
|
20
|
-
let(:response_valid_signed_without_recipient) { OneLogin::RubySaml::Response.new(response_document_valid_signed, {:skip_recipient_check => true })}
|
21
|
-
let(:response_valid_signed_without_x509certificate) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate) }
|
22
|
-
let(:response_no_id) { OneLogin::RubySaml::Response.new(read_invalid_response("no_id.xml.base64")) }
|
23
|
-
let(:response_no_version) { OneLogin::RubySaml::Response.new(read_invalid_response("no_saml2.xml.base64")) }
|
24
|
-
let(:response_multi_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_assertions.xml.base64")) }
|
25
|
-
let(:response_no_conditions) { OneLogin::RubySaml::Response.new(read_invalid_response("no_conditions.xml.base64")) }
|
26
|
-
let(:response_no_conditions_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("no_conditions.xml.base64"), { :skip_conditions => true }) }
|
27
|
-
let(:response_no_authnstatement) { OneLogin::RubySaml::Response.new(read_invalid_response("no_authnstatement.xml.base64")) }
|
28
|
-
let(:response_no_authnstatement_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("no_authnstatement.xml.base64"), {:skip_authnstatement => true}) }
|
29
|
-
let(:response_empty_destination) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64")) }
|
30
|
-
let(:response_empty_destination_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64"), {:skip_destination => true}) }
|
31
|
-
let(:response_no_status) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status.xml.base64")) }
|
32
|
-
let(:response_no_statuscode) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status_code.xml.base64")) }
|
33
|
-
let(:response_statuscode_responder) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responder.xml.base64")) }
|
34
|
-
let(:response_statuscode_responder_and_msg) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responer_and_msg.xml.base64")) }
|
35
|
-
let(:response_double_statuscode) { OneLogin::RubySaml::Response.new(response_document_double_status_code) }
|
36
|
-
let(:response_encrypted_attrs) { OneLogin::RubySaml::Response.new(response_document_encrypted_attrs) }
|
37
|
-
let(:response_no_signed_elements) { OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64")) }
|
38
|
-
let(:response_multiple_signed) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_signed.xml.base64")) }
|
39
|
-
let(:response_audience_self_closed) { OneLogin::RubySaml::Response.new(read_response("response_audience_self_closed_tag.xml.base64")) }
|
40
|
-
let(:response_invalid_audience) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_audience.xml.base64")) }
|
41
|
-
let(:response_invalid_signed_element) { OneLogin::RubySaml::Response.new(read_invalid_response("response_invalid_signed_element.xml.base64")) }
|
42
|
-
let(:response_invalid_issuer_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_assertion.xml.base64")) }
|
43
|
-
let(:response_invalid_issuer_message) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_message.xml.base64")) }
|
44
|
-
let(:response_no_issuer_response) { OneLogin::RubySaml::Response.new(read_invalid_response("no_issuer_response.xml.base64")) }
|
45
|
-
let(:response_no_issuer_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("no_issuer_assertion.xml.base64")) }
|
46
|
-
let(:response_no_nameid) { OneLogin::RubySaml::Response.new(read_invalid_response("no_nameid.xml.base64")) }
|
47
|
-
let(:response_empty_nameid) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_nameid.xml.base64")) }
|
48
|
-
let(:response_wrong_spnamequalifier) { OneLogin::RubySaml::Response.new(read_invalid_response("wrong_spnamequalifier.xml.base64")) }
|
49
|
-
let(:response_duplicated_attributes) { OneLogin::RubySaml::Response.new(read_invalid_response("duplicated_attributes.xml.base64")) }
|
50
|
-
let(:response_no_subjectconfirmation_data) { OneLogin::RubySaml::Response.new(read_invalid_response("no_subjectconfirmation_data.xml.base64")) }
|
51
|
-
let(:response_no_subjectconfirmation_method) { OneLogin::RubySaml::Response.new(read_invalid_response("no_subjectconfirmation_method.xml.base64")) }
|
52
|
-
let(:response_invalid_subjectconfirmation_inresponse) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_inresponse.xml.base64")) }
|
53
|
-
let(:response_invalid_subjectconfirmation_recipient) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_recipient.xml.base64")) }
|
54
|
-
let(:response_invalid_subjectconfirmation_nb) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_nb.xml.base64")) }
|
55
|
-
let(:response_invalid_subjectconfirmation_noa) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_noa.xml.base64")) }
|
56
|
-
let(:response_invalid_signature_position) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_signature_position.xml.base64")) }
|
57
|
-
let(:response_encrypted_nameid) { OneLogin::RubySaml::Response.new(response_document_encrypted_nameid) }
|
58
|
-
|
59
|
-
def generate_audience_error(expected, actual)
|
60
|
-
s = actual.count > 1 ? 's' : '';
|
61
|
-
return "Invalid Audience#{s}. The audience#{s} #{actual.join(',')}, did not match the expected audience #{expected}"
|
62
|
-
end
|
63
|
-
|
64
|
-
it "raise an exception when response is initialized with nil" do
|
65
|
-
assert_raises(ArgumentError) { OneLogin::RubySaml::Response.new(nil) }
|
66
|
-
end
|
67
|
-
|
68
|
-
it "not filter available options only" do
|
69
|
-
options = { :skip_destination => true, :foo => :bar }
|
70
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, options)
|
71
|
-
assert_includes response.options.keys, :skip_destination
|
72
|
-
assert_includes response.options.keys, :foo
|
73
|
-
end
|
74
|
-
|
75
|
-
it "be able to parse a document which contains ampersands" do
|
76
|
-
XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
|
77
|
-
OneLogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
|
78
|
-
|
79
|
-
ampersands_response = OneLogin::RubySaml::Response.new(ampersands_document)
|
80
|
-
ampersands_response.settings = settings
|
81
|
-
ampersands_response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
82
|
-
|
83
|
-
assert !ampersands_response.is_valid?
|
84
|
-
assert_includes ampersands_response.errors, "SAML Response must contain 1 assertion"
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "Prevent node text with comment attack (VU#475445)" do
|
88
|
-
before do
|
89
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack.xml.base64'))
|
90
|
-
end
|
91
|
-
|
92
|
-
it "receives the full NameID when there is an injected comment" do
|
93
|
-
assert_equal "support@onelogin.com", @response.name_id
|
94
|
-
end
|
95
|
-
|
96
|
-
it "receives the full AttributeValue when there is an injected comment" do
|
97
|
-
assert_equal "smith", @response.attributes["surname"]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe "Another test to prevent with comment attack (VU#475445)" do
|
102
|
-
before do
|
103
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack2.xml.base64'), {:skip_recipient_check => true })
|
104
|
-
@response.settings = settings
|
105
|
-
@response.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
106
|
-
end
|
107
|
-
|
108
|
-
it "receives the full NameID when there is an injected comment, validates the response" do
|
109
|
-
assert_equal "test@onelogin.com", @response.name_id
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "Another test with CDATA injected" do
|
114
|
-
before do
|
115
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack3.xml.base64'), {:skip_recipient_check => true })
|
116
|
-
@response.settings = settings
|
117
|
-
@response.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
118
|
-
end
|
119
|
-
|
120
|
-
it "it normalizes CDATA but reject SAMLResponse due signature invalidation" do
|
121
|
-
assert_equal "test@onelogin.com.evil.com", @response.name_id
|
122
|
-
assert !@response.is_valid?
|
123
|
-
assert_includes @response.errors, "Invalid Signature on SAML Response"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe "Prevent XEE attack" do
|
128
|
-
before do
|
129
|
-
@response = OneLogin::RubySaml::Response.new(fixture(:attackxee))
|
130
|
-
end
|
131
|
-
|
132
|
-
it "false when evil attack vector is present, soft = true" do
|
133
|
-
@response.soft = true
|
134
|
-
assert !@response.send(:validate_structure)
|
135
|
-
assert_includes @response.errors, "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
136
|
-
end
|
137
|
-
|
138
|
-
it "raise when evil attack vector is present, soft = false " do
|
139
|
-
@response.soft = false
|
140
|
-
|
141
|
-
assert_raises(OneLogin::RubySaml::ValidationError) do
|
142
|
-
@response.send(:validate_structure)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
it "adapt namespace" do
|
148
|
-
refute_nil response.nameid
|
149
|
-
refute_nil response_without_attributes.nameid
|
150
|
-
refute_nil response_with_signed_assertion.nameid
|
151
|
-
end
|
152
|
-
|
153
|
-
it "default to raw input when a response is not Base64 encoded" do
|
154
|
-
decoded = Base64.decode64(response_document_without_attributes)
|
155
|
-
response_from_raw = OneLogin::RubySaml::Response.new(decoded)
|
156
|
-
assert response_from_raw.document
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "Assertion" do
|
160
|
-
it "only retreive an assertion with an ID that matches the signature's reference URI" do
|
161
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
162
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
163
|
-
response_wrapped.settings = settings
|
164
|
-
assert_nil response_wrapped.nameid
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe "#is_valid?" do
|
169
|
-
describe "soft = false" do
|
170
|
-
|
171
|
-
before do
|
172
|
-
response.soft = false
|
173
|
-
response_valid_signed.soft = false
|
174
|
-
end
|
175
|
-
|
176
|
-
it "raise when response is initialized with blank data" do
|
177
|
-
blank_response = OneLogin::RubySaml::Response.new('')
|
178
|
-
blank_response.soft = false
|
179
|
-
error_msg = "Blank response"
|
180
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
181
|
-
blank_response.is_valid?
|
182
|
-
end
|
183
|
-
assert_includes blank_response.errors, error_msg
|
184
|
-
end
|
185
|
-
|
186
|
-
it "raise when settings have not been set" do
|
187
|
-
error_msg = "No settings on response"
|
188
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
189
|
-
response.is_valid?
|
190
|
-
end
|
191
|
-
assert_includes response.errors, error_msg
|
192
|
-
end
|
193
|
-
|
194
|
-
it "raise when No fingerprint or certificate on settings" do
|
195
|
-
settings.idp_cert_fingerprint = nil
|
196
|
-
settings.idp_cert = nil
|
197
|
-
settings.idp_cert_multi = nil
|
198
|
-
response.settings = settings
|
199
|
-
error_msg = "No fingerprint or certificate on settings"
|
200
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
201
|
-
response.is_valid?
|
202
|
-
end
|
203
|
-
assert_includes response.errors, error_msg
|
204
|
-
end
|
205
|
-
|
206
|
-
it "raise when signature wrapping attack" do
|
207
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
208
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
209
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
210
|
-
response_wrapped.settings = settings
|
211
|
-
assert !response_wrapped.is_valid?
|
212
|
-
end
|
213
|
-
|
214
|
-
it "validate SAML 2.0 XML structure" do
|
215
|
-
resp_xml = Base64.decode64(response_document_unsigned).gsub(/emailAddress/,'test')
|
216
|
-
response_unsigned_mod = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
217
|
-
response_unsigned_mod.stubs(:conditions).returns(nil)
|
218
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
219
|
-
response_unsigned_mod.settings = settings
|
220
|
-
response_unsigned_mod.soft = false
|
221
|
-
assert_raises(OneLogin::RubySaml::ValidationError, 'Digest mismatch') do
|
222
|
-
response_unsigned_mod.is_valid?
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
it "raise when encountering a condition that prevents the document from being valid" do
|
227
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
228
|
-
response.settings = settings
|
229
|
-
response.soft = false
|
230
|
-
error_msg = "Current time is on or after NotOnOrAfter condition"
|
231
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
232
|
-
response.is_valid?
|
233
|
-
end
|
234
|
-
assert_includes response.errors[0], error_msg
|
235
|
-
end
|
236
|
-
|
237
|
-
it "raise when encountering a SAML Response with bad formatted" do
|
238
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
239
|
-
response_without_attributes.settings = settings
|
240
|
-
response_without_attributes.soft = false
|
241
|
-
assert_raises(OneLogin::RubySaml::ValidationError) do
|
242
|
-
response_without_attributes.is_valid?
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
it "raise when the inResponseTo value does not match the Request ID" do
|
247
|
-
settings.soft = false
|
248
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
249
|
-
opts = {}
|
250
|
-
opts[:settings] = settings
|
251
|
-
opts[:matches_request_id] = "invalid_request_id"
|
252
|
-
response_valid_signed = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
253
|
-
error_msg = "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
254
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
255
|
-
response_valid_signed.is_valid?
|
256
|
-
end
|
257
|
-
assert_includes response_valid_signed.errors, error_msg
|
258
|
-
end
|
259
|
-
|
260
|
-
it "raise when there is no valid audience" do
|
261
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
262
|
-
settings.issuer = 'invalid'
|
263
|
-
response_valid_signed.settings = settings
|
264
|
-
response_valid_signed.soft = false
|
265
|
-
error_msg = generate_audience_error(response_valid_signed.settings.issuer, ['https://someone.example.com/audience'])
|
266
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
267
|
-
response_valid_signed.is_valid?
|
268
|
-
end
|
269
|
-
assert_includes response_valid_signed.errors, error_msg
|
270
|
-
end
|
271
|
-
|
272
|
-
it "raise when no ID present in the SAML Response" do
|
273
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
274
|
-
response_no_id.settings = settings
|
275
|
-
response_no_id.soft = false
|
276
|
-
error_msg = "Missing ID attribute on SAML Response"
|
277
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
278
|
-
response_no_id.is_valid?
|
279
|
-
end
|
280
|
-
assert_includes response_no_id.errors, error_msg
|
281
|
-
end
|
282
|
-
|
283
|
-
it "raise when no 2.0 Version present in the SAML Response" do
|
284
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
285
|
-
response_no_version.settings = settings
|
286
|
-
response_no_version.soft = false
|
287
|
-
error_msg = "Unsupported SAML version"
|
288
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
289
|
-
response_no_version.is_valid?
|
290
|
-
end
|
291
|
-
assert_includes response_no_version.errors, error_msg
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
describe "soft = true" do
|
296
|
-
before do
|
297
|
-
response.soft = true
|
298
|
-
response_valid_signed.soft = true
|
299
|
-
end
|
300
|
-
|
301
|
-
it "return true when the response is initialized with valid data" do
|
302
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
303
|
-
response_valid_signed_without_recipient.settings = settings
|
304
|
-
response_valid_signed_without_recipient.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
305
|
-
assert response_valid_signed_without_recipient.is_valid?
|
306
|
-
assert_empty response_valid_signed_without_recipient.errors
|
307
|
-
end
|
308
|
-
|
309
|
-
it "return true when the response is initialized with valid data and using certificate instead of fingerprint" do
|
310
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
311
|
-
response_valid_signed_without_recipient.settings = settings
|
312
|
-
response_valid_signed_without_recipient.settings.idp_cert = ruby_saml_cert_text
|
313
|
-
assert response_valid_signed_without_recipient.is_valid?
|
314
|
-
assert_empty response_valid_signed_without_recipient.errors
|
315
|
-
end
|
316
|
-
|
317
|
-
it "return false when response is initialized with blank data" do
|
318
|
-
blank_response = OneLogin::RubySaml::Response.new('')
|
319
|
-
blank_response.soft = true
|
320
|
-
assert !blank_response.is_valid?
|
321
|
-
assert_includes blank_response.errors, "Blank response"
|
322
|
-
end
|
323
|
-
|
324
|
-
it "return false if settings have not been set" do
|
325
|
-
assert !response.is_valid?
|
326
|
-
assert_includes response.errors, "No settings on response"
|
327
|
-
end
|
328
|
-
|
329
|
-
it "return false if fingerprint or certificate not been set on settings" do
|
330
|
-
response.settings = settings
|
331
|
-
assert !response.is_valid?
|
332
|
-
assert_includes response.errors, "No fingerprint or certificate on settings"
|
333
|
-
end
|
334
|
-
|
335
|
-
it "should be idempotent when the response is initialized with invalid data" do
|
336
|
-
response_unsigned.stubs(:conditions).returns(nil)
|
337
|
-
response_unsigned.settings = settings
|
338
|
-
assert !response_unsigned.is_valid?
|
339
|
-
assert !response_unsigned.is_valid?
|
340
|
-
end
|
341
|
-
|
342
|
-
it "should be idempotent when the response is initialized with valid data" do
|
343
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
344
|
-
response_valid_signed_without_recipient.settings = settings
|
345
|
-
response_valid_signed_without_recipient.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
346
|
-
assert response_valid_signed_without_recipient.is_valid?
|
347
|
-
assert response_valid_signed_without_recipient.is_valid?
|
348
|
-
end
|
349
|
-
|
350
|
-
it "not allow signature wrapping attack" do
|
351
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
352
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
353
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
354
|
-
response_wrapped.settings = settings
|
355
|
-
assert !response_wrapped.is_valid?
|
356
|
-
end
|
357
|
-
|
358
|
-
it "support dynamic namespace resolution on signature elements" do
|
359
|
-
no_signature_response = OneLogin::RubySaml::Response.new(fixture("no_signature_ns.xml"))
|
360
|
-
no_signature_response.stubs(:conditions).returns(nil)
|
361
|
-
no_signature_response.stubs(:validate_subject_confirmation).returns(true)
|
362
|
-
no_signature_response.settings = settings
|
363
|
-
no_signature_response.settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
364
|
-
XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
|
365
|
-
assert no_signature_response.is_valid?
|
366
|
-
end
|
367
|
-
|
368
|
-
it "validate ADFS assertions" do
|
369
|
-
adfs_response = OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
|
370
|
-
adfs_response.stubs(:conditions).returns(nil)
|
371
|
-
adfs_response.stubs(:validate_subject_confirmation).returns(true)
|
372
|
-
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
373
|
-
adfs_response.settings = settings
|
374
|
-
adfs_response.soft = true
|
375
|
-
assert adfs_response.is_valid?
|
376
|
-
end
|
377
|
-
|
378
|
-
it "validate SAML 2.0 XML structure" do
|
379
|
-
resp_xml = Base64.decode64(response_document_unsigned).gsub(/emailAddress/,'test')
|
380
|
-
response_unsigned_mod = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
381
|
-
response_unsigned_mod.stubs(:conditions).returns(nil)
|
382
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
383
|
-
response_unsigned_mod.settings = settings
|
384
|
-
response_unsigned_mod.soft = true
|
385
|
-
assert !response_unsigned_mod.is_valid?
|
386
|
-
end
|
387
|
-
|
388
|
-
it "return false when encountering a condition that prevents the document from being valid" do
|
389
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
390
|
-
response.settings = settings
|
391
|
-
error_msg = "Current time is on or after NotOnOrAfter condition"
|
392
|
-
assert !response.is_valid?
|
393
|
-
assert_includes response.errors[0], "Current time is on or after NotOnOrAfter condition"
|
394
|
-
end
|
395
|
-
|
396
|
-
it "return false when encountering a SAML Response with bad formatted" do
|
397
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
398
|
-
response_without_attributes.settings = settings
|
399
|
-
response_without_attributes.soft = true
|
400
|
-
error_msg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
401
|
-
response_without_attributes.is_valid?
|
402
|
-
assert_includes response_without_attributes.errors, error_msg
|
403
|
-
end
|
404
|
-
|
405
|
-
it "return false when the inResponseTo value does not match the Request ID" do
|
406
|
-
settings.soft = true
|
407
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
408
|
-
opts = {}
|
409
|
-
opts[:settings] = settings
|
410
|
-
opts[:matches_request_id] = "invalid_request_id"
|
411
|
-
response_valid_signed = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
412
|
-
response_valid_signed.is_valid?
|
413
|
-
assert_includes response_valid_signed.errors, "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
414
|
-
end
|
415
|
-
|
416
|
-
it "return false when there is no valid audience" do
|
417
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
418
|
-
settings.issuer = 'invalid'
|
419
|
-
response_valid_signed.settings = settings
|
420
|
-
response_valid_signed.is_valid?
|
421
|
-
|
422
|
-
assert_includes response_valid_signed.errors, generate_audience_error(response_valid_signed.settings.issuer, ['https://someone.example.com/audience'])
|
423
|
-
end
|
424
|
-
|
425
|
-
it "return false when no ID present in the SAML Response" do
|
426
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
427
|
-
response_no_id.settings = settings
|
428
|
-
response_no_id.soft = true
|
429
|
-
response_no_id.is_valid?
|
430
|
-
assert_includes response_no_id.errors, "Missing ID attribute on SAML Response"
|
431
|
-
end
|
432
|
-
|
433
|
-
it "return false when no 2.0 Version present in the SAML Response" do
|
434
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
435
|
-
response_no_version.settings = settings
|
436
|
-
response_no_version.soft = true
|
437
|
-
error_msg = "Unsupported SAML version"
|
438
|
-
response_no_version.is_valid?
|
439
|
-
assert_includes response_no_version.errors, "Unsupported SAML version"
|
440
|
-
end
|
441
|
-
|
442
|
-
it "return true when a nil URI is given in the ds:Reference" do
|
443
|
-
settings.idp_cert = ruby_saml_cert_text
|
444
|
-
settings.assertion_consumer_service_url = "http://localhost:9001/v1/users/authorize/saml"
|
445
|
-
response_without_reference_uri.settings = settings
|
446
|
-
response_without_reference_uri.stubs(:conditions).returns(nil)
|
447
|
-
response_without_reference_uri.is_valid?
|
448
|
-
assert_empty response_without_reference_uri.errors
|
449
|
-
assert 'saml@user.com', response_without_reference_uri.attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress']
|
450
|
-
end
|
451
|
-
|
452
|
-
it "collect errors when collect_errors=true" do
|
453
|
-
settings.idp_cert = ruby_saml_cert_text
|
454
|
-
settings.issuer = 'invalid'
|
455
|
-
response_invalid_subjectconfirmation_recipient.settings = settings
|
456
|
-
collect_errors = true
|
457
|
-
response_invalid_subjectconfirmation_recipient.is_valid?(collect_errors)
|
458
|
-
assert_includes response_invalid_subjectconfirmation_recipient.errors, generate_audience_error('invalid', ['http://stuff.com/endpoints/metadata.php'])
|
459
|
-
assert_includes response_invalid_subjectconfirmation_recipient.errors, "Invalid Signature on SAML Response"
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
describe "#validate_audience" do
|
465
|
-
it "return true when the audience is valid" do
|
466
|
-
response.settings = settings
|
467
|
-
response.settings.issuer = '{audience}'
|
468
|
-
assert response.send(:validate_audience)
|
469
|
-
assert_empty response.errors
|
470
|
-
end
|
471
|
-
|
472
|
-
it "return true when the audience is self closing" do
|
473
|
-
response_audience_self_closed.settings = settings
|
474
|
-
response_audience_self_closed.settings.issuer = '{audience}'
|
475
|
-
assert response_audience_self_closed.send(:validate_audience)
|
476
|
-
assert_empty response_audience_self_closed.errors
|
477
|
-
end
|
478
|
-
|
479
|
-
it "return false when the audience is valid" do
|
480
|
-
response.settings = settings
|
481
|
-
response.settings.issuer = 'invalid_audience'
|
482
|
-
assert !response.send(:validate_audience)
|
483
|
-
assert_includes response.errors, generate_audience_error(response.settings.issuer, ['{audience}'])
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
describe "#validate_destination" do
|
488
|
-
it "return true when the destination of the SAML Response matches the assertion consumer service url" do
|
489
|
-
response.settings = settings
|
490
|
-
assert response.send(:validate_destination)
|
491
|
-
assert_empty response.errors
|
492
|
-
end
|
493
|
-
|
494
|
-
it "return false when the destination of the SAML Response does not match the assertion consumer service url" do
|
495
|
-
response.settings = settings
|
496
|
-
response.settings.assertion_consumer_service_url = 'invalid_acs'
|
497
|
-
assert !response.send(:validate_destination)
|
498
|
-
assert_includes response.errors, "The response was received at #{response.destination} instead of #{response.settings.assertion_consumer_service_url}"
|
499
|
-
end
|
500
|
-
|
501
|
-
it "return false when the destination of the SAML Response is empty" do
|
502
|
-
response_empty_destination.settings = settings
|
503
|
-
assert !response_empty_destination.send(:validate_destination)
|
504
|
-
assert_includes response_empty_destination.errors, "The response has an empty Destination value"
|
505
|
-
end
|
506
|
-
|
507
|
-
it "return true when the destination of the SAML Response is empty but skip_destination option is used" do
|
508
|
-
response_empty_destination_with_skip.settings = settings
|
509
|
-
assert response_empty_destination_with_skip.send(:validate_destination)
|
510
|
-
assert_empty response_empty_destination.errors
|
511
|
-
end
|
512
|
-
|
513
|
-
it "returns true on a case insensitive match on the domain" do
|
514
|
-
response_valid_signed_without_x509certificate.settings = settings
|
515
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'http://APP.muDa.no/sso/consume'
|
516
|
-
assert response_valid_signed_without_x509certificate.send(:validate_destination)
|
517
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
518
|
-
end
|
519
|
-
|
520
|
-
it "returns true on a case insensitive match on the scheme" do
|
521
|
-
response_valid_signed_without_x509certificate.settings = settings
|
522
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'HTTP://app.muda.no/sso/consume'
|
523
|
-
assert response_valid_signed_without_x509certificate.send(:validate_destination)
|
524
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
525
|
-
end
|
526
|
-
|
527
|
-
it "returns false on a case insenstive match on the path" do
|
528
|
-
response_valid_signed_without_x509certificate.settings = settings
|
529
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'http://app.muda.no/SSO/consume'
|
530
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_destination)
|
531
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "The response was received at #{response_valid_signed_without_x509certificate.destination} instead of #{response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url}"
|
532
|
-
end
|
533
|
-
|
534
|
-
it "returns true if it can't parse out a full URI." do
|
535
|
-
response_valid_signed_without_x509certificate.settings = settings
|
536
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'presenter'
|
537
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_destination)
|
538
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "The response was received at #{response_valid_signed_without_x509certificate.destination} instead of #{response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url}"
|
539
|
-
end
|
540
|
-
end
|
541
|
-
|
542
|
-
describe "#validate_issuer" do
|
543
|
-
it "return true when the issuer of the Message/Assertion matches the IdP entityId" do
|
544
|
-
response_valid_signed.settings = settings
|
545
|
-
assert response_valid_signed.send(:validate_issuer)
|
546
|
-
|
547
|
-
response_valid_signed.settings.idp_entity_id = 'https://app.onelogin.com/saml2'
|
548
|
-
assert response_valid_signed.send(:validate_issuer)
|
549
|
-
end
|
550
|
-
|
551
|
-
it "return false when the issuer of the Message does not match the IdP entityId" do
|
552
|
-
response_invalid_issuer_message.settings = settings
|
553
|
-
response_invalid_issuer_message.settings.idp_entity_id = 'http://idp.example.com/'
|
554
|
-
assert !response_invalid_issuer_message.send(:validate_issuer)
|
555
|
-
assert_includes response_invalid_issuer_message.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_message.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
556
|
-
end
|
557
|
-
|
558
|
-
it "return false when the issuer of the Assertion does not match the IdP entityId" do
|
559
|
-
response_invalid_issuer_assertion.settings = settings
|
560
|
-
response_invalid_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
561
|
-
assert !response_invalid_issuer_assertion.send(:validate_issuer)
|
562
|
-
assert_includes response_invalid_issuer_assertion.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_assertion.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
|
-
describe "#validate_num_assertion" do
|
567
|
-
it "return true when SAML Response contains 1 assertion" do
|
568
|
-
assert response.send(:validate_num_assertion)
|
569
|
-
assert_empty response.errors
|
570
|
-
end
|
571
|
-
|
572
|
-
it "return false when no 2.0 Version present in the SAML Response" do
|
573
|
-
assert !response_multi_assertion.send(:validate_num_assertion)
|
574
|
-
assert_includes response_multi_assertion.errors, "SAML Response must contain 1 assertion"
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
describe "validate_success_status" do
|
579
|
-
it "return true when the status is 'Success'" do
|
580
|
-
assert response.send(:validate_success_status)
|
581
|
-
assert_empty response.errors
|
582
|
-
end
|
583
|
-
|
584
|
-
it "return false when no Status provided" do
|
585
|
-
assert !response_no_status.send(:validate_success_status)
|
586
|
-
assert_includes response_no_status.errors, "The status code of the Response was not Success"
|
587
|
-
end
|
588
|
-
|
589
|
-
it "return false when no StatusCode provided" do
|
590
|
-
assert !response_no_statuscode.send(:validate_success_status)
|
591
|
-
assert_includes response_no_statuscode.errors, "The status code of the Response was not Success"
|
592
|
-
end
|
593
|
-
|
594
|
-
it "return false when the status is not 'Success'" do
|
595
|
-
assert !response_statuscode_responder.send(:validate_success_status)
|
596
|
-
assert_includes response_statuscode_responder.errors, "The status code of the Response was not Success, was Responder"
|
597
|
-
end
|
598
|
-
|
599
|
-
it "return false when the status is not 'Success', and shows the StatusMessage" do
|
600
|
-
assert !response_statuscode_responder_and_msg.send(:validate_success_status)
|
601
|
-
assert_includes response_statuscode_responder_and_msg.errors, "The status code of the Response was not Success, was Responder -> something_is_wrong"
|
602
|
-
end
|
603
|
-
|
604
|
-
it "return false when the status is not 'Success'" do
|
605
|
-
assert !response_double_statuscode.send(:validate_success_status)
|
606
|
-
assert_includes response_double_statuscode.errors, "The status code of the Response was not Success, was Requester => UnsupportedBinding"
|
607
|
-
end
|
608
|
-
end
|
609
|
-
|
610
|
-
describe "#validate_structure" do
|
611
|
-
it "return true when encountering a wellformed SAML Response" do
|
612
|
-
assert response.send(:validate_structure)
|
613
|
-
assert_empty response.errors
|
614
|
-
end
|
615
|
-
|
616
|
-
it "return false when encountering a mailformed element that prevents the document from being valid" do
|
617
|
-
response_without_attributes.soft = true
|
618
|
-
response_without_attributes.send(:validate_structure)
|
619
|
-
assert response_without_attributes.errors.include? "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
620
|
-
end
|
621
|
-
|
622
|
-
it "raise when encountering a mailformed element that prevents the document from being valid" do
|
623
|
-
response_without_attributes.soft = false
|
624
|
-
assert_raises(OneLogin::RubySaml::ValidationError) {
|
625
|
-
response_without_attributes.send(:validate_structure)
|
626
|
-
}
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
describe "validate_formatted_x509_certificate" do
|
631
|
-
let(:response_with_formatted_x509certificate) {
|
632
|
-
OneLogin::RubySaml::Response.new(read_response("valid_response_with_formatted_x509certificate.xml.base64"), {
|
633
|
-
:skip_conditions => true,
|
634
|
-
:skip_subject_confirmation => true })
|
635
|
-
}
|
636
|
-
|
637
|
-
it "be able to parse the response wihout errors" do
|
638
|
-
response_with_formatted_x509certificate.settings = settings
|
639
|
-
response_with_formatted_x509certificate.settings.idp_cert = ruby_saml_cert_text
|
640
|
-
assert response_with_formatted_x509certificate.is_valid?
|
641
|
-
assert_empty response_with_formatted_x509certificate.errors
|
642
|
-
end
|
643
|
-
end
|
644
|
-
|
645
|
-
describe "#validate_in_response_to" do
|
646
|
-
it "return true when the inResponseTo value matches the Request ID" do
|
647
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings, :matches_request_id => "_fc4a34b0-7efb-012e-caae-782bcb13bb38")
|
648
|
-
assert response.send(:validate_in_response_to)
|
649
|
-
assert_empty response.errors
|
650
|
-
end
|
651
|
-
|
652
|
-
it "return true when no Request ID is provided for checking" do
|
653
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings)
|
654
|
-
assert response.send(:validate_in_response_to)
|
655
|
-
assert_empty response.errors
|
656
|
-
end
|
657
|
-
|
658
|
-
it "return false when the inResponseTo value does not match the Request ID" do
|
659
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings, :matches_request_id => "invalid_request_id")
|
660
|
-
assert !response.send(:validate_in_response_to)
|
661
|
-
assert_includes response.errors, "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
665
|
-
describe "#validate_audience" do
|
666
|
-
it "return true when the audience is valid" do
|
667
|
-
response_valid_signed.settings = settings
|
668
|
-
response_valid_signed.settings.issuer = "https://someone.example.com/audience"
|
669
|
-
assert response_valid_signed.send(:validate_audience)
|
670
|
-
assert_empty response_valid_signed.errors
|
671
|
-
end
|
672
|
-
|
673
|
-
it "return true when there is not issuer defined" do
|
674
|
-
response_valid_signed.settings = settings
|
675
|
-
response_valid_signed.settings.issuer = nil
|
676
|
-
assert response_valid_signed.send(:validate_audience)
|
677
|
-
assert_empty response_valid_signed.errors
|
678
|
-
end
|
679
|
-
|
680
|
-
it "return false when there is no valid audience" do
|
681
|
-
response_invalid_audience.settings = settings
|
682
|
-
response_invalid_audience.settings.issuer = "https://invalid.example.com/audience"
|
683
|
-
assert !response_invalid_audience.send(:validate_audience)
|
684
|
-
assert_includes response_invalid_audience.errors, generate_audience_error(response_invalid_audience.settings.issuer, ['http://invalid.audience.com'])
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
describe "#validate_issuer" do
|
689
|
-
it "return true when the issuer of the Message/Assertion matches the IdP entityId or it was empty" do
|
690
|
-
response_valid_signed.settings = settings
|
691
|
-
assert response_valid_signed.send(:validate_issuer)
|
692
|
-
assert_empty response_valid_signed.errors
|
693
|
-
|
694
|
-
response_valid_signed.settings.idp_entity_id = 'https://app.onelogin.com/saml2'
|
695
|
-
assert response_valid_signed.send(:validate_issuer)
|
696
|
-
assert_empty response_valid_signed.errors
|
697
|
-
end
|
698
|
-
|
699
|
-
it "return false when the issuer of the Message does not match the IdP entityId" do
|
700
|
-
response_invalid_issuer_message.settings = settings
|
701
|
-
response_invalid_issuer_message.settings.idp_entity_id = 'http://idp.example.com/'
|
702
|
-
assert !response_invalid_issuer_message.send(:validate_issuer)
|
703
|
-
assert_includes response_invalid_issuer_message.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_message.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
704
|
-
end
|
705
|
-
|
706
|
-
it "return false when the issuer of the Assertion does not match the IdP entityId" do
|
707
|
-
response_invalid_issuer_assertion.settings = settings
|
708
|
-
response_invalid_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
709
|
-
assert !response_invalid_issuer_assertion.send(:validate_issuer)
|
710
|
-
assert_includes response_invalid_issuer_assertion.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_assertion.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
711
|
-
end
|
712
|
-
|
713
|
-
it "return false when the no issuer at the Response" do
|
714
|
-
response_no_issuer_response.settings = settings
|
715
|
-
response_no_issuer_response.settings.idp_entity_id = 'http://idp.example.com/'
|
716
|
-
assert !response_no_issuer_response.send(:validate_issuer)
|
717
|
-
assert_includes response_no_issuer_response.errors, "Issuer of the Response not found or multiple."
|
718
|
-
end
|
719
|
-
|
720
|
-
it "return false when the no issuer at the Assertion" do
|
721
|
-
response_no_issuer_assertion.settings = settings
|
722
|
-
response_no_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
723
|
-
assert !response_no_issuer_assertion.send(:validate_issuer)
|
724
|
-
assert_includes response_no_issuer_assertion.errors, "Issuer of the Assertion not found or multiple."
|
725
|
-
end
|
726
|
-
end
|
727
|
-
|
728
|
-
describe "#validate_subject_confirmation" do
|
729
|
-
it "return true when valid subject confirmation" do
|
730
|
-
response_valid_signed.settings = settings
|
731
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'recipient'
|
732
|
-
assert response_valid_signed.send(:validate_subject_confirmation)
|
733
|
-
assert_empty response_valid_signed.errors
|
734
|
-
end
|
735
|
-
|
736
|
-
it "return false when no subject confirmation data" do
|
737
|
-
response_no_subjectconfirmation_data.settings = settings
|
738
|
-
assert !response_no_subjectconfirmation_data.send(:validate_subject_confirmation)
|
739
|
-
assert_includes response_no_subjectconfirmation_data.errors, "A valid SubjectConfirmation was not found on this Response"
|
740
|
-
end
|
741
|
-
|
742
|
-
it "return false when no valid subject confirmation method" do
|
743
|
-
response_no_subjectconfirmation_method.settings = settings
|
744
|
-
assert !response_no_subjectconfirmation_method.send(:validate_subject_confirmation)
|
745
|
-
assert_includes response_no_subjectconfirmation_method.errors, "A valid SubjectConfirmation was not found on this Response"
|
746
|
-
end
|
747
|
-
|
748
|
-
it "return false when invalid inresponse" do
|
749
|
-
response_invalid_subjectconfirmation_inresponse.settings = settings
|
750
|
-
assert !response_invalid_subjectconfirmation_inresponse.send(:validate_subject_confirmation)
|
751
|
-
assert_includes response_invalid_subjectconfirmation_inresponse.errors, "A valid SubjectConfirmation was not found on this Response"
|
752
|
-
end
|
753
|
-
|
754
|
-
it "return false when invalid NotBefore" do
|
755
|
-
response_invalid_subjectconfirmation_nb.settings = settings
|
756
|
-
assert !response_invalid_subjectconfirmation_nb.send(:validate_subject_confirmation)
|
757
|
-
assert_includes response_invalid_subjectconfirmation_nb.errors, "A valid SubjectConfirmation was not found on this Response"
|
758
|
-
end
|
759
|
-
|
760
|
-
it "return false when invalid NotOnOrAfter" do
|
761
|
-
response_invalid_subjectconfirmation_noa.settings = settings
|
762
|
-
assert !response_invalid_subjectconfirmation_noa.send(:validate_subject_confirmation)
|
763
|
-
assert_includes response_invalid_subjectconfirmation_noa.errors, "A valid SubjectConfirmation was not found on this Response"
|
764
|
-
end
|
765
|
-
|
766
|
-
it "return true when valid subject confirmation recipient" do
|
767
|
-
response_valid_signed.settings = settings
|
768
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'recipient'
|
769
|
-
assert response_valid_signed.send(:validate_subject_confirmation)
|
770
|
-
assert_empty response_valid_signed.errors
|
771
|
-
assert_empty response_valid_signed.errors
|
772
|
-
end
|
773
|
-
|
774
|
-
it "return false when invalid subject confirmation recipient" do
|
775
|
-
response_valid_signed.settings = settings
|
776
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'not-the-recipient'
|
777
|
-
assert !response_valid_signed.send(:validate_subject_confirmation)
|
778
|
-
assert_includes response_valid_signed.errors, "A valid SubjectConfirmation was not found on this Response"
|
779
|
-
end
|
780
|
-
|
781
|
-
it "return false when invalid subject confirmation recipient, but skipping the check(default)" do
|
782
|
-
response_valid_signed_without_recipient.settings = settings
|
783
|
-
response_valid_signed_without_recipient.settings.assertion_consumer_service_url = 'not-the-recipient'
|
784
|
-
assert response_valid_signed_without_recipient.send(:validate_subject_confirmation)
|
785
|
-
assert_empty response_valid_signed_without_recipient.errors
|
786
|
-
end
|
787
|
-
|
788
|
-
it "return true when the skip_subject_confirmation option is passed and the subject confirmation is valid" do
|
789
|
-
opts = {}
|
790
|
-
opts[:skip_subject_confirmation] = true
|
791
|
-
response_with_skip = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
792
|
-
response_with_skip.settings = settings
|
793
|
-
response_with_skip.settings.assertion_consumer_service_url = 'recipient'
|
794
|
-
Time.expects(:now).times(0) # ensures the test isn't run and thus Time.now.utc is never called within the test
|
795
|
-
assert response_with_skip.send(:validate_subject_confirmation)
|
796
|
-
assert_empty response_with_skip.errors
|
797
|
-
end
|
798
|
-
|
799
|
-
it "return true when the skip_subject_confirmation option is passed and the response has an invalid subject confirmation" do
|
800
|
-
opts = {}
|
801
|
-
opts[:skip_subject_confirmation] = true
|
802
|
-
response_with_skip = OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_noa.xml.base64"), opts)
|
803
|
-
response_with_skip.settings = settings
|
804
|
-
Time.expects(:now).times(0) # ensures the test isn't run and thus Time.now.utc is never called within the test
|
805
|
-
assert response_with_skip.send(:validate_subject_confirmation)
|
806
|
-
assert_empty response_with_skip.errors
|
807
|
-
end
|
808
|
-
end
|
809
|
-
|
810
|
-
describe "#validate_session_expiration" do
|
811
|
-
it "return true when the session has not expired" do
|
812
|
-
response_valid_signed.settings = settings
|
813
|
-
assert response_valid_signed.send(:validate_session_expiration)
|
814
|
-
assert_empty response_valid_signed.errors
|
815
|
-
end
|
816
|
-
|
817
|
-
it "return false when the session has expired" do
|
818
|
-
response.settings = settings
|
819
|
-
assert !response.send(:validate_session_expiration)
|
820
|
-
assert_includes response.errors, "The attributes have expired, based on the SessionNotOnOrAfter of the AuthnStatement of this Response"
|
821
|
-
end
|
822
|
-
|
823
|
-
it "returns true when the session has expired, but is still within the allowed_clock_drift" do
|
824
|
-
drift = (Time.now - Time.parse("2010-11-19T21:57:37Z")) * 60 # seconds ago that this assertion expired
|
825
|
-
drift += 10 # add a buffer of 10 seconds to make sure the test passes
|
826
|
-
opts = {}
|
827
|
-
opts[:allowed_clock_drift] = drift
|
828
|
-
|
829
|
-
response_with_drift = OneLogin::RubySaml::Response.new(response_document_without_recipient, opts)
|
830
|
-
response_with_drift.settings = settings
|
831
|
-
assert response_with_drift.send(:validate_session_expiration)
|
832
|
-
assert_empty response_with_drift.errors
|
833
|
-
end
|
834
|
-
end
|
835
|
-
|
836
|
-
describe "#validate_signature" do
|
837
|
-
it "return true when the signature is valid" do
|
838
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
839
|
-
response_valid_signed.settings = settings
|
840
|
-
assert response_valid_signed.send(:validate_signature)
|
841
|
-
assert_empty response_valid_signed.errors
|
842
|
-
end
|
843
|
-
|
844
|
-
it "return true when the signature is valid and ds namespace is at the root" do
|
845
|
-
settings.idp_cert_fingerprint = '5614657ab692b960480389723a36446a5fe1f7ec'
|
846
|
-
response_with_ds_namespace_at_the_root.settings = settings
|
847
|
-
assert response_with_ds_namespace_at_the_root.send(:validate_signature)
|
848
|
-
assert_empty response_with_ds_namespace_at_the_root.errors
|
849
|
-
end
|
850
|
-
|
851
|
-
it "return true when the signature is valid and fingerprint provided" do
|
852
|
-
settings.idp_cert_fingerprint = '49:EC:3F:A4:71:8A:1E:C9:DB:70:A7:CC:33:36:96:F0:48:8C:4E:DA'
|
853
|
-
xml = 'PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERlc3RpbmF0aW9uPSJodHRwczovL2NvZGVycGFkLmlvL3NhbWwvYWNzIiBJRD0iXzEwOGE1ZTg0MDllYzRjZjlhY2QxYzQ2OWU5ZDcxNGFkIiBJblJlc3BvbnNlVG89Il80ZmZmYWE2MC02OTZiLTAxMzMtMzg4Ni0wMjQxZjY1YzA2OTMiIElzc3VlSW5zdGFudD0iMjAxNS0xMS0wOVQyMzo1NTo0M1oiIFZlcnNpb249IjIuMCI+PHNhbWw6SXNzdWVyIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHBzOi8vbG9naW4uaHVsdS5jb208L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj48L2RzOkNhbm9uaWNhbGl6YXRpb25NZXRob2Q+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSI+PC9kczpTaWduYXR1cmVNZXRob2Q+PGRzOlJlZmVyZW5jZSBVUkk9IiNfMTA4YTVlODQwOWVjNGNmOWFjZDFjNDY5ZTlkNzE0YWQiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSI+PC9kczpUcmFuc2Zvcm0+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyI+PC9kczpUcmFuc2Zvcm0+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSI+PC9kczpEaWdlc3RNZXRob2Q+PGRzOkRpZ2VzdFZhbHVlPm9sQllXbTQyRi9oZm0xdHJYTHk2a3V6MXlMUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+dXNRTmY5WGpKTDRlOXVucnVCdWViSnQ3R0tXM2hJUk9teWVqTm1NMHM4WFhlWHN3WHc4U3ZCZi8zeDNNWEpkWnpNV0pOM3ExN2tGWHN2bTVna1JzbkE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJQ1FEQ0NBZXFnQXdJQkFnSUpBSVZOdzVLRzR1aTFNQTBHQ1NxR1NJYjNEUUVCQlFVQU1Fd3hDekFKQmdOVkJBWVRBa2RDTVJJd0VBWURWUVFJRXdsQ1pYSnJjMmhwY21VeEVEQU9CZ05WQkFjVEIwNWxkMkoxY25reEZ6QVZCZ05WQkFvVERrMTVJRU52YlhCaGJua2dUSFJrTUI0WERURXlNVEF5TlRBMk1qY3pORm9YRFRJeU1UQXlNekEyTWpjek5Gb3dUREVMTUFrR0ExVUVCaE1DUjBJeEVqQVFCZ05WQkFnVENVSmxjbXR6YUdseVpURVFNQTRHQTFVRUJ4TUhUbVYzWW5WeWVURVhNQlVHQTFVRUNoTU9UWGtnUTI5dGNHRnVlU0JNZEdRd1hEQU5CZ2txaGtpRzl3MEJBUUVGQUFOTEFEQklBa0VBd1NOL2dpMzNSbXBBUW9MUWo3UDZ6QW5OVDBSbjdiakMzMjNuM3ExT25mdm52UjBmUWp2TnQ3ckRrQTVBdjVRbk02VjRZVU5Vbk1mYk9RcTBXTGJMU3dJREFRQUJvNEd1TUlHck1CMEdBMVVkRGdRV0JCUWZJSDFvZkJWcHNSQWNJTUsyaGJsN25nTVRZREI4QmdOVkhTTUVkVEJ6Z0JRZklIMW9mQlZwc1JBY0lNSzJoYmw3bmdNVFlLRlFwRTR3VERFTE1Ba0dBMVVFQmhNQ1IwSXhFakFRQmdOVkJBZ1RDVUpsY210emFHbHlaVEVRTUE0R0ExVUVCeE1IVG1WM1luVnllVEVYTUJVR0ExVUVDaE1PVFhrZ1EyOXRjR0Z1ZVNCTWRHU0NDUUNGVGNPU2h1TG90VEFNQmdOVkhSTUVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJCUVVBQTBFQXFvZ1YzdVBjbEtYRG1EWk1UN3ZsUFl4TEFxQ0dIWnRsQ3h6NGhNNEtTdGxEMi9HTmMxWGlMYjFoL0swQ0pMRG9zckVJYm0zd2lPMk12VEVSclZZU01RPT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiPjwvc2FtbHA6U3RhdHVzQ29kZT48L3NhbWxwOlN0YXR1cz48c2FtbDpBc3NlcnRpb24geG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9Il8wMTg4MmRhOTM2OTQ0ZDFlYTZlZmY0NDA2NTc2MzFiNSIgSXNzdWVJbnN0YW50PSIyMDE1LTExLTA5VDIzOjU1OjQzWiIgVmVyc2lvbj0iMi4wIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9sb2dpbi5odWx1LmNvbTwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+PGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiPjwvZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZD48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3JzYS1zaGExIj48L2RzOlNpZ25hdHVyZU1ldGhvZD48ZHM6UmVmZXJlbmNlIFVSST0iI18wMTg4MmRhOTM2OTQ0ZDFlYTZlZmY0NDA2NTc2MzFiNSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIj48L2RzOlRyYW5zZm9ybT48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj48L2RzOlRyYW5zZm9ybT48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIj48L2RzOkRpZ2VzdE1ldGhvZD48ZHM6RGlnZXN0VmFsdWU+cmo2YzhucC9BUmV0ZkJ1dWVOSzNPS0xDYnowPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5hR05FemZHM1dLcExKc2ZLRGJSNmpva2d6OEFnZ0FIRVVESEZyd0dsTHVQeWpyNEl3M09NcFNkV2gyL01YK1F3M1dPTk5mNHJNalh5TGVZSFJIVGpMQT09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDUURDQ0FlcWdBd0lCQWdJSkFJVk53NUtHNHVpMU1BMEdDU3FHU0liM0RRRUJCUVVBTUV3eEN6QUpCZ05WQkFZVEFrZENNUkl3RUFZRFZRUUlFd2xDWlhKcmMyaHBjbVV4RURBT0JnTlZCQWNUQjA1bGQySjFjbmt4RnpBVkJnTlZCQW9URGsxNUlFTnZiWEJoYm5rZ1RIUmtNQjRYRFRFeU1UQXlOVEEyTWpjek5Gb1hEVEl5TVRBeU16QTJNamN6TkZvd1RERUxNQWtHQTFVRUJoTUNSMEl4RWpBUUJnTlZCQWdUQ1VKbGNtdHphR2x5WlRFUU1BNEdBMVVFQnhNSFRtVjNZblZ5ZVRFWE1CVUdBMVVFQ2hNT1RYa2dRMjl0Y0dGdWVTQk1kR1F3WERBTkJna3Foa2lHOXcwQkFRRUZBQU5MQURCSUFrRUF3U04vZ2kzM1JtcEFRb0xRajdQNnpBbk5UMFJuN2JqQzMyM24zcTFPbmZ2bnZSMGZRanZOdDdyRGtBNUF2NVFuTTZWNFlVTlVuTWZiT1FxMFdMYkxTd0lEQVFBQm80R3VNSUdyTUIwR0ExVWREZ1FXQkJRZklIMW9mQlZwc1JBY0lNSzJoYmw3bmdNVFlEQjhCZ05WSFNNRWRUQnpnQlFmSUgxb2ZCVnBzUkFjSU1LMmhibDduZ01UWUtGUXBFNHdUREVMTUFrR0ExVUVCaE1DUjBJeEVqQVFCZ05WQkFnVENVSmxjbXR6YUdseVpURVFNQTRHQTFVRUJ4TUhUbVYzWW5WeWVURVhNQlVHQTFVRUNoTU9UWGtnUTI5dGNHRnVlU0JNZEdTQ0NRQ0ZUY09TaHVMb3RUQU1CZ05WSFJNRUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkJRVUFBMEVBcW9nVjN1UGNsS1hEbURaTVQ3dmxQWXhMQXFDR0hadGxDeHo0aE00S1N0bEQyL0dOYzFYaUxiMWgvSzBDSkxEb3NyRUlibTN3aU8yTXZURVJyVllTTVE9PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sOlN1YmplY3Q+PHNhbWw6TmFtZUlEIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzIiBTUE5hbWVRdWFsaWZpZXI9Imh0dHBzOi8vY29kZXJwYWQuaW8iPm1hdHQuanVyaWtAaHVsdS5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBJblJlc3BvbnNlVG89Il80ZmZmYWE2MC02OTZiLTAxMzMtMzg4Ni0wMjQxZjY1YzA2OTMiIE5vdE9uT3JBZnRlcj0iMjAxNS0xMS0xMFQwMDoxMDo0M1oiIFJlY2lwaWVudD0iaHR0cHM6Ly9jb2RlcnBhZC5pby9zYW1sL2FjcyI+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb25EYXRhPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDE1LTExLTA5VDIyOjU1OjQzWiIgTm90T25PckFmdGVyPSIyMDE1LTExLTEwVDAwOjEwOjQzWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL2NvZGVycGFkLmlvPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNS0xMS0wOVQyMzo1NTo0M1oiPjxzYW1sOkF1dGhuQ29udGV4dD48c2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZDwvc2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj48L3NhbWw6QXV0aG5Db250ZXh0Pjwvc2FtbDpBdXRoblN0YXRlbWVudD48c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlIE5hbWU9IkdpdmVuLW5hbWUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPk1hdHQ8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iU3VybmFtZSI+PHNhbWw6QXR0cmlidXRlVmFsdWU+SnVyaWs8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iRW1haWwiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPm1hdHQuanVyaWtAaHVsdS5jb208L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50Pjwvc2FtbDpBc3NlcnRpb24+PC9zYW1scDpSZXNwb25zZT4='
|
854
|
-
response_x = OneLogin::RubySaml::Response.new(xml)
|
855
|
-
response_x.settings = settings
|
856
|
-
assert response_x.send(:validate_signature)
|
857
|
-
assert_empty response_x.errors
|
858
|
-
end
|
859
|
-
|
860
|
-
it "return false when no fingerprint" do
|
861
|
-
settings.idp_cert_fingerprint = nil
|
862
|
-
settings.idp_cert = nil
|
863
|
-
response.settings = settings
|
864
|
-
assert !response.send(:validate_signature)
|
865
|
-
assert_includes response.errors, "Invalid Signature on SAML Response"
|
866
|
-
end
|
867
|
-
|
868
|
-
it "return false when the signature is invalid" do
|
869
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
870
|
-
response.settings = settings
|
871
|
-
assert !response.send(:validate_signature)
|
872
|
-
assert_includes response.errors, "Invalid Signature on SAML Response"
|
873
|
-
end
|
874
|
-
|
875
|
-
it "return false when no X509Certificate and not cert provided at settings" do
|
876
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
877
|
-
settings.idp_cert = nil
|
878
|
-
response_valid_signed_without_x509certificate.settings = settings
|
879
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_signature)
|
880
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "Invalid Signature on SAML Response"
|
881
|
-
end
|
882
|
-
|
883
|
-
it "return false when no X509Certificate and the cert provided at settings mismatches" do
|
884
|
-
settings.idp_cert_fingerprint = nil
|
885
|
-
settings.idp_cert = signature_1
|
886
|
-
response_valid_signed_without_x509certificate.settings = settings
|
887
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_signature)
|
888
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "Invalid Signature on SAML Response"
|
889
|
-
end
|
890
|
-
|
891
|
-
it "return true when no X509Certificate and the cert provided at settings matches" do
|
892
|
-
settings.idp_cert_fingerprint = nil
|
893
|
-
settings.idp_cert = ruby_saml_cert_text
|
894
|
-
response_valid_signed_without_x509certificate.settings = settings
|
895
|
-
assert response_valid_signed_without_x509certificate.send(:validate_signature)
|
896
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
897
|
-
end
|
898
|
-
|
899
|
-
it "return false when signature wrapping attack" do
|
900
|
-
signature_wrapping_attack = read_invalid_response("signature_wrapping_attack.xml.base64")
|
901
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack)
|
902
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
903
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
904
|
-
settings.idp_cert_fingerprint = "afe71c28ef740bc87425be13a2263d37971da1f9"
|
905
|
-
response_wrapped.settings = settings
|
906
|
-
assert !response_wrapped.send(:validate_signature)
|
907
|
-
assert_includes response_wrapped.errors, "Invalid Signature on SAML Response"
|
908
|
-
end
|
909
|
-
end
|
910
|
-
|
911
|
-
describe "#validate_signature with multiple idp certs" do
|
912
|
-
it "return true when at least a cert on idp_cert_multi is valid" do
|
913
|
-
settings.idp_cert_multi = {
|
914
|
-
:signing => [ruby_saml_cert_text2, ruby_saml_cert_text],
|
915
|
-
:encryption => []
|
916
|
-
}
|
917
|
-
response_valid_signed.settings = settings
|
918
|
-
assert response_valid_signed.send(:validate_signature)
|
919
|
-
assert_empty response_valid_signed.errors
|
920
|
-
end
|
921
|
-
|
922
|
-
it "return false when none cert on idp_cert_multi is valid" do
|
923
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
924
|
-
settings.idp_cert_multi = {
|
925
|
-
:signing => [ruby_saml_cert_text2, ruby_saml_cert_text2],
|
926
|
-
:encryption => []
|
927
|
-
}
|
928
|
-
response_valid_signed.settings = settings
|
929
|
-
assert !response_valid_signed.send(:validate_signature)
|
930
|
-
assert_includes response_valid_signed.errors, "Invalid Signature on SAML Response"
|
931
|
-
end
|
932
|
-
end
|
933
|
-
|
934
|
-
describe "#validate nameid" do
|
935
|
-
it "return false when no nameid element and required by settings" do
|
936
|
-
settings.security[:want_name_id] = true
|
937
|
-
response_no_nameid.settings = settings
|
938
|
-
assert !response_no_nameid.send(:validate_name_id)
|
939
|
-
assert_includes response_no_nameid.errors, "No NameID element found in the assertion of the Response"
|
940
|
-
end
|
941
|
-
|
942
|
-
it "return false when no nameid element and required by settings" do
|
943
|
-
response_empty_nameid.settings = settings
|
944
|
-
assert !response_empty_nameid.send(:validate_name_id)
|
945
|
-
assert_includes response_empty_nameid.errors, "An empty NameID value found"
|
946
|
-
end
|
947
|
-
|
948
|
-
it "return false when no nameid value" do
|
949
|
-
response_empty_nameid.settings = settings
|
950
|
-
assert !response_empty_nameid.send(:validate_name_id)
|
951
|
-
assert_includes response_empty_nameid.errors, "An empty NameID value found"
|
952
|
-
end
|
953
|
-
|
954
|
-
it "return false when wrong_spnamequalifier" do
|
955
|
-
settings.issuer = 'sp_entity_id'
|
956
|
-
response_wrong_spnamequalifier.settings = settings
|
957
|
-
assert !response_wrong_spnamequalifier.send(:validate_name_id)
|
958
|
-
assert_includes response_wrong_spnamequalifier.errors, "The SPNameQualifier value mistmatch the SP entityID value."
|
959
|
-
end
|
960
|
-
|
961
|
-
it "return true when no nameid element but not required by settings" do
|
962
|
-
settings.security[:want_name_id] = false
|
963
|
-
response_no_nameid.settings = settings
|
964
|
-
assert response_no_nameid.send(:validate_name_id)
|
965
|
-
end
|
966
|
-
|
967
|
-
it "return true when nameid is valid and response_wrong_spnamequalifier matches the SP issuer" do
|
968
|
-
settings.issuer = 'wrong-sp-entityid'
|
969
|
-
response_wrong_spnamequalifier.settings = settings
|
970
|
-
assert response_wrong_spnamequalifier.send(:validate_name_id)
|
971
|
-
end
|
972
|
-
end
|
973
|
-
|
974
|
-
describe "#nameid" do
|
975
|
-
it "extract the value of the name id element" do
|
976
|
-
assert_equal "support@onelogin.com", response.nameid
|
977
|
-
assert_equal "someone@example.com", response_with_signed_assertion.nameid
|
978
|
-
end
|
979
|
-
|
980
|
-
it "be extractable from an OpenSAML response" do
|
981
|
-
response_open_saml = OneLogin::RubySaml::Response.new(fixture(:open_saml))
|
982
|
-
assert_equal "someone@example.org", response_open_saml.nameid
|
983
|
-
end
|
984
|
-
|
985
|
-
it "be extractable from a Simple SAML PHP response" do
|
986
|
-
response_ssp = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
987
|
-
assert_equal "someone@example.com", response_ssp.nameid
|
988
|
-
end
|
989
|
-
end
|
990
|
-
|
991
|
-
describe "#name_id_format" do
|
992
|
-
it "extract the value of the name id element" do
|
993
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response.name_id_format
|
994
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_with_signed_assertion.name_id_format
|
995
|
-
end
|
996
|
-
end
|
997
|
-
|
998
|
-
describe "#sessionindex" do
|
999
|
-
it "extract the value of the sessionindex element" do
|
1000
|
-
response = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
1001
|
-
assert_equal "_51be37965feb5579d803141076936dc2e9d1d98ebf", response.sessionindex
|
1002
|
-
end
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
describe "#check_one_conditions" do
|
1006
|
-
it "return false when none or more than one conditions element" do
|
1007
|
-
response_no_conditions.soft = true
|
1008
|
-
assert !response_no_conditions.send(:validate_one_conditions)
|
1009
|
-
assert_includes response_no_conditions.errors, "The Assertion must include one Conditions element"
|
1010
|
-
end
|
1011
|
-
|
1012
|
-
it "return true when one conditions element" do
|
1013
|
-
response.soft = true
|
1014
|
-
assert response.send(:validate_one_conditions)
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
it "return true when no conditions are present and skip_conditions is true" do
|
1018
|
-
response_no_conditions_with_skip.soft = true
|
1019
|
-
assert response_no_conditions_with_skip.send(:validate_one_conditions)
|
1020
|
-
end
|
1021
|
-
end
|
1022
|
-
|
1023
|
-
describe "#check_one_authnstatement" do
|
1024
|
-
it "return false when none or more than one authnstatement element" do
|
1025
|
-
response_no_authnstatement.soft = true
|
1026
|
-
assert !response_no_authnstatement.send(:validate_one_authnstatement)
|
1027
|
-
assert_includes response_no_authnstatement.errors, "The Assertion must include one AuthnStatement element"
|
1028
|
-
end
|
1029
|
-
|
1030
|
-
it "return true when one authnstatement element" do
|
1031
|
-
response.soft = true
|
1032
|
-
assert response.send(:validate_one_authnstatement)
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
it "return true when SAML Response is empty but skip_authstatement option is used" do
|
1036
|
-
response_no_authnstatement_with_skip.soft = true
|
1037
|
-
assert response_no_authnstatement_with_skip.send(:validate_one_authnstatement)
|
1038
|
-
assert_empty response_empty_destination_with_skip.errors
|
1039
|
-
end
|
1040
|
-
end
|
1041
|
-
|
1042
|
-
describe "#check_conditions" do
|
1043
|
-
it "check time conditions" do
|
1044
|
-
response.soft = true
|
1045
|
-
assert !response.send(:validate_conditions)
|
1046
|
-
response_time_updated = OneLogin::RubySaml::Response.new(response_document_without_recipient_with_time_updated)
|
1047
|
-
response_time_updated.soft = true
|
1048
|
-
assert response_time_updated.send(:validate_conditions)
|
1049
|
-
Timecop.freeze(Time.parse("2011-06-14T18:25:01.516Z")) do
|
1050
|
-
response_with_saml2_namespace = OneLogin::RubySaml::Response.new(response_document_with_saml2_namespace)
|
1051
|
-
response_with_saml2_namespace.soft = true
|
1052
|
-
assert response_with_saml2_namespace.send(:validate_conditions)
|
1053
|
-
end
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
it "optionally allows for clock drift" do
|
1057
|
-
# The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
|
1058
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1059
|
-
settings.soft = true
|
1060
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1061
|
-
response_document_with_saml2_namespace,
|
1062
|
-
:allowed_clock_drift => 0.515,
|
1063
|
-
:settings => settings
|
1064
|
-
)
|
1065
|
-
assert !special_response_with_saml2_namespace.send(:validate_conditions)
|
1066
|
-
end
|
1067
|
-
|
1068
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1069
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1070
|
-
response_document_with_saml2_namespace,
|
1071
|
-
:allowed_clock_drift => 0.516
|
1072
|
-
)
|
1073
|
-
assert special_response_with_saml2_namespace.send(:validate_conditions)
|
1074
|
-
end
|
1075
|
-
|
1076
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1077
|
-
settings.soft = true
|
1078
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1079
|
-
response_document_with_saml2_namespace,
|
1080
|
-
:allowed_clock_drift => '0.515',
|
1081
|
-
:settings => settings
|
1082
|
-
)
|
1083
|
-
assert !special_response_with_saml2_namespace.send(:validate_conditions)
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1087
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1088
|
-
response_document_with_saml2_namespace,
|
1089
|
-
:allowed_clock_drift => '0.516'
|
1090
|
-
)
|
1091
|
-
assert special_response_with_saml2_namespace.send(:validate_conditions)
|
1092
|
-
end
|
1093
|
-
end
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
describe "#attributes" do
|
1097
|
-
it "extract the first attribute in a hash accessed via its symbol" do
|
1098
|
-
assert_equal "demo", response.attributes[:uid]
|
1099
|
-
end
|
1100
|
-
|
1101
|
-
it "extract the first attribute in a hash accessed via its name" do
|
1102
|
-
assert_equal "demo", response.attributes["uid"]
|
1103
|
-
end
|
1104
|
-
|
1105
|
-
it "extract all attributes" do
|
1106
|
-
assert_equal "demo", response.attributes[:uid]
|
1107
|
-
assert_equal "value", response.attributes[:another_value]
|
1108
|
-
end
|
1109
|
-
|
1110
|
-
it "work for implicit namespaces" do
|
1111
|
-
assert_equal "someone@example.com", response_with_signed_assertion.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
it "extract attributes from all AttributeStatement tags" do
|
1115
|
-
assert_equal "smith", response_with_multiple_attribute_statements.attributes[:surname]
|
1116
|
-
assert_equal "bob", response_with_multiple_attribute_statements.attributes[:firstname]
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
it "not raise on responses without attributes" do
|
1120
|
-
assert_equal OneLogin::RubySaml::Attributes.new, response_unsigned.attributes
|
1121
|
-
end
|
1122
|
-
|
1123
|
-
describe "#encrypted attributes" do
|
1124
|
-
it "raise error when the assertion contains encrypted attributes but no private key to decrypt" do
|
1125
|
-
settings.private_key = nil
|
1126
|
-
response_encrypted_attrs.settings = settings
|
1127
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedAttribute found and no SP private key found on the settings to decrypt it") do
|
1128
|
-
attrs = response_encrypted_attrs.attributes
|
1129
|
-
end
|
1130
|
-
end
|
1131
|
-
|
1132
|
-
it "extract attributes when the assertion contains encrypted attributes and the private key is provided" do
|
1133
|
-
settings.certificate = ruby_saml_cert_text
|
1134
|
-
settings.private_key = ruby_saml_key_text
|
1135
|
-
response_encrypted_attrs.settings = settings
|
1136
|
-
attributes = response_encrypted_attrs.attributes
|
1137
|
-
assert_equal "test", attributes[:uid]
|
1138
|
-
assert_equal "test@example.com", attributes[:mail]
|
1139
|
-
end
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
it "return false when validating a response with duplicate attributes" do
|
1143
|
-
response_duplicated_attributes.settings = settings
|
1144
|
-
response_duplicated_attributes.options[:check_duplicated_attributes] = true
|
1145
|
-
assert !response_duplicated_attributes.send(:validate_no_duplicated_attributes)
|
1146
|
-
assert_includes response_duplicated_attributes.errors, "Found an Attribute element with duplicated Name"
|
1147
|
-
end
|
1148
|
-
|
1149
|
-
it "return true when validating a response with duplicate attributes but skip check" do
|
1150
|
-
response_duplicated_attributes.settings = settings
|
1151
|
-
assert response_duplicated_attributes.send(:validate_no_duplicated_attributes)
|
1152
|
-
end
|
1153
|
-
|
1154
|
-
describe "#multiple values" do
|
1155
|
-
it "extract single value as string" do
|
1156
|
-
assert_equal "demo", response_multiple_attr_values.attributes[:uid]
|
1157
|
-
end
|
1158
|
-
|
1159
|
-
it "extract single value as string in compatibility mode off" do
|
1160
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1161
|
-
assert_equal ["demo"], response_multiple_attr_values.attributes[:uid]
|
1162
|
-
# classes are not reloaded between tests so restore default
|
1163
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
it "extract first of multiple values as string for b/w compatibility" do
|
1167
|
-
assert_equal 'value1', response_multiple_attr_values.attributes[:another_value]
|
1168
|
-
end
|
1169
|
-
|
1170
|
-
it "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
|
1171
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1172
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes[:another_value]
|
1173
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1174
|
-
end
|
1175
|
-
|
1176
|
-
it "return array with all attributes when asked in XML order" do
|
1177
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
1178
|
-
end
|
1179
|
-
|
1180
|
-
it "return array with all attributes when asked in XML order in compatibility mode off" do
|
1181
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1182
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
1183
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1184
|
-
end
|
1185
|
-
|
1186
|
-
it "return first of multiple values when multiple Attribute tags in XML" do
|
1187
|
-
assert_equal 'role1', response_multiple_attr_values.attributes[:role]
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
it "return first of multiple values when multiple Attribute tags in XML in compatibility mode off" do
|
1191
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1192
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes[:role]
|
1193
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
it "return all of multiple values in reverse order when multiple Attribute tags in XML" do
|
1197
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
1198
|
-
end
|
1199
|
-
|
1200
|
-
it "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
|
1201
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1202
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
1203
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1204
|
-
end
|
1205
|
-
|
1206
|
-
it "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
|
1207
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1208
|
-
assert_equal ['role1', 'role2', 'role3'], response_with_multiple_attribute_statements.attributes.multi(:role)
|
1209
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
it "return nil value correctly" do
|
1213
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
1214
|
-
end
|
1215
|
-
|
1216
|
-
it "return nil value correctly when not in compatibility mode off" do
|
1217
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1218
|
-
assert_equal [nil], response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
1219
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
it "return multiple values including nil and empty string" do
|
1223
|
-
response = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
|
1224
|
-
assert_equal ["", "valuePresent", nil, nil], response.attributes.multi(:attribute_with_nils_and_empty_strings)
|
1225
|
-
end
|
1226
|
-
|
1227
|
-
it "return multiple values from [] when not in compatibility mode off" do
|
1228
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1229
|
-
assert_equal ["", "valuePresent", nil, nil], response_multiple_attr_values.attributes[:attribute_with_nils_and_empty_strings]
|
1230
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1231
|
-
end
|
1232
|
-
|
1233
|
-
it "check what happens when trying retrieve attribute that does not exists" do
|
1234
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
1235
|
-
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
1236
|
-
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
1237
|
-
|
1238
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1239
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
1240
|
-
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
1241
|
-
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
1242
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1243
|
-
end
|
1244
|
-
|
1245
|
-
end
|
1246
|
-
end
|
1247
|
-
|
1248
|
-
describe "#session_expires_at" do
|
1249
|
-
it "extract the value of the SessionNotOnOrAfter attribute" do
|
1250
|
-
assert response.session_expires_at.is_a?(Time)
|
1251
|
-
end
|
1252
|
-
|
1253
|
-
it "return nil when the value of the SessionNotOnOrAfter is not set" do
|
1254
|
-
assert_nil response_without_attributes.session_expires_at
|
1255
|
-
end
|
1256
|
-
end
|
1257
|
-
|
1258
|
-
describe "#success" do
|
1259
|
-
it "find a status code that says success" do
|
1260
|
-
response.success?
|
1261
|
-
end
|
1262
|
-
end
|
1263
|
-
|
1264
|
-
describe '#xpath_first_from_signed_assertion' do
|
1265
|
-
it 'not allow arbitrary code execution' do
|
1266
|
-
malicious_response_document = fixture('response_eval', false)
|
1267
|
-
malicious_response = OneLogin::RubySaml::Response.new(malicious_response_document)
|
1268
|
-
malicious_response.send(:xpath_first_from_signed_assertion)
|
1269
|
-
assert_nil $evalled
|
1270
|
-
end
|
1271
|
-
end
|
1272
|
-
|
1273
|
-
describe '#sign_document' do
|
1274
|
-
it 'Sign an unsigned SAML Response XML and initiate the SAML object with it' do
|
1275
|
-
xml = Base64.decode64(fixture("test_sign.xml"))
|
1276
|
-
|
1277
|
-
document = XMLSecurity::Document.new(xml)
|
1278
|
-
|
1279
|
-
formatted_cert = OneLogin::RubySaml::Utils.format_cert(ruby_saml_cert_text)
|
1280
|
-
cert = OpenSSL::X509::Certificate.new(formatted_cert)
|
1281
|
-
|
1282
|
-
formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(ruby_saml_key_text)
|
1283
|
-
private_key = OpenSSL::PKey::RSA.new(formatted_private_key)
|
1284
|
-
document.sign_document(private_key, cert)
|
1285
|
-
|
1286
|
-
signed_response = OneLogin::RubySaml::Response.new(document.to_s)
|
1287
|
-
settings.assertion_consumer_service_url = "http://recipient"
|
1288
|
-
settings.idp_cert = ruby_saml_cert_text
|
1289
|
-
signed_response.settings = settings
|
1290
|
-
Timecop.freeze(Time.parse("2015-03-18T04:50:24Z")) do
|
1291
|
-
assert signed_response.is_valid?
|
1292
|
-
end
|
1293
|
-
assert_empty signed_response.errors
|
1294
|
-
end
|
1295
|
-
end
|
1296
|
-
|
1297
|
-
describe '#want_assertion_signed' do
|
1298
|
-
before do
|
1299
|
-
settings.security[:want_assertions_signed] = true
|
1300
|
-
@signed_assertion = OneLogin::RubySaml::Response.new(response_document_with_signed_assertion, :settings => settings)
|
1301
|
-
@no_signed_assertion = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings)
|
1302
|
-
end
|
1303
|
-
|
1304
|
-
|
1305
|
-
it 'returns false if :want_assertion_signed enabled and Assertion not signed' do
|
1306
|
-
assert !@no_signed_assertion.send(:validate_signed_elements)
|
1307
|
-
assert_includes @no_signed_assertion.errors, "The Assertion of the Response is not signed and the SP requires it"
|
1308
|
-
|
1309
|
-
end
|
1310
|
-
|
1311
|
-
it 'returns true if :want_assertion_signed enabled and Assertion is signed' do
|
1312
|
-
assert @signed_assertion.send(:validate_signed_elements)
|
1313
|
-
assert_empty @signed_assertion.errors
|
1314
|
-
end
|
1315
|
-
end
|
1316
|
-
|
1317
|
-
describe "retrieve nameID" do
|
1318
|
-
it 'is possible when nameID inside the assertion' do
|
1319
|
-
response_valid_signed.settings = settings
|
1320
|
-
assert_equal "test@onelogin.com", response_valid_signed.nameid
|
1321
|
-
end
|
1322
|
-
|
1323
|
-
it 'is not possible when encryptID inside the assertion but no private key' do
|
1324
|
-
response_encrypted_nameid.settings = settings
|
1325
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
|
1326
|
-
assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
|
1327
|
-
end
|
1328
|
-
|
1329
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
|
1330
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
|
1331
|
-
end
|
1332
|
-
end
|
1333
|
-
|
1334
|
-
it 'is possible when encryptID inside the assertion and settings has the private key' do
|
1335
|
-
settings.private_key = ruby_saml_key_text
|
1336
|
-
response_encrypted_nameid.settings = settings
|
1337
|
-
assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
|
1338
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
|
1339
|
-
end
|
1340
|
-
|
1341
|
-
end
|
1342
|
-
|
1343
|
-
describe 'try to initialize an encrypted response' do
|
1344
|
-
it 'raise if an encrypted assertion is found and no sp private key to decrypt it' do
|
1345
|
-
error_msg = "An EncryptedAssertion found and no SP private key found on the settings to decrypt it. Be sure you provided the :settings parameter at the initialize method"
|
1346
|
-
|
1347
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1348
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
|
1349
|
-
end
|
1350
|
-
|
1351
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1352
|
-
response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1353
|
-
end
|
1354
|
-
|
1355
|
-
settings.certificate = ruby_saml_cert_text
|
1356
|
-
settings.private_key = ruby_saml_key_text
|
1357
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1358
|
-
response3 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
|
1359
|
-
response3.settings
|
1360
|
-
end
|
1361
|
-
end
|
1362
|
-
|
1363
|
-
it 'raise if an encrypted assertion is found and the sp private key is wrong' do
|
1364
|
-
settings.certificate = ruby_saml_cert_text
|
1365
|
-
wrong_private_key = ruby_saml_key_text.sub!('A', 'B')
|
1366
|
-
settings.private_key = wrong_private_key
|
1367
|
-
|
1368
|
-
error_msg = "Neither PUB key nor PRIV key: nested asn1 error"
|
1369
|
-
assert_raises(OpenSSL::PKey::RSAError, error_msg) do
|
1370
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1371
|
-
end
|
1372
|
-
end
|
1373
|
-
|
1374
|
-
it 'return true if an encrypted assertion is found and settings initialized with private_key' do
|
1375
|
-
settings.certificate = ruby_saml_cert_text
|
1376
|
-
settings.private_key = ruby_saml_key_text
|
1377
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1378
|
-
assert response.decrypted_document
|
1379
|
-
|
1380
|
-
response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_signed_assertion, :settings => settings)
|
1381
|
-
assert response2.decrypted_document
|
1382
|
-
|
1383
|
-
response3 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
|
1384
|
-
assert response3.decrypted_document
|
1385
|
-
|
1386
|
-
response4 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
|
1387
|
-
assert response4.decrypted_document
|
1388
|
-
|
1389
|
-
assert OneLogin::RubySaml::Response.new(
|
1390
|
-
Base64.encode64(File.read('test/responses/unsigned_encrypted_adfs.xml')),
|
1391
|
-
:settings => settings
|
1392
|
-
).decrypted_document
|
1393
|
-
end
|
1394
|
-
end
|
1395
|
-
|
1396
|
-
describe "retrieve nameID and attributes from encrypted assertion" do
|
1397
|
-
|
1398
|
-
before do
|
1399
|
-
settings.idp_cert_fingerprint = 'EE:17:4E:FB:A8:81:71:12:0D:2A:78:43:BC:E7:0C:07:58:79:F4:F4'
|
1400
|
-
settings.issuer = 'http://rubysaml.com:3000/saml/metadata'
|
1401
|
-
settings.assertion_consumer_service_url = 'http://rubysaml.com:3000/saml/acs'
|
1402
|
-
settings.certificate = ruby_saml_cert_text
|
1403
|
-
settings.private_key = ruby_saml_key_text
|
1404
|
-
end
|
1405
|
-
|
1406
|
-
it 'is possible when signed_message_encrypted_unsigned_assertion' do
|
1407
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1408
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1409
|
-
assert response.is_valid?
|
1410
|
-
assert_empty response.errors
|
1411
|
-
assert_equal "test", response.attributes[:uid]
|
1412
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1413
|
-
end
|
1414
|
-
end
|
1415
|
-
|
1416
|
-
it 'is possible when signed_message_encrypted_signed_assertion' do
|
1417
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_signed_assertion, :settings => settings)
|
1418
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1419
|
-
assert response.is_valid?
|
1420
|
-
assert_empty response.errors
|
1421
|
-
assert_equal "test", response.attributes[:uid]
|
1422
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1423
|
-
end
|
1424
|
-
end
|
1425
|
-
|
1426
|
-
it 'is possible when unsigned_message_encrypted_signed_assertion' do
|
1427
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
|
1428
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1429
|
-
assert response.is_valid?
|
1430
|
-
assert_empty response.errors
|
1431
|
-
assert_equal "test", response.attributes[:uid]
|
1432
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1433
|
-
end
|
1434
|
-
end
|
1435
|
-
|
1436
|
-
it 'is not possible when unsigned_message_encrypted_unsigned_assertion' do
|
1437
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
|
1438
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1439
|
-
assert !response.is_valid?
|
1440
|
-
assert_includes response.errors, "Found an unexpected number of Signature Element. SAML Response rejected"
|
1441
|
-
end
|
1442
|
-
end
|
1443
|
-
end
|
1444
|
-
|
1445
|
-
describe "#decrypt_assertion" do
|
1446
|
-
before do
|
1447
|
-
settings.private_key = ruby_saml_key_text
|
1448
|
-
end
|
1449
|
-
|
1450
|
-
describe "check right settings" do
|
1451
|
-
|
1452
|
-
it "is not possible to decrypt the assertion if no private key" do
|
1453
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1454
|
-
|
1455
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1456
|
-
response.document,
|
1457
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1458
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1459
|
-
)
|
1460
|
-
response.settings.private_key = nil
|
1461
|
-
|
1462
|
-
error_msg = "An EncryptedAssertion found and no SP private key found on the settings to decrypt it"
|
1463
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1464
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1465
|
-
end
|
1466
|
-
end
|
1467
|
-
|
1468
|
-
it "is possible to decrypt the assertion if private key" do
|
1469
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1470
|
-
|
1471
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1472
|
-
response.document,
|
1473
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1474
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1475
|
-
)
|
1476
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1477
|
-
|
1478
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1479
|
-
decrypted,
|
1480
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1481
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1482
|
-
)
|
1483
|
-
assert_nil encrypted_assertion_node2
|
1484
|
-
assert decrypted.name, "Assertion"
|
1485
|
-
end
|
1486
|
-
|
1487
|
-
it "is possible to decrypt the assertion if private key provided and EncryptedKey RetrievalMethod presents in response" do
|
1488
|
-
settings.private_key = ruby_saml_key_text
|
1489
|
-
resp = read_response('response_with_retrieval_method.xml')
|
1490
|
-
response = OneLogin::RubySaml::Response.new(resp, :settings => settings)
|
1491
|
-
|
1492
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1493
|
-
response.document,
|
1494
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1495
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1496
|
-
)
|
1497
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1498
|
-
|
1499
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1500
|
-
decrypted,
|
1501
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1502
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1503
|
-
)
|
1504
|
-
|
1505
|
-
assert_nil encrypted_assertion_node2
|
1506
|
-
assert decrypted.name, "Assertion"
|
1507
|
-
end
|
1508
|
-
|
1509
|
-
it "is possible to decrypt the assertion if private key but no saml namespace on the Assertion Element that is inside the EncryptedAssertion" do
|
1510
|
-
unsigned_message_encrypted_assertion_without_saml_namespace = read_response('unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64')
|
1511
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_assertion_without_saml_namespace, :settings => settings)
|
1512
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1513
|
-
response.document,
|
1514
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1515
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1516
|
-
)
|
1517
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1518
|
-
|
1519
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1520
|
-
decrypted,
|
1521
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1522
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1523
|
-
)
|
1524
|
-
assert_nil encrypted_assertion_node2
|
1525
|
-
assert decrypted.name, "Assertion"
|
1526
|
-
end
|
1527
|
-
end
|
1528
|
-
|
1529
|
-
describe "check different encrypt methods supported" do
|
1530
|
-
it "EncryptionMethod DES-192 && Key Encryption Algorithm RSA-1_5" do
|
1531
|
-
unsigned_message_des192_encrypted_signed_assertion = read_response('unsigned_message_des192_encrypted_signed_assertion.xml.base64')
|
1532
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_des192_encrypted_signed_assertion, :settings => settings)
|
1533
|
-
assert_equal "test", response.attributes[:uid]
|
1534
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1535
|
-
end
|
1536
|
-
|
1537
|
-
it "EncryptionMethod AES-128 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1538
|
-
unsigned_message_aes128_encrypted_signed_assertion = read_response('unsigned_message_aes128_encrypted_signed_assertion.xml.base64')
|
1539
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes128_encrypted_signed_assertion, :settings => settings)
|
1540
|
-
assert_equal "test", response.attributes[:uid]
|
1541
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1542
|
-
end
|
1543
|
-
|
1544
|
-
it "EncryptionMethod AES-192 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1545
|
-
unsigned_message_aes192_encrypted_signed_assertion = read_response('unsigned_message_aes192_encrypted_signed_assertion.xml.base64')
|
1546
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes192_encrypted_signed_assertion, :settings => settings)
|
1547
|
-
assert_equal "test", response.attributes[:uid]
|
1548
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1549
|
-
end
|
1550
|
-
|
1551
|
-
it "EncryptionMethod AES-256 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1552
|
-
unsigned_message_aes256_encrypted_signed_assertion = read_response('unsigned_message_aes256_encrypted_signed_assertion.xml.base64')
|
1553
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes256_encrypted_signed_assertion, :settings => settings)
|
1554
|
-
assert_equal "test", response.attributes[:uid]
|
1555
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1556
|
-
end
|
1557
|
-
end
|
1558
|
-
|
1559
|
-
end
|
1560
|
-
describe "test qualified name id in attributes" do
|
1561
|
-
|
1562
|
-
it "parsed the nameid" do
|
1563
|
-
response = OneLogin::RubySaml::Response.new(read_response("signed_nameid_in_atts.xml"), :settings => settings)
|
1564
|
-
response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
1565
|
-
assert_empty response.errors
|
1566
|
-
assert_equal "test", response.attributes[:uid]
|
1567
|
-
assert_equal "http://idp.example.com/metadata.php/ZdrjpwEdw22vKoxWAbZB78/gQ7s=", response.attributes.single('urn:oid:1.3.6.1.4.1.5923.1.1.1.10')
|
1568
|
-
end
|
1569
|
-
end
|
1570
|
-
|
1571
|
-
describe "test unqualified name id in attributes" do
|
1572
|
-
|
1573
|
-
it "parsed the nameid" do
|
1574
|
-
response = OneLogin::RubySaml::Response.new(read_response("signed_unqual_nameid_in_atts.xml"), :settings => settings)
|
1575
|
-
response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
1576
|
-
assert_empty response.errors
|
1577
|
-
assert_equal "test", response.attributes[:uid]
|
1578
|
-
assert_equal "ZdrjpwEdw22vKoxWAbZB78/gQ7s=", response.attributes.single('urn:oid:1.3.6.1.4.1.5923.1.1.1.10')
|
1579
|
-
end
|
1580
|
-
end
|
1581
|
-
|
1582
|
-
describe "signature wrapping attack with encrypted assertion" do
|
1583
|
-
it "should not be valid" do
|
1584
|
-
settings.private_key = ruby_saml_key_text
|
1585
|
-
signature_wrapping_attack = read_invalid_response("encrypted_new_attack.xml.base64")
|
1586
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1587
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1588
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1589
|
-
settings.idp_cert_fingerprint = "385b1eec71143f00db6af936e2ea12a28771d72c"
|
1590
|
-
assert !response_wrapped.is_valid?
|
1591
|
-
assert_includes response_wrapped.errors, "Found an invalid Signed Element. SAML Response rejected"
|
1592
|
-
end
|
1593
|
-
end
|
1594
|
-
|
1595
|
-
describe "signature wrapping attack - concealed SAML response body" do
|
1596
|
-
it "should not be valid" do
|
1597
|
-
signature_wrapping_attack = read_invalid_response("response_with_concealed_signed_assertion.xml")
|
1598
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1599
|
-
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
1600
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1601
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1602
|
-
assert !response_wrapped.is_valid?
|
1603
|
-
assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
|
1604
|
-
end
|
1605
|
-
end
|
1606
|
-
|
1607
|
-
describe "signature wrapping attack - doubled signed assertion SAML response" do
|
1608
|
-
it "should not be valid" do
|
1609
|
-
signature_wrapping_attack = read_invalid_response("response_with_doubled_signed_assertion.xml")
|
1610
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1611
|
-
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
1612
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1613
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1614
|
-
assert !response_wrapped.is_valid?
|
1615
|
-
assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
|
1616
|
-
end
|
1617
|
-
end
|
1618
|
-
end
|
1619
|
-
end
|