ruby-saml 0.8.16 → 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  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 -89
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
  12. data/lib/onelogin/ruby-saml/logoutrequest.rb +34 -93
  13. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -24
  14. data/lib/onelogin/ruby-saml/metadata.rb +46 -16
  15. data/lib/onelogin/ruby-saml/response.rb +62 -322
  16. data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +54 -121
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -61
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -84
  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 -144
  39. data/test/logoutresponse_test.rb +43 -25
  40. data/test/metadata_test.rb +87 -0
  41. data/test/request_test.rb +103 -90
  42. data/test/response_test.rb +181 -471
  43. data/test/responses/idp_descriptor.xml +3 -0
  44. data/test/responses/logoutresponse_fixtures.rb +5 -5
  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 +41 -44
  50. data/test/slo_logoutresponse_test.rb +87 -167
  51. data/test/test_helper.rb +27 -102
  52. data/test/xml_security_test.rb +114 -337
  53. metadata +34 -84
  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
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.date = Time.now.strftime("%Y-%m-%d")
11
11
  s.description = %q{SAML toolkit for Ruby on Rails}
12
12
  s.email = %q{support@onelogin.com}
13
+ s.license = 'MIT'
13
14
  s.extra_rdoc_files = [
14
15
  "LICENSE",
15
16
  "README.md"
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
+ require 'net/http'
3
+ require 'net/https'
4
+
5
+ class IdpMetadataParserTest < Test::Unit::TestCase
6
+
7
+ class MockResponse
8
+ attr_accessor :body
9
+ end
10
+
11
+ context "parsing an IdP descriptor file" do
12
+ should "extract settings details from xml" do
13
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
14
+
15
+ settings = idp_metadata_parser.parse(idp_metadata)
16
+
17
+ assert_equal "https://example.hello.com/access/saml/login", settings.idp_sso_target_url
18
+ assert_equal "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72", settings.idp_cert_fingerprint
19
+ assert_equal "https://example.hello.com/access/saml/logout", settings.idp_slo_target_url
20
+ end
21
+ end
22
+
23
+ context "download and parse IdP descriptor file" do
24
+ setup do
25
+ mock_response = MockResponse.new
26
+ mock_response.body = idp_metadata
27
+ @url = "https://example.com"
28
+ uri = URI(@url)
29
+
30
+ @http = Net::HTTP.new(uri.host, uri.port)
31
+ Net::HTTP.expects(:new).returns(@http)
32
+ @http.expects(:request).returns(mock_response)
33
+ end
34
+
35
+
36
+ should "extract settings from remote xml" do
37
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
38
+ settings = idp_metadata_parser.parse_remote(@url)
39
+
40
+ assert_equal "https://example.hello.com/access/saml/login", settings.idp_sso_target_url
41
+ assert_equal "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72", settings.idp_cert_fingerprint
42
+ assert_equal "https://example.hello.com/access/saml/logout", settings.idp_slo_target_url
43
+ assert_equal OpenSSL::SSL::VERIFY_PEER, @http.verify_mode
44
+ end
45
+
46
+ should "accept self signed certificate if insturcted" do
47
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
48
+ settings = idp_metadata_parser.parse_remote(@url, false)
49
+
50
+ assert_equal OpenSSL::SSL::VERIFY_NONE, @http.verify_mode
51
+ end
52
+ end
53
+
54
+ end
@@ -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,167 +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
-
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
142
 
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
201
-
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
145
+ assert params['SigAlg'] == XMLSecurity::Document::SHA1
213
146
 
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
155
+ end
233
156
 
234
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
235
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
236
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
157
+ def decode_saml_request_payload(unauth_url)
158
+ payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
159
+ decoded = Base64.decode64(payload)
237
160
 
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
161
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
162
+ inflated = zstream.inflate(decoded)
163
+ zstream.finish
164
+ zstream.close
165
+ inflated
243
166
  end
167
+
244
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"
34
+
36
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,13 +80,26 @@ 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
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
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)
99
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
100
+ end
101
+
102
+ should "raise error for invalid xml" do
91
103
  logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
92
104
 
93
105
  assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
@@ -95,4 +107,10 @@ class LogoutResponseTest < Minitest::Test
95
107
  end
96
108
 
97
109
  end
110
+
111
+ # logoutresponse fixtures
112
+ def random_id
113
+ "_#{UUID.new.generate}"
114
+ end
115
+
98
116
  end