ruby-saml 0.8.8 → 0.8.13

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.

Potentially problematic release.


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

Files changed (45) hide show
  1. checksums.yaml +7 -7
  2. data/Gemfile +11 -1
  3. data/README.md +5 -2
  4. data/Rakefile +0 -14
  5. data/lib/onelogin/ruby-saml/authrequest.rb +86 -20
  6. data/lib/onelogin/ruby-saml/logoutrequest.rb +95 -20
  7. data/lib/onelogin/ruby-saml/logoutresponse.rb +5 -28
  8. data/lib/onelogin/ruby-saml/metadata.rb +5 -5
  9. data/lib/onelogin/ruby-saml/response.rb +187 -4
  10. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  11. data/lib/onelogin/ruby-saml/settings.rb +146 -10
  12. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
  13. data/lib/onelogin/ruby-saml/utils.rb +169 -0
  14. data/lib/onelogin/ruby-saml/version.rb +1 -1
  15. data/lib/ruby-saml.rb +2 -1
  16. data/lib/xml_security.rb +330 -78
  17. data/test/certificates/ruby-saml-2.crt +15 -0
  18. data/test/certificates/ruby-saml.crt +14 -0
  19. data/test/certificates/ruby-saml.key +15 -0
  20. data/test/logoutrequest_test.rb +177 -44
  21. data/test/logoutresponse_test.rb +25 -29
  22. data/test/request_test.rb +100 -37
  23. data/test/response_test.rb +213 -111
  24. data/test/responses/adfs_response_xmlns.xml +45 -0
  25. data/test/responses/encrypted_new_attack.xml.base64 +1 -0
  26. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  27. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  28. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
  29. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
  30. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
  31. data/test/responses/logoutresponse_fixtures.rb +6 -6
  32. data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
  33. data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
  34. data/test/responses/response_with_signed_assertion_3.xml +30 -0
  35. data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
  36. data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
  37. data/test/responses/response_wrapped.xml.base64 +150 -0
  38. data/test/responses/valid_response.xml.base64 +1 -0
  39. data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
  40. data/test/settings_test.rb +7 -7
  41. data/test/slo_logoutresponse_test.rb +226 -0
  42. data/test/test_helper.rb +117 -12
  43. data/test/utils_test.rb +10 -10
  44. data/test/xml_security_test.rb +310 -68
  45. metadata +88 -45
@@ -1,38 +1,38 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class UtilsTest < Test::Unit::TestCase
4
- context "Utils" do
5
- context 'element_text' do
6
- should 'returns the element text' do
3
+ class UtilsTest < Minitest::Test
4
+ describe "Utils" do
5
+ describe 'element_text' do
6
+ it 'returns the element text' do
7
7
  element = REXML::Document.new('<element>element text</element>').elements.first
8
8
  assert_equal 'element text', OneLogin::RubySaml::Utils.element_text(element)
9
9
  end
10
10
 
11
- should 'returns all segments of the element text' do
11
+ it 'returns all segments of the element text' do
12
12
  element = REXML::Document.new('<element>element <!-- comment -->text</element>').elements.first
13
13
  assert_equal 'element text', OneLogin::RubySaml::Utils.element_text(element)
14
14
  end
15
15
 
16
- should 'returns normalized element text' do
16
+ it 'returns normalized element text' do
17
17
  element = REXML::Document.new('<element>element &amp; text</element>').elements.first
18
18
  assert_equal 'element & text', OneLogin::RubySaml::Utils.element_text(element)
19
19
  end
20
20
 
21
- should 'returns the CDATA element text' do
21
+ it 'returns the CDATA element text' do
22
22
  element = REXML::Document.new('<element><![CDATA[element & text]]></element>').elements.first
23
23
  assert_equal 'element & text', OneLogin::RubySaml::Utils.element_text(element)
24
24
  end
25
25
 
26
- should 'returns the element text with newlines and additional whitespace' do
26
+ it 'returns the element text with newlines and additional whitespace' do
27
27
  element = REXML::Document.new("<element> element \n text </element>").elements.first
28
28
  assert_equal " element \n text ", OneLogin::RubySaml::Utils.element_text(element)
29
29
  end
30
30
 
31
- should 'returns nil when element is nil' do
31
+ it 'returns nil when element is nil' do
32
32
  assert_nil OneLogin::RubySaml::Utils.element_text(nil)
33
33
  end
34
34
 
35
- should 'returns empty string when element has no text' do
35
+ it 'returns empty string when element has no text' do
36
36
  element = REXML::Document.new('<element></element>').elements.first
37
37
  assert_equal '', OneLogin::RubySaml::Utils.element_text(element)
38
38
  end
@@ -1,94 +1,197 @@
1
- require 'test_helper'
2
- require 'xml_security'
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
3
2
 
4
- class XmlSecurityTest < Test::Unit::TestCase
3
+ class XmlSecurityTest < Minitest::Test
5
4
  include XMLSecurity
6
5
 
7
- context "XmlSecurity" do
8
- setup do
9
- @document = XMLSecurity::SignedDocument.new(Base64.decode64(response_document))
10
- @base64cert = @document.elements["//ds:X509Certificate"].text
6
+ describe "XmlSecurity" do
7
+
8
+ let(:decoded_response) { Base64.decode64(response_document_without_recipient) }
9
+ let(:document) { XMLSecurity::SignedDocument.new(decoded_response) }
10
+ let(:settings) { OneLogin::RubySaml::Settings.new() }
11
+
12
+ before do
13
+ @base64cert = document.elements["//ds:X509Certificate"].text
11
14
  end
12
15
 
13
- should "should run validate without throwing NS related exceptions" do
14
- assert !@document.validate_signature(@base64cert, true)
16
+ it "should run validate without throwing NS related exceptions" do
17
+ assert !document.validate_signature(@base64cert, true)
15
18
  end
16
19
 
17
- should "should run validate with throwing NS related exceptions" do
18
- assert_raise(OneLogin::RubySaml::ValidationError) do
19
- @document.validate_signature(@base64cert, false)
20
+ it "should run validate with throwing NS related exceptions" do
21
+ assert_raises(OneLogin::RubySaml::ValidationError) do
22
+ document.validate_signature(@base64cert, false)
20
23
  end
21
24
  end
22
25
 
23
- should "not raise an error when softly validating the document multiple times" do
24
- assert_nothing_raised do
25
- 2.times { @document.validate_signature(@base64cert, true) }
26
- end
26
+ it "not raise an error when softly validating the document multiple times" do
27
+ 2.times { assert_equal document.validate_signature(@base64cert, true), false }
27
28
  end
28
29
 
29
- should "should raise Fingerprint mismatch" do
30
- exception = assert_raise(OneLogin::RubySaml::ValidationError) do
31
- @document.validate_document("no:fi:ng:er:pr:in:t", false)
30
+ it "not raise an error when softly validating the document and the X509Certificate is missing" do
31
+ decoded_response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
32
+ mod_document = XMLSecurity::SignedDocument.new(decoded_response)
33
+ assert !mod_document.validate_document("a fingerprint", true) # The fingerprint isn't relevant to this test
34
+ end
35
+
36
+ it "should raise Fingerprint mismatch" do
37
+ exception = assert_raises(OneLogin::RubySaml::ValidationError) do
38
+ document.validate_document("no:fi:ng:er:pr:in:t", false)
32
39
  end
33
40
  assert_equal("Fingerprint mismatch", exception.message)
34
41
  end
35
42
 
36
- should "should raise Digest mismatch" do
37
- exception = assert_raise(OneLogin::RubySaml::ValidationError) do
38
- @document.validate_signature(@base64cert, false)
43
+ it "should raise Digest mismatch" do
44
+ exception = assert_raises(OneLogin::RubySaml::ValidationError) do
45
+ document.validate_signature(@base64cert, false)
39
46
  end
40
47
  assert_equal("Digest mismatch", exception.message)
41
48
  end
42
49
 
43
- should "should raise Key validation error" do
44
- response = Base64.decode64(response_document)
45
- response.sub!("<ds:DigestValue>pJQ7MS/ek4KRRWGmv/H43ReHYMs=</ds:DigestValue>",
50
+ it "should raise Key validation error" do
51
+ decoded_response.sub!("<ds:DigestValue>pJQ7MS/ek4KRRWGmv/H43ReHYMs=</ds:DigestValue>",
46
52
  "<ds:DigestValue>b9xsAXLsynugg3Wc1CI3kpWku+0=</ds:DigestValue>")
47
- document = XMLSecurity::SignedDocument.new(response)
48
- base64cert = document.elements["//ds:X509Certificate"].text
49
- exception = assert_raise(OneLogin::RubySaml::ValidationError) do
50
- document.validate_signature(base64cert, false)
53
+ mod_document = XMLSecurity::SignedDocument.new(decoded_response)
54
+ base64cert = mod_document.elements["//ds:X509Certificate"].text
55
+ exception = assert_raises(OneLogin::RubySaml::ValidationError) do
56
+ mod_document.validate_signature(base64cert, false)
51
57
  end
52
58
  assert_equal("Key validation error", exception.message)
53
59
  end
54
60
 
55
- should "raise validation error when the X509Certificate is missing" do
56
- response = Base64.decode64(response_document)
57
- response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
58
- document = XMLSecurity::SignedDocument.new(response)
59
- exception = assert_raise(OneLogin::RubySaml::ValidationError) do
60
- document.validate_document("a fingerprint", false) # The fingerprint isn't relevant to this test
61
+ it "correctly obtain the digest method with alternate namespace declaration" do
62
+ adfs_document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_xmlns, false))
63
+ base64cert = adfs_document.elements["//X509Certificate"].text
64
+ assert adfs_document.validate_signature(base64cert, false)
65
+ end
66
+
67
+ it "raise validation error when the X509Certificate is missing and no cert provided" do
68
+ decoded_response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
69
+ mod_document = XMLSecurity::SignedDocument.new(decoded_response)
70
+ exception = assert_raises(OneLogin::RubySaml::ValidationError) do
71
+ mod_document.validate_document("a fingerprint", false) # The fingerprint isn't relevant to this test
61
72
  end
62
- assert_equal("Certificate element missing in response (ds:X509Certificate)", exception.message)
73
+ assert_equal("Certificate element missing in response (ds:X509Certificate) and not cert provided at settings", exception.message)
74
+ end
75
+
76
+ it "invalidaties when the X509Certificate is missing and the cert is provided but mismatches" do
77
+ decoded_response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
78
+ mod_document = XMLSecurity::SignedDocument.new(decoded_response)
79
+ cert = OpenSSL::X509::Certificate.new(ruby_saml_cert)
80
+ assert !mod_document.validate_document("a fingerprint", true, :cert => cert) # The fingerprint isn't relevant to this test
81
+ end
82
+ end
83
+
84
+ describe "#canon_algorithm" do
85
+ it "C14N_EXCLUSIVE_1_0" do
86
+ canon_algorithm = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
87
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/2001/10/xml-exc-c14n#")
88
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/2001/10/xml-exc-c14n#WithComments")
89
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("other")
90
+ end
91
+
92
+ it "C14N_1_0" do
93
+ canon_algorithm = Nokogiri::XML::XML_C14N_1_0
94
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
95
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments")
96
+ end
97
+
98
+ it "XML_C14N_1_1" do
99
+ canon_algorithm = Nokogiri::XML::XML_C14N_1_1
100
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/2006/12/xml-c14n11")
101
+ assert_equal canon_algorithm, XMLSecurity::BaseDocument.new.canon_algorithm("http://www.w3.org/2006/12/xml-c14n11#WithComments")
102
+ end
103
+ end
104
+
105
+ describe "#algorithm" do
106
+ it "SHA1" do
107
+ alg = OpenSSL::Digest::SHA1
108
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha1")
109
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2000/09/xmldsig#sha1")
110
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("other")
111
+ end
112
+
113
+ it "SHA256" do
114
+ alg = OpenSSL::Digest::SHA256
115
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
116
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#sha256")
117
+ end
118
+
119
+ it "SHA384" do
120
+ alg = OpenSSL::Digest::SHA384
121
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384")
122
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#sha384")
123
+ end
124
+
125
+ it "SHA512" do
126
+ alg = OpenSSL::Digest::SHA512
127
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512")
128
+ assert_equal alg, XMLSecurity::BaseDocument.new.algorithm("http://www.w3.org/2001/04/xmldsig-more#sha512")
63
129
  end
64
130
  end
65
131
 
66
- context "Algorithms" do
67
- should "validate using SHA1" do
68
- @document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha1, false))
69
- assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
132
+ describe "Fingerprint Algorithms" do
133
+ let(:response_fingerprint_test) { OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha1, false)) }
134
+
135
+ it "validate using SHA1" do
136
+ sha1_fingerprint = "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72"
137
+ sha1_fingerprint_downcase = "f13c6b80905a030e6c913e5d15faddb016454872"
138
+
139
+ assert response_fingerprint_test.document.validate_document(sha1_fingerprint)
140
+ assert response_fingerprint_test.document.validate_document(sha1_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
141
+
142
+ assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase)
143
+ assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
70
144
  end
71
145
 
72
- should "validate using SHA256" do
73
- @document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha256, false))
74
- assert @document.validate_document("28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA")
146
+ it "validate using SHA256" do
147
+ sha256_fingerprint = "C4:C6:BD:41:EC:AD:57:97:CE:7B:7D:80:06:C3:E4:30:53:29:02:0B:DD:2D:47:02:9E:BD:85:AD:93:02:45:21"
148
+
149
+ assert !response_fingerprint_test.document.validate_document(sha256_fingerprint)
150
+ assert response_fingerprint_test.document.validate_document(sha256_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA256)
75
151
  end
76
152
 
77
- should "validate using SHA384" do
78
- @document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha384, false))
79
- assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
153
+ it "validate using SHA384" do
154
+ sha384_fingerprint = "98:FE:17:90:31:E7:68:18:8A:65:4D:DA:F5:76:E2:09:97:BE:8B:E3:7E:AA:8D:63:64:7C:0C:38:23:9A:AC:A2:EC:CE:48:A6:74:4D:E0:4C:50:80:40:B4:8D:55:14:14"
155
+
156
+ assert !response_fingerprint_test.document.validate_document(sha384_fingerprint)
157
+ assert response_fingerprint_test.document.validate_document(sha384_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA384)
80
158
  end
81
159
 
82
- should "validate using SHA512" do
83
- @document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha512, false))
84
- assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
160
+ it "validate using SHA512" do
161
+ sha512_fingerprint = "5A:AE:BA:D0:BA:9D:1E:25:05:01:1E:1A:C9:E9:FF:DB:ED:FA:6E:F7:52:EB:45:49:BD:DB:06:D8:A3:7E:CC:63:3A:04:A2:DD:DF:EE:61:05:D9:58:95:2A:77:17:30:4B:EB:4A:9F:48:4A:44:1C:D0:9E:0B:1E:04:77:FD:A3:D2"
162
+
163
+ assert !response_fingerprint_test.document.validate_document(sha512_fingerprint)
164
+ assert response_fingerprint_test.document.validate_document(sha512_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA512)
85
165
  end
166
+
86
167
  end
87
168
 
88
- context "XmlSecurity::SignedDocument" do
169
+ describe "Signature Algorithms" do
170
+ it "validate using SHA1" do
171
+ document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha1, false))
172
+ assert document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
173
+ end
174
+
175
+ it "validate using SHA256" do
176
+ document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha256, false))
177
+ assert document.validate_document("28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA")
178
+ end
179
+
180
+ it "validate using SHA384" do
181
+ document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha384, false))
182
+ assert document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
183
+ end
89
184
 
90
- context "#extract_inclusive_namespaces" do
91
- should "support explicit namespace resolution for exclusive canonicalization" do
185
+ it "validate using SHA512" do
186
+ document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha512, false))
187
+ assert document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
188
+ end
189
+ end
190
+
191
+ describe "XmlSecurity::SignedDocument" do
192
+
193
+ describe "#extract_inclusive_namespaces" do
194
+ it "support explicit namespace resolution for exclusive canonicalization" do
92
195
  response = fixture(:open_saml_response, false)
93
196
  document = XMLSecurity::SignedDocument.new(response)
94
197
  inclusive_namespaces = document.send(:extract_inclusive_namespaces)
@@ -96,7 +199,7 @@ class XmlSecurityTest < Test::Unit::TestCase
96
199
  assert_equal %w[ xs ], inclusive_namespaces
97
200
  end
98
201
 
99
- should "support implicit namespace resolution for exclusive canonicalization" do
202
+ it "support implicit namespace resolution for exclusive canonicalization" do
100
203
  response = fixture(:no_signature_ns, false)
101
204
  document = XMLSecurity::SignedDocument.new(response)
102
205
  inclusive_namespaces = document.send(:extract_inclusive_namespaces)
@@ -104,57 +207,196 @@ class XmlSecurityTest < Test::Unit::TestCase
104
207
  assert_equal %w[ #default saml ds xs xsi ], inclusive_namespaces
105
208
  end
106
209
 
107
- should_eventually 'support inclusive canonicalization' do
108
-
210
+ it 'support inclusive canonicalization' do
211
+ skip('test not yet implemented')
109
212
  response = OneLogin::RubySaml::Response.new(fixture("tdnf_response.xml"))
110
213
  response.stubs(:conditions).returns(nil)
111
214
  assert !response.is_valid?
112
- settings = OneLogin::RubySaml::Settings.new
113
215
  assert !response.is_valid?
114
216
  response.settings = settings
115
217
  assert !response.is_valid?
116
218
  settings.idp_cert_fingerprint = "e6 38 9a 20 b7 4f 13 db 6a bc b1 42 6a e7 52 1d d6 56 d4 1b".upcase.gsub(" ", ":")
117
- assert response.validate!
219
+ assert response.is_valid?
118
220
  end
119
221
 
120
- should "return an empty list when inclusive namespace element is missing" do
222
+ it "return nil when inclusive namespace element is missing" do
121
223
  response = fixture(:no_signature_ns, false)
122
224
  response.slice! %r{<InclusiveNamespaces xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="#default saml ds xs xsi"/>}
123
225
 
124
226
  document = XMLSecurity::SignedDocument.new(response)
125
227
  inclusive_namespaces = document.send(:extract_inclusive_namespaces)
126
228
 
127
- assert inclusive_namespaces.empty?
229
+ assert inclusive_namespaces.nil?
128
230
  end
129
231
  end
130
232
 
131
- context "StarfieldTMS" do
132
- setup do
233
+ describe "XMLSecurity::DSIG" do
234
+ before do
235
+ settings.idp_sso_target_url = "https://idp.example.com/sso"
236
+ settings.protocol_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
237
+ settings.idp_slo_target_url = "https://idp.example.com/slo",
238
+ settings.sp_entity_id = "https://sp.example.com/saml2"
239
+ settings.assertion_consumer_service_url = "https://sp.example.com/acs"
240
+ settings.single_logout_service_url = "https://sp.example.com/sls"
241
+ end
242
+
243
+ it "sign an AuthNRequest" do
244
+ request = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
245
+ request.sign_document(ruby_saml_key, ruby_saml_cert)
246
+ # verify our signature
247
+ signed_doc = XMLSecurity::SignedDocument.new(request.to_s)
248
+ assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
249
+
250
+ request2 = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
251
+ request2.sign_document(ruby_saml_key, ruby_saml_cert_text)
252
+ # verify our signature
253
+ signed_doc2 = XMLSecurity::SignedDocument.new(request2.to_s)
254
+ assert signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
255
+ end
256
+
257
+ it "sign an AuthNRequest with certificate as text" do
258
+ request = OneLogin::RubySaml::Authrequest.new.create_authentication_xml_doc(settings)
259
+ request.sign_document(ruby_saml_key, ruby_saml_cert_text)
260
+
261
+ # verify our signature
262
+ signed_doc = XMLSecurity::SignedDocument.new(request.to_s)
263
+ assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
264
+ end
265
+
266
+ it "sign a LogoutRequest" do
267
+ logout_request = OneLogin::RubySaml::Logoutrequest.new.create_logout_request_xml_doc(settings)
268
+ logout_request.sign_document(ruby_saml_key, ruby_saml_cert)
269
+ # verify our signature
270
+ signed_doc = XMLSecurity::SignedDocument.new(logout_request.to_s)
271
+ assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
272
+
273
+ logout_request2 = OneLogin::RubySaml::Logoutrequest.new.create_logout_request_xml_doc(settings)
274
+ logout_request2.sign_document(ruby_saml_key, ruby_saml_cert_text)
275
+ # verify our signature
276
+ signed_doc2 = XMLSecurity::SignedDocument.new(logout_request2.to_s)
277
+ signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
278
+ assert signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
279
+ end
280
+
281
+ it "sign a LogoutResponse" do
282
+ logout_response = OneLogin::RubySaml::SloLogoutresponse.new.create_logout_response_xml_doc(settings, 'request_id_example', "Custom Logout Message")
283
+ logout_response.sign_document(ruby_saml_key, ruby_saml_cert)
284
+ # verify our signature
285
+ signed_doc = XMLSecurity::SignedDocument.new(logout_response.to_s)
286
+ assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
287
+
288
+ logout_response2 = OneLogin::RubySaml::SloLogoutresponse.new.create_logout_response_xml_doc(settings, 'request_id_example', "Custom Logout Message")
289
+ logout_response2.sign_document(ruby_saml_key, ruby_saml_cert_text)
290
+ # verify our signature
291
+ signed_doc2 = XMLSecurity::SignedDocument.new(logout_response2.to_s)
292
+ signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
293
+ assert signed_doc2.validate_document(ruby_saml_cert_fingerprint, false)
294
+ end
295
+ end
296
+
297
+ describe "StarfieldTMS" do
298
+ before do
133
299
  @response = OneLogin::RubySaml::Response.new(fixture(:starfield_response))
134
- @response.settings = OneLogin::RubySaml::Settings.new(
135
- :idp_cert_fingerprint => "8D:BA:53:8E:A3:B6:F9:F1:69:6C:BB:D9:D8:BD:41:B3:AC:4F:9D:4D"
136
- )
300
+ @response.settings = OneLogin::RubySaml::Settings.new( :idp_cert_fingerprint => "8D:BA:53:8E:A3:B6:F9:F1:69:6C:BB:D9:D8:BD:41:B3:AC:4F:9D:4D")
137
301
  end
138
302
 
139
- should "be able to validate a good response" do
303
+ it "be able to validate a good response" do
140
304
  Timecop.freeze Time.parse('2012-11-28 17:55:00 UTC') do
141
305
  assert @response.validate!
142
306
  end
143
307
  end
144
308
 
145
- should "fail before response is valid" do
309
+ it "fail before response is valid" do
146
310
  Timecop.freeze Time.parse('2012-11-20 17:55:00 UTC') do
147
311
  assert ! @response.is_valid?
148
312
  end
149
313
  end
150
314
 
151
- should "fail after response expires" do
315
+ it "fail after response expires" do
152
316
  Timecop.freeze Time.parse('2012-11-30 17:55:00 UTC') do
153
317
  assert ! @response.is_valid?
154
318
  end
155
319
  end
156
320
  end
157
321
 
158
- end
322
+ describe '#validate_document' do
323
+ describe 'with valid document' do
324
+ describe 'when response has signed message and assertion' do
325
+ let(:document_data) { read_response('response_with_signed_message_and_assertion.xml') }
326
+ let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
327
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
328
+
329
+ it 'is valid' do
330
+ assert document.validate_document(fingerprint, true), 'Document should be valid'
331
+ end
332
+ end
333
+
334
+ describe 'when response has signed assertion' do
335
+ let(:document_data) { read_response('response_with_signed_assertion_3.xml') }
336
+ let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
337
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
338
+
339
+ it 'is valid' do
340
+ assert document.validate_document(fingerprint, true), 'Document should be valid'
341
+ end
342
+ end
343
+ end
344
+
345
+ describe 'signature_wrapping_attack' do
346
+ let(:document_data) { read_invalid_response("signature_wrapping_attack.xml.base64") }
347
+ let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
348
+ let(:fingerprint) { 'afe71c28ef740bc87425be13a2263d37971da1f9' }
349
+
350
+ it 'is invalid' do
351
+ assert !document.validate_document(fingerprint, true), 'Document should be invalid'
352
+ end
353
+ end
354
+
355
+ describe 'signature wrapping attack - doubled SAML response body' do
356
+ let(:document_data) { read_invalid_response("response_with_doubled_signed_assertion.xml") }
357
+ let(:document) { OneLogin::RubySaml::Response.new(document_data) }
358
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
159
359
 
360
+ it 'is valid, but the unsigned information is ignored in favour of the signed information' do
361
+ assert document.document.validate_document(fingerprint, true), 'Document should be valid'
362
+ assert_equal 'someone@example.org', document.name_id, 'Document should expose only signed, valid details'
363
+ end
364
+ end
365
+
366
+ describe 'signature wrapping attack - concealed SAML response body' do
367
+ let(:document_data) { read_invalid_response("response_with_concealed_signed_assertion.xml") }
368
+ let(:document) { OneLogin::RubySaml::Response.new(document_data) }
369
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
370
+
371
+ it 'is valid, but fails to retrieve information' do
372
+ assert document.document.validate_document(fingerprint, true), 'Document should be valid'
373
+ assert document.name_id.nil?, 'Document should expose only signed, valid details'
374
+ end
375
+ end
376
+ end
377
+
378
+ describe '#validate_document_with_cert' do
379
+ describe 'with valid document ' do
380
+ describe 'when response has cert' do
381
+ let(:document_data) { read_response('response_with_signed_message_and_assertion.xml') }
382
+ let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
383
+ let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
384
+ let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
385
+
386
+ it 'is valid' do
387
+ assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
388
+ end
389
+ end
390
+
391
+ describe 'when response has no cert but you have local cert' do
392
+ let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
393
+ let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
394
+
395
+ it 'is valid' do
396
+ assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
397
+ end
398
+ end
399
+ end
400
+ end
401
+ end
160
402
  end