ruby-saml 1.7.2 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/changelog.md +9 -0
- data/lib/onelogin/ruby-saml/authrequest.rb +7 -1
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +2 -0
- data/lib/onelogin/ruby-saml/logoutrequest.rb +5 -0
- data/lib/onelogin/ruby-saml/response.rb +16 -1
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +6 -1
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/test/idp_metadata_parser_test.rb +11 -0
- data/test/logoutrequest_test.rb +14 -0
- data/test/metadata/idp_descriptor_4.xml +72 -0
- data/test/request_test.rb +29 -2
- data/test/response_test.rb +56 -5
- data/test/responses/response_node_text_attack2.xml.base64 +1 -0
- data/test/responses/response_node_text_attack3.xml.base64 +1 -0
- data/test/slo_logoutresponse_test.rb +14 -0
- data/test/test_helper.rb +8 -4
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e2594fe194305df6e9fae1f6d2ec5f642155fec
|
4
|
+
data.tar.gz: c0493eb47ce432fff7575241117d69860a5d1a36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 941cba217d85b8b05b51d22d39f2136ed62ac1a00ce5f52166fbb76a0e82681d0d4ea565d6990476eaaf563af9b3be676df6adb47dce1134235928c21614f149
|
7
|
+
data.tar.gz: 972bb6d3d9f71b5278035928a2188de402ff730e9e83d2a9be7e49a1075d08ca76e8c866263415170bdd439071ff956f0c283edb531410a34dd01de8e23d0aaf
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.svg)](http://travis-ci.org/onelogin/ruby-saml) [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master%0A)](https://coveralls.io/r/onelogin/ruby-saml?branch=master%0A) [![Gem Version](https://badge.fury.io/rb/ruby-saml.svg)](http://badge.fury.io/rb/ruby-saml)
|
2
2
|
|
3
|
+
## Updating from 1.7.X to 1.8.0
|
4
|
+
On Version `1.8.0`, creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState param will not generate a URL with an empty RelayState parameter anymore. It also changes the invalid audience error message.
|
5
|
+
|
3
6
|
## Updating from 1.6.0 to 1.7.0
|
4
7
|
|
5
8
|
Version `1.7.0` is a recommended update for all Ruby SAML users as it includes a fix for the [CVE-2017-11428](https://www.cvedetails.com/cve/CVE-2017-11428/) vulnerability.
|
@@ -41,6 +44,10 @@ value.
|
|
41
44
|
If you want to skip that validation, add the :skip_recipient_check option to the
|
42
45
|
initialize method of the Response object.
|
43
46
|
|
47
|
+
Parsing metadata that contains more than one certificate will propagate the
|
48
|
+
idp_cert_multi property rather than idp_cert. See [signature validation
|
49
|
+
section](#signature-validation) for details.
|
50
|
+
|
44
51
|
## Updating from 1.3.x to 1.4.X
|
45
52
|
|
46
53
|
Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
|
@@ -235,9 +242,10 @@ def saml_settings
|
|
235
242
|
end
|
236
243
|
```
|
237
244
|
|
238
|
-
Some assertion validations can be skipped by passing parameters to `OneLogin::RubySaml::Response.new()`. For example, you can skip the `Conditions`, `Recipient`, or the `SubjectConfirmation` validations by initializing the response with different options:
|
245
|
+
Some assertion validations can be skipped by passing parameters to `OneLogin::RubySaml::Response.new()`. For example, you can skip the `AuthnStatement`, `Conditions`, `Recipient`, or the `SubjectConfirmation` validations by initializing the response with different options:
|
239
246
|
|
240
247
|
```ruby
|
248
|
+
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnstatement: true}) # skips AuthnStatement
|
241
249
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
|
242
250
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
|
243
251
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_recipient_check: true}) # doens't skip subject confirmation, but skips the recipient check which is a sub check of the subject_confirmation check
|
data/changelog.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# RubySaml Changelog
|
2
2
|
|
3
|
+
### 1.8.0 (April 23, 2018)
|
4
|
+
* [#437](https://github.com/onelogin/ruby-saml/issues/437) Creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState should not send empty RelayState URL param
|
5
|
+
* [#454](https://github.com/onelogin/ruby-saml/pull/454) Added Response available options
|
6
|
+
* [#453](https://github.com/onelogin/ruby-saml/pull/453) Raise a more descriptive exception if idp_sso_target_url is missing
|
7
|
+
* [#452](https://github.com/onelogin/ruby-saml/pull/452) Fix behavior of skip_conditions flag on Response
|
8
|
+
* [#449](https://github.com/onelogin/ruby-saml/pull/449) Add ability to skip authnstatement validation
|
9
|
+
* Clear cached values to be able to use IdpMetadataParser more than once
|
10
|
+
* Updated invalid audience error message
|
11
|
+
|
3
12
|
### 1.7.2 (Feb 28, 2018)
|
4
13
|
* [#446](https://github.com/onelogin/ruby-saml/pull/446) Normalize text returned by OneLogin::RubySaml::Utils.element_text
|
5
14
|
|
@@ -36,6 +36,7 @@ module OneLogin
|
|
36
36
|
params.each_pair do |key, value|
|
37
37
|
request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
|
38
38
|
end
|
39
|
+
raise "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil?
|
39
40
|
@login_url = settings.idp_sso_target_url + request_params
|
40
41
|
end
|
41
42
|
|
@@ -50,6 +51,11 @@ module OneLogin
|
|
50
51
|
# conflicts so this line will solve them.
|
51
52
|
relay_state = params[:RelayState] || params['RelayState']
|
52
53
|
|
54
|
+
if relay_state.nil?
|
55
|
+
params.delete(:RelayState)
|
56
|
+
params.delete('RelayState')
|
57
|
+
end
|
58
|
+
|
53
59
|
request_doc = create_authentication_xml_doc(settings)
|
54
60
|
request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
|
55
61
|
|
@@ -157,7 +163,7 @@ module OneLogin
|
|
157
163
|
|
158
164
|
def sign_document(document, settings)
|
159
165
|
# embed signature
|
160
|
-
if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
|
166
|
+
if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
|
161
167
|
private_key = settings.get_sp_key
|
162
168
|
cert = settings.get_sp_cert
|
163
169
|
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
@@ -101,6 +101,8 @@ module OneLogin
|
|
101
101
|
@document = REXML::Document.new(idp_metadata)
|
102
102
|
@options = options
|
103
103
|
@entity_descriptor = nil
|
104
|
+
@certificates = nil
|
105
|
+
@fingerprint = nil
|
104
106
|
|
105
107
|
if idpsso_descriptor.nil?
|
106
108
|
raise ArgumentError.new("idp_metadata must contain an IDPSSODescriptor element")
|
@@ -47,6 +47,11 @@ module OneLogin
|
|
47
47
|
# conflicts so this line will solve them.
|
48
48
|
relay_state = params[:RelayState] || params['RelayState']
|
49
49
|
|
50
|
+
if relay_state.nil?
|
51
|
+
params.delete(:RelayState)
|
52
|
+
params.delete('RelayState')
|
53
|
+
end
|
54
|
+
|
50
55
|
request_doc = create_logout_request_xml_doc(settings)
|
51
56
|
request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
|
52
57
|
|
@@ -30,6 +30,15 @@ module OneLogin
|
|
30
30
|
|
31
31
|
attr_accessor :soft
|
32
32
|
|
33
|
+
# Response available options
|
34
|
+
# This is not a whitelist to allow people extending OneLogin::RubySaml:Response
|
35
|
+
# and pass custom options
|
36
|
+
AVAILABLE_OPTIONS = [
|
37
|
+
:allowed_clock_drift, :check_duplicated_attributes, :matches_request_id, :settings, :skip_authnstatement, :skip_conditions,
|
38
|
+
:skip_destination, :skip_recipient_check, :skip_subject_confirmation
|
39
|
+
]
|
40
|
+
# TODO: Update the comment on initialize to describe every option
|
41
|
+
|
33
42
|
# Constructs the SAML Response. A Response Object that is an extension of the SamlMessage class.
|
34
43
|
# @param response [String] A UUEncoded SAML response from the IdP.
|
35
44
|
# @param options [Hash] :settings to provide the OneLogin::RubySaml::Settings object
|
@@ -583,7 +592,8 @@ module OneLogin
|
|
583
592
|
return true if audiences.empty? || settings.issuer.nil? || settings.issuer.empty?
|
584
593
|
|
585
594
|
unless audiences.include? settings.issuer
|
586
|
-
|
595
|
+
s = audiences.count > 1 ? 's' : '';
|
596
|
+
error_msg = "Invalid Audience#{s}. The audience#{s} #{audiences.join(',')}, did not match the expected audience #{settings.issuer}"
|
587
597
|
return append_error(error_msg)
|
588
598
|
end
|
589
599
|
|
@@ -615,10 +625,13 @@ module OneLogin
|
|
615
625
|
end
|
616
626
|
|
617
627
|
# Checks that the samlp:Response/saml:Assertion/saml:Conditions element exists and is unique.
|
628
|
+
# (If the response was initialized with the :skip_conditions option, this validation is skipped)
|
618
629
|
# If fails, the error is added to the errors array
|
619
630
|
# @return [Boolean] True if there is a conditions element and is unique
|
620
631
|
#
|
621
632
|
def validate_one_conditions
|
633
|
+
return true if options[:skip_conditions]
|
634
|
+
|
622
635
|
conditions_nodes = xpath_from_signed_assertion('/a:Conditions')
|
623
636
|
unless conditions_nodes.size == 1
|
624
637
|
error_msg = "The Assertion must include one Conditions element"
|
@@ -633,6 +646,8 @@ module OneLogin
|
|
633
646
|
# @return [Boolean] True if there is a authnstatement element and is unique
|
634
647
|
#
|
635
648
|
def validate_one_authnstatement
|
649
|
+
return true if options[:skip_authnstatement]
|
650
|
+
|
636
651
|
authnstatement_nodes = xpath_from_signed_assertion('/a:AuthnStatement')
|
637
652
|
unless authnstatement_nodes.size == 1
|
638
653
|
error_msg = "The Assertion must include one AuthnStatement element"
|
@@ -53,6 +53,11 @@ module OneLogin
|
|
53
53
|
# conflicts so this line will solve them.
|
54
54
|
relay_state = params[:RelayState] || params['RelayState']
|
55
55
|
|
56
|
+
if relay_state.nil?
|
57
|
+
params.delete(:RelayState)
|
58
|
+
params.delete('RelayState')
|
59
|
+
end
|
60
|
+
|
56
61
|
response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
|
57
62
|
response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
|
58
63
|
|
@@ -108,7 +113,7 @@ module OneLogin
|
|
108
113
|
issuer = root.add_element "saml:Issuer"
|
109
114
|
issuer.text = settings.issuer
|
110
115
|
end
|
111
|
-
|
116
|
+
|
112
117
|
# add success message
|
113
118
|
status = root.add_element 'samlp:Status'
|
114
119
|
|
@@ -185,6 +185,17 @@ class IdpMetadataParserTest < Minitest::Test
|
|
185
185
|
assert_equal "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72", parsed_metadata[:idp_cert_fingerprint]
|
186
186
|
assert_nil parsed_metadata[:security]
|
187
187
|
end
|
188
|
+
|
189
|
+
it "can extract certificates multiple times in sequence" do
|
190
|
+
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
|
191
|
+
idp_metadata1 = idp_metadata_descriptor
|
192
|
+
idp_metadata2 = idp_metadata_descriptor4
|
193
|
+
metadata1 = idp_metadata_parser.parse_to_hash(idp_metadata1)
|
194
|
+
metadata2 = idp_metadata_parser.parse_to_hash(idp_metadata2)
|
195
|
+
|
196
|
+
assert_equal "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72", metadata1[:idp_cert_fingerprint]
|
197
|
+
assert_equal "CD:2B:2B:DA:FF:F5:DB:64:10:7C:AC:FD:FE:0F:CB:5D:73:5F:16:07", metadata2[:idp_cert_fingerprint]
|
198
|
+
end
|
188
199
|
end
|
189
200
|
|
190
201
|
describe "parsing an IdP descriptor file with multiple signing certs" do
|
data/test/logoutrequest_test.rb
CHANGED
@@ -28,6 +28,20 @@ class RequestTest < Minitest::Test
|
|
28
28
|
assert_match /&foo=bar$/, unauth_url
|
29
29
|
end
|
30
30
|
|
31
|
+
it "RelayState cases" do
|
32
|
+
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => nil })
|
33
|
+
assert !unauth_url.include?('RelayState')
|
34
|
+
|
35
|
+
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => "http://example.com" })
|
36
|
+
assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
37
|
+
|
38
|
+
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => nil })
|
39
|
+
assert !unauth_url.include?('RelayState')
|
40
|
+
|
41
|
+
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => "http://example.com" })
|
42
|
+
assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
43
|
+
end
|
44
|
+
|
31
45
|
it "set sessionindex" do
|
32
46
|
settings.idp_slo_target_url = "http://example.com"
|
33
47
|
sessionidx = OneLogin::RubySaml::Utils.uuid
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<md:EntityDescriptor entityID="https://hello.example.com/access/saml/idp.xml" validUntil="2014-04-17T18:02:33.910Z" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
|
3
|
+
<md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
4
|
+
<md:KeyDescriptor use="signing">
|
5
|
+
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
6
|
+
<ds:X509Data>
|
7
|
+
<ds:X509Certificate>MIIEZTCCA02gAwIBAgIUPyy/A3bZAZ4m28PzEUUoT7RJhxIwDQYJKoZIhvcNAQEF
|
8
|
+
BQAwcjELMAkGA1UEBhMCVVMxKzApBgNVBAoMIk9uZUxvZ2luIFRlc3QgKHNnYXJj
|
9
|
+
aWEtdXMtcHJlcHJvZCkxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEfMB0GA1UEAwwW
|
10
|
+
T25lTG9naW4gQWNjb3VudCA4OTE0NjAeFw0xNjA4MDQyMjI5MzdaFw0yMTA4MDUy
|
11
|
+
MjI5MzdaMHIxCzAJBgNVBAYTAlVTMSswKQYDVQQKDCJPbmVMb2dpbiBUZXN0IChz
|
12
|
+
Z2FyY2lhLXVzLXByZXByb2QpMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxHzAdBgNV
|
13
|
+
BAMMFk9uZUxvZ2luIEFjY291bnQgODkxNDYwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
14
|
+
DwAwggEKAoIBAQDN6iqQGcLOCglNO42I2rkzE05UXSiMXT6c8ALThMMiaDw6qqzo
|
15
|
+
3sd/tKK+NcNKWLIIC8TozWVyh5ykUiVZps+08xil7VsTU7E+wKu3kvmOsvw2wlRw
|
16
|
+
tnoKZJwYhnr+RkBa+h1r3ZYUgXm1ZPeHMKj1g18KaWz9+MxYL6BhKqrOzfW/P2xx
|
17
|
+
VRcFH7/pq+ZsDdgNzD2GD+apzY4MZyZj/N6BpBWJ0GlFsmtBegpbX3LBitJuFkk5
|
18
|
+
L4/U/jjF1AJa3boBdCUVfATqO5G03H4XS1GySjBIRQXmlUF52rLjg6xCgWJ30/+t
|
19
|
+
1X+IHLJeixiQ0vxyh6C4/usCEt94cgD1r8ADAgMBAAGjgfIwge8wDAYDVR0TAQH/
|
20
|
+
BAIwADAdBgNVHQ4EFgQUPW0DcH0G3IwynWgi74co4wZ6n7gwga8GA1UdIwSBpzCB
|
21
|
+
pIAUPW0DcH0G3IwynWgi74co4wZ6n7ihdqR0MHIxCzAJBgNVBAYTAlVTMSswKQYD
|
22
|
+
VQQKDCJPbmVMb2dpbiBUZXN0IChzZ2FyY2lhLXVzLXByZXByb2QpMRUwEwYDVQQL
|
23
|
+
DAxPbmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxvZ2luIEFjY291bnQgODkxNDaC
|
24
|
+
FD8svwN22QGeJtvD8xFFKE+0SYcSMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0B
|
25
|
+
AQUFAAOCAQEAQhB4q9jrycwbHrDSoYR1X4LFFzvJ9Us75wQquRHXpdyS9D6HUBXM
|
26
|
+
GI6ahPicXCQrfLgN8vzMIiqZqfySXXv/8/dxe/X4UsWLYKYJHDJmxXD5EmWTa65c
|
27
|
+
hjkeP1oJAc8f3CKCpcP2lOBTthbnk2fEVAeLHR4xNdQO0VvGXWO9BliYPpkYqUIB
|
28
|
+
vlm+Fg9mF7AM/Uagq2503XXIE1Lq//HON68P10vNMwLSKOtYLsoTiCnuIKGJqG37
|
29
|
+
MsZVjQ1ZPRcO+LSLkq0i91gFxrOrVCrgztX4JQi5XkvEsYZGIXXjwHqxTVyt3adZ
|
30
|
+
WQO0LPxPqRiUqUzyhDhLo/xXNrHCu4VbMw==</ds:X509Certificate>
|
31
|
+
</ds:X509Data>
|
32
|
+
</ds:KeyInfo>
|
33
|
+
</md:KeyDescriptor>
|
34
|
+
<md:KeyDescriptor use="encryption">
|
35
|
+
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
36
|
+
<ds:X509Data>
|
37
|
+
<ds:X509Certificate>MIIEZTCCA02gAwIBAgIUPyy/A3bZAZ4m28PzEUUoT7RJhxIwDQYJKoZIhvcNAQEF
|
38
|
+
BQAwcjELMAkGA1UEBhMCVVMxKzApBgNVBAoMIk9uZUxvZ2luIFRlc3QgKHNnYXJj
|
39
|
+
aWEtdXMtcHJlcHJvZCkxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEfMB0GA1UEAwwW
|
40
|
+
T25lTG9naW4gQWNjb3VudCA4OTE0NjAeFw0xNjA4MDQyMjI5MzdaFw0yMTA4MDUy
|
41
|
+
MjI5MzdaMHIxCzAJBgNVBAYTAlVTMSswKQYDVQQKDCJPbmVMb2dpbiBUZXN0IChz
|
42
|
+
Z2FyY2lhLXVzLXByZXByb2QpMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxHzAdBgNV
|
43
|
+
BAMMFk9uZUxvZ2luIEFjY291bnQgODkxNDYwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
44
|
+
DwAwggEKAoIBAQDN6iqQGcLOCglNO42I2rkzE05UXSiMXT6c8ALThMMiaDw6qqzo
|
45
|
+
3sd/tKK+NcNKWLIIC8TozWVyh5ykUiVZps+08xil7VsTU7E+wKu3kvmOsvw2wlRw
|
46
|
+
tnoKZJwYhnr+RkBa+h1r3ZYUgXm1ZPeHMKj1g18KaWz9+MxYL6BhKqrOzfW/P2xx
|
47
|
+
VRcFH7/pq+ZsDdgNzD2GD+apzY4MZyZj/N6BpBWJ0GlFsmtBegpbX3LBitJuFkk5
|
48
|
+
L4/U/jjF1AJa3boBdCUVfATqO5G03H4XS1GySjBIRQXmlUF52rLjg6xCgWJ30/+t
|
49
|
+
1X+IHLJeixiQ0vxyh6C4/usCEt94cgD1r8ADAgMBAAGjgfIwge8wDAYDVR0TAQH/
|
50
|
+
BAIwADAdBgNVHQ4EFgQUPW0DcH0G3IwynWgi74co4wZ6n7gwga8GA1UdIwSBpzCB
|
51
|
+
pIAUPW0DcH0G3IwynWgi74co4wZ6n7ihdqR0MHIxCzAJBgNVBAYTAlVTMSswKQYD
|
52
|
+
VQQKDCJPbmVMb2dpbiBUZXN0IChzZ2FyY2lhLXVzLXByZXByb2QpMRUwEwYDVQQL
|
53
|
+
DAxPbmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxvZ2luIEFjY291bnQgODkxNDaC
|
54
|
+
FD8svwN22QGeJtvD8xFFKE+0SYcSMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0B
|
55
|
+
AQUFAAOCAQEAQhB4q9jrycwbHrDSoYR1X4LFFzvJ9Us75wQquRHXpdyS9D6HUBXM
|
56
|
+
GI6ahPicXCQrfLgN8vzMIiqZqfySXXv/8/dxe/X4UsWLYKYJHDJmxXD5EmWTa65c
|
57
|
+
hjkeP1oJAc8f3CKCpcP2lOBTthbnk2fEVAeLHR4xNdQO0VvGXWO9BliYPpkYqUIB
|
58
|
+
vlm+Fg9mF7AM/Uagq2503XXIE1Lq//HON68P10vNMwLSKOtYLsoTiCnuIKGJqG37
|
59
|
+
MsZVjQ1ZPRcO+LSLkq0i91gFxrOrVCrgztX4JQi5XkvEsYZGIXXjwHqxTVyt3adZ
|
60
|
+
WQO0LPxPqRiUqUzyhDhLo/xXNrHCu4VbMw==</ds:X509Certificate>
|
61
|
+
</ds:X509Data>
|
62
|
+
</ds:KeyInfo>
|
63
|
+
</md:KeyDescriptor>
|
64
|
+
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://hello.example.com/access/saml/logout" ResponseLocation="https://hello.example.com/access/saml/logout"/>
|
65
|
+
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
|
66
|
+
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
|
67
|
+
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
|
68
|
+
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://hello.example.com/access/saml/login"/>
|
69
|
+
<saml:Attribute Name="AuthToken" NameFormat="urn:oasis:names:tc:SAML:2.0:att rname-format:basic" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"/>
|
70
|
+
<saml:Attribute Name="SSOStartPage" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"/>
|
71
|
+
</md:IDPSSODescriptor>
|
72
|
+
</md:EntityDescriptor>
|
data/test/request_test.rb
CHANGED
@@ -129,6 +129,33 @@ class RequestTest < Minitest::Test
|
|
129
129
|
assert_match /&hello=$/, auth_url
|
130
130
|
end
|
131
131
|
|
132
|
+
it "RelayState cases" do
|
133
|
+
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => nil })
|
134
|
+
assert !auth_url.include?('RelayState')
|
135
|
+
|
136
|
+
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { :RelayState => "http://example.com" })
|
137
|
+
assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
138
|
+
|
139
|
+
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => nil })
|
140
|
+
assert !auth_url.include?('RelayState')
|
141
|
+
|
142
|
+
auth_url = OneLogin::RubySaml::Authrequest.new.create(settings, { 'RelayState' => "http://example.com" })
|
143
|
+
assert auth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "when the target url is not set" do
|
147
|
+
before do
|
148
|
+
settings.idp_sso_target_url = nil
|
149
|
+
end
|
150
|
+
|
151
|
+
it "raises an error with a descriptive message" do
|
152
|
+
err = assert_raises RuntimeError do
|
153
|
+
OneLogin::RubySaml::Authrequest.new.create(settings)
|
154
|
+
end
|
155
|
+
assert_match /idp_sso_target_url is not set/, err.message
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
132
159
|
describe "when the target url doesn't contain a query string" do
|
133
160
|
it "create the SAMLRequest parameter correctly" do
|
134
161
|
|
@@ -222,7 +249,7 @@ class RequestTest < Minitest::Test
|
|
222
249
|
settings.certificate = ruby_saml_cert_text
|
223
250
|
settings.private_key = ruby_saml_key_text
|
224
251
|
end
|
225
|
-
|
252
|
+
|
226
253
|
it "create a signature parameter with RSA_SHA1 and validate it" do
|
227
254
|
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
228
255
|
|
@@ -255,7 +282,7 @@ class RequestTest < Minitest::Test
|
|
255
282
|
|
256
283
|
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
257
284
|
assert_equal signature_algorithm, OpenSSL::Digest::SHA256
|
258
|
-
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
285
|
+
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
259
286
|
end
|
260
287
|
end
|
261
288
|
|
data/test/response_test.rb
CHANGED
@@ -23,7 +23,9 @@ class RubySamlTest < Minitest::Test
|
|
23
23
|
let(:response_no_version) { OneLogin::RubySaml::Response.new(read_invalid_response("no_saml2.xml.base64")) }
|
24
24
|
let(:response_multi_assertion) { OneLogin::RubySaml::Response.new(read_invalid_response("multiple_assertions.xml.base64")) }
|
25
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 }) }
|
26
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}) }
|
27
29
|
let(:response_empty_destination) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64")) }
|
28
30
|
let(:response_empty_destination_with_skip) { OneLogin::RubySaml::Response.new(read_invalid_response("empty_destination.xml.base64"), {:skip_destination => true}) }
|
29
31
|
let(:response_no_status) { OneLogin::RubySaml::Response.new(read_invalid_response("no_status.xml.base64")) }
|
@@ -54,10 +56,22 @@ class RubySamlTest < Minitest::Test
|
|
54
56
|
let(:response_invalid_signature_position) { OneLogin::RubySaml::Response.new(read_invalid_response("invalid_signature_position.xml.base64")) }
|
55
57
|
let(:response_encrypted_nameid) { OneLogin::RubySaml::Response.new(response_document_encrypted_nameid) }
|
56
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
|
+
|
57
64
|
it "raise an exception when response is initialized with nil" do
|
58
65
|
assert_raises(ArgumentError) { OneLogin::RubySaml::Response.new(nil) }
|
59
66
|
end
|
60
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
|
+
|
61
75
|
it "be able to parse a document which contains ampersands" do
|
62
76
|
XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
|
63
77
|
OneLogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
|
@@ -82,7 +96,32 @@ class RubySamlTest < Minitest::Test
|
|
82
96
|
it "receives the full AttributeValue when there is an injected comment" do
|
83
97
|
assert_equal "smith", @response.attributes["surname"]
|
84
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
|
85
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
|
86
125
|
end
|
87
126
|
|
88
127
|
describe "Prevent XEE attack" do
|
@@ -223,7 +262,7 @@ class RubySamlTest < Minitest::Test
|
|
223
262
|
settings.issuer = 'invalid'
|
224
263
|
response_valid_signed.settings = settings
|
225
264
|
response_valid_signed.soft = false
|
226
|
-
error_msg =
|
265
|
+
error_msg = generate_audience_error(response_valid_signed.settings.issuer, ['https://someone.example.com/audience'])
|
227
266
|
assert_raises(OneLogin::RubySaml::ValidationError, error_msg) do
|
228
267
|
response_valid_signed.is_valid?
|
229
268
|
end
|
@@ -379,7 +418,8 @@ class RubySamlTest < Minitest::Test
|
|
379
418
|
settings.issuer = 'invalid'
|
380
419
|
response_valid_signed.settings = settings
|
381
420
|
response_valid_signed.is_valid?
|
382
|
-
|
421
|
+
|
422
|
+
assert_includes response_valid_signed.errors, generate_audience_error(response_valid_signed.settings.issuer, ['https://someone.example.com/audience'])
|
383
423
|
end
|
384
424
|
|
385
425
|
it "return false when no ID present in the SAML Response" do
|
@@ -415,7 +455,7 @@ class RubySamlTest < Minitest::Test
|
|
415
455
|
response_invalid_subjectconfirmation_recipient.settings = settings
|
416
456
|
collect_errors = true
|
417
457
|
response_invalid_subjectconfirmation_recipient.is_valid?(collect_errors)
|
418
|
-
assert_includes response_invalid_subjectconfirmation_recipient.errors,
|
458
|
+
assert_includes response_invalid_subjectconfirmation_recipient.errors, generate_audience_error('invalid', ['http://stuff.com/endpoints/metadata.php'])
|
419
459
|
assert_includes response_invalid_subjectconfirmation_recipient.errors, "Invalid Signature on SAML Response"
|
420
460
|
end
|
421
461
|
end
|
@@ -440,7 +480,7 @@ class RubySamlTest < Minitest::Test
|
|
440
480
|
response.settings = settings
|
441
481
|
response.settings.issuer = 'invalid_audience'
|
442
482
|
assert !response.send(:validate_audience)
|
443
|
-
assert_includes response.errors,
|
483
|
+
assert_includes response.errors, generate_audience_error(response.settings.issuer, ['{audience}'])
|
444
484
|
end
|
445
485
|
end
|
446
486
|
|
@@ -626,7 +666,7 @@ class RubySamlTest < Minitest::Test
|
|
626
666
|
response_invalid_audience.settings = settings
|
627
667
|
response_invalid_audience.settings.issuer = "https://invalid.example.com/audience"
|
628
668
|
assert !response_invalid_audience.send(:validate_audience)
|
629
|
-
assert_includes response_invalid_audience.errors,
|
669
|
+
assert_includes response_invalid_audience.errors, generate_audience_error(response_invalid_audience.settings.issuer, ['http://invalid.audience.com'])
|
630
670
|
end
|
631
671
|
end
|
632
672
|
|
@@ -958,6 +998,11 @@ class RubySamlTest < Minitest::Test
|
|
958
998
|
response.soft = true
|
959
999
|
assert response.send(:validate_one_conditions)
|
960
1000
|
end
|
1001
|
+
|
1002
|
+
it "return true when no conditions are present and skip_conditions is true" do
|
1003
|
+
response_no_conditions_with_skip.soft = true
|
1004
|
+
assert response_no_conditions_with_skip.send(:validate_one_conditions)
|
1005
|
+
end
|
961
1006
|
end
|
962
1007
|
|
963
1008
|
describe "#check_one_authnstatement" do
|
@@ -971,6 +1016,12 @@ class RubySamlTest < Minitest::Test
|
|
971
1016
|
response.soft = true
|
972
1017
|
assert response.send(:validate_one_authnstatement)
|
973
1018
|
end
|
1019
|
+
|
1020
|
+
it "return true when SAML Response is empty but skip_authstatement option is used" do
|
1021
|
+
response_no_authnstatement_with_skip.soft = true
|
1022
|
+
assert response_no_authnstatement_with_skip.send(:validate_one_authnstatement)
|
1023
|
+
assert_empty response_empty_destination_with_skip.errors
|
1024
|
+
end
|
974
1025
|
end
|
975
1026
|
|
976
1027
|
describe "#check_conditions" do
|
@@ -0,0 +1 @@
|
|
1
|
+
PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9InBmeGJjODI2YWZkLWU5ZmUtZDNmYi1kODc0LWM0NzAwYzNlZjBjOCIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIiBEZXN0aW5hdGlvbj0iaHR0cDovL2FwcC5tdWRhLm5vL3Nzby9jb25zdW1lIiBJblJlc3BvbnNlVG89Il9mYzRhMzRiMC03ZWZiLTAxMmUtY2FhZS03ODJiY2IxM2JiMzgiPjxzYW1sOklzc3Vlcj5odHRwczovL2FwcC5vbmVsb2dpbi5jb20vc2FtbDI8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KICA8ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPg0KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz4NCiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNwZnhiYzgyNmFmZC1lOWZlLWQzZmItZDg3NC1jNDcwMGMzZWYwYzgiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPkl6NFpRbHMzQUpaRGIzczh2Y1VYLzNSYytGUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+UWhLSm1vbnlzUDFxbW5hN1MrZUUxTGMycktBampDMk9HclFPZ1NqUHBUb2N1bVE2aFlIa3pUU1pyN3QvSS9LVE9TdkhDUXFEMXJoNGxTMGpEUC9FdUhOQUN0azlZN2xsMlV5Z3U3MkwrYkZ0cVoyOURuOXJMa1NkR3JpK0k3SGh4TDM2N2RmQVNTaDYrc3k3V2V2RWRrTWZ3ZURRMkFYL3NhNkJCR2d6N1RFPTwvZHM6U2lnbmF0dXJlVmFsdWU+DQo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDR3pDQ0FZUUNDUUNOTmNRWG9tMzJWREFOQmdrcWhraUc5dzBCQVFVRkFEQlNNUXN3Q1FZRFZRUUdFd0pWVXpFTE1Ba0dBMVVFQ0JNQ1NVNHhGVEFUQmdOVkJBY1RERWx1WkdsaGJtRndiMnhwY3pFUk1BOEdBMVVFQ2hNSVQyNWxURzluYVc0eEREQUtCZ05WQkFzVEEwVnVaekFlRncweE5EQTBNak14T0RReE1ERmFGdzB4TlRBME1qTXhPRFF4TURGYU1GSXhDekFKQmdOVkJBWVRBbFZUTVFzd0NRWURWUVFJRXdKSlRqRVZNQk1HQTFVRUJ4TU1TVzVrYVdGdVlYQnZiR2x6TVJFd0R3WURWUVFLRXdoUGJtVk1iMmRwYmpFTU1Bb0dBMVVFQ3hNRFJXNW5NSUdmTUEwR0NTcUdTSWIzRFFFQkFRVUFBNEdOQURDQmlRS0JnUURvNm0rUVp2WVEveEwwRWxMZ3VwSzFRRGNZTDRmNVBja3dzTmdTOXBVdlY3ZnpUcUNIazhUaEx4VGs0Mk1RMk1jSnNPZVVKVlA3MjhLaHltakZDcXhnUDRWdXdSazlycEFsMCttaHk2TVBkeWp5QTZHMTRqckRXUzY1eXNMY2hLNHQvdndwRUR6MFNRbEVvRzFrTXpsbFNtN3paUzNYcmVnQTdEak5hVVlRcXdJREFRQUJNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0R0JBTE0ydkdDaVEvdm0rYTZ2NDArVlgyemRxSEEyUS8xdkYxaWJReko1NE1KQ09WV3ZzK3ZRWGZaRmhkbTBPUE0ySXJEVTdvcXZLUHFQNnhPQWVKSzZIMHlQN000WUwzZmF0U3ZJWW1tZnlYQzlrdDNTdnovTnlySHpQaFVuSjB5ZS9zVVNYeG56UXh3Y20vOVB3QXFyUWFBM1FwUWtINTd5YkYvT29yeVBlKzJoPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgVmVyc2lvbj0iMi4wIiBJRD0icGZ4OTUxNmIwZjMtNDUzNi0xMGY2LWM2ZmEtOWRkNTIzZTE0OThjIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9hcHAub25lbG9naW4uY29tL3NhbWwyPC9zYW1sOklzc3Vlcj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+dGVzdDwhLS0gYXR0YWNrIC0tPkBvbmVsb2dpbi5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwMzAtMDYtMDRUMDI6Mjc6MDJaIiBSZWNpcGllbnQ9InJlY2lwaWVudCIvPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDExLTA2LTA0VDAyOjE3OjAyWiIgTm90T25PckFmdGVyPSIyMDMwLTA2LTA0VDAyOjI3OjAyWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL3NvbWVvbmUuZXhhbXBsZS5jb20vYXVkaWVuY2U8L3NhbWw6QXVkaWVuY2U+PC9zYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PC9zYW1sOkNvbmRpdGlvbnM+PHNhbWw6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTA2LTA0VDAyOjIyOjAyWiIgU2Vzc2lvbk5vdE9uT3JBZnRlcj0iMjAzMC0wNi0wNVQwMjoyMjowMloiIFNlc3Npb25JbmRleD0iXzE2ZjU3MGZiYzAzMTUwMDdhMDM1NWRmZWE2YjNjNDZjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==
|
@@ -0,0 +1 @@
|
|
1
|
+
PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9InBmeGJjODI2YWZkLWU5ZmUtZDNmYi1kODc0LWM0NzAwYzNlZjBjOCIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIiBEZXN0aW5hdGlvbj0iaHR0cDovL2FwcC5tdWRhLm5vL3Nzby9jb25zdW1lIiBJblJlc3BvbnNlVG89Il9mYzRhMzRiMC03ZWZiLTAxMmUtY2FhZS03ODJiY2IxM2JiMzgiPjxzYW1sOklzc3Vlcj5odHRwczovL2FwcC5vbmVsb2dpbi5jb20vc2FtbDI8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KICA8ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPg0KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz4NCiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNwZnhiYzgyNmFmZC1lOWZlLWQzZmItZDg3NC1jNDcwMGMzZWYwYzgiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPkl6NFpRbHMzQUpaRGIzczh2Y1VYLzNSYytGUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+UWhLSm1vbnlzUDFxbW5hN1MrZUUxTGMycktBampDMk9HclFPZ1NqUHBUb2N1bVE2aFlIa3pUU1pyN3QvSS9LVE9TdkhDUXFEMXJoNGxTMGpEUC9FdUhOQUN0azlZN2xsMlV5Z3U3MkwrYkZ0cVoyOURuOXJMa1NkR3JpK0k3SGh4TDM2N2RmQVNTaDYrc3k3V2V2RWRrTWZ3ZURRMkFYL3NhNkJCR2d6N1RFPTwvZHM6U2lnbmF0dXJlVmFsdWU+DQo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDR3pDQ0FZUUNDUUNOTmNRWG9tMzJWREFOQmdrcWhraUc5dzBCQVFVRkFEQlNNUXN3Q1FZRFZRUUdFd0pWVXpFTE1Ba0dBMVVFQ0JNQ1NVNHhGVEFUQmdOVkJBY1RERWx1WkdsaGJtRndiMnhwY3pFUk1BOEdBMVVFQ2hNSVQyNWxURzluYVc0eEREQUtCZ05WQkFzVEEwVnVaekFlRncweE5EQTBNak14T0RReE1ERmFGdzB4TlRBME1qTXhPRFF4TURGYU1GSXhDekFKQmdOVkJBWVRBbFZUTVFzd0NRWURWUVFJRXdKSlRqRVZNQk1HQTFVRUJ4TU1TVzVrYVdGdVlYQnZiR2x6TVJFd0R3WURWUVFLRXdoUGJtVk1iMmRwYmpFTU1Bb0dBMVVFQ3hNRFJXNW5NSUdmTUEwR0NTcUdTSWIzRFFFQkFRVUFBNEdOQURDQmlRS0JnUURvNm0rUVp2WVEveEwwRWxMZ3VwSzFRRGNZTDRmNVBja3dzTmdTOXBVdlY3ZnpUcUNIazhUaEx4VGs0Mk1RMk1jSnNPZVVKVlA3MjhLaHltakZDcXhnUDRWdXdSazlycEFsMCttaHk2TVBkeWp5QTZHMTRqckRXUzY1eXNMY2hLNHQvdndwRUR6MFNRbEVvRzFrTXpsbFNtN3paUzNYcmVnQTdEak5hVVlRcXdJREFRQUJNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0R0JBTE0ydkdDaVEvdm0rYTZ2NDArVlgyemRxSEEyUS8xdkYxaWJReko1NE1KQ09WV3ZzK3ZRWGZaRmhkbTBPUE0ySXJEVTdvcXZLUHFQNnhPQWVKSzZIMHlQN000WUwzZmF0U3ZJWW1tZnlYQzlrdDNTdnovTnlySHpQaFVuSjB5ZS9zVVNYeG56UXh3Y20vOVB3QXFyUWFBM1FwUWtINTd5YkYvT29yeVBlKzJoPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgVmVyc2lvbj0iMi4wIiBJRD0icGZ4OTUxNmIwZjMtNDUzNi0xMGY2LWM2ZmEtOWRkNTIzZTE0OThjIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9hcHAub25lbG9naW4uY29tL3NhbWwyPC9zYW1sOklzc3Vlcj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+dGVzdEBvbmVsb2dpbi5jb208IVtDREFUQVsuZXZpbC5jb21dXT48L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwMzAtMDYtMDRUMDI6Mjc6MDJaIiBSZWNpcGllbnQ9InJlY2lwaWVudCIvPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDExLTA2LTA0VDAyOjE3OjAyWiIgTm90T25PckFmdGVyPSIyMDMwLTA2LTA0VDAyOjI3OjAyWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL3NvbWVvbmUuZXhhbXBsZS5jb20vYXVkaWVuY2U8L3NhbWw6QXVkaWVuY2U+PC9zYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PC9zYW1sOkNvbmRpdGlvbnM+PHNhbWw6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTA2LTA0VDAyOjIyOjAyWiIgU2Vzc2lvbk5vdE9uT3JBZnRlcj0iMjAzMC0wNi0wNVQwMjoyMjowMloiIFNlc3Npb25JbmRleD0iXzE2ZjU3MGZiYzAzMTUwMDdhMDM1NWRmZWE2YjNjNDZjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==
|
@@ -37,6 +37,20 @@ class SloLogoutresponseTest < Minitest::Test
|
|
37
37
|
assert_match /&RelayState=http%3A%2F%2Fidp.example.com$/, unauth_url
|
38
38
|
end
|
39
39
|
|
40
|
+
it "RelayState cases" do
|
41
|
+
unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request.id, nil, { :RelayState => nil })
|
42
|
+
assert !unauth_url.include?('RelayState')
|
43
|
+
|
44
|
+
unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request.id, nil, { :RelayState => "http://example.com" })
|
45
|
+
assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
46
|
+
|
47
|
+
unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request.id, nil, { 'RelayState' => nil })
|
48
|
+
assert !unauth_url.include?('RelayState')
|
49
|
+
|
50
|
+
unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request.id, nil, { 'RelayState' => "http://example.com" })
|
51
|
+
assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
|
52
|
+
end
|
53
|
+
|
40
54
|
it "set InResponseTo to the ID from the logout request" do
|
41
55
|
unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request.id)
|
42
56
|
|
data/test/test_helper.rb
CHANGED
@@ -117,15 +117,15 @@ class Minitest::Test
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def signed_message_encrypted_unsigned_assertion
|
120
|
-
@signed_message_encrypted_unsigned_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'signed_message_encrypted_unsigned_assertion.xml.base64'))
|
120
|
+
@signed_message_encrypted_unsigned_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'signed_message_encrypted_unsigned_assertion.xml.base64'))
|
121
121
|
end
|
122
122
|
|
123
123
|
def signed_message_encrypted_signed_assertion
|
124
|
-
@signed_message_encrypted_signed_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'signed_message_encrypted_signed_assertion.xml.base64'))
|
124
|
+
@signed_message_encrypted_signed_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'signed_message_encrypted_signed_assertion.xml.base64'))
|
125
125
|
end
|
126
126
|
|
127
127
|
def unsigned_message_encrypted_signed_assertion
|
128
|
-
@unsigned_message_encrypted_signed_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'unsigned_message_encrypted_signed_assertion.xml.base64'))
|
128
|
+
@unsigned_message_encrypted_signed_assertion ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'unsigned_message_encrypted_signed_assertion.xml.base64'))
|
129
129
|
end
|
130
130
|
|
131
131
|
def unsigned_message_encrypted_unsigned_assertion
|
@@ -145,7 +145,7 @@ class Minitest::Test
|
|
145
145
|
end
|
146
146
|
|
147
147
|
# certificate used on response_with_undefined_recipient
|
148
|
-
def signature_1
|
148
|
+
def signature_1
|
149
149
|
@signature1 ||= read_certificate("certificate1")
|
150
150
|
end
|
151
151
|
|
@@ -166,6 +166,10 @@ class Minitest::Test
|
|
166
166
|
@idp_metadata_descriptor3 ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'idp_descriptor_3.xml'))
|
167
167
|
end
|
168
168
|
|
169
|
+
def idp_metadata_descriptor4
|
170
|
+
@idp_metadata_descriptor4 ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'idp_descriptor_4.xml'))
|
171
|
+
end
|
172
|
+
|
169
173
|
def no_idp_metadata_descriptor
|
170
174
|
@no_idp_metadata_descriptor ||= File.read(File.join(File.dirname(__FILE__), 'metadata', 'no_idp_descriptor.xml'))
|
171
175
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-saml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OneLogin LLC
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -220,6 +220,7 @@ files:
|
|
220
220
|
- test/metadata/idp_descriptor.xml
|
221
221
|
- test/metadata/idp_descriptor_2.xml
|
222
222
|
- test/metadata/idp_descriptor_3.xml
|
223
|
+
- test/metadata/idp_descriptor_4.xml
|
223
224
|
- test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml
|
224
225
|
- test/metadata/idp_metadata_multi_certs.xml
|
225
226
|
- test/metadata/idp_metadata_multi_signing_certs.xml
|
@@ -278,6 +279,8 @@ files:
|
|
278
279
|
- test/responses/response_eval.xml
|
279
280
|
- test/responses/response_no_cert_and_encrypted_attrs.xml
|
280
281
|
- test/responses/response_node_text_attack.xml.base64
|
282
|
+
- test/responses/response_node_text_attack2.xml.base64
|
283
|
+
- test/responses/response_node_text_attack3.xml.base64
|
281
284
|
- test/responses/response_unsigned_xml_base64
|
282
285
|
- test/responses/response_with_ampersands.xml
|
283
286
|
- test/responses/response_with_ampersands.xml.base64
|
@@ -377,6 +380,7 @@ test_files:
|
|
377
380
|
- test/metadata/idp_descriptor.xml
|
378
381
|
- test/metadata/idp_descriptor_2.xml
|
379
382
|
- test/metadata/idp_descriptor_3.xml
|
383
|
+
- test/metadata/idp_descriptor_4.xml
|
380
384
|
- test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml
|
381
385
|
- test/metadata/idp_metadata_multi_certs.xml
|
382
386
|
- test/metadata/idp_metadata_multi_signing_certs.xml
|
@@ -435,6 +439,8 @@ test_files:
|
|
435
439
|
- test/responses/response_eval.xml
|
436
440
|
- test/responses/response_no_cert_and_encrypted_attrs.xml
|
437
441
|
- test/responses/response_node_text_attack.xml.base64
|
442
|
+
- test/responses/response_node_text_attack2.xml.base64
|
443
|
+
- test/responses/response_node_text_attack3.xml.base64
|
438
444
|
- test/responses/response_unsigned_xml_base64
|
439
445
|
- test/responses/response_with_ampersands.xml
|
440
446
|
- test/responses/response_with_ampersands.xml.base64
|