ruby-saml 0.8.12 → 0.8.17
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.
- checksums.yaml +7 -7
- data/lib/onelogin/ruby-saml/logoutrequest.rb +2 -1
- data/lib/onelogin/ruby-saml/logoutresponse.rb +9 -51
- data/lib/onelogin/ruby-saml/response.rb +133 -21
- data/lib/onelogin/ruby-saml/settings.rb +28 -10
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +101 -0
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +12 -9
- data/lib/onelogin/ruby-saml/utils.rb +92 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +1 -0
- data/lib/xml_security.rb +222 -86
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/formatted_certificate +14 -0
- data/test/certificates/formatted_chained_certificate +42 -0
- data/test/certificates/formatted_private_key +12 -0
- data/test/certificates/formatted_rsa_private_key +12 -0
- data/test/certificates/invalid_certificate1 +1 -0
- data/test/certificates/invalid_certificate2 +1 -0
- data/test/certificates/invalid_certificate3 +12 -0
- data/test/certificates/invalid_chained_certificate1 +1 -0
- data/test/certificates/invalid_private_key1 +1 -0
- data/test/certificates/invalid_private_key2 +1 -0
- data/test/certificates/invalid_private_key3 +10 -0
- data/test/certificates/invalid_rsa_private_key1 +1 -0
- data/test/certificates/invalid_rsa_private_key2 +1 -0
- data/test/certificates/invalid_rsa_private_key3 +10 -0
- data/test/certificates/ruby-saml-2.crt +15 -0
- data/test/logoutresponse_test.rb +2 -16
- data/test/requests/logoutrequest_fixtures.rb +47 -0
- data/test/response_test.rb +227 -15
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +1 -0
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +1 -0
- data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
- data/test/responses/invalids/no_signature.xml.base64 +1 -0
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
- data/test/responses/logoutresponse_fixtures.rb +4 -4
- data/test/responses/response_with_signed_assertion_3.xml +30 -0
- data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
- data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +106 -0
- data/test/slo_logoutrequest_test.rb +66 -0
- data/test/slo_logoutresponse_test.rb +8 -0
- data/test/test_helper.rb +62 -30
- data/test/utils_test.rb +191 -1
- data/test/xml_security_test.rb +329 -36
- metadata +109 -45
data/test/test_helper.rb
CHANGED
@@ -30,6 +30,10 @@ class Minitest::Test
|
|
30
30
|
RUBY_VERSION < '1.9' ? "_#{UUID.new.generate}" : "_#{SecureRandom.uuid}"
|
31
31
|
end
|
32
32
|
|
33
|
+
def read_invalid_response(response)
|
34
|
+
File.read(File.join(File.dirname(__FILE__), "responses", "invalids", response))
|
35
|
+
end
|
36
|
+
|
33
37
|
def read_response(response)
|
34
38
|
File.read(File.join(File.dirname(__FILE__), "responses", response))
|
35
39
|
end
|
@@ -81,6 +85,14 @@ class Minitest::Test
|
|
81
85
|
response_document_valid_signed ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'valid_response.xml.base64'))
|
82
86
|
end
|
83
87
|
|
88
|
+
def response_document_valid_signed_without_x509certificate
|
89
|
+
@response_document_valid_signed_without_x509certificate ||= read_response("valid_response_without_x509certificate.xml.base64")
|
90
|
+
end
|
91
|
+
|
92
|
+
def response_document_without_recipient
|
93
|
+
@response_document_without_recipient ||= read_response("response_with_undefined_recipient.xml.base64")
|
94
|
+
end
|
95
|
+
|
84
96
|
def wrapped_response_2
|
85
97
|
@wrapped_response_2 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'wrapped_response_2.xml.base64'))
|
86
98
|
end
|
@@ -116,40 +128,60 @@ class Minitest::Test
|
|
116
128
|
def response_multiple_attr_values
|
117
129
|
@response_multiple_attr_values = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
|
118
130
|
end
|
119
|
-
end
|
120
131
|
|
121
|
-
def
|
122
|
-
|
123
|
-
end
|
132
|
+
def ruby_saml_cert
|
133
|
+
@ruby_saml_cert ||= OpenSSL::X509::Certificate.new(ruby_saml_cert_text)
|
134
|
+
end
|
124
135
|
|
125
|
-
def
|
126
|
-
|
127
|
-
end
|
136
|
+
def ruby_saml_cert2
|
137
|
+
@ruby_saml_cert2 ||= OpenSSL::X509::Certificate.new(ruby_saml_cert_text2)
|
138
|
+
end
|
128
139
|
|
129
|
-
def
|
130
|
-
|
131
|
-
end
|
140
|
+
def ruby_saml_cert_fingerprint
|
141
|
+
@ruby_saml_cert_fingerprint ||= Digest::SHA1.hexdigest(ruby_saml_cert.to_der).scan(/../).join(":")
|
142
|
+
end
|
132
143
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
144
|
+
def ruby_saml_cert_text
|
145
|
+
read_certificate("ruby-saml.crt")
|
146
|
+
end
|
136
147
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
148
|
+
def ruby_saml_cert_text2
|
149
|
+
read_certificate("ruby-saml-2.crt")
|
150
|
+
end
|
151
|
+
|
152
|
+
def ruby_saml_key_text
|
153
|
+
read_certificate("ruby-saml.key")
|
154
|
+
end
|
155
|
+
|
156
|
+
def ruby_saml_key
|
157
|
+
@ruby_saml_key ||= OpenSSL::PKey::RSA.new(ruby_saml_key_text)
|
158
|
+
end
|
159
|
+
|
160
|
+
def read_certificate(certificate)
|
161
|
+
File.read(File.join(File.dirname(__FILE__), "certificates", certificate))
|
162
|
+
end
|
143
163
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
164
|
+
def decode_saml_request_payload(unauth_url)
|
165
|
+
payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
|
166
|
+
decoded = Base64.decode64(payload)
|
167
|
+
|
168
|
+
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
169
|
+
inflated = zstream.inflate(decoded)
|
170
|
+
zstream.finish
|
171
|
+
zstream.close
|
172
|
+
inflated
|
173
|
+
end
|
174
|
+
|
175
|
+
# decodes a base64 encoded SAML response for use in SloLogoutresponse tests
|
176
|
+
#
|
177
|
+
def decode_saml_response_payload(unauth_url)
|
178
|
+
payload = CGI.unescape(unauth_url.split("SAMLResponse=").last)
|
179
|
+
decoded = Base64.decode64(payload)
|
180
|
+
|
181
|
+
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
182
|
+
inflated = zstream.inflate(decoded)
|
183
|
+
zstream.finish
|
184
|
+
zstream.close
|
185
|
+
inflated
|
186
|
+
end
|
155
187
|
end
|
data/test/utils_test.rb
CHANGED
@@ -2,6 +2,194 @@ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
|
2
2
|
|
3
3
|
class UtilsTest < Minitest::Test
|
4
4
|
describe "Utils" do
|
5
|
+
|
6
|
+
describe "format_cert" do
|
7
|
+
let(:formatted_certificate) {read_certificate("formatted_certificate")}
|
8
|
+
let(:formatted_chained_certificate) {read_certificate("formatted_chained_certificate")}
|
9
|
+
|
10
|
+
it "returns empty string when the cert is an empty string" do
|
11
|
+
cert = ""
|
12
|
+
assert_equal "", OneLogin::RubySaml::Utils.format_cert(cert)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns nil when the cert is nil" do
|
16
|
+
cert = nil
|
17
|
+
assert_nil OneLogin::RubySaml::Utils.format_cert(cert)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns the certificate when it is valid" do
|
21
|
+
assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(formatted_certificate)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "reformats the certificate when there are spaces and no line breaks" do
|
25
|
+
invalid_certificate1 = read_certificate("invalid_certificate1")
|
26
|
+
assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "reformats the certificate when there are spaces and no headers" do
|
30
|
+
invalid_certificate2 = read_certificate("invalid_certificate2")
|
31
|
+
assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate2)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the cert when it's encoded" do
|
35
|
+
encoded_certificate = read_certificate("certificate.der")
|
36
|
+
assert_equal encoded_certificate, OneLogin::RubySaml::Utils.format_cert(encoded_certificate)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "reformats the certificate when there line breaks and no headers" do
|
40
|
+
invalid_certificate3 = read_certificate("invalid_certificate3")
|
41
|
+
assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate3)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns the chained certificate when it is a valid chained certificate" do
|
45
|
+
assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(formatted_chained_certificate)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "reformats the chained certificate when there are spaces and no line breaks" do
|
49
|
+
invalid_chained_certificate1 = read_certificate("invalid_chained_certificate1")
|
50
|
+
assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_chained_certificate1)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "format_private_key" do
|
56
|
+
let(:formatted_private_key) do
|
57
|
+
read_certificate("formatted_private_key")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns empty string when the private key is an empty string" do
|
61
|
+
private_key = ""
|
62
|
+
assert_equal "", OneLogin::RubySaml::Utils.format_private_key(private_key)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns nil when the private key is nil" do
|
66
|
+
private_key = nil
|
67
|
+
assert_nil OneLogin::RubySaml::Utils.format_private_key(private_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "returns the private key when it is valid" do
|
71
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(formatted_private_key)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "reformats the private key when there are spaces and no line breaks" do
|
75
|
+
invalid_private_key1 = read_certificate("invalid_private_key1")
|
76
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "reformats the private key when there are spaces and no headers" do
|
80
|
+
invalid_private_key2 = read_certificate("invalid_private_key2")
|
81
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key2)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "reformats the private key when there line breaks and no headers" do
|
85
|
+
invalid_private_key3 = read_certificate("invalid_private_key3")
|
86
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key3)
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "an RSA public key" do
|
90
|
+
let(:formatted_rsa_private_key) do
|
91
|
+
read_certificate("formatted_rsa_private_key")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns the private key when it is valid" do
|
95
|
+
assert_equal formatted_rsa_private_key, OneLogin::RubySaml::Utils.format_private_key(formatted_rsa_private_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "reformats the private key when there are spaces and no line breaks" do
|
99
|
+
invalid_rsa_private_key1 = read_certificate("invalid_rsa_private_key1")
|
100
|
+
assert_equal formatted_rsa_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key1)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "reformats the private key when there are spaces and no headers" do
|
104
|
+
invalid_rsa_private_key2 = read_certificate("invalid_rsa_private_key2")
|
105
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key2)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "reformats the private key when there line breaks and no headers" do
|
109
|
+
invalid_rsa_private_key3 = read_certificate("invalid_rsa_private_key3")
|
110
|
+
assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key3)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "build_query" do
|
116
|
+
it "returns the query string" do
|
117
|
+
params = {}
|
118
|
+
params[:type] = "SAMLRequest"
|
119
|
+
params[:data] = "PHNhbWxwOkF1dGhuUmVxdWVzdCBEZXN0aW5hdGlvbj0naHR0cDovL2V4YW1wbGUuY29tP2ZpZWxkPXZhbHVlJyBJRD0nXzk4NmUxZDEwLWVhY2ItMDEzMi01MGRkLTAwOTBmNWRlZGQ3NycgSXNzdWVJbnN0YW50PScyMDE1LTA2LTAxVDIwOjM0OjU5WicgVmVyc2lvbj0nMi4wJyB4bWxuczpzYW1sPSd1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uJyB4bWxuczpzYW1scD0ndXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sJy8+"
|
120
|
+
params[:relay_state] = "http://example.com"
|
121
|
+
params[:sig_alg] = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
|
122
|
+
query_string = OneLogin::RubySaml::Utils.build_query(params)
|
123
|
+
assert_equal "SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCBEZXN0aW5hdGlvbj0naHR0cDovL2V4YW1wbGUuY29tP2ZpZWxkPXZhbHVlJyBJRD0nXzk4NmUxZDEwLWVhY2ItMDEzMi01MGRkLTAwOTBmNWRlZGQ3NycgSXNzdWVJbnN0YW50PScyMDE1LTA2LTAxVDIwOjM0OjU5WicgVmVyc2lvbj0nMi4wJyB4bWxuczpzYW1sPSd1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uJyB4bWxuczpzYW1scD0ndXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sJy8%2B&RelayState=http%3A%2F%2Fexample.com&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1", query_string
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "#status_error_msg" do
|
128
|
+
it "returns a error msg with a status message" do
|
129
|
+
error_msg = "The status code of the Logout Response was not Success"
|
130
|
+
status_code = "urn:oasis:names:tc:SAML:2.0:status:Requester"
|
131
|
+
status_message = "The request could not be performed due to an error on the part of the requester."
|
132
|
+
status_error_msg = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code, status_message)
|
133
|
+
assert_equal = "The status code of the Logout Response was not Success, was Requester -> The request could not be performed due to an error on the part of the requester.", status_error_msg
|
134
|
+
|
135
|
+
status_error_msg2 = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code)
|
136
|
+
assert_equal = "The status code of the Logout Response was not Success, was Requester", status_error_msg2
|
137
|
+
|
138
|
+
status_error_msg3 = OneLogin::RubySaml::Utils.status_error_msg(error_msg)
|
139
|
+
assert_equal = "The status code of the Logout Response was not Success", status_error_msg3
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'uri_match' do
|
144
|
+
it 'matches two urls' do
|
145
|
+
destination = 'http://www.example.com/test?var=stuff'
|
146
|
+
settings = 'http://www.example.com/test?var=stuff'
|
147
|
+
assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'fails to match two urls' do
|
151
|
+
destination = 'http://www.example.com/test?var=stuff'
|
152
|
+
settings = 'http://www.example.com/othertest?var=stuff'
|
153
|
+
assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "matches two URLs if the scheme case doesn't match" do
|
157
|
+
destination = 'http://www.example.com/test?var=stuff'
|
158
|
+
settings = 'HTTP://www.example.com/test?var=stuff'
|
159
|
+
assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "matches two URLs if the host case doesn't match" do
|
163
|
+
destination = 'http://www.EXAMPLE.com/test?var=stuff'
|
164
|
+
settings = 'http://www.example.com/test?var=stuff'
|
165
|
+
assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "fails to match two URLs if the path case doesn't match" do
|
169
|
+
destination = 'http://www.example.com/TEST?var=stuff'
|
170
|
+
settings = 'http://www.example.com/test?var=stuff'
|
171
|
+
assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "fails to match two URLs if the query case doesn't match" do
|
175
|
+
destination = 'http://www.example.com/test?var=stuff'
|
176
|
+
settings = 'http://www.example.com/test?var=STUFF'
|
177
|
+
assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'matches two non urls' do
|
181
|
+
destination = 'stuff'
|
182
|
+
settings = 'stuff'
|
183
|
+
assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "fails to match two non urls" do
|
187
|
+
destination = 'stuff'
|
188
|
+
settings = 'not stuff'
|
189
|
+
assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
5
193
|
describe 'element_text' do
|
6
194
|
it 'returns the element text' do
|
7
195
|
element = REXML::Document.new('<element>element text</element>').elements.first
|
@@ -36,6 +224,8 @@ class UtilsTest < Minitest::Test
|
|
36
224
|
element = REXML::Document.new('<element></element>').elements.first
|
37
225
|
assert_equal '', OneLogin::RubySaml::Utils.element_text(element)
|
38
226
|
end
|
227
|
+
|
228
|
+
|
39
229
|
end
|
40
230
|
end
|
41
|
-
end
|
231
|
+
end
|
data/test/xml_security_test.rb
CHANGED
@@ -4,81 +4,187 @@ class XmlSecurityTest < Minitest::Test
|
|
4
4
|
include XMLSecurity
|
5
5
|
|
6
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
|
+
|
7
12
|
before do
|
8
|
-
@
|
9
|
-
@base64cert = @document.elements["//ds:X509Certificate"].text
|
13
|
+
@base64cert = document.elements["//ds:X509Certificate"].text
|
10
14
|
end
|
11
15
|
|
12
16
|
it "should run validate without throwing NS related exceptions" do
|
13
|
-
assert
|
17
|
+
assert !document.validate_signature(@base64cert, true)
|
14
18
|
end
|
15
19
|
|
16
20
|
it "should run validate with throwing NS related exceptions" do
|
17
21
|
assert_raises(OneLogin::RubySaml::ValidationError) do
|
18
|
-
|
22
|
+
document.validate_signature(@base64cert, false)
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
26
|
it "not raise an error when softly validating the document multiple times" do
|
23
|
-
2.times {
|
27
|
+
2.times { assert_equal document.validate_signature(@base64cert, true), false }
|
28
|
+
end
|
29
|
+
|
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
|
24
34
|
end
|
25
35
|
|
26
36
|
it "should raise Fingerprint mismatch" do
|
27
37
|
exception = assert_raises(OneLogin::RubySaml::ValidationError) do
|
28
|
-
|
38
|
+
document.validate_document("no:fi:ng:er:pr:in:t", false)
|
29
39
|
end
|
30
40
|
assert_equal("Fingerprint mismatch", exception.message)
|
31
41
|
end
|
32
42
|
|
33
43
|
it "should raise Digest mismatch" do
|
34
44
|
exception = assert_raises(OneLogin::RubySaml::ValidationError) do
|
35
|
-
|
45
|
+
document.validate_signature(@base64cert, false)
|
36
46
|
end
|
37
47
|
assert_equal("Digest mismatch", exception.message)
|
38
48
|
end
|
39
49
|
|
40
50
|
it "should raise Key validation error" do
|
41
|
-
|
42
|
-
response.sub!("<ds:DigestValue>pJQ7MS/ek4KRRWGmv/H43ReHYMs=</ds:DigestValue>",
|
51
|
+
decoded_response.sub!("<ds:DigestValue>pJQ7MS/ek4KRRWGmv/H43ReHYMs=</ds:DigestValue>",
|
43
52
|
"<ds:DigestValue>b9xsAXLsynugg3Wc1CI3kpWku+0=</ds:DigestValue>")
|
44
|
-
|
45
|
-
base64cert =
|
53
|
+
mod_document = XMLSecurity::SignedDocument.new(decoded_response)
|
54
|
+
base64cert = mod_document.elements["//ds:X509Certificate"].text
|
46
55
|
exception = assert_raises(OneLogin::RubySaml::ValidationError) do
|
47
|
-
|
56
|
+
mod_document.validate_signature(base64cert, false)
|
48
57
|
end
|
49
58
|
assert_equal("Key validation error", exception.message)
|
50
59
|
end
|
51
60
|
|
52
|
-
it "
|
53
|
-
|
54
|
-
|
55
|
-
|
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)
|
56
70
|
exception = assert_raises(OneLogin::RubySaml::ValidationError) do
|
57
|
-
|
71
|
+
mod_document.validate_document("a fingerprint", false) # The fingerprint isn't relevant to this test
|
58
72
|
end
|
59
|
-
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
|
60
81
|
end
|
61
82
|
end
|
62
83
|
|
63
|
-
describe "
|
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")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "Fingerprint Algorithms" do
|
133
|
+
let(:response_fingerprint_test) { OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha1, false)) }
|
134
|
+
|
64
135
|
it "validate using SHA1" do
|
65
|
-
|
66
|
-
|
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)
|
67
144
|
end
|
68
145
|
|
69
146
|
it "validate using SHA256" do
|
70
|
-
|
71
|
-
|
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)
|
151
|
+
end
|
152
|
+
|
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)
|
158
|
+
end
|
159
|
+
|
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)
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
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")
|
72
178
|
end
|
73
179
|
|
74
180
|
it "validate using SHA384" do
|
75
|
-
|
76
|
-
assert
|
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")
|
77
183
|
end
|
78
184
|
|
79
185
|
it "validate using SHA512" do
|
80
|
-
|
81
|
-
assert
|
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")
|
82
188
|
end
|
83
189
|
end
|
84
190
|
|
@@ -103,35 +209,95 @@ class XmlSecurityTest < Minitest::Test
|
|
103
209
|
|
104
210
|
it 'support inclusive canonicalization' do
|
105
211
|
skip('test not yet implemented')
|
106
|
-
|
107
212
|
response = OneLogin::RubySaml::Response.new(fixture("tdnf_response.xml"))
|
108
213
|
response.stubs(:conditions).returns(nil)
|
109
214
|
assert !response.is_valid?
|
110
|
-
settings = OneLogin::RubySaml::Settings.new
|
111
215
|
assert !response.is_valid?
|
112
216
|
response.settings = settings
|
113
217
|
assert !response.is_valid?
|
114
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(" ", ":")
|
115
|
-
assert response.
|
219
|
+
assert response.is_valid?
|
116
220
|
end
|
117
221
|
|
118
|
-
it "return
|
222
|
+
it "return nil when inclusive namespace element is missing" do
|
119
223
|
response = fixture(:no_signature_ns, false)
|
120
224
|
response.slice! %r{<InclusiveNamespaces xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="#default saml ds xs xsi"/>}
|
121
225
|
|
122
226
|
document = XMLSecurity::SignedDocument.new(response)
|
123
227
|
inclusive_namespaces = document.send(:extract_inclusive_namespaces)
|
124
228
|
|
125
|
-
assert inclusive_namespaces.
|
229
|
+
assert inclusive_namespaces.nil?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
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)
|
126
294
|
end
|
127
295
|
end
|
128
296
|
|
129
297
|
describe "StarfieldTMS" do
|
130
298
|
before do
|
131
299
|
@response = OneLogin::RubySaml::Response.new(fixture(:starfield_response))
|
132
|
-
@response.settings = OneLogin::RubySaml::Settings.new(
|
133
|
-
:idp_cert_fingerprint => "8D:BA:53:8E:A3:B6:F9:F1:69:6C:BB:D9:D8:BD:41:B3:AC:4F:9D:4D"
|
134
|
-
)
|
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")
|
135
301
|
end
|
136
302
|
|
137
303
|
it "be able to validate a good response" do
|
@@ -153,6 +319,133 @@ class XmlSecurityTest < Minitest::Test
|
|
153
319
|
end
|
154
320
|
end
|
155
321
|
|
156
|
-
|
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' }
|
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
|
+
|
377
|
+
describe 'when response has no cert and you provide cert' do
|
378
|
+
let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
|
379
|
+
let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
|
380
|
+
let(:options) { {} }
|
381
|
+
|
382
|
+
it 'is valid' do
|
383
|
+
options[:cert] = idp_cert
|
384
|
+
assert document.document.validate_document(idp_cert, true, options), 'Document should be valid'
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'is valid if cert text instead x509cert provided' do
|
388
|
+
options[:cert] = ruby_saml_cert_text
|
389
|
+
assert document.document.validate_document(idp_cert, true, options), 'Document should be valid'
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
describe 'when response has no cert and you dont provide cert' do
|
394
|
+
let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
|
395
|
+
let(:options) { {} }
|
396
|
+
let(:idp_cert) { nil }
|
397
|
+
|
398
|
+
it 'is invalid' do
|
399
|
+
options[:cert] = idp_cert
|
400
|
+
assert !document.document.validate_document(idp_cert, true, options), 'Document should not be valid'
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'is invalid and error raised' do
|
404
|
+
options[:cert] = idp_cert
|
405
|
+
assert_raises(OneLogin::RubySaml::ValidationError) do
|
406
|
+
document.document.validate_document(idp_cert, false, options)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
describe '#validate_document_with_cert' do
|
413
|
+
describe 'with valid document ' do
|
414
|
+
describe 'when response has cert' do
|
415
|
+
let(:document_data) { read_response('response_with_signed_message_and_assertion.xml') }
|
416
|
+
let(:document) { OneLogin::RubySaml::Response.new(document_data).document }
|
417
|
+
let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
|
418
|
+
let(:fingerprint) { '4b68c453c7d994aad9025c99d5efcf566287fe8d' }
|
419
|
+
|
420
|
+
it 'is valid' do
|
421
|
+
assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
describe 'when response has no cert and you provide cert' do
|
426
|
+
let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
|
427
|
+
let(:idp_cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
|
428
|
+
|
429
|
+
it 'is valid' do
|
430
|
+
assert document.validate_document_with_cert(idp_cert), 'Document should be valid'
|
431
|
+
end
|
432
|
+
end
|
157
433
|
|
434
|
+
describe 'when response has no cert and you dont provide cert' do
|
435
|
+
let(:document) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate).document }
|
436
|
+
let(:idp_cert) { nil }
|
437
|
+
|
438
|
+
it 'is invalid' do
|
439
|
+
assert !document.validate_document_with_cert(idp_cert), 'Document should not be valid'
|
440
|
+
end
|
441
|
+
|
442
|
+
it 'is invalid and error raised' do
|
443
|
+
assert_raises(OneLogin::RubySaml::ValidationError) do
|
444
|
+
document.validate_document_with_cert(idp_cert, false)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
158
451
|
end
|