ruby-saml 1.5.0 → 1.6.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 +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 [![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.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
|