From 28d3fffc0d744382d84c8f7b42a2e8a16c6e43b0 Mon Sep 17 00:00:00 2001 From: Sixto Martin Date: Mon, 30 Sep 2024 09:18:46 +0200 Subject: [PATCH] Add support to retrieve from SAMLResponse the AuthnInstant and AuthnContextClassRef values. See #718 --- CHANGELOG.md | 15 ++++++++------- lib/ruby_saml/response.rb | 21 +++++++++++++++++++++ test/response_test.rb | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e370db..3f326514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Ruby SAML Changelog ### 2.0.0 +* [#718](https://github.com/SAML-Toolkits/ruby-saml/pull/718/) Add support to retrieve from SAMLResponse the AuthnInstant and AuthnContextClassRef values * [#685](https://github.com/SAML-Toolkits/ruby-saml/pull/685) Remove `OneLogin` namespace. The root namespace of the gem is now `RubySaml`. * [#685](https://github.com/SAML-Toolkits/ruby-saml/pull/685) Create namespace alias `OneLogin = Object` for backward compatibility, to be removed in version `2.1.0`. * [#685](https://github.com/SAML-Toolkits/ruby-saml/pull/685) Change directly structure from `lib/onelogin/ruby-saml` to `lib/ruby_saml`. @@ -28,7 +29,7 @@ ### 1.15.0 (Jan 04, 2023) * [#650](https://github.com/SAML-Toolkits/ruby-saml/pull/650) Replace strip! by strip on compute_digest method -* [#638](https://github.com/SAML-Toolkits/ruby-saml/pull/638) Fix dateTime format for the validUntil attribute of the generated metadata +* [#638](https://github.com/SAML-Toolkits/ruby-saml/pull/638) Fix dateTime format for the validUntil attribute of the generated metadata * [#576](https://github.com/SAML-Toolkits/ruby-saml/pull/576) Support `Settings#idp_cert_multi` with string keys * [#567](https://github.com/SAML-Toolkits/ruby-saml/pull/567) Improve Code quality * Add info about new repo, new maintainer, new security contact @@ -62,7 +63,7 @@ ### 1.12.0 (Feb 18, 2021) * Support AES-128-GCM, AES-192-GCM, and AES-256-GCM encryptions -* Parse & return SLO ResponseLocation in IDPMetadataParser & Settings +* Parse & return SLO ResponseLocation in IDPMetadataParser & Settings * Adding idp_sso_service_url and idp_slo_service_url settings * [#536](https://github.com/SAML-Toolkits/ruby-saml/pull/536) Adding feth method to be able retrieve attributes based on regex * Reduce size of built gem by excluding the test folder @@ -192,7 +193,7 @@ * Fix response_test.rb of gem 1.3.0 * Add reference to Security Guidelines * Update License -* [#334](https://github.com/SAML-Toolkits/ruby-saml/pull/334) Keep API backward-compatibility on IdpMetadataParser fingerprint method. +* [#334](https://github.com/SAML-Toolkits/ruby-saml/pull/334) Keep API backward-compatibility on IdpMetadataParser fingerprint method. ### 1.3.0 (June 24, 2016) * [Security Fix](https://github.com/SAML-Toolkits/ruby-saml/commit/a571f52171e6bfd87db59822d1d9e8c38fb3b995) Add extra validations to prevent Signature wrapping attacks @@ -210,7 +211,7 @@ * [#316](https://github.com/SAML-Toolkits/ruby-saml/pull/316) Fix Misspelling of transation_id to transaction_id * [#321](https://github.com/SAML-Toolkits/ruby-saml/pull/321) Support Attribute Names on IDPSSODescriptor parser * Changes on empty URI of Signature reference management -* [#320](https://github.com/SAML-Toolkits/ruby-saml/pull/320) Dont mutate document to fix lack of reference URI +* [#320](https://github.com/SAML-Toolkits/ruby-saml/pull/320) Dont mutate document to fix lack of reference URI * [#306](https://github.com/SAML-Toolkits/ruby-saml/pull/306) Support WantAssertionsSigned ### 1.1.2 (February 15, 2016) @@ -227,9 +228,9 @@ * [#270](https://github.com/SAML-Toolkits/ruby-saml/pull/270) Allow SAML elements to come from any namespace (at decryption process) * [#261](https://github.com/SAML-Toolkits/ruby-saml/pull/261) Allow validate_subject_confirmation Response validation to be skipped * [#258](https://github.com/SAML-Toolkits/ruby-saml/pull/258) Fix allowed_clock_drift on the validate_session_expiration test -* [#256](https://github.com/SAML-Toolkits/ruby-saml/pull/256) Separate the create_authentication_xml_doc in two methods. +* [#256](https://github.com/SAML-Toolkits/ruby-saml/pull/256) Separate the create_authentication_xml_doc in two methods. * [#255](https://github.com/SAML-Toolkits/ruby-saml/pull/255) Refactor validate signature. -* [#254](https://github.com/SAML-Toolkits/ruby-saml/pull/254) Handle empty URI references +* [#254](https://github.com/SAML-Toolkits/ruby-saml/pull/254) Handle empty URI references * [#251](https://github.com/SAML-Toolkits/ruby-saml/pull/251) Support qualified and unqualified NameID in attributes * [#234](https://github.com/SAML-Toolkits/ruby-saml/pull/234) Add explicit support for JRuby @@ -237,7 +238,7 @@ * [#247](https://github.com/SAML-Toolkits/ruby-saml/pull/247) Avoid entity expansion (XEE attacks) * [#246](https://github.com/SAML-Toolkits/ruby-saml/pull/246) Fix bug generating Logout Response (issuer was at wrong order) * [#243](https://github.com/SAML-Toolkits/ruby-saml/issues/243) and [#244](https://github.com/SAML-Toolkits/ruby-saml/issues/244) Fix metadata builder errors. Fix metadata xsd. -* [#241](https://github.com/SAML-Toolkits/ruby-saml/pull/241) Add decrypt support (EncryptID and EncryptedAssertion). Improve compatibility with namespaces. +* [#241](https://github.com/SAML-Toolkits/ruby-saml/pull/241) Add decrypt support (EncryptID and EncryptedAssertion). Improve compatibility with namespaces. * [#240](https://github.com/SAML-Toolkits/ruby-saml/pull/240) and [#238](https://github.com/SAML-Toolkits/ruby-saml/pull/238) Improve test coverage and refactor. * [#239](https://github.com/SAML-Toolkits/ruby-saml/pull/239) Improve security: Add more validations to SAMLResponse, LogoutRequest and LogoutResponse. Refactor code and improve tests coverage. * [#237](https://github.com/SAML-Toolkits/ruby-saml/pull/237) Don't pretty print metadata by default. diff --git a/lib/ruby_saml/response.rb b/lib/ruby_saml/response.rb index a12007ea..eee85da4 100644 --- a/lib/ruby_saml/response.rb +++ b/lib/ruby_saml/response.rb @@ -201,6 +201,27 @@ def session_expires_at end end + # Gets the AuthnInstant from the AuthnStatement. + # Could be used to require re-authentication if a long time has passed + # since the last user authentication. + # @return [String] AuthnInstant value + # + def authn_instant + @authn_instant ||= begin + node = xpath_first_from_signed_assertion('/a:AuthnStatement') + node.nil? ? nil : node.attributes['AuthnInstant'] + end + end + + # Gets the AuthnContextClassRef from the AuthnStatement + # Could be used to require re-authentication if the assertion + # did not met the requested authentication context class. + # @return [String] AuthnContextClassRef value + # + def authn_context_class_ref + @authn_context_class_ref ||= Utils.element_text(xpath_first_from_signed_assertion('/a:AuthnStatement/a:AuthnContext/a:AuthnContextClassRef')) + end + # Checks if the Status has the "Success" code # @return [Boolean] True if the StatusCode is Sucess # diff --git a/test/response_test.rb b/test/response_test.rb index 2eef8464..fb443074 100644 --- a/test/response_test.rb +++ b/test/response_test.rb @@ -1357,6 +1357,27 @@ def generate_audience_error(expected, actual) end end + # Gets the AuthnInstant from the AuthnStatement. + # Could be used to require re-authentication if a long time has passed + # since the last user authentication. + # @return [String] AuthnInstant value + # + def authn_instant + @authn_instant ||= begin + node = xpath_first_from_signed_assertion('/a:AuthnStatement') + node.nil? ? nil : node.attributes['AuthnInstant'] + end + end + + # Gets the AuthnContextClassRef from the AuthnStatement + # Could be used to require re-authentication if the assertion + # did not met the requested authentication context class. + # @return [String] AuthnContextClassRef value + # + def authn_context_class_ref + @authn_context_class_ref ||= Utils.element_text(xpath_first_from_signed_assertion('/a:AuthnStatement/a:AuthnContext/a:AuthnContextClassRef')) + end + describe "#success" do it "find a status code that says success" do response.success?