ruby-saml 1.13.0 → 1.17.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: 188af740c1b9627be73d3a4cbd8261316773d3b3da0b74b0ef49b5d1c9c04f02
4
+ data.tar.gz: 85cb561ba597924b7037be197dac6fd175c1a626969829e170bb44d8e8a1a50d
5
5
  SHA512:
6
- metadata.gz: 957e2b7598309e9b770019902f28bdec07a28a19a77abfb7e72d503ab3c8b4c57138451d3bb0bced671aca4d454d6637821a3931e91e6f4d79ef4d5d1a91a25e
7
- data.tar.gz: 74d06dcdc7ba3f3c0dc797ad3e329987f0bd32bfc5b0bdee62f9c081688dd97bb4892ef42de795c09c59b2c48487b673476a6dd12aedca0770b600c770e2c4b7
6
+ metadata.gz: 0b154ce0a94f1f1b525179d33f8a98d5422cabafe527f32104646135ae0a9218064638639b7ec5735de1dda8ef55faa5571f22f563d57f44e040a81b6116b5a1
7
+ data.tar.gz: 78ea0021299530423e28935782b851894ed9740c1e93c610575518532d22bcc20829dbe26b0569f38ad21894cc145b3d785c75765c8bd0dde6e078598d864545
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [SAML-Toolkits]
@@ -8,11 +8,57 @@ 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:
12
+ - ubuntu-20.04
13
+ - macos-latest
14
+ - windows-latest
15
+ ruby-version:
16
+ - 2.1
17
+ - 2.2
18
+ - 2.3
19
+ - 2.4
20
+ - 2.5
21
+ - 2.6
22
+ - 2.7
23
+ - 3.0
24
+ - 3.1
25
+ - 3.2
26
+ - 3.3
27
+ - jruby-9.1
28
+ - jruby-9.2
29
+ - jruby-9.3
30
+ - jruby-9.4
31
+ - truffleruby
32
+ exclude:
33
+ - os: macos-latest
34
+ ruby-version: 2.1
35
+ - os: macos-latest
36
+ ruby-version: 2.2
37
+ - os: macos-latest
38
+ ruby-version: 2.3
39
+ - os: macos-latest
40
+ ruby-version: 2.4
41
+ - os: macos-latest
42
+ ruby-version: 2.5
43
+ - os: macos-latest
44
+ ruby-version: jruby-9.1
45
+ - os: macos-latest
46
+ ruby-version: jruby-9.2
47
+ - os: windows-latest
48
+ ruby-version: 2.1
49
+ - os: windows-latest
50
+ ruby-version: jruby-9.1
51
+ - os: windows-latest
52
+ ruby-version: jruby-9.2
53
+ - os: windows-latest
54
+ ruby-version: jruby-9.3
55
+ - os: windows-latest
56
+ ruby-version: jruby-9.4
57
+ - os: windows-latest
58
+ ruby-version: truffleruby
13
59
  runs-on: ${{ matrix.os }}
14
60
  steps:
15
- - uses: actions/checkout@v2
61
+ - uses: actions/checkout@v4
16
62
  - name: Set up Ruby ${{ matrix.ruby-version }}
17
63
  uses: ruby/setup-ruby@v1
18
64
  with:
@@ -23,3 +69,21 @@ jobs:
23
69
 
24
70
  - name: Run tests
25
71
  run: bundle exec rake
72
+
73
+ - name: Coveralls
74
+ uses: coverallsapp/github-action@master
75
+ with:
76
+ github-token: ${{ secrets.github_token }}
77
+ parallel: true
78
+ flag-name: run-${{ matrix.ruby-version }}
79
+
80
+ finish:
81
+ needs: test
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - name: Coveralls Finished
85
+ uses: coverallsapp/github-action@master
86
+ with:
87
+ github-token: ${{ secrets.github_token }}
88
+ flag-name: run-${{ matrix.ruby-version }}
89
+ parallel-finished: true
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Ruby SAML Changelog
2
2
 
3
+ ### 1.17.0 (Sep 10, 2024)
4
+ * Fix for critical vulnerability CVE-2024-45409: SAML authentication bypass via Incorrect XPath selector
5
+ * [#687](https://github.com/SAML-Toolkits/ruby-saml/pull/687) Add CI coverage for Ruby 3.3 and Windows.
6
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) Add `Settings#sp_cert_multi` paramter to facilitate SP certificate and key rotation.
7
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) Support multiple simultaneous SP decryption keys via `Settings#sp_cert_multi` parameter.
8
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) Deprecate `Settings#certificate_new` parameter.
9
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) `:check_sp_cert_expiration` will use the first non-expired certificate/key when signing/decrypting. It will raise an error only if there are no valid certificates/keys.
10
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) `:check_sp_cert_expiration` now validates the certificate `not_before` condition; previously it was only validating `not_after`.
11
+ * [#673](https://github.com/SAML-Toolkits/ruby-saml/pull/673) `:check_sp_cert_expiration` now causes the generated SP metadata to exclude any inactive/expired certificates.
12
+
13
+ ### 1.16.0 (Oct 09, 2023)
14
+ * [#671](https://github.com/SAML-Toolkits/ruby-saml/pull/671) Add support on LogoutRequest with Encrypted NameID
15
+
16
+ ### 1.15.0 (Jan 04, 2023)
17
+ * [#650](https://github.com/SAML-Toolkits/ruby-saml/pull/650) Replace strip! by strip on compute_digest method
18
+ * [#638](https://github.com/SAML-Toolkits/ruby-saml/pull/638) Fix dateTime format for the validUntil attribute of the generated metadata
19
+ * [#576](https://github.com/SAML-Toolkits/ruby-saml/pull/576) Support `Settings#idp_cert_multi` with string keys
20
+ * [#567](https://github.com/SAML-Toolkits/ruby-saml/pull/567) Improve Code quality
21
+ * Add info about new repo, new maintainer, new security contact
22
+ * Fix tests, Adjust dependencies, Add ruby 3.2 and new jruby versions tests to the CI. Add coveralls support
23
+
24
+ ### 1.14.0 (Feb 01, 2022)
25
+ * [#627](https://github.com/onelogin/ruby-saml/pull/627) Support escape downcasing for validating SLO Signatures of ADFS/Azure
26
+ * [#633](https://github.com/onelogin/ruby-saml/pull/633) Support ability to change ID prefix
27
+ * Make the uuid editable on the SAML Messages generated by the toolkit
28
+ * [#622](https://github.com/onelogin/ruby-saml/pull/622) Add security setting to more strictly enforce audience validation
29
+
3
30
  ### 1.13.0 (Sept 06, 2021)
4
31
  * [#611](https://github.com/onelogin/ruby-saml/pull/601) Replace MAX_BYTE_SIZE constant with setting: message_max_bytesize
5
32
  * [#605](https://github.com/onelogin/ruby-saml/pull/605) :allowed_clock_drift is now bidrectional
@@ -13,6 +40,9 @@
13
40
  * Add warning about the use of IdpMetadataParser class and SSRF
14
41
  * CI: Migrate from Travis to Github Actions
15
42
 
43
+ ### 1.12.3 (Sep 10, 2024)
44
+ * Fix for critical vulnerability CVE-2024-45409: SAML authentication bypass via Incorrect XPath selector
45
+
16
46
  ### 1.12.2 (Apr 08, 2021)
17
47
  * [#575](https://github.com/onelogin/ruby-saml/pull/575) Fix SloLogoutresponse bug on LogoutRequest
18
48
 
@@ -34,7 +64,7 @@
34
64
  * Support Process Transform
35
65
  * Raise SettingError if invoking an action with no endpoint defined on the settings
36
66
  * Made IdpMetadataParser more extensible for subclasses
37
- *[#548](https://github.com/onelogin/ruby-saml/pull/548) Add :skip_audience option
67
+ * [#548](https://github.com/onelogin/ruby-saml/pull/548) Add :skip_audience option
38
68
  * [#555](https://github.com/onelogin/ruby-saml/pull/555) Define 'soft' variable to prevent exception when doc cert is invalid
39
69
  * Improve documentation
40
70
 
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
@@ -1,10 +1,14 @@
1
1
  # Ruby SAML
2
- [![Build Status](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml/badge.svg?query=branch%3Amaster)](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml?query=branch%3Amaster)
3
- [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master)](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
2
+ [![ruby-saml CI](https://github.com/SAML-Toolkits/ruby-saml/actions/workflows/test.yml/badge.svg)](https://github.com/SAML-Toolkits/ruby-saml/actions/workflows/test.yml)
3
+ [![Coverage Status](https://coveralls.io/repos/github/SAML-Toolkits/ruby-saml/badge.svg?branch=master)](https://coveralls.io/github/SAML-Toolkits/ruby-saml?branch=master)
4
+ [![Rubygem Version](https://badge.fury.io/rb/ruby-saml.svg)](https://badge.fury.io/rb/ruby-saml)
5
+ [![GitHub version](https://badge.fury.io/gh/SAML-Toolkits%2Fruby-saml.svg)](https://badge.fury.io/gh/SAML-Toolkits%2Fruby-saml) ![GitHub](https://img.shields.io/github/license/SAML-Toolkits/ruby-saml) ![Gem](https://img.shields.io/gem/dtv/ruby-saml?label=gem%20downloads%20latest) ![Gem](https://img.shields.io/gem/dt/ruby-saml?label=gem%20total%20downloads)
4
6
 
5
7
  Ruby SAML minor and tiny versions may introduce breaking changes. Please read
6
8
  [UPGRADING.md](UPGRADING.md) for guidance on upgrading to new Ruby SAML versions.
7
9
 
10
+ There is a critical vulnerability affecting ruby-saml < 1.17.0 (CVE-2024-45409). Make sure you are using an updated version. (1.12.3 is safe)
11
+
8
12
  ## Overview
9
13
 
10
14
  The Ruby SAML library is for implementing the client side of a SAML authorization,
@@ -14,32 +18,16 @@ requests from identity providers.
14
18
  SAML authorization is a two step process and you are expected to implement support for both.
15
19
 
16
20
  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)
21
+ [ruby-saml-example](https://github.com/saml-toolkits/ruby-saml-example)
18
22
 
19
23
  ### Supported Ruby Versions
20
24
 
21
25
  The following Ruby versions are covered by CI testing:
22
26
 
23
- * 2.1.x
24
- * 2.2.x
25
- * 2.3.x
26
- * 2.4.x
27
- * 2.5.x
28
- * 2.6.x
29
- * 2.7.x
30
- * 3.0.x
31
- * JRuby 9.1.x
32
- * JRuby 9.2.x
27
+ * Ruby (MRI) 2.1 to 3.3
28
+ * JRuby 9.1 to 9.4
33
29
  * TruffleRuby (latest)
34
30
 
35
- In addition, the following may work but are untested:
36
-
37
- * 1.8.7
38
- * 1.9.x
39
- * 2.0.x
40
- * JRuby 1.7.x
41
- * JRuby 9.0.x
42
-
43
31
  ## Adding Features, Pull Requests
44
32
 
45
33
  * Fork the repository
@@ -52,8 +40,7 @@ In addition, the following may work but are untested:
52
40
  ## Security Guidelines
53
41
 
54
42
  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.
43
+ by mail to the maintainer: sixto.martin.garcia+security@gmail.com
57
44
 
58
45
  ### Security Warning
59
46
 
@@ -66,7 +53,7 @@ However, ruby-saml never enables this dangerous Nokogiri configuration;
66
53
  ruby-saml never enables DTDLOAD, and it never disables NONET.
67
54
 
68
55
  The OneLogin::RubySaml::IdpMetadataParser class does not validate in any way the URL
69
- that is introduced in order to be parsed.
56
+ that is introduced in order to be parsed.
70
57
 
71
58
  Usually the same administrator that handles the Service Provider also sets the URL to
72
59
  the IdP, which should be a trusted resource.
@@ -87,7 +74,7 @@ Using `Gemfile`
87
74
  gem 'ruby-saml', '~> 1.11.0'
88
75
 
89
76
  # or track master for bleeding-edge
90
- gem 'ruby-saml', :github => 'onelogin/ruby-saml'
77
+ gem 'ruby-saml', :github => 'saml-toolkit/ruby-saml'
91
78
  ```
92
79
 
93
80
  Using RubyGems
@@ -386,12 +373,78 @@ IdpMetadataParser by its Entity Id value:
386
373
  )
387
374
  ```
388
375
 
376
+ ### Retrieve one Entity Descriptor with an specific binding and nameid format when several are available
377
+
378
+ If the Metadata contains several bindings and nameids, the relevant ones
379
+ also can be specified when retrieving the settings from the IdpMetadataParser
380
+ by the values of binding and nameid:
381
+
382
+ ```ruby
383
+ validate_cert = true
384
+ options = {
385
+ entity_id: "http//example.com/target/entity",
386
+ name_id_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
387
+ sso_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
388
+ slo_binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
389
+ }
390
+ settings = idp_metadata_parser.parse_remote(
391
+ "https://example.com/auth/saml2/idp/metadata",
392
+ validate_cert,
393
+ options
394
+ )
395
+ ```
396
+
389
397
  ### Parsing Metadata into an Hash
390
398
 
391
399
  The `OneLogin::RubySaml::IdpMetadataParser` also provides the methods `#parse_to_hash` and `#parse_remote_to_hash`.
392
400
  Those return an Hash instead of a `Settings` object, which may be useful for configuring
393
401
  [omniauth-saml](https://github.com/omniauth/omniauth-saml), for instance.
394
402
 
403
+
404
+ ### Validating Signature of Metadata and retrieve settings
405
+
406
+ Right now there is no method at ruby_saml to validate the signature of the metadata that gonna be parsed,
407
+ but it can be done as follows:
408
+ * Download the XML.
409
+ * Validate the Signature, providing the cert.
410
+ * Provide the XML to the parse method if the signature was validated
411
+
412
+ ```ruby
413
+ require "xml_security"
414
+ require "onelogin/ruby-saml/utils"
415
+ require "onelogin/ruby-saml/idp_metadata_parser"
416
+
417
+ url = "<url_to_the_metadata>"
418
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
419
+
420
+ uri = URI.parse(url)
421
+ raise ArgumentError.new("url must begin with http or https") unless /^https?/ =~ uri.scheme
422
+ http = Net::HTTP.new(uri.host, uri.port)
423
+ if uri.scheme == "https"
424
+ http.use_ssl = true
425
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
426
+ end
427
+
428
+ get = Net::HTTP::Get.new(uri.request_uri)
429
+ get.basic_auth uri.user, uri.password if uri.user
430
+ response = http.request(get)
431
+ xml = response.body
432
+ errors = []
433
+ doc = XMLSecurity::SignedDocument.new(xml, errors)
434
+ cert_str = "<include_cert_here>"
435
+ cert = OneLogin::RubySaml::Utils.format_cert("cert_str")
436
+ metadata_sign_cert = OpenSSL::X509::Certificate.new(cert)
437
+ valid = doc.validate_document_with_cert(metadata_sign_cert, true)
438
+ if valid
439
+ settings = idp_metadata_parser.parse(
440
+ xml,
441
+ entity_id: "<entity_id_of_the_entity_to_be_retrieved>"
442
+ )
443
+ else
444
+ print "Metadata Signarture failed to be verified with the cert provided"
445
+ end
446
+ ```
447
+
395
448
  ## Retrieving Attributes
396
449
 
397
450
  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
@@ -627,7 +680,7 @@ signature validation process will fail at the Identity Provider.
627
680
  Ruby SAML supports EncryptedAssertion. The Identity Provider will encrypt the Assertion with the
628
681
  public cert of the Service Provider. The Service Provider will decrypt the EncryptedAssertion with its private key.
629
682
 
630
- You may enable EncryptedAssertion as follows. This will add `<md:KeyDescriptor use="encrytion">` to your
683
+ You may enable EncryptedAssertion as follows. This will add `<md:KeyDescriptor use="encryption">` to your
631
684
  SP Metadata XML, to be read by the IdP.
632
685
 
633
686
  ```ruby
@@ -664,27 +717,69 @@ validation fails. You may disable such exceptions using the `settings.security[:
664
717
  settings.security[:soft] = true # Do not raise error on failed signature/certificate validations
665
718
  ```
666
719
 
667
- #### Key Rollover
720
+ #### Advanced SP Certificate Usage & Key Rollover
668
721
 
669
- To update the SP X.509 certificate and private key without disruption of service, you may define the parameter
670
- `settings.certificate_new`. This will publish the new SP certificate in your metadata so that your IdP counterparties
671
- may cache it in preparation for rollover.
722
+ Ruby SAML provides the `settings.sp_cert_multi` parameter to enable the following
723
+ advanced usage scenarios:
724
+ - Rotating SP certificates and private keys without disruption of service.
725
+ - Specifying separate SP certificates for signing and encryption.
672
726
 
673
- For example, if you to rollover from `CERT A` to `CERT B`. Before rollover, your settings should look as follows.
674
- Both `CERT A` and `CERT B` will now appear in your SP metadata, however `CERT A` will still be used for signing
675
- and encryption at this time.
727
+ The `sp_cert_multi` parameter replaces `certificate` and `private_key`
728
+ (you may not specify both pparameters at the same time.) `sp_cert_multi` has the following shape:
676
729
 
677
730
  ```ruby
678
- settings.certificate = "CERT A"
679
- settings.private_key = "PRIVATE KEY FOR CERT A"
680
- settings.certificate_new = "CERT B"
731
+ settings.sp_cert_multi = {
732
+ signing: [
733
+ { certificate: cert1, private_key: private_key1 },
734
+ { certificate: cert2, private_key: private_key2 }
735
+ ],
736
+ encryption: [
737
+ { certificate: cert1, private_key: private_key1 },
738
+ { certificate: cert3, private_key: private_key1 }
739
+ ],
740
+ }
681
741
  ```
682
742
 
683
- After the IdP has cached `CERT B`, you may then change your settings as follows:
743
+ Certificate rotation is acheived by inserting new certificates at the bottom of each list,
744
+ and then removing the old certificates from the top of the list once your IdPs have migrated.
745
+ A common practice is for apps to publish the current SP metadata at a URL endpoint and have
746
+ the IdP regularly poll for updates.
747
+
748
+ Note the following:
749
+ - You may re-use the same certificate and/or private key in multiple places, including for both signing and encryption.
750
+ - The IdP should attempt to verify signatures with *all* `:signing` certificates,
751
+ and permit if *any one* succeeds. When signing, Ruby SAML will use the first SP certificate
752
+ in the `sp_cert_multi[:signing]` array. This will be the first active/non-expired certificate
753
+ in the array if `settings.security[:check_sp_cert_expiration]` is true.
754
+ - The IdP may encrypt with any of the SP certificates in the `sp_cert_multi[:encryption]`
755
+ array. When decrypting, Ruby SAML attempt to decrypt with each SP private key in
756
+ `sp_cert_multi[:encryption]` until the decryption is successful. This will skip private
757
+ keys for inactive/expired certificates if `:check_sp_cert_expiration` is true.
758
+ - If `:check_sp_cert_expiration` is true, the generated SP metadata XML will not include
759
+ inactive/expired certificates. This avoids validation errors when the IdP reads the SP
760
+ metadata.
761
+
762
+ #### Audience Validation
763
+
764
+ A service provider should only consider a SAML response valid if the IdP includes an <AudienceRestriction>
765
+ element containting an <Audience> element that uniquely identifies the service provider. Unless you specify
766
+ the `skip_audience` option, Ruby SAML will validate that each SAML response includes an <Audience> element
767
+ whose contents matches `settings.sp_entity_id`.
768
+
769
+ By default, Ruby SAML considers an <AudienceRestriction> element containing only empty <Audience> elements
770
+ to be valid. That means an otherwise valid SAML response with a condition like this would be valid:
771
+
772
+ ```xml
773
+ <AudienceRestriction>
774
+ <Audience />
775
+ </AudienceRestriction>
776
+ ```
777
+
778
+ You may enforce that an <AudienceRestriction> element containing only empty <Audience> elements
779
+ is invalid using the `settings.security[:strict_audience_validation]` parameter.
684
780
 
685
781
  ```ruby
686
- settings.certificate = "CERT B"
687
- settings.private_key = "PRIVATE KEY FOR CERT B"
782
+ settings.security[:strict_audience_validation] = true
688
783
  ```
689
784
 
690
785
  ## Single Log Out
@@ -767,7 +862,13 @@ Here is an example that we could add to our previous controller to process a SAM
767
862
  # Method to handle IdP initiated logouts
768
863
  def idp_logout_request
769
864
  settings = Account.get_saml_settings
770
- logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
865
+ # ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses
866
+ # uppercase. Turn it True for ADFS compatibility on signature verification
867
+ settings.security[:lowercase_url_encoding] = true
868
+
869
+ logout_request = OneLogin::RubySaml::SloLogoutrequest.new(
870
+ params[:SAMLRequest], settings: settings
871
+ )
771
872
  if !logout_request.is_valid?
772
873
  logger.error "IdP initiated LogoutRequest was not valid!"
773
874
  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
@@ -72,9 +72,10 @@ module OneLogin
72
72
  request = deflate(request) if settings.compress_request
73
73
  base64_request = encode(request)
74
74
  request_params = {"SAMLRequest" => base64_request}
75
+ sp_signing_key = settings.get_sp_signing_key
75
76
 
76
- if settings.idp_sso_service_binding == Utils::BINDINGS[:redirect] && settings.security[:authn_requests_signed] && settings.private_key
77
- params['SigAlg'] = settings.security[:signature_method]
77
+ if settings.idp_sso_service_binding == Utils::BINDINGS[:redirect] && settings.security[:authn_requests_signed] && sp_signing_key
78
+ params['SigAlg'] = settings.security[:signature_method]
78
79
  url_string = OneLogin::RubySaml::Utils.build_query(
79
80
  :type => 'SAMLRequest',
80
81
  :data => base64_request,
@@ -82,7 +83,7 @@ module OneLogin
82
83
  :sig_alg => params['SigAlg']
83
84
  )
84
85
  sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
85
- signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
86
+ signature = sp_signing_key.sign(sign_algorithm.new, url_string)
86
87
  params['Signature'] = encode(signature)
87
88
  end
88
89
 
@@ -179,15 +180,13 @@ module OneLogin
179
180
  end
180
181
 
181
182
  def sign_document(document, settings)
182
- if settings.idp_sso_service_binding == Utils::BINDINGS[:post] && settings.security[:authn_requests_signed] && settings.private_key && settings.certificate
183
- private_key = settings.get_sp_key
184
- cert = settings.get_sp_cert
183
+ cert, private_key = settings.get_sp_signing_pair
184
+ if settings.idp_sso_service_binding == Utils::BINDINGS[:post] && settings.security[:authn_requests_signed] && private_key && cert
185
185
  document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
186
186
  end
187
187
 
188
188
  document
189
189
  end
190
-
191
190
  end
192
191
  end
193
192
  end
@@ -186,8 +186,6 @@ module OneLogin
186
186
  idpsso_descriptors.map {|id| IdpMetadata.new(id, id.parent.attributes["entityID"])}
187
187
  end
188
188
 
189
- private
190
-
191
189
  # Retrieve the remote IdP metadata from the URL or a cached copy.
192
190
  # @param url [String] Url where the XML of the Identity Provider Metadata is published.
193
191
  # @param validate_cert [Boolean] If true and the URL is HTTPs, the cert of the domain is checked.
@@ -220,6 +218,8 @@ module OneLogin
220
218
  )
221
219
  end
222
220
 
221
+ private
222
+
223
223
  class IdpMetadata
224
224
  attr_reader :idpsso_descriptor, :entity_id
225
225
 
@@ -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
@@ -69,8 +69,9 @@ module OneLogin
69
69
  request = deflate(request) if settings.compress_request
70
70
  base64_request = encode(request)
71
71
  request_params = {"SAMLRequest" => base64_request}
72
+ sp_signing_key = settings.get_sp_signing_key
72
73
 
73
- if settings.idp_slo_service_binding == Utils::BINDINGS[:redirect] && settings.security[:logout_requests_signed] && settings.private_key
74
+ if settings.idp_slo_service_binding == Utils::BINDINGS[:redirect] && settings.security[:logout_requests_signed] && sp_signing_key
74
75
  params['SigAlg'] = settings.security[:signature_method]
75
76
  url_string = OneLogin::RubySaml::Utils.build_query(
76
77
  :type => 'SAMLRequest',
@@ -79,7 +80,7 @@ module OneLogin
79
80
  :sig_alg => params['SigAlg']
80
81
  )
81
82
  sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
82
- signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
83
+ signature = settings.get_sp_signing_key.sign(sign_algorithm.new, url_string)
83
84
  params['Signature'] = encode(signature)
84
85
  end
85
86
 
@@ -138,9 +139,8 @@ module OneLogin
138
139
 
139
140
  def sign_document(document, settings)
140
141
  # embed signature
141
- if settings.idp_slo_service_binding == Utils::BINDINGS[:post] && settings.security[:logout_requests_signed] && settings.private_key && settings.certificate
142
- private_key = settings.get_sp_key
143
- cert = settings.get_sp_cert
142
+ cert, private_key = settings.get_sp_signing_pair
143
+ if settings.idp_slo_service_binding == Utils::BINDINGS[:post] && settings.security[:logout_requests_signed] && private_key && cert
144
144
  document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
145
145
  end
146
146
 
@@ -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
@@ -62,29 +62,14 @@ module OneLogin
62
62
  }
63
63
  end
64
64
 
65
- # Add KeyDescriptor if messages will be signed / encrypted
66
- # with SP certificate, and new SP certificate if any
65
+ # Add KeyDescriptor elements for SP certificates.
67
66
  def add_sp_certificates(sp_sso, settings)
68
- cert = settings.get_sp_cert
69
- cert_new = settings.get_sp_cert_new
70
-
71
- for sp_cert in [cert, cert_new]
72
- if sp_cert
73
- cert_text = Base64.encode64(sp_cert.to_der).gsub("\n", '')
74
- kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
75
- ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
76
- xd = ki.add_element "ds:X509Data"
77
- xc = xd.add_element "ds:X509Certificate"
78
- xc.text = cert_text
79
-
80
- if settings.security[:want_assertions_encrypted]
81
- kd2 = sp_sso.add_element "md:KeyDescriptor", { "use" => "encryption" }
82
- ki2 = kd2.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
83
- xd2 = ki2.add_element "ds:X509Data"
84
- xc2 = xd2.add_element "ds:X509Certificate"
85
- xc2.text = cert_text
86
- end
87
- end
67
+ certs = settings.get_sp_certs
68
+
69
+ certs[:signing].each { |cert, _| add_sp_cert_element(sp_sso, cert, :signing) }
70
+
71
+ if settings.security[:want_assertions_encrypted]
72
+ certs[:encryption].each { |cert, _| add_sp_cert_element(sp_sso, cert, :encryption) }
88
73
  end
89
74
 
90
75
  sp_sso
@@ -153,8 +138,7 @@ module OneLogin
153
138
  def embed_signature(meta_doc, settings)
154
139
  return unless settings.security[:metadata_signed]
155
140
 
156
- private_key = settings.get_sp_key
157
- cert = settings.get_sp_cert
141
+ cert, private_key = settings.get_sp_signing_pair
158
142
  return unless private_key && cert
159
143
 
160
144
  meta_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
@@ -172,6 +156,18 @@ module OneLogin
172
156
 
173
157
  ret
174
158
  end
159
+
160
+ private
161
+
162
+ def add_sp_cert_element(sp_sso, cert, use)
163
+ return unless cert
164
+ cert_text = Base64.encode64(cert.to_der).gsub("\n", '')
165
+ kd = sp_sso.add_element "md:KeyDescriptor", { "use" => use.to_s }
166
+ ki = kd.add_element "ds:KeyInfo", { "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#" }
167
+ xd = ki.add_element "ds:X509Data"
168
+ xc = xd.add_element "ds:X509Certificate"
169
+ xc.text = cert_text
170
+ end
175
171
  end
176
172
  end
177
173
  end