ruby-saml 1.11.0 → 1.12.1
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/.travis.yml +14 -12
- data/README.md +76 -22
- data/changelog.md +27 -0
- data/lib/onelogin/ruby-saml/attributes.rb +24 -1
- data/lib/onelogin/ruby-saml/authrequest.rb +9 -4
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +62 -24
- data/lib/onelogin/ruby-saml/logoutrequest.rb +7 -1
- data/lib/onelogin/ruby-saml/logoutresponse.rb +4 -0
- data/lib/onelogin/ruby-saml/metadata.rb +9 -1
- data/lib/onelogin/ruby-saml/response.rb +38 -16
- data/lib/onelogin/ruby-saml/saml_message.rb +6 -0
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +34 -2
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +4 -0
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -14
- data/lib/onelogin/ruby-saml/utils.rb +56 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +34 -6
- data/ruby-saml.gemspec +8 -4
- metadata +22 -282
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/certificate1 +0 -12
- data/test/certificates/certificate_without_head_foot +0 -1
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/certificates/ruby-saml.crt +0 -14
- data/test/certificates/ruby-saml.key +0 -15
- data/test/idp_metadata_parser_test.rb +0 -594
- data/test/logging_test.rb +0 -62
- data/test/logout_requests/invalid_slo_request.xml +0 -6
- data/test/logout_requests/slo_request.xml +0 -4
- data/test/logout_requests/slo_request.xml.base64 +0 -1
- data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
- data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
- data/test/logout_requests/slo_request_with_session_index.xml +0 -5
- data/test/logout_responses/logoutresponse_fixtures.rb +0 -86
- data/test/logoutrequest_test.rb +0 -260
- data/test/logoutresponse_test.rb +0 -427
- data/test/metadata/idp_descriptor.xml +0 -26
- data/test/metadata/idp_descriptor_2.xml +0 -56
- data/test/metadata/idp_descriptor_3.xml +0 -14
- data/test/metadata/idp_descriptor_4.xml +0 -72
- data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
- data/test/metadata/idp_metadata_multi_certs.xml +0 -75
- data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
- data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
- data/test/metadata/idp_multiple_descriptors.xml +0 -59
- data/test/metadata/idp_multiple_descriptors_2.xml +0 -59
- data/test/metadata/no_idp_descriptor.xml +0 -21
- data/test/metadata_test.rb +0 -331
- data/test/request_test.rb +0 -340
- data/test/response_test.rb +0 -1629
- data/test/responses/adfs_response_sha1.xml +0 -46
- data/test/responses/adfs_response_sha256.xml +0 -46
- data/test/responses/adfs_response_sha384.xml +0 -46
- data/test/responses/adfs_response_sha512.xml +0 -46
- data/test/responses/adfs_response_xmlns.xml +0 -45
- data/test/responses/attackxee.xml +0 -13
- data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
- data/test/responses/invalids/empty_destination.xml.base64 +0 -1
- data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
- data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
- data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
- data/test/responses/invalids/no_conditions.xml.base64 +0 -1
- data/test/responses/invalids/no_id.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
- data/test/responses/invalids/no_nameid.xml.base64 +0 -1
- data/test/responses/invalids/no_saml2.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/no_status.xml.base64 +0 -1
- data/test/responses/invalids/no_status_code.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
- data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
- data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
- data/test/responses/no_signature_ns.xml +0 -48
- data/test/responses/open_saml_response.xml +0 -56
- data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
- data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
- data/test/responses/response_double_status_code.xml.base64 +0 -1
- data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
- data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
- data/test/responses/response_eval.xml +0 -7
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack2.xml.base64 +0 -1
- data/test/responses/response_node_text_attack3.xml.base64 +0 -1
- data/test/responses/response_unsigned_xml_base64 +0 -1
- data/test/responses/response_with_ampersands.xml +0 -139
- data/test/responses/response_with_ampersands.xml.base64 +0 -93
- data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_multiple_attribute_values.xml +0 -67
- data/test/responses/response_with_retrieval_method.xml +0 -26
- data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
- data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
- data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_without_attributes.xml.base64 +0 -79
- data/test/responses/response_without_reference_uri.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/signed_nameid_in_atts.xml +0 -47
- data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
- data/test/responses/simple_saml_php.xml +0 -71
- data/test/responses/starfield_response.xml.base64 +0 -1
- data/test/responses/test_sign.xml +0 -43
- data/test/responses/unsigned_encrypted_adfs.xml +0 -23
- data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- data/test/saml_message_test.rb +0 -56
- data/test/settings_test.rb +0 -338
- data/test/slo_logoutrequest_test.rb +0 -467
- data/test/slo_logoutresponse_test.rb +0 -233
- data/test/test_helper.rb +0 -333
- data/test/utils_test.rb +0 -259
- data/test/xml_security_test.rb +0 -421
data/test/response_test.rb
DELETED
@@ -1,1629 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
-
|
3
|
-
require 'onelogin/ruby-saml/response'
|
4
|
-
|
5
|
-
class RubySamlTest < Minitest::Test
|
6
|
-
|
7
|
-
describe "Response" do
|
8
|
-
|
9
|
-
let(:settings) { OneLogin::RubySaml::Settings.new }
|
10
|
-
let(:response) { OneLogin::RubySaml::Response.new(response_document_without_recipient) }
|
11
|
-
let(:response_without_attributes) { OneLogin::RubySaml::Response.new(response_document_without_attributes) }
|
12
|
-
let(:response_with_multiple_attribute_statements) { OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_statements)) }
|
13
|
-
let(:response_without_reference_uri) { OneLogin::RubySaml::Response.new(response_document_without_reference_uri) }
|
14
|
-
let(:response_with_signed_assertion) { OneLogin::RubySaml::Response.new(response_document_with_signed_assertion) }
|
15
|
-
let(:response_with_ds_namespace_at_the_root) { OneLogin::RubySaml::Response.new(response_document_with_ds_namespace_at_the_root)}
|
16
|
-
let(:response_unsigned) { OneLogin::RubySaml::Response.new(response_document_unsigned) }
|
17
|
-
let(:response_wrapped) { OneLogin::RubySaml::Response.new(response_document_wrapped) }
|
18
|
-
let(:response_multiple_attr_values) { OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values)) }
|
19
|
-
let(:response_valid_signed) { OneLogin::RubySaml::Response.new(response_document_valid_signed) }
|
20
|
-
let(:response_valid_signed_without_recipient) { OneLogin::RubySaml::Response.new(response_document_valid_signed, {:skip_recipient_check => true })}
|
21
|
-
let(:response_valid_signed_without_x509certificate) { OneLogin::RubySaml::Response.new(response_document_valid_signed_without_x509certificate) }
|
22
|
-
let(:response_no_id) { OneLogin::RubySaml::Response.new(read_invalid_response("no_id.xml.base64")) }
|
23
|
-
let(:response_no_version) { OneLogin::RubySaml::Response.new(read_invalid_response("no_saml2.xml.base64")) }
|
24
|
-
let(:response_multi_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_assertions.xml.base64")) }
|
25
|
-
let(:response_no_conditions) { OneLogin::RubySaml::Response.new(read_invalid_response("no_conditions.xml.base64")) }
|
26
|
-
let(:response_no_conditions_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("no_conditions.xml.base64"), { :skip_conditions => true }) }
|
27
|
-
let(:response_no_authnstatement) { OneLogin::RubySaml::Response.new(read_invalid_response("no_authnstatement.xml.base64")) }
|
28
|
-
let(:response_no_authnstatement_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("no_authnstatement.xml.base64"), {:skip_authnstatement => true}) }
|
29
|
-
let(:response_empty_destination) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64")) }
|
30
|
-
let(:response_empty_destination_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64"), {:skip_destination => true}) }
|
31
|
-
let(:response_no_status) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status.xml.base64")) }
|
32
|
-
let(:response_no_statuscode) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status_code.xml.base64")) }
|
33
|
-
let(:response_statuscode_responder) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responder.xml.base64")) }
|
34
|
-
let(:response_statuscode_responder_and_msg) { OneLogin::RubySaml::Response.new(read_invalid_response("status_code_responer_and_msg.xml.base64")) }
|
35
|
-
let(:response_double_statuscode) { OneLogin::RubySaml::Response.new(response_document_double_status_code) }
|
36
|
-
let(:response_encrypted_attrs) { OneLogin::RubySaml::Response.new(response_document_encrypted_attrs) }
|
37
|
-
let(:response_no_signed_elements) { OneLogin::RubySaml::Response.new(read_invalid_response("no_signature.xml.base64")) }
|
38
|
-
let(:response_multiple_signed) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_signed.xml.base64")) }
|
39
|
-
let(:response_audience_self_closed) { OneLogin::RubySaml::Response.new(read_response("response_audience_self_closed_tag.xml.base64")) }
|
40
|
-
let(:response_invalid_audience) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_audience.xml.base64")) }
|
41
|
-
let(:response_invalid_signed_element) { OneLogin::RubySaml::Response.new(read_invalid_response("response_invalid_signed_element.xml.base64")) }
|
42
|
-
let(:response_invalid_issuer_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_assertion.xml.base64")) }
|
43
|
-
let(:response_invalid_issuer_message) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_issuer_message.xml.base64")) }
|
44
|
-
let(:response_no_issuer_response) { OneLogin::RubySaml::Response.new(read_invalid_response("no_issuer_response.xml.base64")) }
|
45
|
-
let(:response_no_issuer_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("no_issuer_assertion.xml.base64")) }
|
46
|
-
let(:response_no_nameid) { OneLogin::RubySaml::Response.new(read_invalid_response("no_nameid.xml.base64")) }
|
47
|
-
let(:response_empty_nameid) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_nameid.xml.base64")) }
|
48
|
-
let(:response_wrong_spnamequalifier) { OneLogin::RubySaml::Response.new(read_invalid_response("wrong_spnamequalifier.xml.base64")) }
|
49
|
-
let(:response_duplicated_attributes) { OneLogin::RubySaml::Response.new(read_invalid_response("duplicated_attributes.xml.base64")) }
|
50
|
-
let(:response_no_subjectconfirmation_data) { OneLogin::RubySaml::Response.new(read_invalid_response("no_subjectconfirmation_data.xml.base64")) }
|
51
|
-
let(:response_no_subjectconfirmation_method) { OneLogin::RubySaml::Response.new(read_invalid_response("no_subjectconfirmation_method.xml.base64")) }
|
52
|
-
let(:response_invalid_subjectconfirmation_inresponse) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_inresponse.xml.base64")) }
|
53
|
-
let(:response_invalid_subjectconfirmation_recipient) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_recipient.xml.base64")) }
|
54
|
-
let(:response_invalid_subjectconfirmation_nb) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_nb.xml.base64")) }
|
55
|
-
let(:response_invalid_subjectconfirmation_noa) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_noa.xml.base64")) }
|
56
|
-
let(:response_invalid_signature_position) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_signature_position.xml.base64")) }
|
57
|
-
let(:response_encrypted_nameid) { OneLogin::RubySaml::Response.new(response_document_encrypted_nameid) }
|
58
|
-
|
59
|
-
def generate_audience_error(expected, actual)
|
60
|
-
s = actual.count > 1 ? 's' : '';
|
61
|
-
return "Invalid Audience#{s}. The audience#{s} #{actual.join(',')}, did not match the expected audience #{expected}"
|
62
|
-
end
|
63
|
-
|
64
|
-
it "raise an exception when response is initialized with nil" do
|
65
|
-
assert_raises(ArgumentError) { OneLogin::RubySaml::Response.new(nil) }
|
66
|
-
end
|
67
|
-
|
68
|
-
it "not filter available options only" do
|
69
|
-
options = { :skip_destination => true, :foo => :bar }
|
70
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, options)
|
71
|
-
assert_includes response.options.keys, :skip_destination
|
72
|
-
assert_includes response.options.keys, :foo
|
73
|
-
end
|
74
|
-
|
75
|
-
it "be able to parse a document which contains ampersands" do
|
76
|
-
XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
|
77
|
-
OneLogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
|
78
|
-
|
79
|
-
ampersands_response = OneLogin::RubySaml::Response.new(ampersands_document)
|
80
|
-
ampersands_response.settings = settings
|
81
|
-
ampersands_response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
82
|
-
|
83
|
-
assert !ampersands_response.is_valid?
|
84
|
-
assert_includes ampersands_response.errors, "SAML Response must contain 1 assertion"
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "Prevent node text with comment attack (VU#475445)" do
|
88
|
-
before do
|
89
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack.xml.base64'))
|
90
|
-
end
|
91
|
-
|
92
|
-
it "receives the full NameID when there is an injected comment" do
|
93
|
-
assert_equal "support@onelogin.com", @response.name_id
|
94
|
-
end
|
95
|
-
|
96
|
-
it "receives the full AttributeValue when there is an injected comment" do
|
97
|
-
assert_equal "smith", @response.attributes["surname"]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe "Another test to prevent with comment attack (VU#475445)" do
|
102
|
-
before do
|
103
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack2.xml.base64'), {:skip_recipient_check => true })
|
104
|
-
@response.settings = settings
|
105
|
-
@response.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
106
|
-
end
|
107
|
-
|
108
|
-
it "receives the full NameID when there is an injected comment, validates the response" do
|
109
|
-
assert_equal "test@onelogin.com", @response.name_id
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "Another test with CDATA injected" do
|
114
|
-
before do
|
115
|
-
@response = OneLogin::RubySaml::Response.new(read_response('response_node_text_attack3.xml.base64'), {:skip_recipient_check => true })
|
116
|
-
@response.settings = settings
|
117
|
-
@response.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
118
|
-
end
|
119
|
-
|
120
|
-
it "it normalizes CDATA but reject SAMLResponse due signature invalidation" do
|
121
|
-
assert_equal "test@onelogin.com.evil.com", @response.name_id
|
122
|
-
assert !@response.is_valid?
|
123
|
-
assert_includes @response.errors, "Invalid Signature on SAML Response"
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe "Prevent XEE attack" do
|
128
|
-
before do
|
129
|
-
@response = OneLogin::RubySaml::Response.new(fixture(:attackxee))
|
130
|
-
end
|
131
|
-
|
132
|
-
it "false when evil attack vector is present, soft = true" do
|
133
|
-
@response.soft = true
|
134
|
-
assert !@response.send(:validate_structure)
|
135
|
-
assert_includes @response.errors, "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
136
|
-
end
|
137
|
-
|
138
|
-
it "raise when evil attack vector is present, soft = false " do
|
139
|
-
@response.soft = false
|
140
|
-
|
141
|
-
assert_raises(OneLogin::RubySaml::ValidationError) do
|
142
|
-
@response.send(:validate_structure)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
it "adapt namespace" do
|
148
|
-
refute_nil response.nameid
|
149
|
-
refute_nil response_without_attributes.nameid
|
150
|
-
refute_nil response_with_signed_assertion.nameid
|
151
|
-
end
|
152
|
-
|
153
|
-
it "default to raw input when a response is not Base64 encoded" do
|
154
|
-
decoded = Base64.decode64(response_document_without_attributes)
|
155
|
-
response_from_raw = OneLogin::RubySaml::Response.new(decoded)
|
156
|
-
assert response_from_raw.document
|
157
|
-
end
|
158
|
-
|
159
|
-
describe "Assertion" do
|
160
|
-
it "only retreive an assertion with an ID that matches the signature's reference URI" do
|
161
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
162
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
163
|
-
response_wrapped.settings = settings
|
164
|
-
assert_nil response_wrapped.nameid
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe "#is_valid?" do
|
169
|
-
describe "soft = false" do
|
170
|
-
|
171
|
-
before do
|
172
|
-
response.soft = false
|
173
|
-
response_valid_signed.soft = false
|
174
|
-
end
|
175
|
-
|
176
|
-
it "raise when response is initialized with blank data" do
|
177
|
-
blank_response = OneLogin::RubySaml::Response.new('')
|
178
|
-
blank_response.soft = false
|
179
|
-
error_msg = "Blank response"
|
180
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
181
|
-
blank_response.is_valid?
|
182
|
-
end
|
183
|
-
assert_includes blank_response.errors, error_msg
|
184
|
-
end
|
185
|
-
|
186
|
-
it "raise when settings have not been set" do
|
187
|
-
error_msg = "No settings on response"
|
188
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
189
|
-
response.is_valid?
|
190
|
-
end
|
191
|
-
assert_includes response.errors, error_msg
|
192
|
-
end
|
193
|
-
|
194
|
-
it "raise when No fingerprint or certificate on settings" do
|
195
|
-
settings.idp_cert_fingerprint = nil
|
196
|
-
settings.idp_cert = nil
|
197
|
-
settings.idp_cert_multi = nil
|
198
|
-
response.settings = settings
|
199
|
-
error_msg = "No fingerprint or certificate on settings"
|
200
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
201
|
-
response.is_valid?
|
202
|
-
end
|
203
|
-
assert_includes response.errors, error_msg
|
204
|
-
end
|
205
|
-
|
206
|
-
it "raise when signature wrapping attack" do
|
207
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
208
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
209
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
210
|
-
response_wrapped.settings = settings
|
211
|
-
assert !response_wrapped.is_valid?
|
212
|
-
end
|
213
|
-
|
214
|
-
it "validate SAML 2.0 XML structure" do
|
215
|
-
resp_xml = Base64.decode64(response_document_unsigned).gsub(/emailAddress/,'test')
|
216
|
-
response_unsigned_mod = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
217
|
-
response_unsigned_mod.stubs(:conditions).returns(nil)
|
218
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
219
|
-
response_unsigned_mod.settings = settings
|
220
|
-
response_unsigned_mod.soft = false
|
221
|
-
assert_raises(OneLogin::RubySaml::ValidationError, 'Digest mismatch') do
|
222
|
-
response_unsigned_mod.is_valid?
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
it "raise when encountering a condition that prevents the document from being valid" do
|
227
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
228
|
-
response.settings = settings
|
229
|
-
response.soft = false
|
230
|
-
error_msg = "Current time is on or after NotOnOrAfter condition"
|
231
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
232
|
-
response.is_valid?
|
233
|
-
end
|
234
|
-
assert_includes response.errors[0], error_msg
|
235
|
-
end
|
236
|
-
|
237
|
-
it "raise when encountering a SAML Response with bad formatted" do
|
238
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
239
|
-
response_without_attributes.settings = settings
|
240
|
-
response_without_attributes.soft = false
|
241
|
-
assert_raises(OneLogin::RubySaml::ValidationError) do
|
242
|
-
response_without_attributes.is_valid?
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
it "raise when the inResponseTo value does not match the Request ID" do
|
247
|
-
settings.soft = false
|
248
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
249
|
-
opts = {}
|
250
|
-
opts[:settings] = settings
|
251
|
-
opts[:matches_request_id] = "invalid_request_id"
|
252
|
-
response_valid_signed = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
253
|
-
error_msg = "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
254
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
255
|
-
response_valid_signed.is_valid?
|
256
|
-
end
|
257
|
-
assert_includes response_valid_signed.errors, error_msg
|
258
|
-
end
|
259
|
-
|
260
|
-
it "raise when there is no valid audience" do
|
261
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
262
|
-
settings.sp_entity_id = 'invalid'
|
263
|
-
response_valid_signed.settings = settings
|
264
|
-
response_valid_signed.soft = false
|
265
|
-
error_msg = generate_audience_error(response_valid_signed.settings.sp_entity_id, ['https://someone.example.com/audience'])
|
266
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
267
|
-
response_valid_signed.is_valid?
|
268
|
-
end
|
269
|
-
assert_includes response_valid_signed.errors, error_msg
|
270
|
-
end
|
271
|
-
|
272
|
-
it "raise when no ID present in the SAML Response" do
|
273
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
274
|
-
response_no_id.settings = settings
|
275
|
-
response_no_id.soft = false
|
276
|
-
error_msg = "Missing ID attribute on SAML Response"
|
277
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
278
|
-
response_no_id.is_valid?
|
279
|
-
end
|
280
|
-
assert_includes response_no_id.errors, error_msg
|
281
|
-
end
|
282
|
-
|
283
|
-
it "raise when no 2.0 Version present in the SAML Response" do
|
284
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
285
|
-
response_no_version.settings = settings
|
286
|
-
response_no_version.soft = false
|
287
|
-
error_msg = "Unsupported SAML version"
|
288
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
289
|
-
response_no_version.is_valid?
|
290
|
-
end
|
291
|
-
assert_includes response_no_version.errors, error_msg
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
describe "soft = true" do
|
296
|
-
before do
|
297
|
-
response.soft = true
|
298
|
-
response_valid_signed.soft = true
|
299
|
-
end
|
300
|
-
|
301
|
-
it "return true when the response is initialized with valid data" do
|
302
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
303
|
-
response_valid_signed_without_recipient.settings = settings
|
304
|
-
response_valid_signed_without_recipient.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
305
|
-
assert response_valid_signed_without_recipient.is_valid?
|
306
|
-
assert_empty response_valid_signed_without_recipient.errors
|
307
|
-
end
|
308
|
-
|
309
|
-
it "return true when the response is initialized with valid data and using certificate instead of fingerprint" do
|
310
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
311
|
-
response_valid_signed_without_recipient.settings = settings
|
312
|
-
response_valid_signed_without_recipient.settings.idp_cert = ruby_saml_cert_text
|
313
|
-
assert response_valid_signed_without_recipient.is_valid?
|
314
|
-
assert_empty response_valid_signed_without_recipient.errors
|
315
|
-
end
|
316
|
-
|
317
|
-
it "return false when response is initialized with blank data" do
|
318
|
-
blank_response = OneLogin::RubySaml::Response.new('')
|
319
|
-
blank_response.soft = true
|
320
|
-
assert !blank_response.is_valid?
|
321
|
-
assert_includes blank_response.errors, "Blank response"
|
322
|
-
end
|
323
|
-
|
324
|
-
it "return false if settings have not been set" do
|
325
|
-
assert !response.is_valid?
|
326
|
-
assert_includes response.errors, "No settings on response"
|
327
|
-
end
|
328
|
-
|
329
|
-
it "return false if fingerprint or certificate not been set on settings" do
|
330
|
-
response.settings = settings
|
331
|
-
assert !response.is_valid?
|
332
|
-
assert_includes response.errors, "No fingerprint or certificate on settings"
|
333
|
-
end
|
334
|
-
|
335
|
-
it "should be idempotent when the response is initialized with invalid data" do
|
336
|
-
response_unsigned.stubs(:conditions).returns(nil)
|
337
|
-
response_unsigned.settings = settings
|
338
|
-
assert !response_unsigned.is_valid?
|
339
|
-
assert !response_unsigned.is_valid?
|
340
|
-
end
|
341
|
-
|
342
|
-
it "should be idempotent when the response is initialized with valid data" do
|
343
|
-
response_valid_signed_without_recipient.stubs(:conditions).returns(nil)
|
344
|
-
response_valid_signed_without_recipient.settings = settings
|
345
|
-
response_valid_signed_without_recipient.settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
346
|
-
assert response_valid_signed_without_recipient.is_valid?
|
347
|
-
assert response_valid_signed_without_recipient.is_valid?
|
348
|
-
end
|
349
|
-
|
350
|
-
it "not allow signature wrapping attack" do
|
351
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
352
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
353
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
354
|
-
response_wrapped.settings = settings
|
355
|
-
assert !response_wrapped.is_valid?
|
356
|
-
end
|
357
|
-
|
358
|
-
it "support dynamic namespace resolution on signature elements" do
|
359
|
-
no_signature_response = OneLogin::RubySaml::Response.new(fixture("no_signature_ns.xml"))
|
360
|
-
no_signature_response.stubs(:conditions).returns(nil)
|
361
|
-
no_signature_response.stubs(:validate_subject_confirmation).returns(true)
|
362
|
-
no_signature_response.settings = settings
|
363
|
-
no_signature_response.settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
364
|
-
XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
|
365
|
-
assert no_signature_response.is_valid?
|
366
|
-
end
|
367
|
-
|
368
|
-
it "validate ADFS assertions" do
|
369
|
-
adfs_response = OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
|
370
|
-
adfs_response.stubs(:conditions).returns(nil)
|
371
|
-
adfs_response.stubs(:validate_subject_confirmation).returns(true)
|
372
|
-
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
373
|
-
adfs_response.settings = settings
|
374
|
-
adfs_response.soft = true
|
375
|
-
assert adfs_response.is_valid?
|
376
|
-
end
|
377
|
-
|
378
|
-
it "validate SAML 2.0 XML structure" do
|
379
|
-
resp_xml = Base64.decode64(response_document_unsigned).gsub(/emailAddress/,'test')
|
380
|
-
response_unsigned_mod = OneLogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
381
|
-
response_unsigned_mod.stubs(:conditions).returns(nil)
|
382
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
383
|
-
response_unsigned_mod.settings = settings
|
384
|
-
response_unsigned_mod.soft = true
|
385
|
-
assert !response_unsigned_mod.is_valid?
|
386
|
-
end
|
387
|
-
|
388
|
-
it "return false when encountering a condition that prevents the document from being valid" do
|
389
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
390
|
-
response.settings = settings
|
391
|
-
error_msg = "Current time is on or after NotOnOrAfter condition"
|
392
|
-
assert !response.is_valid?
|
393
|
-
assert_includes response.errors[0], "Current time is on or after NotOnOrAfter condition"
|
394
|
-
end
|
395
|
-
|
396
|
-
it "return false when encountering a SAML Response with bad formatted" do
|
397
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
398
|
-
response_without_attributes.settings = settings
|
399
|
-
response_without_attributes.soft = true
|
400
|
-
error_msg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
401
|
-
response_without_attributes.is_valid?
|
402
|
-
assert_includes response_without_attributes.errors, error_msg
|
403
|
-
end
|
404
|
-
|
405
|
-
it "return false when the inResponseTo value does not match the Request ID" do
|
406
|
-
settings.soft = true
|
407
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
408
|
-
opts = {}
|
409
|
-
opts[:settings] = settings
|
410
|
-
opts[:matches_request_id] = "invalid_request_id"
|
411
|
-
response_valid_signed = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
412
|
-
response_valid_signed.is_valid?
|
413
|
-
assert_includes response_valid_signed.errors, "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
414
|
-
end
|
415
|
-
|
416
|
-
it "return false when there is no valid audience" do
|
417
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
418
|
-
settings.sp_entity_id = 'invalid'
|
419
|
-
response_valid_signed.settings = settings
|
420
|
-
response_valid_signed.is_valid?
|
421
|
-
|
422
|
-
assert_includes response_valid_signed.errors, generate_audience_error(response_valid_signed.settings.sp_entity_id, ['https://someone.example.com/audience'])
|
423
|
-
end
|
424
|
-
|
425
|
-
it "return false when no ID present in the SAML Response" do
|
426
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
427
|
-
response_no_id.settings = settings
|
428
|
-
response_no_id.soft = true
|
429
|
-
response_no_id.is_valid?
|
430
|
-
assert_includes response_no_id.errors, "Missing ID attribute on SAML Response"
|
431
|
-
end
|
432
|
-
|
433
|
-
it "return false when no 2.0 Version present in the SAML Response" do
|
434
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
435
|
-
response_no_version.settings = settings
|
436
|
-
response_no_version.soft = true
|
437
|
-
error_msg = "Unsupported SAML version"
|
438
|
-
response_no_version.is_valid?
|
439
|
-
assert_includes response_no_version.errors, "Unsupported SAML version"
|
440
|
-
end
|
441
|
-
|
442
|
-
it "return true when a nil URI is given in the ds:Reference" do
|
443
|
-
settings.idp_cert = ruby_saml_cert_text
|
444
|
-
settings.assertion_consumer_service_url = "http://localhost:9001/v1/users/authorize/saml"
|
445
|
-
response_without_reference_uri.settings = settings
|
446
|
-
response_without_reference_uri.stubs(:conditions).returns(nil)
|
447
|
-
response_without_reference_uri.is_valid?
|
448
|
-
assert_empty response_without_reference_uri.errors
|
449
|
-
assert 'saml@user.com', response_without_reference_uri.attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress']
|
450
|
-
end
|
451
|
-
|
452
|
-
it "collect errors when collect_errors=true" do
|
453
|
-
settings.idp_cert = ruby_saml_cert_text
|
454
|
-
settings.sp_entity_id = 'invalid'
|
455
|
-
response_invalid_subjectconfirmation_recipient.settings = settings
|
456
|
-
collect_errors = true
|
457
|
-
response_invalid_subjectconfirmation_recipient.is_valid?(collect_errors)
|
458
|
-
assert_includes response_invalid_subjectconfirmation_recipient.errors, generate_audience_error('invalid', ['http://stuff.com/endpoints/metadata.php'])
|
459
|
-
assert_includes response_invalid_subjectconfirmation_recipient.errors, "Invalid Signature on SAML Response"
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
describe "#validate_audience" do
|
465
|
-
it "return true when the audience is valid" do
|
466
|
-
response.settings = settings
|
467
|
-
response.settings.sp_entity_id = '{audience}'
|
468
|
-
assert response.send(:validate_audience)
|
469
|
-
assert_empty response.errors
|
470
|
-
end
|
471
|
-
|
472
|
-
it "return true when the audience is self closing" do
|
473
|
-
response_audience_self_closed.settings = settings
|
474
|
-
response_audience_self_closed.settings.sp_entity_id = '{audience}'
|
475
|
-
assert response_audience_self_closed.send(:validate_audience)
|
476
|
-
assert_empty response_audience_self_closed.errors
|
477
|
-
end
|
478
|
-
|
479
|
-
it "return false when the audience is valid" do
|
480
|
-
response.settings = settings
|
481
|
-
response.settings.sp_entity_id = 'invalid_audience'
|
482
|
-
assert !response.send(:validate_audience)
|
483
|
-
assert_includes response.errors, generate_audience_error(response.settings.sp_entity_id, ['{audience}'])
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
describe "#validate_destination" do
|
488
|
-
it "return true when the destination of the SAML Response matches the assertion consumer service url" do
|
489
|
-
response.settings = settings
|
490
|
-
assert response.send(:validate_destination)
|
491
|
-
assert_empty response.errors
|
492
|
-
end
|
493
|
-
|
494
|
-
it "return false when the destination of the SAML Response does not match the assertion consumer service url" do
|
495
|
-
response.settings = settings
|
496
|
-
response.settings.assertion_consumer_service_url = 'invalid_acs'
|
497
|
-
assert !response.send(:validate_destination)
|
498
|
-
assert_includes response.errors, "The response was received at #{response.destination} instead of #{response.settings.assertion_consumer_service_url}"
|
499
|
-
end
|
500
|
-
|
501
|
-
it "return false when the destination of the SAML Response is empty" do
|
502
|
-
response_empty_destination.settings = settings
|
503
|
-
assert !response_empty_destination.send(:validate_destination)
|
504
|
-
assert_includes response_empty_destination.errors, "The response has an empty Destination value"
|
505
|
-
end
|
506
|
-
|
507
|
-
it "return true when the destination of the SAML Response is empty but skip_destination option is used" do
|
508
|
-
response_empty_destination_with_skip.settings = settings
|
509
|
-
assert response_empty_destination_with_skip.send(:validate_destination)
|
510
|
-
assert_empty response_empty_destination.errors
|
511
|
-
end
|
512
|
-
|
513
|
-
it "returns true on a case insensitive match on the domain" do
|
514
|
-
response_valid_signed_without_x509certificate.settings = settings
|
515
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'http://APP.muDa.no/sso/consume'
|
516
|
-
assert response_valid_signed_without_x509certificate.send(:validate_destination)
|
517
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
518
|
-
end
|
519
|
-
|
520
|
-
it "returns true on a case insensitive match on the scheme" do
|
521
|
-
response_valid_signed_without_x509certificate.settings = settings
|
522
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'HTTP://app.muda.no/sso/consume'
|
523
|
-
assert response_valid_signed_without_x509certificate.send(:validate_destination)
|
524
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
525
|
-
end
|
526
|
-
|
527
|
-
it "returns false on a case insenstive match on the path" do
|
528
|
-
response_valid_signed_without_x509certificate.settings = settings
|
529
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'http://app.muda.no/SSO/consume'
|
530
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_destination)
|
531
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "The response was received at #{response_valid_signed_without_x509certificate.destination} instead of #{response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url}"
|
532
|
-
end
|
533
|
-
|
534
|
-
it "returns true if it can't parse out a full URI." do
|
535
|
-
response_valid_signed_without_x509certificate.settings = settings
|
536
|
-
response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url = 'presenter'
|
537
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_destination)
|
538
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "The response was received at #{response_valid_signed_without_x509certificate.destination} instead of #{response_valid_signed_without_x509certificate.settings.assertion_consumer_service_url}"
|
539
|
-
end
|
540
|
-
end
|
541
|
-
|
542
|
-
describe "#validate_issuer" do
|
543
|
-
it "return true when the issuer of the Message/Assertion matches the IdP entityId" do
|
544
|
-
response_valid_signed.settings = settings
|
545
|
-
assert response_valid_signed.send(:validate_issuer)
|
546
|
-
|
547
|
-
response_valid_signed.settings.idp_entity_id = 'https://app.onelogin.com/saml2'
|
548
|
-
assert response_valid_signed.send(:validate_issuer)
|
549
|
-
end
|
550
|
-
|
551
|
-
it "return false when the issuer of the Message does not match the IdP entityId" do
|
552
|
-
response_invalid_issuer_message.settings = settings
|
553
|
-
response_invalid_issuer_message.settings.idp_entity_id = 'http://idp.example.com/'
|
554
|
-
assert !response_invalid_issuer_message.send(:validate_issuer)
|
555
|
-
assert_includes response_invalid_issuer_message.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_message.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
556
|
-
end
|
557
|
-
|
558
|
-
it "return false when the issuer of the Assertion does not match the IdP entityId" do
|
559
|
-
response_invalid_issuer_assertion.settings = settings
|
560
|
-
response_invalid_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
561
|
-
assert !response_invalid_issuer_assertion.send(:validate_issuer)
|
562
|
-
assert_includes response_invalid_issuer_assertion.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_assertion.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
|
-
describe "#validate_num_assertion" do
|
567
|
-
it "return true when SAML Response contains 1 assertion" do
|
568
|
-
assert response.send(:validate_num_assertion)
|
569
|
-
assert_empty response.errors
|
570
|
-
end
|
571
|
-
|
572
|
-
it "return false when no 2.0 Version present in the SAML Response" do
|
573
|
-
assert !response_multi_assertion.send(:validate_num_assertion)
|
574
|
-
assert_includes response_multi_assertion.errors, "SAML Response must contain 1 assertion"
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
describe "validate_success_status" do
|
579
|
-
it "return true when the status is 'Success'" do
|
580
|
-
assert response.send(:validate_success_status)
|
581
|
-
assert_empty response.errors
|
582
|
-
end
|
583
|
-
|
584
|
-
it "return false when no Status provided" do
|
585
|
-
assert !response_no_status.send(:validate_success_status)
|
586
|
-
assert_includes response_no_status.errors, "The status code of the Response was not Success"
|
587
|
-
end
|
588
|
-
|
589
|
-
it "return false when no StatusCode provided" do
|
590
|
-
assert !response_no_statuscode.send(:validate_success_status)
|
591
|
-
assert_includes response_no_statuscode.errors, "The status code of the Response was not Success"
|
592
|
-
end
|
593
|
-
|
594
|
-
it "return false when the status is not 'Success'" do
|
595
|
-
assert !response_statuscode_responder.send(:validate_success_status)
|
596
|
-
assert_includes response_statuscode_responder.errors, "The status code of the Response was not Success, was Responder"
|
597
|
-
end
|
598
|
-
|
599
|
-
it "return false when the status is not 'Success', and shows the StatusMessage" do
|
600
|
-
assert !response_statuscode_responder_and_msg.send(:validate_success_status)
|
601
|
-
assert_includes response_statuscode_responder_and_msg.errors, "The status code of the Response was not Success, was Responder -> something_is_wrong"
|
602
|
-
end
|
603
|
-
|
604
|
-
it "return false when the status is not 'Success'" do
|
605
|
-
assert !response_double_statuscode.send(:validate_success_status)
|
606
|
-
assert_includes response_double_statuscode.errors, "The status code of the Response was not Success, was Requester => UnsupportedBinding"
|
607
|
-
end
|
608
|
-
end
|
609
|
-
|
610
|
-
describe "#validate_structure" do
|
611
|
-
it "return true when encountering a wellformed SAML Response" do
|
612
|
-
assert response.send(:validate_structure)
|
613
|
-
assert_empty response.errors
|
614
|
-
end
|
615
|
-
|
616
|
-
it "return false when encountering a mailformed element that prevents the document from being valid" do
|
617
|
-
response_without_attributes.soft = true
|
618
|
-
response_without_attributes.send(:validate_structure)
|
619
|
-
assert response_without_attributes.errors.include? "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"
|
620
|
-
end
|
621
|
-
|
622
|
-
it "raise when encountering a mailformed element that prevents the document from being valid" do
|
623
|
-
response_without_attributes.soft = false
|
624
|
-
assert_raises(OneLogin::RubySaml::ValidationError) {
|
625
|
-
response_without_attributes.send(:validate_structure)
|
626
|
-
}
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
describe "validate_formatted_x509_certificate" do
|
631
|
-
let(:response_with_formatted_x509certificate) {
|
632
|
-
OneLogin::RubySaml::Response.new(read_response("valid_response_with_formatted_x509certificate.xml.base64"), {
|
633
|
-
:skip_conditions => true,
|
634
|
-
:skip_subject_confirmation => true })
|
635
|
-
}
|
636
|
-
|
637
|
-
it "be able to parse the response wihout errors" do
|
638
|
-
response_with_formatted_x509certificate.settings = settings
|
639
|
-
response_with_formatted_x509certificate.settings.idp_cert = ruby_saml_cert_text
|
640
|
-
assert response_with_formatted_x509certificate.is_valid?
|
641
|
-
assert_empty response_with_formatted_x509certificate.errors
|
642
|
-
end
|
643
|
-
end
|
644
|
-
|
645
|
-
describe "#validate_in_response_to" do
|
646
|
-
it "return true when the inResponseTo value matches the Request ID" do
|
647
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings, :matches_request_id => "_fc4a34b0-7efb-012e-caae-782bcb13bb38")
|
648
|
-
assert response.send(:validate_in_response_to)
|
649
|
-
assert_empty response.errors
|
650
|
-
end
|
651
|
-
|
652
|
-
it "return true when no Request ID is provided for checking" do
|
653
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings)
|
654
|
-
assert response.send(:validate_in_response_to)
|
655
|
-
assert_empty response.errors
|
656
|
-
end
|
657
|
-
|
658
|
-
it "return false when the inResponseTo value does not match the Request ID" do
|
659
|
-
response = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings, :matches_request_id => "invalid_request_id")
|
660
|
-
assert !response.send(:validate_in_response_to)
|
661
|
-
assert_includes response.errors, "The InResponseTo of the Response: _fc4a34b0-7efb-012e-caae-782bcb13bb38, does not match the ID of the AuthNRequest sent by the SP: invalid_request_id"
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
665
|
-
describe "#validate_audience" do
|
666
|
-
it "return true when the audience is valid" do
|
667
|
-
response_valid_signed.settings = settings
|
668
|
-
response_valid_signed.settings.sp_entity_id = "https://someone.example.com/audience"
|
669
|
-
assert response_valid_signed.send(:validate_audience)
|
670
|
-
assert_empty response_valid_signed.errors
|
671
|
-
end
|
672
|
-
|
673
|
-
it "return true when there is not sp_entity_id defined" do
|
674
|
-
response_valid_signed.settings = settings
|
675
|
-
response_valid_signed.settings.sp_entity_id = nil
|
676
|
-
assert response_valid_signed.send(:validate_audience)
|
677
|
-
assert_empty response_valid_signed.errors
|
678
|
-
end
|
679
|
-
|
680
|
-
it "return false when there is no valid audience" do
|
681
|
-
response_invalid_audience.settings = settings
|
682
|
-
response_invalid_audience.settings.sp_entity_id = "https://invalid.example.com/audience"
|
683
|
-
assert !response_invalid_audience.send(:validate_audience)
|
684
|
-
assert_includes response_invalid_audience.errors, generate_audience_error(response_invalid_audience.settings.sp_entity_id, ['http://invalid.audience.com'])
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
describe "#validate_issuer" do
|
689
|
-
it "return true when the issuer of the Message/Assertion matches the IdP entityId or it was empty" do
|
690
|
-
response_valid_signed.settings = settings
|
691
|
-
assert response_valid_signed.send(:validate_issuer)
|
692
|
-
assert_empty response_valid_signed.errors
|
693
|
-
|
694
|
-
response_valid_signed.settings.idp_entity_id = 'https://app.onelogin.com/saml2'
|
695
|
-
assert response_valid_signed.send(:validate_issuer)
|
696
|
-
assert_empty response_valid_signed.errors
|
697
|
-
end
|
698
|
-
|
699
|
-
it "return false when the issuer of the Message does not match the IdP entityId" do
|
700
|
-
response_invalid_issuer_message.settings = settings
|
701
|
-
response_invalid_issuer_message.settings.idp_entity_id = 'http://idp.example.com/'
|
702
|
-
assert !response_invalid_issuer_message.send(:validate_issuer)
|
703
|
-
assert_includes response_invalid_issuer_message.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_message.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
704
|
-
end
|
705
|
-
|
706
|
-
it "return false when the issuer of the Assertion does not match the IdP entityId" do
|
707
|
-
response_invalid_issuer_assertion.settings = settings
|
708
|
-
response_invalid_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
709
|
-
assert !response_invalid_issuer_assertion.send(:validate_issuer)
|
710
|
-
assert_includes response_invalid_issuer_assertion.errors, "Doesn't match the issuer, expected: <#{response_invalid_issuer_assertion.settings.idp_entity_id}>, but was: <http://invalid.issuer.example.com/>"
|
711
|
-
end
|
712
|
-
|
713
|
-
it "return false when the no issuer at the Response" do
|
714
|
-
response_no_issuer_response.settings = settings
|
715
|
-
response_no_issuer_response.settings.idp_entity_id = 'http://idp.example.com/'
|
716
|
-
assert !response_no_issuer_response.send(:validate_issuer)
|
717
|
-
assert_includes response_no_issuer_response.errors, "Issuer of the Response not found or multiple."
|
718
|
-
end
|
719
|
-
|
720
|
-
it "return false when the no issuer at the Assertion" do
|
721
|
-
response_no_issuer_assertion.settings = settings
|
722
|
-
response_no_issuer_assertion.settings.idp_entity_id = 'http://idp.example.com/'
|
723
|
-
assert !response_no_issuer_assertion.send(:validate_issuer)
|
724
|
-
assert_includes response_no_issuer_assertion.errors, "Issuer of the Assertion not found or multiple."
|
725
|
-
end
|
726
|
-
end
|
727
|
-
|
728
|
-
describe "#validate_subject_confirmation" do
|
729
|
-
it "return true when valid subject confirmation" do
|
730
|
-
response_valid_signed.settings = settings
|
731
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'recipient'
|
732
|
-
assert response_valid_signed.send(:validate_subject_confirmation)
|
733
|
-
assert_empty response_valid_signed.errors
|
734
|
-
end
|
735
|
-
|
736
|
-
it "return false when no subject confirmation data" do
|
737
|
-
response_no_subjectconfirmation_data.settings = settings
|
738
|
-
assert !response_no_subjectconfirmation_data.send(:validate_subject_confirmation)
|
739
|
-
assert_includes response_no_subjectconfirmation_data.errors, "A valid SubjectConfirmation was not found on this Response"
|
740
|
-
end
|
741
|
-
|
742
|
-
it "return false when no valid subject confirmation method" do
|
743
|
-
response_no_subjectconfirmation_method.settings = settings
|
744
|
-
assert !response_no_subjectconfirmation_method.send(:validate_subject_confirmation)
|
745
|
-
assert_includes response_no_subjectconfirmation_method.errors, "A valid SubjectConfirmation was not found on this Response"
|
746
|
-
end
|
747
|
-
|
748
|
-
it "return false when invalid inresponse" do
|
749
|
-
response_invalid_subjectconfirmation_inresponse.settings = settings
|
750
|
-
assert !response_invalid_subjectconfirmation_inresponse.send(:validate_subject_confirmation)
|
751
|
-
assert_includes response_invalid_subjectconfirmation_inresponse.errors, "A valid SubjectConfirmation was not found on this Response"
|
752
|
-
end
|
753
|
-
|
754
|
-
it "return false when invalid NotBefore" do
|
755
|
-
response_invalid_subjectconfirmation_nb.settings = settings
|
756
|
-
assert !response_invalid_subjectconfirmation_nb.send(:validate_subject_confirmation)
|
757
|
-
assert_includes response_invalid_subjectconfirmation_nb.errors, "A valid SubjectConfirmation was not found on this Response"
|
758
|
-
end
|
759
|
-
|
760
|
-
it "return false when invalid NotOnOrAfter" do
|
761
|
-
response_invalid_subjectconfirmation_noa.settings = settings
|
762
|
-
assert !response_invalid_subjectconfirmation_noa.send(:validate_subject_confirmation)
|
763
|
-
assert_includes response_invalid_subjectconfirmation_noa.errors, "A valid SubjectConfirmation was not found on this Response"
|
764
|
-
end
|
765
|
-
|
766
|
-
it "return true when valid subject confirmation recipient" do
|
767
|
-
response_valid_signed.settings = settings
|
768
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'recipient'
|
769
|
-
assert response_valid_signed.send(:validate_subject_confirmation)
|
770
|
-
assert_empty response_valid_signed.errors
|
771
|
-
assert_empty response_valid_signed.errors
|
772
|
-
end
|
773
|
-
|
774
|
-
it "return false when invalid subject confirmation recipient" do
|
775
|
-
response_valid_signed.settings = settings
|
776
|
-
response_valid_signed.settings.assertion_consumer_service_url = 'not-the-recipient'
|
777
|
-
assert !response_valid_signed.send(:validate_subject_confirmation)
|
778
|
-
assert_includes response_valid_signed.errors, "A valid SubjectConfirmation was not found on this Response"
|
779
|
-
end
|
780
|
-
|
781
|
-
it "return false when invalid subject confirmation recipient, but skipping the check(default)" do
|
782
|
-
response_valid_signed_without_recipient.settings = settings
|
783
|
-
response_valid_signed_without_recipient.settings.assertion_consumer_service_url = 'not-the-recipient'
|
784
|
-
assert response_valid_signed_without_recipient.send(:validate_subject_confirmation)
|
785
|
-
assert_empty response_valid_signed_without_recipient.errors
|
786
|
-
end
|
787
|
-
|
788
|
-
it "return true when the skip_subject_confirmation option is passed and the subject confirmation is valid" do
|
789
|
-
opts = {}
|
790
|
-
opts[:skip_subject_confirmation] = true
|
791
|
-
response_with_skip = OneLogin::RubySaml::Response.new(response_document_valid_signed, opts)
|
792
|
-
response_with_skip.settings = settings
|
793
|
-
response_with_skip.settings.assertion_consumer_service_url = 'recipient'
|
794
|
-
Time.expects(:now).times(0) # ensures the test isn't run and thus Time.now.utc is never called within the test
|
795
|
-
assert response_with_skip.send(:validate_subject_confirmation)
|
796
|
-
assert_empty response_with_skip.errors
|
797
|
-
end
|
798
|
-
|
799
|
-
it "return true when the skip_subject_confirmation option is passed and the response has an invalid subject confirmation" do
|
800
|
-
opts = {}
|
801
|
-
opts[:skip_subject_confirmation] = true
|
802
|
-
response_with_skip = OneLogin::RubySaml::Response.new(read_invalid_response("invalid_subjectconfirmation_noa.xml.base64"), opts)
|
803
|
-
response_with_skip.settings = settings
|
804
|
-
Time.expects(:now).times(0) # ensures the test isn't run and thus Time.now.utc is never called within the test
|
805
|
-
assert response_with_skip.send(:validate_subject_confirmation)
|
806
|
-
assert_empty response_with_skip.errors
|
807
|
-
end
|
808
|
-
end
|
809
|
-
|
810
|
-
describe "#validate_session_expiration" do
|
811
|
-
it "return true when the session has not expired" do
|
812
|
-
response_valid_signed.settings = settings
|
813
|
-
assert response_valid_signed.send(:validate_session_expiration)
|
814
|
-
assert_empty response_valid_signed.errors
|
815
|
-
end
|
816
|
-
|
817
|
-
it "return false when the session has expired" do
|
818
|
-
response.settings = settings
|
819
|
-
assert !response.send(:validate_session_expiration)
|
820
|
-
assert_includes response.errors, "The attributes have expired, based on the SessionNotOnOrAfter of the AuthnStatement of this Response"
|
821
|
-
end
|
822
|
-
|
823
|
-
it "returns true when the session has expired, but is still within the allowed_clock_drift" do
|
824
|
-
drift = (Time.now - Time.parse("2010-11-19T21:57:37Z")) * 60 # seconds ago that this assertion expired
|
825
|
-
drift += 10 # add a buffer of 10 seconds to make sure the test passes
|
826
|
-
opts = {}
|
827
|
-
opts[:allowed_clock_drift] = drift
|
828
|
-
|
829
|
-
response_with_drift = OneLogin::RubySaml::Response.new(response_document_without_recipient, opts)
|
830
|
-
response_with_drift.settings = settings
|
831
|
-
assert response_with_drift.send(:validate_session_expiration)
|
832
|
-
assert_empty response_with_drift.errors
|
833
|
-
end
|
834
|
-
end
|
835
|
-
|
836
|
-
describe "#validate_signature" do
|
837
|
-
it "return true when the signature is valid" do
|
838
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
839
|
-
response_valid_signed.settings = settings
|
840
|
-
assert response_valid_signed.send(:validate_signature)
|
841
|
-
assert_empty response_valid_signed.errors
|
842
|
-
end
|
843
|
-
|
844
|
-
it "return true when the signature is valid and ds namespace is at the root" do
|
845
|
-
settings.idp_cert_fingerprint = '5614657ab692b960480389723a36446a5fe1f7ec'
|
846
|
-
response_with_ds_namespace_at_the_root.settings = settings
|
847
|
-
assert response_with_ds_namespace_at_the_root.send(:validate_signature)
|
848
|
-
assert_empty response_with_ds_namespace_at_the_root.errors
|
849
|
-
end
|
850
|
-
|
851
|
-
it "return true when the signature is valid and fingerprint provided" do
|
852
|
-
settings.idp_cert_fingerprint = '49:EC:3F:A4:71:8A:1E:C9:DB:70:A7:CC:33:36:96:F0:48:8C:4E:DA'
|
853
|
-
xml = 'PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERlc3RpbmF0aW9uPSJodHRwczovL2NvZGVycGFkLmlvL3NhbWwvYWNzIiBJRD0iXzEwOGE1ZTg0MDllYzRjZjlhY2QxYzQ2OWU5ZDcxNGFkIiBJblJlc3BvbnNlVG89Il80ZmZmYWE2MC02OTZiLTAxMzMtMzg4Ni0wMjQxZjY1YzA2OTMiIElzc3VlSW5zdGFudD0iMjAxNS0xMS0wOVQyMzo1NTo0M1oiIFZlcnNpb249IjIuMCI+PHNhbWw6SXNzdWVyIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHBzOi8vbG9naW4uaHVsdS5jb208L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj48L2RzOkNhbm9uaWNhbGl6YXRpb25NZXRob2Q+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSI+PC9kczpTaWduYXR1cmVNZXRob2Q+PGRzOlJlZmVyZW5jZSBVUkk9IiNfMTA4YTVlODQwOWVjNGNmOWFjZDFjNDY5ZTlkNzE0YWQiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSI+PC9kczpUcmFuc2Zvcm0+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyI+PC9kczpUcmFuc2Zvcm0+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSI+PC9kczpEaWdlc3RNZXRob2Q+PGRzOkRpZ2VzdFZhbHVlPm9sQllXbTQyRi9oZm0xdHJYTHk2a3V6MXlMUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+dXNRTmY5WGpKTDRlOXVucnVCdWViSnQ3R0tXM2hJUk9teWVqTm1NMHM4WFhlWHN3WHc4U3ZCZi8zeDNNWEpkWnpNV0pOM3ExN2tGWHN2bTVna1JzbkE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJQ1FEQ0NBZXFnQXdJQkFnSUpBSVZOdzVLRzR1aTFNQTBHQ1NxR1NJYjNEUUVCQlFVQU1Fd3hDekFKQmdOVkJBWVRBa2RDTVJJd0VBWURWUVFJRXdsQ1pYSnJjMmhwY21VeEVEQU9CZ05WQkFjVEIwNWxkMkoxY25reEZ6QVZCZ05WQkFvVERrMTVJRU52YlhCaGJua2dUSFJrTUI0WERURXlNVEF5TlRBMk1qY3pORm9YRFRJeU1UQXlNekEyTWpjek5Gb3dUREVMTUFrR0ExVUVCaE1DUjBJeEVqQVFCZ05WQkFnVENVSmxjbXR6YUdseVpURVFNQTRHQTFVRUJ4TUhUbVYzWW5WeWVURVhNQlVHQTFVRUNoTU9UWGtnUTI5dGNHRnVlU0JNZEdRd1hEQU5CZ2txaGtpRzl3MEJBUUVGQUFOTEFEQklBa0VBd1NOL2dpMzNSbXBBUW9MUWo3UDZ6QW5OVDBSbjdiakMzMjNuM3ExT25mdm52UjBmUWp2TnQ3ckRrQTVBdjVRbk02VjRZVU5Vbk1mYk9RcTBXTGJMU3dJREFRQUJvNEd1TUlHck1CMEdBMVVkRGdRV0JCUWZJSDFvZkJWcHNSQWNJTUsyaGJsN25nTVRZREI4QmdOVkhTTUVkVEJ6Z0JRZklIMW9mQlZwc1JBY0lNSzJoYmw3bmdNVFlLRlFwRTR3VERFTE1Ba0dBMVVFQmhNQ1IwSXhFakFRQmdOVkJBZ1RDVUpsY210emFHbHlaVEVRTUE0R0ExVUVCeE1IVG1WM1luVnllVEVYTUJVR0ExVUVDaE1PVFhrZ1EyOXRjR0Z1ZVNCTWRHU0NDUUNGVGNPU2h1TG90VEFNQmdOVkhSTUVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJCUVVBQTBFQXFvZ1YzdVBjbEtYRG1EWk1UN3ZsUFl4TEFxQ0dIWnRsQ3h6NGhNNEtTdGxEMi9HTmMxWGlMYjFoL0swQ0pMRG9zckVJYm0zd2lPMk12VEVSclZZU01RPT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiPjwvc2FtbHA6U3RhdHVzQ29kZT48L3NhbWxwOlN0YXR1cz48c2FtbDpBc3NlcnRpb24geG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9Il8wMTg4MmRhOTM2OTQ0ZDFlYTZlZmY0NDA2NTc2MzFiNSIgSXNzdWVJbnN0YW50PSIyMDE1LTExLTA5VDIzOjU1OjQzWiIgVmVyc2lvbj0iMi4wIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9sb2dpbi5odWx1LmNvbTwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+PGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiPjwvZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZD48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3JzYS1zaGExIj48L2RzOlNpZ25hdHVyZU1ldGhvZD48ZHM6UmVmZXJlbmNlIFVSST0iI18wMTg4MmRhOTM2OTQ0ZDFlYTZlZmY0NDA2NTc2MzFiNSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIj48L2RzOlRyYW5zZm9ybT48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj48L2RzOlRyYW5zZm9ybT48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIj48L2RzOkRpZ2VzdE1ldGhvZD48ZHM6RGlnZXN0VmFsdWU+cmo2YzhucC9BUmV0ZkJ1dWVOSzNPS0xDYnowPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5hR05FemZHM1dLcExKc2ZLRGJSNmpva2d6OEFnZ0FIRVVESEZyd0dsTHVQeWpyNEl3M09NcFNkV2gyL01YK1F3M1dPTk5mNHJNalh5TGVZSFJIVGpMQT09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDUURDQ0FlcWdBd0lCQWdJSkFJVk53NUtHNHVpMU1BMEdDU3FHU0liM0RRRUJCUVVBTUV3eEN6QUpCZ05WQkFZVEFrZENNUkl3RUFZRFZRUUlFd2xDWlhKcmMyaHBjbVV4RURBT0JnTlZCQWNUQjA1bGQySjFjbmt4RnpBVkJnTlZCQW9URGsxNUlFTnZiWEJoYm5rZ1RIUmtNQjRYRFRFeU1UQXlOVEEyTWpjek5Gb1hEVEl5TVRBeU16QTJNamN6TkZvd1RERUxNQWtHQTFVRUJoTUNSMEl4RWpBUUJnTlZCQWdUQ1VKbGNtdHphR2x5WlRFUU1BNEdBMVVFQnhNSFRtVjNZblZ5ZVRFWE1CVUdBMVVFQ2hNT1RYa2dRMjl0Y0dGdWVTQk1kR1F3WERBTkJna3Foa2lHOXcwQkFRRUZBQU5MQURCSUFrRUF3U04vZ2kzM1JtcEFRb0xRajdQNnpBbk5UMFJuN2JqQzMyM24zcTFPbmZ2bnZSMGZRanZOdDdyRGtBNUF2NVFuTTZWNFlVTlVuTWZiT1FxMFdMYkxTd0lEQVFBQm80R3VNSUdyTUIwR0ExVWREZ1FXQkJRZklIMW9mQlZwc1JBY0lNSzJoYmw3bmdNVFlEQjhCZ05WSFNNRWRUQnpnQlFmSUgxb2ZCVnBzUkFjSU1LMmhibDduZ01UWUtGUXBFNHdUREVMTUFrR0ExVUVCaE1DUjBJeEVqQVFCZ05WQkFnVENVSmxjbXR6YUdseVpURVFNQTRHQTFVRUJ4TUhUbVYzWW5WeWVURVhNQlVHQTFVRUNoTU9UWGtnUTI5dGNHRnVlU0JNZEdTQ0NRQ0ZUY09TaHVMb3RUQU1CZ05WSFJNRUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkJRVUFBMEVBcW9nVjN1UGNsS1hEbURaTVQ3dmxQWXhMQXFDR0hadGxDeHo0aE00S1N0bEQyL0dOYzFYaUxiMWgvSzBDSkxEb3NyRUlibTN3aU8yTXZURVJyVllTTVE9PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sOlN1YmplY3Q+PHNhbWw6TmFtZUlEIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzIiBTUE5hbWVRdWFsaWZpZXI9Imh0dHBzOi8vY29kZXJwYWQuaW8iPm1hdHQuanVyaWtAaHVsdS5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBJblJlc3BvbnNlVG89Il80ZmZmYWE2MC02OTZiLTAxMzMtMzg4Ni0wMjQxZjY1YzA2OTMiIE5vdE9uT3JBZnRlcj0iMjAxNS0xMS0xMFQwMDoxMDo0M1oiIFJlY2lwaWVudD0iaHR0cHM6Ly9jb2RlcnBhZC5pby9zYW1sL2FjcyI+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb25EYXRhPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDE1LTExLTA5VDIyOjU1OjQzWiIgTm90T25PckFmdGVyPSIyMDE1LTExLTEwVDAwOjEwOjQzWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL2NvZGVycGFkLmlvPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNS0xMS0wOVQyMzo1NTo0M1oiPjxzYW1sOkF1dGhuQ29udGV4dD48c2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZDwvc2FtbDpBdXRobkNvbnRleHRDbGFzc1JlZj48L3NhbWw6QXV0aG5Db250ZXh0Pjwvc2FtbDpBdXRoblN0YXRlbWVudD48c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlIE5hbWU9IkdpdmVuLW5hbWUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPk1hdHQ8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iU3VybmFtZSI+PHNhbWw6QXR0cmlidXRlVmFsdWU+SnVyaWs8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iRW1haWwiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPm1hdHQuanVyaWtAaHVsdS5jb208L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50Pjwvc2FtbDpBc3NlcnRpb24+PC9zYW1scDpSZXNwb25zZT4='
|
854
|
-
response_x = OneLogin::RubySaml::Response.new(xml)
|
855
|
-
response_x.settings = settings
|
856
|
-
assert response_x.send(:validate_signature)
|
857
|
-
assert_empty response_x.errors
|
858
|
-
end
|
859
|
-
|
860
|
-
it "return false when no fingerprint" do
|
861
|
-
settings.idp_cert_fingerprint = nil
|
862
|
-
settings.idp_cert = nil
|
863
|
-
response.settings = settings
|
864
|
-
assert !response.send(:validate_signature)
|
865
|
-
assert_includes response.errors, "Invalid Signature on SAML Response"
|
866
|
-
end
|
867
|
-
|
868
|
-
it "return false when the signature is invalid" do
|
869
|
-
settings.idp_cert_fingerprint = signature_fingerprint_1
|
870
|
-
response.settings = settings
|
871
|
-
assert !response.send(:validate_signature)
|
872
|
-
assert_includes response.errors, "Invalid Signature on SAML Response"
|
873
|
-
end
|
874
|
-
|
875
|
-
it "return false when no X509Certificate and not cert provided at settings" do
|
876
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
877
|
-
settings.idp_cert = nil
|
878
|
-
response_valid_signed_without_x509certificate.settings = settings
|
879
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_signature)
|
880
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "Invalid Signature on SAML Response"
|
881
|
-
end
|
882
|
-
|
883
|
-
it "return false when cert expired and check_idp_cert_expiration enabled" do
|
884
|
-
settings.idp_cert_fingerprint = nil
|
885
|
-
settings.idp_cert = ruby_saml_cert_text
|
886
|
-
settings.security[:check_idp_cert_expiration] = true
|
887
|
-
response_valid_signed.settings = settings
|
888
|
-
assert !response_valid_signed.send(:validate_signature)
|
889
|
-
assert_includes response_valid_signed.errors, "IdP x509 certificate expired"
|
890
|
-
end
|
891
|
-
|
892
|
-
it "return false when no X509Certificate and the cert provided at settings mismatches" do
|
893
|
-
settings.idp_cert_fingerprint = nil
|
894
|
-
settings.idp_cert = signature_1
|
895
|
-
response_valid_signed_without_x509certificate.settings = settings
|
896
|
-
assert !response_valid_signed_without_x509certificate.send(:validate_signature)
|
897
|
-
assert_includes response_valid_signed_without_x509certificate.errors, "Invalid Signature on SAML Response"
|
898
|
-
end
|
899
|
-
|
900
|
-
it "return true when no X509Certificate and the cert provided at settings matches" do
|
901
|
-
settings.idp_cert_fingerprint = nil
|
902
|
-
settings.idp_cert = ruby_saml_cert_text
|
903
|
-
response_valid_signed_without_x509certificate.settings = settings
|
904
|
-
assert response_valid_signed_without_x509certificate.send(:validate_signature)
|
905
|
-
assert_empty response_valid_signed_without_x509certificate.errors
|
906
|
-
end
|
907
|
-
|
908
|
-
it "return false when signature wrapping attack" do
|
909
|
-
signature_wrapping_attack = read_invalid_response("signature_wrapping_attack.xml.base64")
|
910
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack)
|
911
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
912
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
913
|
-
settings.idp_cert_fingerprint = "afe71c28ef740bc87425be13a2263d37971da1f9"
|
914
|
-
response_wrapped.settings = settings
|
915
|
-
assert !response_wrapped.send(:validate_signature)
|
916
|
-
assert_includes response_wrapped.errors, "Invalid Signature on SAML Response"
|
917
|
-
assert_includes response_wrapped.errors, "Signed element id #pfxc3d2b542-0f7e-8767-8e87-5b0dc6913375 is not found"
|
918
|
-
end
|
919
|
-
end
|
920
|
-
|
921
|
-
describe "#validate_signature with multiple idp certs" do
|
922
|
-
it "return true when at least a cert on idp_cert_multi is valid" do
|
923
|
-
settings.idp_cert_multi = {
|
924
|
-
:signing => [ruby_saml_cert_text2, ruby_saml_cert_text],
|
925
|
-
:encryption => []
|
926
|
-
}
|
927
|
-
response_valid_signed.settings = settings
|
928
|
-
assert response_valid_signed.send(:validate_signature)
|
929
|
-
assert_empty response_valid_signed.errors
|
930
|
-
end
|
931
|
-
|
932
|
-
it "return false when none cert on idp_cert_multi is valid" do
|
933
|
-
settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
|
934
|
-
settings.idp_cert_multi = {
|
935
|
-
:signing => [ruby_saml_cert_text2, ruby_saml_cert_text2],
|
936
|
-
:encryption => []
|
937
|
-
}
|
938
|
-
response_valid_signed.settings = settings
|
939
|
-
assert !response_valid_signed.send(:validate_signature)
|
940
|
-
assert_includes response_valid_signed.errors, "Invalid Signature on SAML Response"
|
941
|
-
end
|
942
|
-
end
|
943
|
-
|
944
|
-
describe "#validate nameid" do
|
945
|
-
it "return false when no nameid element and required by settings" do
|
946
|
-
settings.security[:want_name_id] = true
|
947
|
-
response_no_nameid.settings = settings
|
948
|
-
assert !response_no_nameid.send(:validate_name_id)
|
949
|
-
assert_includes response_no_nameid.errors, "No NameID element found in the assertion of the Response"
|
950
|
-
end
|
951
|
-
|
952
|
-
it "return false when no nameid element and required by settings" do
|
953
|
-
response_empty_nameid.settings = settings
|
954
|
-
assert !response_empty_nameid.send(:validate_name_id)
|
955
|
-
assert_includes response_empty_nameid.errors, "An empty NameID value found"
|
956
|
-
end
|
957
|
-
|
958
|
-
it "return false when no nameid value" do
|
959
|
-
response_empty_nameid.settings = settings
|
960
|
-
assert !response_empty_nameid.send(:validate_name_id)
|
961
|
-
assert_includes response_empty_nameid.errors, "An empty NameID value found"
|
962
|
-
end
|
963
|
-
|
964
|
-
it "return false when wrong_spnamequalifier" do
|
965
|
-
settings.sp_entity_id = 'sp_entity_id'
|
966
|
-
response_wrong_spnamequalifier.settings = settings
|
967
|
-
assert !response_wrong_spnamequalifier.send(:validate_name_id)
|
968
|
-
assert_includes response_wrong_spnamequalifier.errors, "The SPNameQualifier value mistmatch the SP entityID value."
|
969
|
-
end
|
970
|
-
|
971
|
-
it "return true when no nameid element but not required by settings" do
|
972
|
-
settings.security[:want_name_id] = false
|
973
|
-
response_no_nameid.settings = settings
|
974
|
-
assert response_no_nameid.send(:validate_name_id)
|
975
|
-
end
|
976
|
-
|
977
|
-
it "return true when nameid is valid and response_wrong_spnamequalifier matches the SP issuer" do
|
978
|
-
settings.sp_entity_id = 'wrong-sp-entityid'
|
979
|
-
response_wrong_spnamequalifier.settings = settings
|
980
|
-
assert response_wrong_spnamequalifier.send(:validate_name_id)
|
981
|
-
end
|
982
|
-
end
|
983
|
-
|
984
|
-
describe "#nameid" do
|
985
|
-
it "extract the value of the name id element" do
|
986
|
-
assert_equal "support@onelogin.com", response.nameid
|
987
|
-
assert_equal "someone@example.com", response_with_signed_assertion.nameid
|
988
|
-
end
|
989
|
-
|
990
|
-
it "be extractable from an OpenSAML response" do
|
991
|
-
response_open_saml = OneLogin::RubySaml::Response.new(fixture(:open_saml))
|
992
|
-
assert_equal "someone@example.org", response_open_saml.nameid
|
993
|
-
end
|
994
|
-
|
995
|
-
it "be extractable from a Simple SAML PHP response" do
|
996
|
-
response_ssp = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
997
|
-
assert_equal "someone@example.com", response_ssp.nameid
|
998
|
-
end
|
999
|
-
end
|
1000
|
-
|
1001
|
-
describe "#name_id_format" do
|
1002
|
-
it "extract the value of the name id element" do
|
1003
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response.name_id_format
|
1004
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_with_signed_assertion.name_id_format
|
1005
|
-
end
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
describe "#sessionindex" do
|
1009
|
-
it "extract the value of the sessionindex element" do
|
1010
|
-
response = OneLogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
1011
|
-
assert_equal "_51be37965feb5579d803141076936dc2e9d1d98ebf", response.sessionindex
|
1012
|
-
end
|
1013
|
-
end
|
1014
|
-
|
1015
|
-
describe "#check_one_conditions" do
|
1016
|
-
it "return false when none or more than one conditions element" do
|
1017
|
-
response_no_conditions.soft = true
|
1018
|
-
assert !response_no_conditions.send(:validate_one_conditions)
|
1019
|
-
assert_includes response_no_conditions.errors, "The Assertion must include one Conditions element"
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
it "return true when one conditions element" do
|
1023
|
-
response.soft = true
|
1024
|
-
assert response.send(:validate_one_conditions)
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
it "return true when no conditions are present and skip_conditions is true" do
|
1028
|
-
response_no_conditions_with_skip.soft = true
|
1029
|
-
assert response_no_conditions_with_skip.send(:validate_one_conditions)
|
1030
|
-
end
|
1031
|
-
end
|
1032
|
-
|
1033
|
-
describe "#check_one_authnstatement" do
|
1034
|
-
it "return false when none or more than one authnstatement element" do
|
1035
|
-
response_no_authnstatement.soft = true
|
1036
|
-
assert !response_no_authnstatement.send(:validate_one_authnstatement)
|
1037
|
-
assert_includes response_no_authnstatement.errors, "The Assertion must include one AuthnStatement element"
|
1038
|
-
end
|
1039
|
-
|
1040
|
-
it "return true when one authnstatement element" do
|
1041
|
-
response.soft = true
|
1042
|
-
assert response.send(:validate_one_authnstatement)
|
1043
|
-
end
|
1044
|
-
|
1045
|
-
it "return true when SAML Response is empty but skip_authstatement option is used" do
|
1046
|
-
response_no_authnstatement_with_skip.soft = true
|
1047
|
-
assert response_no_authnstatement_with_skip.send(:validate_one_authnstatement)
|
1048
|
-
assert_empty response_empty_destination_with_skip.errors
|
1049
|
-
end
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
describe "#check_conditions" do
|
1053
|
-
it "check time conditions" do
|
1054
|
-
response.soft = true
|
1055
|
-
assert !response.send(:validate_conditions)
|
1056
|
-
response_time_updated = OneLogin::RubySaml::Response.new(response_document_without_recipient_with_time_updated)
|
1057
|
-
response_time_updated.soft = true
|
1058
|
-
assert response_time_updated.send(:validate_conditions)
|
1059
|
-
Timecop.freeze(Time.parse("2011-06-14T18:25:01.516Z")) do
|
1060
|
-
response_with_saml2_namespace = OneLogin::RubySaml::Response.new(response_document_with_saml2_namespace)
|
1061
|
-
response_with_saml2_namespace.soft = true
|
1062
|
-
assert response_with_saml2_namespace.send(:validate_conditions)
|
1063
|
-
end
|
1064
|
-
end
|
1065
|
-
|
1066
|
-
it "optionally allows for clock drift" do
|
1067
|
-
# The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
|
1068
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1069
|
-
settings.soft = true
|
1070
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1071
|
-
response_document_with_saml2_namespace,
|
1072
|
-
:allowed_clock_drift => 0.515,
|
1073
|
-
:settings => settings
|
1074
|
-
)
|
1075
|
-
assert !special_response_with_saml2_namespace.send(:validate_conditions)
|
1076
|
-
end
|
1077
|
-
|
1078
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1079
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1080
|
-
response_document_with_saml2_namespace,
|
1081
|
-
:allowed_clock_drift => 0.516
|
1082
|
-
)
|
1083
|
-
assert special_response_with_saml2_namespace.send(:validate_conditions)
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1087
|
-
settings.soft = true
|
1088
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1089
|
-
response_document_with_saml2_namespace,
|
1090
|
-
:allowed_clock_drift => '0.515',
|
1091
|
-
:settings => settings
|
1092
|
-
)
|
1093
|
-
assert !special_response_with_saml2_namespace.send(:validate_conditions)
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
|
1097
|
-
special_response_with_saml2_namespace = OneLogin::RubySaml::Response.new(
|
1098
|
-
response_document_with_saml2_namespace,
|
1099
|
-
:allowed_clock_drift => '0.516'
|
1100
|
-
)
|
1101
|
-
assert special_response_with_saml2_namespace.send(:validate_conditions)
|
1102
|
-
end
|
1103
|
-
end
|
1104
|
-
end
|
1105
|
-
|
1106
|
-
describe "#attributes" do
|
1107
|
-
it "extract the first attribute in a hash accessed via its symbol" do
|
1108
|
-
assert_equal "demo", response.attributes[:uid]
|
1109
|
-
end
|
1110
|
-
|
1111
|
-
it "extract the first attribute in a hash accessed via its name" do
|
1112
|
-
assert_equal "demo", response.attributes["uid"]
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
it "extract all attributes" do
|
1116
|
-
assert_equal "demo", response.attributes[:uid]
|
1117
|
-
assert_equal "value", response.attributes[:another_value]
|
1118
|
-
end
|
1119
|
-
|
1120
|
-
it "work for implicit namespaces" do
|
1121
|
-
assert_equal "someone@example.com", response_with_signed_assertion.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
it "extract attributes from all AttributeStatement tags" do
|
1125
|
-
assert_equal "smith", response_with_multiple_attribute_statements.attributes[:surname]
|
1126
|
-
assert_equal "bob", response_with_multiple_attribute_statements.attributes[:firstname]
|
1127
|
-
end
|
1128
|
-
|
1129
|
-
it "not raise on responses without attributes" do
|
1130
|
-
assert_equal OneLogin::RubySaml::Attributes.new, response_unsigned.attributes
|
1131
|
-
end
|
1132
|
-
|
1133
|
-
describe "#encrypted attributes" do
|
1134
|
-
it "raise error when the assertion contains encrypted attributes but no private key to decrypt" do
|
1135
|
-
settings.private_key = nil
|
1136
|
-
response_encrypted_attrs.settings = settings
|
1137
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedAttribute found and no SP private key found on the settings to decrypt it") do
|
1138
|
-
attrs = response_encrypted_attrs.attributes
|
1139
|
-
end
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
it "extract attributes when the assertion contains encrypted attributes and the private key is provided" do
|
1143
|
-
settings.certificate = ruby_saml_cert_text
|
1144
|
-
settings.private_key = ruby_saml_key_text
|
1145
|
-
response_encrypted_attrs.settings = settings
|
1146
|
-
attributes = response_encrypted_attrs.attributes
|
1147
|
-
assert_equal "test", attributes[:uid]
|
1148
|
-
assert_equal "test@example.com", attributes[:mail]
|
1149
|
-
end
|
1150
|
-
end
|
1151
|
-
|
1152
|
-
it "return false when validating a response with duplicate attributes" do
|
1153
|
-
response_duplicated_attributes.settings = settings
|
1154
|
-
response_duplicated_attributes.options[:check_duplicated_attributes] = true
|
1155
|
-
assert !response_duplicated_attributes.send(:validate_no_duplicated_attributes)
|
1156
|
-
assert_includes response_duplicated_attributes.errors, "Found an Attribute element with duplicated Name"
|
1157
|
-
end
|
1158
|
-
|
1159
|
-
it "return true when validating a response with duplicate attributes but skip check" do
|
1160
|
-
response_duplicated_attributes.settings = settings
|
1161
|
-
assert response_duplicated_attributes.send(:validate_no_duplicated_attributes)
|
1162
|
-
end
|
1163
|
-
|
1164
|
-
describe "#multiple values" do
|
1165
|
-
it "extract single value as string" do
|
1166
|
-
assert_equal "demo", response_multiple_attr_values.attributes[:uid]
|
1167
|
-
end
|
1168
|
-
|
1169
|
-
it "extract single value as string in compatibility mode off" do
|
1170
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1171
|
-
assert_equal ["demo"], response_multiple_attr_values.attributes[:uid]
|
1172
|
-
# classes are not reloaded between tests so restore default
|
1173
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1174
|
-
end
|
1175
|
-
|
1176
|
-
it "extract first of multiple values as string for b/w compatibility" do
|
1177
|
-
assert_equal 'value1', response_multiple_attr_values.attributes[:another_value]
|
1178
|
-
end
|
1179
|
-
|
1180
|
-
it "extract first of multiple values as string for b/w compatibility in compatibility mode off" do
|
1181
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1182
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes[:another_value]
|
1183
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1184
|
-
end
|
1185
|
-
|
1186
|
-
it "return array with all attributes when asked in XML order" do
|
1187
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
it "return array with all attributes when asked in XML order in compatibility mode off" do
|
1191
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1192
|
-
assert_equal ['value1', 'value2'], response_multiple_attr_values.attributes.multi(:another_value)
|
1193
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
it "return first of multiple values when multiple Attribute tags in XML" do
|
1197
|
-
assert_equal 'role1', response_multiple_attr_values.attributes[:role]
|
1198
|
-
end
|
1199
|
-
|
1200
|
-
it "return first of multiple values when multiple Attribute tags in XML in compatibility mode off" do
|
1201
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1202
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes[:role]
|
1203
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1204
|
-
end
|
1205
|
-
|
1206
|
-
it "return all of multiple values in reverse order when multiple Attribute tags in XML" do
|
1207
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
1208
|
-
end
|
1209
|
-
|
1210
|
-
it "return all of multiple values in reverse order when multiple Attribute tags in XML in compatibility mode off" do
|
1211
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1212
|
-
assert_equal ['role1', 'role2', 'role3'], response_multiple_attr_values.attributes.multi(:role)
|
1213
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1214
|
-
end
|
1215
|
-
|
1216
|
-
it "return all of multiple values when multiple Attribute tags in multiple AttributeStatement tags" do
|
1217
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1218
|
-
assert_equal ['role1', 'role2', 'role3'], response_with_multiple_attribute_statements.attributes.multi(:role)
|
1219
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
it "return nil value correctly" do
|
1223
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
1224
|
-
end
|
1225
|
-
|
1226
|
-
it "return nil value correctly when not in compatibility mode off" do
|
1227
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1228
|
-
assert_equal [nil], response_multiple_attr_values.attributes[:attribute_with_nil_value]
|
1229
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1230
|
-
end
|
1231
|
-
|
1232
|
-
it "return multiple values including nil and empty string" do
|
1233
|
-
response = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
|
1234
|
-
assert_equal ["", "valuePresent", nil, nil], response.attributes.multi(:attribute_with_nils_and_empty_strings)
|
1235
|
-
end
|
1236
|
-
|
1237
|
-
it "return multiple values from [] when not in compatibility mode off" do
|
1238
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1239
|
-
assert_equal ["", "valuePresent", nil, nil], response_multiple_attr_values.attributes[:attribute_with_nils_and_empty_strings]
|
1240
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1241
|
-
end
|
1242
|
-
|
1243
|
-
it "check what happens when trying retrieve attribute that does not exists" do
|
1244
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
1245
|
-
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
1246
|
-
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
1247
|
-
|
1248
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
1249
|
-
assert_nil response_multiple_attr_values.attributes[:attribute_not_exists]
|
1250
|
-
assert_nil response_multiple_attr_values.attributes.single(:attribute_not_exists)
|
1251
|
-
assert_nil response_multiple_attr_values.attributes.multi(:attribute_not_exists)
|
1252
|
-
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
1253
|
-
end
|
1254
|
-
|
1255
|
-
end
|
1256
|
-
end
|
1257
|
-
|
1258
|
-
describe "#session_expires_at" do
|
1259
|
-
it "extract the value of the SessionNotOnOrAfter attribute" do
|
1260
|
-
assert response.session_expires_at.is_a?(Time)
|
1261
|
-
end
|
1262
|
-
|
1263
|
-
it "return nil when the value of the SessionNotOnOrAfter is not set" do
|
1264
|
-
assert_nil response_without_attributes.session_expires_at
|
1265
|
-
end
|
1266
|
-
end
|
1267
|
-
|
1268
|
-
describe "#success" do
|
1269
|
-
it "find a status code that says success" do
|
1270
|
-
response.success?
|
1271
|
-
end
|
1272
|
-
end
|
1273
|
-
|
1274
|
-
describe '#xpath_first_from_signed_assertion' do
|
1275
|
-
it 'not allow arbitrary code execution' do
|
1276
|
-
malicious_response_document = fixture('response_eval', false)
|
1277
|
-
malicious_response = OneLogin::RubySaml::Response.new(malicious_response_document)
|
1278
|
-
malicious_response.send(:xpath_first_from_signed_assertion)
|
1279
|
-
assert_nil $evalled
|
1280
|
-
end
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
describe '#sign_document' do
|
1284
|
-
it 'Sign an unsigned SAML Response XML and initiate the SAML object with it' do
|
1285
|
-
xml = Base64.decode64(fixture("test_sign.xml"))
|
1286
|
-
|
1287
|
-
document = XMLSecurity::Document.new(xml)
|
1288
|
-
|
1289
|
-
formatted_cert = OneLogin::RubySaml::Utils.format_cert(ruby_saml_cert_text)
|
1290
|
-
cert = OpenSSL::X509::Certificate.new(formatted_cert)
|
1291
|
-
|
1292
|
-
formatted_private_key = OneLogin::RubySaml::Utils.format_private_key(ruby_saml_key_text)
|
1293
|
-
private_key = OpenSSL::PKey::RSA.new(formatted_private_key)
|
1294
|
-
document.sign_document(private_key, cert)
|
1295
|
-
|
1296
|
-
signed_response = OneLogin::RubySaml::Response.new(document.to_s)
|
1297
|
-
settings.assertion_consumer_service_url = "http://recipient"
|
1298
|
-
settings.idp_cert = ruby_saml_cert_text
|
1299
|
-
signed_response.settings = settings
|
1300
|
-
Timecop.freeze(Time.parse("2015-03-18T04:50:24Z")) do
|
1301
|
-
assert signed_response.is_valid?
|
1302
|
-
end
|
1303
|
-
assert_empty signed_response.errors
|
1304
|
-
end
|
1305
|
-
end
|
1306
|
-
|
1307
|
-
describe '#want_assertion_signed' do
|
1308
|
-
before do
|
1309
|
-
settings.security[:want_assertions_signed] = true
|
1310
|
-
@signed_assertion = OneLogin::RubySaml::Response.new(response_document_with_signed_assertion, :settings => settings)
|
1311
|
-
@no_signed_assertion = OneLogin::RubySaml::Response.new(response_document_valid_signed, :settings => settings)
|
1312
|
-
end
|
1313
|
-
|
1314
|
-
|
1315
|
-
it 'returns false if :want_assertion_signed enabled and Assertion not signed' do
|
1316
|
-
assert !@no_signed_assertion.send(:validate_signed_elements)
|
1317
|
-
assert_includes @no_signed_assertion.errors, "The Assertion of the Response is not signed and the SP requires it"
|
1318
|
-
|
1319
|
-
end
|
1320
|
-
|
1321
|
-
it 'returns true if :want_assertion_signed enabled and Assertion is signed' do
|
1322
|
-
assert @signed_assertion.send(:validate_signed_elements)
|
1323
|
-
assert_empty @signed_assertion.errors
|
1324
|
-
end
|
1325
|
-
end
|
1326
|
-
|
1327
|
-
describe "retrieve nameID" do
|
1328
|
-
it 'is possible when nameID inside the assertion' do
|
1329
|
-
response_valid_signed.settings = settings
|
1330
|
-
assert_equal "test@onelogin.com", response_valid_signed.nameid
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
it 'is not possible when encryptID inside the assertion but no private key' do
|
1334
|
-
response_encrypted_nameid.settings = settings
|
1335
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
|
1336
|
-
assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
|
1337
|
-
end
|
1338
|
-
|
1339
|
-
assert_raises(OneLogin::RubySaml::ValidationError, "An EncryptedID found and no SP private key found on the settings to decrypt it") do
|
1340
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
|
1341
|
-
end
|
1342
|
-
end
|
1343
|
-
|
1344
|
-
it 'is possible when encryptID inside the assertion and settings has the private key' do
|
1345
|
-
settings.private_key = ruby_saml_key_text
|
1346
|
-
response_encrypted_nameid.settings = settings
|
1347
|
-
assert_equal "test@onelogin.com", response_encrypted_nameid.nameid
|
1348
|
-
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", response_encrypted_nameid.name_id_format
|
1349
|
-
end
|
1350
|
-
|
1351
|
-
end
|
1352
|
-
|
1353
|
-
describe 'try to initialize an encrypted response' do
|
1354
|
-
it 'raise if an encrypted assertion is found and no sp private key to decrypt it' do
|
1355
|
-
error_msg = "An EncryptedAssertion found and no SP private key found on the settings to decrypt it. Be sure you provided the :settings parameter at the initialize method"
|
1356
|
-
|
1357
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1358
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
|
1359
|
-
end
|
1360
|
-
|
1361
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1362
|
-
response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1363
|
-
end
|
1364
|
-
|
1365
|
-
settings.certificate = ruby_saml_cert_text
|
1366
|
-
settings.private_key = ruby_saml_key_text
|
1367
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1368
|
-
response3 = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion)
|
1369
|
-
response3.settings
|
1370
|
-
end
|
1371
|
-
end
|
1372
|
-
|
1373
|
-
it 'raise if an encrypted assertion is found and the sp private key is wrong' do
|
1374
|
-
settings.certificate = ruby_saml_cert_text
|
1375
|
-
wrong_private_key = ruby_saml_key_text.sub!('A', 'B')
|
1376
|
-
settings.private_key = wrong_private_key
|
1377
|
-
|
1378
|
-
error_msg = "Neither PUB key nor PRIV key: nested asn1 error"
|
1379
|
-
assert_raises(OpenSSL::PKey::RSAError, error_msg) do
|
1380
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1381
|
-
end
|
1382
|
-
end
|
1383
|
-
|
1384
|
-
it 'return true if an encrypted assertion is found and settings initialized with private_key' do
|
1385
|
-
settings.certificate = ruby_saml_cert_text
|
1386
|
-
settings.private_key = ruby_saml_key_text
|
1387
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1388
|
-
assert response.decrypted_document
|
1389
|
-
|
1390
|
-
response2 = OneLogin::RubySaml::Response.new(signed_message_encrypted_signed_assertion, :settings => settings)
|
1391
|
-
assert response2.decrypted_document
|
1392
|
-
|
1393
|
-
response3 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
|
1394
|
-
assert response3.decrypted_document
|
1395
|
-
|
1396
|
-
response4 = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
|
1397
|
-
assert response4.decrypted_document
|
1398
|
-
|
1399
|
-
assert OneLogin::RubySaml::Response.new(
|
1400
|
-
Base64.encode64(File.read('test/responses/unsigned_encrypted_adfs.xml')),
|
1401
|
-
:settings => settings
|
1402
|
-
).decrypted_document
|
1403
|
-
end
|
1404
|
-
end
|
1405
|
-
|
1406
|
-
describe "retrieve nameID and attributes from encrypted assertion" do
|
1407
|
-
|
1408
|
-
before do
|
1409
|
-
settings.idp_cert_fingerprint = 'EE:17:4E:FB:A8:81:71:12:0D:2A:78:43:BC:E7:0C:07:58:79:F4:F4'
|
1410
|
-
settings.sp_entity_id = 'http://rubysaml.com:3000/saml/metadata'
|
1411
|
-
settings.assertion_consumer_service_url = 'http://rubysaml.com:3000/saml/acs'
|
1412
|
-
settings.certificate = ruby_saml_cert_text
|
1413
|
-
settings.private_key = ruby_saml_key_text
|
1414
|
-
end
|
1415
|
-
|
1416
|
-
it 'is possible when signed_message_encrypted_unsigned_assertion' do
|
1417
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1418
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1419
|
-
assert response.is_valid?
|
1420
|
-
assert_empty response.errors
|
1421
|
-
assert_equal "test", response.attributes[:uid]
|
1422
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1423
|
-
end
|
1424
|
-
end
|
1425
|
-
|
1426
|
-
it 'is possible when signed_message_encrypted_signed_assertion' do
|
1427
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_signed_assertion, :settings => settings)
|
1428
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1429
|
-
assert response.is_valid?
|
1430
|
-
assert_empty response.errors
|
1431
|
-
assert_equal "test", response.attributes[:uid]
|
1432
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1433
|
-
end
|
1434
|
-
end
|
1435
|
-
|
1436
|
-
it 'is possible when unsigned_message_encrypted_signed_assertion' do
|
1437
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_signed_assertion, :settings => settings)
|
1438
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1439
|
-
assert response.is_valid?
|
1440
|
-
assert_empty response.errors
|
1441
|
-
assert_equal "test", response.attributes[:uid]
|
1442
|
-
assert_equal "98e2bb61075e951b37d6b3be6954a54b340d86c7", response.nameid
|
1443
|
-
end
|
1444
|
-
end
|
1445
|
-
|
1446
|
-
it 'is not possible when unsigned_message_encrypted_unsigned_assertion' do
|
1447
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_unsigned_assertion, :settings => settings)
|
1448
|
-
Timecop.freeze(Time.parse("2015-03-19T14:30:31Z")) do
|
1449
|
-
assert !response.is_valid?
|
1450
|
-
assert_includes response.errors, "Found an unexpected number of Signature Element. SAML Response rejected"
|
1451
|
-
end
|
1452
|
-
end
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
describe "#decrypt_assertion" do
|
1456
|
-
before do
|
1457
|
-
settings.private_key = ruby_saml_key_text
|
1458
|
-
end
|
1459
|
-
|
1460
|
-
describe "check right settings" do
|
1461
|
-
|
1462
|
-
it "is not possible to decrypt the assertion if no private key" do
|
1463
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1464
|
-
|
1465
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1466
|
-
response.document,
|
1467
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1468
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1469
|
-
)
|
1470
|
-
response.settings.private_key = nil
|
1471
|
-
|
1472
|
-
error_msg = "An EncryptedAssertion found and no SP private key found on the settings to decrypt it"
|
1473
|
-
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
1474
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1475
|
-
end
|
1476
|
-
end
|
1477
|
-
|
1478
|
-
it "is possible to decrypt the assertion if private key" do
|
1479
|
-
response = OneLogin::RubySaml::Response.new(signed_message_encrypted_unsigned_assertion, :settings => settings)
|
1480
|
-
|
1481
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1482
|
-
response.document,
|
1483
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1484
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1485
|
-
)
|
1486
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1487
|
-
|
1488
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1489
|
-
decrypted,
|
1490
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1491
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1492
|
-
)
|
1493
|
-
assert_nil encrypted_assertion_node2
|
1494
|
-
assert decrypted.name, "Assertion"
|
1495
|
-
end
|
1496
|
-
|
1497
|
-
it "is possible to decrypt the assertion if private key provided and EncryptedKey RetrievalMethod presents in response" do
|
1498
|
-
settings.private_key = ruby_saml_key_text
|
1499
|
-
resp = read_response('response_with_retrieval_method.xml')
|
1500
|
-
response = OneLogin::RubySaml::Response.new(resp, :settings => settings)
|
1501
|
-
|
1502
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1503
|
-
response.document,
|
1504
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1505
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1506
|
-
)
|
1507
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1508
|
-
|
1509
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1510
|
-
decrypted,
|
1511
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1512
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1513
|
-
)
|
1514
|
-
|
1515
|
-
assert_nil encrypted_assertion_node2
|
1516
|
-
assert decrypted.name, "Assertion"
|
1517
|
-
end
|
1518
|
-
|
1519
|
-
it "is possible to decrypt the assertion if private key but no saml namespace on the Assertion Element that is inside the EncryptedAssertion" do
|
1520
|
-
unsigned_message_encrypted_assertion_without_saml_namespace = read_response('unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64')
|
1521
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_encrypted_assertion_without_saml_namespace, :settings => settings)
|
1522
|
-
encrypted_assertion_node = REXML::XPath.first(
|
1523
|
-
response.document,
|
1524
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1525
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1526
|
-
)
|
1527
|
-
decrypted = response.send(:decrypt_assertion, encrypted_assertion_node)
|
1528
|
-
|
1529
|
-
encrypted_assertion_node2 = REXML::XPath.first(
|
1530
|
-
decrypted,
|
1531
|
-
"(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)",
|
1532
|
-
{ "p" => "urn:oasis:names:tc:SAML:2.0:protocol", "a" => "urn:oasis:names:tc:SAML:2.0:assertion" }
|
1533
|
-
)
|
1534
|
-
assert_nil encrypted_assertion_node2
|
1535
|
-
assert decrypted.name, "Assertion"
|
1536
|
-
end
|
1537
|
-
end
|
1538
|
-
|
1539
|
-
describe "check different encrypt methods supported" do
|
1540
|
-
it "EncryptionMethod DES-192 && Key Encryption Algorithm RSA-1_5" do
|
1541
|
-
unsigned_message_des192_encrypted_signed_assertion = read_response('unsigned_message_des192_encrypted_signed_assertion.xml.base64')
|
1542
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_des192_encrypted_signed_assertion, :settings => settings)
|
1543
|
-
assert_equal "test", response.attributes[:uid]
|
1544
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1545
|
-
end
|
1546
|
-
|
1547
|
-
it "EncryptionMethod AES-128 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1548
|
-
unsigned_message_aes128_encrypted_signed_assertion = read_response('unsigned_message_aes128_encrypted_signed_assertion.xml.base64')
|
1549
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes128_encrypted_signed_assertion, :settings => settings)
|
1550
|
-
assert_equal "test", response.attributes[:uid]
|
1551
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1552
|
-
end
|
1553
|
-
|
1554
|
-
it "EncryptionMethod AES-192 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1555
|
-
unsigned_message_aes192_encrypted_signed_assertion = read_response('unsigned_message_aes192_encrypted_signed_assertion.xml.base64')
|
1556
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes192_encrypted_signed_assertion, :settings => settings)
|
1557
|
-
assert_equal "test", response.attributes[:uid]
|
1558
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
it "EncryptionMethod AES-256 && Key Encryption Algorithm RSA-OAEP-MGF1P" do
|
1562
|
-
unsigned_message_aes256_encrypted_signed_assertion = read_response('unsigned_message_aes256_encrypted_signed_assertion.xml.base64')
|
1563
|
-
response = OneLogin::RubySaml::Response.new(unsigned_message_aes256_encrypted_signed_assertion, :settings => settings)
|
1564
|
-
assert_equal "test", response.attributes[:uid]
|
1565
|
-
assert_equal "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7", response.nameid
|
1566
|
-
end
|
1567
|
-
end
|
1568
|
-
|
1569
|
-
end
|
1570
|
-
describe "test qualified name id in attributes" do
|
1571
|
-
|
1572
|
-
it "parsed the nameid" do
|
1573
|
-
response = OneLogin::RubySaml::Response.new(read_response("signed_nameid_in_atts.xml"), :settings => settings)
|
1574
|
-
response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
1575
|
-
assert_empty response.errors
|
1576
|
-
assert_equal "test", response.attributes[:uid]
|
1577
|
-
assert_equal "http://idp.example.com/metadata.php/ZdrjpwEdw22vKoxWAbZB78/gQ7s=", response.attributes.single('urn:oid:1.3.6.1.4.1.5923.1.1.1.10')
|
1578
|
-
end
|
1579
|
-
end
|
1580
|
-
|
1581
|
-
describe "test unqualified name id in attributes" do
|
1582
|
-
|
1583
|
-
it "parsed the nameid" do
|
1584
|
-
response = OneLogin::RubySaml::Response.new(read_response("signed_unqual_nameid_in_atts.xml"), :settings => settings)
|
1585
|
-
response.settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
1586
|
-
assert_empty response.errors
|
1587
|
-
assert_equal "test", response.attributes[:uid]
|
1588
|
-
assert_equal "ZdrjpwEdw22vKoxWAbZB78/gQ7s=", response.attributes.single('urn:oid:1.3.6.1.4.1.5923.1.1.1.10')
|
1589
|
-
end
|
1590
|
-
end
|
1591
|
-
|
1592
|
-
describe "signature wrapping attack with encrypted assertion" do
|
1593
|
-
it "should not be valid" do
|
1594
|
-
settings.private_key = ruby_saml_key_text
|
1595
|
-
signature_wrapping_attack = read_invalid_response("encrypted_new_attack.xml.base64")
|
1596
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1597
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1598
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1599
|
-
settings.idp_cert_fingerprint = "385b1eec71143f00db6af936e2ea12a28771d72c"
|
1600
|
-
assert !response_wrapped.is_valid?
|
1601
|
-
assert_includes response_wrapped.errors, "Found an invalid Signed Element. SAML Response rejected"
|
1602
|
-
end
|
1603
|
-
end
|
1604
|
-
|
1605
|
-
describe "signature wrapping attack - concealed SAML response body" do
|
1606
|
-
it "should not be valid" do
|
1607
|
-
signature_wrapping_attack = read_invalid_response("response_with_concealed_signed_assertion.xml")
|
1608
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1609
|
-
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
1610
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1611
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1612
|
-
assert !response_wrapped.is_valid?
|
1613
|
-
assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
|
1614
|
-
end
|
1615
|
-
end
|
1616
|
-
|
1617
|
-
describe "signature wrapping attack - doubled signed assertion SAML response" do
|
1618
|
-
it "should not be valid" do
|
1619
|
-
signature_wrapping_attack = read_invalid_response("response_with_doubled_signed_assertion.xml")
|
1620
|
-
response_wrapped = OneLogin::RubySaml::Response.new(signature_wrapping_attack, :settings => settings)
|
1621
|
-
settings.idp_cert_fingerprint = '4b68c453c7d994aad9025c99d5efcf566287fe8d'
|
1622
|
-
response_wrapped.stubs(:conditions).returns(nil)
|
1623
|
-
response_wrapped.stubs(:validate_subject_confirmation).returns(true)
|
1624
|
-
assert !response_wrapped.is_valid?
|
1625
|
-
assert_includes response_wrapped.errors, "SAML Response must contain 1 assertion"
|
1626
|
-
end
|
1627
|
-
end
|
1628
|
-
end
|
1629
|
-
end
|