ruby-saml 1.13.0 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ded4e8f9560644f26e90079ecf0021f81fb8fb90
4
- data.tar.gz: 034e0d8ee8d11aa443435b20d071015dfbcf5161
2
+ SHA256:
3
+ metadata.gz: 3ed3b0ab8cb9f9fd8b4e23b34f8ad06fd1e6c6a13d885d34c2f7b385297783b3
4
+ data.tar.gz: 757dccd6c1418f1128a69c7fdcd95cdd8d8bcac697ae750edb92f058aee50c7f
5
5
  SHA512:
6
- metadata.gz: 957e2b7598309e9b770019902f28bdec07a28a19a77abfb7e72d503ab3c8b4c57138451d3bb0bced671aca4d454d6637821a3931e91e6f4d79ef4d5d1a91a25e
7
- data.tar.gz: 74d06dcdc7ba3f3c0dc797ad3e329987f0bd32bfc5b0bdee62f9c081688dd97bb4892ef42de795c09c59b2c48487b673476a6dd12aedca0770b600c770e2c4b7
6
+ metadata.gz: 9cc12490c6b57281677f1db5a5a804c07a9b97f57a86d3b5676b79b36ca28bd7d9971ed3db893b730ff09ab6c03374600d87118949440c4271293bc48333b3d6
7
+ data.tar.gz: 4c330a53de476f479a22dbe07b18f51e0ebe1dcde834eac9cb65678b8767094e365a0ea043a5e4b09d1cabfa6a8f0c4287f29fffe6e53328b70572a64cefcd04
@@ -8,8 +8,8 @@ jobs:
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- os: [ubuntu-latest, macos-latest]
12
- ruby-version: [2.1.9, 2.2.10, 2.3.8, 2.4.6, 2.5.8, 2.6.6, 2.7.2, 3.0.1, jruby-9.1.17.0, jruby-9.2.17.0, truffleruby]
11
+ os: [ubuntu-20.04, macos-latest]
12
+ ruby-version: [2.1.9, 2.2.10, 2.3.8, 2.4.6, 2.5.8, 2.6.6, 2.7.2, 3.0.1, 3.1, 3.2, jruby-9.1.17.0, jruby-9.2.17.0, jruby-9.3.2.0, jruby-9.4.0.0, truffleruby]
13
13
  runs-on: ${{ matrix.os }}
14
14
  steps:
15
15
  - uses: actions/checkout@v2
@@ -23,3 +23,21 @@ jobs:
23
23
 
24
24
  - name: Run tests
25
25
  run: bundle exec rake
26
+
27
+ - name: Coveralls
28
+ uses: coverallsapp/github-action@master
29
+ with:
30
+ github-token: ${{ secrets.github_token }}
31
+ parallel: true
32
+ flag-name: run-${{ matrix.ruby-version }}
33
+
34
+ finish:
35
+ needs: test
36
+ runs-on: ubuntu-latest
37
+ steps:
38
+ - name: Coveralls Finished
39
+ uses: coverallsapp/github-action@master
40
+ with:
41
+ github-token: ${{ secrets.github_token }}
42
+ flag-name: run-${{ matrix.ruby-version }}
43
+ parallel-finished: true
data/CHANGELOG.md CHANGED
@@ -1,4 +1,17 @@
1
1
  # Ruby SAML Changelog
2
+ ### 1.15.0 (Jan 04, 2023)
3
+ * [#650](https://github.com/SAML-Toolkits/ruby-saml/pull/650) Replace strip! by strip on compute_digest method
4
+ * [#638](https://github.com/SAML-Toolkits/ruby-saml/pull/638) Fix dateTime format for the validUntil attribute of the generated metadata
5
+ * [#576](https://github.com/SAML-Toolkits/ruby-saml/pull/576) Support idp cert multi with string keys
6
+ * [#567](https://github.com/SAML-Toolkits/ruby-saml/pull/567) Improve Code quality
7
+ * Add info about new repo, new maintainer, new security contact
8
+ * Fix tests, Adjust dependencies, Add ruby 3.2 and new jruby versions tests to the CI. Add coveralls support
9
+
10
+ ### 1.14.0 (Feb 01, 2022)
11
+ * [#627](https://github.com/onelogin/ruby-saml/pull/627) Support escape downcasing for validating SLO Signatures of ADFS/Azure
12
+ * [#633](https://github.com/onelogin/ruby-saml/pull/633) Support ability to change ID prefix
13
+ * Make the uuid editable on the SAML Messages generated by the toolkit
14
+ * [#622](https://github.com/onelogin/ruby-saml/pull/622) Add security setting to more strictly enforce audience validation
2
15
 
3
16
  ### 1.13.0 (Sept 06, 2021)
4
17
  * [#611](https://github.com/onelogin/ruby-saml/pull/601) Replace MAX_BYTE_SIZE constant with setting: message_max_bytesize
data/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
- Copyright (c) 2010-2016 OneLogin, Inc.
1
+ Copyright (c) 2010-2022 OneLogin, Inc.
2
+ Copyright (c) 2023 IAM Digital Services, SL.
2
3
 
3
4
  Permission is hereby granted, free of charge, to any person
4
5
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -14,7 +14,7 @@ requests from identity providers.
14
14
  SAML authorization is a two step process and you are expected to implement support for both.
15
15
 
16
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)
17
+ [ruby-saml-example](https://github.com/saml-toolkit/ruby-saml-example)
18
18
 
19
19
  ### Supported Ruby Versions
20
20
 
@@ -52,8 +52,7 @@ In addition, the following may work but are untested:
52
52
  ## Security Guidelines
53
53
 
54
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.
55
+ by mail to the maintainer: sixto.martin.garcia+security@gmail.com
57
56
 
58
57
  ### Security Warning
59
58
 
@@ -66,7 +65,7 @@ However, ruby-saml never enables this dangerous Nokogiri configuration;
66
65
  ruby-saml never enables DTDLOAD, and it never disables NONET.
67
66
 
68
67
  The OneLogin::RubySaml::IdpMetadataParser class does not validate in any way the URL
69
- that is introduced in order to be parsed.
68
+ that is introduced in order to be parsed.
70
69
 
71
70
  Usually the same administrator that handles the Service Provider also sets the URL to
72
71
  the IdP, which should be a trusted resource.
@@ -87,7 +86,7 @@ Using `Gemfile`
87
86
  gem 'ruby-saml', '~> 1.11.0'
88
87
 
89
88
  # or track master for bleeding-edge
90
- gem 'ruby-saml', :github => 'onelogin/ruby-saml'
89
+ gem 'ruby-saml', :github => 'saml-toolkit/ruby-saml'
91
90
  ```
92
91
 
93
92
  Using RubyGems
@@ -392,6 +391,51 @@ The `OneLogin::RubySaml::IdpMetadataParser` also provides the methods `#parse_to
392
391
  Those return an Hash instead of a `Settings` object, which may be useful for configuring
393
392
  [omniauth-saml](https://github.com/omniauth/omniauth-saml), for instance.
394
393
 
394
+
395
+ ### Validating Signature of Metadata and retrieve settings
396
+
397
+ Right now there is no method at ruby_saml to validate the signature of the metadata that gonna be parsed,
398
+ but it can be done as follows:
399
+ * Download the XML.
400
+ * Validate the Signature, providing the cert.
401
+ * Provide the XML to the parse method if the signature was validated
402
+
403
+ ```
404
+ require "xml_security"
405
+ require "onelogin/ruby-saml/utils"
406
+ require "onelogin/ruby-saml/idp_metadata_parser"
407
+
408
+ url = "<url_to_the_metadata>"
409
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
410
+
411
+ uri = URI.parse(url)
412
+ raise ArgumentError.new("url must begin with http or https") unless /^https?/ =~ uri.scheme
413
+ http = Net::HTTP.new(uri.host, uri.port)
414
+ if uri.scheme == "https"
415
+ http.use_ssl = true
416
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
417
+ end
418
+
419
+ get = Net::HTTP::Get.new(uri.request_uri)
420
+ get.basic_auth uri.user, uri.password if uri.user
421
+ response = http.request(get)
422
+ xml = response.body
423
+ errors = []
424
+ doc = XMLSecurity::SignedDocument.new(xml, errors)
425
+ cert_str = "<include_cert_here>"
426
+ cert = OneLogin::RubySaml::Utils.format_cert("cert_str")
427
+ metadata_sign_cert = OpenSSL::X509::Certificate.new(cert)
428
+ valid = doc.validate_document_with_cert(metadata_sign_cert, true)
429
+ if valid
430
+ settings = idp_metadata_parser.parse(
431
+ xml,
432
+ entity_id: "<entity_id_of_the_entity_to_be_retrieved>"
433
+ )
434
+ else
435
+ print "Metadata Signarture failed to be verified with the cert provided"
436
+ end
437
+
438
+
395
439
  ## Retrieving Attributes
396
440
 
397
441
  If you are using `saml:AttributeStatement` to transfer data like the username, you can access all the attributes through `response.attributes`. It contains all the `saml:AttributeStatement`s with its 'Name' as an indifferent key and one or more `saml:AttributeValue`s as values. The value returned depends on the value of the
@@ -664,6 +708,29 @@ validation fails. You may disable such exceptions using the `settings.security[:
664
708
  settings.security[:soft] = true # Do not raise error on failed signature/certificate validations
665
709
  ```
666
710
 
711
+ #### Audience Validation
712
+
713
+ A service provider should only consider a SAML response valid if the IdP includes an <AudienceRestriction>
714
+ element containting an <Audience> element that uniquely identifies the service provider. Unless you specify
715
+ the `skip_audience` option, Ruby SAML will validate that each SAML response includes an <Audience> element
716
+ whose contents matches `settings.sp_entity_id`.
717
+
718
+ By default, Ruby SAML considers an <AudienceRestriction> element containing only empty <Audience> elements
719
+ to be valid. That means an otherwise valid SAML response with a condition like this would be valid:
720
+
721
+ ```xml
722
+ <AudienceRestriction>
723
+ <Audience />
724
+ </AudienceRestriction>
725
+ ```
726
+
727
+ You may enforce that an <AudienceRestriction> element containing only empty <Audience> elements
728
+ is invalid using the `settings.security[:strict_audience_validation]` parameter.
729
+
730
+ ```ruby
731
+ settings.security[:strict_audience_validation] = true
732
+ ```
733
+
667
734
  #### Key Rollover
668
735
 
669
736
  To update the SP X.509 certificate and private key without disruption of service, you may define the parameter
@@ -767,7 +834,13 @@ Here is an example that we could add to our previous controller to process a SAM
767
834
  # Method to handle IdP initiated logouts
768
835
  def idp_logout_request
769
836
  settings = Account.get_saml_settings
770
- logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
837
+ # ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses
838
+ # uppercase. Turn it True for ADFS compatibility on signature verification
839
+ settings.security[:lowercase_url_encoding] = true
840
+
841
+ logout_request = OneLogin::RubySaml::SloLogoutrequest.new(
842
+ params[:SAMLRequest], settings: settings
843
+ )
771
844
  if !logout_request.is_valid?
772
845
  logger.error "IdP initiated LogoutRequest was not valid!"
773
846
  return render :inline => logger.error
data/UPGRADING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ruby SAML Migration Guide
2
2
 
3
- ## Updating from 1.12.x to 1.13.0 (NOT YET RELEASED)
3
+ ## Updating from 1.12.x to 1.13.0
4
4
 
5
5
  Version `1.13.0` adds `settings.idp_sso_service_binding` and `settings.idp_slo_service_binding`, and
6
6
  deprecates `settings.security[:embed_sign]`. If specified, new binding parameters will be used in place of `:embed_sign`
@@ -15,7 +15,7 @@ module OneLogin
15
15
  class Authrequest < SamlMessage
16
16
 
17
17
  # AuthNRequest ID
18
- attr_reader :uuid
18
+ attr_accessor :uuid
19
19
 
20
20
  # Initializes the AuthNRequest. An Authrequest Object that is an extension of the SamlMessage class.
21
21
  # Asigns an ID, a random uuid.
@@ -39,7 +39,7 @@ module OneLogin
39
39
  saml_request = CGI.escape(params.delete("SAMLRequest"))
40
40
  request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
41
41
  params.each_pair do |key, value|
42
- request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
42
+ request_params << "&#{key}=#{CGI.escape(value.to_s)}"
43
43
  end
44
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
45
  @login_url = settings.idp_sso_service_url + request_params
@@ -442,7 +442,7 @@ module OneLogin
442
442
  priority = Array(priority)
443
443
  if priority.any?
444
444
  values = nodes.map(&:text)
445
- Array(priority).detect { |candidate| values.include?(candidate) }
445
+ priority.detect { |candidate| values.include?(candidate) }
446
446
  else
447
447
  nodes.first.text
448
448
  end
@@ -12,7 +12,7 @@ module OneLogin
12
12
  class Logoutrequest < SamlMessage
13
13
 
14
14
  # Logout Request ID
15
- attr_reader :uuid
15
+ attr_accessor :uuid
16
16
 
17
17
  # Initializes the Logout Request. A Logoutrequest Object that is an extension of the SamlMessage class.
18
18
  # Asigns an ID, a random uuid.
@@ -36,7 +36,7 @@ module OneLogin
36
36
  saml_request = CGI.escape(params.delete("SAMLRequest"))
37
37
  request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
38
38
  params.each_pair do |key, value|
39
- request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
39
+ request_params << "&#{key}=#{CGI.escape(value.to_s)}"
40
40
  end
41
41
  raise SettingError.new "Invalid settings, idp_slo_service_url is not set!" if settings.idp_slo_service_url.nil? or settings.idp_slo_service_url.empty?
42
42
  @logout_url = settings.idp_slo_service_url + request_params
@@ -212,7 +212,7 @@ module OneLogin
212
212
  return true unless options.has_key? :get_params
213
213
  return true unless options[:get_params].has_key? 'Signature'
214
214
 
215
- options[:raw_get_params] = OneLogin::RubySaml::Utils.prepare_raw_get_params(options[:raw_get_params], options[:get_params])
215
+ options[:raw_get_params] = OneLogin::RubySaml::Utils.prepare_raw_get_params(options[:raw_get_params], options[:get_params], settings.security[:lowercase_url_encoding])
216
216
 
217
217
  if options[:get_params]['SigAlg'].nil? && !options[:raw_get_params]['SigAlg'].nil?
218
218
  options[:get_params]['SigAlg'] = CGI.unescape(options[:raw_get_params]['SigAlg'])
@@ -49,7 +49,7 @@ module OneLogin
49
49
  root = meta_doc.add_element("md:EntityDescriptor", namespaces)
50
50
  root.attributes["ID"] = OneLogin::RubySaml::Utils.uuid
51
51
  root.attributes["entityID"] = settings.sp_entity_id if settings.sp_entity_id
52
- root.attributes["validUntil"] = valid_until.strftime('%Y-%m-%dT%H:%M:%S%z') if valid_until
52
+ root.attributes["validUntil"] = valid_until.utc.strftime('%Y-%m-%dT%H:%M:%SZ') if valid_until
53
53
  root.attributes["cacheDuration"] = "PT" + cache_duration.to_s + "S" if cache_duration
54
54
  root
55
55
  end
@@ -613,7 +613,12 @@ module OneLogin
613
613
  #
614
614
  def validate_audience
615
615
  return true if options[:skip_audience]
616
- return true if audiences.empty? || settings.sp_entity_id.nil? || settings.sp_entity_id.empty?
616
+ return true if settings.sp_entity_id.nil? || settings.sp_entity_id.empty?
617
+
618
+ if audiences.empty?
619
+ return true unless settings.security[:strict_audience_validation]
620
+ return append_error("Invalid Audiences. The <AudienceRestriction> element contained only empty <Audience> elements. Expected audience #{settings.sp_entity_id}.")
621
+ end
617
622
 
618
623
  unless audiences.include? settings.sp_entity_id
619
624
  s = audiences.count > 1 ? 's' : '';
@@ -736,7 +741,7 @@ module OneLogin
736
741
  # @return [Boolean] True if the SessionNotOnOrAfter of the AuthnStatement is valid, otherwise (when expired) False if soft=True
737
742
  # @raise [ValidationError] if soft == false and validation fails
738
743
  #
739
- def validate_session_expiration(soft = true)
744
+ def validate_session_expiration
740
745
  return true if session_expires_at.nil?
741
746
 
742
747
  now = Time.now.utc
@@ -4,7 +4,6 @@ require 'base64'
4
4
  require 'nokogiri'
5
5
  require 'rexml/document'
6
6
  require 'rexml/xpath'
7
- require 'thread'
8
7
  require "onelogin/ruby-saml/error_handling"
9
8
 
10
9
  # Only supports SAML 2.0
@@ -69,14 +68,14 @@ module OneLogin
69
68
  xml = Nokogiri::XML(document.to_s) do |config|
70
69
  config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS
71
70
  end
72
- rescue Exception => error
71
+ rescue StandardError => error
73
72
  return false if soft
74
73
  raise ValidationError.new("XML load failed: #{error.message}")
75
74
  end
76
75
 
77
76
  SamlMessage.schema.validate(xml).map do |schema_error|
78
77
  return false if soft
79
- raise ValidationError.new("#{schema_error.message}\n\n#{xml.to_s}")
78
+ raise ValidationError.new("#{schema_error.message}\n\n#{xml}")
80
79
  end
81
80
  end
82
81
 
@@ -20,7 +20,7 @@ module OneLogin
20
20
  end
21
21
 
22
22
  config.each do |k,v|
23
- acc = "#{k.to_s}=".to_sym
23
+ acc = "#{k}=".to_sym
24
24
  if respond_to? acc
25
25
  value = v.is_a?(Hash) ? v.dup : v
26
26
  send(acc, value)
@@ -195,17 +195,13 @@ module OneLogin
195
195
 
196
196
  certs = {:signing => [], :encryption => [] }
197
197
 
198
- if idp_cert_multi.key?(:signing) and not idp_cert_multi[:signing].empty?
199
- idp_cert_multi[:signing].each do |idp_cert|
200
- formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
201
- certs[:signing].push(OpenSSL::X509::Certificate.new(formatted_cert))
202
- end
203
- end
198
+ [:signing, :encryption].each do |type|
199
+ certs_for_type = idp_cert_multi[type] || idp_cert_multi[type.to_s]
200
+ next if !certs_for_type || certs_for_type.empty?
204
201
 
205
- if idp_cert_multi.key?(:encryption) and not idp_cert_multi[:encryption].empty?
206
- idp_cert_multi[:encryption].each do |idp_cert|
202
+ certs_for_type.each do |idp_cert|
207
203
  formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
208
- certs[:encryption].push(OpenSSL::X509::Certificate.new(formatted_cert))
204
+ certs[type].push(OpenSSL::X509::Certificate.new(formatted_cert))
209
205
  end
210
206
  end
211
207
 
@@ -247,7 +243,6 @@ module OneLogin
247
243
  OpenSSL::PKey::RSA.new(formatted_private_key)
248
244
  end
249
245
 
250
- private
251
246
 
252
247
  def idp_binding_from_embed_sign
253
248
  security[:embed_sign] ? Utils::BINDINGS[:post] : Utils::BINDINGS[:redirect]
@@ -280,7 +275,9 @@ module OneLogin
280
275
  :digest_method => XMLSecurity::Document::SHA1,
281
276
  :signature_method => XMLSecurity::Document::RSA_SHA1,
282
277
  :check_idp_cert_expiration => false,
283
- :check_sp_cert_expiration => false
278
+ :check_sp_cert_expiration => false,
279
+ :strict_audience_validation => false,
280
+ :lowercase_url_encoding => false
284
281
  }.freeze
285
282
  }.freeze
286
283
  end
@@ -248,32 +248,8 @@ module OneLogin
248
248
  return true unless options.has_key? :get_params
249
249
  return true unless options[:get_params].has_key? 'Signature'
250
250
 
251
- # SAML specifies that the signature should be derived from a concatenation
252
- # of URI-encoded values _as sent by the IDP_:
253
- #
254
- # > Further, note that URL-encoding is not canonical; that is, there are multiple legal encodings for a given
255
- # > value. The relying party MUST therefore perform the verification step using the original URL-encoded
256
- # > values it received on the query string. It is not sufficient to re-encode the parameters after they have been
257
- # > processed by software because the resulting encoding may not match the signer's encoding.
258
- #
259
- # <http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf>
260
- #
261
- # If we don't have the original parts (for backward compatibility) required to correctly verify the signature,
262
- # then fabricate them by re-encoding the parsed URI parameters, and hope that we're lucky enough to use
263
- # the exact same URI-encoding as the IDP. (This is not the case if the IDP is ADFS!)
264
- options[:raw_get_params] ||= {}
265
- if options[:raw_get_params]['SAMLRequest'].nil? && !options[:get_params]['SAMLRequest'].nil?
266
- options[:raw_get_params]['SAMLRequest'] = CGI.escape(options[:get_params]['SAMLRequest'])
267
- end
268
- if options[:raw_get_params]['RelayState'].nil? && !options[:get_params]['RelayState'].nil?
269
- options[:raw_get_params]['RelayState'] = CGI.escape(options[:get_params]['RelayState'])
270
- end
271
- if options[:raw_get_params]['SigAlg'].nil? && !options[:get_params]['SigAlg'].nil?
272
- options[:raw_get_params]['SigAlg'] = CGI.escape(options[:get_params]['SigAlg'])
273
- end
251
+ options[:raw_get_params] = OneLogin::RubySaml::Utils.prepare_raw_get_params(options[:raw_get_params], options[:get_params], settings.security[:lowercase_url_encoding])
274
252
 
275
- # If we only received the raw version of SigAlg,
276
- # then parse it back into the decoded params hash for convenience.
277
253
  if options[:get_params]['SigAlg'].nil? && !options[:raw_get_params]['SigAlg'].nil?
278
254
  options[:get_params]['SigAlg'] = CGI.unescape(options[:raw_get_params]['SigAlg'])
279
255
  end
@@ -335,7 +311,6 @@ module OneLogin
335
311
 
336
312
  true
337
313
  end
338
-
339
314
  end
340
315
  end
341
316
  end
@@ -13,7 +13,7 @@ module OneLogin
13
13
  class SloLogoutresponse < SamlMessage
14
14
 
15
15
  # Logout Response ID
16
- attr_reader :uuid
16
+ attr_accessor :uuid
17
17
 
18
18
  # Initializes the Logout Response. A SloLogoutresponse Object that is an extension of the SamlMessage class.
19
19
  # Asigns an ID, a random uuid.
@@ -41,7 +41,7 @@ module OneLogin
41
41
  saml_response = CGI.escape(params.delete("SAMLResponse"))
42
42
  response_params = "#{params_prefix}SAMLResponse=#{saml_response}"
43
43
  params.each_pair do |key, value|
44
- response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
44
+ response_params << "&#{key}=#{CGI.escape(value.to_s)}"
45
45
  end
46
46
 
47
47
  raise SettingError.new "Invalid settings, idp_slo_service_url is not set!" if url.nil? or url.empty?
@@ -32,6 +32,7 @@ module OneLogin
32
32
  (\d+)W # 8: Weeks
33
33
  )
34
34
  $)x.freeze
35
+ UUID_PREFIX = '_'
35
36
 
36
37
  # Checks if the x509 cert provided is expired
37
38
  #
@@ -166,27 +167,36 @@ module OneLogin
166
167
  #
167
168
  # @param rawparams [Hash] Raw GET Parameters
168
169
  # @param params [Hash] GET Parameters
170
+ # @param lowercase_url_encoding [bool] Lowercase URL Encoding (For ADFS urlencode compatiblity)
169
171
  # @return [Hash] New raw parameters
170
172
  #
171
- def self.prepare_raw_get_params(rawparams, params)
173
+ def self.prepare_raw_get_params(rawparams, params, lowercase_url_encoding=false)
172
174
  rawparams ||= {}
173
175
 
174
176
  if rawparams['SAMLRequest'].nil? && !params['SAMLRequest'].nil?
175
- rawparams['SAMLRequest'] = CGI.escape(params['SAMLRequest'])
177
+ rawparams['SAMLRequest'] = escape_request_param(params['SAMLRequest'], lowercase_url_encoding)
176
178
  end
177
179
  if rawparams['SAMLResponse'].nil? && !params['SAMLResponse'].nil?
178
- rawparams['SAMLResponse'] = CGI.escape(params['SAMLResponse'])
180
+ rawparams['SAMLResponse'] = escape_request_param(params['SAMLResponse'], lowercase_url_encoding)
179
181
  end
180
182
  if rawparams['RelayState'].nil? && !params['RelayState'].nil?
181
- rawparams['RelayState'] = CGI.escape(params['RelayState'])
183
+ rawparams['RelayState'] = escape_request_param(params['RelayState'], lowercase_url_encoding)
182
184
  end
183
185
  if rawparams['SigAlg'].nil? && !params['SigAlg'].nil?
184
- rawparams['SigAlg'] = CGI.escape(params['SigAlg'])
186
+ rawparams['SigAlg'] = escape_request_param(params['SigAlg'], lowercase_url_encoding)
185
187
  end
186
188
 
187
189
  rawparams
188
190
  end
189
191
 
192
+ def self.escape_request_param(param, lowercase_url_encoding)
193
+ CGI.escape(param).tap do |escaped|
194
+ next unless lowercase_url_encoding
195
+
196
+ escaped.gsub!(/%[A-Fa-f0-9]{2}/) { |match| match.downcase }
197
+ end
198
+ end
199
+
190
200
  # Validate the Signature parameter sent on the HTTP-Redirect binding
191
201
  # @param params [Hash] Parameters to be used in the validation process
192
202
  # @option params [OpenSSL::X509::Certificate] cert The Identity provider public certtificate
@@ -333,8 +343,12 @@ module OneLogin
333
343
  end
334
344
  end
335
345
 
346
+ def self.set_prefix(value)
347
+ UUID_PREFIX.replace value
348
+ end
349
+
336
350
  def self.uuid
337
- RUBY_VERSION < '1.9' ? "_#{@@uuid_generator.generate}" : "_#{SecureRandom.uuid}"
351
+ "#{UUID_PREFIX}" + (RUBY_VERSION < '1.9' ? "#{@@uuid_generator.generate}" : "#{SecureRandom.uuid}")
338
352
  end
339
353
 
340
354
  # Given two strings, attempt to match them as URIs using Rails' parse method. If they can be parsed,
@@ -1,5 +1,5 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
- VERSION = '1.13.0'
3
+ VERSION = '1.15.0'
4
4
  end
5
5
  end
data/lib/xml_security.rb CHANGED
@@ -177,7 +177,7 @@ module XMLSecurity
177
177
 
178
178
  def compute_digest(document, digest_algorithm)
179
179
  digest = digest_algorithm.digest(document)
180
- Base64.encode64(digest).strip!
180
+ Base64.encode64(digest).strip
181
181
  end
182
182
 
183
183
  end
@@ -216,7 +216,7 @@ module XMLSecurity
216
216
  if options[:fingerprint_alg]
217
217
  fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(options[:fingerprint_alg]).new
218
218
  else
219
- fingerprint_alg = OpenSSL::Digest::SHA1.new
219
+ fingerprint_alg = OpenSSL::Digest.new('SHA1')
220
220
  end
221
221
  fingerprint = fingerprint_alg.hexdigest(cert.to_der)
222
222
 
data/ruby-saml.gemspec CHANGED
@@ -6,17 +6,17 @@ Gem::Specification.new do |s|
6
6
  s.version = OneLogin::RubySaml::VERSION
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
- s.authors = ["OneLogin LLC"]
9
+ s.authors = ["SAML Toolkit", "Sixto Martin"]
10
+ s.email = ['contact@iamdigitalservices.com', 'sixto.martin.garcia@gmail.com']
10
11
  s.date = Time.now.strftime("%Y-%m-%d")
11
- s.description = %q{SAML toolkit for Ruby on Rails}
12
- s.email = %q{support@onelogin.com}
12
+ s.description = %q{SAML Ruby toolkit. Add SAML support to your Ruby software using this library}
13
13
  s.license = 'MIT'
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
16
16
  "README.md"
17
17
  ]
18
18
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
- s.homepage = %q{https://github.com/onelogin/ruby-saml}
19
+ s.homepage = %q{https://github.com/saml-toolkit/ruby-saml}
20
20
  s.rdoc_options = ["--charset=UTF-8"]
21
21
  s.require_paths = ["lib"]
22
22
  s.rubygems_version = %q{1.3.7}
@@ -27,12 +27,18 @@ Gem::Specification.new do |s|
27
27
  # Nokogiri's version dependent on the Ruby version, even though we would
28
28
  # have liked to constrain Ruby 1.8.7 to install only the 1.5.x versions.
29
29
  if defined?(JRUBY_VERSION)
30
- if JRUBY_VERSION < '9.2.0.0'
30
+ if JRUBY_VERSION < '9.1.7.0'
31
31
  s.add_runtime_dependency('nokogiri', '>= 1.8.2', '<= 1.8.5')
32
32
  s.add_runtime_dependency('jruby-openssl', '>= 0.9.8')
33
33
  s.add_runtime_dependency('json', '< 2.3.0')
34
+ elsif JRUBY_VERSION < '9.2.0.0'
35
+ s.add_runtime_dependency('nokogiri', '>= 1.9.1', '< 1.10.0')
36
+ elsif JRUBY_VERSION < '9.3.2.0'
37
+ s.add_runtime_dependency('nokogiri', '>= 1.11.4')
38
+ s.add_runtime_dependency('rexml')
34
39
  else
35
- s.add_runtime_dependency('nokogiri', '>= 1.8.2')
40
+ s.add_runtime_dependency('nokogiri', '>= 1.13.10')
41
+ s.add_runtime_dependency('rexml')
36
42
  end
37
43
  elsif RUBY_VERSION < '1.9'
38
44
  s.add_runtime_dependency('uuid')
@@ -41,20 +47,42 @@ Gem::Specification.new do |s|
41
47
  s.add_runtime_dependency('nokogiri', '>= 1.5.10', '<= 1.6.8.1')
42
48
  s.add_runtime_dependency('json', '< 2.3.0')
43
49
  elsif RUBY_VERSION < '2.3'
44
- s.add_runtime_dependency('nokogiri', '>= 1.9.1', '<= 1.10.0')
50
+ s.add_runtime_dependency('nokogiri', '>= 1.9.1', '< 1.10.0')
51
+ elsif RUBY_VERSION < '2.5'
52
+ s.add_runtime_dependency('nokogiri', '>= 1.10.10', '< 1.11.0')
53
+ s.add_runtime_dependency('rexml')
54
+ elsif RUBY_VERSION < '2.6'
55
+ s.add_runtime_dependency('nokogiri', '>= 1.11.4')
56
+ s.add_runtime_dependency('rexml')
45
57
  else
46
- s.add_runtime_dependency('nokogiri', '>= 1.10.5')
58
+ s.add_runtime_dependency('nokogiri', '>= 1.13.10')
47
59
  s.add_runtime_dependency('rexml')
48
60
  end
49
61
 
50
- s.add_development_dependency('coveralls')
62
+ s.add_development_dependency('simplecov', '<0.22.0')
63
+ if RUBY_VERSION < '2.4.1'
64
+ s.add_development_dependency('simplecov-lcov', '<0.8.0')
65
+ else
66
+ s.add_development_dependency('simplecov-lcov', '>0.7.0')
67
+ end
68
+
51
69
  s.add_development_dependency('minitest', '~> 5.5')
52
70
  s.add_development_dependency('mocha', '~> 0.14')
53
- s.add_development_dependency('rake', '~> 10')
71
+
72
+ if RUBY_VERSION < '2.0'
73
+ s.add_development_dependency('rake', '~> 10')
74
+ else
75
+ s.add_development_dependency('rake', '>= 12.3.3')
76
+ end
77
+
54
78
  s.add_development_dependency('shoulda', '~> 2.11')
55
- s.add_development_dependency('simplecov')
56
79
  s.add_development_dependency('systemu', '~> 2')
57
- s.add_development_dependency('timecop', '<= 0.6.0')
80
+
81
+ if RUBY_VERSION < '2.1'
82
+ s.add_development_dependency('timecop', '<= 0.6.0')
83
+ else
84
+ s.add_development_dependency('timecop', '~> 0.9')
85
+ end
58
86
 
59
87
  if defined?(JRUBY_VERSION)
60
88
  # All recent versions of JRuby play well with pry
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-saml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.0
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
- - OneLogin LLC
8
- autorequire:
7
+ - SAML Toolkit
8
+ - Sixto Martin
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2021-09-06 00:00:00.000000000 Z
12
+ date: 2023-01-04 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: nokogiri
@@ -16,14 +17,14 @@ dependencies:
16
17
  requirements:
17
18
  - - ">="
18
19
  - !ruby/object:Gem::Version
19
- version: 1.10.5
20
+ version: 1.13.10
20
21
  type: :runtime
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - ">="
25
26
  - !ruby/object:Gem::Version
26
- version: 1.10.5
27
+ version: 1.13.10
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: rexml
29
30
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +40,33 @@ dependencies:
39
40
  - !ruby/object:Gem::Version
40
41
  version: '0'
41
42
  - !ruby/object:Gem::Dependency
42
- name: coveralls
43
+ name: simplecov
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
- - - ">="
46
+ - - "<"
46
47
  - !ruby/object:Gem::Version
47
- version: '0'
48
+ version: 0.22.0
48
49
  type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
- - - ">="
53
+ - - "<"
53
54
  - !ruby/object:Gem::Version
54
- version: '0'
55
+ version: 0.22.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: simplecov-lcov
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.7.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">"
68
+ - !ruby/object:Gem::Version
69
+ version: 0.7.0
55
70
  - !ruby/object:Gem::Dependency
56
71
  name: minitest
57
72
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +99,16 @@ dependencies:
84
99
  name: rake
85
100
  requirement: !ruby/object:Gem::Requirement
86
101
  requirements:
87
- - - "~>"
102
+ - - ">="
88
103
  - !ruby/object:Gem::Version
89
- version: '10'
104
+ version: 12.3.3
90
105
  type: :development
91
106
  prerelease: false
92
107
  version_requirements: !ruby/object:Gem::Requirement
93
108
  requirements:
94
- - - "~>"
109
+ - - ">="
95
110
  - !ruby/object:Gem::Version
96
- version: '10'
111
+ version: 12.3.3
97
112
  - !ruby/object:Gem::Dependency
98
113
  name: shoulda
99
114
  requirement: !ruby/object:Gem::Requirement
@@ -108,20 +123,6 @@ dependencies:
108
123
  - - "~>"
109
124
  - !ruby/object:Gem::Version
110
125
  version: '2.11'
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
126
  - !ruby/object:Gem::Dependency
126
127
  name: systemu
127
128
  requirement: !ruby/object:Gem::Requirement
@@ -140,16 +141,16 @@ dependencies:
140
141
  name: timecop
141
142
  requirement: !ruby/object:Gem::Requirement
142
143
  requirements:
143
- - - "<="
144
+ - - "~>"
144
145
  - !ruby/object:Gem::Version
145
- version: 0.6.0
146
+ version: '0.9'
146
147
  type: :development
147
148
  prerelease: false
148
149
  version_requirements: !ruby/object:Gem::Requirement
149
150
  requirements:
150
- - - "<="
151
+ - - "~>"
151
152
  - !ruby/object:Gem::Version
152
- version: 0.6.0
153
+ version: '0.9'
153
154
  - !ruby/object:Gem::Dependency
154
155
  name: pry-byebug
155
156
  requirement: !ruby/object:Gem::Requirement
@@ -164,8 +165,11 @@ dependencies:
164
165
  - - ">="
165
166
  - !ruby/object:Gem::Version
166
167
  version: '0'
167
- description: SAML toolkit for Ruby on Rails
168
- email: support@onelogin.com
168
+ description: SAML Ruby toolkit. Add SAML support to your Ruby software using this
169
+ library
170
+ email:
171
+ - contact@iamdigitalservices.com
172
+ - sixto.martin.garcia@gmail.com
169
173
  executables: []
170
174
  extensions: []
171
175
  extra_rdoc_files:
@@ -217,11 +221,11 @@ files:
217
221
  - lib/schemas/xmldsig-core-schema.xsd
218
222
  - lib/xml_security.rb
219
223
  - ruby-saml.gemspec
220
- homepage: https://github.com/onelogin/ruby-saml
224
+ homepage: https://github.com/saml-toolkit/ruby-saml
221
225
  licenses:
222
226
  - MIT
223
227
  metadata: {}
224
- post_install_message:
228
+ post_install_message:
225
229
  rdoc_options:
226
230
  - "--charset=UTF-8"
227
231
  require_paths:
@@ -237,9 +241,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
241
  - !ruby/object:Gem::Version
238
242
  version: '0'
239
243
  requirements: []
240
- rubyforge_project:
241
- rubygems_version: 2.5.2.1
242
- signing_key:
244
+ rubygems_version: 3.3.26
245
+ signing_key:
243
246
  specification_version: 4
244
247
  summary: SAML Ruby Tookit
245
248
  test_files: []