ruby-saml 0.8.18 → 0.9

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -6
  4. data/Gemfile +2 -12
  5. data/README.md +363 -35
  6. data/Rakefile +14 -0
  7. data/changelog.md +22 -9
  8. data/lib/onelogin/ruby-saml/attribute_service.rb +34 -0
  9. data/lib/onelogin/ruby-saml/attributes.rb +26 -64
  10. data/lib/onelogin/ruby-saml/authrequest.rb +47 -93
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
  12. data/lib/onelogin/ruby-saml/logoutrequest.rb +36 -100
  13. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -35
  14. data/lib/onelogin/ruby-saml/metadata.rb +46 -16
  15. data/lib/onelogin/ruby-saml/response.rb +63 -373
  16. data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +54 -122
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +25 -71
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +37 -102
  20. data/lib/onelogin/ruby-saml/utils.rb +32 -199
  21. data/lib/onelogin/ruby-saml/version.rb +1 -1
  22. data/lib/ruby-saml.rb +5 -2
  23. data/lib/schemas/{saml20assertion_schema.xsd → saml-schema-assertion-2.0.xsd} +283 -283
  24. data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
  25. data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
  26. data/lib/schemas/saml-schema-metadata-2.0.xsd +339 -0
  27. data/lib/schemas/{saml20protocol_schema.xsd → saml-schema-protocol-2.0.xsd} +302 -302
  28. data/lib/schemas/sstc-metadata-attr.xsd +35 -0
  29. data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
  30. data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
  31. data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
  32. data/lib/schemas/{xenc_schema.xsd → xenc-schema.xsd} +1 -11
  33. data/lib/schemas/xml.xsd +287 -0
  34. data/lib/schemas/{xmldsig_schema.xsd → xmldsig-core-schema.xsd} +0 -9
  35. data/lib/xml_security.rb +83 -235
  36. data/ruby-saml.gemspec +1 -0
  37. data/test/idp_metadata_parser_test.rb +54 -0
  38. data/test/logoutrequest_test.rb +68 -155
  39. data/test/logoutresponse_test.rb +43 -32
  40. data/test/metadata_test.rb +87 -0
  41. data/test/request_test.rb +102 -99
  42. data/test/response_test.rb +181 -495
  43. data/test/responses/idp_descriptor.xml +3 -0
  44. data/test/responses/logoutresponse_fixtures.rb +7 -8
  45. data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
  46. data/test/responses/response_with_multiple_attribute_values.xml +1 -1
  47. data/test/responses/slo_request.xml +4 -0
  48. data/test/settings_test.rb +25 -112
  49. data/test/slo_logoutrequest_test.rb +40 -50
  50. data/test/slo_logoutresponse_test.rb +86 -185
  51. data/test/test_helper.rb +27 -102
  52. data/test/xml_security_test.rb +114 -337
  53. metadata +30 -81
  54. data/lib/onelogin/ruby-saml/setting_error.rb +0 -6
  55. data/test/certificates/certificate.der +0 -0
  56. data/test/certificates/formatted_certificate +0 -14
  57. data/test/certificates/formatted_chained_certificate +0 -42
  58. data/test/certificates/formatted_private_key +0 -12
  59. data/test/certificates/formatted_rsa_private_key +0 -12
  60. data/test/certificates/invalid_certificate1 +0 -1
  61. data/test/certificates/invalid_certificate2 +0 -1
  62. data/test/certificates/invalid_certificate3 +0 -12
  63. data/test/certificates/invalid_chained_certificate1 +0 -1
  64. data/test/certificates/invalid_private_key1 +0 -1
  65. data/test/certificates/invalid_private_key2 +0 -1
  66. data/test/certificates/invalid_private_key3 +0 -10
  67. data/test/certificates/invalid_rsa_private_key1 +0 -1
  68. data/test/certificates/invalid_rsa_private_key2 +0 -1
  69. data/test/certificates/invalid_rsa_private_key3 +0 -10
  70. data/test/certificates/ruby-saml-2.crt +0 -15
  71. data/test/requests/logoutrequest_fixtures.rb +0 -47
  72. data/test/responses/encrypted_new_attack.xml.base64 +0 -1
  73. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  74. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  75. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  76. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  77. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  78. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  79. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  80. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  81. data/test/responses/response_with_concealed_signed_assertion.xml +0 -51
  82. data/test/responses/response_with_doubled_signed_assertion.xml +0 -49
  83. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  84. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  85. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  86. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  87. data/test/responses/response_wrapped.xml.base64 +0 -150
  88. data/test/responses/valid_response.xml.base64 +0 -1
  89. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  90. data/test/utils_test.rb +0 -231
@@ -1,16 +1,14 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class LogoutRequestTest < Minitest::Test
3
+ class RequestTest < Test::Unit::TestCase
4
4
 
5
- describe "Logoutrequest" do
6
- let(:settings) { OneLogin::RubySaml::Settings.new }
5
+ context "Logoutrequest" do
6
+ settings = OneLogin::RubySaml::Settings.new
7
7
 
8
- before do
8
+ should "create the deflated SAMLRequest URL parameter" do
9
9
  settings.idp_slo_target_url = "http://unauth.com/logout"
10
10
  settings.name_identifier_value = "f00f00"
11
- end
12
11
 
13
- it "create the deflated SAMLRequest URL parameter" do
14
12
  unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
15
13
  assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLRequest=/
16
14
 
@@ -19,7 +17,8 @@ class LogoutRequestTest < Minitest::Test
19
17
  assert_match /^<samlp:LogoutRequest/, inflated
20
18
  end
21
19
 
22
- it "support additional params" do
20
+ should "support additional params" do
21
+
23
22
  unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :hello => nil })
24
23
  assert unauth_url =~ /&hello=$/
25
24
 
@@ -27,8 +26,9 @@ class LogoutRequestTest < Minitest::Test
27
26
  assert unauth_url =~ /&foo=bar$/
28
27
  end
29
28
 
30
- it "set sessionindex" do
31
- sessionidx = random_id
29
+ should "set sessionindex" do
30
+ settings.idp_slo_target_url = "http://example.com"
31
+ sessionidx = UUID.new.generate
32
32
  settings.sessionindex = sessionidx
33
33
 
34
34
  unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :name_id => "there" })
@@ -38,7 +38,9 @@ class LogoutRequestTest < Minitest::Test
38
38
  assert_match %r(#{sessionidx}</samlp:SessionIndex>), inflated
39
39
  end
40
40
 
41
- it "set name_identifier_value" do
41
+ should "set name_identifier_value" do
42
+ settings = OneLogin::RubySaml::Settings.new
43
+ settings.idp_slo_target_url = "http://example.com"
42
44
  settings.name_identifier_format = "transient"
43
45
  name_identifier_value = "abc123"
44
46
  settings.name_identifier_value = name_identifier_value
@@ -50,25 +52,33 @@ class LogoutRequestTest < Minitest::Test
50
52
  assert_match %r(#{name_identifier_value}</saml:NameID>), inflated
51
53
  end
52
54
 
53
- describe "when the target url doesn't contain a query string" do
54
- it "create the SAMLRequest parameter correctly" do
55
+ context "when the target url doesn't contain a query string" do
56
+ should "create the SAMLRequest parameter correctly" do
57
+ settings = OneLogin::RubySaml::Settings.new
55
58
  settings.idp_slo_target_url = "http://example.com"
59
+ settings.name_identifier_value = "f00f00"
60
+
56
61
  unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
57
62
  assert unauth_url =~ /^http:\/\/example.com\?SAMLRequest/
58
63
  end
59
64
  end
60
65
 
61
- describe "when the target url contains a query string" do
62
- it "create the SAMLRequest parameter correctly" do
66
+ context "when the target url contains a query string" do
67
+ should "create the SAMLRequest parameter correctly" do
68
+ settings = OneLogin::RubySaml::Settings.new
63
69
  settings.idp_slo_target_url = "http://example.com?field=value"
70
+ settings.name_identifier_value = "f00f00"
71
+
64
72
  unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
65
73
  assert unauth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
66
74
  end
67
75
  end
68
76
 
69
- describe "consumation of logout may need to track the transaction" do
70
- it "have access to the request uuid" do
77
+ context "consumation of logout may need to track the transaction" do
78
+ should "have access to the request uuid" do
79
+ settings = OneLogin::RubySaml::Settings.new
71
80
  settings.idp_slo_target_url = "http://example.com?field=value"
81
+ settings.name_identifier_value = "f00f00"
72
82
 
73
83
  unauth_req = OneLogin::RubySaml::Logoutrequest.new
74
84
  unauth_url = unauth_req.create(settings)
@@ -78,178 +88,81 @@ class LogoutRequestTest < Minitest::Test
78
88
  end
79
89
  end
80
90
 
81
-
82
- describe "when the settings indicate to sign (embedded) logout request" do
83
-
84
- before do
91
+ context "when the settings indicate to sign (embebed) the logout request" do
92
+ should "created a signed logout request" do
93
+ settings = OneLogin::RubySaml::Settings.new
94
+ settings.idp_slo_target_url = "http://example.com?field=value"
95
+ settings.name_identifier_value = "f00f00"
85
96
  # sign the logout request
86
97
  settings.security[:logout_requests_signed] = true
87
98
  settings.security[:embed_sign] = true
88
99
  settings.certificate = ruby_saml_cert_text
89
100
  settings.private_key = ruby_saml_key_text
90
- end
91
-
92
- it "doesn't sign through create_xml_document" do
93
- unauth_req = OneLogin::RubySaml::Logoutrequest.new
94
- inflated = unauth_req.create_xml_document(settings).to_s
95
-
96
- refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
97
- refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
98
- refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
99
- end
100
-
101
- it "sign unsigned request" do
102
- unauth_req = OneLogin::RubySaml::Logoutrequest.new
103
- unauth_req_doc = unauth_req.create_xml_document(settings)
104
- inflated = unauth_req_doc.to_s
105
-
106
- refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
107
- refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
108
- refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
109
-
110
- inflated = unauth_req.sign_document(unauth_req_doc, settings).to_s
111
-
112
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
113
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
114
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
115
- end
116
-
117
- it "signs through create_logout_request_xml_doc" do
118
- unauth_req = OneLogin::RubySaml::Logoutrequest.new
119
- inflated = unauth_req.create_logout_request_xml_doc(settings).to_s
120
-
121
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
122
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
123
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
124
- end
125
-
126
- it "created a signed logout request" do
127
- settings.compress_request = true
128
101
 
129
102
  unauth_req = OneLogin::RubySaml::Logoutrequest.new
130
103
  unauth_url = unauth_req.create(settings)
131
104
 
132
105
  inflated = decode_saml_request_payload(unauth_url)
133
106
  assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
134
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
135
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
136
107
  end
137
108
 
138
- it "create a signed logout request with 256 digest and signature method" do
109
+ should "create a signed logout request with 256 digest and signature methods" do
110
+ settings = OneLogin::RubySaml::Settings.new
139
111
  settings.compress_request = false
140
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
141
- settings.security[:digest_method] = XMLSecurity::Document::SHA256
142
-
143
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
144
- request_xml = Base64.decode64(params["SAMLRequest"])
145
-
146
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
147
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
148
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha256'/>], request_xml
149
- end
150
-
151
- it "create a signed logout request with 512 digest and signature method RSA_SHA384" do
152
- settings.compress_request = false
153
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
112
+ settings.idp_slo_target_url = "http://example.com?field=value"
113
+ settings.name_identifier_value = "f00f00"
114
+ # sign the logout request
115
+ settings.security[:logout_requests_signed] = true
116
+ settings.security[:embed_sign] = true
117
+ settings.security[:signature_method] = XMLSecurity::Document::SHA256
154
118
  settings.security[:digest_method] = XMLSecurity::Document::SHA512
119
+ settings.certificate = ruby_saml_cert_text
120
+ settings.private_key = ruby_saml_key_text
155
121
 
156
122
  params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
157
123
  request_xml = Base64.decode64(params["SAMLRequest"])
158
124
 
159
125
  assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
160
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'/>], request_xml
161
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha512'/>], request_xml
126
+ request_xml =~ /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha256'\/>/
127
+ request_xml =~ /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha512'\/>/
162
128
  end
163
129
  end
164
130
 
165
- describe "#create_params when the settings indicate to sign the logout request" do
166
-
167
- let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
168
-
169
- before do
170
- # sign the logout request
131
+ context "when the settings indicate to sign the logout request" do
132
+ should "create a signature parameter" do
133
+ settings = OneLogin::RubySaml::Settings.new
134
+ settings.compress_request = false
135
+ settings.idp_slo_target_url = "http://example.com?field=value"
136
+ settings.name_identifier_value = "f00f00"
171
137
  settings.security[:logout_requests_signed] = true
172
138
  settings.security[:embed_sign] = false
173
- settings.certificate = ruby_saml_cert_text
139
+ settings.security[:signature_method] = XMLSecurity::Document::SHA1
140
+ settings.certificate = ruby_saml_cert_text
174
141
  settings.private_key = ruby_saml_key_text
175
- end
176
-
177
- it "create a signature parameter with RSA_SHA1 / SHA1 and validate it" do
178
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
179
-
180
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
181
- assert params['SAMLRequest']
182
- assert params[:RelayState]
183
- assert params['Signature']
184
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
185
-
186
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
187
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
188
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
189
142
 
190
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
191
- assert_equal signature_algorithm, OpenSSL::Digest::SHA1
192
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
193
- end
194
-
195
- it "create a signature parameter with RSA_SHA256 / SHA256 and validate it" do
196
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
197
-
198
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
143
+ params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
199
144
  assert params['Signature']
200
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
145
+ assert params['SigAlg'] == XMLSecurity::Document::SHA1
201
146
 
202
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
203
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
204
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
205
-
206
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
207
- assert_equal signature_algorithm, OpenSSL::Digest::SHA256
208
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
209
- end
210
-
211
- it "create a signature parameter with RSA_SHA384 / SHA384 and validate it" do
212
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
213
-
214
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
147
+ # signature_method only affects the embedeed signature
148
+ settings.security[:signature_method] = XMLSecurity::Document::SHA256
149
+ params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
215
150
  assert params['Signature']
216
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA384
217
-
218
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
219
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
220
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
221
-
222
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
223
- assert_equal signature_algorithm, OpenSSL::Digest::SHA384
224
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
151
+ assert params['SigAlg'] == XMLSecurity::Document::SHA1
225
152
  end
153
+ end
226
154
 
227
- it "create a signature parameter with RSA_SHA512 / SHA512 and validate it" do
228
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA512
229
-
230
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
231
- assert params['Signature']
232
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA512
233
-
234
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
235
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
236
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
155
+ end
237
156
 
238
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
239
- assert_equal signature_algorithm, OpenSSL::Digest::SHA512
240
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
241
- end
242
- end
157
+ def decode_saml_request_payload(unauth_url)
158
+ payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
159
+ decoded = Base64.decode64(payload)
243
160
 
244
- describe "#manipulate request_id" do
245
- it "be able to modify the request id" do
246
- logoutrequest = OneLogin::RubySaml::Logoutrequest.new
247
- request_id = logoutrequest.request_id
248
- assert_equal request_id, logoutrequest.uuid
249
- logoutrequest.uuid = "new_uuid"
250
- assert_equal logoutrequest.request_id, logoutrequest.uuid
251
- assert_equal "new_uuid", logoutrequest.request_id
252
- end
253
- end
161
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
162
+ inflated = zstream.inflate(decoded)
163
+ zstream.finish
164
+ zstream.close
165
+ inflated
254
166
  end
167
+
255
168
  end
@@ -1,27 +1,26 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
- require File.expand_path(File.join(File.dirname(__FILE__), "responses/logoutresponse_fixtures"))
2
+ require 'rexml/document'
3
+ require 'responses/logoutresponse_fixtures'
4
+ class RubySamlTest < Test::Unit::TestCase
3
5
 
4
- class LogoutResponseTest < Minitest::Test
5
-
6
- describe "Logoutresponse" do
7
-
8
- describe "#new" do
9
- it "raise an exception when response is initialized with nil" do
6
+ context "Logoutresponse" do
7
+ context "#new" do
8
+ should "raise an exception when response is initialized with nil" do
10
9
  assert_raises(ArgumentError) { OneLogin::RubySaml::Logoutresponse.new(nil) }
11
10
  end
12
- it "default to empty settings" do
11
+ should "default to empty settings" do
13
12
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new( valid_response)
14
- assert logoutresponse.settings.nil?
13
+ assert_nil logoutresponse.settings
15
14
  end
16
- it "accept constructor-injected settings" do
15
+ should "accept constructor-injected settings" do
17
16
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings)
18
- assert !logoutresponse.settings.nil?
17
+ assert_not_nil logoutresponse.settings
19
18
  end
20
- it "accept constructor-injected options" do
19
+ should "accept constructor-injected options" do
21
20
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, nil, { :foo => :bar} )
22
21
  assert !logoutresponse.options.empty?
23
22
  end
24
- it "support base64 encoded responses" do
23
+ should "support base64 encoded responses" do
25
24
  expected_response = valid_response
26
25
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(expected_response), settings)
27
26
 
@@ -29,21 +28,21 @@ class LogoutResponseTest < Minitest::Test
29
28
  end
30
29
  end
31
30
 
32
- describe "#validate" do
33
- it "validate the response" do
31
+ context "#validate" do
32
+ should "validate the response" do
34
33
  in_relation_to_request_id = random_id
35
- settings.idp_entity_id = "https://example.com/idp"
36
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid2 => in_relation_to_request_id}), settings)
34
+
35
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
37
36
 
38
37
  assert logoutresponse.validate
39
38
 
40
- assert_equal settings.idp_entity_id, logoutresponse.issuer
39
+ assert_equal settings.issuer, logoutresponse.issuer
41
40
  assert_equal in_relation_to_request_id, logoutresponse.in_response_to
42
41
 
43
42
  assert logoutresponse.success?
44
43
  end
45
44
 
46
- it "invalidate responses with wrong id when given option :matches_uuid" do
45
+ should "invalidate responses with wrong id when given option :matches_uuid" do
47
46
 
48
47
  expected_request_id = "_some_other_expected_uuid"
49
48
  opts = { :matches_request_id => expected_request_id}
@@ -51,10 +50,10 @@ class LogoutResponseTest < Minitest::Test
51
50
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
52
51
 
53
52
  assert !logoutresponse.validate
54
- assert expected_request_id != logoutresponse.in_response_to
53
+ assert_not_equal expected_request_id, logoutresponse.in_response_to
55
54
  end
56
55
 
57
- it "invalidate responses with wrong request status" do
56
+ should "invalidate responses with wrong request status" do
58
57
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
59
58
 
60
59
  assert !logoutresponse.validate
@@ -62,8 +61,8 @@ class LogoutResponseTest < Minitest::Test
62
61
  end
63
62
  end
64
63
 
65
- describe "#validate!" do
66
- it "validates good responses" do
64
+ context "#validate!" do
65
+ should "validates good responses" do
67
66
  in_relation_to_request_id = random_id
68
67
 
69
68
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
@@ -71,7 +70,7 @@ class LogoutResponseTest < Minitest::Test
71
70
  logoutresponse.validate!
72
71
  end
73
72
 
74
- it "raises validation error when matching for wrong request id" do
73
+ should "raises validation error when matching for wrong request id" do
75
74
 
76
75
  expected_request_id = "_some_other_expected_id"
77
76
  opts = { :matches_request_id => expected_request_id}
@@ -81,25 +80,37 @@ class LogoutResponseTest < Minitest::Test
81
80
  assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
82
81
  end
83
82
 
84
- it "raise validation error for wrong request status" do
83
+ should "raise validation error for wrong request status" do
85
84
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
86
85
 
87
86
  assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
88
87
  end
89
88
 
90
- it "raise error for invalid xml" do
91
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
89
+ should "raise validation error when in bad state" do
90
+ # no settings
91
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response)
92
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
93
+ end
92
94
 
95
+ should "raise validation error when in lack of issuer setting" do
96
+ bad_settings = settings
97
+ bad_settings.issuer = nil
98
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, bad_settings)
93
99
  assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
94
100
  end
95
- end
96
101
 
97
- describe "#response_id" do
98
- it "extract the value of the Response ID" do
99
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings)
100
- assert_equal "_28024690-000e-0130-b6d2-38f6b112be8b", logoutresponse.response_id
102
+ should "raise error for invalid xml" do
103
+ logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
104
+
105
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
101
106
  end
102
107
  end
103
108
 
104
109
  end
110
+
111
+ # logoutresponse fixtures
112
+ def random_id
113
+ "_#{UUID.new.generate}"
114
+ end
115
+
105
116
  end
@@ -0,0 +1,87 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
+
3
+ class MetadataTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @settings = OneLogin::RubySaml::Settings.new
7
+ @settings.issuer = "https://example.com"
8
+ @settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
9
+ @settings.assertion_consumer_service_url = "https://foo.example/saml/consume"
10
+ @settings.security[:authn_requests_signed] = false
11
+ end
12
+
13
+ should "generate Service Provider Metadata with X509Certificate" do
14
+ @settings.security[:authn_requests_signed] = true
15
+ @settings.certificate = ruby_saml_cert_text
16
+
17
+ xml_text = OneLogin::RubySaml::Metadata.new.generate(@settings)
18
+
19
+ # assert xml_text can be parsed into an xml doc
20
+ xml_doc = REXML::Document.new(xml_text)
21
+
22
+ spsso_descriptor = REXML::XPath.first(xml_doc, "//md:SPSSODescriptor")
23
+ assert_equal "true", spsso_descriptor.attribute("AuthnRequestsSigned").value
24
+
25
+ cert_node = REXML::XPath.first(xml_doc, "//md:KeyDescriptor/ds:KeyInfo/ds:X509Data/ds:X509Certificate", {
26
+ "md" => "urn:oasis:names:tc:SAML:2.0:metadata",
27
+ "ds" => "http://www.w3.org/2000/09/xmldsig#"
28
+ })
29
+ cert_text = cert_node.text
30
+ cert = OpenSSL::X509::Certificate.new(Base64.decode64(cert_text))
31
+ assert_equal ruby_saml_cert.to_der, cert.to_der
32
+ end
33
+
34
+ should "should generate Service Provider Metadata" do
35
+ settings = OneLogin::RubySaml::Settings.new
36
+ settings.issuer = "https://example.com"
37
+ settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
38
+ settings.assertion_consumer_service_url = "https://foo.example/saml/consume"
39
+ settings.security[:authn_requests_signed] = false
40
+
41
+ xml_text = OneLogin::RubySaml::Metadata.new.generate(settings)
42
+
43
+ # assert correct xml declaration
44
+ start = "<?xml version='1.0' encoding='UTF-8'?>\n<md:EntityDescriptor"
45
+ assert xml_text[0..start.length-1] == start
46
+
47
+ # assert xml_text can be parsed into an xml doc
48
+ xml_doc = REXML::Document.new(xml_text)
49
+
50
+ assert_equal "https://example.com", REXML::XPath.first(xml_doc, "//md:EntityDescriptor").attribute("entityID").value
51
+
52
+ spsso_descriptor = REXML::XPath.first(xml_doc, "//md:SPSSODescriptor")
53
+ assert_equal "urn:oasis:names:tc:SAML:2.0:protocol", spsso_descriptor.attribute("protocolSupportEnumeration").value
54
+ assert_equal "false", spsso_descriptor.attribute("AuthnRequestsSigned").value
55
+ assert_equal "false", spsso_descriptor.attribute("WantAssertionsSigned").value
56
+
57
+ assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", REXML::XPath.first(xml_doc, "//md:NameIDFormat").text.strip
58
+
59
+ acs = REXML::XPath.first(xml_doc, "//md:AssertionConsumerService")
60
+ assert_equal "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", acs.attribute("Binding").value
61
+ assert_equal "https://foo.example/saml/consume", acs.attribute("Location").value
62
+ end
63
+
64
+ should "generate attribute service if configured" do
65
+ settings = OneLogin::RubySaml::Settings.new
66
+ settings.issuer = "https://example.com"
67
+ settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
68
+ settings.assertion_consumer_service_url = "https://foo.example/saml/consume"
69
+ settings.attribute_consuming_service.configure do
70
+ service_name "Test Service"
71
+ add_attribute(:name => "Name", :name_format => "Name Format", :friendly_name => "Friendly Name", :attribute_value => "Attribute Value")
72
+ end
73
+
74
+ xml_text = OneLogin::RubySaml::Metadata.new.generate(settings)
75
+ xml_doc = REXML::Document.new(xml_text)
76
+ acs = REXML::XPath.first(xml_doc, "//md:AttributeConsumingService")
77
+ assert_equal "true", acs.attribute("isDefault").value
78
+ assert_equal "1", acs.attribute("index").value
79
+ assert_equal REXML::XPath.first(xml_doc, "//md:ServiceName").text.strip, "Test Service"
80
+ req_attr = REXML::XPath.first(xml_doc, "//md:RequestedAttribute")
81
+ assert_equal "Name", req_attr.attribute("Name").value
82
+ assert_equal "Name Format", req_attr.attribute("NameFormat").value
83
+ assert_equal "Friendly Name", req_attr.attribute("FriendlyName").value
84
+ assert_equal "Attribute Value", REXML::XPath.first(xml_doc, "//md:AttributeValue").text.strip
85
+ end
86
+
87
+ end