Skip to content

Commit 7c6206e

Browse files
authored
Merge pull request #215 from smudge/relay-state-mocking
feat: Support RelayState binding by default during SSO
2 parents d974a84 + a508436 commit 7c6206e

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

lib/omniauth/strategies/saml.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def self.inherited(subclass)
1414
RUBYSAML_RESPONSE_OPTIONS = OneLogin::RubySaml::Response::AVAILABLE_OPTIONS
1515

1616
option :name_identifier_format, nil
17-
option :idp_sso_service_url_runtime_params, {}
17+
option :idp_sso_service_url_runtime_params, { RelayState: 'RelayState' }
1818
option :request_attributes, [
1919
{ :name => 'email', :name_format => 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', :friendly_name => 'Email address' },
2020
{ :name => 'name', :name_format => 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', :friendly_name => 'Full name' },
@@ -139,6 +139,22 @@ def find_attribute_by(keys)
139139
nil
140140
end
141141

142+
def mock_request_call
143+
# Per SAML 2.0, if a RelayState param is passed, IDPs "MUST place the exact RelayState
144+
# data it received with the request into the corresponding RelayState parameter in the response."
145+
#
146+
# By default, the "mock" `OmniAuth::Strategy` implementation will forward along any URL params,
147+
# so we can in turn take any POSTed RelayState params and put them in the GET query string:
148+
query_hash = request.GET.merge!(additional_params_for_authn_request.slice('RelayState'))
149+
query_string = Rack::Utils.build_query(query_hash)
150+
151+
request.set_header(Rack::QUERY_STRING, query_string)
152+
request.set_header(Rack::RACK_REQUEST_QUERY_STRING, query_string)
153+
request.set_header(Rack::RACK_REQUEST_QUERY_HASH, query_hash)
154+
155+
super
156+
end
157+
142158
private
143159

144160
def request_path_pattern

spec/omniauth/strategies/saml_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,33 @@
108108
end
109109
end
110110

111+
context 'with RelayState param' do
112+
before do
113+
post '/auth/saml', 'RelayState' => 'RELAY_STATE_VALUE'
114+
end
115+
116+
it 'should get authentication page' do
117+
expect(last_response).to be_redirect
118+
expect(last_response.location).to match(
119+
/\Ahttps:\/\/idp.sso.example.com\/signon\/29490\?SAMLRequest=.*&RelayState=RELAY_STATE_VALUE\z/,
120+
)
121+
end
122+
123+
context 'when test_mode is enabled' do
124+
around do |example|
125+
OmniAuth.config.test_mode = true
126+
example.run
127+
ensure
128+
OmniAuth.config.test_mode = false
129+
end
130+
131+
it 'should redirect to local saml callback page' do
132+
expect(last_response).to be_redirect
133+
expect(last_response.location).to eq('http://example.org/auth/saml/callback?RelayState=RELAY_STATE_VALUE')
134+
end
135+
end
136+
end
137+
111138
context "when the assertion_consumer_service_url is the default" do
112139
before :each do
113140
saml_options[:compress_request] = false

0 commit comments

Comments
 (0)