You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Minor and patch versions of Ruby SAML may introduce breaking changes. Please read
8
8
[UPGRADING.md](UPGRADING.md) for guidance on upgrading to new Ruby SAML versions.
9
9
10
-
### Pay it Forward: Support RubySAML and Strengthen Open-Source Security
11
10
12
-
RubySAML is a trusted authentication library used by startups and enterprises alike.
11
+
## Vulnerability Notice
13
12
14
-
But security doesn't happen in a vacuum. Vulnerabilities in authentication libraries can
15
-
have widespread consequences. Maintaining open-source security requires continuous
16
-
effort, expertise, and funding. By supporting RubySAML, you’re not just securing your
17
-
own systems—you’re strengthening auth security globally.
13
+
CVE-2025-54572 affects version ruby-saml < 1.18.1
18
14
19
-
#### How you can help
15
+
There are critical vulnerabilities affecting ruby-saml < 1.18.0, two of them allows SAML authentication bypass (CVE-2025-25291, CVE-2025-25292, CVE-2025-25293). Please upgrade to a fixed version (1.18.0)
There are critical vulnerabilities affecting ruby-saml < 1.18.0, two of them allows SAML authentication bypass (CVE-2025-25291, CVE-2025-25292, CVE-2025-25293). Please upgrade to a fixed version (1.18.0)
41
-
42
29
## Overview
43
30
44
31
The Ruby SAML library is for implementing the client side of a SAML authorization,
@@ -50,6 +37,22 @@ SAML authorization is a two-step process and you are expected to implement suppo
50
37
We created a demo project for Rails 4 that uses the latest version of this library:
-**Validation of the IdP Metadata URL:** When loading IdP Metadata from a URLs,
44
+
Ruby SAML requires you (the developer/administrator) to ensure the supplied URL is correct
45
+
and from a trusted source. Ruby SAML does not perform any validation that the URL
46
+
you entered is correct and/or safe.
47
+
-**False-Positive Security Warnings:** Some tools may incorrectly report Ruby SAML as a
48
+
potential security vulnerability, due to its dependency on Nokogiri. Such warnings can
49
+
be ignored; Ruby SAML uses Nokogiri in a safe way, by always disabling its DTDLOAD option
50
+
and enabling its NONET option.
51
+
-**Prevent Replay attacks:** A replay attack is when an attacker intercepts a valid SAML
52
+
assertion and "replays" it at a later time to gain unauthorized access. The `ruby-saml`
53
+
library provides the tools to prevent this, but **you, the developer, must implement thecore logic**, see an specific section later in the README.
54
+
55
+
53
56
### Supported Ruby Versions
54
57
55
58
The following Ruby versions are covered by CI testing:
@@ -58,38 +61,6 @@ The following Ruby versions are covered by CI testing:
58
61
* JRuby 9.1 to 9.4
59
62
* TruffleRuby (latest)
60
63
61
-
## Adding Features, Pull Requests
62
-
63
-
* Fork the repository
64
-
* Make your feature addition or bug fix
65
-
* Add tests for your new features. This is important so we don't break any features in a future version unintentionally.
66
-
* Ensure all tests pass by running `bundle exec rake test`.
67
-
* Do not change Rakefile, version, or history.
68
-
* Open a pull request, following [this template](https://gist.github.com/Lordnibbler/11002759).
69
-
70
-
## Security Guidelines
71
-
72
-
If you believe you have discovered a security vulnerability in this gem, please report it
73
-
by mail to the maintainer: sixto.martin.garcia+security@gmail.com
74
-
75
-
### Security Warning
76
-
77
-
Some tools may incorrectly report ruby-saml is a potential security vulnerability.
78
-
ruby-saml depends on Nokogiri, and it is possible to use Nokogiri in a dangerous way
79
-
(by enabling its DTDLOAD option and disabling its NONET option).
80
-
This dangerous Nokogiri configuration, which is sometimes used by other components,
81
-
can create an XML External Entity (XXE) vulnerability if the XML data is not trusted.
82
-
However, ruby-saml never enables this dangerous Nokogiri configuration;
83
-
ruby-saml never enables DTDLOAD, and it never disables NONET.
84
-
85
-
The OneLogin::RubySaml::IdpMetadataParser class does not validate the provided URL before parsing.
86
-
87
-
Usually, the same administrator who handles the Service Provider also sets the URL to
88
-
the IdP, which should be a trusted resource.
89
-
90
-
But there are other scenarios, like a SaaS app where the administrator of the app
91
-
delegates this functionality to other users. In this case, extra precautions should
92
-
be taken in order to validate such URL inputs and avoid attacks like SSRF.
93
64
94
65
## Getting Started
95
66
@@ -432,8 +403,8 @@ Those return an Hash instead of a `Settings` object, which may be useful for con
432
403
433
404
### Validating Signature of Metadata and retrieve settings
434
405
435
-
Right now there is no method at ruby_saml to validate the signature of the metadata that gonna be parsed,
436
-
but it can be done as follows:
406
+
Right now there is no method at ruby_saml to validate the signature of the metadata that is going to be parsed, but it can be done as follows:
407
+
437
408
* Download the XML.
438
409
* Validate the Signature, providing the cert.
439
410
* Provide the XML to the parse method if the signature was validated
@@ -722,7 +693,7 @@ SP Metadata XML, to be read by the IdP.
722
693
#### Verifying Signature on IdP Assertions
723
694
724
695
You may require the IdP to sign its SAML Assertions using the following setting.
725
-
With will add `<md:SPSSODescriptor WantAssertionsSigned="true">` to your SP Metadata XML.
696
+
This will add `<md:SPSSODescriptor WantAssertionsSigned="true">` to your SP Metadata XML.
726
697
The signature will be checked against the `<md:KeyDescriptor use="signing">` element
727
698
present in the IdP's metadata.
728
699
@@ -754,7 +725,7 @@ advanced usage scenarios:
754
725
- Specifying separate SP certificates for signing and encryption.
755
726
756
727
The `sp_cert_multi` parameter replaces `certificate` and `private_key`
757
-
(you may not specify both pparameters at the same time.) `sp_cert_multi` has the following shape:
728
+
(you may not specify both parameters at the same time.) `sp_cert_multi` has the following shape:
758
729
759
730
```ruby
760
731
settings.sp_cert_multi = {
@@ -824,7 +795,7 @@ def sp_logout_request
824
795
settings = saml_settings
825
796
826
797
if settings.idp_slo_service_url.nil?
827
-
logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
798
+
logger.info "SLO IdP Endpoint not found in settings, then executing a normal logout'"
828
799
delete_session
829
800
else
830
801
@@ -1007,3 +978,151 @@ end
1007
978
# Output XML with custom metadata
1008
979
MyMetadata.new.generate(settings)
1009
980
```
981
+
982
+
### Preventing Replay Attacks
983
+
984
+
A replay attack is when an attacker intercepts a valid SAML assertion and "replays" it at a later time to gain unauthorized access.
985
+
986
+
The library only checks the assertion's validity window (`NotBefore` and `NotOnOrAfter` conditions). An attacker can replay a valid assertion as many times as they want within this window.
987
+
988
+
A robust defense requires tracking of assertion IDs to ensure any given assertion is only accepted once.
989
+
990
+
#### 1. Extract the Assertion ID after Validation
991
+
992
+
After a response has been successfully validated, get the assertion ID. The library makes this available via `response.assertion_id`.
993
+
994
+
995
+
#### 2. Store the ID with an Expiry
996
+
997
+
You must store this ID in a persistent cache (like Redis or Memcached) that is shared across your servers. Do not store it in the user's session, as that is not a secure cache.
998
+
999
+
The ID should be stored until the assertion's validity window has passed. You will need to check how long the trusted IdPs consider the assertion valid and then add the allowed_clock_drift.
1000
+
1001
+
You can define a global value, or set this value dinamically based on the `not_on_or_after` value of the re + `allowed_clock_drift`.
1002
+
1003
+
```ruby
1004
+
# In your `consume` action, after a successful validation:
1005
+
if response.is_valid?
1006
+
# Prevent replay of this specific assertion
1007
+
assertion_id = response.assertion_id
1008
+
authorize_failure("Assertion ID is mandatory") if assertion_id.nil?
### Enforce SP-Initiated Flow with `InResponseTo` validation
1046
+
1047
+
This is the best way to prevent IdP-initiated logins and ensure that you only accept assertions that you recently requested.
1048
+
1049
+
#### 1. Store the `AuthnRequest` ID
1050
+
1051
+
When you create an `AuthnRequest`, the library assigns it a unique ID. You must store this ID, forexamplein the user's session *before* redirecting them to the IdP.
1052
+
1053
+
```ruby
1054
+
def init
1055
+
request = OneLogin::RubySaml::Authrequest.new
1056
+
# The unique ID of the request is in request.uuid
1057
+
session[:saml_request_id] = request.uuid
1058
+
redirect_to(request.create(saml_settings))
1059
+
end
1060
+
```
1061
+
1062
+
#### 2. Validate the `InResponseTo` value of the `Response` with the Stored ID
1063
+
1064
+
When you process the `SAMLResponse`, retrieve the ID from the session and pass it to the `Response` constructor. Use `session.delete` to ensure the ID can only be used once.
1065
+
1066
+
```ruby
1067
+
def consume
1068
+
request_id = session.delete(:saml_request_id) # Use delete to prevent re-use
1069
+
1070
+
# You can reject the response if no previous saml_request_id was stored
1071
+
raise "IdP-initiaited detected" if request_id.nil?
1072
+
1073
+
response = OneLogin::RubySaml::Response.new(
1074
+
params[:SAMLResponse],
1075
+
settings: saml_settings,
1076
+
matches_request_id: request_id
1077
+
)
1078
+
1079
+
if response.is_valid?
1080
+
# ... authorize user
1081
+
else
1082
+
# Response is invalid, errors in response.errors
1083
+
end
1084
+
end
1085
+
```
1086
+
1087
+
## Contributing
1088
+
1089
+
### Pay it Forward: Support RubySAML and Strengthen Open-Source Security
1090
+
1091
+
RubySAML is a trusted authentication library used by startups and enterprises alike—
1092
+
a community-driven alternative to costly third-party services.
1093
+
1094
+
But security doesn't happen in a vacuum. Vulnerabilities in authentication libraries can
1095
+
have widespread consequences. Maintaining open-source security requires continuous
1096
+
effort, expertise, and funding. By supporting RubySAML, you’re not just securing your
1097
+
own systems—you’re strengthening auth security globally. Instead of paying for closed
1098
+
solutions, consider investing in the community that does the real security work.
Copy file name to clipboardExpand all lines: UPGRADING.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ how validation happens in the toolkit and also the toolkit by default will check
7
7
when parsing a SAML Message (`settings.check_malformed_doc`).
8
8
9
9
The SignedDocument class defined at xml_security.rb experienced several changes.
10
-
We don't expect compatibilty issues if you use the main methods offered by ruby-saml, but if you use a fork or customized usage, is possible that you need to adapt your code.
10
+
We don't expect compatibility issues if you use the main methods offered by ruby-saml, but if you use a fork or customized usage, is possible that you need to adapt your code.
11
11
12
12
## Updating from 1.12.x to 1.13.0
13
13
@@ -33,7 +33,7 @@ in favor of `idp_sso_service_url` and `idp_slo_service_url`. The `IdpMetadataPar
33
33
34
34
## Upgrading from 1.10.x to 1.11.0
35
35
36
-
Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
36
+
Version `1.11.0` deprecates the use of `settings.issuer` in favor of `settings.sp_entity_id`.
37
37
There are two new security settings: `settings.security[:check_idp_cert_expiration]` and
38
38
`settings.security[:check_sp_cert_expiration]` (both false by default) that check if the
39
39
IdP or SP X.509 certificate has expired, respectively.
@@ -44,7 +44,7 @@ Version `1.10.1` improves Ruby 1.8.7 support.
44
44
45
45
## Upgrading from 1.9.0 to 1.10.0
46
46
47
-
Version `1.10.0` improves IdpMetadataParser to allow parse multiple IDPSSODescriptor,
47
+
Version `1.10.0` improves IdpMetadataParser to allow parsing multiple IDPSSODescriptor,
48
48
Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user
49
49
to be authenticated and updates the format_cert method to accept certs with /\x0d/
50
50
@@ -128,7 +128,7 @@ It adds security improvements in order to prevent Signature wrapping attacks.
128
128
129
129
## Upgrading from 1.1.x to 1.2.x
130
130
131
-
Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favour of SecureRandom,
131
+
Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favor of SecureRandom,
132
132
refactor error handling and some minor improvements.
133
133
134
134
There is no compatibility issue detected.
@@ -143,7 +143,7 @@ Version `1.1` adds some improvements on signature validation and solves some nam
143
143
144
144
Version `1.0` is a recommended update for all Ruby SAML users as it includes security fixes.
145
145
146
-
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decrypt support.
146
+
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decryption support.
0 commit comments