ruby-saml 0.8.11 → 0.8.16
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 +5 -5
- data/Gemfile +3 -1
- data/Rakefile +0 -14
- data/lib/onelogin/ruby-saml/logoutresponse.rb +9 -51
- data/lib/onelogin/ruby-saml/response.rb +121 -30
- data/lib/onelogin/ruby-saml/settings.rb +27 -10
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +101 -0
- 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 -87
- 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/logoutrequest_test.rb +124 -126
- data/test/logoutresponse_test.rb +22 -42
- data/test/requests/logoutrequest_fixtures.rb +47 -0
- data/test/response_test.rb +373 -129
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/encrypted_new_attack.xml.base64 +1 -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_concealed_signed_assertion.xml +51 -0
- data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
- 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/response_wrapped.xml.base64 +150 -0
- data/test/responses/valid_response.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +111 -5
- data/test/slo_logoutrequest_test.rb +66 -0
- data/test/test_helper.rb +110 -41
- data/test/utils_test.rb +201 -11
- data/test/xml_security_test.rb +359 -68
- metadata +77 -7
data/test/logoutresponse_test.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
-
require
|
3
|
-
require 'responses/logoutresponse_fixtures'
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "responses/logoutresponse_fixtures"))
|
4
3
|
|
5
|
-
class LogoutResponseTest < Test
|
4
|
+
class LogoutResponseTest < Minitest::Test
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
describe "Logoutresponse" do
|
7
|
+
|
8
|
+
describe "#new" do
|
9
|
+
it "raise an exception when response is initialized with nil" do
|
10
10
|
assert_raises(ArgumentError) { OneLogin::RubySaml::Logoutresponse.new(nil) }
|
11
11
|
end
|
12
|
-
|
12
|
+
it "default to empty settings" do
|
13
13
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new( valid_response)
|
14
14
|
assert logoutresponse.settings.nil?
|
15
15
|
end
|
16
|
-
|
16
|
+
it "accept constructor-injected settings" do
|
17
17
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings)
|
18
18
|
assert !logoutresponse.settings.nil?
|
19
19
|
end
|
20
|
-
|
20
|
+
it "accept constructor-injected options" do
|
21
21
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, nil, { :foo => :bar} )
|
22
22
|
assert !logoutresponse.options.empty?
|
23
23
|
end
|
24
|
-
|
24
|
+
it "support base64 encoded responses" do
|
25
25
|
expected_response = valid_response
|
26
26
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(expected_response), settings)
|
27
27
|
|
@@ -29,21 +29,21 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
describe "#validate" do
|
33
|
+
it "validate the response" do
|
34
34
|
in_relation_to_request_id = random_id
|
35
|
-
|
35
|
+
settings.idp_entity_id = "https://example.com/idp"
|
36
36
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
37
37
|
|
38
38
|
assert logoutresponse.validate
|
39
39
|
|
40
|
-
assert_equal settings.
|
40
|
+
assert_equal settings.idp_entity_id, logoutresponse.issuer
|
41
41
|
assert_equal in_relation_to_request_id, logoutresponse.in_response_to
|
42
42
|
|
43
43
|
assert logoutresponse.success?
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
it "invalidate responses with wrong id when given option :matches_uuid" do
|
47
47
|
|
48
48
|
expected_request_id = "_some_other_expected_uuid"
|
49
49
|
opts = { :matches_request_id => expected_request_id}
|
@@ -51,10 +51,10 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
51
51
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
|
52
52
|
|
53
53
|
assert !logoutresponse.validate
|
54
|
-
|
54
|
+
assert expected_request_id != logoutresponse.in_response_to
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
it "invalidate responses with wrong request status" do
|
58
58
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
59
59
|
|
60
60
|
assert !logoutresponse.validate
|
@@ -62,8 +62,8 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
describe "#validate!" do
|
66
|
+
it "validates good responses" do
|
67
67
|
in_relation_to_request_id = random_id
|
68
68
|
|
69
69
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
@@ -71,7 +71,7 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
71
71
|
logoutresponse.validate!
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
it "raises validation error when matching for wrong request id" do
|
75
75
|
|
76
76
|
expected_request_id = "_some_other_expected_id"
|
77
77
|
opts = { :matches_request_id => expected_request_id}
|
@@ -81,27 +81,13 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
81
81
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
82
82
|
end
|
83
83
|
|
84
|
-
|
84
|
+
it "raise validation error for wrong request status" do
|
85
85
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
86
86
|
|
87
87
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
88
88
|
end
|
89
89
|
|
90
|
-
|
91
|
-
# no settings
|
92
|
-
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response)
|
93
|
-
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
94
|
-
end
|
95
|
-
|
96
|
-
should "raise validation error when in lack of sp_entity_id setting" do
|
97
|
-
bad_settings = settings
|
98
|
-
bad_settings.issuer = nil
|
99
|
-
bad_settings.sp_entity_id = nil
|
100
|
-
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, bad_settings)
|
101
|
-
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
102
|
-
end
|
103
|
-
|
104
|
-
should "raise error for invalid xml" do
|
90
|
+
it "raise error for invalid xml" do
|
105
91
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
|
106
92
|
|
107
93
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
@@ -109,10 +95,4 @@ class LogoutResponseTest < Test::Unit::TestCase
|
|
109
95
|
end
|
110
96
|
|
111
97
|
end
|
112
|
-
|
113
|
-
# logoutresponse fixtures
|
114
|
-
def random_id
|
115
|
-
"_#{UUID.new.generate}"
|
116
|
-
end
|
117
|
-
|
118
98
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
def default_request_opts
|
4
|
+
{
|
5
|
+
:uuid => "_28024690-000e-0130-b6d2-38f6b112be8b",
|
6
|
+
:issue_instant => Time.now.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
7
|
+
:nameid => "testuser@example.com",
|
8
|
+
:nameid_format => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
9
|
+
:settings => settings
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_request(opts = {})
|
14
|
+
opts = default_request_opts.merge!(opts)
|
15
|
+
|
16
|
+
"<samlp:LogoutRequest
|
17
|
+
xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
|
18
|
+
xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"
|
19
|
+
ID=\"#{random_id}\" Version=\"2.0\"
|
20
|
+
IssueInstant=\"#{opts[:issue_instant]}\"
|
21
|
+
Destination=\"#{opts[:settings].idp_slo_target_url}\">
|
22
|
+
<saml:Issuer>#{opts[:settings].idp_entity_id}</saml:Issuer>
|
23
|
+
<saml:NameID Format=\"#{opts[:nameid_format]}\">#{opts[:nameid]}</saml:NameID>
|
24
|
+
</samlp:LogoutRequest>"
|
25
|
+
end
|
26
|
+
|
27
|
+
def invalid_xml_request
|
28
|
+
"<samlp:SomethingAwful
|
29
|
+
xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
|
30
|
+
ID=\"#{random_id}\" Version=\"2.0\">
|
31
|
+
</samlp:SomethingAwful>"
|
32
|
+
end
|
33
|
+
|
34
|
+
def settings
|
35
|
+
@settings ||= OneLogin::RubySaml::Settings.new(
|
36
|
+
{
|
37
|
+
:assertion_consumer_service_url => "http://app.muda.no/sso/consume",
|
38
|
+
:single_logout_service_url => "http://app.muda.no/sso/consume_logout",
|
39
|
+
:sp_entity_id => "http://app.muda.no",
|
40
|
+
:sp_name_qualifier => "http://sso.muda.no",
|
41
|
+
:idp_sso_target_url => "http://sso.muda.no/sso",
|
42
|
+
:idp_slo_target_url => "http://sso.muda.no/slo",
|
43
|
+
:idp_cert_fingerprint => "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
|
44
|
+
:name_identifier_format => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
45
|
+
}
|
46
|
+
)
|
47
|
+
end
|
data/test/response_test.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
2
|
|
3
|
-
class ResponseTest <
|
3
|
+
class ResponseTest < Minitest::Test
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
assert_raises(ArgumentError)
|
5
|
+
describe "Response" do
|
6
|
+
it "raise an exception when response is initialized with nil" do
|
7
|
+
err = assert_raises(ArgumentError) do
|
8
|
+
OneLogin::RubySaml::Response.new(nil)
|
9
|
+
end
|
10
|
+
assert_equal "Response cannot be nil", err.message
|
8
11
|
end
|
9
12
|
|
10
|
-
|
13
|
+
it "be able to parse a document which contains ampersands" do
|
11
14
|
XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
|
12
15
|
OneLogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
|
13
16
|
|
@@ -18,7 +21,7 @@ class ResponseTest < Test::Unit::TestCase
|
|
18
21
|
response.validate!
|
19
22
|
end
|
20
23
|
|
21
|
-
|
24
|
+
it "adapt namespace" do
|
22
25
|
response = OneLogin::RubySaml::Response.new(response_document)
|
23
26
|
assert !response.name_id.nil?
|
24
27
|
response = OneLogin::RubySaml::Response.new(response_document_2)
|
@@ -27,14 +30,14 @@ class ResponseTest < Test::Unit::TestCase
|
|
27
30
|
assert !response.name_id.nil?
|
28
31
|
end
|
29
32
|
|
30
|
-
|
33
|
+
it "default to raw input when a response is not Base64 encoded" do
|
31
34
|
decoded = Base64.decode64(response_document_2)
|
32
35
|
response = OneLogin::RubySaml::Response.new(decoded)
|
33
36
|
assert response.document
|
34
37
|
end
|
35
38
|
|
36
|
-
|
37
|
-
|
39
|
+
describe "Assertion" do
|
40
|
+
it "only retreive an assertion with an ID that matches the signature's reference URI" do
|
38
41
|
response = OneLogin::RubySaml::Response.new(wrapped_response_2)
|
39
42
|
response.stubs(:conditions).returns(nil)
|
40
43
|
settings = OneLogin::RubySaml::Settings.new
|
@@ -44,40 +47,109 @@ class ResponseTest < Test::Unit::TestCase
|
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
47
|
-
|
48
|
-
|
50
|
+
describe "#validate!" do
|
51
|
+
it "raise when settings not initialized" do
|
52
|
+
response = OneLogin::RubySaml::Response.new(response_document)
|
53
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
54
|
+
response.validate!
|
55
|
+
end
|
56
|
+
assert_equal "No settings on response", err.message
|
57
|
+
end
|
58
|
+
|
59
|
+
it "raise when encountering a condition that prevents the document from being valid" do
|
49
60
|
response = OneLogin::RubySaml::Response.new(response_document)
|
50
|
-
|
61
|
+
response.settings = settings
|
62
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
51
63
|
response.validate!
|
52
64
|
end
|
65
|
+
assert_equal "Current time is on or after NotOnOrAfter condition", err.message
|
53
66
|
end
|
67
|
+
|
68
|
+
it "raises an exception when no cert or fingerprint provided" do
|
69
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
70
|
+
response.stubs(:conditions).returns(nil)
|
71
|
+
settings = OneLogin::RubySaml::Settings.new
|
72
|
+
response.settings = settings
|
73
|
+
settings.idp_cert = nil
|
74
|
+
settings.idp_cert_fingerprint = nil
|
75
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
76
|
+
response.validate!
|
77
|
+
end
|
78
|
+
assert_equal "No fingerprint or certificate on settings", err.message
|
79
|
+
end
|
80
|
+
|
81
|
+
it "raise when no signature" do
|
82
|
+
response_no_signed_elements = OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64"))
|
83
|
+
settings.idp_cert_fingerprint = signature_fingerprint_1
|
84
|
+
response_no_signed_elements.settings = settings
|
85
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
86
|
+
response_no_signed_elements.validate!
|
87
|
+
end
|
88
|
+
assert_equal "Found an unexpected number of Signature Element. SAML Response rejected", err.message
|
89
|
+
end
|
90
|
+
|
91
|
+
it "raise when multiple signatures" do
|
92
|
+
response_multiple_signed = OneLogin::RubySaml::Response.new(read_invalid_response("multiple_signed.xml.base64"))
|
93
|
+
settings.idp_cert_fingerprint = signature_fingerprint_1
|
94
|
+
response_multiple_signed.settings = settings
|
95
|
+
response_multiple_signed.stubs(:validate_structure).returns(true)
|
96
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
97
|
+
response_multiple_signed.validate!
|
98
|
+
end
|
99
|
+
assert_equal "Duplicated ID. SAML Response rejected", err.message
|
100
|
+
end
|
101
|
+
|
102
|
+
it "raise when fingerprint missmatch" do
|
103
|
+
resp_xml = Base64.decode64(response_document_valid_signed)
|
104
|
+
response = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
105
|
+
response.stubs(:conditions).returns(nil)
|
106
|
+
settings = OneLogin::RubySaml::Settings.new
|
107
|
+
settings.idp_cert_fingerprint = signature_fingerprint_1
|
108
|
+
response.settings = settings
|
109
|
+
|
110
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
111
|
+
response.validate!
|
112
|
+
end
|
113
|
+
assert_equal 'Fingerprint mismatch', err.message
|
114
|
+
end
|
115
|
+
|
54
116
|
end
|
55
117
|
|
56
|
-
|
57
|
-
|
118
|
+
describe "#is_valid?" do
|
119
|
+
it "return false when response is initialized with blank data" do
|
58
120
|
response = OneLogin::RubySaml::Response.new('')
|
59
121
|
assert !response.is_valid?
|
60
122
|
end
|
61
123
|
|
62
|
-
|
124
|
+
it "return false if settings have not been set" do
|
63
125
|
response = OneLogin::RubySaml::Response.new(response_document)
|
64
126
|
assert !response.is_valid?
|
65
127
|
end
|
66
128
|
|
67
|
-
|
68
|
-
response = OneLogin::RubySaml::Response.new(
|
129
|
+
it "return false when no cert or fingerprint provided" do
|
130
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
131
|
+
response.stubs(:conditions).returns(nil)
|
132
|
+
settings = OneLogin::RubySaml::Settings.new
|
133
|
+
response.settings = settings
|
134
|
+
settings.idp_cert = nil
|
135
|
+
settings.idp_cert_fingerprint = nil
|
136
|
+
assert !response.is_valid?
|
137
|
+
end
|
138
|
+
|
139
|
+
it "return true when the response is initialized with valid data" do
|
140
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
69
141
|
response.stubs(:conditions).returns(nil)
|
70
142
|
assert !response.is_valid?
|
71
143
|
settings = OneLogin::RubySaml::Settings.new
|
72
144
|
assert !response.is_valid?
|
73
145
|
response.settings = settings
|
74
146
|
assert !response.is_valid?
|
75
|
-
settings.idp_cert_fingerprint =
|
76
|
-
|
147
|
+
response.settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
148
|
+
response.validate!
|
77
149
|
end
|
78
150
|
|
79
|
-
|
80
|
-
response = OneLogin::RubySaml::Response.new(
|
151
|
+
it "should be idempotent when the response is initialized with invalid data" do
|
152
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
81
153
|
response.stubs(:conditions).returns(nil)
|
82
154
|
settings = OneLogin::RubySaml::Settings.new
|
83
155
|
response.settings = settings
|
@@ -85,36 +157,58 @@ class ResponseTest < Test::Unit::TestCase
|
|
85
157
|
assert !response.is_valid?
|
86
158
|
end
|
87
159
|
|
88
|
-
|
89
|
-
response = OneLogin::RubySaml::Response.new(
|
160
|
+
it "should be idempotent when the response is initialized with valid data" do
|
161
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
90
162
|
response.stubs(:conditions).returns(nil)
|
91
163
|
settings = OneLogin::RubySaml::Settings.new
|
92
164
|
response.settings = settings
|
93
|
-
settings.idp_cert_fingerprint =
|
165
|
+
response.settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
94
166
|
assert response.is_valid?
|
95
167
|
assert response.is_valid?
|
96
168
|
end
|
97
169
|
|
98
|
-
|
99
|
-
response = OneLogin::RubySaml::Response.new(
|
170
|
+
it "return true when valid response and using fingerprint" do
|
171
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
100
172
|
response.stubs(:conditions).returns(nil)
|
101
173
|
settings = OneLogin::RubySaml::Settings.new
|
102
174
|
response.settings = settings
|
103
|
-
settings.idp_cert =
|
175
|
+
settings.idp_cert = nil
|
176
|
+
settings.idp_cert_fingerprint = "4B:68:C4:53:C7:D9:94:AA:D9:02:5C:99:D5:EF:CF:56:62:87:FE:8D"
|
104
177
|
assert response.is_valid?
|
105
178
|
end
|
106
179
|
|
107
|
-
|
180
|
+
it "return true when valid response using certificate" do
|
181
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
182
|
+
response.stubs(:conditions).returns(nil)
|
183
|
+
settings = OneLogin::RubySaml::Settings.new
|
184
|
+
response.settings = settings
|
185
|
+
settings.idp_cert = valid_cert
|
186
|
+
assert response.is_valid?
|
187
|
+
end
|
188
|
+
|
189
|
+
it "not allow signature wrapping attack" do
|
108
190
|
response = OneLogin::RubySaml::Response.new(response_document_4)
|
109
191
|
response.stubs(:conditions).returns(nil)
|
110
192
|
settings = OneLogin::RubySaml::Settings.new
|
111
193
|
settings.idp_cert_fingerprint = signature_fingerprint_1
|
112
194
|
response.settings = settings
|
113
|
-
assert response.is_valid?
|
195
|
+
assert !response.is_valid?
|
114
196
|
assert response.name_id == "test@onelogin.com"
|
115
197
|
end
|
116
198
|
|
117
|
-
|
199
|
+
it "not allow element wrapping attack" do
|
200
|
+
response_wrapped = OneLogin::RubySaml::Response.new(response_document_wrapped)
|
201
|
+
response_wrapped.stubs(:conditions).returns(nil)
|
202
|
+
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
203
|
+
settings = OneLogin::RubySaml::Settings.new
|
204
|
+
response_wrapped.settings = settings
|
205
|
+
response_wrapped.settings.idp_cert_fingerprint = signature_fingerprint_1
|
206
|
+
|
207
|
+
assert !response_wrapped.is_valid?
|
208
|
+
assert_nil response_wrapped.name_id
|
209
|
+
end
|
210
|
+
|
211
|
+
it "support dynamic namespace resolution on signature elements" do
|
118
212
|
response = OneLogin::RubySaml::Response.new(fixture("no_signature_ns.xml"))
|
119
213
|
response.stubs(:conditions).returns(nil)
|
120
214
|
settings = OneLogin::RubySaml::Settings.new
|
@@ -124,35 +218,70 @@ class ResponseTest < Test::Unit::TestCase
|
|
124
218
|
assert response.validate!
|
125
219
|
end
|
126
220
|
|
127
|
-
|
128
|
-
response = OneLogin::RubySaml::Response.new(
|
221
|
+
it "support signature elements with no KeyInfo if cert provided" do
|
222
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
|
129
223
|
response.stubs(:conditions).returns(nil)
|
130
224
|
settings = OneLogin::RubySaml::Settings.new
|
131
|
-
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
132
225
|
response.settings = settings
|
226
|
+
settings.idp_cert = ruby_saml_cert
|
227
|
+
settings.idp_cert_fingerprint = nil
|
228
|
+
XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
|
133
229
|
assert response.validate!
|
134
230
|
end
|
135
231
|
|
136
|
-
|
137
|
-
response = OneLogin::RubySaml::Response.new(
|
232
|
+
it "support signature elements with no KeyInfo if cert provided as text" do
|
233
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
|
138
234
|
response.stubs(:conditions).returns(nil)
|
139
235
|
settings = OneLogin::RubySaml::Settings.new
|
140
|
-
settings.idp_cert = Base64.decode64(r1_signature_2)
|
141
236
|
response.settings = settings
|
237
|
+
settings.idp_cert = ruby_saml_cert_text
|
238
|
+
settings.idp_cert_fingerprint = nil
|
239
|
+
XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
|
142
240
|
assert response.validate!
|
143
241
|
end
|
144
242
|
|
145
|
-
|
146
|
-
|
147
|
-
response = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
243
|
+
it "returns an error if the signature contains no KeyInfo, cert is not provided and soft" do
|
244
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
|
148
245
|
response.stubs(:conditions).returns(nil)
|
149
246
|
settings = OneLogin::RubySaml::Settings.new
|
150
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
151
247
|
response.settings = settings
|
152
|
-
|
248
|
+
settings.idp_cert = nil
|
249
|
+
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
250
|
+
assert !response.is_valid?
|
251
|
+
end
|
252
|
+
|
253
|
+
it "raises an exception if the signature contains no KeyInfo, cert is not provided and no soft" do
|
254
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate)
|
255
|
+
response.stubs(:conditions).returns(nil)
|
256
|
+
settings = OneLogin::RubySaml::Settings.new
|
257
|
+
response.settings = settings
|
258
|
+
settings.idp_cert = nil
|
259
|
+
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
260
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
261
|
+
response.validate!
|
262
|
+
end
|
263
|
+
assert_equal "Certificate element missing in response (ds:X509Certificate) and not cert provided at settings", err.message
|
264
|
+
end
|
265
|
+
|
266
|
+
it "validate ADFS assertions" do
|
267
|
+
response = OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
|
268
|
+
response.stubs(:conditions).returns(nil)
|
269
|
+
settings = OneLogin::RubySaml::Settings.new
|
270
|
+
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
271
|
+
response.settings = settings
|
272
|
+
assert response.validate!
|
153
273
|
end
|
154
274
|
|
155
|
-
|
275
|
+
it "validate the digest" do
|
276
|
+
response = OneLogin::RubySaml::Response.new(r1_response_document_6)
|
277
|
+
response.stubs(:conditions).returns(nil)
|
278
|
+
settings = OneLogin::RubySaml::Settings.new
|
279
|
+
settings.idp_cert = Base64.decode64(r1_signature_2)
|
280
|
+
response.settings = settings
|
281
|
+
assert response.validate!
|
282
|
+
end
|
283
|
+
|
284
|
+
it "Prevent node text with comment (VU#475445) attack" do
|
156
285
|
response_doc = File.read(File.join(File.dirname(__FILE__), "responses", 'response_node_text_attack.xml.base64'))
|
157
286
|
response = OneLogin::RubySaml::Response.new(response_doc)
|
158
287
|
|
@@ -160,42 +289,67 @@ class ResponseTest < Test::Unit::TestCase
|
|
160
289
|
assert_equal "smith", response.attributes["surname"]
|
161
290
|
end
|
162
291
|
|
163
|
-
|
164
|
-
|
165
|
-
response = OneLogin::RubySaml::Response.new(
|
292
|
+
describe '#validate_audience' do
|
293
|
+
it "return true when sp_entity_id not set or empty" do
|
294
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
166
295
|
response.stubs(:conditions).returns(nil)
|
167
296
|
settings = OneLogin::RubySaml::Settings.new
|
168
297
|
response.settings = settings
|
169
|
-
settings.idp_cert_fingerprint =
|
298
|
+
settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
170
299
|
assert response.is_valid?
|
171
300
|
settings.sp_entity_id = ''
|
172
301
|
assert response.is_valid?
|
173
302
|
end
|
174
303
|
|
175
|
-
|
176
|
-
response = OneLogin::RubySaml::Response.new(
|
304
|
+
it "return false when sp_entity_id set to incorrectly" do
|
305
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
177
306
|
response.stubs(:conditions).returns(nil)
|
178
307
|
settings = OneLogin::RubySaml::Settings.new
|
179
308
|
response.settings = settings
|
180
|
-
settings.idp_cert_fingerprint =
|
309
|
+
settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
181
310
|
settings.sp_entity_id = 'wrong_audience'
|
182
311
|
assert !response.is_valid?
|
183
312
|
end
|
184
313
|
|
185
|
-
|
186
|
-
response = OneLogin::RubySaml::Response.new(
|
314
|
+
it "return true when sp_entity_id set to correctly" do
|
315
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
187
316
|
response.stubs(:conditions).returns(nil)
|
188
317
|
settings = OneLogin::RubySaml::Settings.new
|
189
318
|
response.settings = settings
|
190
|
-
settings.idp_cert_fingerprint =
|
191
|
-
settings.sp_entity_id = 'audience'
|
319
|
+
settings.idp_cert_fingerprint = signature_fingerprint_valid_res
|
320
|
+
settings.sp_entity_id = 'https://someone.example.com/audience'
|
192
321
|
assert response.is_valid?
|
193
322
|
end
|
194
323
|
end
|
195
324
|
end
|
196
325
|
|
197
|
-
|
198
|
-
|
326
|
+
describe "#validate_issuer" do
|
327
|
+
it "return true when the issuer of the Message/Assertion matches the IdP entityId" do
|
328
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
329
|
+
response.settings = settings
|
330
|
+
assert response.send(:validate_issuer)
|
331
|
+
|
332
|
+
response.settings.idp_entity_id = 'https://app.onelogin.com/saml2'
|
333
|
+
assert response.send(:validate_issuer)
|
334
|
+
end
|
335
|
+
|
336
|
+
it "return false when the issuer of the Message does not match the IdP entityId" do
|
337
|
+
response = OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_message.xml.base64"))
|
338
|
+
response.settings = settings
|
339
|
+
response.settings.idp_entity_id = 'http://idp.example.com/'
|
340
|
+
assert !response.send(:validate_issuer)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "return false when the issuer of the Assertion does not match the IdP entityId" do
|
344
|
+
response = OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_assertion.xml.base64"))
|
345
|
+
response.settings = settings
|
346
|
+
response.settings.idp_entity_id = 'http://idp.example.com/'
|
347
|
+
assert !response.send(:validate_issuer)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe "#name_id" do
|
352
|
+
it "extract the value of the name id element" do
|
199
353
|
response = OneLogin::RubySaml::Response.new(response_document)
|
200
354
|
assert_equal "support@onelogin.com", response.name_id
|
201
355
|
|
@@ -203,19 +357,19 @@ class ResponseTest < Test::Unit::TestCase
|
|
203
357
|
assert_equal "someone@example.com", response.name_id
|
204
358
|
end
|
205
359
|
|
206
|
-
|
360
|
+
it "be extractable from an OpenSAML response" do
|
207
361
|
response = OneLogin::RubySaml::Response.new(fixture(:open_saml))
|
208
362
|
assert_equal "someone@example.org", response.name_id
|
209
363
|
end
|
210
364
|
|
211
|
-
|
365
|
+
it "be extractable from a Simple SAML PHP response" do
|
212
366
|
response = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
213
367
|
assert_equal "someone@example.com", response.name_id
|
214
368
|
end
|
215
369
|
end
|
216
370
|
|
217
|
-
|
218
|
-
|
371
|
+
describe "#check_conditions" do
|
372
|
+
it "check time conditions" do
|
219
373
|
response = OneLogin::RubySaml::Response.new(response_document)
|
220
374
|
assert !response.send(:validate_conditions, true)
|
221
375
|
response = OneLogin::RubySaml::Response.new(response_document_6)
|
@@ -226,75 +380,122 @@ class ResponseTest < Test::Unit::TestCase
|
|
226
380
|
assert response.send(:validate_conditions, true)
|
227
381
|
end
|
228
382
|
|
229
|
-
|
383
|
+
it "optionally allow for clock drift" do
|
230
384
|
# The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
|
231
|
-
Time.
|
385
|
+
expected_time = Time.parse("2011-06-14T18:21:01Z")
|
386
|
+
Time.stubs(:now).returns(expected_time)
|
232
387
|
response = OneLogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.515)
|
233
388
|
assert !response.send(:validate_conditions, true)
|
234
389
|
|
235
|
-
Time.
|
390
|
+
expected_time = Time.parse("2011-06-14T18:21:01Z")
|
391
|
+
Time.stubs(:now).returns(expected_time)
|
236
392
|
response = OneLogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.516)
|
237
393
|
assert response.send(:validate_conditions, true)
|
238
394
|
end
|
239
395
|
end
|
240
396
|
|
241
|
-
|
242
|
-
|
243
|
-
response = OneLogin::RubySaml::Response.new(
|
244
|
-
|
397
|
+
describe "validate_signature" do
|
398
|
+
it "raises an exception when no cert or fingerprint provided" do
|
399
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
400
|
+
settings = OneLogin::RubySaml::Settings.new
|
401
|
+
response.settings = settings
|
402
|
+
settings.idp_cert = nil
|
403
|
+
settings.idp_cert_fingerprint = nil
|
404
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
405
|
+
response.send(:validate_signature, false)
|
406
|
+
end
|
407
|
+
assert_equal "No fingerprint or certificate on settings", err.message
|
245
408
|
end
|
246
409
|
|
247
|
-
|
248
|
-
response = OneLogin::RubySaml::Response.new(
|
249
|
-
|
410
|
+
it "raises an exception when wrong cert provided" do
|
411
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
412
|
+
settings = OneLogin::RubySaml::Settings.new
|
413
|
+
response.settings = settings
|
414
|
+
settings.idp_cert = ruby_saml_cert2
|
415
|
+
settings.idp_cert_fingerprint = nil
|
416
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
417
|
+
response.send(:validate_signature, false)
|
418
|
+
end
|
419
|
+
assert_equal "Fingerprint mismatch", err.message
|
250
420
|
end
|
251
421
|
|
252
|
-
|
253
|
-
response = OneLogin::RubySaml::Response.new(
|
254
|
-
|
255
|
-
|
422
|
+
it "raises an exception when wrong fingerprint provided" do
|
423
|
+
response = OneLogin::RubySaml::Response.new(response_document_valid_signed)
|
424
|
+
settings = OneLogin::RubySaml::Settings.new
|
425
|
+
response.settings = settings
|
426
|
+
settings.idp_cert = nil
|
427
|
+
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
428
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
429
|
+
response.send(:validate_signature, false)
|
430
|
+
end
|
431
|
+
assert_equal "Fingerprint mismatch", err.message
|
256
432
|
end
|
257
433
|
|
258
|
-
|
259
|
-
|
260
|
-
|
434
|
+
it "raises an exception when no signature" do
|
435
|
+
response_no_signed_elements = OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64"))
|
436
|
+
settings.idp_cert_fingerprint = signature_fingerprint_1
|
437
|
+
response_no_signed_elements.settings = settings
|
438
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
439
|
+
response_no_signed_elements.validate!
|
440
|
+
end
|
441
|
+
assert_equal "Found an unexpected number of Signature Element. SAML Response rejected", err.message
|
261
442
|
end
|
443
|
+
end
|
262
444
|
|
263
|
-
|
264
|
-
|
265
|
-
|
445
|
+
describe "#attributes" do
|
446
|
+
before do
|
447
|
+
@response = OneLogin::RubySaml::Response.new(response_document)
|
266
448
|
end
|
267
449
|
|
268
|
-
|
450
|
+
it "extract the first attribute in a hash accessed via its symbol" do
|
451
|
+
assert_equal "demo", @response.attributes[:uid]
|
452
|
+
end
|
453
|
+
|
454
|
+
it "extract the first attribute in a hash accessed via its name" do
|
455
|
+
assert_equal "demo", @response.attributes["uid"]
|
456
|
+
end
|
457
|
+
|
458
|
+
it "extract all attributes" do
|
459
|
+
assert_equal "demo", @response.attributes[:uid]
|
460
|
+
assert_equal "value", @response.attributes[:another_value]
|
461
|
+
end
|
462
|
+
|
463
|
+
it "work for implicit namespaces" do
|
464
|
+
response_3 = OneLogin::RubySaml::Response.new(response_document_3)
|
465
|
+
assert_equal "someone@example.com", response_3.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
|
466
|
+
end
|
467
|
+
|
468
|
+
it "not raise on responses without attributes" do
|
469
|
+
response_4 = OneLogin::RubySaml::Response.new(response_document_4)
|
470
|
+
assert_equal OneLogin::RubySaml::Attributes.new, response_4.attributes
|
471
|
+
end
|
472
|
+
|
473
|
+
it "extract attributes from all AttributeStatement tags" do
|
269
474
|
assert_equal "smith", response_with_multiple_attribute_statements.attributes[:surname]
|
270
475
|
assert_equal "bob", response_with_multiple_attribute_statements.attributes[:firstname]
|
271
476
|
end
|
272
477
|
|
273
|
-
|
274
|
-
response
|
275
|
-
response.attributes.merge({ :testing_attribute => "test" })
|
478
|
+
it "be manipulable by hash methods such as #merge and not raise an exception" do
|
479
|
+
@response.attributes.merge({ :testing_attribute => "test" })
|
276
480
|
end
|
277
481
|
|
278
|
-
|
279
|
-
response
|
280
|
-
response.attributes.shift
|
482
|
+
it "be manipulable by hash methods such as #shift and not raise an exception" do
|
483
|
+
@response.attributes.shift
|
281
484
|
end
|
282
485
|
|
283
|
-
|
284
|
-
response
|
285
|
-
response.attributes
|
286
|
-
assert response.attributes[:testing_attribute]
|
486
|
+
it "be manipulable by hash methods such as #merge! and actually contain the value" do
|
487
|
+
@response.attributes.merge!({ :testing_attribute => "test" })
|
488
|
+
assert @response.attributes[:testing_attribute]
|
287
489
|
end
|
288
490
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
assert_nil response.attributes[removed_value[0]]
|
491
|
+
it "be manipulable by hash methods such as #shift and actually remove the value" do
|
492
|
+
removed_value = @response.attributes.shift
|
493
|
+
assert_nil @response.attributes[removed_value[0]]
|
293
494
|
end
|
294
495
|
end
|
295
496
|
|
296
|
-
|
297
|
-
|
497
|
+
describe "#session_expires_at" do
|
498
|
+
it "extract the value of the SessionNotOnOrAfter attribute" do
|
298
499
|
response = OneLogin::RubySaml::Response.new(response_document)
|
299
500
|
assert response.session_expires_at.is_a?(Time)
|
300
501
|
|
@@ -303,124 +504,167 @@ class ResponseTest < Test::Unit::TestCase
|
|
303
504
|
end
|
304
505
|
end
|
305
506
|
|
306
|
-
|
307
|
-
|
507
|
+
describe "#issuer" do
|
508
|
+
it "return the issuer inside the response assertion" do
|
308
509
|
response = OneLogin::RubySaml::Response.new(response_document)
|
309
510
|
assert_equal "https://app.onelogin.com/saml/metadata/13590", response.issuer
|
310
511
|
end
|
311
512
|
|
312
|
-
|
513
|
+
it "return the issuer inside the response" do
|
313
514
|
response = OneLogin::RubySaml::Response.new(response_document_2)
|
314
515
|
assert_equal "wibble", response.issuer
|
315
516
|
end
|
316
517
|
end
|
317
518
|
|
318
|
-
|
319
|
-
|
519
|
+
describe "#success" do
|
520
|
+
it "find a status code that says success" do
|
320
521
|
response = OneLogin::RubySaml::Response.new(response_document)
|
321
|
-
response.success?
|
522
|
+
assert response.send(:success?)
|
322
523
|
end
|
323
524
|
end
|
324
525
|
|
325
|
-
|
326
|
-
|
526
|
+
describe '#xpath_first_from_signed_assertion' do
|
527
|
+
it 'not allow arbitrary code execution' do
|
327
528
|
malicious_response_document = fixture('response_eval', false)
|
328
529
|
response = OneLogin::RubySaml::Response.new(malicious_response_document)
|
329
530
|
response.send(:xpath_first_from_signed_assertion)
|
330
|
-
|
531
|
+
assert_nil $evalled
|
331
532
|
end
|
332
533
|
end
|
333
534
|
|
334
|
-
|
335
|
-
|
535
|
+
describe "#multiple values" do
|
536
|
+
it "extract single value as string" do
|
336
537
|
assert_equal "demo", response_multiple_attr_values.attributes[:uid]
|
337
538
|
end
|
338
539
|
|
339
|
-
|
540
|
+
it "extract single value as string in compatibility mode off" do
|
340
541
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
341
542
|
assert_equal ["demo"], response_multiple_attr_values.attributes[:uid]
|
342
543
|
# classes are not reloaded between tests so restore default
|
343
544
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
344
545
|
end
|
345
546
|
|
346
|
-
|
547
|
+
it "extract first of multiple values as string for b/w compatibility" do
|
347
548
|
assert_equal 'value1', response_multiple_attr_values.attributes[:another_value]
|
348
549
|
end
|
349
550
|
|
350
|
-
|
551
|
+
it "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
|
351
552
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
352
553
|
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes[:another_value]
|
353
554
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
354
555
|
end
|
355
556
|
|
356
|
-
|
557
|
+
it "return array with all attributes when asked in XML order" do
|
357
558
|
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
358
559
|
end
|
359
560
|
|
360
|
-
|
561
|
+
it "return array with all attributes when asked in XML order in compatibility mode off" do
|
361
562
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
362
563
|
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
363
564
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
364
565
|
end
|
365
566
|
|
366
|
-
|
567
|
+
it "return first of multiple values when multiple Attribute tags in XML" do
|
367
568
|
assert_equal 'role1', response_multiple_attr_values.attributes[:role]
|
368
569
|
end
|
369
570
|
|
370
|
-
|
571
|
+
it "return first of multiple values when multiple Attribute tags in XML in compatibility mode off" do
|
371
572
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
372
573
|
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes[:role]
|
373
574
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
374
575
|
end
|
375
576
|
|
376
|
-
|
577
|
+
it "return all of multiple values in reverse order when multiple Attribute tags in XML" do
|
377
578
|
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
378
579
|
end
|
379
580
|
|
380
|
-
|
581
|
+
it "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
|
381
582
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
382
583
|
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
383
584
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
384
585
|
end
|
385
586
|
|
386
|
-
|
587
|
+
it "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
|
387
588
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
388
589
|
assert_equal ['role1', 'role2', 'role3'], response_with_multiple_attribute_statements.attributes.multi(:role)
|
389
590
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
390
591
|
end
|
391
592
|
|
392
|
-
|
593
|
+
it "return nil value correctly" do
|
393
594
|
assert_nil response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
394
595
|
end
|
395
596
|
|
396
|
-
|
597
|
+
it "return nil value correctly when not in compatibility mode off" do
|
397
598
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
398
|
-
|
599
|
+
assert [nil] == response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
399
600
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
400
601
|
end
|
401
602
|
|
402
|
-
|
603
|
+
it "return multiple values including nil and empty string" do
|
403
604
|
response = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
|
404
605
|
assert_equal ["", "valuePresent", nil, nil], response.attributes.multi(:attribute_with_nils_and_empty_strings)
|
405
606
|
end
|
406
607
|
|
407
|
-
|
608
|
+
it "return multiple values from [] when not in compatibility mode off" do
|
408
609
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
409
610
|
assert_equal ["", "valuePresent", nil, nil], response_multiple_attr_values.attributes[:attribute_with_nils_and_empty_strings]
|
410
611
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
411
612
|
end
|
412
613
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
614
|
+
it "check what happens when trying retrieve attribute that does not exists" do
|
615
|
+
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
616
|
+
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
617
|
+
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
417
618
|
|
418
619
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
419
|
-
|
420
|
-
|
421
|
-
|
620
|
+
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
621
|
+
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
622
|
+
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
422
623
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
423
624
|
end
|
424
625
|
end
|
626
|
+
|
627
|
+
describe "signature wrapping attack with encrypted assertion" do
|
628
|
+
it "should not be valid" do
|
629
|
+
settings = OneLogin::RubySaml::Settings.new
|
630
|
+
settings.private_key = valid_key
|
631
|
+
signature_wrapping_attack = read_response("encrypted_new_attack.xml.base64")
|
632
|
+
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
633
|
+
response_wrapped.stubs(:conditions).returns(nil)
|
634
|
+
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
635
|
+
settings.idp_cert_fingerprint = "385b1eec71143f00db6af936e2ea12a28771d72c"
|
636
|
+
assert !response_wrapped.is_valid?
|
637
|
+
err = assert_raises(OneLogin::RubySaml::ValidationError) do
|
638
|
+
response_wrapped.validate!
|
639
|
+
end
|
640
|
+
assert_equal "Found an invalid Signed Element. SAML Response rejected", err.message
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
describe "signature wrapping attack - concealed SAML response body" do
|
645
|
+
it "should not be valid" do
|
646
|
+
settings = OneLogin::RubySaml::Settings.new
|
647
|
+
signature_wrapping_attack = read_response("response_with_concealed_signed_assertion.xml")
|
648
|
+
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
649
|
+
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
650
|
+
response_wrapped.stubs(:conditions).returns(nil)
|
651
|
+
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
652
|
+
response_wrapped.stubs(:validate_structure).returns(true)
|
653
|
+
assert !response_wrapped.is_valid?
|
654
|
+
assert !response_wrapped.validate!
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
describe "signature wrapping attack - doubled signed assertion SAML response" do
|
659
|
+
it "should not be valid" do
|
660
|
+
settings = OneLogin::RubySaml::Settings.new
|
661
|
+
signature_wrapping_attack = read_response("response_with_doubled_signed_assertion.xml")
|
662
|
+
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
663
|
+
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
664
|
+
response_wrapped.stubs(:conditions).returns(nil)
|
665
|
+
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
666
|
+
assert !response_wrapped.is_valid?
|
667
|
+
end
|
668
|
+
end
|
425
669
|
end
|
426
670
|
end
|