ruby-saml 1.12.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,118 +1,25 @@
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)
1
+ # Ruby SAML
2
+ [![Build Status](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml/badge.svg?query=branch%3Amaster)](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml?query=branch%3Amaster)
3
+ [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master)](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
2
4
 
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.
20
-
21
- ## Updating from 1.7.X to 1.8.0
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.
23
-
24
- ## Updating from 1.6.0 to 1.7.0
25
-
26
- Version `1.7.0` is a recommended update for all Ruby SAML users as it includes a fix for the [CVE-2017-11428](https://www.cvedetails.com/cve/CVE-2017-11428/) vulnerability.
27
-
28
- ## Updating from 1.5.0 to 1.6.0
29
-
30
- Version `1.6.0` changes the preferred way to construct instances of `Logoutresponse` and `SloLogoutrequest`. Previously the _SAMLResponse_, _RelayState_, and _SigAlg_ parameters of these message types were provided via the constructor's `options[:get_params]` parameter. Unfortunately this can result in incompatibility with other SAML implementations; signatures are specified to be computed based on the _sender's_ URI-encoding of the message, which can differ from that of Ruby SAML. In particular, Ruby SAML's URI-encoding does not match that of Microsoft ADFS, so messages from ADFS can fail signature validation.
31
-
32
- The new preferred way to provide _SAMLResponse_, _RelayState_, and _SigAlg_ is via the `options[:raw_get_params]` parameter. For example:
33
-
34
- ```ruby
35
- # In this example `query_params` is assumed to contain decoded query parameters,
36
- # and `raw_query_params` is assumed to contain encoded query parameters as sent by the IDP.
37
- settings = {
38
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
39
- settings.soft = false
40
- }
41
- options = {
42
- get_params: {
43
- "Signature" => query_params["Signature"],
44
- },
45
- raw_get_params: {
46
- "SAMLRequest" => raw_query_params["SAMLRequest"],
47
- "SigAlg" => raw_query_params["SigAlg"],
48
- "RelayState" => raw_query_params["RelayState"],
49
- },
50
- }
51
- slo_logout_request = OneLogin::RubySaml::SloLogoutrequest.new(query_params["SAMLRequest"], settings, options)
52
- raise "Invalid Logout Request" unless slo_logout_request.is_valid?
53
- ```
54
-
55
- The old form is still supported for backward compatibility, but all Ruby SAML users should prefer `options[:raw_get_params]` where possible to ensure compatibility with other SAML implementations.
56
-
57
- ## Updating from 1.4.2 to 1.4.3
58
-
59
- Version `1.4.3` introduces Recipient validation of SubjectConfirmation elements.
60
- The 'Recipient' value is compared with the settings.assertion_consumer_service_url
61
- value.
62
- If you want to skip that validation, add the :skip_recipient_check option to the
63
- initialize method of the Response object.
64
-
65
- Parsing metadata that contains more than one certificate will propagate the
66
- idp_cert_multi property rather than idp_cert. See [signature validation
67
- section](#signature-validation) for details.
68
-
69
- ## Updating from 1.3.x to 1.4.X
70
-
71
- Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
72
-
73
- ## Updating from 1.2.x to 1.3.X
74
-
75
- Version `1.3.0` is a recommended update for all Ruby SAML users as it includes security fixes. It adds security improvements in order to prevent Signature wrapping attacks. [CVE-2016-5697](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5697)
76
-
77
- ## Updating from 1.1.x to 1.2.X
78
-
79
- Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favour of SecureRandom, refactor error handling and some minor improvements
80
-
81
- There is no compatibility issue detected.
82
-
83
- For more details, please review [the changelog](changelog.md).
84
-
85
- ## Updating from 1.0.x to 1.1.X
86
-
87
- Version `1.1` adds some improvements on signature validation and solves some namespace conflicts.
88
-
89
- ## Updating from 0.9.x to 1.0.X
90
-
91
- Version `1.0` is a recommended update for all Ruby SAML users as it includes security fixes.
92
-
93
- Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decrypt support.
94
-
95
- ### Important Changes
96
- 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.
97
-
98
- ## Updating from 0.8.x to 0.9.x
99
- Version `0.9` adds many new features and improvements.
100
-
101
- ## Updating from 0.7.x to 0.8.x
102
- Version `0.8.x` changes the namespace of the gem from `OneLogin::Saml` to `OneLogin::RubySaml`. Please update your implementations of the gem accordingly.
5
+ Ruby SAML minor and tiny versions may introduce breaking changes. Please read
6
+ [UPGRADING.md](UPGRADING.md) for guidance on upgrading to new Ruby SAML versions.
103
7
 
104
8
  ## Overview
105
9
 
106
- The Ruby SAML library is for implementing the client side of a SAML authorization, i.e. it provides a means for managing authorization initialization and confirmation requests from identity providers.
10
+ The Ruby SAML library is for implementing the client side of a SAML authorization,
11
+ i.e. it provides a means for managing authorization initialization and confirmation
12
+ requests from identity providers.
107
13
 
108
14
  SAML authorization is a two step process and you are expected to implement support for both.
109
15
 
110
- We created a demo project for Rails4 that uses the latest version of this library: [ruby-saml-example](https://github.com/onelogin/ruby-saml-example)
16
+ We created a demo project for Rails 4 that uses the latest version of this library:
17
+ [ruby-saml-example](https://github.com/onelogin/ruby-saml-example)
18
+
19
+ ### Supported Ruby Versions
20
+
21
+ The following Ruby versions are covered by CI testing:
111
22
 
112
- ### Supported versions of Ruby
113
- * 1.8.7
114
- * 1.9.x
115
- * 2.0.x
116
23
  * 2.1.x
117
24
  * 2.2.x
118
25
  * 2.3.x
@@ -120,23 +27,35 @@ We created a demo project for Rails4 that uses the latest version of this librar
120
27
  * 2.5.x
121
28
  * 2.6.x
122
29
  * 2.7.x
123
- * JRuby 1.7.19
124
- * JRuby 9.0.0.0
125
- * JRuby 9.2.0.0
30
+ * 3.0.x
31
+ * JRuby 9.1.x
32
+ * JRuby 9.2.x
33
+ * TruffleRuby (latest)
34
+
35
+ In addition, the following may work but are untested:
36
+
37
+ * 1.8.7
38
+ * 1.9.x
39
+ * 2.0.x
40
+ * JRuby 1.7.x
41
+ * JRuby 9.0.x
126
42
 
127
43
  ## Adding Features, Pull Requests
44
+
128
45
  * Fork the repository
129
46
  * Make your feature addition or bug fix
130
47
  * Add tests for your new features. This is important so we don't break any features in a future version unintentionally.
131
- * Ensure all tests pass.
48
+ * Ensure all tests pass by running `bundle exec rake test`.
132
49
  * Do not change rakefile, version, or history.
133
50
  * Open a pull request, following [this template](https://gist.github.com/Lordnibbler/11002759).
134
51
 
135
52
  ## Security Guidelines
136
53
 
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.
54
+ If you believe you have discovered a security vulnerability in this gem, please report it
55
+ at https://www.onelogin.com/security with a description. We follow responsible disclosure
56
+ guidelines, and will work with you to quickly find a resolution.
138
57
 
139
- ### Security warning
58
+ ### Security Warning
140
59
 
141
60
  Some tools may incorrectly report ruby-saml is a potential security vulnerability.
142
61
  ruby-saml depends on Nokogiri, and it's possible to use Nokogiri in a dangerous way
@@ -146,9 +65,20 @@ can create an XML External Entity (XXE) vulnerability if the XML data is not tru
146
65
  However, ruby-saml never enables this dangerous Nokogiri configuration;
147
66
  ruby-saml never enables DTDLOAD, and it never disables NONET.
148
67
 
68
+ The OneLogin::RubySaml::IdpMetadataParser class does not validate in any way the URL
69
+ that is introduced in order to be parsed.
70
+
71
+ Usually the same administrator that handles the Service Provider also sets the URL to
72
+ the IdP, which should be a trusted resource.
73
+
74
+ But there are other scenarios, like a SAAS app where the administrator of the app
75
+ delegates this functionality to other users. In this case, extra precaution should
76
+ be taken in order to validate such URL inputs and avoid attacks like SSRF.
149
77
 
150
78
  ## Getting Started
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:
79
+
80
+ In order to use Ruby SAML you will need to install the gem (either manually or using Bundler),
81
+ and require the library in your Ruby application:
152
82
 
153
83
  Using `Gemfile`
154
84
 
@@ -166,7 +96,8 @@ Using RubyGems
166
96
  gem install ruby-saml
167
97
  ```
168
98
 
169
- When requiring the gem, you can add the whole toolkit
99
+ You may require the entire Ruby SAML gem:
100
+
170
101
  ```ruby
171
102
  require 'onelogin/ruby-saml'
172
103
  ```
@@ -179,7 +110,9 @@ require 'onelogin/ruby-saml/authrequest'
179
110
 
180
111
  ### Installation on Ruby 1.8.7
181
112
 
182
- This gem uses Nokogiri as a dependency, which dropped support for Ruby 1.8.x in Nokogiri 1.6. When installing this gem on Ruby 1.8.7, you will need to make sure a version of Nokogiri prior to 1.6 is installed or specified if it hasn't been already.
113
+ This gem uses Nokogiri as a dependency, which dropped support for Ruby 1.8.x in Nokogiri 1.6.
114
+ When installing this gem on Ruby 1.8.7, you will need to make sure a version of Nokogiri
115
+ prior to 1.6 is installed or specified if it hasn't been already.
183
116
 
184
117
  Using `Gemfile`
185
118
 
@@ -208,7 +141,10 @@ OneLogin::RubySaml::Logging.logger = Logger.new('/var/log/ruby-saml.log')
208
141
 
209
142
  ## The Initialization Phase
210
143
 
211
- This is the first request you will get from the identity provider. It will hit your application at a specific URL that you've announced as your SAML initialization point. The response to this initialization is a redirect back to the identity provider, which can look something like this (ignore the saml_settings method call for now):
144
+ This is the first request you will get from the identity provider. It will hit your application
145
+ at a specific URL that you've announced as your SAML initialization point. The response to
146
+ this initialization is a redirect back to the identity provider, which can look something
147
+ like this (ignore the saml_settings method call for now):
212
148
 
213
149
  ```ruby
214
150
  def init
@@ -228,7 +164,10 @@ def init
228
164
  end
229
165
  ```
230
166
 
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):
167
+ Once you've redirected back to the identity provider, it will ensure that the user has been
168
+ authorized and redirect back to your application for final consumption.
169
+ This can look something like this (the `authorize_success` and `authorize_failure`
170
+ methods are specific to your application):
232
171
 
233
172
  ```ruby
234
173
  def consume
@@ -246,16 +185,19 @@ def consume
246
185
  end
247
186
  ```
248
187
 
249
- In the above there are a few assumptions, one being that `response.nameid` is an email address. This is all handled with how you specify the settings that are in play via the `saml_settings` method. That could be implemented along the lines of this:
188
+ In the above there are a few assumptions, one being that `response.nameid` is an email address.
189
+ This is all handled with how you specify the settings that are in play via the `saml_settings` method.
190
+ That could be implemented along the lines of this:
250
191
 
251
192
  ```
252
193
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
253
194
  response.settings = saml_settings
254
195
  ```
255
196
 
256
- If the assertion of the SAMLResponse is not encrypted, you can initialize the Response without the `:settings` parameter and set it later.
257
- If the SAMLResponse contains an encrypted assertion, you need to provide the settings in the
258
- initialize method in order to obtain the decrypted assertion, using the service provider private key in order to decrypt.
197
+ If the assertion of the SAMLResponse is not encrypted, you can initialize the Response
198
+ without the `:settings` parameter and set it later. If the SAMLResponse contains an encrypted
199
+ assertion, you need to provide the settings in the initialize method in order to obtain the
200
+ decrypted assertion, using the service provider private key in order to decrypt.
259
201
  If you don't know what expect, always use the former (set the settings on initialize).
260
202
 
261
203
  ```ruby
@@ -265,8 +207,10 @@ def saml_settings
265
207
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
266
208
  settings.sp_entity_id = "http://#{request.host}/saml/metadata"
267
209
  settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
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}"
210
+ settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
211
+ settings.idp_sso_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
212
+ settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
213
+ settings.idp_slo_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
270
214
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
271
215
  settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
272
216
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -279,9 +223,9 @@ def saml_settings
279
223
  "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
280
224
  ]
281
225
 
282
- # Optional bindings (defaults to Redirect for logout POST for acs)
283
- settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
284
- settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
226
+ # Optional bindings (defaults to Redirect for logout POST for ACS)
227
+ settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
228
+ settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
285
229
 
286
230
  settings
287
231
  end
@@ -289,17 +233,20 @@ end
289
233
 
290
234
  The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
291
235
 
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:
236
+ Some assertion validations can be skipped by passing parameters to `OneLogin::RubySaml::Response.new()`.
237
+ For example, you can skip the `AuthnStatement`, `Conditions`, `Recipient`, or the `SubjectConfirmation`
238
+ validations by initializing the response with different options:
293
239
 
294
240
  ```ruby
295
241
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnstatement: true}) # skips AuthnStatement
296
242
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
297
243
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
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
244
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_recipient_check: true}) # doesn't skip subject confirmation, but skips the recipient check which is a sub check of the subject_confirmation check
299
245
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_audience: true}) # skips audience check
300
246
  ```
301
247
 
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:
248
+ All that's left is to wrap everything in a controller and reference it in the initialization and
249
+ consumption URLs in OneLogin. A full controller example could look like this:
303
250
 
304
251
  ```ruby
305
252
  # This controller expects you to use the URLs /saml/init and /saml/consume in your OneLogin application.
@@ -352,44 +299,56 @@ class SamlController < ApplicationController
352
299
  end
353
300
  ```
354
301
 
302
+ ## Signature Validation
303
+
304
+ Ruby SAML allows different ways to validate the signature of the SAMLResponse:
305
+ - You can provide the IdP X.509 public certificate at the `idp_cert` setting.
306
+ - You can provide the IdP X.509 public certificate in fingerprint format using the
307
+ `idp_cert_fingerprint` setting parameter and additionally the `idp_cert_fingerprint_algorithm` parameter.
355
308
 
356
- ## Signature validation
309
+ When validating the signature of redirect binding, the fingerprint is useless and the certificate
310
+ of the IdP is required in order to execute the validation. You can pass the option
311
+ `:relax_signature_validation` to `SloLogoutrequest` and `Logoutresponse` if want to avoid signature
312
+ validation if no certificate of the IdP is provided.
357
313
 
358
- On the ruby-saml toolkit there are different ways to validate the signature of the SAMLResponse:
359
- - You can provide the IdP x509 public certificate at the 'idp_cert' setting.
360
- - You can provide the IdP x509 public certificate in fingerprint format using the 'idp_cert_fingerprint' setting parameter and additionally the 'idp_cert_fingerprint_algorithm' parameter.
314
+ In production also we highly recommend to register on the settings the IdP certificate instead
315
+ of using the fingerprint method. The fingerprint, is a hash, so at the end is open to a collision
316
+ attack that can end on a signature validation bypass. Other SAML toolkits deprecated that mechanism,
317
+ we maintain it for compatibility and also to be used on test environment.
361
318
 
362
- When validating the signature of redirect binding, the fingerprint is useless and the certficate of the IdP is required in order to execute the validation.
363
- You can pass the option :relax_signature_validation to SloLogoutrequest and Logoutresponse if want to avoid signature validation if no certificate of the IdP is provided.
319
+ ## Handling Multiple IdP Certificates
364
320
 
365
- In production also we highly recommend to register on the settings the IdP certificate instead of using the fingerprint method. The fingerprint, is a hash, so at the end is open to a collision attack that can end on a signature validation bypass. Other SAML toolkits deprecated that mechanism, we maintain it for compatibility and also to be used on test environment.
321
+ If the IdP metadata XML includes multiple certificates, you may specify the `idp_cert_multi`
322
+ parameter. When used, the `idp_cert` and `idp_cert_fingerprint` parameters are ignored.
323
+ This is useful in the following scenarios:
366
324
 
367
- In some scenarios the IdP uses different certificates for signing/encryption, or is under key rollover phase and more than one certificate is published on IdP metadata.
325
+ * The IdP uses different certificates for signing versus encryption.
326
+ * The IdP is undergoing a key rollover and is publishing the old and new certificates in parallel.
368
327
 
369
- In order to handle that the toolkit offers the 'idp_cert_multi' parameter.
370
- When used, 'idp_cert' and 'idp_cert_fingerprint' values are ignored.
328
+ The `idp_cert_multi` must be a `Hash` as follows. The `:signing` and `:encryption` arrays below,
329
+ add the IdP X.509 public certificates which were published in the IdP metadata.
371
330
 
372
- That 'idp_cert_multi' must be a Hash as follows:
331
+ ```ruby
373
332
  {
374
333
  :signing => [],
375
334
  :encryption => []
376
335
  }
377
-
378
- And on 'signing' and 'encryption' arrays, add the different IdP x509 public certificates published on the IdP metadata.
379
-
336
+ ```
380
337
 
381
338
  ## Metadata Based Configuration
382
339
 
383
- The method above requires a little extra work to manually specify attributes about the IdP. (And your SP application) There's an easier method -- use a metadata exchange. Metadata is just an XML file that defines the capabilities of both the IdP and the SP application. It also contains the X.509 public
384
- key certificates which add to the trusted relationship. The IdP administrator can also configure custom settings for an SP based on the metadata.
340
+ The method above requires a little extra work to manually specify attributes about both the IdP and your SP application.
341
+ There's an easier method: use a metadata exchange. Metadata is an XML file that defines the capabilities of both the IdP
342
+ and the SP application. It also contains the X.509 public key certificates which add to the trusted relationship.
343
+ The IdP administrator can also configure custom settings for an SP based on the metadata.
385
344
 
386
- Using ```idp_metadata_parser.parse_remote``` IdP metadata will be added to the settings without further ado.
345
+ Using `IdpMetadataParser#parse_remote`, the IdP metadata will be added to the settings.
387
346
 
388
347
  ```ruby
389
348
  def saml_settings
390
349
 
391
350
  idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
392
- # Returns OneLogin::RubySaml::Settings prepopulated with idp metadata
351
+ # Returns OneLogin::RubySaml::Settings pre-populated with IdP metadata
393
352
  settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
394
353
 
395
354
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
@@ -401,6 +360,7 @@ def saml_settings
401
360
  settings
402
361
  end
403
362
  ```
363
+
404
364
  The following attributes are set:
405
365
  * idp_entity_id
406
366
  * name_identifier_format
@@ -419,11 +379,11 @@ IdpMetadataParser by its Entity Id value:
419
379
 
420
380
  ```ruby
421
381
  validate_cert = true
422
- settings = idp_metadata_parser.parse_remote(
423
- "https://example.com/auth/saml2/idp/metadata",
424
- validate_cert,
425
- entity_id: "http//example.com/target/entity"
426
- )
382
+ settings = idp_metadata_parser.parse_remote(
383
+ "https://example.com/auth/saml2/idp/metadata",
384
+ validate_cert,
385
+ entity_id: "http//example.com/target/entity"
386
+ )
427
387
  ```
428
388
 
429
389
  ### Parsing Metadata into an Hash
@@ -438,7 +398,7 @@ If you are using `saml:AttributeStatement` to transfer data like the username, y
438
398
  `single_value_compatibility` (when activated, only the first value is returned)
439
399
 
440
400
  ```ruby
441
- response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
401
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
442
402
  response.settings = saml_settings
443
403
 
444
404
  response.attributes[:username]
@@ -523,7 +483,7 @@ pp(response.attributes.multi(:not_exists))
523
483
  pp(response.attributes.fetch(/givenname/))
524
484
  # => "usersName"
525
485
 
526
- # Deactive single_value_compatibility
486
+ # Deprecated single_value_compatibility
527
487
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
528
488
 
529
489
  pp(response.attributes[:uid])
@@ -566,74 +526,193 @@ To add a `saml:AuthnContextDeclRef`, define `settings.authn_context_decl_ref`.
566
526
  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
527
  building the authrequest object.
568
528
 
529
+ ## Service Provider Metadata
569
530
 
570
- ## Signing
531
+ To form a trusted pair relationship with the IdP, the SP (you) need to provide metadata XML
532
+ to the IdP for various good reasons. (Caching, certificate lookups, relaying party permissions, etc)
571
533
 
572
- The Ruby Toolkit supports 2 different kinds of signature: Embeded and `GET` parameters
534
+ The class `OneLogin::RubySaml::Metadata` takes care of this by reading the Settings and returning XML. All you have to do is add a controller to return the data, then give this URL to the IdP administrator.
573
535
 
574
- In order to be able to sign, define the private key and the public cert of the service provider:
536
+ The metadata will be polled by the IdP every few minutes, so updating your settings should propagate
537
+ to the IdP settings.
575
538
 
576
539
  ```ruby
577
- settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
578
- settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
540
+ class SamlController < ApplicationController
541
+ # ... the rest of your controller definitions ...
542
+ def metadata
543
+ settings = Account.get_saml_settings
544
+ meta = OneLogin::RubySaml::Metadata.new
545
+ render :xml => meta.generate(settings), :content_type => "application/samlmetadata+xml"
546
+ end
547
+ end
548
+ ```
549
+
550
+ You can add `ValidUntil` and `CacheDuration` to the SP Metadata XML using instead:
551
+
552
+ ```ruby
553
+ # Valid until => 2 days from now
554
+ # Cache duration = 604800s = 1 week
555
+ valid_until = Time.now + 172800
556
+ cache_duration = 604800
557
+ meta.generate(settings, false, valid_until, cache_duration)
579
558
  ```
580
559
 
581
- The settings related to sign are stored in the `security` attribute of the settings:
560
+ ## Signing and Decryption
561
+
562
+ Ruby SAML supports the following functionality:
563
+
564
+ 1. Signing your SP Metadata XML
565
+ 2. Signing your SP SAML messages
566
+ 3. Decrypting IdP Assertion messages upon receipt (EncryptedAssertion)
567
+ 4. Verifying signatures on SAML messages and IdP Assertions
568
+
569
+ In order to use functions 1-3 above, you must first define your SP public certificate and private key:
582
570
 
583
571
  ```ruby
584
- settings.security[:authn_requests_signed] = true # Enable or not signature on AuthNRequest
585
- settings.security[:logout_requests_signed] = true # Enable or not signature on Logout Request
586
- settings.security[:logout_responses_signed] = true # Enable or not signature on Logout Response
587
- settings.security[:want_assertions_signed] = true # Enable or not the requirement of signed assertion
588
- settings.security[:metadata_signed] = true # Enable or not signature on Metadata
572
+ settings.certificate = "CERTIFICATE TEXT WITH BEGIN/END HEADER AND FOOTER"
573
+ settings.private_key = "PRIVATE KEY TEXT WITH BEGIN/END HEADER AND FOOTER"
574
+ ```
589
575
 
576
+ Note that the same certificate (and its associated private key) are used to perform
577
+ all decryption and signing-related functions (1-4) above. Ruby SAML does not currently allow
578
+ to specify different certificates for each function.
579
+
580
+ You may also globally set the SP signature and digest method, to be used in SP signing (functions 1 and 2 above):
581
+
582
+ ```ruby
590
583
  settings.security[:digest_method] = XMLSecurity::Document::SHA1
591
584
  settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
585
+ ```
586
+
587
+ #### Signing SP Metadata
592
588
 
593
- # Embeded signature or HTTP GET parameter signature
594
- # Note that metadata signature is always embedded regardless of this value.
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
589
+ You may add a `<ds:Signature>` digital signature element to your SP Metadata XML using the following setting:
590
+
591
+ ```ruby
592
+ settings.certificate = "CERTIFICATE TEXT WITH BEGIN/END HEADER AND FOOTER"
593
+ settings.private_key = "PRIVATE KEY TEXT WITH BEGIN/END HEADER AND FOOTER"
594
+
595
+ settings.security[:metadata_signed] = true # Enable signature on Metadata
596
+ ```
597
+
598
+ #### Signing SP SAML Messages
599
+
600
+ Ruby SAML supports SAML request signing. The Service Provider will sign the
601
+ request/responses with its private key. The Identity Provider will then validate the signature
602
+ of the received request/responses with the public X.509 cert of the Service Provider.
603
+
604
+ To enable, please first set your certificate and private key. This will add `<md:KeyDescriptor use="signing">`
605
+ to your SP Metadata XML, to be read by the IdP.
606
+
607
+ ```ruby
608
+ settings.certificate = "CERTIFICATE TEXT WITH BEGIN/END HEADER AND FOOTER"
609
+ settings.private_key = "PRIVATE KEY TEXT WITH BEGIN/END HEADER AND FOOTER"
598
610
  ```
599
611
 
600
- Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
612
+ Next, you may specify the specific SP SAML messages you would like to sign:
613
+
614
+ ```ruby
615
+ settings.security[:authn_requests_signed] = true # Enable signature on AuthNRequest
616
+ settings.security[:logout_requests_signed] = true # Enable signature on Logout Request
617
+ settings.security[:logout_responses_signed] = true # Enable signature on Logout Response
618
+ ```
619
+
620
+ Signatures will be handled automatically for both `HTTP-Redirect` and `HTTP-Redirect` Binding.
621
+ Note that the RelayState parameter is used when creating the Signature on the `HTTP-Redirect` Binding.
601
622
  Remember to provide it to the Signature builder if you are sending a `GET RelayState` parameter or the
602
623
  signature validation process will fail at the Identity Provider.
603
624
 
604
- The Service Provider will sign the request/responses with its private key.
605
- The Identity Provider will validate the sign of the received request/responses with the public x509 cert of the
606
- Service Provider.
625
+ #### Decrypting IdP SAML Assertions
626
+
627
+ Ruby SAML supports EncryptedAssertion. The Identity Provider will encrypt the Assertion with the
628
+ public cert of the Service Provider. The Service Provider will decrypt the EncryptedAssertion with its private key.
607
629
 
608
- Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
630
+ You may enable EncryptedAssertion as follows. This will add `<md:KeyDescriptor use="encrytion">` to your
631
+ SP Metadata XML, to be read by the IdP.
609
632
 
610
- Enable/disable the soft mode with the `settings.soft` parameter. When set to `false`, saml validations errors will raise an exception.
633
+ ```ruby
634
+ settings.certificate = "CERTIFICATE TEXT WITH BEGIN/END HEADER AND FOOTER"
635
+ settings.private_key = "PRIVATE KEY TEXT WITH BEGIN/END HEADER AND FOOTER"
611
636
 
612
- ## Decrypting
637
+ settings.security[:want_assertions_encrypted] = true # Invalidate SAML messages without an EncryptedAssertion
638
+ ```
613
639
 
614
- The Ruby Toolkit supports EncryptedAssertion.
640
+ #### Verifying Signature on IdP Assertions
615
641
 
616
- In order to be able to decrypt a SAML Response that contains a EncryptedAssertion you need define the private key and the public cert of the service provider, then share this with the Identity Provider.
642
+ You may require the IdP to sign its SAML Assertions using the following setting.
643
+ With will add `<md:SPSSODescriptor WantAssertionsSigned="true">` to your SP Metadata XML.
644
+ The signature will be checked against the `<md:KeyDescriptor use="signing">` element
645
+ present in the IdP's metadata.
617
646
 
618
647
  ```ruby
619
- settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
620
- settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
648
+ settings.security[:want_assertions_signed] = true # Require the IdP to sign its SAML Assertions
621
649
  ```
622
650
 
623
- The Identity Provider will encrypt the Assertion with the public cert of the Service Provider.
624
- The Service Provider will decrypt the EncryptedAssertion with its private key.
651
+ #### Certificate and Signature Validation
625
652
 
626
- Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
653
+ You may require SP and IdP certificates to be non-expired using the following settings:
627
654
 
655
+ ```ruby
656
+ settings.security[:check_idp_cert_expiration] = true # Raise error if IdP X.509 cert is expired
657
+ settings.security[:check_sp_cert_expiration] = true # Raise error SP X.509 cert is expired
658
+ ```
628
659
 
629
- ## Key rollover
660
+ By default, Ruby SAML will raise a `OneLogin::RubySaml::ValidationError` if a signature or certificate
661
+ validation fails. You may disable such exceptions using the `settings.security[:soft]` parameter.
630
662
 
631
- If you plan to update the SP x509cert and privateKey you can define the parameter 'certificate_new' at the settings and that new SP public certificate will be published on the SP metadata so Identity Providers can read them and get ready for rollover.
663
+ ```ruby
664
+ settings.security[:soft] = true # Do not raise error on failed signature/certificate validations
665
+ ```
666
+
667
+ #### Audience Validation
632
668
 
669
+ A service provider should only consider a SAML response valid if the IdP includes an <AudienceRestriction>
670
+ element containting an <Audience> element that uniquely identifies the service provider. Unless you specify
671
+ the `skip_audience` option, Ruby SAML will validate that each SAML response includes an <Audience> element
672
+ whose contents matches `settings.sp_entity_id`.
673
+
674
+ By default, Ruby SAML considers an <AudienceRestriction> element containing only empty <Audience> elements
675
+ to be valid. That means an otherwise valid SAML response with a condition like this would be valid:
676
+
677
+ ```xml
678
+ <AudienceRestriction>
679
+ <Audience />
680
+ </AudienceRestriction>
681
+ ```
682
+
683
+ You may enforce that an <AudienceRestriction> element containing only empty <Audience> elements
684
+ is invalid using the `settings.security[:strict_audience_validation]` parameter.
685
+
686
+ ```ruby
687
+ settings.security[:strict_audience_validation] = true
688
+ ```
689
+
690
+ #### Key Rollover
691
+
692
+ To update the SP X.509 certificate and private key without disruption of service, you may define the parameter
693
+ `settings.certificate_new`. This will publish the new SP certificate in your metadata so that your IdP counterparties
694
+ may cache it in preparation for rollover.
695
+
696
+ For example, if you to rollover from `CERT A` to `CERT B`. Before rollover, your settings should look as follows.
697
+ Both `CERT A` and `CERT B` will now appear in your SP metadata, however `CERT A` will still be used for signing
698
+ and encryption at this time.
699
+
700
+ ```ruby
701
+ settings.certificate = "CERT A"
702
+ settings.private_key = "PRIVATE KEY FOR CERT A"
703
+ settings.certificate_new = "CERT B"
704
+ ```
705
+
706
+ After the IdP has cached `CERT B`, you may then change your settings as follows:
707
+
708
+ ```ruby
709
+ settings.certificate = "CERT B"
710
+ settings.private_key = "PRIVATE KEY FOR CERT B"
711
+ ```
633
712
 
634
713
  ## Single Log Out
635
714
 
636
- The Ruby Toolkit supports SP-initiated Single Logout and IdP-Initiated Single Logout.
715
+ Ruby SAML supports SP-initiated Single Logout and IdP-Initiated Single Logout.
637
716
 
638
717
  Here is an example that we could add to our previous controller to generate and send a SAML Logout Request to the IdP:
639
718
 
@@ -648,7 +727,7 @@ def sp_logout_request
648
727
  delete_session
649
728
  else
650
729
 
651
- logout_request = OneLogin::RubySaml::Logoutrequest.new()
730
+ logout_request = OneLogin::RubySaml::Logoutrequest.new
652
731
  logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
653
732
 
654
733
  if settings.name_identifier_value.nil?
@@ -664,7 +743,7 @@ def sp_logout_request
664
743
  session[:transaction_id] = logout_request.uuid
665
744
  session[:logged_out_user] = logged_user
666
745
 
667
- relayState = url_for controller: 'saml', action: 'index'
746
+ relayState = url_for(controller: 'saml', action: 'index')
668
747
  redirect_to(logout_request.create(settings, :RelayState => relayState))
669
748
  end
670
749
  end
@@ -711,7 +790,13 @@ Here is an example that we could add to our previous controller to process a SAM
711
790
  # Method to handle IdP initiated logouts
712
791
  def idp_logout_request
713
792
  settings = Account.get_saml_settings
714
- logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
793
+ # ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses
794
+ # uppercase. Turn it True for ADFS compatibility on signature verification
795
+ settings.security[:lowercase_url_encoding] = true
796
+
797
+ logout_request = OneLogin::RubySaml::SloLogoutrequest.new(
798
+ params[:SAMLRequest], settings: settings
799
+ )
715
800
  if !logout_request.is_valid?
716
801
  logger.error "IdP initiated LogoutRequest was not valid!"
717
802
  return render :inline => logger.error
@@ -746,38 +831,6 @@ def logout
746
831
  end
747
832
  ```
748
833
 
749
-
750
-
751
- ## Service Provider Metadata
752
-
753
- To form a trusted pair relationship with the IdP, the SP (you) need to provide metadata XML
754
- to the IdP for various good reasons. (Caching, certificate lookups, relaying party permissions, etc)
755
-
756
- The class `OneLogin::RubySaml::Metadata` takes care of this by reading the Settings and returning XML. All you have to do is add a controller to return the data, then give this URL to the IdP administrator.
757
-
758
- The metadata will be polled by the IdP every few minutes, so updating your settings should propagate
759
- to the IdP settings.
760
-
761
- ```ruby
762
- class SamlController < ApplicationController
763
- # ... the rest of your controller definitions ...
764
- def metadata
765
- settings = Account.get_saml_settings
766
- meta = OneLogin::RubySaml::Metadata.new
767
- render :xml => meta.generate(settings), :content_type => "application/samlmetadata+xml"
768
- end
769
- end
770
- ```
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
- ```
780
-
781
834
  ## Clock Drift
782
835
 
783
836
  Server clocks tend to drift naturally. If during validation of the response you get the error "Current time is earlier than NotBefore condition", this may be due to clock differences between your system and that of the Identity Provider.
@@ -792,13 +845,33 @@ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], :allowed_cloc
792
845
 
793
846
  Make sure to keep the value as comfortably small as possible to keep security risks to a minimum.
794
847
 
848
+ ## Deflation Limit
849
+
850
+ To protect against decompression bombs (a form of DoS attack), SAML messages are limited to 250,000 bytes by default.
851
+ Sometimes legitimate SAML messages will exceed this limit,
852
+ for example due to custom claims like including groups a user is a member of.
853
+ If you want to customize this limit, you need to provide a different setting when initializing the response object.
854
+ Example:
855
+
856
+ ```ruby
857
+ def consume
858
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], { settings: saml_settings })
859
+ ...
860
+ end
861
+
862
+ private
863
+
864
+ def saml_settings
865
+ OneLogin::RubySaml::Settings.new(message_max_bytesize: 500_000)
866
+ end
867
+ ```
868
+
795
869
  ## Attribute Service
796
870
 
797
871
  To request attributes from the IdP the SP needs to provide an attribute service within it's metadata and reference the index in the assertion.
798
872
 
799
873
  ```ruby
800
874
  settings = OneLogin::RubySaml::Settings.new
801
-
802
875
  settings.attributes_index = 5
803
876
  settings.attribute_consuming_service.configure do
804
877
  service_name "Service"
@@ -809,3 +882,27 @@ end
809
882
  ```
810
883
 
811
884
  The `attribute_value` option additionally accepts an array of possible values.
885
+
886
+ ## Custom Metadata Fields
887
+
888
+ Some IdPs may require to add SPs to add additional fields (Organization, ContactPerson, etc.)
889
+ into the SP metadata. This can be achieved by extending the `OneLogin::RubySaml::Metadata`
890
+ class and overriding the `#add_extras` method as per the following example:
891
+
892
+ ```ruby
893
+ class MyMetadata < OneLogin::RubySaml::Metadata
894
+ def add_extras(root, _settings)
895
+ org = root.add_element("md:Organization")
896
+ org.add_element("md:OrganizationName", 'xml:lang' => "en-US").text = 'ACME Inc.'
897
+ org.add_element("md:OrganizationDisplayName", 'xml:lang' => "en-US").text = 'ACME'
898
+ org.add_element("md:OrganizationURL", 'xml:lang' => "en-US").text = 'https://www.acme.com'
899
+
900
+ cp = root.add_element("md:ContactPerson", 'contactType' => 'technical')
901
+ cp.add_element("md:GivenName").text = 'ACME SAML Team'
902
+ cp.add_element("md:EmailAddress").text = 'saml@acme.com'
903
+ end
904
+ end
905
+
906
+ # Output XML with custom metadata
907
+ MyMetadata.new.generate(settings)
908
+ ```