ruby-saml 0.9.4 → 1.0.0

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

Potentially problematic release.


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

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/LICENSE +1 -1
  4. data/README.md +71 -15
  5. data/changelog.md +15 -6
  6. data/lib/onelogin/ruby-saml.rb +1 -0
  7. data/lib/onelogin/ruby-saml/attribute_service.rb +25 -2
  8. data/lib/onelogin/ruby-saml/attributes.rb +42 -23
  9. data/lib/onelogin/ruby-saml/authrequest.rb +33 -8
  10. data/lib/onelogin/ruby-saml/http_error.rb +7 -0
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +65 -10
  12. data/lib/onelogin/ruby-saml/logging.rb +14 -10
  13. data/lib/onelogin/ruby-saml/logoutrequest.rb +39 -14
  14. data/lib/onelogin/ruby-saml/logoutresponse.rb +166 -39
  15. data/lib/onelogin/ruby-saml/metadata.rb +40 -23
  16. data/lib/onelogin/ruby-saml/response.rb +562 -88
  17. data/lib/onelogin/ruby-saml/saml_message.rb +80 -14
  18. data/lib/onelogin/ruby-saml/settings.rb +62 -23
  19. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +210 -20
  20. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +44 -13
  21. data/lib/onelogin/ruby-saml/utils.rb +163 -40
  22. data/lib/onelogin/ruby-saml/version.rb +1 -1
  23. data/lib/schemas/saml-schema-metadata-2.0.xsd +0 -2
  24. data/lib/xml_security.rb +87 -29
  25. data/ruby-saml.gemspec +1 -0
  26. data/test/certificates/{r1_certificate2_base64 → certificate_without_head_foot} +0 -0
  27. data/test/certificates/formatted_certificate +14 -0
  28. data/test/certificates/formatted_private_key +12 -0
  29. data/test/certificates/formatted_rsa_private_key +12 -0
  30. data/test/certificates/invalid_certificate1 +1 -0
  31. data/test/certificates/invalid_certificate2 +1 -0
  32. data/test/certificates/invalid_certificate3 +12 -0
  33. data/test/certificates/invalid_private_key1 +1 -0
  34. data/test/certificates/invalid_private_key2 +1 -0
  35. data/test/certificates/invalid_private_key3 +10 -0
  36. data/test/certificates/invalid_rsa_private_key1 +1 -0
  37. data/test/certificates/invalid_rsa_private_key2 +1 -0
  38. data/test/certificates/invalid_rsa_private_key3 +10 -0
  39. data/test/idp_metadata_parser_test.rb +41 -4
  40. data/test/logging_test.rb +62 -0
  41. data/test/logout_requests/invalid_slo_request.xml +6 -0
  42. data/test/{responses → logout_requests}/slo_request.xml +0 -0
  43. data/test/logout_requests/slo_request.xml.base64 +1 -0
  44. data/test/logout_requests/slo_request_deflated.xml.base64 +1 -0
  45. data/test/logout_requests/slo_request_with_session_index.xml +5 -0
  46. data/test/{responses → logout_responses}/logoutresponse_fixtures.rb +6 -6
  47. data/test/logoutrequest_test.rb +79 -52
  48. data/test/logoutresponse_test.rb +206 -59
  49. data/test/metadata_test.rb +77 -7
  50. data/test/request_test.rb +80 -65
  51. data/test/response_test.rb +862 -189
  52. data/test/responses/attackxee.xml +13 -0
  53. data/test/responses/invalids/invalid_audience.xml.base64 +1 -0
  54. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +1 -0
  55. data/test/responses/invalids/invalid_issuer_message.xml.base64 +1 -0
  56. data/test/responses/invalids/invalid_signature_position.xml.base64 +1 -0
  57. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +1 -0
  58. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +1 -0
  59. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +1 -0
  60. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +1 -0
  61. data/test/responses/invalids/multiple_assertions.xml.base64 +2 -0
  62. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  63. data/test/responses/invalids/no_id.xml.base64 +1 -0
  64. data/test/responses/invalids/no_saml2.xml.base64 +1 -0
  65. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  66. data/test/responses/invalids/no_status.xml.base64 +1 -0
  67. data/test/responses/invalids/no_status_code.xml.base64 +1 -0
  68. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +1 -0
  69. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +1 -0
  70. data/test/responses/invalids/response_encrypted_attrs.xml.base64 +1 -0
  71. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +1 -0
  72. data/test/responses/invalids/status_code_responder.xml.base64 +1 -0
  73. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +1 -0
  74. data/test/responses/{response4.xml.base64 → response_assertion_wrapped.xml.base64} +0 -0
  75. data/test/responses/response_encrypted_nameid.xml.base64 +1 -0
  76. data/test/responses/response_unsigned_xml_base64 +1 -0
  77. data/test/responses/{response5.xml.base64 → response_with_saml2_namespace.xml.base64} +0 -0
  78. data/test/responses/{response3.xml.base64 → response_with_signed_assertion.xml.base64} +0 -0
  79. data/test/responses/{r1_response6.xml.base64 → response_with_signed_assertion_2.xml.base64} +0 -0
  80. data/test/responses/{response1.xml.base64 → response_with_undefined_recipient.xml.base64} +0 -0
  81. data/test/responses/{response2.xml.base64 → response_without_attributes.xml.base64} +0 -0
  82. data/test/responses/{wrapped_response_2.xml.base64 → response_wrapped.xml.base64} +0 -0
  83. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +1 -0
  84. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  85. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +1 -0
  86. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +1 -0
  87. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +1 -0
  88. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +1 -0
  89. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +1 -0
  90. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +1 -0
  91. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  92. data/test/responses/valid_response.xml.base64 +1 -0
  93. data/test/saml_message_test.rb +56 -0
  94. data/test/settings_test.rb +138 -1
  95. data/test/slo_logoutrequest_test.rb +239 -28
  96. data/test/slo_logoutresponse_test.rb +93 -71
  97. data/test/test_helper.rb +138 -31
  98. data/test/utils_test.rb +129 -25
  99. data/test/xml_security_test.rb +140 -71
  100. metadata +142 -25
  101. data/test/responses/response_node_text_attack.xml.base64 +0 -1
@@ -1,110 +1,257 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
3
  require 'onelogin/ruby-saml/logoutresponse'
4
- require 'responses/logoutresponse_fixtures'
4
+ require 'logout_responses/logoutresponse_fixtures'
5
5
 
6
6
  class RubySamlTest < Minitest::Test
7
7
 
8
8
  describe "Logoutresponse" do
9
+
10
+ let(:valid_logout_response_without_settings) { OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document) }
11
+ let(:valid_logout_response) { OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings) }
12
+
9
13
  describe "#new" do
10
14
  it "raise an exception when response is initialized with nil" do
11
15
  assert_raises(ArgumentError) { OneLogin::RubySaml::Logoutresponse.new(nil) }
12
16
  end
13
17
  it "default to empty settings" do
14
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new( valid_response)
15
- assert_nil logoutresponse.settings
18
+ assert_nil valid_logout_response_without_settings.settings
16
19
  end
17
20
  it "accept constructor-injected settings" do
18
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings)
19
- refute_nil logoutresponse.settings
21
+ refute_nil valid_logout_response.settings
20
22
  end
21
23
  it "accept constructor-injected options" do
22
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, nil, { :foo => :bar} )
24
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, nil, { :foo => :bar} )
23
25
  assert !logoutresponse.options.empty?
24
26
  end
25
27
  it "support base64 encoded responses" do
26
- expected_response = valid_response
27
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(expected_response), settings)
28
-
29
- assert_equal expected_response, logoutresponse.response
28
+ generated_logout_response = valid_logout_response_document
29
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(generated_logout_response), settings)
30
+ assert_equal generated_logout_response, logoutresponse.response
30
31
  end
31
32
  end
32
33
 
34
+ describe "#validate_structure" do
35
+ it "invalidates when the logout response has an invalid xml" do
36
+ settings.soft = true
37
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_logout_response_document, settings)
38
+ assert !logoutresponse.send(:validate_structure)
39
+ assert_includes logoutresponse.errors, "Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd"
40
+ end
41
+
42
+ it "raise when the logout response has an invalid xml" do
43
+ settings.soft = false
44
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_logout_response_document, settings)
45
+ assert_raises OneLogin::RubySaml::ValidationError do
46
+ logoutresponse.send(:validate_structure)
47
+ end
48
+ end
49
+ end
50
+
33
51
  describe "#validate" do
34
- it "validate the response" do
35
- in_relation_to_request_id = random_id
52
+ describe "when soft=true" do
53
+ before do
54
+ settings.soft = true
55
+ end
36
56
 
37
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
57
+ it "validate the logout response" do
58
+ in_relation_to_request_id = random_id
59
+ opts = { :matches_request_id => in_relation_to_request_id}
38
60
 
39
- assert logoutresponse.validate
61
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings, opts)
40
62
 
41
- assert_equal settings.issuer, logoutresponse.issuer
42
- assert_equal in_relation_to_request_id, logoutresponse.in_response_to
63
+ assert logoutresponse.validate
43
64
 
44
- assert logoutresponse.success?
45
- end
65
+ assert_equal settings.issuer, logoutresponse.issuer
66
+ assert_equal in_relation_to_request_id, logoutresponse.in_response_to
46
67
 
47
- it "invalidate responses with wrong id when given option :matches_uuid" do
68
+ assert logoutresponse.success?
69
+ assert_empty logoutresponse.errors
70
+ end
48
71
 
49
- expected_request_id = "_some_other_expected_uuid"
50
- opts = { :matches_request_id => expected_request_id}
72
+ it "validate the logout response extended" do
73
+ in_relation_to_request_id = random_id
74
+ settings.idp_entity_id = 'http://app.muda.no'
75
+ opts = { :matches_request_id => in_relation_to_request_id}
51
76
 
52
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
77
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings, opts)
78
+ assert logoutresponse.validate
79
+ assert_equal in_relation_to_request_id, logoutresponse.in_response_to
80
+ assert logoutresponse.success?
81
+ assert_empty logoutresponse.errors
82
+ end
53
83
 
54
- assert !logoutresponse.validate
55
- refute_equal expected_request_id, logoutresponse.in_response_to
56
- end
84
+ it "invalidate logout response when initiated with blank" do
85
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new("", settings)
86
+ assert !logoutresponse.validate
87
+ assert_includes logoutresponse.errors, "Blank logout response"
88
+ end
57
89
 
58
- it "invalidate responses with wrong request status" do
59
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
90
+ it "invalidate logout response when initiated with no idp cert or fingerprint" do
91
+ settings.idp_cert_fingerprint = nil
92
+ settings.idp_cert = nil
93
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings)
94
+ assert !logoutresponse.validate
95
+ assert_includes logoutresponse.errors, "No fingerprint or certificate on settings of the logout response"
96
+ end
60
97
 
61
- assert !logoutresponse.validate
62
- assert !logoutresponse.success?
63
- end
64
- end
98
+ it "invalidate logout response with wrong id when given option :matches_request_id" do
99
+ expected_request_id = "_some_other_expected_uuid"
100
+ opts = { :matches_request_id => expected_request_id}
65
101
 
66
- describe "#validate!" do
67
- it "validates good responses" do
68
- in_relation_to_request_id = random_id
102
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings, opts)
69
103
 
70
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
104
+ assert !logoutresponse.validate
105
+ refute_equal expected_request_id, logoutresponse.in_response_to
106
+ assert_includes logoutresponse.errors, "Response does not match the request ID, expected: <#{expected_request_id}>, but was: <#{logoutresponse.in_response_to}>"
107
+ end
71
108
 
72
- logoutresponse.validate!
73
- end
109
+ it "invalidate logout response with wrong request status" do
110
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
74
111
 
75
- it "raises validation error when matching for wrong request id" do
112
+ assert !logoutresponse.success?
113
+ assert !logoutresponse.validate
114
+ assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
115
+ assert_includes logoutresponse.errors, "The status code of the Logout Response was not Success, was Requester"
116
+ end
76
117
 
77
- expected_request_id = "_some_other_expected_id"
78
- opts = { :matches_request_id => expected_request_id}
118
+ it "invalidate logout response when in lack of issuer setting" do
119
+ bad_settings = settings
120
+ bad_settings.issuer = nil
121
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, bad_settings)
122
+ assert !logoutresponse.validate
123
+ assert_includes logoutresponse.errors, "No issuer in settings of the logout response"
124
+ end
79
125
 
80
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
126
+ it "invalidate logout response with wrong issuer" do
127
+ in_relation_to_request_id = random_id
128
+ settings.idp_entity_id = 'http://invalid.issuer.example.com/'
129
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
130
+ assert !logoutresponse.validate
131
+ assert_includes logoutresponse.errors, "Doesn't match the issuer, expected: <#{logoutresponse.settings.idp_entity_id}>, but was: <http://app.muda.no>"
132
+ end
81
133
 
82
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
83
134
  end
84
135
 
85
- it "raise validation error for wrong request status" do
86
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
136
+ describe "when soft=false" do
137
+ before do
138
+ settings.soft = false
139
+ end
87
140
 
88
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
89
- end
141
+ it "validates good logout response" do
142
+ in_relation_to_request_id = random_id
90
143
 
91
- it "raise validation error when in bad state" do
92
- # no settings
93
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response)
94
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
95
- end
144
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
145
+ assert logoutresponse.validate
146
+ assert_empty logoutresponse.errors
147
+ end
148
+
149
+ it "raises validation error when response initiated with blank" do
150
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new("", settings)
96
151
 
97
- it "raise validation error when in lack of issuer setting" do
98
- bad_settings = settings
99
- bad_settings.issuer = nil
100
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, bad_settings)
101
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
152
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
153
+ assert_includes logoutresponse.errors, "Blank logout response"
154
+ end
155
+
156
+ it "raises validation error when initiated with no idp cert or fingerprint" do
157
+ settings.idp_cert_fingerprint = nil
158
+ settings.idp_cert = nil
159
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings)
160
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
161
+ assert_includes logoutresponse.errors, "No fingerprint or certificate on settings of the logout response"
162
+ end
163
+
164
+ it "raises validation error when matching for wrong request id" do
165
+
166
+ expected_request_id = "_some_other_expected_id"
167
+ opts = { :matches_request_id => expected_request_id}
168
+
169
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings, opts)
170
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
171
+ assert_includes logoutresponse.errors, "Response does not match the request ID, expected: <#{expected_request_id}>, but was: <#{logoutresponse.in_response_to}>"
172
+ end
173
+
174
+ it "raise validation error for wrong request status" do
175
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
176
+
177
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
178
+ assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
179
+ end
180
+
181
+ it "raise validation error when in bad state" do
182
+ # no settings
183
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
184
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
185
+ assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
186
+ end
187
+
188
+ it "raise validation error when in lack of issuer setting" do
189
+ settings.issuer = nil
190
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
191
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
192
+ assert_includes logoutresponse.errors, "No issuer in settings of the logout response"
193
+ end
194
+
195
+ it "raise validation error when logout response with wrong issuer" do
196
+ in_relation_to_request_id = random_id
197
+ settings.idp_entity_id = 'http://invalid.issuer.example.com/'
198
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
199
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
200
+ assert_includes logoutresponse.errors, "Doesn't match the issuer, expected: <#{logoutresponse.settings.idp_entity_id}>, but was: <http://app.muda.no>"
201
+ end
102
202
  end
103
203
 
104
- it "raise error for invalid xml" do
105
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
204
+ describe "#validate_signature" do
205
+ let (:params) { OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, random_id, "Custom Logout Message", :RelayState => 'http://example.com') }
206
+
207
+ before do
208
+ settings.soft = true
209
+ settings.idp_slo_target_url = "http://example.com?field=value"
210
+ settings.security[:logout_responses_signed] = true
211
+ settings.security[:embed_sign] = false
212
+ settings.certificate = ruby_saml_cert_text
213
+ settings.private_key = ruby_saml_key_text
214
+ settings.idp_cert = ruby_saml_cert_text
215
+ end
216
+
217
+ it "return true when valid RSA_SHA1 Signature" do
218
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
219
+ params['RelayState'] = params[:RelayState]
220
+ options = {}
221
+ options[:get_params] = params
222
+ logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
223
+ assert logoutresponse_sign_test.send(:validate_signature)
224
+ end
225
+
226
+ it "return true when valid RSA_SHA256 Signature" do
227
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
228
+ params['RelayState'] = params[:RelayState]
229
+ options = {}
230
+ options[:get_params] = params
231
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
232
+ assert logoutresponse.send(:validate_signature)
233
+ end
234
+
235
+ it "return false when invalid RSA_SHA1 Signature" do
236
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
237
+ params['RelayState'] = 'http://invalid.example.com'
238
+ options = {}
239
+ options[:get_params] = params
240
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
241
+ assert !logoutresponse.send(:validate_signature)
242
+ end
243
+
244
+ it "raise when invalid RSA_SHA1 Signature" do
245
+ settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
246
+ settings.soft = false
247
+ params['RelayState'] = 'http://invalid.example.com'
248
+ options = {}
249
+ options[:get_params] = params
250
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
106
251
 
107
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
252
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.send(:validate_signature) }
253
+ assert logoutresponse.errors.include? "Invalid Signature on Logout Response"
254
+ end
108
255
  end
109
256
  end
110
257
  end
@@ -33,10 +33,31 @@ class MetadataTest < Minitest::Test
33
33
 
34
34
  assert_equal "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", acs.attribute("Binding").value
35
35
  assert_equal "https://foo.example/saml/consume", acs.attribute("Location").value
36
+
37
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
36
38
  end
37
39
 
38
40
  it "generates Service Provider Metadata" do
39
- # assert correct xml declaration
41
+ settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
42
+ settings.single_logout_service_url = "https://foo.example/saml/sls"
43
+ xml_metadata = OneLogin::RubySaml::Metadata.new.generate(settings, false)
44
+
45
+ start = "<?xml version='1.0' encoding='UTF-8'?><md:EntityDescriptor"
46
+ assert_equal xml_metadata[0..start.length-1],start
47
+
48
+ doc_metadata = REXML::Document.new(xml_metadata)
49
+ sls = REXML::XPath.first(doc_metadata, "//md:SingleLogoutService")
50
+
51
+ assert_equal "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", sls.attribute("Binding").value
52
+ assert_equal "https://foo.example/saml/sls", sls.attribute("Location").value
53
+ assert_equal "https://foo.example/saml/sls", sls.attribute("ResponseLocation").value
54
+ assert_nil sls.attribute("isDefault")
55
+ assert_nil sls.attribute("index")
56
+
57
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
58
+ end
59
+
60
+ it "generates Service Provider Metadata with single logout service" do
40
61
  start = "<?xml version='1.0' encoding='UTF-8'?><md:EntityDescriptor"
41
62
  assert_equal xml_text[0..start.length-1], start
42
63
 
@@ -50,27 +71,50 @@ class MetadataTest < Minitest::Test
50
71
 
51
72
  assert_equal "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", acs.attribute("Binding").value
52
73
  assert_equal "https://foo.example/saml/consume", acs.attribute("Location").value
74
+
75
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
53
76
  end
54
77
 
55
78
  describe "when auth requests are signed" do
56
- let(:cert_node) do
57
- REXML::XPath.first(
79
+ let(:key_descriptors) do
80
+ REXML::XPath.match(
81
+ xml_doc,
82
+ "//md:KeyDescriptor",
83
+ "md" => "urn:oasis:names:tc:SAML:2.0:metadata"
84
+ )
85
+ end
86
+ let(:cert_nodes) do
87
+ REXML::XPath.match(
58
88
  xml_doc,
59
89
  "//md:KeyDescriptor/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
60
90
  "md" => "urn:oasis:names:tc:SAML:2.0:metadata",
61
91
  "ds" => "http://www.w3.org/2000/09/xmldsig#"
62
92
  )
63
93
  end
64
- let(:cert) { OpenSSL::X509::Certificate.new(Base64.decode64(cert_node.text)) }
94
+ let(:cert) { OpenSSL::X509::Certificate.new(Base64.decode64(cert_nodes[0].text)) }
65
95
 
66
96
  before do
67
- settings.security[:authn_requests_signed] = true
68
97
  settings.certificate = ruby_saml_cert_text
69
98
  end
70
99
 
71
- it "generates Service Provider Metadata with X509Certificate" do
100
+ it "generates Service Provider Metadata with AuthnRequestsSigned" do
101
+ settings.security[:authn_requests_signed] = true
72
102
  assert_equal "true", spsso_descriptor.attribute("AuthnRequestsSigned").value
73
103
  assert_equal ruby_saml_cert.to_der, cert.to_der
104
+
105
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
106
+ end
107
+
108
+ it "generates Service Provider Metadata with X509Certificate for sign and encrypt" do
109
+ assert_equal 2, key_descriptors.length
110
+ assert_equal "signing", key_descriptors[0].attribute("use").value
111
+ assert_equal "encryption", key_descriptors[1].attribute("use").value
112
+
113
+ assert_equal 2, cert_nodes.length
114
+ assert_equal ruby_saml_cert.to_der, cert.to_der
115
+ assert_equal cert_nodes[0].text, cert_nodes[1].text
116
+
117
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
74
118
  end
75
119
  end
76
120
 
@@ -93,7 +137,29 @@ class MetadataTest < Minitest::Test
93
137
  assert_equal "Name", req_attr.attribute("Name").value
94
138
  assert_equal "Name Format", req_attr.attribute("NameFormat").value
95
139
  assert_equal "Friendly Name", req_attr.attribute("FriendlyName").value
96
- assert_equal "Attribute Value", REXML::XPath.first(xml_doc, "//md:AttributeValue").text.strip
140
+ assert_equal "Attribute Value", REXML::XPath.first(xml_doc, "//saml:AttributeValue").text.strip
141
+
142
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
143
+ end
144
+
145
+ describe "#service_name" do
146
+ before do
147
+ settings.attribute_consuming_service.service_name("Test2 Service")
148
+ end
149
+
150
+ it "change service name" do
151
+ assert_equal REXML::XPath.first(xml_doc, "//md:ServiceName").text.strip, "Test2 Service"
152
+ end
153
+ end
154
+
155
+ describe "#service_index" do
156
+ before do
157
+ settings.attribute_consuming_service.service_index(2)
158
+ end
159
+
160
+ it "change service index" do
161
+ assert_equal "2", attr_svc.attribute("index").value
162
+ end
97
163
  end
98
164
  end
99
165
 
@@ -110,6 +176,8 @@ class MetadataTest < Minitest::Test
110
176
  assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], xml_text
111
177
  signed_metadata = XMLSecurity::SignedDocument.new(xml_text)
112
178
  assert signed_metadata.validate_document(ruby_saml_cert_fingerprint, false)
179
+
180
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
113
181
  end
114
182
 
115
183
  describe "when digest and signature methods are specified" do
@@ -126,6 +194,8 @@ class MetadataTest < Minitest::Test
126
194
  signed_metadata_2 = XMLSecurity::SignedDocument.new(xml_text)
127
195
 
128
196
  assert signed_metadata_2.validate_document(ruby_saml_cert_fingerprint, false)
197
+
198
+ assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
129
199
  end
130
200
  end
131
201
  end