ruby-saml 1.11.0 → 1.13.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +25 -0
- data/{changelog.md → CHANGELOG.md} +44 -1
- data/README.md +333 -217
- data/UPGRADING.md +149 -0
- data/lib/onelogin/ruby-saml/attributes.rb +24 -1
- data/lib/onelogin/ruby-saml/authrequest.rb +11 -7
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +154 -83
- data/lib/onelogin/ruby-saml/logoutrequest.rb +12 -6
- data/lib/onelogin/ruby-saml/logoutresponse.rb +5 -1
- data/lib/onelogin/ruby-saml/metadata.rb +62 -17
- data/lib/onelogin/ruby-saml/response.rb +51 -31
- data/lib/onelogin/ruby-saml/saml_message.rb +8 -3
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +89 -49
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +16 -4
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +31 -17
- data/lib/onelogin/ruby-saml/utils.rb +63 -2
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +39 -13
- data/ruby-saml.gemspec +8 -4
- metadata +24 -282
- data/.travis.yml +0 -46
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/certificate1 +0 -12
- data/test/certificates/certificate_without_head_foot +0 -1
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/certificates/ruby-saml.crt +0 -14
- data/test/certificates/ruby-saml.key +0 -15
- data/test/idp_metadata_parser_test.rb +0 -594
- data/test/logging_test.rb +0 -62
- data/test/logout_requests/invalid_slo_request.xml +0 -6
- data/test/logout_requests/slo_request.xml +0 -4
- data/test/logout_requests/slo_request.xml.base64 +0 -1
- data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
- data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
- data/test/logout_requests/slo_request_with_session_index.xml +0 -5
- data/test/logout_responses/logoutresponse_fixtures.rb +0 -86
- data/test/logoutrequest_test.rb +0 -260
- data/test/logoutresponse_test.rb +0 -427
- data/test/metadata/idp_descriptor.xml +0 -26
- data/test/metadata/idp_descriptor_2.xml +0 -56
- data/test/metadata/idp_descriptor_3.xml +0 -14
- data/test/metadata/idp_descriptor_4.xml +0 -72
- data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
- data/test/metadata/idp_metadata_multi_certs.xml +0 -75
- data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
- data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
- data/test/metadata/idp_multiple_descriptors.xml +0 -59
- data/test/metadata/idp_multiple_descriptors_2.xml +0 -59
- data/test/metadata/no_idp_descriptor.xml +0 -21
- data/test/metadata_test.rb +0 -331
- data/test/request_test.rb +0 -340
- data/test/response_test.rb +0 -1629
- data/test/responses/adfs_response_sha1.xml +0 -46
- data/test/responses/adfs_response_sha256.xml +0 -46
- data/test/responses/adfs_response_sha384.xml +0 -46
- data/test/responses/adfs_response_sha512.xml +0 -46
- data/test/responses/adfs_response_xmlns.xml +0 -45
- data/test/responses/attackxee.xml +0 -13
- data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
- data/test/responses/invalids/empty_destination.xml.base64 +0 -1
- data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
- data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
- data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
- data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
- data/test/responses/invalids/no_conditions.xml.base64 +0 -1
- data/test/responses/invalids/no_id.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
- data/test/responses/invalids/no_nameid.xml.base64 +0 -1
- data/test/responses/invalids/no_saml2.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/no_status.xml.base64 +0 -1
- data/test/responses/invalids/no_status_code.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
- data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
- data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
- data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
- data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
- data/test/responses/no_signature_ns.xml +0 -48
- data/test/responses/open_saml_response.xml +0 -56
- data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
- data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
- data/test/responses/response_double_status_code.xml.base64 +0 -1
- data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
- data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
- data/test/responses/response_eval.xml +0 -7
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack2.xml.base64 +0 -1
- data/test/responses/response_node_text_attack3.xml.base64 +0 -1
- data/test/responses/response_unsigned_xml_base64 +0 -1
- data/test/responses/response_with_ampersands.xml +0 -139
- data/test/responses/response_with_ampersands.xml.base64 +0 -93
- data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_multiple_attribute_values.xml +0 -67
- data/test/responses/response_with_retrieval_method.xml +0 -26
- data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
- data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
- data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_without_attributes.xml.base64 +0 -79
- data/test/responses/response_without_reference_uri.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/signed_nameid_in_atts.xml +0 -47
- data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
- data/test/responses/simple_saml_php.xml +0 -71
- data/test/responses/starfield_response.xml.base64 +0 -1
- data/test/responses/test_sign.xml +0 -43
- data/test/responses/unsigned_encrypted_adfs.xml +0 -23
- data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
- data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- data/test/saml_message_test.rb +0 -56
- data/test/settings_test.rb +0 -338
- data/test/slo_logoutrequest_test.rb +0 -467
- data/test/slo_logoutresponse_test.rb +0 -233
- data/test/test_helper.rb +0 -333
- data/test/utils_test.rb +0 -259
- data/test/xml_security_test.rb +0 -421
data/UPGRADING.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Ruby SAML Migration Guide
|
|
2
|
+
|
|
3
|
+
## Updating from 1.12.x to 1.13.0 (NOT YET RELEASED)
|
|
4
|
+
|
|
5
|
+
Version `1.13.0` adds `settings.idp_sso_service_binding` and `settings.idp_slo_service_binding`, and
|
|
6
|
+
deprecates `settings.security[:embed_sign]`. If specified, new binding parameters will be used in place of `:embed_sign`
|
|
7
|
+
to determine how to handle SAML message signing (`HTTP-POST` embeds signature and `HTTP-Redirect` does not.)
|
|
8
|
+
|
|
9
|
+
In addition, the `IdpMetadataParser#parse`, `#parse_to_hash` and `#parse_to_array` methods now retrieve
|
|
10
|
+
`idp_sso_service_binding` and `idp_slo_service_binding`.
|
|
11
|
+
|
|
12
|
+
Lastly, for convenience you may now use the Symbol aliases `:post` and `:redirect` for any `settings.*_binding` parameter.
|
|
13
|
+
|
|
14
|
+
## Upgrading from 1.11.x to 1.12.0
|
|
15
|
+
|
|
16
|
+
Version `1.12.0` adds support for gcm algorithm and
|
|
17
|
+
change/adds specific error messages for signature validations
|
|
18
|
+
|
|
19
|
+
`idp_sso_target_url` and `idp_slo_target_url` attributes of the Settings class deprecated
|
|
20
|
+
in favor of `idp_sso_service_url` and `idp_slo_service_url`. The `IdpMetadataParser#parse`,
|
|
21
|
+
`#parse_to_hash` and `#parse_to_array` methods now retrieve SSO URL and SLO URL endpoints with
|
|
22
|
+
`idp_sso_service_url` and `idp_slo_service_url` (previously `idp_sso_target_url` and
|
|
23
|
+
`idp_slo_target_url` respectively).
|
|
24
|
+
|
|
25
|
+
## Upgrading from 1.10.x to 1.11.0
|
|
26
|
+
|
|
27
|
+
Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
|
|
28
|
+
There are two new security settings: `settings.security[:check_idp_cert_expiration]` and
|
|
29
|
+
`settings.security[:check_sp_cert_expiration]` (both false by default) that check if the
|
|
30
|
+
IdP or SP X.509 certificate has expired, respectively.
|
|
31
|
+
|
|
32
|
+
Version `1.10.2` includes the `valid_until` attribute in parsed IdP metadata.
|
|
33
|
+
|
|
34
|
+
Version `1.10.1` improves Ruby 1.8.7 support.
|
|
35
|
+
|
|
36
|
+
## Upgrading from 1.9.0 to 1.10.0
|
|
37
|
+
|
|
38
|
+
Version `1.10.0` improves IdpMetadataParser to allow parse multiple IDPSSODescriptor,
|
|
39
|
+
Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user
|
|
40
|
+
to be authenticated and updates the format_cert method to accept certs with /\x0d/
|
|
41
|
+
|
|
42
|
+
## Upgrading from 1.8.0 to 1.9.0
|
|
43
|
+
|
|
44
|
+
Version `1.9.0` better supports Ruby 2.4+ and JRuby 9.2.0.0. `Settings` initialization
|
|
45
|
+
now has a second parameter, `keep_security_settings` (default: false), which saves security
|
|
46
|
+
settings attributes that are not explicitly overridden, if set to true.
|
|
47
|
+
|
|
48
|
+
## Upgrading from 1.7.x to 1.8.0
|
|
49
|
+
|
|
50
|
+
On Version `1.8.0`, creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState
|
|
51
|
+
param will not generate a URL with an empty RelayState parameter anymore. It also changes
|
|
52
|
+
the invalid audience error message.
|
|
53
|
+
|
|
54
|
+
## Upgrading from 1.6.0 to 1.7.0
|
|
55
|
+
|
|
56
|
+
Version `1.7.0` is a recommended update for all Ruby SAML users as it includes a fix for
|
|
57
|
+
the [CVE-2017-11428](https://www.cvedetails.com/cve/CVE-2017-11428/) vulnerability.
|
|
58
|
+
|
|
59
|
+
## Upgrading from 1.5.0 to 1.6.0
|
|
60
|
+
|
|
61
|
+
Version `1.6.0` changes the preferred way to construct instances of `Logoutresponse` and
|
|
62
|
+
`SloLogoutrequest`. Previously the _SAMLResponse_, _RelayState_, and _SigAlg_ parameters
|
|
63
|
+
of these message types were provided via the constructor's `options[:get_params]` parameter.
|
|
64
|
+
Unfortunately this can result in incompatibility with other SAML implementations; signatures
|
|
65
|
+
are specified to be computed based on the _sender's_ URI-encoding of the message, which can
|
|
66
|
+
differ from that of Ruby SAML. In particular, Ruby SAML's URI-encoding does not match that
|
|
67
|
+
of Microsoft ADFS, so messages from ADFS can fail signature validation.
|
|
68
|
+
|
|
69
|
+
The new preferred way to provide _SAMLResponse_, _RelayState_, and _SigAlg_ is via the
|
|
70
|
+
`options[:raw_get_params]` parameter. For example:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# In this example `query_params` is assumed to contain decoded query parameters,
|
|
74
|
+
# and `raw_query_params` is assumed to contain encoded query parameters as sent by the IDP.
|
|
75
|
+
settings = {
|
|
76
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
|
77
|
+
settings.soft = false
|
|
78
|
+
}
|
|
79
|
+
options = {
|
|
80
|
+
get_params: {
|
|
81
|
+
"Signature" => query_params["Signature"],
|
|
82
|
+
},
|
|
83
|
+
raw_get_params: {
|
|
84
|
+
"SAMLRequest" => raw_query_params["SAMLRequest"],
|
|
85
|
+
"SigAlg" => raw_query_params["SigAlg"],
|
|
86
|
+
"RelayState" => raw_query_params["RelayState"],
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
slo_logout_request = OneLogin::RubySaml::SloLogoutrequest.new(query_params["SAMLRequest"], settings, options)
|
|
90
|
+
raise "Invalid Logout Request" unless slo_logout_request.is_valid?
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The old form is still supported for backward compatibility, but all Ruby SAML users
|
|
94
|
+
should prefer `options[:raw_get_params]` where possible to ensure compatibility with
|
|
95
|
+
other SAML implementations.
|
|
96
|
+
|
|
97
|
+
## Upgrading from 1.4.2 to 1.4.3
|
|
98
|
+
|
|
99
|
+
Version `1.4.3` introduces Recipient validation of SubjectConfirmation elements.
|
|
100
|
+
The 'Recipient' value is compared with the settings.assertion_consumer_service_url
|
|
101
|
+
value.
|
|
102
|
+
|
|
103
|
+
If you want to skip that validation, add the :skip_recipient_check option to the
|
|
104
|
+
initialize method of the Response object.
|
|
105
|
+
|
|
106
|
+
Parsing metadata that contains more than one certificate will propagate the
|
|
107
|
+
idp_cert_multi property rather than idp_cert. See [signature validation
|
|
108
|
+
section](#signature-validation) for details.
|
|
109
|
+
|
|
110
|
+
## Upgrading from 1.3.x to 1.4.x
|
|
111
|
+
|
|
112
|
+
Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
|
|
113
|
+
|
|
114
|
+
## Upgrading from 1.2.x to 1.3.x
|
|
115
|
+
|
|
116
|
+
Version `1.3.0` is a recommended update for all Ruby SAML users as it includes security fixes.
|
|
117
|
+
It adds security improvements in order to prevent Signature wrapping attacks.
|
|
118
|
+
[CVE-2016-5697](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5697)
|
|
119
|
+
|
|
120
|
+
## Upgrading from 1.1.x to 1.2.x
|
|
121
|
+
|
|
122
|
+
Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favour of SecureRandom,
|
|
123
|
+
refactor error handling and some minor improvements.
|
|
124
|
+
|
|
125
|
+
There is no compatibility issue detected.
|
|
126
|
+
|
|
127
|
+
For more details, please review [CHANGELOG.md](CHANGELOG.md).
|
|
128
|
+
|
|
129
|
+
## Upgrading from 1.0.x to 1.1.x
|
|
130
|
+
|
|
131
|
+
Version `1.1` adds some improvements on signature validation and solves some namespace conflicts.
|
|
132
|
+
|
|
133
|
+
## Upgrading from 0.9.x to 1.0.x
|
|
134
|
+
|
|
135
|
+
Version `1.0` is a recommended update for all Ruby SAML users as it includes security fixes.
|
|
136
|
+
|
|
137
|
+
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decrypt support.
|
|
138
|
+
|
|
139
|
+
### Important Changes
|
|
140
|
+
|
|
141
|
+
Please note the `get_idp_metadata` method raises an exception when it is not able to fetch the idp metadata, so review your integration if you are using this functionality.
|
|
142
|
+
|
|
143
|
+
## Upgrading from 0.8.x to 0.9.x
|
|
144
|
+
|
|
145
|
+
Version `0.9` adds many new features and improvements.
|
|
146
|
+
|
|
147
|
+
## Upgrading from 0.7.x to 0.8.x
|
|
148
|
+
|
|
149
|
+
Version `0.8.x` changes the namespace of the gem from `OneLogin::Saml` to `OneLogin::RubySaml`. Please update your implementations of the gem accordingly.
|
|
@@ -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.
|
|
@@ -68,7 +73,7 @@ module OneLogin
|
|
|
68
73
|
base64_request = encode(request)
|
|
69
74
|
request_params = {"SAMLRequest" => base64_request}
|
|
70
75
|
|
|
71
|
-
if settings.
|
|
76
|
+
if settings.idp_sso_service_binding == Utils::BINDINGS[:redirect] && settings.security[:authn_requests_signed] && settings.private_key
|
|
72
77
|
params['SigAlg'] = settings.security[:signature_method]
|
|
73
78
|
url_string = OneLogin::RubySaml::Utils.build_query(
|
|
74
79
|
:type => 'SAMLRequest',
|
|
@@ -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?
|
|
@@ -174,8 +179,7 @@ module OneLogin
|
|
|
174
179
|
end
|
|
175
180
|
|
|
176
181
|
def sign_document(document, settings)
|
|
177
|
-
|
|
178
|
-
if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
|
|
182
|
+
if settings.idp_sso_service_binding == Utils::BINDINGS[:post] && settings.security[:authn_requests_signed] && settings.private_key && settings.certificate
|
|
179
183
|
private_key = settings.get_sp_key
|
|
180
184
|
cert = settings.get_sp_cert
|
|
181
185
|
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
|
@@ -11,14 +11,18 @@ module OneLogin
|
|
|
11
11
|
|
|
12
12
|
# Auxiliary class to retrieve and parse the Identity Provider Metadata
|
|
13
13
|
#
|
|
14
|
+
# This class does not validate in any way the URL that is introduced,
|
|
15
|
+
# make sure to validate it properly before use it in a parse_remote method.
|
|
16
|
+
# Read the `Security warning` section of the README.md file to get more info
|
|
17
|
+
#
|
|
14
18
|
class IdpMetadataParser
|
|
15
19
|
|
|
16
20
|
module SamlMetadata
|
|
17
21
|
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"
|
|
22
|
+
METADATA = "urn:oasis:names:tc:SAML:2.0:metadata".freeze
|
|
23
|
+
DSIG = "http://www.w3.org/2000/09/xmldsig#".freeze
|
|
24
|
+
NAME_FORMAT = "urn:oasis:names:tc:SAML:2.0:attrname-format:*".freeze
|
|
25
|
+
SAML_ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion".freeze
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
NAMESPACE = {
|
|
@@ -26,7 +30,7 @@ module OneLogin
|
|
|
26
30
|
"NameFormat" => Vocabulary::NAME_FORMAT,
|
|
27
31
|
"saml" => Vocabulary::SAML_ASSERTION,
|
|
28
32
|
"ds" => Vocabulary::DSIG
|
|
29
|
-
}
|
|
33
|
+
}.freeze
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
include SamlMetadata::Vocabulary
|
|
@@ -34,6 +38,16 @@ module OneLogin
|
|
|
34
38
|
attr_reader :response
|
|
35
39
|
attr_reader :options
|
|
36
40
|
|
|
41
|
+
# fetch IdP descriptors from a metadata document
|
|
42
|
+
def self.get_idps(metadata_document, only_entity_id=nil)
|
|
43
|
+
path = "//md:EntityDescriptor#{only_entity_id && '[@entityID="' + only_entity_id + '"]'}/md:IDPSSODescriptor"
|
|
44
|
+
REXML::XPath.match(
|
|
45
|
+
metadata_document,
|
|
46
|
+
path,
|
|
47
|
+
SamlMetadata::NAMESPACE
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
37
51
|
# Parse the Identity Provider metadata and update the settings with the
|
|
38
52
|
# IdP values
|
|
39
53
|
#
|
|
@@ -42,9 +56,10 @@ module OneLogin
|
|
|
42
56
|
#
|
|
43
57
|
# @param options [Hash] options used for parsing the metadata and the returned Settings instance
|
|
44
58
|
# @option options [OneLogin::RubySaml::Settings, Hash] :settings the OneLogin::RubySaml::Settings object which gets the parsed metadata merged into or an hash for Settings overrides.
|
|
45
|
-
# @option options [
|
|
46
|
-
# @option options [Array<String>, nil] :
|
|
47
|
-
# @option options [String, nil] :
|
|
59
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used.
|
|
60
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
61
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
62
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
48
63
|
#
|
|
49
64
|
# @return [OneLogin::RubySaml::Settings]
|
|
50
65
|
#
|
|
@@ -60,9 +75,10 @@ module OneLogin
|
|
|
60
75
|
# @param validate_cert [Boolean] If true and the URL is HTTPs, the cert of the domain is checked.
|
|
61
76
|
#
|
|
62
77
|
# @param options [Hash] options used for parsing the metadata
|
|
63
|
-
# @option options [
|
|
64
|
-
# @option options [Array<String>, nil] :
|
|
65
|
-
# @option options [String, nil] :
|
|
78
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used.
|
|
79
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
80
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
81
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
66
82
|
#
|
|
67
83
|
# @return [Hash]
|
|
68
84
|
#
|
|
@@ -77,9 +93,10 @@ module OneLogin
|
|
|
77
93
|
# @param validate_cert [Boolean] If true and the URL is HTTPs, the cert of the domain is checked.
|
|
78
94
|
#
|
|
79
95
|
# @param options [Hash] options used for parsing the metadata
|
|
80
|
-
# @option options [
|
|
81
|
-
# @option options [Array<String>, nil] :
|
|
82
|
-
# @option options [String, nil] :
|
|
96
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, all found IdPs are returned.
|
|
97
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
98
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
99
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
83
100
|
#
|
|
84
101
|
# @return [Array<Hash>]
|
|
85
102
|
#
|
|
@@ -95,14 +112,27 @@ module OneLogin
|
|
|
95
112
|
#
|
|
96
113
|
# @param options [Hash] :settings to provide the OneLogin::RubySaml::Settings object or an hash for Settings overrides
|
|
97
114
|
# @option options [OneLogin::RubySaml::Settings, Hash] :settings the OneLogin::RubySaml::Settings object which gets the parsed metadata merged into or an hash for Settings overrides.
|
|
98
|
-
# @option options [
|
|
99
|
-
# @option options [Array<String>, nil] :
|
|
100
|
-
# @option options [String, nil] :
|
|
115
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used.
|
|
116
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
117
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
118
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
101
119
|
#
|
|
102
120
|
# @return [OneLogin::RubySaml::Settings]
|
|
103
121
|
def parse(idp_metadata, options = {})
|
|
104
122
|
parsed_metadata = parse_to_hash(idp_metadata, options)
|
|
105
123
|
|
|
124
|
+
unless parsed_metadata[:cache_duration].nil?
|
|
125
|
+
cache_valid_until_timestamp = OneLogin::RubySaml::Utils.parse_duration(parsed_metadata[:cache_duration])
|
|
126
|
+
unless cache_valid_until_timestamp.nil?
|
|
127
|
+
if parsed_metadata[:valid_until].nil? || cache_valid_until_timestamp < Time.parse(parsed_metadata[:valid_until], Time.now.utc).to_i
|
|
128
|
+
parsed_metadata[:valid_until] = Time.at(cache_valid_until_timestamp).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
# Remove the cache_duration because on the settings
|
|
133
|
+
# we only gonna suppot valid_until
|
|
134
|
+
parsed_metadata.delete(:cache_duration)
|
|
135
|
+
|
|
106
136
|
settings = options[:settings]
|
|
107
137
|
|
|
108
138
|
if settings.nil?
|
|
@@ -119,9 +149,10 @@ module OneLogin
|
|
|
119
149
|
# @param idp_metadata [String]
|
|
120
150
|
#
|
|
121
151
|
# @param options [Hash] options used for parsing the metadata and the returned Settings instance
|
|
122
|
-
# @option options [
|
|
123
|
-
# @option options [Array<String>, nil] :
|
|
124
|
-
# @option options [String, nil] :
|
|
152
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used.
|
|
153
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
154
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
155
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
125
156
|
#
|
|
126
157
|
# @return [Hash]
|
|
127
158
|
def parse_to_hash(idp_metadata, options = {})
|
|
@@ -133,21 +164,26 @@ module OneLogin
|
|
|
133
164
|
# @param idp_metadata [String]
|
|
134
165
|
#
|
|
135
166
|
# @param options [Hash] options used for parsing the metadata and the returned Settings instance
|
|
136
|
-
# @option options [
|
|
137
|
-
# @option options [Array<String>, nil] :
|
|
138
|
-
# @option options [String, nil] :
|
|
167
|
+
# @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, all found IdPs are returned.
|
|
168
|
+
# @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used.
|
|
169
|
+
# @option options [String, Array<String>, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used.
|
|
170
|
+
# @option options [String, Array<String>, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used.
|
|
139
171
|
#
|
|
140
172
|
# @return [Array<Hash>]
|
|
141
173
|
def parse_to_array(idp_metadata, options = {})
|
|
174
|
+
parse_to_idp_metadata_array(idp_metadata, options).map { |idp_md| idp_md.to_hash(options) }
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def parse_to_idp_metadata_array(idp_metadata, options = {})
|
|
142
178
|
@document = REXML::Document.new(idp_metadata)
|
|
143
179
|
@options = options
|
|
144
180
|
|
|
145
|
-
idpsso_descriptors =
|
|
181
|
+
idpsso_descriptors = self.class.get_idps(@document, options[:entity_id])
|
|
146
182
|
if !idpsso_descriptors.any?
|
|
147
183
|
raise ArgumentError.new("idp_metadata must contain an IDPSSODescriptor element")
|
|
148
184
|
end
|
|
149
185
|
|
|
150
|
-
|
|
186
|
+
idpsso_descriptors.map {|id| IdpMetadata.new(id, id.parent.attributes["entityID"])}
|
|
151
187
|
end
|
|
152
188
|
|
|
153
189
|
private
|
|
@@ -175,6 +211,7 @@ module OneLogin
|
|
|
175
211
|
end
|
|
176
212
|
|
|
177
213
|
get = Net::HTTP::Get.new(uri.request_uri)
|
|
214
|
+
get.basic_auth uri.user, uri.password if uri.user
|
|
178
215
|
@response = http.request(get)
|
|
179
216
|
return response.body if response.is_a? Net::HTTPSuccess
|
|
180
217
|
|
|
@@ -184,14 +221,7 @@ module OneLogin
|
|
|
184
221
|
end
|
|
185
222
|
|
|
186
223
|
class IdpMetadata
|
|
187
|
-
|
|
188
|
-
path = "//md:EntityDescriptor#{only_entity_id && '[@entityID="' + only_entity_id + '"]'}/md:IDPSSODescriptor"
|
|
189
|
-
REXML::XPath.match(
|
|
190
|
-
metadata_document,
|
|
191
|
-
path,
|
|
192
|
-
SamlMetadata::NAMESPACE
|
|
193
|
-
)
|
|
194
|
-
end
|
|
224
|
+
attr_reader :idpsso_descriptor, :entity_id
|
|
195
225
|
|
|
196
226
|
def initialize(idpsso_descriptor, entity_id)
|
|
197
227
|
@idpsso_descriptor = idpsso_descriptor
|
|
@@ -199,32 +229,27 @@ module OneLogin
|
|
|
199
229
|
end
|
|
200
230
|
|
|
201
231
|
def to_hash(options = {})
|
|
232
|
+
sso_binding = options[:sso_binding]
|
|
233
|
+
slo_binding = options[:slo_binding]
|
|
202
234
|
{
|
|
203
235
|
:idp_entity_id => @entity_id,
|
|
204
|
-
:name_identifier_format => idp_name_id_format,
|
|
205
|
-
:
|
|
206
|
-
:
|
|
236
|
+
:name_identifier_format => idp_name_id_format(options[:name_id_format]),
|
|
237
|
+
:idp_sso_service_url => single_signon_service_url(sso_binding),
|
|
238
|
+
:idp_sso_service_binding => single_signon_service_binding(sso_binding),
|
|
239
|
+
:idp_slo_service_url => single_logout_service_url(slo_binding),
|
|
240
|
+
:idp_slo_service_binding => single_logout_service_binding(slo_binding),
|
|
241
|
+
:idp_slo_response_service_url => single_logout_response_service_url(slo_binding),
|
|
207
242
|
:idp_attribute_names => attribute_names,
|
|
208
243
|
:idp_cert => nil,
|
|
209
244
|
:idp_cert_fingerprint => nil,
|
|
210
245
|
:idp_cert_multi => nil,
|
|
211
|
-
:valid_until => valid_until
|
|
246
|
+
:valid_until => valid_until,
|
|
247
|
+
:cache_duration => cache_duration,
|
|
212
248
|
}.tap do |response_hash|
|
|
213
249
|
merge_certificates_into(response_hash) unless certificates.nil?
|
|
214
250
|
end
|
|
215
251
|
end
|
|
216
252
|
|
|
217
|
-
# @return [String|nil] IdP Name ID Format value if exists
|
|
218
|
-
#
|
|
219
|
-
def idp_name_id_format
|
|
220
|
-
node = REXML::XPath.first(
|
|
221
|
-
@idpsso_descriptor,
|
|
222
|
-
"md:NameIDFormat",
|
|
223
|
-
SamlMetadata::NAMESPACE
|
|
224
|
-
)
|
|
225
|
-
Utils.element_text(node)
|
|
226
|
-
end
|
|
227
|
-
|
|
228
253
|
# @return [String|nil] 'validUntil' attribute of metadata
|
|
229
254
|
#
|
|
230
255
|
def valid_until
|
|
@@ -232,7 +257,26 @@ module OneLogin
|
|
|
232
257
|
root.attributes['validUntil'] if root && root.attributes
|
|
233
258
|
end
|
|
234
259
|
|
|
235
|
-
# @
|
|
260
|
+
# @return [String|nil] 'cacheDuration' attribute of metadata
|
|
261
|
+
#
|
|
262
|
+
def cache_duration
|
|
263
|
+
root = @idpsso_descriptor.root
|
|
264
|
+
root.attributes['cacheDuration'] if root && root.attributes
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# @param name_id_priority [String|Array<String>] The prioritized list of NameIDFormat values to select. Will select first value if nil.
|
|
268
|
+
# @return [String|nil] IdP NameIDFormat value if exists
|
|
269
|
+
#
|
|
270
|
+
def idp_name_id_format(name_id_priority = nil)
|
|
271
|
+
nodes = REXML::XPath.match(
|
|
272
|
+
@idpsso_descriptor,
|
|
273
|
+
"md:NameIDFormat",
|
|
274
|
+
SamlMetadata::NAMESPACE
|
|
275
|
+
)
|
|
276
|
+
first_ranked_text(nodes, name_id_priority)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil.
|
|
236
280
|
# @return [String|nil] SingleSignOnService binding if exists
|
|
237
281
|
#
|
|
238
282
|
def single_signon_service_binding(binding_priority = nil)
|
|
@@ -241,19 +285,26 @@ module OneLogin
|
|
|
241
285
|
"md:SingleSignOnService/@Binding",
|
|
242
286
|
SamlMetadata::NAMESPACE
|
|
243
287
|
)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
288
|
+
first_ranked_value(nodes, binding_priority)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil.
|
|
292
|
+
# @return [String|nil] SingleLogoutService binding if exists
|
|
293
|
+
#
|
|
294
|
+
def single_logout_service_binding(binding_priority = nil)
|
|
295
|
+
nodes = REXML::XPath.match(
|
|
296
|
+
@idpsso_descriptor,
|
|
297
|
+
"md:SingleLogoutService/@Binding",
|
|
298
|
+
SamlMetadata::NAMESPACE
|
|
299
|
+
)
|
|
300
|
+
first_ranked_value(nodes, binding_priority)
|
|
250
301
|
end
|
|
251
302
|
|
|
252
|
-
# @param
|
|
303
|
+
# @param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil.
|
|
253
304
|
# @return [String|nil] SingleSignOnService endpoint if exists
|
|
254
305
|
#
|
|
255
|
-
def single_signon_service_url(
|
|
256
|
-
binding = single_signon_service_binding(
|
|
306
|
+
def single_signon_service_url(binding_priority = nil)
|
|
307
|
+
binding = single_signon_service_binding(binding_priority)
|
|
257
308
|
return if binding.nil?
|
|
258
309
|
|
|
259
310
|
node = REXML::XPath.first(
|
|
@@ -261,39 +312,37 @@ module OneLogin
|
|
|
261
312
|
"md:SingleSignOnService[@Binding=\"#{binding}\"]/@Location",
|
|
262
313
|
SamlMetadata::NAMESPACE
|
|
263
314
|
)
|
|
264
|
-
|
|
315
|
+
node.value if node
|
|
265
316
|
end
|
|
266
317
|
|
|
267
|
-
# @param binding_priority [Array]
|
|
268
|
-
# @return [String|nil] SingleLogoutService
|
|
318
|
+
# @param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil.
|
|
319
|
+
# @return [String|nil] SingleLogoutService endpoint if exists
|
|
269
320
|
#
|
|
270
|
-
def
|
|
271
|
-
|
|
321
|
+
def single_logout_service_url(binding_priority = nil)
|
|
322
|
+
binding = single_logout_service_binding(binding_priority)
|
|
323
|
+
return if binding.nil?
|
|
324
|
+
|
|
325
|
+
node = REXML::XPath.first(
|
|
272
326
|
@idpsso_descriptor,
|
|
273
|
-
"md:SingleLogoutService
|
|
327
|
+
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@Location",
|
|
274
328
|
SamlMetadata::NAMESPACE
|
|
275
329
|
)
|
|
276
|
-
if
|
|
277
|
-
values = nodes.map(&:value)
|
|
278
|
-
binding_priority.detect{ |binding| values.include? binding }
|
|
279
|
-
else
|
|
280
|
-
nodes.first.value if nodes.any?
|
|
281
|
-
end
|
|
330
|
+
node.value if node
|
|
282
331
|
end
|
|
283
332
|
|
|
284
|
-
# @param
|
|
285
|
-
# @return [String|nil] SingleLogoutService
|
|
333
|
+
# @param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil.
|
|
334
|
+
# @return [String|nil] SingleLogoutService response url if exists
|
|
286
335
|
#
|
|
287
|
-
def
|
|
288
|
-
binding = single_logout_service_binding(
|
|
336
|
+
def single_logout_response_service_url(binding_priority = nil)
|
|
337
|
+
binding = single_logout_service_binding(binding_priority)
|
|
289
338
|
return if binding.nil?
|
|
290
339
|
|
|
291
340
|
node = REXML::XPath.first(
|
|
292
341
|
@idpsso_descriptor,
|
|
293
|
-
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@
|
|
342
|
+
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@ResponseLocation",
|
|
294
343
|
SamlMetadata::NAMESPACE
|
|
295
344
|
)
|
|
296
|
-
|
|
345
|
+
node.value if node
|
|
297
346
|
end
|
|
298
347
|
|
|
299
348
|
# @return [String|nil] Unformatted Certificate if exists
|
|
@@ -375,15 +424,41 @@ module OneLogin
|
|
|
375
424
|
parsed_metadata[:idp_cert_fingerprint_algorithm]
|
|
376
425
|
)
|
|
377
426
|
end
|
|
378
|
-
else
|
|
379
|
-
# symbolize keys of certificates and pass it on
|
|
380
|
-
parsed_metadata[:idp_cert_multi] = Hash[certificates.map { |k, v| [k.to_sym, v] }]
|
|
381
427
|
end
|
|
428
|
+
|
|
429
|
+
# symbolize keys of certificates and pass it on
|
|
430
|
+
parsed_metadata[:idp_cert_multi] = Hash[certificates.map { |k, v| [k.to_sym, v] }]
|
|
382
431
|
end
|
|
383
432
|
|
|
384
433
|
def certificates_has_one(key)
|
|
385
434
|
certificates.key?(key) && certificates[key].size == 1
|
|
386
435
|
end
|
|
436
|
+
|
|
437
|
+
private
|
|
438
|
+
|
|
439
|
+
def first_ranked_text(nodes, priority = nil)
|
|
440
|
+
return unless nodes.any?
|
|
441
|
+
|
|
442
|
+
priority = Array(priority)
|
|
443
|
+
if priority.any?
|
|
444
|
+
values = nodes.map(&:text)
|
|
445
|
+
Array(priority).detect { |candidate| values.include?(candidate) }
|
|
446
|
+
else
|
|
447
|
+
nodes.first.text
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def first_ranked_value(nodes, priority = nil)
|
|
452
|
+
return unless nodes.any?
|
|
453
|
+
|
|
454
|
+
priority = Array(priority)
|
|
455
|
+
if priority.any?
|
|
456
|
+
values = nodes.map(&:value)
|
|
457
|
+
priority.detect { |candidate| values.include?(candidate) }
|
|
458
|
+
else
|
|
459
|
+
nodes.first.value
|
|
460
|
+
end
|
|
461
|
+
end
|
|
387
462
|
end
|
|
388
463
|
|
|
389
464
|
def merge_parsed_metadata_into(settings, parsed_metadata)
|
|
@@ -393,10 +468,6 @@ module OneLogin
|
|
|
393
468
|
|
|
394
469
|
settings
|
|
395
470
|
end
|
|
396
|
-
|
|
397
|
-
if self.respond_to?(:private_constant)
|
|
398
|
-
private_constant :SamlMetadata, :IdpMetadata
|
|
399
|
-
end
|
|
400
471
|
end
|
|
401
472
|
end
|
|
402
473
|
end
|