diff --git a/README.md b/README.md index 25ce034..131a58a 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,10 @@ be present. * `:uid_attribute` - Attribute that uniquely identifies the user. If unset, the name identifier returned by the IdP is used. +* `:store_request_uuid` - Used to store the request's UUID for later verification of InReponseTo. + By default it saves the request uuid in the session as "saml_transaction_id", + but also accepts a proc that will then be called with the uuid for custom storage. + * See the `OneLogin::RubySaml::Settings` class in the [Ruby SAML gem](https://github.com/onelogin/ruby-saml) for additional supported options. ## IdP Metadata diff --git a/lib/omniauth/strategies/saml.rb b/lib/omniauth/strategies/saml.rb index bbee4af..75d84e0 100644 --- a/lib/omniauth/strategies/saml.rb +++ b/lib/omniauth/strategies/saml.rb @@ -30,15 +30,26 @@ def self.inherited(subclass) option :slo_default_relay_state option :uid_attribute option :idp_slo_session_destroy, proc { |_env, session| session.clear } + option :store_request_uuid def request_phase authn_request = OneLogin::RubySaml::Authrequest.new + store_request_uuid(authn_request.uuid) + with_settings do |settings| redirect(authn_request.create(settings, additional_params_for_authn_request)) end end + def store_request_uuid(uuid) + if options.store_request_uuid.respond_to?(:call) + options.store_request_uuid.call(uuid) + elsif options.store_request_uuid + session["saml_transaction_id"] = uuid + end + end + def callback_phase raise OmniAuth::Strategies::SAML::ValidationError.new("SAML response missing") unless request.params["SAMLResponse"] diff --git a/spec/omniauth/strategies/saml_spec.rb b/spec/omniauth/strategies/saml_spec.rb index 1dfbb7f..d2c1d83 100644 --- a/spec/omniauth/strategies/saml_spec.rb +++ b/spec/omniauth/strategies/saml_spec.rb @@ -115,6 +115,29 @@ def post_xml(xml=:example_response, opts = {}) expect(query['SigAlg']).to eq XMLSecurity::Document::RSA_SHA256 end end + + context 'with store_request_uuid set' do + let(:store_request_uuid) { true } + let(:uuid_regex) { /_\w{8}-\w{4}-\w{4}-\w{4}-\w{11}/ } + + before do + saml_options[:store_request_uuid] = store_request_uuid + + get '/auth/saml' + end + + it 'stores uuid as saml_transaction_id' do + expect(session['saml_transaction_id']).to match(uuid_regex) + end + + context 'using a proc' do + let(:store_request_uuid) { Proc.new { |uuid| @uuid_stored = uuid } } + + it 'allows customized storage of request uuid' do + expect(@uuid_stored).to match(uuid_regex) + end + end + end end describe 'POST /auth/saml/callback' do