ruby-saml 1.7.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +37 -15
  3. data/README.md +119 -23
  4. data/changelog.md +60 -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 +25 -5
  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 +44 -17
  19. data/lib/onelogin/ruby-saml/utils.rb +88 -11
  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 -272
  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 -1527
  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_double_status_code.xml.base64 +0 -1
  109. data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
  110. data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
  111. data/test/responses/response_eval.xml +0 -7
  112. data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
  113. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  114. data/test/responses/response_unsigned_xml_base64 +0 -1
  115. data/test/responses/response_with_ampersands.xml +0 -139
  116. data/test/responses/response_with_ampersands.xml.base64 +0 -93
  117. data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
  118. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  119. data/test/responses/response_with_multiple_attribute_values.xml +0 -67
  120. data/test/responses/response_with_retrieval_method.xml +0 -26
  121. data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
  122. data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
  123. data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
  124. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  125. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  126. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  127. data/test/responses/response_without_attributes.xml.base64 +0 -79
  128. data/test/responses/response_without_reference_uri.xml.base64 +0 -1
  129. data/test/responses/response_wrapped.xml.base64 +0 -150
  130. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
  131. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  132. data/test/responses/signed_nameid_in_atts.xml +0 -47
  133. data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
  134. data/test/responses/simple_saml_php.xml +0 -71
  135. data/test/responses/starfield_response.xml.base64 +0 -1
  136. data/test/responses/test_sign.xml +0 -43
  137. data/test/responses/unsigned_encrypted_adfs.xml +0 -23
  138. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
  139. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
  140. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
  141. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
  142. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
  143. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
  144. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  145. data/test/responses/valid_response.xml.base64 +0 -1
  146. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  147. data/test/saml_message_test.rb +0 -56
  148. data/test/settings_test.rb +0 -301
  149. data/test/slo_logoutrequest_test.rb +0 -448
  150. data/test/slo_logoutresponse_test.rb +0 -185
  151. data/test/test_helper.rb +0 -323
  152. data/test/utils_test.rb +0 -217
  153. data/test/xml_security_test.rb +0 -421
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cb5007dd289f308983339a7ae35cd40018f58143
4
- data.tar.gz: 16f12f151a3ab5d9cb32739b4d55f7437748d17e
2
+ SHA256:
3
+ metadata.gz: 43bc92cf8a14835577d9bb32d1bdcef71fd5ffccb351dd41ac9b56863fb173c7
4
+ data.tar.gz: e7975fcf413d9c64801f7b5190246685548205034dc74315bc169738697e1006
5
5
  SHA512:
6
- metadata.gz: 6395d86c33cd7d49bc329f486a5be5a8c4cc5e24076d75234f96bb51fcefe1d8c782f6bf18fd07201751d300c23c521cf4441c7514d61651c89d363ffb9cf700
7
- data.tar.gz: d5eb6efeb77b267ad51487dfb3baa06f28103c582e61efbf996c279f0e7f0915d1abe18ed34be1c5b60eef69240b31d0d40c44e6cf6157b9c968bf96208ad7c8
6
+ metadata.gz: 0a09fcb8777969eb6d54b29d20520c7e17e3f7dc128cfc81475eba8c9b31f5926f2b64d308b18268762b43fb60cf7956f6e266c1f5343d2b9d58e545be0c3392
7
+ data.tar.gz: 8e9008647a610935764b2f578b76c5eb72d09be482d76b5f4d8ab51fd29d4569a3ba2e2db61f63fbdde27bd1be14bf4afdeffe1c7f699afc0b7d5e1c85d0fe09
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,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%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
+ ## 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.
2
23
 
3
24
  ## Updating from 1.6.0 to 1.7.0
4
25
 
@@ -41,6 +62,10 @@ value.
41
62
  If you want to skip that validation, add the :skip_recipient_check option to the
42
63
  initialize method of the Response object.
43
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
+
44
69
  ## Updating from 1.3.x to 1.4.X
45
70
 
46
71
  Version `1.4.0` is a recommended update for all Ruby SAML users as it includes security improvements.
@@ -92,8 +117,12 @@ We created a demo project for Rails4 that uses the latest version of this librar
92
117
  * 2.2.x
93
118
  * 2.3.x
94
119
  * 2.4.x
120
+ * 2.5.x
121
+ * 2.6.x
122
+ * 2.7.x
95
123
  * JRuby 1.7.19
96
124
  * JRuby 9.0.0.0
125
+ * JRuby 9.2.0.0
97
126
 
98
127
  ## Adding Features, Pull Requests
99
128
  * Fork the repository
@@ -107,6 +136,17 @@ We created a demo project for Rails4 that uses the latest version of this librar
107
136
 
108
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.
109
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
+
110
150
  ## Getting Started
111
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:
112
152
 
@@ -114,7 +154,7 @@ Using `Gemfile`
114
154
 
115
155
  ```ruby
116
156
  # latest stable
117
- gem 'ruby-saml', '~> 1.0.0'
157
+ gem 'ruby-saml', '~> 1.11.0'
118
158
 
119
159
  # or track master for bleeding-edge
120
160
  gem 'ruby-saml', :github => 'onelogin/ruby-saml'
@@ -163,7 +203,7 @@ To override the default behavior and control the destination of log messages, pr
163
203
  a ruby Logger object to the gem's logging singleton:
164
204
 
165
205
  ```ruby
166
- OneLogin::RubySaml::Logging.logger = Logger.new(File.open('/var/log/ruby-saml.log', 'w'))
206
+ OneLogin::RubySaml::Logging.logger = Logger.new('/var/log/ruby-saml.log')
167
207
  ```
168
208
 
169
209
  ## The Initialization Phase
@@ -177,6 +217,17 @@ def init
177
217
  end
178
218
  ```
179
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
+
180
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):
181
232
 
182
233
  ```ruby
@@ -190,6 +241,7 @@ def consume
190
241
  session[:attributes] = response.attributes
191
242
  else
192
243
  authorize_failure # This method shows an error message
244
+ # List of errors is available in response.errors array
193
245
  end
194
246
  end
195
247
  ```
@@ -211,10 +263,10 @@ def saml_settings
211
263
  settings = OneLogin::RubySaml::Settings.new
212
264
 
213
265
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
214
- settings.issuer = "http://#{request.host}/saml/metadata"
266
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
215
267
  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}"
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}"
218
270
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
219
271
  settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
220
272
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -235,12 +287,16 @@ def saml_settings
235
287
  end
236
288
  ```
237
289
 
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:
290
+ The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
291
+
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:
239
293
 
240
294
  ```ruby
295
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_authnstatement: true}) # skips AuthnStatement
241
296
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_conditions: true}) # skips conditions
242
297
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], {skip_subject_confirmation: true}) # skips subject confirmation
243
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
244
300
  ```
245
301
 
246
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:
@@ -264,6 +320,7 @@ class SamlController < ApplicationController
264
320
  session[:attributes] = response.attributes
265
321
  else
266
322
  authorize_failure # This method shows an error message
323
+ # List of errors is available in response.errors array
267
324
  end
268
325
  end
269
326
 
@@ -273,8 +330,8 @@ class SamlController < ApplicationController
273
330
  settings = OneLogin::RubySaml::Settings.new
274
331
 
275
332
  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}"
333
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
334
+ settings.idp_sso_service_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
278
335
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
279
336
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
280
337
 
@@ -305,6 +362,8 @@ On the ruby-saml toolkit there are different ways to validate the signature of t
305
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.
306
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.
307
364
 
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.
366
+
308
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.
309
368
 
310
369
  In order to handle that the toolkit offers the 'idp_cert_multi' parameter.
@@ -334,7 +393,7 @@ def saml_settings
334
393
  settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
335
394
 
336
395
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
337
- settings.issuer = "http://#{request.host}/saml/metadata"
396
+ settings.sp_entity_id = "http://#{request.host}/saml/metadata"
338
397
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
339
398
  # Optional for most SAML IdPs
340
399
  settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
@@ -345,11 +404,11 @@ end
345
404
  The following attributes are set:
346
405
  * idp_entity_id
347
406
  * name_identifier_format
348
- * idp_sso_target_url
349
- * idp_slo_target_url
407
+ * idp_sso_service_url
408
+ * idp_slo_service_url
350
409
  * idp_attribute_names
351
- * idp_cert
352
- * idp_cert_fingerprint
410
+ * idp_cert
411
+ * idp_cert_fingerprint
353
412
  * idp_cert_multi
354
413
 
355
414
  ### Retrieve one Entity Descriptor when many exist in Metadata
@@ -412,6 +471,9 @@ Imagine this `saml:AttributeStatement`
412
471
  <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
413
472
  <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>
414
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>
415
477
  </saml:AttributeStatement>
416
478
  ```
417
479
 
@@ -422,7 +484,8 @@ pp(response.attributes) # is an OneLogin::RubySaml::Attributes object
422
484
  "another_value"=>["value1", "value2"],
423
485
  "role"=>["role1", "role2", "role3"],
424
486
  "attribute_with_nil_value"=>[nil],
425
- "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"]}>
426
489
 
427
490
  # Active single_value_compatibility
428
491
  OneLogin::RubySaml::Attributes.single_value_compatibility = true
@@ -439,6 +502,9 @@ pp(response.attributes.single(:role))
439
502
  pp(response.attributes.multi(:role))
440
503
  # => ["role1", "role2", "role3"]
441
504
 
505
+ pp(response.attributes.fetch(:role))
506
+ # => "role1"
507
+
442
508
  pp(response.attributes[:attribute_with_nil_value])
443
509
  # => nil
444
510
 
@@ -454,6 +520,9 @@ pp(response.attributes.single(:not_exists))
454
520
  pp(response.attributes.multi(:not_exists))
455
521
  # => nil
456
522
 
523
+ pp(response.attributes.fetch(/givenname/))
524
+ # => "usersName"
525
+
457
526
  # Deactive single_value_compatibility
458
527
  OneLogin::RubySaml::Attributes.single_value_compatibility = false
459
528
 
@@ -469,6 +538,9 @@ pp(response.attributes.single(:role))
469
538
  pp(response.attributes.multi(:role))
470
539
  # => ["role1", "role2", "role3"]
471
540
 
541
+ pp(response.attributes.fetch(:role))
542
+ # => ["role1", "role2", "role3"]
543
+
472
544
  pp(response.attributes[:attribute_with_nil_value])
473
545
  # => [nil]
474
546
 
@@ -483,11 +555,17 @@ pp(response.attributes.single(:not_exists))
483
555
 
484
556
  pp(response.attributes.multi(:not_exists))
485
557
  # => nil
558
+
559
+ pp(response.attributes.fetch(/givenname/))
560
+ # => ["usersName"]
486
561
  ```
487
562
 
488
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').
489
564
  To add a `saml:AuthnContextDeclRef`, define `settings.authn_context_decl_ref`.
490
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
+
491
569
 
492
570
  ## Signing
493
571
 
@@ -515,6 +593,8 @@ The settings related to sign are stored in the `security` attribute of the setti
515
593
  # Embeded signature or HTTP GET parameter signature
516
594
  # Note that metadata signature is always embedded regardless of this value.
517
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
518
598
  ```
519
599
 
520
600
  Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
@@ -522,7 +602,7 @@ Remember to provide it to the Signature builder if you are sending a `GET RelayS
522
602
  signature validation process will fail at the Identity Provider.
523
603
 
524
604
  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
605
+ The Identity Provider will validate the sign of the received request/responses with the public x509 cert of the
526
606
  Service Provider.
527
607
 
528
608
  Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and decrypt processes.
@@ -563,21 +643,27 @@ def sp_logout_request
563
643
  # LogoutRequest accepts plain browser requests w/o paramters
564
644
  settings = saml_settings
565
645
 
566
- if settings.idp_slo_target_url.nil?
646
+ if settings.idp_slo_service_url.nil?
567
647
  logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
568
648
  delete_session
569
649
  else
570
650
 
571
- # Since we created a new SAML request, save the transaction_id
572
- # to compare it with the response we get back
573
651
  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]}'"
652
+ logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
576
653
 
577
654
  if settings.name_identifier_value.nil?
578
655
  settings.name_identifier_value = session[:userid]
579
656
  end
580
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
+
581
667
  relayState = url_for controller: 'saml', action: 'index'
582
668
  redirect_to(logout_request.create(settings, :RelayState => relayState))
583
669
  end
@@ -605,7 +691,7 @@ def process_logout_response
605
691
  logger.error "The SAML Logout Response is invalid"
606
692
  else
607
693
  # Actually log out this session
608
- logger.info "Delete session for '#{session[:userid]}'"
694
+ logger.info "SLO completed for '#{session[:logged_out_user]}'"
609
695
  delete_session
610
696
  end
611
697
  end
@@ -614,6 +700,8 @@ end
614
700
  def delete_session
615
701
  session[:userid] = nil
616
702
  session[:attributes] = nil
703
+ session[:transaction_id] = nil
704
+ session[:logged_out_user] = nil
617
705
  end
618
706
  ```
619
707
 
@@ -626,7 +714,7 @@ def idp_logout_request
626
714
  logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
627
715
  if !logout_request.is_valid?
628
716
  logger.error "IdP initiated LogoutRequest was not valid!"
629
- render :inline => logger.error
717
+ return render :inline => logger.error
630
718
  end
631
719
  logger.info "IdP initiated Logout for #{logout_request.name_id}"
632
720
 
@@ -681,6 +769,14 @@ class SamlController < ApplicationController
681
769
  end
682
770
  ```
683
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
+ ```
684
780
 
685
781
  ## Clock Drift
686
782
 
data/changelog.md CHANGED
@@ -1,5 +1,65 @@
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
+
41
+ ### 1.9.0 (Sept 03, 2018)
42
+ * [#458](https://github.com/onelogin/ruby-saml/pull/458) Remove ruby 2.4+ warnings
43
+ * Improve JRuby support
44
+ * [#465](https://github.com/onelogin/ruby-saml/pull/465) Extend Settings initialization with the new keep_security_attributes parameter
45
+ * Fix wrong message when SessionNotOnOrAfter expired
46
+ * [#471](https://github.com/onelogin/ruby-saml/pull/471) Allow for `allowed_clock_drift` to be set as a string
47
+
48
+ ### 1.8.0 (April 23, 2018)
49
+ * [#437](https://github.com/onelogin/ruby-saml/issues/437) Creating AuthRequests/LogoutRequests/LogoutResponses with nil RelayState should not send empty RelayState URL param
50
+ * [#454](https://github.com/onelogin/ruby-saml/pull/454) Added Response available options
51
+ * [#453](https://github.com/onelogin/ruby-saml/pull/453) Raise a more descriptive exception if idp_sso_target_url is missing
52
+ * [#452](https://github.com/onelogin/ruby-saml/pull/452) Fix behavior of skip_conditions flag on Response
53
+ * [#449](https://github.com/onelogin/ruby-saml/pull/449) Add ability to skip authnstatement validation
54
+ * Clear cached values to be able to use IdpMetadataParser more than once
55
+ * Updated invalid audience error message
56
+
57
+ ### 1.7.2 (Feb 28, 2018)
58
+ * [#446](https://github.com/onelogin/ruby-saml/pull/446) Normalize text returned by OneLogin::RubySaml::Utils.element_text
59
+
60
+ ### 1.7.1 (Feb 28, 2018)
61
+ * [#444](https://github.com/onelogin/ruby-saml/pull/444) Fix audience validation for empty audience restriction
62
+
3
63
  ### 1.7.0 (Feb 27, 2018)
4
64
  * Fix vulnerability CVE-2017-11428. Process text of nodes properly, ignoring comments
5
65
 
@@ -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.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
@@ -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])