ruby-saml 1.9.0 → 1.12.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 +5 -5
- data/.travis.yml +30 -14
- data/README.md +108 -22
- data/changelog.md +38 -0
- data/lib/onelogin/ruby-saml/attributes.rb +24 -1
- data/lib/onelogin/ruby-saml/authrequest.rb +23 -6
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +239 -171
- data/lib/onelogin/ruby-saml/logging.rb +3 -3
- data/lib/onelogin/ruby-saml/logoutrequest.rb +20 -5
- data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -9
- data/lib/onelogin/ruby-saml/metadata.rb +11 -3
- data/lib/onelogin/ruby-saml/response.rb +67 -21
- data/lib/onelogin/ruby-saml/saml_message.rb +12 -2
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +73 -7
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +20 -1
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +38 -16
- data/lib/onelogin/ruby-saml/utils.rb +74 -1
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +34 -6
- data/ruby-saml.gemspec +15 -7
- metadata +36 -278
- 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 -579
- 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 -67
- data/test/logoutrequest_test.rb +0 -226
- data/test/logoutresponse_test.rb +0 -402
- 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 -53
- data/test/metadata/no_idp_descriptor.xml +0 -21
- data/test/metadata_test.rb +0 -331
- data/test/request_test.rb +0 -323
- data/test/response_test.rb +0 -1619
- 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 -329
- data/test/slo_logoutrequest_test.rb +0 -448
- data/test/slo_logoutresponse_test.rb +0 -199
- data/test/test_helper.rb +0 -327
- data/test/utils_test.rb +0 -254
- 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: 43bc92cf8a14835577d9bb32d1bdcef71fd5ffccb351dd41ac9b56863fb173c7
|
4
|
+
data.tar.gz: e7975fcf413d9c64801f7b5190246685548205034dc74315bc169738697e1006
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a09fcb8777969eb6d54b29d20520c7e17e3f7dc128cfc81475eba8c9b31f5926f2b64d308b18268762b43fb60cf7956f6e266c1f5343d2b9d58e545be0c3392
|
7
|
+
data.tar.gz: 8e9008647a610935764b2f578b76c5eb72d09be482d76b5f4d8ab51fd29d4569a3ba2e2db61f63fbdde27bd1be14bf4afdeffe1c7f699afc0b7d5e1c85d0fe09
|
data/.travis.yml
CHANGED
@@ -1,32 +1,48 @@
|
|
1
|
-
sudo: false
|
2
1
|
language: ruby
|
3
2
|
rvm:
|
4
|
-
- 1.8.7
|
5
3
|
- 1.9.3
|
6
4
|
- 2.0.0
|
7
|
-
- 2.1.
|
8
|
-
- 2.2.
|
9
|
-
- 2.3.
|
10
|
-
- 2.4.
|
11
|
-
- 2.5.
|
12
|
-
-
|
5
|
+
- 2.1.10
|
6
|
+
- 2.2.10
|
7
|
+
- 2.3.8
|
8
|
+
- 2.4.6
|
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
|
19
|
+
before_install:
|
20
|
+
- gem update bundler
|
19
21
|
matrix:
|
20
22
|
exclude:
|
21
|
-
- rvm: 1.8.7
|
22
|
-
gemfile: Gemfile
|
23
|
-
- rvm: ree
|
24
|
-
gemfile: Gemfile
|
25
23
|
- rvm: jruby-1.7.27
|
26
24
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
27
25
|
- rvm: jruby-9.1.17.0
|
28
26
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
29
|
-
- rvm: jruby-9.2.
|
27
|
+
- rvm: jruby-9.2.13.0
|
28
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
29
|
+
- rvm: 2.1.5
|
30
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
31
|
+
- rvm: 2.1.10
|
32
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
33
|
+
- rvm: 2.2.10
|
34
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
35
|
+
- rvm: 2.3.8
|
36
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
37
|
+
- rvm: 2.4.6
|
38
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
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
|
44
|
+
gemfile: gemfiles/nokogiri-1.5.gemfile
|
45
|
+
- rvm: 3.0.0
|
30
46
|
gemfile: gemfiles/nokogiri-1.5.gemfile
|
31
47
|
env:
|
32
48
|
- JRUBY_OPTS="--debug"
|
data/README.md
CHANGED
@@ -1,4 +1,22 @@
|
|
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
|
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)](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
|
2
|
+
|
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
|
+
## Updating from 1.10.x to 1.11.0
|
8
|
+
Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
|
9
|
+
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.
|
10
|
+
|
11
|
+
Version `1.10.2` includes the `valid_until` attribute in parsed IdP metadata.
|
12
|
+
|
13
|
+
Version `1.10.1` improves Ruby 1.8.7 support.
|
14
|
+
|
15
|
+
## Updating from 1.9.0 to 1.10.0
|
16
|
+
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/
|
17
|
+
|
18
|
+
## Updating from 1.8.0 to 1.9.0
|
19
|
+
Version `1.9.0` better supports Ruby 2.4+ and JRuby 9.2.0.0. `Settings` initialization now has a second parameter, `keep_security_settings` (default: false), which saves security settings attributes that are not explicitly overridden, if set to true.
|
2
20
|
|
3
21
|
## Updating from 1.7.X to 1.8.0
|
4
22
|
On Version `1.8.0`, creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState param will not generate a URL with an empty RelayState parameter anymore. It also changes the invalid audience error message.
|
@@ -99,8 +117,12 @@ We created a demo project for Rails4 that uses the latest version of this librar
|
|
99
117
|
* 2.2.x
|
100
118
|
* 2.3.x
|
101
119
|
* 2.4.x
|
120
|
+
* 2.5.x
|
121
|
+
* 2.6.x
|
122
|
+
* 2.7.x
|
102
123
|
* JRuby 1.7.19
|
103
124
|
* JRuby 9.0.0.0
|
125
|
+
* JRuby 9.2.0.0
|
104
126
|
|
105
127
|
## Adding Features, Pull Requests
|
106
128
|
* Fork the repository
|
@@ -114,6 +136,17 @@ We created a demo project for Rails4 that uses the latest version of this librar
|
|
114
136
|
|
115
137
|
If you believe you have discovered a security vulnerability in this gem, please report it at https://www.onelogin.com/security with a description. We follow responsible disclosure guidelines, and will work with you to quickly find a resolution.
|
116
138
|
|
139
|
+
### Security warning
|
140
|
+
|
141
|
+
Some tools may incorrectly report ruby-saml is a potential security vulnerability.
|
142
|
+
ruby-saml depends on Nokogiri, and it's possible to use Nokogiri in a dangerous way
|
143
|
+
(by enabling its DTDLOAD option and disabling its NONET option).
|
144
|
+
This dangerous Nokogiri configuration, which is sometimes used by other components,
|
145
|
+
can create an XML External Entity (XXE) vulnerability if the XML data is not trusted.
|
146
|
+
However, ruby-saml never enables this dangerous Nokogiri configuration;
|
147
|
+
ruby-saml never enables DTDLOAD, and it never disables NONET.
|
148
|
+
|
149
|
+
|
117
150
|
## Getting Started
|
118
151
|
In order to use the toolkit you will need to install the gem (either manually or using Bundler), and require the library in your Ruby application:
|
119
152
|
|
@@ -121,7 +154,7 @@ Using `Gemfile`
|
|
121
154
|
|
122
155
|
```ruby
|
123
156
|
# latest stable
|
124
|
-
gem 'ruby-saml', '~> 1.
|
157
|
+
gem 'ruby-saml', '~> 1.11.0'
|
125
158
|
|
126
159
|
# or track master for bleeding-edge
|
127
160
|
gem 'ruby-saml', :github => 'onelogin/ruby-saml'
|
@@ -170,7 +203,7 @@ To override the default behavior and control the destination of log messages, pr
|
|
170
203
|
a ruby Logger object to the gem's logging singleton:
|
171
204
|
|
172
205
|
```ruby
|
173
|
-
OneLogin::RubySaml::Logging.logger = Logger.new(
|
206
|
+
OneLogin::RubySaml::Logging.logger = Logger.new('/var/log/ruby-saml.log')
|
174
207
|
```
|
175
208
|
|
176
209
|
## The Initialization Phase
|
@@ -184,6 +217,17 @@ def init
|
|
184
217
|
end
|
185
218
|
```
|
186
219
|
|
220
|
+
If the SP knows who should be authenticated in the IdP, then can provide that info as follows:
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
def init
|
224
|
+
request = OneLogin::RubySaml::Authrequest.new
|
225
|
+
saml_settings.name_identifier_value_requested = "testuser@example.com"
|
226
|
+
saml_settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
227
|
+
redirect_to(request.create(saml_settings))
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
187
231
|
Once you've redirected back to the identity provider, it will ensure that the user has been authorized and redirect back to your application for final consumption. This can look something like this (the `authorize_success` and `authorize_failure` methods are specific to your application):
|
188
232
|
|
189
233
|
```ruby
|
@@ -197,6 +241,7 @@ def consume
|
|
197
241
|
session[:attributes] = response.attributes
|
198
242
|
else
|
199
243
|
authorize_failure # This method shows an error message
|
244
|
+
# List of errors is available in response.errors array
|
200
245
|
end
|
201
246
|
end
|
202
247
|
```
|
@@ -218,10 +263,10 @@ def saml_settings
|
|
218
263
|
settings = OneLogin::RubySaml::Settings.new
|
219
264
|
|
220
265
|
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
221
|
-
settings.
|
266
|
+
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
|
222
267
|
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
|
223
|
-
settings.
|
224
|
-
settings.
|
268
|
+
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
|
269
|
+
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
|
225
270
|
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
226
271
|
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
|
227
272
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
@@ -242,6 +287,8 @@ def saml_settings
|
|
242
287
|
end
|
243
288
|
```
|
244
289
|
|
290
|
+
The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
|
291
|
+
|
245
292
|
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:
|
246
293
|
|
247
294
|
```ruby
|
@@ -249,6 +296,7 @@ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnst
|
|
249
296
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
|
250
297
|
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
|
251
298
|
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
|
299
|
+
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_audience: true}) # skips audience check
|
252
300
|
```
|
253
301
|
|
254
302
|
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:
|
@@ -272,6 +320,7 @@ class SamlController < ApplicationController
|
|
272
320
|
session[:attributes] = response.attributes
|
273
321
|
else
|
274
322
|
authorize_failure # This method shows an error message
|
323
|
+
# List of errors is available in response.errors array
|
275
324
|
end
|
276
325
|
end
|
277
326
|
|
@@ -281,8 +330,8 @@ class SamlController < ApplicationController
|
|
281
330
|
settings = OneLogin::RubySaml::Settings.new
|
282
331
|
|
283
332
|
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
284
|
-
settings.
|
285
|
-
settings.
|
333
|
+
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
|
334
|
+
settings.idp_sso_service_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
|
286
335
|
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
287
336
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
288
337
|
|
@@ -344,7 +393,7 @@ def saml_settings
|
|
344
393
|
settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
|
345
394
|
|
346
395
|
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
347
|
-
settings.
|
396
|
+
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
|
348
397
|
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
349
398
|
# Optional for most SAML IdPs
|
350
399
|
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
|
@@ -355,11 +404,11 @@ end
|
|
355
404
|
The following attributes are set:
|
356
405
|
* idp_entity_id
|
357
406
|
* name_identifier_format
|
358
|
-
*
|
359
|
-
*
|
407
|
+
* idp_sso_service_url
|
408
|
+
* idp_slo_service_url
|
360
409
|
* idp_attribute_names
|
361
|
-
* idp_cert
|
362
|
-
* idp_cert_fingerprint
|
410
|
+
* idp_cert
|
411
|
+
* idp_cert_fingerprint
|
363
412
|
* idp_cert_multi
|
364
413
|
|
365
414
|
### Retrieve one Entity Descriptor when many exist in Metadata
|
@@ -422,6 +471,9 @@ Imagine this `saml:AttributeStatement`
|
|
422
471
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
|
423
472
|
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>
|
424
473
|
</saml:Attribute>
|
474
|
+
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
|
475
|
+
<saml:AttributeValue>usersName</saml:AttributeValue>
|
476
|
+
</saml:Attribute>
|
425
477
|
</saml:AttributeStatement>
|
426
478
|
```
|
427
479
|
|
@@ -432,7 +484,8 @@ pp(response.attributes) # is an OneLogin::RubySaml::Attributes object
|
|
432
484
|
"another_value"=>["value1", "value2"],
|
433
485
|
"role"=>["role1", "role2", "role3"],
|
434
486
|
"attribute_with_nil_value"=>[nil],
|
435
|
-
"attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]
|
487
|
+
"attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]
|
488
|
+
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"=>["usersName"]}>
|
436
489
|
|
437
490
|
# Active single_value_compatibility
|
438
491
|
OneLogin::RubySaml::Attributes.single_value_compatibility = true
|
@@ -449,6 +502,9 @@ pp(response.attributes.single(:role))
|
|
449
502
|
pp(response.attributes.multi(:role))
|
450
503
|
# => ["role1", "role2", "role3"]
|
451
504
|
|
505
|
+
pp(response.attributes.fetch(:role))
|
506
|
+
# => "role1"
|
507
|
+
|
452
508
|
pp(response.attributes[:attribute_with_nil_value])
|
453
509
|
# => nil
|
454
510
|
|
@@ -464,6 +520,9 @@ pp(response.attributes.single(:not_exists))
|
|
464
520
|
pp(response.attributes.multi(:not_exists))
|
465
521
|
# => nil
|
466
522
|
|
523
|
+
pp(response.attributes.fetch(/givenname/))
|
524
|
+
# => "usersName"
|
525
|
+
|
467
526
|
# Deactive single_value_compatibility
|
468
527
|
OneLogin::RubySaml::Attributes.single_value_compatibility = false
|
469
528
|
|
@@ -479,6 +538,9 @@ pp(response.attributes.single(:role))
|
|
479
538
|
pp(response.attributes.multi(:role))
|
480
539
|
# => ["role1", "role2", "role3"]
|
481
540
|
|
541
|
+
pp(response.attributes.fetch(:role))
|
542
|
+
# => ["role1", "role2", "role3"]
|
543
|
+
|
482
544
|
pp(response.attributes[:attribute_with_nil_value])
|
483
545
|
# => [nil]
|
484
546
|
|
@@ -493,11 +555,17 @@ pp(response.attributes.single(:not_exists))
|
|
493
555
|
|
494
556
|
pp(response.attributes.multi(:not_exists))
|
495
557
|
# => nil
|
558
|
+
|
559
|
+
pp(response.attributes.fetch(/givenname/))
|
560
|
+
# => ["usersName"]
|
496
561
|
```
|
497
562
|
|
498
563
|
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').
|
499
564
|
To add a `saml:AuthnContextDeclRef`, define `settings.authn_context_decl_ref`.
|
500
565
|
|
566
|
+
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
|
567
|
+
building the authrequest object.
|
568
|
+
|
501
569
|
|
502
570
|
## Signing
|
503
571
|
|
@@ -525,6 +593,8 @@ The settings related to sign are stored in the `security` attribute of the setti
|
|
525
593
|
# Embeded signature or HTTP GET parameter signature
|
526
594
|
# Note that metadata signature is always embedded regardless of this value.
|
527
595
|
settings.security[:embed_sign] = false
|
596
|
+
settings.security[:check_idp_cert_expiration] = false # Enable or not IdP x509 cert expiration check
|
597
|
+
settings.security[:check_sp_cert_expiration] = false # Enable or not SP x509 cert expiration check
|
528
598
|
```
|
529
599
|
|
530
600
|
Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
|
@@ -532,7 +602,7 @@ Remember to provide it to the Signature builder if you are sending a `GET RelayS
|
|
532
602
|
signature validation process will fail at the Identity Provider.
|
533
603
|
|
534
604
|
The Service Provider will sign the request/responses with its private key.
|
535
|
-
The Identity Provider will validate the sign of the received request/responses with the public
|
605
|
+
The Identity Provider will validate the sign of the received request/responses with the public x509 cert of the
|
536
606
|
Service Provider.
|
537
607
|
|
538
608
|
Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
|
@@ -573,21 +643,27 @@ def sp_logout_request
|
|
573
643
|
# LogoutRequest accepts plain browser requests w/o paramters
|
574
644
|
settings = saml_settings
|
575
645
|
|
576
|
-
if settings.
|
646
|
+
if settings.idp_slo_service_url.nil?
|
577
647
|
logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
|
578
648
|
delete_session
|
579
649
|
else
|
580
650
|
|
581
|
-
# Since we created a new SAML request, save the transaction_id
|
582
|
-
# to compare it with the response we get back
|
583
651
|
logout_request = OneLogin::RubySaml::Logoutrequest.new()
|
584
|
-
session[:
|
585
|
-
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{session[:transaction_id]}'"
|
652
|
+
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
|
586
653
|
|
587
654
|
if settings.name_identifier_value.nil?
|
588
655
|
settings.name_identifier_value = session[:userid]
|
589
656
|
end
|
590
657
|
|
658
|
+
# Ensure user is logged out before redirect to IdP, in case anything goes wrong during single logout process (as recommended by saml2int [SDP-SP34])
|
659
|
+
logged_user = session[:userid]
|
660
|
+
logger.info "Delete session for '#{session[:userid]}'"
|
661
|
+
delete_session
|
662
|
+
|
663
|
+
# Save the transaction_id to compare it with the response we get back
|
664
|
+
session[:transaction_id] = logout_request.uuid
|
665
|
+
session[:logged_out_user] = logged_user
|
666
|
+
|
591
667
|
relayState = url_for controller: 'saml', action: 'index'
|
592
668
|
redirect_to(logout_request.create(settings, :RelayState => relayState))
|
593
669
|
end
|
@@ -615,7 +691,7 @@ def process_logout_response
|
|
615
691
|
logger.error "The SAML Logout Response is invalid"
|
616
692
|
else
|
617
693
|
# Actually log out this session
|
618
|
-
logger.info "
|
694
|
+
logger.info "SLO completed for '#{session[:logged_out_user]}'"
|
619
695
|
delete_session
|
620
696
|
end
|
621
697
|
end
|
@@ -624,6 +700,8 @@ end
|
|
624
700
|
def delete_session
|
625
701
|
session[:userid] = nil
|
626
702
|
session[:attributes] = nil
|
703
|
+
session[:transaction_id] = nil
|
704
|
+
session[:logged_out_user] = nil
|
627
705
|
end
|
628
706
|
```
|
629
707
|
|
@@ -636,7 +714,7 @@ def idp_logout_request
|
|
636
714
|
logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
|
637
715
|
if !logout_request.is_valid?
|
638
716
|
logger.error "IdP initiated LogoutRequest was not valid!"
|
639
|
-
render :inline => logger.error
|
717
|
+
return render :inline => logger.error
|
640
718
|
end
|
641
719
|
logger.info "IdP initiated Logout for #{logout_request.name_id}"
|
642
720
|
|
@@ -691,6 +769,14 @@ class SamlController < ApplicationController
|
|
691
769
|
end
|
692
770
|
```
|
693
771
|
|
772
|
+
You can add ValidUntil and CacheDuration to the XML Metadata using instead
|
773
|
+
```ruby
|
774
|
+
# Valid until => 2 days from now
|
775
|
+
# Cache duration = 604800s = 1 week
|
776
|
+
valid_until = Time.now + 172800
|
777
|
+
cache_duration = 604800
|
778
|
+
meta.generate(settings, false, valid_until, cache_duration)
|
779
|
+
```
|
694
780
|
|
695
781
|
## Clock Drift
|
696
782
|
|
data/changelog.md
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
# RubySaml Changelog
|
2
2
|
|
3
|
+
### 1.12.0 (Feb 18, 2021)
|
4
|
+
* Support AES-128-GCM, AES-192-GCM, and AES-256-GCM encryptions
|
5
|
+
* Parse & return SLO ResponseLocation in IDPMetadataParser & Settings
|
6
|
+
* Adding idp_sso_service_url and idp_slo_service_url settings
|
7
|
+
* [#536](https://github.com/onelogin/ruby-saml/pull/536) Adding feth method to be able retrieve attributes based on regex
|
8
|
+
* Reduce size of built gem by excluding the test folder
|
9
|
+
* Improve protection on Zlib deflate decompression bomb attack.
|
10
|
+
* Add ValidUntil and cacheDuration support on Metadata generator
|
11
|
+
* Add support for cacheDuration at the IdpMetadataParser
|
12
|
+
* Support customizable statusCode on generated LogoutResponse
|
13
|
+
* [#545](https://github.com/onelogin/ruby-saml/pull/545) More specific error messages for signature validation
|
14
|
+
* Support Process Transform
|
15
|
+
* Raise SettingError if invoking an action with no endpoint defined on the settings
|
16
|
+
* Made IdpMetadataParser more extensible for subclasses
|
17
|
+
*[#548](https://github.com/onelogin/ruby-saml/pull/548) Add :skip_audience option
|
18
|
+
* [#555](https://github.com/onelogin/ruby-saml/pull/555) Define 'soft' variable to prevent exception when doc cert is invalid
|
19
|
+
* Improve documentation
|
20
|
+
|
21
|
+
### 1.11.0 (Jul 24, 2019)
|
22
|
+
|
23
|
+
* Deprecate settings.issuer in favor of settings.sp_entity_id
|
24
|
+
* Add support for certification expiration
|
25
|
+
|
26
|
+
### 1.10.2 (Apr 29, 2019)
|
27
|
+
|
28
|
+
* Add valid until, accessor
|
29
|
+
* Fix Rubygem metadata that requested nokogiri <= 1.5.11
|
30
|
+
|
31
|
+
### 1.10.1 (Apr 08, 2019)
|
32
|
+
|
33
|
+
* Fix ruby 1.8.7 incompatibilities
|
34
|
+
|
35
|
+
### 1.10.0 (Mar 21, 2019)
|
36
|
+
* Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user to be authenticated
|
37
|
+
* Improves IdpMetadataParser to allow parse multiple IDPSSODescriptors
|
38
|
+
* Improves format_cert method to accept certs with /\x0d/
|
39
|
+
* Forces nokogiri >= 1.8.2 when possible
|
40
|
+
|
3
41
|
### 1.9.0 (Sept 03, 2018)
|
4
42
|
* [#458](https://github.com/onelogin/ruby-saml/pull/458) Remove ruby 2.4+ warnings
|
5
43
|
* Improve JRuby support
|
@@ -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.method_exists? :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
|