ruby-saml 1.7.2 → 1.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +37 -15
  3. data/README.md +127 -25
  4. data/changelog.md +61 -0
  5. data/lib/onelogin/ruby-saml/attribute_service.rb +1 -1
  6. data/lib/onelogin/ruby-saml/attributes.rb +24 -1
  7. data/lib/onelogin/ruby-saml/authrequest.rb +29 -6
  8. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +239 -169
  9. data/lib/onelogin/ruby-saml/logging.rb +4 -1
  10. data/lib/onelogin/ruby-saml/logoutrequest.rb +27 -7
  11. data/lib/onelogin/ruby-saml/logoutresponse.rb +32 -16
  12. data/lib/onelogin/ruby-saml/metadata.rb +11 -3
  13. data/lib/onelogin/ruby-saml/response.rb +91 -30
  14. data/lib/onelogin/ruby-saml/saml_message.rb +15 -5
  15. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  16. data/lib/onelogin/ruby-saml/settings.rb +82 -9
  17. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -7
  18. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +46 -18
  19. data/lib/onelogin/ruby-saml/utils.rb +87 -10
  20. data/lib/onelogin/ruby-saml/version.rb +1 -1
  21. data/lib/xml_security.rb +39 -12
  22. data/ruby-saml.gemspec +16 -8
  23. metadata +40 -274
  24. data/test/certificates/certificate1 +0 -12
  25. data/test/certificates/certificate_without_head_foot +0 -1
  26. data/test/certificates/formatted_certificate +0 -14
  27. data/test/certificates/formatted_chained_certificate +0 -42
  28. data/test/certificates/formatted_private_key +0 -12
  29. data/test/certificates/formatted_rsa_private_key +0 -12
  30. data/test/certificates/invalid_certificate1 +0 -1
  31. data/test/certificates/invalid_certificate2 +0 -1
  32. data/test/certificates/invalid_certificate3 +0 -12
  33. data/test/certificates/invalid_chained_certificate1 +0 -1
  34. data/test/certificates/invalid_private_key1 +0 -1
  35. data/test/certificates/invalid_private_key2 +0 -1
  36. data/test/certificates/invalid_private_key3 +0 -10
  37. data/test/certificates/invalid_rsa_private_key1 +0 -1
  38. data/test/certificates/invalid_rsa_private_key2 +0 -1
  39. data/test/certificates/invalid_rsa_private_key3 +0 -10
  40. data/test/certificates/ruby-saml-2.crt +0 -15
  41. data/test/certificates/ruby-saml.crt +0 -14
  42. data/test/certificates/ruby-saml.key +0 -15
  43. data/test/idp_metadata_parser_test.rb +0 -568
  44. data/test/logging_test.rb +0 -62
  45. data/test/logout_requests/invalid_slo_request.xml +0 -6
  46. data/test/logout_requests/slo_request.xml +0 -4
  47. data/test/logout_requests/slo_request.xml.base64 +0 -1
  48. data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
  49. data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
  50. data/test/logout_requests/slo_request_with_session_index.xml +0 -5
  51. data/test/logout_responses/logoutresponse_fixtures.rb +0 -67
  52. data/test/logoutrequest_test.rb +0 -212
  53. data/test/logoutresponse_test.rb +0 -402
  54. data/test/metadata/idp_descriptor.xml +0 -26
  55. data/test/metadata/idp_descriptor_2.xml +0 -56
  56. data/test/metadata/idp_descriptor_3.xml +0 -14
  57. data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
  58. data/test/metadata/idp_metadata_multi_certs.xml +0 -75
  59. data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
  60. data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
  61. data/test/metadata/idp_multiple_descriptors.xml +0 -53
  62. data/test/metadata/no_idp_descriptor.xml +0 -21
  63. data/test/metadata_test.rb +0 -331
  64. data/test/request_test.rb +0 -296
  65. data/test/response_test.rb +0 -1535
  66. data/test/responses/adfs_response_sha1.xml +0 -46
  67. data/test/responses/adfs_response_sha256.xml +0 -46
  68. data/test/responses/adfs_response_sha384.xml +0 -46
  69. data/test/responses/adfs_response_sha512.xml +0 -46
  70. data/test/responses/adfs_response_xmlns.xml +0 -45
  71. data/test/responses/attackxee.xml +0 -13
  72. data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
  73. data/test/responses/invalids/empty_destination.xml.base64 +0 -1
  74. data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
  75. data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
  76. data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
  77. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  78. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  79. data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
  80. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
  81. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
  82. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
  83. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
  84. data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
  85. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  86. data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
  87. data/test/responses/invalids/no_conditions.xml.base64 +0 -1
  88. data/test/responses/invalids/no_id.xml.base64 +0 -1
  89. data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
  90. data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
  91. data/test/responses/invalids/no_nameid.xml.base64 +0 -1
  92. data/test/responses/invalids/no_saml2.xml.base64 +0 -1
  93. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  94. data/test/responses/invalids/no_status.xml.base64 +0 -1
  95. data/test/responses/invalids/no_status_code.xml.base64 +0 -1
  96. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
  97. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
  98. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
  99. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  100. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  101. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  102. data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
  103. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
  104. data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
  105. data/test/responses/no_signature_ns.xml +0 -48
  106. data/test/responses/open_saml_response.xml +0 -56
  107. data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
  108. data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
  109. data/test/responses/response_double_status_code.xml.base64 +0 -1
  110. data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
  111. data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
  112. data/test/responses/response_eval.xml +0 -7
  113. data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
  114. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  115. data/test/responses/response_unsigned_xml_base64 +0 -1
  116. data/test/responses/response_with_ampersands.xml +0 -139
  117. data/test/responses/response_with_ampersands.xml.base64 +0 -93
  118. data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
  119. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  120. data/test/responses/response_with_multiple_attribute_values.xml +0 -67
  121. data/test/responses/response_with_retrieval_method.xml +0 -26
  122. data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
  123. data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
  124. data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
  125. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  126. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  127. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  128. data/test/responses/response_without_attributes.xml.base64 +0 -79
  129. data/test/responses/response_without_reference_uri.xml.base64 +0 -1
  130. data/test/responses/response_wrapped.xml.base64 +0 -150
  131. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
  132. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  133. data/test/responses/signed_nameid_in_atts.xml +0 -47
  134. data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
  135. data/test/responses/simple_saml_php.xml +0 -71
  136. data/test/responses/starfield_response.xml.base64 +0 -1
  137. data/test/responses/test_sign.xml +0 -43
  138. data/test/responses/unsigned_encrypted_adfs.xml +0 -23
  139. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
  140. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
  141. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
  142. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
  143. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
  144. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
  145. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  146. data/test/responses/valid_response.xml.base64 +0 -1
  147. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  148. data/test/saml_message_test.rb +0 -56
  149. data/test/settings_test.rb +0 -301
  150. data/test/slo_logoutrequest_test.rb +0 -448
  151. data/test/slo_logoutresponse_test.rb +0 -185
  152. data/test/test_helper.rb +0 -323
  153. data/test/utils_test.rb +0 -254
  154. data/test/xml_security_test.rb +0 -421
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 58b2d78436fa5304bc67e40cd5f4a0cc766b4301
4
- data.tar.gz: b2445dcda50eeb89ce6fe2b9b285c5021755e189
2
+ SHA256:
3
+ metadata.gz: 25c4115dff650511c702291e7e6e3277a2c50c43b603c4cf68ae1473b3c061b5
4
+ data.tar.gz: 375b631e4059b50e112f4fc5b890e48c000ddae894fdef7cc665b9a58bad5b7a
5
5
  SHA512:
6
- metadata.gz: 5b90724f90916e973182de8bf2d009aeabfbc356acb167e927a63d1e360b831e540b25602ba4bb1d79b74fd6e07889860fda5f4620eeb31f76fdc9b585bd13f0
7
- data.tar.gz: cd3750758fa6326bfe6be73552480b1f37994ba137eb048750afbd093d7ee4b23afadcbc1869bfdd49f9b77bdf29f629b0fc6963d814e3cdf54ad72281053999
6
+ metadata.gz: 1207da19dae7cb853704a0dbbd1d55791156d6703a5d3162adaa4d47ea1e645e4806687392db53c8c3e9c0a51b2fbb45772b8202975565f9157d32b707fd56a1
7
+ data.tar.gz: 9a4a9ba94e5ffd0eb24ef08e4a45435dec63333b2cbf1a0f0ecc164ce0569bb8720941c88874d64aef8524bebb5209bd70299e0e5bbdc953b7546aa055da58be
data/.travis.yml CHANGED
@@ -1,26 +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.5
8
- - 2.2.0
9
- - 2.3.0
10
- - 2.4.0
11
- - ree
12
- - jruby-1.7.21
13
- - jruby-9.0.0.0
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
+ - jruby-1.7.27
14
+ - jruby-9.1.17.0
15
+ - jruby-9.2.13.0
14
16
  gemfile:
15
17
  - Gemfile
16
18
  - gemfiles/nokogiri-1.5.gemfile
19
+ before_install:
20
+ - gem update bundler
17
21
  matrix:
18
22
  exclude:
19
- - rvm: 1.8.7
20
- gemfile: Gemfile
21
- - rvm: ree
22
- gemfile: Gemfile
23
- - rvm: jruby-9.0.0.0
23
+ - rvm: jruby-1.7.27
24
24
  gemfile: gemfiles/nokogiri-1.5.gemfile
25
- - rvm: jruby-1.7.21
25
+ - rvm: jruby-9.1.17.0
26
26
  gemfile: gemfiles/nokogiri-1.5.gemfile
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
46
+ gemfile: gemfiles/nokogiri-1.5.gemfile
47
+ env:
48
+ - JRUBY_OPTS="--debug"
data/README.md CHANGED
@@ -1,4 +1,29 @@
1
- # Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.svg)](http://travis-ci.org/onelogin/ruby-saml) [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master%0A)](https://coveralls.io/r/onelogin/ruby-saml?branch=master%0A) [![Gem Version](https://badge.fury.io/rb/ruby-saml.svg)](http://badge.fury.io/rb/ruby-saml)
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
+ `idp_sso_target_url` and `idp_slo_target_url` attributes of the Settings class deprecated in favor of `idp_sso_service_url` and `idp_slo_service_url`.
8
+ In IDPMetadataParser, `parse`, `parse_to_hash` and `parse_to_array` methods now retrieve SSO URL and SLO URL endpoints with
9
+ `idp_sso_service_url` and `idp_slo_service_url` (previously `idp_sso_target_url` and `idp_slo_target_url` respectively).
10
+
11
+ ## Updating from 1.10.x to 1.11.0
12
+ Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
13
+ There are two new security settings: `settings.security[:check_idp_cert_expiration]` and `settings.security[:check_sp_cert_expiration]` (both false by default) that check if the IdP or SP X.509 certificate has expired, respectively.
14
+
15
+ Version `1.10.2` includes the `valid_until` attribute in parsed IdP metadata.
16
+
17
+ Version `1.10.1` improves Ruby 1.8.7 support.
18
+
19
+ ## Updating from 1.9.0 to 1.10.0
20
+ Version `1.10.0` improves IdpMetadataParser to allow parse multiple IDPSSODescriptor, Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user to be authenticated and updates the format_cert method to accept certs with /\x0d/
21
+
22
+ ## Updating from 1.8.0 to 1.9.0
23
+ 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.
24
+
25
+ ## Updating from 1.7.X to 1.8.0
26
+ 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.
2
27
 
3
28
  ## Updating from 1.6.0 to 1.7.0
4
29
 
@@ -41,6 +66,10 @@ value.
41
66
  If you want to skip that validation, add the :skip_recipient_check option to the
42
67
  initialize method of the Response object.
43
68
 
69
+ Parsing metadata that contains more than one certificate will propagate the
70
+ idp_cert_multi property rather than idp_cert. See [signature validation
71
+ section](#signature-validation) for details.
72
+
44
73
  ## Updating from 1.3.x to 1.4.X
45
74
 
46
75
  Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
@@ -92,8 +121,14 @@ We created a demo project for Rails4 that uses the latest version of this librar
92
121
  * 2.2.x
93
122
  * 2.3.x
94
123
  * 2.4.x
95
- * JRuby 1.7.19
96
- * JRuby 9.0.0.0
124
+ * 2.5.x
125
+ * 2.6.x
126
+ * 2.7.x
127
+ * 3.0.x
128
+ * JRuby 1.7.x
129
+ * JRuby 9.0.x
130
+ * JRuby 9.1.x
131
+ * JRuby 9.2.x
97
132
 
98
133
  ## Adding Features, Pull Requests
99
134
  * Fork the repository
@@ -107,6 +142,17 @@ We created a demo project for Rails4 that uses the latest version of this librar
107
142
 
108
143
  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.
109
144
 
145
+ ### Security warning
146
+
147
+ Some tools may incorrectly report ruby-saml is a potential security vulnerability.
148
+ ruby-saml depends on Nokogiri, and it's possible to use Nokogiri in a dangerous way
149
+ (by enabling its DTDLOAD option and disabling its NONET option).
150
+ This dangerous Nokogiri configuration, which is sometimes used by other components,
151
+ can create an XML External Entity (XXE) vulnerability if the XML data is not trusted.
152
+ However, ruby-saml never enables this dangerous Nokogiri configuration;
153
+ ruby-saml never enables DTDLOAD, and it never disables NONET.
154
+
155
+
110
156
  ## Getting Started
111
157
  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:
112
158
 
@@ -114,7 +160,7 @@ Using `Gemfile`
114
160
 
115
161
  ```ruby
116
162
  # latest stable
117
- gem 'ruby-saml', '~> 1.0.0'
163
+ gem 'ruby-saml', '~> 1.11.0'
118
164
 
119
165
  # or track master for bleeding-edge
120
166
  gem 'ruby-saml', :github => 'onelogin/ruby-saml'
@@ -163,7 +209,7 @@ To override the default behavior and control the destination of log messages, pr
163
209
  a ruby Logger object to the gem's logging singleton:
164
210
 
165
211
  ```ruby
166
- OneLogin::RubySaml::Logging.logger = Logger.new(File.open('/var/log/ruby-saml.log', 'w'))
212
+ OneLogin::RubySaml::Logging.logger = Logger.new('/var/log/ruby-saml.log')
167
213
  ```
168
214
 
169
215
  ## The Initialization Phase
@@ -177,6 +223,17 @@ def init
177
223
  end
178
224
  ```
179
225
 
226
+ If the SP knows who should be authenticated in the IdP, then can provide that info as follows:
227
+
228
+ ```ruby
229
+ def init
230
+ request = OneLogin::RubySaml::Authrequest.new
231
+ saml_settings.name_identifier_value_requested = "testuser@example.com"
232
+ saml_settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
233
+ redirect_to(request.create(saml_settings))
234
+ end
235
+ ```
236
+
180
237
  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):
181
238
 
182
239
  ```ruby
@@ -190,6 +247,7 @@ def consume
190
247
  session[:attributes] = response.attributes
191
248
  else
192
249
  authorize_failure # This method shows an error message
250
+ # List of errors is available in response.errors array
193
251
  end
194
252
  end
195
253
  ```
@@ -211,10 +269,10 @@ def saml_settings
211
269
  settings = OneLogin::RubySaml::Settings.new
212
270
 
213
271
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
214
- settings.issuer = "http://#{request.host}/saml/metadata"
272
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
215
273
  settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
216
- settings.idp_sso_target_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
217
- settings.idp_slo_target_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
274
+ settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
275
+ settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
218
276
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
219
277
  settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
220
278
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -235,12 +293,16 @@ def saml_settings
235
293
  end
236
294
  ```
237
295
 
238
- Some assertion validations can be skipped by passing parameters to `OneLogin::RubySaml::Response.new()`. For example, you can skip the `Conditions`, `Recipient`, or the `SubjectConfirmation` validations by initializing the response with different options:
296
+ The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
297
+
298
+ Some assertion validations can be skipped by passing parameters to `OneLogin::RubySaml::Response.new()`. For example, you can skip the `AuthnStatement`, `Conditions`, `Recipient`, or the `SubjectConfirmation` validations by initializing the response with different options:
239
299
 
240
300
  ```ruby
301
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnstatement: true}) # skips AuthnStatement
241
302
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
242
303
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
243
304
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_recipient_check: true}) # doens't skip subject confirmation, but skips the recipient check which is a sub check of the subject_confirmation check
305
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_audience: true}) # skips audience check
244
306
  ```
245
307
 
246
308
  All that's left is to wrap everything in a controller and reference it in the initialization and consumption URLs in OneLogin. A full controller example could look like this:
@@ -264,6 +326,7 @@ class SamlController < ApplicationController
264
326
  session[:attributes] = response.attributes
265
327
  else
266
328
  authorize_failure # This method shows an error message
329
+ # List of errors is available in response.errors array
267
330
  end
268
331
  end
269
332
 
@@ -273,8 +336,8 @@ class SamlController < ApplicationController
273
336
  settings = OneLogin::RubySaml::Settings.new
274
337
 
275
338
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
276
- settings.issuer = "http://#{request.host}/saml/metadata"
277
- settings.idp_sso_target_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
339
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
340
+ settings.idp_sso_service_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
278
341
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
279
342
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
280
343
 
@@ -305,6 +368,8 @@ On the ruby-saml toolkit there are different ways to validate the signature of t
305
368
  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.
306
369
  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.
307
370
 
371
+ 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.
372
+
308
373
  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.
309
374
 
310
375
  In order to handle that the toolkit offers the 'idp_cert_multi' parameter.
@@ -334,7 +399,7 @@ def saml_settings
334
399
  settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
335
400
 
336
401
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
337
- settings.issuer = "http://#{request.host}/saml/metadata"
402
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
338
403
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
339
404
  # Optional for most SAML IdPs
340
405
  settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
@@ -345,11 +410,11 @@ end
345
410
  The following attributes are set:
346
411
  * idp_entity_id
347
412
  * name_identifier_format
348
- * idp_sso_target_url
349
- * idp_slo_target_url
413
+ * idp_sso_service_url
414
+ * idp_slo_service_url
350
415
  * idp_attribute_names
351
- * idp_cert
352
- * idp_cert_fingerprint
416
+ * idp_cert
417
+ * idp_cert_fingerprint
353
418
  * idp_cert_multi
354
419
 
355
420
  ### Retrieve one Entity Descriptor when many exist in Metadata
@@ -412,6 +477,9 @@ Imagine this `saml:AttributeStatement`
412
477
  <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
413
478
  <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>
414
479
  </saml:Attribute>
480
+ <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
481
+ <saml:AttributeValue>usersName</saml:AttributeValue>
482
+ </saml:Attribute>
415
483
  </saml:AttributeStatement>
416
484
  ```
417
485
 
@@ -422,7 +490,8 @@ pp(response.attributes) # is an OneLogin::RubySaml::Attributes object
422
490
  "another_value"=>["value1", "value2"],
423
491
  "role"=>["role1", "role2", "role3"],
424
492
  "attribute_with_nil_value"=>[nil],
425
- "attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]}>
493
+ "attribute_with_nils_and_empty_strings"=>["", "valuePresent", nil, nil]
494
+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"=>["usersName"]}>
426
495
 
427
496
  # Active single_value_compatibility
428
497
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
@@ -439,6 +508,9 @@ pp(response.attributes.single(:role))
439
508
  pp(response.attributes.multi(:role))
440
509
  # => ["role1", "role2", "role3"]
441
510
 
511
+ pp(response.attributes.fetch(:role))
512
+ # => "role1"
513
+
442
514
  pp(response.attributes[:attribute_with_nil_value])
443
515
  # => nil
444
516
 
@@ -454,6 +526,9 @@ pp(response.attributes.single(:not_exists))
454
526
  pp(response.attributes.multi(:not_exists))
455
527
  # => nil
456
528
 
529
+ pp(response.attributes.fetch(/givenname/))
530
+ # => "usersName"
531
+
457
532
  # Deactive single_value_compatibility
458
533
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
459
534
 
@@ -469,6 +544,9 @@ pp(response.attributes.single(:role))
469
544
  pp(response.attributes.multi(:role))
470
545
  # => ["role1", "role2", "role3"]
471
546
 
547
+ pp(response.attributes.fetch(:role))
548
+ # => ["role1", "role2", "role3"]
549
+
472
550
  pp(response.attributes[:attribute_with_nil_value])
473
551
  # => [nil]
474
552
 
@@ -483,11 +561,17 @@ pp(response.attributes.single(:not_exists))
483
561
 
484
562
  pp(response.attributes.multi(:not_exists))
485
563
  # => nil
564
+
565
+ pp(response.attributes.fetch(/givenname/))
566
+ # => ["usersName"]
486
567
  ```
487
568
 
488
569
  The `saml:AuthnContextClassRef` of the AuthNRequest can be provided by `settings.authn_context`; possible values are described at [SAMLAuthnCxt]. The comparison method can be set using `settings.authn_context_comparison` parameter. Possible values include: 'exact', 'better', 'maximum' and 'minimum' (default value is 'exact').
489
570
  To add a `saml:AuthnContextDeclRef`, define `settings.authn_context_decl_ref`.
490
571
 
572
+ In a SP-initiated flow, the SP can indicate to the IdP the subject that should be authenticated. This is done by defining the `settings.name_identifier_value_requested` before
573
+ building the authrequest object.
574
+
491
575
 
492
576
  ## Signing
493
577
 
@@ -515,6 +599,8 @@ The settings related to sign are stored in the `security` attribute of the setti
515
599
  # Embeded signature or HTTP GET parameter signature
516
600
  # Note that metadata signature is always embedded regardless of this value.
517
601
  settings.security[:embed_sign] = false
602
+ settings.security[:check_idp_cert_expiration] = false # Enable or not IdP x509 cert expiration check
603
+ settings.security[:check_sp_cert_expiration] = false # Enable or not SP x509 cert expiration check
518
604
  ```
519
605
 
520
606
  Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
@@ -522,7 +608,7 @@ Remember to provide it to the Signature builder if you are sending a `GET RelayS
522
608
  signature validation process will fail at the Identity Provider.
523
609
 
524
610
  The Service Provider will sign the request/responses with its private key.
525
- The Identity Provider will validate the sign of the received request/responses with the public x500 cert of the
611
+ The Identity Provider will validate the sign of the received request/responses with the public x509 cert of the
526
612
  Service Provider.
527
613
 
528
614
  Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
@@ -563,21 +649,27 @@ def sp_logout_request
563
649
  # LogoutRequest accepts plain browser requests w/o paramters
564
650
  settings = saml_settings
565
651
 
566
- if settings.idp_slo_target_url.nil?
652
+ if settings.idp_slo_service_url.nil?
567
653
  logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
568
654
  delete_session
569
655
  else
570
656
 
571
- # Since we created a new SAML request, save the transaction_id
572
- # to compare it with the response we get back
573
657
  logout_request = OneLogin::RubySaml::Logoutrequest.new()
574
- session[:transaction_id] = logout_request.uuid
575
- logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{session[:transaction_id]}'"
658
+ logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
576
659
 
577
660
  if settings.name_identifier_value.nil?
578
661
  settings.name_identifier_value = session[:userid]
579
662
  end
580
663
 
664
+ # Ensure user is logged out before redirect to IdP, in case anything goes wrong during single logout process (as recommended by saml2int [SDP-SP34])
665
+ logged_user = session[:userid]
666
+ logger.info "Delete session for '#{session[:userid]}'"
667
+ delete_session
668
+
669
+ # Save the transaction_id to compare it with the response we get back
670
+ session[:transaction_id] = logout_request.uuid
671
+ session[:logged_out_user] = logged_user
672
+
581
673
  relayState = url_for controller: 'saml', action: 'index'
582
674
  redirect_to(logout_request.create(settings, :RelayState => relayState))
583
675
  end
@@ -605,7 +697,7 @@ def process_logout_response
605
697
  logger.error "The SAML Logout Response is invalid"
606
698
  else
607
699
  # Actually log out this session
608
- logger.info "Delete session for '#{session[:userid]}'"
700
+ logger.info "SLO completed for '#{session[:logged_out_user]}'"
609
701
  delete_session
610
702
  end
611
703
  end
@@ -614,6 +706,8 @@ end
614
706
  def delete_session
615
707
  session[:userid] = nil
616
708
  session[:attributes] = nil
709
+ session[:transaction_id] = nil
710
+ session[:logged_out_user] = nil
617
711
  end
618
712
  ```
619
713
 
@@ -626,7 +720,7 @@ def idp_logout_request
626
720
  logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
627
721
  if !logout_request.is_valid?
628
722
  logger.error "IdP initiated LogoutRequest was not valid!"
629
- render :inline => logger.error
723
+ return render :inline => logger.error
630
724
  end
631
725
  logger.info "IdP initiated Logout for #{logout_request.name_id}"
632
726
 
@@ -681,6 +775,14 @@ class SamlController < ApplicationController
681
775
  end
682
776
  ```
683
777
 
778
+ You can add ValidUntil and CacheDuration to the XML Metadata using instead
779
+ ```ruby
780
+ # Valid until => 2 days from now
781
+ # Cache duration = 604800s = 1 week
782
+ valid_until = Time.now + 172800
783
+ cache_duration = 604800
784
+ meta.generate(settings, false, valid_until, cache_duration)
785
+ ```
684
786
 
685
787
  ## Clock Drift
686
788
 
data/changelog.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # RubySaml Changelog
2
2
 
3
+ ### 1.12.2 (Apr 08, 2022)
4
+ * [575](https://github.com/onelogin/ruby-saml/pull/575) Fix SloLogoutresponse bug on LogoutRequest
5
+
6
+ ### 1.12.1 (Apr 05, 2022)
7
+ * Fix XPath typo incompatible with Rexml 3.2.5
8
+ * Refactor GCM support
9
+
10
+ ### 1.12.0 (Feb 18, 2021)
11
+ * Support AES-128-GCM, AES-192-GCM, and AES-256-GCM encryptions
12
+ * Parse & return SLO ResponseLocation in IDPMetadataParser & Settings
13
+ * Adding idp_sso_service_url and idp_slo_service_url settings
14
+ * [#536](https://github.com/onelogin/ruby-saml/pull/536) Adding feth method to be able retrieve attributes based on regex
15
+ * Reduce size of built gem by excluding the test folder
16
+ * Improve protection on Zlib deflate decompression bomb attack.
17
+ * Add ValidUntil and cacheDuration support on Metadata generator
18
+ * Add support for cacheDuration at the IdpMetadataParser
19
+ * Support customizable statusCode on generated LogoutResponse
20
+ * [#545](https://github.com/onelogin/ruby-saml/pull/545) More specific error messages for signature validation
21
+ * Support Process Transform
22
+ * Raise SettingError if invoking an action with no endpoint defined on the settings
23
+ * Made IdpMetadataParser more extensible for subclasses
24
+ *[#548](https://github.com/onelogin/ruby-saml/pull/548) Add :skip_audience option
25
+ * [#555](https://github.com/onelogin/ruby-saml/pull/555) Define 'soft' variable to prevent exception when doc cert is invalid
26
+ * Improve documentation
27
+
28
+ ### 1.11.0 (Jul 24, 2019)
29
+
30
+ * Deprecate settings.issuer in favor of settings.sp_entity_id
31
+ * Add support for certification expiration
32
+
33
+ ### 1.10.2 (Apr 29, 2019)
34
+
35
+ * Add valid until, accessor
36
+ * Fix Rubygem metadata that requested nokogiri <= 1.5.11
37
+
38
+ ### 1.10.1 (Apr 08, 2019)
39
+
40
+ * Fix ruby 1.8.7 incompatibilities
41
+
42
+ ### 1.10.0 (Mar 21, 2019)
43
+ * Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user to be authenticated
44
+ * Improves IdpMetadataParser to allow parse multiple IDPSSODescriptors
45
+ * Improves format_cert method to accept certs with /\x0d/
46
+ * Forces nokogiri >= 1.8.2 when possible
47
+
48
+ ### 1.9.0 (Sept 03, 2018)
49
+ * [#458](https://github.com/onelogin/ruby-saml/pull/458) Remove ruby 2.4+ warnings
50
+ * Improve JRuby support
51
+ * [#465](https://github.com/onelogin/ruby-saml/pull/465) Extend Settings initialization with the new keep_security_attributes parameter
52
+ * Fix wrong message when SessionNotOnOrAfter expired
53
+ * [#471](https://github.com/onelogin/ruby-saml/pull/471) Allow for `allowed_clock_drift` to be set as a string
54
+
55
+ ### 1.8.0 (April 23, 2018)
56
+ * [#437](https://github.com/onelogin/ruby-saml/issues/437) Creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState should not send empty RelayState URL param
57
+ * [#454](https://github.com/onelogin/ruby-saml/pull/454) Added Response available options
58
+ * [#453](https://github.com/onelogin/ruby-saml/pull/453) Raise a more descriptive exception if idp_sso_target_url is missing
59
+ * [#452](https://github.com/onelogin/ruby-saml/pull/452) Fix behavior of skip_conditions flag on Response
60
+ * [#449](https://github.com/onelogin/ruby-saml/pull/449) Add ability to skip authnstatement validation
61
+ * Clear cached values to be able to use IdpMetadataParser more than once
62
+ * Updated invalid audience error message
63
+
3
64
  ### 1.7.2 (Feb 28, 2018)
4
65
  * [#446](https://github.com/onelogin/ruby-saml/pull/446) Normalize text returned by OneLogin::RubySaml::Utils.element_text
5
66
 
@@ -16,7 +16,7 @@ module OneLogin
16
16
  end
17
17
 
18
18
  def configure(&block)
19
- instance_eval &block
19
+ instance_eval(&block)
20
20
  end
21
21
 
22
22
  # @return [Boolean] True if the AttributeService object has been initialized and set with the required values
@@ -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 [Array] Return all attributes as an array
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,13 +35,14 @@ module OneLogin
30
35
  #
31
36
  def create(settings, params = {})
32
37
  params = create_params(settings, params)
33
- params_prefix = (settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
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
- @login_url = settings.idp_sso_target_url + request_params
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
40
46
  end
41
47
 
42
48
  # Creates the Get parameters for the request.
@@ -50,6 +56,11 @@ module OneLogin
50
56
  # conflicts so this line will solve them.
51
57
  relay_state = params[:RelayState] || params['RelayState']
52
58
 
59
+ if relay_state.nil?
60
+ params.delete(:RelayState)
61
+ params.delete('RelayState')
62
+ end
63
+
53
64
  request_doc = create_authentication_xml_doc(settings)
54
65
  request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
55
66
 
@@ -101,7 +112,7 @@ module OneLogin
101
112
  root.attributes['ID'] = uuid
102
113
  root.attributes['IssueInstant'] = time
103
114
  root.attributes['Version'] = "2.0"
104
- root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil?
115
+ root.attributes['Destination'] = settings.idp_sso_service_url unless settings.idp_sso_service_url.nil? or settings.idp_sso_service_url.empty?
105
116
  root.attributes['IsPassive'] = settings.passive unless settings.passive.nil?
106
117
  root.attributes['ProtocolBinding'] = settings.protocol_binding unless settings.protocol_binding.nil?
107
118
  root.attributes["AttributeConsumingServiceIndex"] = settings.attributes_index unless settings.attributes_index.nil?
@@ -111,10 +122,22 @@ module OneLogin
111
122
  if settings.assertion_consumer_service_url != nil
112
123
  root.attributes["AssertionConsumerServiceURL"] = settings.assertion_consumer_service_url
113
124
  end
114
- if settings.issuer != nil
125
+ if settings.sp_entity_id != nil
115
126
  issuer = root.add_element "saml:Issuer"
116
- issuer.text = settings.issuer
127
+ issuer.text = settings.sp_entity_id
117
128
  end
129
+
130
+ if settings.name_identifier_value_requested != nil
131
+ subject = root.add_element "saml:Subject"
132
+
133
+ nameid = subject.add_element "saml:NameID"
134
+ nameid.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
135
+ nameid.text = settings.name_identifier_value_requested
136
+
137
+ subject_confirmation = subject.add_element "saml:SubjectConfirmation"
138
+ subject_confirmation.attributes['Method'] = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
139
+ end
140
+
118
141
  if settings.name_identifier_format != nil
119
142
  root.add_element "samlp:NameIDPolicy", {
120
143
  # Might want to make AllowCreate a setting?
@@ -157,7 +180,7 @@ module OneLogin
157
180
 
158
181
  def sign_document(document, settings)
159
182
  # embed signature
160
- if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
183
+ if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
161
184
  private_key = settings.get_sp_key
162
185
  cert = settings.get_sp_cert
163
186
  document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])