ruby-saml 1.5.0 → 1.6.0
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 +4 -4
- data/README.md +31 -4
- data/changelog.md +7 -0
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +1 -1
- data/lib/onelogin/ruby-saml/logoutresponse.rb +11 -5
- data/lib/onelogin/ruby-saml/metadata.rb +6 -6
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +47 -5
- data/lib/onelogin/ruby-saml/utils.rb +56 -5
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/test/certificates/formatted_chained_certificate +42 -0
- data/test/certificates/invalid_chained_certificate1 +1 -0
- data/test/logout_requests/slo_request_with_name_id_format.xml +4 -0
- data/test/logoutresponse_test.rb +74 -0
- data/test/metadata_test.rb +12 -12
- data/test/slo_logoutrequest_test.rb +80 -0
- data/test/test_helper.rb +9 -0
- data/test/utils_test.rb +13 -4
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39c30acdf4c50284b1112ea62b2be51c412cea9c
|
4
|
+
data.tar.gz: beeb518c01d3bb6d0b871a9909e7ab52f418eb4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 387733f9fc5979968ec493dd2e961969925470ad5c2882a5b4e96266cac027d001a4ce5e11139948e5f2bef1f6cb1bbd436c617e3399fb605958ad76b9e93db5
|
7
|
+
data.tar.gz: ceeb701e8fe82826a20a1768406088cfd2a8f90f3970d95e6c79ca70cc609dac9072dfe58000f88cd8502e3e025fd1948fef0754d63387f0f922fe7fc1d53c39
|
data/README.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Ruby SAML [](http://travis-ci.org/onelogin/ruby-saml) [](https://coveralls.io/r/onelogin/ruby-saml?branch=master%0A) [](http://badge.fury.io/rb/ruby-saml)
|
2
2
|
|
3
|
+
## Updating from 1.5.0 to 1.6.0
|
4
|
+
|
5
|
+
Version `1.6.0` changes the preferred way to construct instances of `Logoutresponse` and `SloLogoutrequest`. Previously the _SAMLResponse_, _RelayState_, and _SigAlg_ parameters of these message types were provided via the constructor's `options[:get_params]` parameter. Unfortunately this can result in incompatibility with other SAML implementations; signatures are specified to be computed based on the _sender's_ URI-encoding of the message, which can differ from that of Ruby SAML. In particular, Ruby SAML's URI-encoding does not match that of Microsoft ADFS, so messages from ADFS can fail signature validation.
|
6
|
+
|
7
|
+
The new preferred way to provide _SAMLResponse_, _RelayState_, and _SigAlg_ is via the `options[:raw_get_params]` parameter. For example:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# In this example `query_params` is assumed to contain decoded query parameters,
|
11
|
+
# and `raw_query_params` is assumed to contain encoded query parameters as sent by the IDP.
|
12
|
+
settings = {
|
13
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
14
|
+
settings.soft = false
|
15
|
+
}
|
16
|
+
options = {
|
17
|
+
get_params: {
|
18
|
+
"Signature" => query_params["Signature"],
|
19
|
+
},
|
20
|
+
raw_get_params: {
|
21
|
+
"SAMLRequest" => raw_query_params["SAMLRequest"],
|
22
|
+
"SigAlg" => raw_query_params["SigAlg"],
|
23
|
+
"RelayState" => raw_query_params["RelayState"],
|
24
|
+
},
|
25
|
+
}
|
26
|
+
slo_logout_request = OneLogin::RubySaml::SloLogoutrequest.new(query_params["SAMLRequest"], settings, options)
|
27
|
+
raise "Invalid Logout Request" unless slo_logout_request.is_valid?
|
28
|
+
```
|
29
|
+
|
30
|
+
The old form is still supported for backward compatibility, but all Ruby SAML users should prefer `options[:raw_get_params]` where possible to ensure compatibility with other SAML implementations.
|
31
|
+
|
3
32
|
## Updating from 1.4.2 to 1.4.3
|
4
33
|
|
5
34
|
Version `1.4.3` introduces Recipient validation of SubjectConfirmation elements.
|
@@ -470,10 +499,8 @@ The settings related to sign are stored in the `security` attribute of the setti
|
|
470
499
|
```ruby
|
471
500
|
settings.security[:authn_requests_signed] = true # Enable or not signature on AuthNRequest
|
472
501
|
settings.security[:logout_requests_signed] = true # Enable or not signature on Logout Request
|
473
|
-
settings.security[:logout_responses_signed] = true # Enable or not
|
474
|
-
|
475
|
-
settings.security[:want_assertions_signed] = true # Enable or not
|
476
|
-
the requirement of signed assertion
|
502
|
+
settings.security[:logout_responses_signed] = true # Enable or not signature on Logout Response
|
503
|
+
settings.security[:want_assertions_signed] = true # Enable or not the requirement of signed assertion
|
477
504
|
settings.security[:metadata_signed] = true # Enable or not signature on Metadata
|
478
505
|
|
479
506
|
settings.security[:digest_method] = XMLSecurity::Document::SHA1
|
data/changelog.md
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
# RubySaml Changelog
|
2
|
+
### 1.6.0 (November 27, 2017)
|
3
|
+
* [#418](https://github.com/onelogin/ruby-saml/pull/418) Improve SAML message signature validation using original encoded parameters instead decoded in order to avoid conflicts (URL-encoding is not canonical, reported issues with ADFS)
|
4
|
+
* [#420](https://github.com/onelogin/ruby-saml/pull/420) Expose NameID Format on SloLogoutrequest
|
5
|
+
* [#423](https://github.com/onelogin/ruby-saml/pull/423) Allow format_cert to work with chained certificates
|
6
|
+
* [#422](https://github.com/onelogin/ruby-saml/pull/422) Use to_s for requested attribute value
|
7
|
+
|
8
|
+
|
2
9
|
### 1.5.0 (August 31, 2017)
|
3
10
|
* [#400](https://github.com/onelogin/ruby-saml/pull/400) When validating Signature use stored IdP certficate if Signature contains no info about Certificate
|
4
11
|
* [#402](https://github.com/onelogin/ruby-saml/pull/402) Fix validate_response_state method that rejected SAMLResponses when using idp_cert_multi and idp_cert and idp_cert_fingerprint were not provided.
|
@@ -103,7 +103,7 @@ module OneLogin
|
|
103
103
|
@entity_descriptor = nil
|
104
104
|
|
105
105
|
if idpsso_descriptor.nil?
|
106
|
-
raise ArgumentError.new("idp_metadata
|
106
|
+
raise ArgumentError.new("idp_metadata must contain an IDPSSODescriptor element")
|
107
107
|
end
|
108
108
|
|
109
109
|
{
|
@@ -211,6 +211,12 @@ module OneLogin
|
|
211
211
|
return true unless options.has_key? :get_params
|
212
212
|
return true unless options[:get_params].has_key? 'Signature'
|
213
213
|
|
214
|
+
options[:raw_get_params] = OneLogin::RubySaml::Utils.prepare_raw_get_params(options[:raw_get_params], options[:get_params])
|
215
|
+
|
216
|
+
if options[:get_params]['SigAlg'].nil? && !options[:raw_get_params]['SigAlg'].nil?
|
217
|
+
options[:get_params]['SigAlg'] = CGI.unescape(options[:raw_get_params]['SigAlg'])
|
218
|
+
end
|
219
|
+
|
214
220
|
idp_cert = settings.get_idp_cert
|
215
221
|
idp_certs = settings.get_idp_cert_multi
|
216
222
|
|
@@ -218,11 +224,11 @@ module OneLogin
|
|
218
224
|
return options.has_key? :relax_signature_validation
|
219
225
|
end
|
220
226
|
|
221
|
-
query_string = OneLogin::RubySaml::Utils.
|
222
|
-
:type
|
223
|
-
:
|
224
|
-
:
|
225
|
-
:
|
227
|
+
query_string = OneLogin::RubySaml::Utils.build_query_from_raw_parts(
|
228
|
+
:type => 'SAMLResponse',
|
229
|
+
:raw_data => options[:raw_get_params]['SAMLResponse'],
|
230
|
+
:raw_relay_state => options[:raw_get_params]['RelayState'],
|
231
|
+
:raw_sig_alg => options[:raw_get_params]['SigAlg']
|
226
232
|
)
|
227
233
|
|
228
234
|
if idp_certs.nil? || idp_certs[:signing].empty?
|
@@ -8,12 +8,12 @@ module OneLogin
|
|
8
8
|
module RubySaml
|
9
9
|
|
10
10
|
# SAML2 Metadata. XML Metadata Builder
|
11
|
-
#
|
11
|
+
#
|
12
12
|
class Metadata
|
13
13
|
|
14
14
|
# Return SP metadata based on the settings.
|
15
15
|
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
16
|
-
# @param pretty_print [Boolean] Pretty print or not the response
|
16
|
+
# @param pretty_print [Boolean] Pretty print or not the response
|
17
17
|
# (No pretty print if you gonna validate the signature)
|
18
18
|
# @return [String] XML Metadata of the Service Provider
|
19
19
|
#
|
@@ -83,7 +83,7 @@ module OneLogin
|
|
83
83
|
if settings.attribute_consuming_service.configured?
|
84
84
|
sp_acs = sp_sso.add_element "md:AttributeConsumingService", {
|
85
85
|
"isDefault" => "true",
|
86
|
-
"index" => settings.attribute_consuming_service.index
|
86
|
+
"index" => settings.attribute_consuming_service.index
|
87
87
|
}
|
88
88
|
srv_name = sp_acs.add_element "md:ServiceName", {
|
89
89
|
"xml:lang" => "en"
|
@@ -92,14 +92,14 @@ module OneLogin
|
|
92
92
|
settings.attribute_consuming_service.attributes.each do |attribute|
|
93
93
|
sp_req_attr = sp_acs.add_element "md:RequestedAttribute", {
|
94
94
|
"NameFormat" => attribute[:name_format],
|
95
|
-
"Name" => attribute[:name],
|
95
|
+
"Name" => attribute[:name],
|
96
96
|
"FriendlyName" => attribute[:friendly_name],
|
97
97
|
"isRequired" => attribute[:is_required] || false
|
98
98
|
}
|
99
99
|
unless attribute[:attribute_value].nil?
|
100
100
|
Array(attribute[:attribute_value]).each do |value|
|
101
101
|
sp_attr_val = sp_req_attr.add_element "saml:AttributeValue"
|
102
|
-
sp_attr_val.text = value.
|
102
|
+
sp_attr_val.text = value.to_s
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -121,7 +121,7 @@ module OneLogin
|
|
121
121
|
# pretty print the XML so IdP administrators can easily see what the SP supports
|
122
122
|
if pretty_print
|
123
123
|
meta_doc.write(ret, 1)
|
124
|
-
else
|
124
|
+
else
|
125
125
|
ret = meta_doc.to_s
|
126
126
|
end
|
127
127
|
|
@@ -66,6 +66,18 @@ module OneLogin
|
|
66
66
|
|
67
67
|
alias_method :nameid, :name_id
|
68
68
|
|
69
|
+
# @return [String] Gets the NameID Format of the Logout Request.
|
70
|
+
#
|
71
|
+
def name_id_format
|
72
|
+
@name_id_node ||= REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
|
73
|
+
@name_id_format ||=
|
74
|
+
if @name_id_node && @name_id_node.attribute("Format")
|
75
|
+
@name_id_node.attribute("Format").value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method :nameid_format, :name_id_format
|
80
|
+
|
69
81
|
# @return [String|nil] Gets the ID attribute from the Logout Request. if exists.
|
70
82
|
#
|
71
83
|
def id
|
@@ -229,6 +241,36 @@ module OneLogin
|
|
229
241
|
return true unless options.has_key? :get_params
|
230
242
|
return true unless options[:get_params].has_key? 'Signature'
|
231
243
|
|
244
|
+
# SAML specifies that the signature should be derived from a concatenation
|
245
|
+
# of URI-encoded values _as sent by the IDP_:
|
246
|
+
#
|
247
|
+
# > Further, note that URL-encoding is not canonical; that is, there are multiple legal encodings for a given
|
248
|
+
# > value. The relying party MUST therefore perform the verification step using the original URL-encoded
|
249
|
+
# > values it received on the query string. It is not sufficient to re-encode the parameters after they have been
|
250
|
+
# > processed by software because the resulting encoding may not match the signer's encoding.
|
251
|
+
#
|
252
|
+
# <http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf>
|
253
|
+
#
|
254
|
+
# If we don't have the original parts (for backward compatibility) required to correctly verify the signature,
|
255
|
+
# then fabricate them by re-encoding the parsed URI parameters, and hope that we're lucky enough to use
|
256
|
+
# the exact same URI-encoding as the IDP. (This is not the case if the IDP is ADFS!)
|
257
|
+
options[:raw_get_params] ||= {}
|
258
|
+
if options[:raw_get_params]['SAMLRequest'].nil? && !options[:get_params]['SAMLRequest'].nil?
|
259
|
+
options[:raw_get_params]['SAMLRequest'] = CGI.escape(options[:get_params]['SAMLRequest'])
|
260
|
+
end
|
261
|
+
if options[:raw_get_params]['RelayState'].nil? && !options[:get_params]['RelayState'].nil?
|
262
|
+
options[:raw_get_params]['RelayState'] = CGI.escape(options[:get_params]['RelayState'])
|
263
|
+
end
|
264
|
+
if options[:raw_get_params]['SigAlg'].nil? && !options[:get_params]['SigAlg'].nil?
|
265
|
+
options[:raw_get_params]['SigAlg'] = CGI.escape(options[:get_params]['SigAlg'])
|
266
|
+
end
|
267
|
+
|
268
|
+
# If we only received the raw version of SigAlg,
|
269
|
+
# then parse it back into the decoded params hash for convenience.
|
270
|
+
if options[:get_params]['SigAlg'].nil? && !options[:raw_get_params]['SigAlg'].nil?
|
271
|
+
options[:get_params]['SigAlg'] = CGI.unescape(options[:raw_get_params]['SigAlg'])
|
272
|
+
end
|
273
|
+
|
232
274
|
idp_cert = settings.get_idp_cert
|
233
275
|
idp_certs = settings.get_idp_cert_multi
|
234
276
|
|
@@ -236,11 +278,11 @@ module OneLogin
|
|
236
278
|
return options.has_key? :relax_signature_validation
|
237
279
|
end
|
238
280
|
|
239
|
-
query_string = OneLogin::RubySaml::Utils.
|
240
|
-
:type
|
241
|
-
:
|
242
|
-
:
|
243
|
-
:
|
281
|
+
query_string = OneLogin::RubySaml::Utils.build_query_from_raw_parts(
|
282
|
+
:type => 'SAMLRequest',
|
283
|
+
:raw_data => options[:raw_get_params]['SAMLRequest'],
|
284
|
+
:raw_relay_state => options[:raw_get_params]['RelayState'],
|
285
|
+
:raw_sig_alg => options[:raw_get_params]['SigAlg']
|
244
286
|
)
|
245
287
|
|
246
288
|
if idp_certs.nil? || idp_certs[:signing].empty?
|
@@ -24,11 +24,19 @@ module OneLogin
|
|
24
24
|
# don't try to format an encoded certificate or if is empty or nil
|
25
25
|
return cert if cert.nil? || cert.empty? || cert.match(/\x0d/)
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
if cert.scan(/BEGIN CERTIFICATE/).length > 1
|
28
|
+
formatted_cert = []
|
29
|
+
cert.scan(/-{5}BEGIN CERTIFICATE-{5}[\n\r]?.*?-{5}END CERTIFICATE-{5}[\n\r]?/m) {|c|
|
30
|
+
formatted_cert << format_cert(c)
|
31
|
+
}
|
32
|
+
formatted_cert.join("\n")
|
33
|
+
else
|
34
|
+
cert = cert.gsub(/\-{5}\s?(BEGIN|END) CERTIFICATE\s?\-{5}/, "")
|
35
|
+
cert = cert.gsub(/[\n\r\s]/, "")
|
36
|
+
cert = cert.scan(/.{1,64}/)
|
37
|
+
cert = cert.join("\n")
|
38
|
+
"-----BEGIN CERTIFICATE-----\n#{cert}\n-----END CERTIFICATE-----"
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
# Return a properly formatted private key
|
@@ -67,6 +75,49 @@ module OneLogin
|
|
67
75
|
url_string << "&SigAlg=#{CGI.escape(sig_alg)}"
|
68
76
|
end
|
69
77
|
|
78
|
+
# Reconstruct a canonical query string from raw URI-encoded parts, to be used in verifying a signature
|
79
|
+
#
|
80
|
+
# @param params [Hash] Parameters to build the Query String
|
81
|
+
# @option params [String] :type 'SAMLRequest' or 'SAMLResponse'
|
82
|
+
# @option params [String] :raw_data URI-encoded, base64 encoded SAMLRequest or SAMLResponse, as sent by IDP
|
83
|
+
# @option params [String] :raw_relay_state URI-encoded RelayState parameter, as sent by IDP
|
84
|
+
# @option params [String] :raw_sig_alg URI-encoded SigAlg parameter, as sent by IDP
|
85
|
+
# @return [String] The Query String
|
86
|
+
#
|
87
|
+
def self.build_query_from_raw_parts(params)
|
88
|
+
type, raw_data, raw_relay_state, raw_sig_alg = [:type, :raw_data, :raw_relay_state, :raw_sig_alg].map { |k| params[k]}
|
89
|
+
|
90
|
+
url_string = "#{type}=#{raw_data}"
|
91
|
+
url_string << "&RelayState=#{raw_relay_state}" if raw_relay_state
|
92
|
+
url_string << "&SigAlg=#{raw_sig_alg}"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Prepare raw GET parameters (build them from normal parameters
|
96
|
+
# if not provided).
|
97
|
+
#
|
98
|
+
# @param rawparams [Hash] Raw GET Parameters
|
99
|
+
# @param params [Hash] GET Parameters
|
100
|
+
# @return [Hash] New raw parameters
|
101
|
+
#
|
102
|
+
def self.prepare_raw_get_params(rawparams, params)
|
103
|
+
rawparams ||= {}
|
104
|
+
|
105
|
+
if rawparams['SAMLRequest'].nil? && !params['SAMLRequest'].nil?
|
106
|
+
rawparams['SAMLRequest'] = CGI.escape(params['SAMLRequest'])
|
107
|
+
end
|
108
|
+
if rawparams['SAMLResponse'].nil? && !params['SAMLResponse'].nil?
|
109
|
+
rawparams['SAMLResponse'] = CGI.escape(params['SAMLResponse'])
|
110
|
+
end
|
111
|
+
if rawparams['RelayState'].nil? && !params['RelayState'].nil?
|
112
|
+
rawparams['RelayState'] = CGI.escape(params['RelayState'])
|
113
|
+
end
|
114
|
+
if rawparams['SigAlg'].nil? && !params['SigAlg'].nil?
|
115
|
+
rawparams['SigAlg'] = CGI.escape(params['SigAlg'])
|
116
|
+
end
|
117
|
+
|
118
|
+
rawparams
|
119
|
+
end
|
120
|
+
|
70
121
|
# Validate the Signature parameter sent on the HTTP-Redirect binding
|
71
122
|
# @param params [Hash] Parameters to be used in the validation process
|
72
123
|
# @option params [OpenSSL::X509::Certificate] cert The Identity provider public certtificate
|
@@ -0,0 +1,42 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICPDCCAaWgAwIBAgIIEiC/9HMAWWAwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UE
|
3
|
+
BhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVh
|
4
|
+
MDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIx
|
5
|
+
wsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNz
|
6
|
+
c28xJDAiBgNVBAMTG2MyNWEwMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkq
|
7
|
+
hkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jC
|
8
|
+
mdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpw
|
9
|
+
Vvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N
|
10
|
+
4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0G
|
11
|
+
CSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ
|
12
|
+
+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/1
|
13
|
+
2Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ
|
14
|
+
-----END CERTIFICATE-----
|
15
|
+
-----BEGIN CERTIFICATE-----
|
16
|
+
MIICPDCCAaWgAwIBAgIIEiC/9HMAWWAwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UE
|
17
|
+
BhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVh
|
18
|
+
MDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIx
|
19
|
+
wsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNz
|
20
|
+
c28xJDAiBgNVBAMTG2MyNWEwMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkq
|
21
|
+
hkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jC
|
22
|
+
mdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpw
|
23
|
+
Vvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N
|
24
|
+
4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0G
|
25
|
+
CSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ
|
26
|
+
+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/1
|
27
|
+
2Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ
|
28
|
+
-----END CERTIFICATE-----
|
29
|
+
-----BEGIN CERTIFICATE-----
|
30
|
+
MIICPDCCAaWgAwIBAgIIEiC/9HMAWWAwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UE
|
31
|
+
BhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVh
|
32
|
+
MDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIx
|
33
|
+
wsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNz
|
34
|
+
c28xJDAiBgNVBAMTG2MyNWEwMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkq
|
35
|
+
hkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jC
|
36
|
+
mdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpw
|
37
|
+
Vvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N
|
38
|
+
4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0G
|
39
|
+
CSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ
|
40
|
+
+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/1
|
41
|
+
2Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ
|
42
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----MIICPDCCAaWgAwIBAgIIEiC/9HMAWW AwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UEBhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVhMDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIxwsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNzc28xJDAiBgNVBAMTG2MyNWE wMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jCmdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpwVvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0GCSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/12Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ-----END CERTIFICATE----------BEGIN CERTIFICATE-----MIICPDCCAaWgAw IBAgIIEiC/9HMAWWAwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UEBhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVhMDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIxwsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNzc28xJDAiBgNVBAMTG2MyNWEwMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jCmdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpwVvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0GCSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/12Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ-----END CERTIFICATE----------BEGIN CERTIFICATE-----MIICPDCCAaWgAwIBAgIIEiC/9HMAWWAwDQYJKoZIhvcNAQEFBQAwTzELMAkGA1UEBhMCVVMxDDAKBgNVBAoTA2libTEMMAoGA1UECxMDc3NvMSQwIgYDVQQDExtjMjVhMDI3Ny50b3JvbnRvLmNhLmlibS5jb20wHhcNMTEwNTI0MTYzNTQ4WhcNMjEwNTIxwsQMPBj4WQTNzTYMCQYDVQQGEwJVUzEMMAoGA1UEChMDaWJtMQwwCgYDVQQLEwNzc28xJDAiBgNVBAMTG2MyNWEwMjc3LnRvcm9udG8uY2EuaWJtLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAgzfYQZuf5FVdJTcrsIQZ+YHTPjOsw2MGo0jCmdGMcp4brWeFgk1OVaOmytPx6P76wHWR436AleX3crHBPd8gPxuZdnvBQ7PkrKpwVvaq52juenFrho8JY0TeVgVkY5jAh45YzytjP2y2k/cGQurI/56NT0PpQJ0S1G3N4eTg718CAwEAAaMhMB8wHQYDVR0OBBYEFCYVLJqcJ7WgdzGIsuJ/TzDGDqinMA0GCSqGSIb3DQEBBQUAA4GBAB80bIePf+qWDvWe+9bEEnbFTw7pCknLexxZ0AMqrsmZ+4jmI+evP1JZYCjfIg9X+MBH01hfp5dFcetz3o6w6SkV+BxLYLgfcy5KUcYsIM/12Zkedj87bS1glzOy5B89pKD2DMbu6828Abzgc+4lyQ2ASifsqM4cZdVayzo8n+dQ-----END CERTIFICATE-----
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<samlp:LogoutRequest Version='2.0' ID='_c0348950-935b-0131-1060-782bcb56fcaa' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol' IssueInstant='2014-03-21T19:20:13'>
|
2
|
+
<saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
|
3
|
+
<saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion' Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'>someone@example.org</saml:NameID>
|
4
|
+
</samlp:LogoutRequest>
|
data/test/logoutresponse_test.rb
CHANGED
@@ -283,6 +283,80 @@ class RubySamlTest < Minitest::Test
|
|
283
283
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.send(:validate_signature) }
|
284
284
|
assert logoutresponse.errors.include? "Invalid Signature on Logout Response"
|
285
285
|
end
|
286
|
+
|
287
|
+
it "raise when get_params encoding differs from what this library generates" do
|
288
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
289
|
+
settings.soft = false
|
290
|
+
options = {}
|
291
|
+
options[:get_params] = params
|
292
|
+
options[:get_params]['RelayState'] = 'http://example.com'
|
293
|
+
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
|
294
|
+
# Assemble query string.
|
295
|
+
query = OneLogin::RubySaml::Utils.build_query(
|
296
|
+
:type => 'SAMLResponse',
|
297
|
+
:data => params['SAMLResponse'],
|
298
|
+
:relay_state => params['RelayState'],
|
299
|
+
:sig_alg => params['SigAlg']
|
300
|
+
)
|
301
|
+
# Modify the query string so that it encodes the same values,
|
302
|
+
# but with different percent-encoding. Sanity-check that they
|
303
|
+
# really are equialent before moving on.
|
304
|
+
original_query = query.dup
|
305
|
+
query.gsub!("example", "ex%61mple")
|
306
|
+
refute_equal(query, original_query)
|
307
|
+
assert_equal(CGI.unescape(query), CGI.unescape(original_query))
|
308
|
+
# Make normalised signature based on our modified params.
|
309
|
+
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
310
|
+
signature = settings.get_sp_key.sign(sign_algorithm.new, query)
|
311
|
+
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
312
|
+
# Re-create the Logoutresponse based on these modified parameters,
|
313
|
+
# and ask it to validate the signature. It will do it incorrectly,
|
314
|
+
# because it will compute it based on re-encoded query parameters,
|
315
|
+
# rather than their original encodings.
|
316
|
+
options[:get_params] = params
|
317
|
+
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
|
318
|
+
assert_raises(OneLogin::RubySaml::ValidationError, "Invalid Signature on Logout Request") do
|
319
|
+
logoutresponse.send(:validate_signature)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
it "return true even if raw_get_params encoding differs from what this library generates" do
|
324
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
325
|
+
settings.soft = false
|
326
|
+
options = {}
|
327
|
+
options[:get_params] = params
|
328
|
+
options[:get_params]['RelayState'] = 'http://example.com'
|
329
|
+
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
|
330
|
+
# Assemble query string.
|
331
|
+
query = OneLogin::RubySaml::Utils.build_query(
|
332
|
+
:type => 'SAMLResponse',
|
333
|
+
:data => params['SAMLResponse'],
|
334
|
+
:relay_state => params['RelayState'],
|
335
|
+
:sig_alg => params['SigAlg']
|
336
|
+
)
|
337
|
+
# Modify the query string so that it encodes the same values,
|
338
|
+
# but with different percent-encoding. Sanity-check that they
|
339
|
+
# really are equialent before moving on.
|
340
|
+
original_query = query.dup
|
341
|
+
query.gsub!("example", "ex%61mple")
|
342
|
+
refute_equal(query, original_query)
|
343
|
+
assert_equal(CGI.unescape(query), CGI.unescape(original_query))
|
344
|
+
# Make normalised signature based on our modified params.
|
345
|
+
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
346
|
+
signature = settings.get_sp_key.sign(sign_algorithm.new, query)
|
347
|
+
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
348
|
+
# Re-create the Logoutresponse based on these modified parameters,
|
349
|
+
# and ask it to validate the signature. Provide the altered parameter
|
350
|
+
# in its raw URI-encoded form, so that we don't have to guess the value
|
351
|
+
# that contributed to the signature.
|
352
|
+
options[:get_params] = params
|
353
|
+
options[:get_params].delete("RelayState")
|
354
|
+
options[:raw_get_params] = {
|
355
|
+
"RelayState" => "http%3A%2F%2Fex%61mple.com",
|
356
|
+
}
|
357
|
+
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
|
358
|
+
assert logoutresponse.send(:validate_signature)
|
359
|
+
end
|
286
360
|
end
|
287
361
|
|
288
362
|
describe "#validate_signature" do
|
data/test/metadata_test.rb
CHANGED
@@ -32,7 +32,7 @@ class MetadataTest < Minitest::Test
|
|
32
32
|
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", REXML::XPath.first(xml_doc, "//md:NameIDFormat").text.strip
|
33
33
|
|
34
34
|
assert_equal "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", acs.attribute("Binding").value
|
35
|
-
assert_equal "https://foo.example/saml/consume", acs.attribute("Location").value
|
35
|
+
assert_equal "https://foo.example/saml/consume", acs.attribute("Location").value
|
36
36
|
|
37
37
|
assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
|
38
38
|
end
|
@@ -225,7 +225,7 @@ class MetadataTest < Minitest::Test
|
|
225
225
|
before do
|
226
226
|
settings.attribute_consuming_service.configure do
|
227
227
|
service_name "Test Service"
|
228
|
-
add_attribute(:name =>
|
228
|
+
add_attribute(:name => 'Name', :name_format => 'Name Format', :friendly_name => 'Friendly Name', :attribute_value => ['Attribute Value One', false])
|
229
229
|
end
|
230
230
|
end
|
231
231
|
|
@@ -240,20 +240,20 @@ class MetadataTest < Minitest::Test
|
|
240
240
|
|
241
241
|
attribute_values = REXML::XPath.match(xml_doc, "//saml:AttributeValue").map(&:text)
|
242
242
|
assert_equal "Attribute Value One", attribute_values[0]
|
243
|
-
assert_equal
|
243
|
+
assert_equal 'false', attribute_values[1]
|
244
244
|
|
245
245
|
assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
|
246
246
|
end
|
247
247
|
end
|
248
248
|
|
249
249
|
describe "when attribute service is configured" do
|
250
|
-
let(:attr_svc)
|
251
|
-
let(:req_attr)
|
250
|
+
let(:attr_svc) { REXML::XPath.first(xml_doc, '//md:AttributeConsumingService') }
|
251
|
+
let(:req_attr) { REXML::XPath.first(xml_doc, '//md:RequestedAttribute') }
|
252
252
|
|
253
253
|
before do
|
254
254
|
settings.attribute_consuming_service.configure do
|
255
255
|
service_name "Test Service"
|
256
|
-
add_attribute(:name =>
|
256
|
+
add_attribute(:name => 'active', :name_format => 'format', :friendly_name => 'Active', :attribute_value => true)
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
@@ -262,10 +262,10 @@ class MetadataTest < Minitest::Test
|
|
262
262
|
assert_equal "1", attr_svc.attribute("index").value
|
263
263
|
assert_equal REXML::XPath.first(xml_doc, "//md:ServiceName").text.strip, "Test Service"
|
264
264
|
|
265
|
-
assert_equal
|
266
|
-
assert_equal
|
267
|
-
assert_equal
|
268
|
-
assert_equal
|
265
|
+
assert_equal 'active', req_attr.attribute('Name').value
|
266
|
+
assert_equal 'format', req_attr.attribute('NameFormat').value
|
267
|
+
assert_equal 'Active', req_attr.attribute('FriendlyName').value
|
268
|
+
assert_equal 'true', REXML::XPath.first(xml_doc, '//saml:AttributeValue').text.strip
|
269
269
|
|
270
270
|
assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
|
271
271
|
end
|
@@ -303,7 +303,7 @@ class MetadataTest < Minitest::Test
|
|
303
303
|
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], xml_text
|
304
304
|
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], xml_text
|
305
305
|
signed_metadata = XMLSecurity::SignedDocument.new(xml_text)
|
306
|
-
assert signed_metadata.validate_document(ruby_saml_cert_fingerprint, false)
|
306
|
+
assert signed_metadata.validate_document(ruby_saml_cert_fingerprint, false)
|
307
307
|
|
308
308
|
assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
|
309
309
|
end
|
@@ -321,7 +321,7 @@ class MetadataTest < Minitest::Test
|
|
321
321
|
|
322
322
|
signed_metadata_2 = XMLSecurity::SignedDocument.new(xml_text)
|
323
323
|
|
324
|
-
assert signed_metadata_2.validate_document(ruby_saml_cert_fingerprint, false)
|
324
|
+
assert signed_metadata_2.validate_document(ruby_saml_cert_fingerprint, false)
|
325
325
|
|
326
326
|
assert validate_xml!(xml_text, "saml-schema-metadata-2.0.xsd")
|
327
327
|
end
|
@@ -91,6 +91,14 @@ class RubySamlTest < Minitest::Test
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
describe "#nameid_format" do
|
95
|
+
let(:logout_request) { OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document_with_name_id_format) }
|
96
|
+
|
97
|
+
it "extract the format attribute of the name id element" do
|
98
|
+
assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", logout_request.nameid_format
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
94
102
|
describe "#issuer" do
|
95
103
|
it "return the issuer inside the logout request" do
|
96
104
|
assert_equal "https://app.onelogin.com/saml/metadata/SOMEACCOUNT", logout_request.issuer
|
@@ -322,6 +330,78 @@ class RubySamlTest < Minitest::Test
|
|
322
330
|
logout_request_sign_test.send(:validate_signature)
|
323
331
|
end
|
324
332
|
end
|
333
|
+
|
334
|
+
it "raise when get_params encoding differs from what this library generates" do
|
335
|
+
# Use Logoutrequest only to build the SAMLRequest parameter.
|
336
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
337
|
+
settings.soft = false
|
338
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, "RelayState" => "http://example.com")
|
339
|
+
# Assemble query string.
|
340
|
+
query = OneLogin::RubySaml::Utils.build_query(
|
341
|
+
:type => 'SAMLRequest',
|
342
|
+
:data => params['SAMLRequest'],
|
343
|
+
:relay_state => params['RelayState'],
|
344
|
+
:sig_alg => params['SigAlg']
|
345
|
+
)
|
346
|
+
# Modify the query string so that it encodes the same values,
|
347
|
+
# but with different percent-encoding. Sanity-check that they
|
348
|
+
# really are equialent before moving on.
|
349
|
+
original_query = query.dup
|
350
|
+
query.gsub!("example", "ex%61mple")
|
351
|
+
refute_equal(query, original_query)
|
352
|
+
assert_equal(CGI.unescape(query), CGI.unescape(original_query))
|
353
|
+
# Make normalised signature based on our modified params.
|
354
|
+
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
355
|
+
signature = settings.get_sp_key.sign(sign_algorithm.new, query)
|
356
|
+
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
357
|
+
# Construct SloLogoutrequest and ask it to validate the signature.
|
358
|
+
# It will do it incorrectly, because it will compute it based on re-encoded
|
359
|
+
# query parameters, rather than their original encodings.
|
360
|
+
options = {}
|
361
|
+
options[:get_params] = params
|
362
|
+
options[:settings] = settings
|
363
|
+
logout_request_sign_test = OneLogin::RubySaml::SloLogoutrequest.new(params['SAMLRequest'], options)
|
364
|
+
assert_raises(OneLogin::RubySaml::ValidationError, "Invalid Signature on Logout Request") do
|
365
|
+
logout_request_sign_test.send(:validate_signature)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
it "return true even if raw_get_params encoding differs from what this library generates" do
|
370
|
+
# Use Logoutrequest only to build the SAMLRequest parameter.
|
371
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
372
|
+
settings.soft = false
|
373
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, "RelayState" => "http://example.com")
|
374
|
+
# Assemble query string.
|
375
|
+
query = OneLogin::RubySaml::Utils.build_query(
|
376
|
+
:type => 'SAMLRequest',
|
377
|
+
:data => params['SAMLRequest'],
|
378
|
+
:relay_state => params['RelayState'],
|
379
|
+
:sig_alg => params['SigAlg']
|
380
|
+
)
|
381
|
+
# Modify the query string so that it encodes the same values,
|
382
|
+
# but with different percent-encoding. Sanity-check that they
|
383
|
+
# really are equialent before moving on.
|
384
|
+
original_query = query.dup
|
385
|
+
query.gsub!("example", "ex%61mple")
|
386
|
+
refute_equal(query, original_query)
|
387
|
+
assert_equal(CGI.unescape(query), CGI.unescape(original_query))
|
388
|
+
# Make normalised signature based on our modified params.
|
389
|
+
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
390
|
+
signature = settings.get_sp_key.sign(sign_algorithm.new, query)
|
391
|
+
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
392
|
+
# Construct SloLogoutrequest and ask it to validate the signature.
|
393
|
+
# Provide the altered parameter in its raw URI-encoded form,
|
394
|
+
# so that we don't have to guess the value that contributed to the signature.
|
395
|
+
options = {}
|
396
|
+
options[:get_params] = params
|
397
|
+
options[:get_params].delete("RelayState")
|
398
|
+
options[:raw_get_params] = {
|
399
|
+
"RelayState" => "http%3A%2F%2Fex%61mple.com",
|
400
|
+
}
|
401
|
+
options[:settings] = settings
|
402
|
+
logout_request_sign_test = OneLogin::RubySaml::SloLogoutrequest.new(params['SAMLRequest'], options)
|
403
|
+
assert logout_request_sign_test.send(:validate_signature)
|
404
|
+
end
|
325
405
|
end
|
326
406
|
|
327
407
|
describe "#validate_signature with multiple idp certs" do
|
data/test/test_helper.rb
CHANGED
@@ -183,6 +183,15 @@ class Minitest::Test
|
|
183
183
|
@logout_request_document
|
184
184
|
end
|
185
185
|
|
186
|
+
def logout_request_document_with_name_id_format
|
187
|
+
unless @logout_request_document_with_name_id_format
|
188
|
+
xml = read_logout_request("slo_request_with_name_id_format.xml")
|
189
|
+
deflated = Zlib::Deflate.deflate(xml, 9)[2..-5]
|
190
|
+
@logout_request_document_with_name_id_format = Base64.encode64(deflated)
|
191
|
+
end
|
192
|
+
@logout_request_document_with_name_id_format
|
193
|
+
end
|
194
|
+
|
186
195
|
def logout_request_xml_with_session_index
|
187
196
|
@logout_request_xml_with_session_index ||= File.read(File.join(File.dirname(__FILE__), 'logout_requests', 'slo_request_with_session_index.xml'))
|
188
197
|
end
|
data/test/utils_test.rb
CHANGED
@@ -2,9 +2,8 @@ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
|
2
2
|
|
3
3
|
class UtilsTest < Minitest::Test
|
4
4
|
describe ".format_cert" do
|
5
|
-
let(:formatted_certificate)
|
6
|
-
|
7
|
-
end
|
5
|
+
let(:formatted_certificate) {read_certificate("formatted_certificate")}
|
6
|
+
let(:formatted_chained_certificate) {read_certificate("formatted_chained_certificate")}
|
8
7
|
|
9
8
|
it "returns empty string when the cert is an empty string" do
|
10
9
|
cert = ""
|
@@ -34,6 +33,16 @@ class UtilsTest < Minitest::Test
|
|
34
33
|
invalid_certificate3 = read_certificate("invalid_certificate3")
|
35
34
|
assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate3)
|
36
35
|
end
|
36
|
+
|
37
|
+
it "returns the chained certificate when it is a valid chained certificate" do
|
38
|
+
assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(formatted_chained_certificate)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "reformats the chained certificate when there are spaces and no line breaks" do
|
42
|
+
invalid_chained_certificate1 = read_certificate("invalid_chained_certificate1")
|
43
|
+
assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_chained_certificate1)
|
44
|
+
end
|
45
|
+
|
37
46
|
end
|
38
47
|
|
39
48
|
describe ".format_private_key" do
|
@@ -138,7 +147,7 @@ class UtilsTest < Minitest::Test
|
|
138
147
|
status_error_msg2 = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code)
|
139
148
|
assert_equal = "The status code of the Logout Response was not Success, was Requester", status_error_msg2
|
140
149
|
|
141
|
-
status_error_msg3 =
|
150
|
+
status_error_msg3 = OneLogin::RubySaml::Utils.status_error_msg(error_msg)
|
142
151
|
assert_equal = "The status code of the Logout Response was not Success", status_error_msg3
|
143
152
|
end
|
144
153
|
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.6.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: 2017-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -190,11 +190,13 @@ files:
|
|
190
190
|
- test/certificates/certificate1
|
191
191
|
- test/certificates/certificate_without_head_foot
|
192
192
|
- test/certificates/formatted_certificate
|
193
|
+
- test/certificates/formatted_chained_certificate
|
193
194
|
- test/certificates/formatted_private_key
|
194
195
|
- test/certificates/formatted_rsa_private_key
|
195
196
|
- test/certificates/invalid_certificate1
|
196
197
|
- test/certificates/invalid_certificate2
|
197
198
|
- test/certificates/invalid_certificate3
|
199
|
+
- test/certificates/invalid_chained_certificate1
|
198
200
|
- test/certificates/invalid_private_key1
|
199
201
|
- test/certificates/invalid_private_key2
|
200
202
|
- test/certificates/invalid_private_key3
|
@@ -210,6 +212,7 @@ files:
|
|
210
212
|
- test/logout_requests/slo_request.xml
|
211
213
|
- test/logout_requests/slo_request.xml.base64
|
212
214
|
- test/logout_requests/slo_request_deflated.xml.base64
|
215
|
+
- test/logout_requests/slo_request_with_name_id_format.xml
|
213
216
|
- test/logout_requests/slo_request_with_session_index.xml
|
214
217
|
- test/logout_responses/logoutresponse_fixtures.rb
|
215
218
|
- test/logoutrequest_test.rb
|
@@ -330,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
330
333
|
version: '0'
|
331
334
|
requirements: []
|
332
335
|
rubyforge_project: http://www.rubygems.org/gems/ruby-saml
|
333
|
-
rubygems_version: 2.
|
336
|
+
rubygems_version: 2.4.8
|
334
337
|
signing_key:
|
335
338
|
specification_version: 4
|
336
339
|
summary: SAML Ruby Tookit
|
@@ -338,11 +341,13 @@ test_files:
|
|
338
341
|
- test/certificates/certificate1
|
339
342
|
- test/certificates/certificate_without_head_foot
|
340
343
|
- test/certificates/formatted_certificate
|
344
|
+
- test/certificates/formatted_chained_certificate
|
341
345
|
- test/certificates/formatted_private_key
|
342
346
|
- test/certificates/formatted_rsa_private_key
|
343
347
|
- test/certificates/invalid_certificate1
|
344
348
|
- test/certificates/invalid_certificate2
|
345
349
|
- test/certificates/invalid_certificate3
|
350
|
+
- test/certificates/invalid_chained_certificate1
|
346
351
|
- test/certificates/invalid_private_key1
|
347
352
|
- test/certificates/invalid_private_key2
|
348
353
|
- test/certificates/invalid_private_key3
|
@@ -358,6 +363,7 @@ test_files:
|
|
358
363
|
- test/logout_requests/slo_request.xml
|
359
364
|
- test/logout_requests/slo_request.xml.base64
|
360
365
|
- test/logout_requests/slo_request_deflated.xml.base64
|
366
|
+
- test/logout_requests/slo_request_with_name_id_format.xml
|
361
367
|
- test/logout_requests/slo_request_with_session_index.xml
|
362
368
|
- test/logout_responses/logoutresponse_fixtures.rb
|
363
369
|
- test/logoutrequest_test.rb
|