ruby-saml 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +14 -12
  3. data/README.md +67 -19
  4. data/changelog.md +23 -0
  5. data/lib/onelogin/ruby-saml/attributes.rb +24 -1
  6. data/lib/onelogin/ruby-saml/authrequest.rb +9 -4
  7. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +62 -24
  8. data/lib/onelogin/ruby-saml/logoutrequest.rb +7 -1
  9. data/lib/onelogin/ruby-saml/logoutresponse.rb +4 -0
  10. data/lib/onelogin/ruby-saml/metadata.rb +9 -1
  11. data/lib/onelogin/ruby-saml/response.rb +37 -15
  12. data/lib/onelogin/ruby-saml/saml_message.rb +6 -0
  13. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  14. data/lib/onelogin/ruby-saml/settings.rb +34 -2
  15. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +4 -0
  16. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -14
  17. data/lib/onelogin/ruby-saml/utils.rb +56 -0
  18. data/lib/onelogin/ruby-saml/version.rb +1 -1
  19. data/lib/xml_security.rb +34 -6
  20. data/ruby-saml.gemspec +8 -4
  21. metadata +22 -282
  22. data/test/certificates/certificate.der +0 -0
  23. data/test/certificates/certificate1 +0 -12
  24. data/test/certificates/certificate_without_head_foot +0 -1
  25. data/test/certificates/formatted_certificate +0 -14
  26. data/test/certificates/formatted_chained_certificate +0 -42
  27. data/test/certificates/formatted_private_key +0 -12
  28. data/test/certificates/formatted_rsa_private_key +0 -12
  29. data/test/certificates/invalid_certificate1 +0 -1
  30. data/test/certificates/invalid_certificate2 +0 -1
  31. data/test/certificates/invalid_certificate3 +0 -12
  32. data/test/certificates/invalid_chained_certificate1 +0 -1
  33. data/test/certificates/invalid_private_key1 +0 -1
  34. data/test/certificates/invalid_private_key2 +0 -1
  35. data/test/certificates/invalid_private_key3 +0 -10
  36. data/test/certificates/invalid_rsa_private_key1 +0 -1
  37. data/test/certificates/invalid_rsa_private_key2 +0 -1
  38. data/test/certificates/invalid_rsa_private_key3 +0 -10
  39. data/test/certificates/ruby-saml-2.crt +0 -15
  40. data/test/certificates/ruby-saml.crt +0 -14
  41. data/test/certificates/ruby-saml.key +0 -15
  42. data/test/idp_metadata_parser_test.rb +0 -594
  43. data/test/logging_test.rb +0 -62
  44. data/test/logout_requests/invalid_slo_request.xml +0 -6
  45. data/test/logout_requests/slo_request.xml +0 -4
  46. data/test/logout_requests/slo_request.xml.base64 +0 -1
  47. data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
  48. data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
  49. data/test/logout_requests/slo_request_with_session_index.xml +0 -5
  50. data/test/logout_responses/logoutresponse_fixtures.rb +0 -86
  51. data/test/logoutrequest_test.rb +0 -260
  52. data/test/logoutresponse_test.rb +0 -427
  53. data/test/metadata/idp_descriptor.xml +0 -26
  54. data/test/metadata/idp_descriptor_2.xml +0 -56
  55. data/test/metadata/idp_descriptor_3.xml +0 -14
  56. data/test/metadata/idp_descriptor_4.xml +0 -72
  57. data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
  58. data/test/metadata/idp_metadata_multi_certs.xml +0 -75
  59. data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
  60. data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
  61. data/test/metadata/idp_multiple_descriptors.xml +0 -59
  62. data/test/metadata/idp_multiple_descriptors_2.xml +0 -59
  63. data/test/metadata/no_idp_descriptor.xml +0 -21
  64. data/test/metadata_test.rb +0 -331
  65. data/test/request_test.rb +0 -340
  66. data/test/response_test.rb +0 -1629
  67. data/test/responses/adfs_response_sha1.xml +0 -46
  68. data/test/responses/adfs_response_sha256.xml +0 -46
  69. data/test/responses/adfs_response_sha384.xml +0 -46
  70. data/test/responses/adfs_response_sha512.xml +0 -46
  71. data/test/responses/adfs_response_xmlns.xml +0 -45
  72. data/test/responses/attackxee.xml +0 -13
  73. data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
  74. data/test/responses/invalids/empty_destination.xml.base64 +0 -1
  75. data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
  76. data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
  77. data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
  78. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  79. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  80. data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
  81. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
  82. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
  83. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
  84. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
  85. data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
  86. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  87. data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
  88. data/test/responses/invalids/no_conditions.xml.base64 +0 -1
  89. data/test/responses/invalids/no_id.xml.base64 +0 -1
  90. data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
  91. data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
  92. data/test/responses/invalids/no_nameid.xml.base64 +0 -1
  93. data/test/responses/invalids/no_saml2.xml.base64 +0 -1
  94. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  95. data/test/responses/invalids/no_status.xml.base64 +0 -1
  96. data/test/responses/invalids/no_status_code.xml.base64 +0 -1
  97. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
  98. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
  99. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
  100. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  101. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  102. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  103. data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
  104. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
  105. data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
  106. data/test/responses/no_signature_ns.xml +0 -48
  107. data/test/responses/open_saml_response.xml +0 -56
  108. data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
  109. data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
  110. data/test/responses/response_double_status_code.xml.base64 +0 -1
  111. data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
  112. data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
  113. data/test/responses/response_eval.xml +0 -7
  114. data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
  115. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  116. data/test/responses/response_node_text_attack2.xml.base64 +0 -1
  117. data/test/responses/response_node_text_attack3.xml.base64 +0 -1
  118. data/test/responses/response_unsigned_xml_base64 +0 -1
  119. data/test/responses/response_with_ampersands.xml +0 -139
  120. data/test/responses/response_with_ampersands.xml.base64 +0 -93
  121. data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
  122. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  123. data/test/responses/response_with_multiple_attribute_values.xml +0 -67
  124. data/test/responses/response_with_retrieval_method.xml +0 -26
  125. data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
  126. data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
  127. data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
  128. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  129. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  130. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  131. data/test/responses/response_without_attributes.xml.base64 +0 -79
  132. data/test/responses/response_without_reference_uri.xml.base64 +0 -1
  133. data/test/responses/response_wrapped.xml.base64 +0 -150
  134. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
  135. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  136. data/test/responses/signed_nameid_in_atts.xml +0 -47
  137. data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
  138. data/test/responses/simple_saml_php.xml +0 -71
  139. data/test/responses/starfield_response.xml.base64 +0 -1
  140. data/test/responses/test_sign.xml +0 -43
  141. data/test/responses/unsigned_encrypted_adfs.xml +0 -23
  142. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
  143. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
  144. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
  145. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
  146. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
  147. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
  148. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  149. data/test/responses/valid_response.xml.base64 +0 -1
  150. data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
  151. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  152. data/test/saml_message_test.rb +0 -56
  153. data/test/settings_test.rb +0 -338
  154. data/test/slo_logoutrequest_test.rb +0 -467
  155. data/test/slo_logoutresponse_test.rb +0 -233
  156. data/test/test_helper.rb +0 -333
  157. data/test/utils_test.rb +0 -259
  158. 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
@@ -1,1629 +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.sp_entity_id = 'invalid'
263
- response_valid_signed.settings = settings
264
- response_valid_signed.soft = false
265
- error_msg = generate_audience_error(response_valid_signed.settings.sp_entity_id, ['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.sp_entity_id = '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.sp_entity_id, ['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.sp_entity_id = '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.sp_entity_id = '{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.sp_entity_id = '{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.sp_entity_id = 'invalid_audience'
482
- assert !response.send(:validate_audience)
483
- assert_includes response.errors, generate_audience_error(response.settings.sp_entity_id, ['{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.sp_entity_id = "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 sp_entity_id defined" do
674
- response_valid_signed.settings = settings
675
- response_valid_signed.settings.sp_entity_id = 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.sp_entity_id = "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.sp_entity_id, ['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 cert expired and check_idp_cert_expiration enabled" do
884
- settings.idp_cert_fingerprint = nil
885
- settings.idp_cert = ruby_saml_cert_text
886
- settings.security[:check_idp_cert_expiration] = true
887
- response_valid_signed.settings = settings
888
- assert !response_valid_signed.send(:validate_signature)
889
- assert_includes response_valid_signed.errors, "IdP x509 certificate expired"
890
- end
891
-
892
- it "return false when no X509Certificate and the cert provided at settings mismatches" do
893
- settings.idp_cert_fingerprint = nil
894
- settings.idp_cert = signature_1
895
- response_valid_signed_without_x509certificate.settings = settings
896
- assert !response_valid_signed_without_x509certificate.send(:validate_signature)
897
- assert_includes response_valid_signed_without_x509certificate.errors, "Invalid Signature on SAML Response"
898
- end
899
-
900
- it "return true when no X509Certificate and the cert provided at settings matches" do
901
- settings.idp_cert_fingerprint = nil
902
- settings.idp_cert = ruby_saml_cert_text
903
- response_valid_signed_without_x509certificate.settings = settings
904
- assert response_valid_signed_without_x509certificate.send(:validate_signature)
905
- assert_empty response_valid_signed_without_x509certificate.errors
906
- end
907
-
908
- it "return false when signature wrapping attack" do
909
- signature_wrapping_attack = read_invalid_response("signature_wrapping_attack.xml.base64")
910
- response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack)
911
- response_wrapped.stubs(:conditions).returns(nil)
912
- response_wrapped.stubs(:validate_subject_confirmation).returns(true)
913
- settings.idp_cert_fingerprint = "afe71c28ef740bc87425be13a2263d37971da1f9"
914
- response_wrapped.settings = settings
915
- assert !response_wrapped.send(:validate_signature)
916
- assert_includes response_wrapped.errors, "Invalid Signature on SAML Response"
917
- assert_includes response_wrapped.errors, "Signed element id #pfxc3d2b542-0f7e-8767-8e87-5b0dc6913375 is not found"
918
- end
919
- end
920
-
921
- describe "#validate_signature with multiple idp certs" do
922
- it "return true when at least a cert on idp_cert_multi is valid" do
923
- settings.idp_cert_multi = {
924
- :signing => [ruby_saml_cert_text2, ruby_saml_cert_text],
925
- :encryption => []
926
- }
927
- response_valid_signed.settings = settings
928
- assert response_valid_signed.send(:validate_signature)
929
- assert_empty response_valid_signed.errors
930
- end
931
-
932
- it "return false when none cert on idp_cert_multi is valid" do
933
- settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
934
- settings.idp_cert_multi = {
935
- :signing => [ruby_saml_cert_text2, ruby_saml_cert_text2],
936
- :encryption => []
937
- }
938
- response_valid_signed.settings = settings
939
- assert !response_valid_signed.send(:validate_signature)
940
- assert_includes response_valid_signed.errors, "Invalid Signature on SAML Response"
941
- end
942
- end
943
-
944
- describe "#validate nameid" do
945
- it "return false when no nameid element and required by settings" do
946
- settings.security[:want_name_id] = true
947
- response_no_nameid.settings = settings
948
- assert !response_no_nameid.send(:validate_name_id)
949
- assert_includes response_no_nameid.errors, "No NameID element found in the assertion of the Response"
950
- end
951
-
952
- it "return false when no nameid element and required by settings" do
953
- response_empty_nameid.settings = settings
954
- assert !response_empty_nameid.send(:validate_name_id)
955
- assert_includes response_empty_nameid.errors, "An empty NameID value found"
956
- end
957
-
958
- it "return false when no nameid value" do
959
- response_empty_nameid.settings = settings
960
- assert !response_empty_nameid.send(:validate_name_id)
961
- assert_includes response_empty_nameid.errors, "An empty NameID value found"
962
- end
963
-
964
- it "return false when wrong_spnamequalifier" do
965
- settings.sp_entity_id = 'sp_entity_id'
966
- response_wrong_spnamequalifier.settings = settings
967
- assert !response_wrong_spnamequalifier.send(:validate_name_id)
968
- assert_includes response_wrong_spnamequalifier.errors, "The SPNameQualifier value mistmatch the SP entityID value."
969
- end
970
-
971
- it "return true when no nameid element but not required by settings" do
972
- settings.security[:want_name_id] = false
973
- response_no_nameid.settings = settings
974
- assert response_no_nameid.send(:validate_name_id)
975
- end
976
-
977
- it "return true when nameid is valid and response_wrong_spnamequalifier matches the SP issuer" do
978
- settings.sp_entity_id = 'wrong-sp-entityid'
979
- response_wrong_spnamequalifier.settings = settings
980
- assert response_wrong_spnamequalifier.send(:validate_name_id)
981
- end
982
- end
983
-
984
- describe "#nameid" do
985
- it "extract the value of the name id element" do
986
- assert_equal "support@onelogin.com", response.nameid
987
- assert_equal "someone@example.com", response_with_signed_assertion.nameid
988
- end
989
-
990
- it "be extractable from an OpenSAML response" do
991
- response_open_saml = OneLogin::RubySaml::Response.new(fixture(:open_saml))
992
- assert_equal "someone@example.org", response_open_saml.nameid
993
- end
994
-
995
- it "be extractable from a Simple SAML PHP response" do
996
- response_ssp = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
997
- assert_equal "someone@example.com", response_ssp.nameid
998
- end
999
- end
1000
-
1001
- describe "#name_id_format" do
1002
- it "extract the value of the name id element" do
1003
- assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response.name_id_format
1004
- assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_with_signed_assertion.name_id_format
1005
- end
1006
- end
1007
-
1008
- describe "#sessionindex" do
1009
- it "extract the value of the sessionindex element" do
1010
- response = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
1011
- assert_equal "_51be37965feb5579d803141076936dc2e9d1d98ebf", response.sessionindex
1012
- end
1013
- end
1014
-
1015
- describe "#check_one_conditions" do
1016
- it "return false when none or more than one conditions element" do
1017
- response_no_conditions.soft = true
1018
- assert !response_no_conditions.send(:validate_one_conditions)
1019
- assert_includes response_no_conditions.errors, "The Assertion must include one Conditions element"
1020
- end
1021
-
1022
- it "return true when one conditions element" do
1023
- response.soft = true
1024
- assert response.send(:validate_one_conditions)
1025
- end
1026
-
1027
- it "return true when no conditions are present and skip_conditions is true" do
1028
- response_no_conditions_with_skip.soft = true
1029
- assert response_no_conditions_with_skip.send(:validate_one_conditions)
1030
- end
1031
- end
1032
-
1033
- describe "#check_one_authnstatement" do
1034
- it "return false when none or more than one authnstatement element" do
1035
- response_no_authnstatement.soft = true
1036
- assert !response_no_authnstatement.send(:validate_one_authnstatement)
1037
- assert_includes response_no_authnstatement.errors, "The Assertion must include one AuthnStatement element"
1038
- end
1039
-
1040
- it "return true when one authnstatement element" do
1041
- response.soft = true
1042
- assert response.send(:validate_one_authnstatement)
1043
- end
1044
-
1045
- it "return true when SAML Response is empty but skip_authstatement option is used" do
1046
- response_no_authnstatement_with_skip.soft = true
1047
- assert response_no_authnstatement_with_skip.send(:validate_one_authnstatement)
1048
- assert_empty response_empty_destination_with_skip.errors
1049
- end
1050
- end
1051
-
1052
- describe "#check_conditions" do
1053
- it "check time conditions" do
1054
- response.soft = true
1055
- assert !response.send(:validate_conditions)
1056
- response_time_updated = OneLogin::RubySaml::Response.new(response_document_without_recipient_with_time_updated)
1057
- response_time_updated.soft = true
1058
- assert response_time_updated.send(:validate_conditions)
1059
- Timecop.freeze(Time.parse("2011-06-14T18:25:01.516Z")) do
1060
- response_with_saml2_namespace = OneLogin::RubySaml::Response.new(response_document_with_saml2_namespace)
1061
- response_with_saml2_namespace.soft = true
1062
- assert response_with_saml2_namespace.send(:validate_conditions)
1063
- end
1064
- end
1065
-
1066
- it "optionally allows for clock drift" do
1067
- # The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
1068
- Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
1069
- settings.soft = true
1070
- special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
1071
- response_document_with_saml2_namespace,
1072
- :allowed_clock_drift => 0.515,
1073
- :settings => settings
1074
- )
1075
- assert !special_response_with_saml2_namespace.send(:validate_conditions)
1076
- end
1077
-
1078
- Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
1079
- special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
1080
- response_document_with_saml2_namespace,
1081
- :allowed_clock_drift => 0.516
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
- settings.soft = true
1088
- special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
1089
- response_document_with_saml2_namespace,
1090
- :allowed_clock_drift => '0.515',
1091
- :settings => settings
1092
- )
1093
- assert !special_response_with_saml2_namespace.send(:validate_conditions)
1094
- end
1095
-
1096
- Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
1097
- special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
1098
- response_document_with_saml2_namespace,
1099
- :allowed_clock_drift => '0.516'
1100
- )
1101
- assert special_response_with_saml2_namespace.send(:validate_conditions)
1102
- end
1103
- end
1104
- end
1105
-
1106
- describe "#attributes" do
1107
- it "extract the first attribute in a hash accessed via its symbol" do
1108
- assert_equal "demo", response.attributes[:uid]
1109
- end
1110
-
1111
- it "extract the first attribute in a hash accessed via its name" do
1112
- assert_equal "demo", response.attributes["uid"]
1113
- end
1114
-
1115
- it "extract all attributes" do
1116
- assert_equal "demo", response.attributes[:uid]
1117
- assert_equal "value", response.attributes[:another_value]
1118
- end
1119
-
1120
- it "work for implicit namespaces" do
1121
- assert_equal "someone@example.com", response_with_signed_assertion.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
1122
- end
1123
-
1124
- it "extract attributes from all AttributeStatement tags" do
1125
- assert_equal "smith", response_with_multiple_attribute_statements.attributes[:surname]
1126
- assert_equal "bob", response_with_multiple_attribute_statements.attributes[:firstname]
1127
- end
1128
-
1129
- it "not raise on responses without attributes" do
1130
- assert_equal OneLogin::RubySaml::Attributes.new, response_unsigned.attributes
1131
- end
1132
-
1133
- describe "#encrypted attributes" do
1134
- it "raise error when the assertion contains encrypted attributes but no private key to decrypt" do
1135
- settings.private_key = nil
1136
- response_encrypted_attrs.settings = settings
1137
- assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedAttribute found and no SP private key found on the settings to decrypt it") do
1138
- attrs = response_encrypted_attrs.attributes
1139
- end
1140
- end
1141
-
1142
- it "extract attributes when the assertion contains encrypted attributes and the private key is provided" do
1143
- settings.certificate = ruby_saml_cert_text
1144
- settings.private_key = ruby_saml_key_text
1145
- response_encrypted_attrs.settings = settings
1146
- attributes = response_encrypted_attrs.attributes
1147
- assert_equal "test", attributes[:uid]
1148
- assert_equal "test@example.com", attributes[:mail]
1149
- end
1150
- end
1151
-
1152
- it "return false when validating a response with duplicate attributes" do
1153
- response_duplicated_attributes.settings = settings
1154
- response_duplicated_attributes.options[:check_duplicated_attributes] = true
1155
- assert !response_duplicated_attributes.send(:validate_no_duplicated_attributes)
1156
- assert_includes response_duplicated_attributes.errors, "Found an Attribute element with duplicated Name"
1157
- end
1158
-
1159
- it "return true when validating a response with duplicate attributes but skip check" do
1160
- response_duplicated_attributes.settings = settings
1161
- assert response_duplicated_attributes.send(:validate_no_duplicated_attributes)
1162
- end
1163
-
1164
- describe "#multiple values" do
1165
- it "extract single value as string" do
1166
- assert_equal "demo", response_multiple_attr_values.attributes[:uid]
1167
- end
1168
-
1169
- it "extract single value as string in compatibility mode off" do
1170
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1171
- assert_equal ["demo"], response_multiple_attr_values.attributes[:uid]
1172
- # classes are not reloaded between tests so restore default
1173
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1174
- end
1175
-
1176
- it "extract first of multiple values as string for b/w compatibility" do
1177
- assert_equal 'value1', response_multiple_attr_values.attributes[:another_value]
1178
- end
1179
-
1180
- it "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
1181
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1182
- assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes[:another_value]
1183
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1184
- end
1185
-
1186
- it "return array with all attributes when asked in XML order" do
1187
- assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
1188
- end
1189
-
1190
- it "return array with all attributes when asked in XML order in compatibility mode off" do
1191
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1192
- assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
1193
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1194
- end
1195
-
1196
- it "return first of multiple values when multiple Attribute tags in XML" do
1197
- assert_equal 'role1', response_multiple_attr_values.attributes[:role]
1198
- end
1199
-
1200
- it "return first of multiple values 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[:role]
1203
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1204
- end
1205
-
1206
- it "return all of multiple values in reverse order when multiple Attribute tags in XML" do
1207
- assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
1208
- end
1209
-
1210
- it "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
1211
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1212
- assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
1213
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1214
- end
1215
-
1216
- it "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
1217
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1218
- assert_equal ['role1', 'role2', 'role3'], response_with_multiple_attribute_statements.attributes.multi(:role)
1219
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1220
- end
1221
-
1222
- it "return nil value correctly" do
1223
- assert_nil response_multiple_attr_values.attributes[:attribute_with_nil_value]
1224
- end
1225
-
1226
- it "return nil value correctly when not in compatibility mode off" do
1227
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1228
- assert_equal [nil], response_multiple_attr_values.attributes[:attribute_with_nil_value]
1229
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1230
- end
1231
-
1232
- it "return multiple values including nil and empty string" do
1233
- response = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
1234
- assert_equal ["", "valuePresent", nil, nil], response.attributes.multi(:attribute_with_nils_and_empty_strings)
1235
- end
1236
-
1237
- it "return multiple values from [] when not in compatibility mode off" do
1238
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1239
- assert_equal ["", "valuePresent", nil, nil], response_multiple_attr_values.attributes[:attribute_with_nils_and_empty_strings]
1240
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1241
- end
1242
-
1243
- it "check what happens when trying retrieve attribute that does not exists" do
1244
- assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
1245
- assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
1246
- assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
1247
-
1248
- OneLogin::RubySaml::Attributes.single_value_compatibility = false
1249
- assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
1250
- assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
1251
- assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
1252
- OneLogin::RubySaml::Attributes.single_value_compatibility = true
1253
- end
1254
-
1255
- end
1256
- end
1257
-
1258
- describe "#session_expires_at" do
1259
- it "extract the value of the SessionNotOnOrAfter attribute" do
1260
- assert response.session_expires_at.is_a?(Time)
1261
- end
1262
-
1263
- it "return nil when the value of the SessionNotOnOrAfter is not set" do
1264
- assert_nil response_without_attributes.session_expires_at
1265
- end
1266
- end
1267
-
1268
- describe "#success" do
1269
- it "find a status code that says success" do
1270
- response.success?
1271
- end
1272
- end
1273
-
1274
- describe '#xpath_first_from_signed_assertion' do
1275
- it 'not allow arbitrary code execution' do
1276
- malicious_response_document = fixture('response_eval', false)
1277
- malicious_response = OneLogin::RubySaml::Response.new(malicious_response_document)
1278
- malicious_response.send(:xpath_first_from_signed_assertion)
1279
- assert_nil $evalled
1280
- end
1281
- end
1282
-
1283
- describe '#sign_document' do
1284
- it 'Sign an unsigned SAML Response XML and initiate the SAML object with it' do
1285
- xml = Base64.decode64(fixture("test_sign.xml"))
1286
-
1287
- document = XMLSecurity::Document.new(xml)
1288
-
1289
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(ruby_saml_cert_text)
1290
- cert = OpenSSL::X509::Certificate.new(formatted_cert)
1291
-
1292
- formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(ruby_saml_key_text)
1293
- private_key = OpenSSL::PKey::RSA.new(formatted_private_key)
1294
- document.sign_document(private_key, cert)
1295
-
1296
- signed_response = OneLogin::RubySaml::Response.new(document.to_s)
1297
- settings.assertion_consumer_service_url = "http://recipient"
1298
- settings.idp_cert = ruby_saml_cert_text
1299
- signed_response.settings = settings
1300
- Timecop.freeze(Time.parse("2015-03-18T04:50:24Z")) do
1301
- assert signed_response.is_valid?
1302
- end
1303
- assert_empty signed_response.errors
1304
- end
1305
- end
1306
-
1307
- describe '#want_assertion_signed' do
1308
- before do
1309
- settings.security[:want_assertions_signed] = true
1310
- @signed_assertion = OneLogin::RubySaml::Response.new(response_document_with_signed_assertion, :settings => settings)
1311
- @no_signed_assertion = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings)
1312
- end
1313
-
1314
-
1315
- it 'returns false if :want_assertion_signed enabled and Assertion not signed' do
1316
- assert !@no_signed_assertion.send(:validate_signed_elements)
1317
- assert_includes @no_signed_assertion.errors, "The Assertion of the Response is not signed and the SP requires it"
1318
-
1319
- end
1320
-
1321
- it 'returns true if :want_assertion_signed enabled and Assertion is signed' do
1322
- assert @signed_assertion.send(:validate_signed_elements)
1323
- assert_empty @signed_assertion.errors
1324
- end
1325
- end
1326
-
1327
- describe "retrieve nameID" do
1328
- it 'is possible when nameID inside the assertion' do
1329
- response_valid_signed.settings = settings
1330
- assert_equal "test@onelogin.com", response_valid_signed.nameid
1331
- end
1332
-
1333
- it 'is not possible when encryptID inside the assertion but no private key' do
1334
- response_encrypted_nameid.settings = settings
1335
- assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
1336
- assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
1337
- end
1338
-
1339
- assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
1340
- assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
1341
- end
1342
- end
1343
-
1344
- it 'is possible when encryptID inside the assertion and settings has the private key' do
1345
- settings.private_key = ruby_saml_key_text
1346
- response_encrypted_nameid.settings = settings
1347
- assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
1348
- assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
1349
- end
1350
-
1351
- end
1352
-
1353
- describe 'try to initialize an encrypted response' do
1354
- it 'raise if an encrypted assertion is found and no sp private key to decrypt it' do
1355
- 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"
1356
-
1357
- assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
1358
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
1359
- end
1360
-
1361
- assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
1362
- response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
1363
- end
1364
-
1365
- settings.certificate = ruby_saml_cert_text
1366
- settings.private_key = ruby_saml_key_text
1367
- assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
1368
- response3 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
1369
- response3.settings
1370
- end
1371
- end
1372
-
1373
- it 'raise if an encrypted assertion is found and the sp private key is wrong' do
1374
- settings.certificate = ruby_saml_cert_text
1375
- wrong_private_key = ruby_saml_key_text.sub!('A', 'B')
1376
- settings.private_key = wrong_private_key
1377
-
1378
- error_msg = "Neither PUB key nor PRIV key: nested asn1 error"
1379
- assert_raises(OpenSSL::PKey::RSAError, error_msg) do
1380
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
1381
- end
1382
- end
1383
-
1384
- it 'return true if an encrypted assertion is found and settings initialized with private_key' do
1385
- settings.certificate = ruby_saml_cert_text
1386
- settings.private_key = ruby_saml_key_text
1387
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
1388
- assert response.decrypted_document
1389
-
1390
- response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_signed_assertion, :settings => settings)
1391
- assert response2.decrypted_document
1392
-
1393
- response3 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
1394
- assert response3.decrypted_document
1395
-
1396
- response4 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
1397
- assert response4.decrypted_document
1398
-
1399
- assert OneLogin::RubySaml::Response.new(
1400
- Base64.encode64(File.read('test/responses/unsigned_encrypted_adfs.xml')),
1401
- :settings => settings
1402
- ).decrypted_document
1403
- end
1404
- end
1405
-
1406
- describe "retrieve nameID and attributes from encrypted assertion" do
1407
-
1408
- before do
1409
- settings.idp_cert_fingerprint = 'EE:17:4E:FB:A8:81:71:12:0D:2A:78:43:BC:E7:0C:07:58:79:F4:F4'
1410
- settings.sp_entity_id = 'http://rubysaml.com:3000/saml/metadata'
1411
- settings.assertion_consumer_service_url = 'http://rubysaml.com:3000/saml/acs'
1412
- settings.certificate = ruby_saml_cert_text
1413
- settings.private_key = ruby_saml_key_text
1414
- end
1415
-
1416
- it 'is possible when signed_message_encrypted_unsigned_assertion' do
1417
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_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 signed_message_encrypted_signed_assertion' do
1427
- response = OneLogin::RubySaml::Response.new(signed_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 possible when unsigned_message_encrypted_signed_assertion' do
1437
- response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
1438
- Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
1439
- assert response.is_valid?
1440
- assert_empty response.errors
1441
- assert_equal "test", response.attributes[:uid]
1442
- assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
1443
- end
1444
- end
1445
-
1446
- it 'is not possible when unsigned_message_encrypted_unsigned_assertion' do
1447
- response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
1448
- Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
1449
- assert !response.is_valid?
1450
- assert_includes response.errors, "Found an unexpected number of Signature Element. SAML Response rejected"
1451
- end
1452
- end
1453
- end
1454
-
1455
- describe "#decrypt_assertion" do
1456
- before do
1457
- settings.private_key = ruby_saml_key_text
1458
- end
1459
-
1460
- describe "check right settings" do
1461
-
1462
- it "is not possible to decrypt the assertion if no private key" do
1463
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
1464
-
1465
- encrypted_assertion_node = REXML::XPath.first(
1466
- response.document,
1467
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1468
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1469
- )
1470
- response.settings.private_key = nil
1471
-
1472
- error_msg = "An EncryptedAssertion found and no SP private key found on the settings to decrypt it"
1473
- assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
1474
- decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
1475
- end
1476
- end
1477
-
1478
- it "is possible to decrypt the assertion if private key" do
1479
- response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
1480
-
1481
- encrypted_assertion_node = REXML::XPath.first(
1482
- response.document,
1483
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1484
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1485
- )
1486
- decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
1487
-
1488
- encrypted_assertion_node2 = REXML::XPath.first(
1489
- decrypted,
1490
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1491
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1492
- )
1493
- assert_nil encrypted_assertion_node2
1494
- assert decrypted.name, "Assertion"
1495
- end
1496
-
1497
- it "is possible to decrypt the assertion if private key provided and EncryptedKey RetrievalMethod presents in response" do
1498
- settings.private_key = ruby_saml_key_text
1499
- resp = read_response('response_with_retrieval_method.xml')
1500
- response = OneLogin::RubySaml::Response.new(resp, :settings => settings)
1501
-
1502
- encrypted_assertion_node = REXML::XPath.first(
1503
- response.document,
1504
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1505
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1506
- )
1507
- decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
1508
-
1509
- encrypted_assertion_node2 = REXML::XPath.first(
1510
- decrypted,
1511
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1512
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1513
- )
1514
-
1515
- assert_nil encrypted_assertion_node2
1516
- assert decrypted.name, "Assertion"
1517
- end
1518
-
1519
- it "is possible to decrypt the assertion if private key but no saml namespace on the Assertion Element that is inside the EncryptedAssertion" do
1520
- unsigned_message_encrypted_assertion_without_saml_namespace = read_response('unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64')
1521
- response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_assertion_without_saml_namespace, :settings => settings)
1522
- encrypted_assertion_node = REXML::XPath.first(
1523
- response.document,
1524
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1525
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1526
- )
1527
- decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
1528
-
1529
- encrypted_assertion_node2 = REXML::XPath.first(
1530
- decrypted,
1531
- "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
1532
- { "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
1533
- )
1534
- assert_nil encrypted_assertion_node2
1535
- assert decrypted.name, "Assertion"
1536
- end
1537
- end
1538
-
1539
- describe "check different encrypt methods supported" do
1540
- it "EncryptionMethod DES-192 && Key Encryption Algorithm RSA-1_5" do
1541
- unsigned_message_des192_encrypted_signed_assertion = read_response('unsigned_message_des192_encrypted_signed_assertion.xml.base64')
1542
- response = OneLogin::RubySaml::Response.new(unsigned_message_des192_encrypted_signed_assertion, :settings => settings)
1543
- assert_equal "test", response.attributes[:uid]
1544
- assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
1545
- end
1546
-
1547
- it "EncryptionMethod AES-128 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
1548
- unsigned_message_aes128_encrypted_signed_assertion = read_response('unsigned_message_aes128_encrypted_signed_assertion.xml.base64')
1549
- response = OneLogin::RubySaml::Response.new(unsigned_message_aes128_encrypted_signed_assertion, :settings => settings)
1550
- assert_equal "test", response.attributes[:uid]
1551
- assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
1552
- end
1553
-
1554
- it "EncryptionMethod AES-192 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
1555
- unsigned_message_aes192_encrypted_signed_assertion = read_response('unsigned_message_aes192_encrypted_signed_assertion.xml.base64')
1556
- response = OneLogin::RubySaml::Response.new(unsigned_message_aes192_encrypted_signed_assertion, :settings => settings)
1557
- assert_equal "test", response.attributes[:uid]
1558
- assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
1559
- end
1560
-
1561
- it "EncryptionMethod AES-256 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
1562
- unsigned_message_aes256_encrypted_signed_assertion = read_response('unsigned_message_aes256_encrypted_signed_assertion.xml.base64')
1563
- response = OneLogin::RubySaml::Response.new(unsigned_message_aes256_encrypted_signed_assertion, :settings => settings)
1564
- assert_equal "test", response.attributes[:uid]
1565
- assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
1566
- end
1567
- end
1568
-
1569
- end
1570
- describe "test qualified name id in attributes" do
1571
-
1572
- it "parsed the nameid" do
1573
- response = OneLogin::RubySaml::Response.new(read_response("signed_nameid_in_atts.xml"), :settings => settings)
1574
- response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
1575
- assert_empty response.errors
1576
- assert_equal "test", response.attributes[:uid]
1577
- 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')
1578
- end
1579
- end
1580
-
1581
- describe "test unqualified name id in attributes" do
1582
-
1583
- it "parsed the nameid" do
1584
- response = OneLogin::RubySaml::Response.new(read_response("signed_unqual_nameid_in_atts.xml"), :settings => settings)
1585
- response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
1586
- assert_empty response.errors
1587
- assert_equal "test", response.attributes[:uid]
1588
- assert_equal "ZdrjpwEdw22vKoxWAbZB78/gQ7s=", response.attributes.single('urn:oid:1.3.6.1.4.1.5923.1.1.1.10')
1589
- end
1590
- end
1591
-
1592
- describe "signature wrapping attack with encrypted assertion" do
1593
- it "should not be valid" do
1594
- settings.private_key = ruby_saml_key_text
1595
- signature_wrapping_attack = read_invalid_response("encrypted_new_attack.xml.base64")
1596
- response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
1597
- response_wrapped.stubs(:conditions).returns(nil)
1598
- response_wrapped.stubs(:validate_subject_confirmation).returns(true)
1599
- settings.idp_cert_fingerprint = "385b1eec71143f00db6af936e2ea12a28771d72c"
1600
- assert !response_wrapped.is_valid?
1601
- assert_includes response_wrapped.errors, "Found an invalid Signed Element. SAML Response rejected"
1602
- end
1603
- end
1604
-
1605
- describe "signature wrapping attack - concealed SAML response body" do
1606
- it "should not be valid" do
1607
- signature_wrapping_attack = read_invalid_response("response_with_concealed_signed_assertion.xml")
1608
- response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
1609
- settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
1610
- response_wrapped.stubs(:conditions).returns(nil)
1611
- response_wrapped.stubs(:validate_subject_confirmation).returns(true)
1612
- assert !response_wrapped.is_valid?
1613
- assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
1614
- end
1615
- end
1616
-
1617
- describe "signature wrapping attack - doubled signed assertion SAML response" do
1618
- it "should not be valid" do
1619
- signature_wrapping_attack = read_invalid_response("response_with_doubled_signed_assertion.xml")
1620
- response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
1621
- settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
1622
- response_wrapped.stubs(:conditions).returns(nil)
1623
- response_wrapped.stubs(:validate_subject_confirmation).returns(true)
1624
- assert !response_wrapped.is_valid?
1625
- assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
1626
- end
1627
- end
1628
- end
1629
- end