ruby-saml 1.11.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.travis.yml +14 -12
- data/README.md +76 -22
- data/changelog.md +27 -0
- data/lib/onelogin/ruby-saml/attributes.rb +24 -1
- data/lib/onelogin/ruby-saml/authrequest.rb +9 -4
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +62 -24
- data/lib/onelogin/ruby-saml/logoutrequest.rb +7 -1
- data/lib/onelogin/ruby-saml/logoutresponse.rb +4 -0
- data/lib/onelogin/ruby-saml/metadata.rb +9 -1
- data/lib/onelogin/ruby-saml/response.rb +38 -16
- data/lib/onelogin/ruby-saml/saml_message.rb +6 -0
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +34 -2
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +4 -0
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -14
- data/lib/onelogin/ruby-saml/utils.rb +56 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +34 -6
- data/ruby-saml.gemspec +8 -4
- metadata +22 -282
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/certificate1 +0 -12
- data/test/certificates/certificate_without_head_foot +0 -1
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/certificates/ruby-saml.crt +0 -14
- data/test/certificates/ruby-saml.key +0 -15
- data/test/idp_metadata_parser_test.rb +0 -594
- data/test/logging_test.rb +0 -62
- data/test/logout_requests/invalid_slo_request.xml +0 -6
- data/test/logout_requests/slo_request.xml +0 -4
- data/test/logout_requests/slo_request.xml.base64 +0 -1
- data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
- data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
- data/test/logout_requests/slo_request_with_session_index.xml +0 -5
- data/test/logout_responses/logoutresponse_fixtures.rb +0 -86
- data/test/logoutrequest_test.rb +0 -260
- data/test/logoutresponse_test.rb +0 -427
- data/test/metadata/idp_descriptor.xml +0 -26
- data/test/metadata/idp_descriptor_2.xml +0 -56
- data/test/metadata/idp_descriptor_3.xml +0 -14
- data/test/metadata/idp_descriptor_4.xml +0 -72
- data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
- data/test/metadata/idp_metadata_multi_certs.xml +0 -75
- data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
- data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
- data/test/metadata/idp_multiple_descriptors.xml +0 -59
- data/test/metadata/idp_multiple_descriptors_2.xml +0 -59
- data/test/metadata/no_idp_descriptor.xml +0 -21
- data/test/metadata_test.rb +0 -331
- data/test/request_test.rb +0 -340
- data/test/response_test.rb +0 -1629
- data/test/responses/adfs_response_sha1.xml +0 -46
- data/test/responses/adfs_response_sha256.xml +0 -46
- data/test/responses/adfs_response_sha384.xml +0 -46
- data/test/responses/adfs_response_sha512.xml +0 -46
- data/test/responses/adfs_response_xmlns.xml +0 -45
- data/test/responses/attackxee.xml +0 -13
- data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
- data/test/responses/invalids/empty_destination.xml.base64 +0 -1
- data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
- data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
- data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
- data/test/responses/invalids/no_conditions.xml.base64 +0 -1
- data/test/responses/invalids/no_id.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
- data/test/responses/invalids/no_nameid.xml.base64 +0 -1
- data/test/responses/invalids/no_saml2.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/no_status.xml.base64 +0 -1
- data/test/responses/invalids/no_status_code.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
- data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
- data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
- data/test/responses/no_signature_ns.xml +0 -48
- data/test/responses/open_saml_response.xml +0 -56
- data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
- data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
- data/test/responses/response_double_status_code.xml.base64 +0 -1
- data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
- data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
- data/test/responses/response_eval.xml +0 -7
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack2.xml.base64 +0 -1
- data/test/responses/response_node_text_attack3.xml.base64 +0 -1
- data/test/responses/response_unsigned_xml_base64 +0 -1
- data/test/responses/response_with_ampersands.xml +0 -139
- data/test/responses/response_with_ampersands.xml.base64 +0 -93
- data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_multiple_attribute_values.xml +0 -67
- data/test/responses/response_with_retrieval_method.xml +0 -26
- data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
- data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
- data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_without_attributes.xml.base64 +0 -79
- data/test/responses/response_without_reference_uri.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/signed_nameid_in_atts.xml +0 -47
- data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
- data/test/responses/simple_saml_php.xml +0 -71
- data/test/responses/starfield_response.xml.base64 +0 -1
- data/test/responses/test_sign.xml +0 -43
- data/test/responses/unsigned_encrypted_adfs.xml +0 -23
- data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- data/test/saml_message_test.rb +0 -56
- data/test/settings_test.rb +0 -338
- data/test/slo_logoutrequest_test.rb +0 -467
- data/test/slo_logoutresponse_test.rb +0 -233
- data/test/test_helper.rb +0 -333
- data/test/utils_test.rb +0 -259
- data/test/xml_security_test.rb +0 -421
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ac80594648fe4830b965c65366f8bb261a4edfe148c9e929f352b39a1b3428f
|
4
|
+
data.tar.gz: b6379aa66a89f2074f434e8c97163022d533e1cdc30c20555135c2e4c82353b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1a380101d7684431209f4e8cc2704c8118621465c3b0a8efc623d573377e14706a4368eae6ea9ef1666da4c36e5e6a61ccae845d9f87e1bab98fbf2cd626ad6
|
7
|
+
data.tar.gz: e251b75351483f04d21bc4228af9752cab4d0cc4568952835960363671c28f9e38e62f9b727bde5d62b3a39e095593041e1e7dea9d93084fe6a87aef45a0f8ab
|
data/.travis.yml
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 1.8.7
|
4
3
|
- 1.9.3
|
5
4
|
- 2.0.0
|
6
5
|
- 2.1.10
|
7
6
|
- 2.2.10
|
8
7
|
- 2.3.8
|
9
8
|
- 2.4.6
|
10
|
-
- 2.5.
|
11
|
-
- 2.6.
|
12
|
-
-
|
9
|
+
- 2.5.8
|
10
|
+
- 2.6.6
|
11
|
+
- 2.7.2
|
12
|
+
- 3.0.0
|
13
13
|
- jruby-1.7.27
|
14
14
|
- jruby-9.1.17.0
|
15
|
-
- jruby-9.2.
|
15
|
+
- jruby-9.2.13.0
|
16
16
|
gemfile:
|
17
17
|
- Gemfile
|
18
18
|
- gemfiles/nokogiri-1.5.gemfile
|
@@ -20,27 +20,29 @@ before_install:
|
|
20
20
|
- gem update bundler
|
21
21
|
matrix:
|
22
22
|
exclude:
|
23
|
-
- rvm: 1.8.7
|
24
|
-
gemfile: Gemfile
|
25
|
-
- rvm: ree
|
26
|
-
gemfile: Gemfile
|
27
23
|
- rvm: jruby-1.7.27
|
28
24
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
29
25
|
- rvm: jruby-9.1.17.0
|
30
26
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
31
|
-
- rvm: jruby-9.2.
|
27
|
+
- rvm: jruby-9.2.13.0
|
32
28
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
33
29
|
- rvm: 2.1.5
|
34
30
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
31
|
+
- rvm: 2.1.10
|
32
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
35
33
|
- rvm: 2.2.10
|
36
34
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
37
35
|
- rvm: 2.3.8
|
38
36
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
39
37
|
- rvm: 2.4.6
|
40
38
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
41
|
-
- rvm: 2.5.
|
39
|
+
- rvm: 2.5.8
|
40
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
41
|
+
- rvm: 2.6.6
|
42
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
43
|
+
- rvm: 2.7.2
|
42
44
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
43
|
-
- rvm:
|
45
|
+
- rvm: 3.0.0
|
44
46
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
45
47
|
env:
|
46
48
|
- JRUBY_OPTS="--debug"
|
data/README.md
CHANGED
@@ -1,6 +1,22 @@
|
|
1
|
-
# Ruby SAML [](http://travis-ci.org/onelogin/ruby-saml) [](http://travis-ci.org/onelogin/ruby-saml) [](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
|
2
2
|
|
3
|
-
|
3
|
+
## Updating from 1.11.x to 1.12.0
|
4
|
+
Version `1.12.0` adds support for gcm algorithm and
|
5
|
+
change/adds specific error messages for signature validations
|
6
|
+
|
7
|
+
`idp_sso_target_url` and `idp_slo_target_url` attributes of the Settings class deprecated in favor of `idp_sso_service_url` and `idp_slo_service_url`.
|
8
|
+
In IDPMetadataParser, `parse`, `parse_to_hash` and `parse_to_array` methods now retrieve SSO URL and SLO URL endpoints with
|
9
|
+
`idp_sso_service_url` and `idp_slo_service_url` (previously `idp_sso_target_url` and `idp_slo_target_url` respectively).
|
10
|
+
|
11
|
+
## Updating from 1.10.x to 1.11.0
|
12
|
+
Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
|
13
|
+
There are two new security settings: `settings.security[:check_idp_cert_expiration]` and `settings.security[:check_sp_cert_expiration]` (both false by default) that check if the IdP or SP X.509 certificate has expired, respectively.
|
14
|
+
|
15
|
+
Version `1.10.2` includes the `valid_until` attribute in parsed IdP metadata.
|
16
|
+
|
17
|
+
Version `1.10.1` improves Ruby 1.8.7 support.
|
18
|
+
|
19
|
+
## Updating from 1.9.0 to 1.10.0
|
4
20
|
Version `1.10.0` improves IdpMetadataParser to allow parse multiple IDPSSODescriptor, Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user to be authenticated and updates the format_cert method to accept certs with /\x0d/
|
5
21
|
|
6
22
|
## Updating from 1.8.0 to 1.9.0
|
@@ -107,9 +123,12 @@ We created a demo project for Rails4 that uses the latest version of this librar
|
|
107
123
|
* 2.4.x
|
108
124
|
* 2.5.x
|
109
125
|
* 2.6.x
|
110
|
-
*
|
111
|
-
*
|
112
|
-
* JRuby
|
126
|
+
* 2.7.x
|
127
|
+
* 3.0.x
|
128
|
+
* JRuby 1.7.x
|
129
|
+
* JRuby 9.0.x
|
130
|
+
* JRuby 9.1.x
|
131
|
+
* JRuby 9.2.x
|
113
132
|
|
114
133
|
## Adding Features, Pull Requests
|
115
134
|
* Fork the repository
|
@@ -141,7 +160,7 @@ Using `Gemfile`
|
|
141
160
|
|
142
161
|
```ruby
|
143
162
|
# latest stable
|
144
|
-
gem 'ruby-saml', '~> 1.
|
163
|
+
gem 'ruby-saml', '~> 1.11.0'
|
145
164
|
|
146
165
|
# or track master for bleeding-edge
|
147
166
|
gem 'ruby-saml', :github => 'onelogin/ruby-saml'
|
@@ -228,6 +247,7 @@ def consume
|
|
228
247
|
session[:attributes] = response.attributes
|
229
248
|
else
|
230
249
|
authorize_failure # This method shows an error message
|
250
|
+
# List of errors is available in response.errors array
|
231
251
|
end
|
232
252
|
end
|
233
253
|
```
|
@@ -251,8 +271,8 @@ def saml_settings
|
|
251
271
|
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
252
272
|
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
|
253
273
|
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
|
254
|
-
settings.
|
255
|
-
settings.
|
274
|
+
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
|
275
|
+
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
|
256
276
|
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
257
277
|
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
|
258
278
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
@@ -273,7 +293,7 @@ def saml_settings
|
|
273
293
|
end
|
274
294
|
```
|
275
295
|
|
276
|
-
The use of settings.issuer is deprecated in favour of settings.sp_entity_id
|
296
|
+
The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
|
277
297
|
|
278
298
|
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:
|
279
299
|
|
@@ -282,6 +302,7 @@ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnst
|
|
282
302
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
|
283
303
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
|
284
304
|
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
|
305
|
+
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_audience: true}) # skips audience check
|
285
306
|
```
|
286
307
|
|
287
308
|
All that's left is to wrap everything in a controller and reference it in the initialization and consumption URLs in OneLogin. A full controller example could look like this:
|
@@ -305,6 +326,7 @@ class SamlController < ApplicationController
|
|
305
326
|
session[:attributes] = response.attributes
|
306
327
|
else
|
307
328
|
authorize_failure # This method shows an error message
|
329
|
+
# List of errors is available in response.errors array
|
308
330
|
end
|
309
331
|
end
|
310
332
|
|
@@ -315,7 +337,7 @@ class SamlController < ApplicationController
|
|
315
337
|
|
316
338
|
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
317
339
|
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
|
318
|
-
settings.
|
340
|
+
settings.idp_sso_service_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
|
319
341
|
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
320
342
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
321
343
|
|
@@ -388,8 +410,8 @@ end
|
|
388
410
|
The following attributes are set:
|
389
411
|
* idp_entity_id
|
390
412
|
* name_identifier_format
|
391
|
-
*
|
392
|
-
*
|
413
|
+
* idp_sso_service_url
|
414
|
+
* idp_slo_service_url
|
393
415
|
* idp_attribute_names
|
394
416
|
* idp_cert
|
395
417
|
* idp_cert_fingerprint
|
@@ -455,6 +477,9 @@ Imagine this `saml:AttributeStatement`
|
|
455
477
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
|
456
478
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>
|
457
479
|
</saml:Attribute>
|
480
|
+
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
|
481
|
+
<saml:AttributeValue>usersName</saml:AttributeValue>
|
482
|
+
</saml:Attribute>
|
458
483
|
</saml:AttributeStatement>
|
459
484
|
```
|
460
485
|
|
@@ -465,7 +490,8 @@ pp(response.attributes) # is an OneLogin::RubySaml::Attributes object
|
|
465
490
|
"another_value"=>["value1", "value2"],
|
466
491
|
"role"=>["role1", "role2", "role3"],
|
467
492
|
"attribute_with_nil_value"=>[nil],
|
468
|
-
"attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]
|
493
|
+
"attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]
|
494
|
+
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"=>["usersName"]}>
|
469
495
|
|
470
496
|
# Active single_value_compatibility
|
471
497
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
@@ -482,6 +508,9 @@ pp(response.attributes.single(:role))
|
|
482
508
|
pp(response.attributes.multi(:role))
|
483
509
|
# => ["role1", "role2", "role3"]
|
484
510
|
|
511
|
+
pp(response.attributes.fetch(:role))
|
512
|
+
# => "role1"
|
513
|
+
|
485
514
|
pp(response.attributes[:attribute_with_nil_value])
|
486
515
|
# => nil
|
487
516
|
|
@@ -497,6 +526,9 @@ pp(response.attributes.single(:not_exists))
|
|
497
526
|
pp(response.attributes.multi(:not_exists))
|
498
527
|
# => nil
|
499
528
|
|
529
|
+
pp(response.attributes.fetch(/givenname/))
|
530
|
+
# => "usersName"
|
531
|
+
|
500
532
|
# Deactive single_value_compatibility
|
501
533
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
502
534
|
|
@@ -512,6 +544,9 @@ pp(response.attributes.single(:role))
|
|
512
544
|
pp(response.attributes.multi(:role))
|
513
545
|
# => ["role1", "role2", "role3"]
|
514
546
|
|
547
|
+
pp(response.attributes.fetch(:role))
|
548
|
+
# => ["role1", "role2", "role3"]
|
549
|
+
|
515
550
|
pp(response.attributes[:attribute_with_nil_value])
|
516
551
|
# => [nil]
|
517
552
|
|
@@ -526,12 +561,15 @@ pp(response.attributes.single(:not_exists))
|
|
526
561
|
|
527
562
|
pp(response.attributes.multi(:not_exists))
|
528
563
|
# => nil
|
564
|
+
|
565
|
+
pp(response.attributes.fetch(/givenname/))
|
566
|
+
# => ["usersName"]
|
529
567
|
```
|
530
568
|
|
531
569
|
The `saml:AuthnContextClassRef` of the AuthNRequest can be provided by `settings.authn_context`; possible values are described at [SAMLAuthnCxt]. The comparison method can be set using `settings.authn_context_comparison` parameter. Possible values include: 'exact', 'better', 'maximum' and 'minimum' (default value is 'exact').
|
532
570
|
To add a `saml:AuthnContextDeclRef`, define `settings.authn_context_decl_ref`.
|
533
571
|
|
534
|
-
In a SP-
|
572
|
+
In a SP-initiated flow, the SP can indicate to the IdP the subject that should be authenticated. This is done by defining the `settings.name_identifier_value_requested` before
|
535
573
|
building the authrequest object.
|
536
574
|
|
537
575
|
|
@@ -570,7 +608,7 @@ Remember to provide it to the Signature builder if you are sending a `GET RelayS
|
|
570
608
|
signature validation process will fail at the Identity Provider.
|
571
609
|
|
572
610
|
The Service Provider will sign the request/responses with its private key.
|
573
|
-
The Identity Provider will validate the sign of the received request/responses with the public
|
611
|
+
The Identity Provider will validate the sign of the received request/responses with the public x509 cert of the
|
574
612
|
Service Provider.
|
575
613
|
|
576
614
|
Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
|
@@ -611,21 +649,27 @@ def sp_logout_request
|
|
611
649
|
# LogoutRequest accepts plain browser requests w/o paramters
|
612
650
|
settings = saml_settings
|
613
651
|
|
614
|
-
if settings.
|
652
|
+
if settings.idp_slo_service_url.nil?
|
615
653
|
logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
|
616
654
|
delete_session
|
617
655
|
else
|
618
656
|
|
619
|
-
# Since we created a new SAML request, save the transaction_id
|
620
|
-
# to compare it with the response we get back
|
621
657
|
logout_request = OneLogin::RubySaml::Logoutrequest.new()
|
622
|
-
session[:
|
623
|
-
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{session[:transaction_id]}'"
|
658
|
+
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
|
624
659
|
|
625
660
|
if settings.name_identifier_value.nil?
|
626
661
|
settings.name_identifier_value = session[:userid]
|
627
662
|
end
|
628
663
|
|
664
|
+
# Ensure user is logged out before redirect to IdP, in case anything goes wrong during single logout process (as recommended by saml2int [SDP-SP34])
|
665
|
+
logged_user = session[:userid]
|
666
|
+
logger.info "Delete session for '#{session[:userid]}'"
|
667
|
+
delete_session
|
668
|
+
|
669
|
+
# Save the transaction_id to compare it with the response we get back
|
670
|
+
session[:transaction_id] = logout_request.uuid
|
671
|
+
session[:logged_out_user] = logged_user
|
672
|
+
|
629
673
|
relayState = url_for controller: 'saml', action: 'index'
|
630
674
|
redirect_to(logout_request.create(settings, :RelayState => relayState))
|
631
675
|
end
|
@@ -653,7 +697,7 @@ def process_logout_response
|
|
653
697
|
logger.error "The SAML Logout Response is invalid"
|
654
698
|
else
|
655
699
|
# Actually log out this session
|
656
|
-
logger.info "
|
700
|
+
logger.info "SLO completed for '#{session[:logged_out_user]}'"
|
657
701
|
delete_session
|
658
702
|
end
|
659
703
|
end
|
@@ -662,6 +706,8 @@ end
|
|
662
706
|
def delete_session
|
663
707
|
session[:userid] = nil
|
664
708
|
session[:attributes] = nil
|
709
|
+
session[:transaction_id] = nil
|
710
|
+
session[:logged_out_user] = nil
|
665
711
|
end
|
666
712
|
```
|
667
713
|
|
@@ -674,7 +720,7 @@ def idp_logout_request
|
|
674
720
|
logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
|
675
721
|
if !logout_request.is_valid?
|
676
722
|
logger.error "IdP initiated LogoutRequest was not valid!"
|
677
|
-
render :inline => logger.error
|
723
|
+
return render :inline => logger.error
|
678
724
|
end
|
679
725
|
logger.info "IdP initiated Logout for #{logout_request.name_id}"
|
680
726
|
|
@@ -729,6 +775,14 @@ class SamlController < ApplicationController
|
|
729
775
|
end
|
730
776
|
```
|
731
777
|
|
778
|
+
You can add ValidUntil and CacheDuration to the XML Metadata using instead
|
779
|
+
```ruby
|
780
|
+
# Valid until => 2 days from now
|
781
|
+
# Cache duration = 604800s = 1 week
|
782
|
+
valid_until = Time.now + 172800
|
783
|
+
cache_duration = 604800
|
784
|
+
meta.generate(settings, false, valid_until, cache_duration)
|
785
|
+
```
|
732
786
|
|
733
787
|
## Clock Drift
|
734
788
|
|
data/changelog.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# RubySaml Changelog
|
2
2
|
|
3
|
+
### 1.12.1 (Apr 05, 2022)
|
4
|
+
* Fix XPath typo incompatible with Rexml 3.2.5
|
5
|
+
* Refactor GCM support
|
6
|
+
|
7
|
+
### 1.12.0 (Feb 18, 2021)
|
8
|
+
* Support AES-128-GCM, AES-192-GCM, and AES-256-GCM encryptions
|
9
|
+
* Parse & return SLO ResponseLocation in IDPMetadataParser & Settings
|
10
|
+
* Adding idp_sso_service_url and idp_slo_service_url settings
|
11
|
+
* [#536](https://github.com/onelogin/ruby-saml/pull/536) Adding feth method to be able retrieve attributes based on regex
|
12
|
+
* Reduce size of built gem by excluding the test folder
|
13
|
+
* Improve protection on Zlib deflate decompression bomb attack.
|
14
|
+
* Add ValidUntil and cacheDuration support on Metadata generator
|
15
|
+
* Add support for cacheDuration at the IdpMetadataParser
|
16
|
+
* Support customizable statusCode on generated LogoutResponse
|
17
|
+
* [#545](https://github.com/onelogin/ruby-saml/pull/545) More specific error messages for signature validation
|
18
|
+
* Support Process Transform
|
19
|
+
* Raise SettingError if invoking an action with no endpoint defined on the settings
|
20
|
+
* Made IdpMetadataParser more extensible for subclasses
|
21
|
+
*[#548](https://github.com/onelogin/ruby-saml/pull/548) Add :skip_audience option
|
22
|
+
* [#555](https://github.com/onelogin/ruby-saml/pull/555) Define 'soft' variable to prevent exception when doc cert is invalid
|
23
|
+
* Improve documentation
|
24
|
+
|
25
|
+
### 1.11.0 (Jul 24, 2019)
|
26
|
+
|
27
|
+
* Deprecate settings.issuer in favor of settings.sp_entity_id
|
28
|
+
* Add support for certification expiration
|
29
|
+
|
3
30
|
### 1.10.2 (Apr 29, 2019)
|
4
31
|
|
5
32
|
* Add valid until, accessor
|
@@ -79,7 +79,7 @@ module OneLogin
|
|
79
79
|
self.class.single_value_compatibility ? single(canonize_name(name)) : multi(canonize_name(name))
|
80
80
|
end
|
81
81
|
|
82
|
-
# @return [
|
82
|
+
# @return [Hash] Return all attributes as a hash
|
83
83
|
#
|
84
84
|
def all
|
85
85
|
attributes
|
@@ -113,6 +113,29 @@ module OneLogin
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
# Fetch attribute value using name or regex
|
117
|
+
# @param name [String|Regexp] The attribute name
|
118
|
+
# @return [String|Array] Depending on the single value compatibility status this returns:
|
119
|
+
# - First value if single_value_compatibility = true
|
120
|
+
# response.attributes['mail'] # => 'user@example.com'
|
121
|
+
# - All values if single_value_compatibility = false
|
122
|
+
# response.attributes['mail'] # => ['user@example.com','user@example.net']
|
123
|
+
#
|
124
|
+
def fetch(name)
|
125
|
+
attributes.each_key do |attribute_key|
|
126
|
+
if name.is_a?(Regexp)
|
127
|
+
if name.respond_to? :match?
|
128
|
+
return self[attribute_key] if name.match?(attribute_key)
|
129
|
+
else
|
130
|
+
return self[attribute_key] if name.match(attribute_key)
|
131
|
+
end
|
132
|
+
elsif canonize_name(name) == canonize_name(attribute_key)
|
133
|
+
return self[attribute_key]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
|
116
139
|
protected
|
117
140
|
|
118
141
|
# stringifies all names so both 'email' and :email return the same result
|
@@ -3,6 +3,7 @@ require "rexml/document"
|
|
3
3
|
require "onelogin/ruby-saml/logging"
|
4
4
|
require "onelogin/ruby-saml/saml_message"
|
5
5
|
require "onelogin/ruby-saml/utils"
|
6
|
+
require "onelogin/ruby-saml/setting_error"
|
6
7
|
|
7
8
|
# Only supports SAML 2.0
|
8
9
|
module OneLogin
|
@@ -23,6 +24,10 @@ module OneLogin
|
|
23
24
|
@uuid = OneLogin::RubySaml::Utils.uuid
|
24
25
|
end
|
25
26
|
|
27
|
+
def request_id
|
28
|
+
@uuid
|
29
|
+
end
|
30
|
+
|
26
31
|
# Creates the AuthNRequest string.
|
27
32
|
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
28
33
|
# @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
|
@@ -30,14 +35,14 @@ module OneLogin
|
|
30
35
|
#
|
31
36
|
def create(settings, params = {})
|
32
37
|
params = create_params(settings, params)
|
33
|
-
params_prefix = (settings.
|
38
|
+
params_prefix = (settings.idp_sso_service_url =~ /\?/) ? '&' : '?'
|
34
39
|
saml_request = CGI.escape(params.delete("SAMLRequest"))
|
35
40
|
request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
|
36
41
|
params.each_pair do |key, value|
|
37
42
|
request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
|
38
43
|
end
|
39
|
-
raise "Invalid settings,
|
40
|
-
@login_url = settings.
|
44
|
+
raise SettingError.new "Invalid settings, idp_sso_service_url is not set!" if settings.idp_sso_service_url.nil? or settings.idp_sso_service_url.empty?
|
45
|
+
@login_url = settings.idp_sso_service_url + request_params
|
41
46
|
end
|
42
47
|
|
43
48
|
# Creates the Get parameters for the request.
|
@@ -107,7 +112,7 @@ module OneLogin
|
|
107
112
|
root.attributes['ID'] = uuid
|
108
113
|
root.attributes['IssueInstant'] = time
|
109
114
|
root.attributes['Version'] = "2.0"
|
110
|
-
root.attributes['Destination'] = settings.
|
115
|
+
root.attributes['Destination'] = settings.idp_sso_service_url unless settings.idp_sso_service_url.nil? or settings.idp_sso_service_url.empty?
|
111
116
|
root.attributes['IsPassive'] = settings.passive unless settings.passive.nil?
|
112
117
|
root.attributes['ProtocolBinding'] = settings.protocol_binding unless settings.protocol_binding.nil?
|
113
118
|
root.attributes["AttributeConsumingServiceIndex"] = settings.attributes_index unless settings.attributes_index.nil?
|
@@ -15,10 +15,10 @@ module OneLogin
|
|
15
15
|
|
16
16
|
module SamlMetadata
|
17
17
|
module Vocabulary
|
18
|
-
METADATA = "urn:oasis:names:tc:SAML:2.0:metadata"
|
19
|
-
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
20
|
-
NAME_FORMAT = "urn:oasis:names:tc:SAML:2.0:attrname-format:*"
|
21
|
-
SAML_ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
|
18
|
+
METADATA = "urn:oasis:names:tc:SAML:2.0:metadata".freeze
|
19
|
+
DSIG = "http://www.w3.org/2000/09/xmldsig#".freeze
|
20
|
+
NAME_FORMAT = "urn:oasis:names:tc:SAML:2.0:attrname-format:*".freeze
|
21
|
+
SAML_ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion".freeze
|
22
22
|
end
|
23
23
|
|
24
24
|
NAMESPACE = {
|
@@ -26,7 +26,7 @@ module OneLogin
|
|
26
26
|
"NameFormat" => Vocabulary::NAME_FORMAT,
|
27
27
|
"saml" => Vocabulary::SAML_ASSERTION,
|
28
28
|
"ds" => Vocabulary::DSIG
|
29
|
-
}
|
29
|
+
}.freeze
|
30
30
|
end
|
31
31
|
|
32
32
|
include SamlMetadata::Vocabulary
|
@@ -34,6 +34,16 @@ module OneLogin
|
|
34
34
|
attr_reader :response
|
35
35
|
attr_reader :options
|
36
36
|
|
37
|
+
# fetch IdP descriptors from a metadata document
|
38
|
+
def self.get_idps(metadata_document, only_entity_id=nil)
|
39
|
+
path = "//md:EntityDescriptor#{only_entity_id && '[@entityID="' + only_entity_id + '"]'}/md:IDPSSODescriptor"
|
40
|
+
REXML::XPath.match(
|
41
|
+
metadata_document,
|
42
|
+
path,
|
43
|
+
SamlMetadata::NAMESPACE
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
37
47
|
# Parse the Identity Provider metadata and update the settings with the
|
38
48
|
# IdP values
|
39
49
|
#
|
@@ -103,6 +113,16 @@ module OneLogin
|
|
103
113
|
def parse(idp_metadata, options = {})
|
104
114
|
parsed_metadata = parse_to_hash(idp_metadata, options)
|
105
115
|
|
116
|
+
unless parsed_metadata[:cache_duration].nil?
|
117
|
+
cache_valid_until_timestamp = OneLogin::RubySaml::Utils.parse_duration(parsed_metadata[:cache_duration])
|
118
|
+
if parsed_metadata[:valid_until].nil? || cache_valid_until_timestamp < Time.parse(parsed_metadata[:valid_until], Time.now.utc).to_i
|
119
|
+
parsed_metadata[:valid_until] = Time.at(cache_valid_until_timestamp).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
# Remove the cache_duration because on the settings
|
123
|
+
# we only gonna suppot valid_until
|
124
|
+
parsed_metadata.delete(:cache_duration)
|
125
|
+
|
106
126
|
settings = options[:settings]
|
107
127
|
|
108
128
|
if settings.nil?
|
@@ -139,17 +159,21 @@ module OneLogin
|
|
139
159
|
#
|
140
160
|
# @return [Array<Hash>]
|
141
161
|
def parse_to_array(idp_metadata, options = {})
|
162
|
+
parse_to_idp_metadata_array(idp_metadata, options).map{|idp_md| idp_md.to_hash(options)}
|
163
|
+
end
|
164
|
+
|
165
|
+
def parse_to_idp_metadata_array(idp_metadata, options = {})
|
142
166
|
@document = REXML::Document.new(idp_metadata)
|
143
167
|
@options = options
|
144
168
|
|
145
|
-
idpsso_descriptors =
|
169
|
+
idpsso_descriptors = self.class.get_idps(@document, options[:entity_id])
|
146
170
|
if !idpsso_descriptors.any?
|
147
171
|
raise ArgumentError.new("idp_metadata must contain an IDPSSODescriptor element")
|
148
172
|
end
|
149
173
|
|
150
|
-
return idpsso_descriptors.map{|id| IdpMetadata.new(id, id.parent.attributes["entityID"])
|
174
|
+
return idpsso_descriptors.map{|id| IdpMetadata.new(id, id.parent.attributes["entityID"])}
|
151
175
|
end
|
152
|
-
|
176
|
+
|
153
177
|
private
|
154
178
|
|
155
179
|
# Retrieve the remote IdP metadata from the URL or a cached copy.
|
@@ -175,6 +199,7 @@ module OneLogin
|
|
175
199
|
end
|
176
200
|
|
177
201
|
get = Net::HTTP::Get.new(uri.request_uri)
|
202
|
+
get.basic_auth uri.user, uri.password if uri.user
|
178
203
|
@response = http.request(get)
|
179
204
|
return response.body if response.is_a? Net::HTTPSuccess
|
180
205
|
|
@@ -184,15 +209,8 @@ module OneLogin
|
|
184
209
|
end
|
185
210
|
|
186
211
|
class IdpMetadata
|
187
|
-
|
188
|
-
|
189
|
-
REXML::XPath.match(
|
190
|
-
metadata_document,
|
191
|
-
path,
|
192
|
-
SamlMetadata::NAMESPACE
|
193
|
-
)
|
194
|
-
end
|
195
|
-
|
212
|
+
attr_reader :idpsso_descriptor, :entity_id
|
213
|
+
|
196
214
|
def initialize(idpsso_descriptor, entity_id)
|
197
215
|
@idpsso_descriptor = idpsso_descriptor
|
198
216
|
@entity_id = entity_id
|
@@ -202,13 +220,15 @@ module OneLogin
|
|
202
220
|
{
|
203
221
|
:idp_entity_id => @entity_id,
|
204
222
|
:name_identifier_format => idp_name_id_format,
|
205
|
-
:
|
206
|
-
:
|
223
|
+
:idp_sso_service_url => single_signon_service_url(options),
|
224
|
+
:idp_slo_service_url => single_logout_service_url(options),
|
225
|
+
:idp_slo_response_service_url => single_logout_response_service_url(options),
|
207
226
|
:idp_attribute_names => attribute_names,
|
208
227
|
:idp_cert => nil,
|
209
228
|
:idp_cert_fingerprint => nil,
|
210
229
|
:idp_cert_multi => nil,
|
211
|
-
:valid_until => valid_until
|
230
|
+
:valid_until => valid_until,
|
231
|
+
:cache_duration => cache_duration,
|
212
232
|
}.tap do |response_hash|
|
213
233
|
merge_certificates_into(response_hash) unless certificates.nil?
|
214
234
|
end
|
@@ -232,6 +252,13 @@ module OneLogin
|
|
232
252
|
root.attributes['validUntil'] if root && root.attributes
|
233
253
|
end
|
234
254
|
|
255
|
+
# @return [String|nil] 'cacheDuration' attribute of metadata
|
256
|
+
#
|
257
|
+
def cache_duration
|
258
|
+
root = @idpsso_descriptor.root
|
259
|
+
root.attributes['cacheDuration'] if root && root.attributes
|
260
|
+
end
|
261
|
+
|
235
262
|
# @param binding_priority [Array]
|
236
263
|
# @return [String|nil] SingleSignOnService binding if exists
|
237
264
|
#
|
@@ -296,6 +323,21 @@ module OneLogin
|
|
296
323
|
return node.value if node
|
297
324
|
end
|
298
325
|
|
326
|
+
# @param options [Hash]
|
327
|
+
# @return [String|nil] SingleLogoutService response url if exists
|
328
|
+
#
|
329
|
+
def single_logout_response_service_url(options = {})
|
330
|
+
binding = single_logout_service_binding(options[:slo_binding])
|
331
|
+
return if binding.nil?
|
332
|
+
|
333
|
+
node = REXML::XPath.first(
|
334
|
+
@idpsso_descriptor,
|
335
|
+
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@ResponseLocation",
|
336
|
+
SamlMetadata::NAMESPACE
|
337
|
+
)
|
338
|
+
return node.value if node
|
339
|
+
end
|
340
|
+
|
299
341
|
# @return [String|nil] Unformatted Certificate if exists
|
300
342
|
#
|
301
343
|
def certificates
|
@@ -393,10 +435,6 @@ module OneLogin
|
|
393
435
|
|
394
436
|
settings
|
395
437
|
end
|
396
|
-
|
397
|
-
if self.respond_to?(:private_constant)
|
398
|
-
private_constant :SamlMetadata, :IdpMetadata
|
399
|
-
end
|
400
438
|
end
|
401
439
|
end
|
402
440
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "onelogin/ruby-saml/logging"
|
2
2
|
require "onelogin/ruby-saml/saml_message"
|
3
3
|
require "onelogin/ruby-saml/utils"
|
4
|
+
require "onelogin/ruby-saml/setting_error"
|
4
5
|
|
5
6
|
# Only supports SAML 2.0
|
6
7
|
module OneLogin
|
@@ -20,6 +21,10 @@ module OneLogin
|
|
20
21
|
@uuid = OneLogin::RubySaml::Utils.uuid
|
21
22
|
end
|
22
23
|
|
24
|
+
def request_id
|
25
|
+
@uuid
|
26
|
+
end
|
27
|
+
|
23
28
|
# Creates the Logout Request string.
|
24
29
|
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
25
30
|
# @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
|
@@ -33,6 +38,7 @@ module OneLogin
|
|
33
38
|
params.each_pair do |key, value|
|
34
39
|
request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
|
35
40
|
end
|
41
|
+
raise SettingError.new "Invalid settings, idp_slo_target_url is not set!" if settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
|
36
42
|
@logout_url = settings.idp_slo_target_url + request_params
|
37
43
|
end
|
38
44
|
|
@@ -103,7 +109,7 @@ module OneLogin
|
|
103
109
|
root.attributes['ID'] = uuid
|
104
110
|
root.attributes['IssueInstant'] = time
|
105
111
|
root.attributes['Version'] = "2.0"
|
106
|
-
root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
|
112
|
+
root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
|
107
113
|
|
108
114
|
if settings.sp_entity_id
|
109
115
|
issuer = root.add_element "saml:Issuer"
|
@@ -47,6 +47,10 @@ module OneLogin
|
|
47
47
|
@document = XMLSecurity::SignedDocument.new(@response)
|
48
48
|
end
|
49
49
|
|
50
|
+
def response_id
|
51
|
+
id(document)
|
52
|
+
end
|
53
|
+
|
50
54
|
# Checks if the Status has the "Success" code
|
51
55
|
# @return [Boolean] True if the StatusCode is Sucess
|
52
56
|
# @raise [ValidationError] if soft == false and validation fails
|