Skip to content

Commit 96de262

Browse files
committed
Make the state parameter verification optional
1 parent 4cf9061 commit 96de262

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v0.4.1 (06.02.2022)
2+
3+
- Make the state parameter verification optional [#122](https://github.com/omniauth/omniauth_openid_connect/pull/122)
4+
15
# v0.4.0 (06.02.2022)
26

37
- Support dynamic parameters to the authorize URI [#90](https://github.com/omniauth/omniauth_openid_connect/pull/90)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ config.omniauth :openid_connect, {
5656
| scope | Which OpenID scopes to include (:openid is always required) | no | Array<sym> [:openid] | [:openid, :profile, :email] |
5757
| response_type | Which OAuth2 response type to use with the authorization request | no | String: code | one of: 'code', 'id_token' |
5858
| state | A value to be used for the OAuth2 state parameter on the authorization request. Can be a proc that generates a string. | no | Random 16 character string | Proc.new { SecureRandom.hex(32) } |
59+
| require_state | Should state param be verified - this is recommended, not required by the OIDC specification | no | true | false |
5960
| response_mode | The response mode per [spec](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) | no | nil | one of: :query, :fragment, :form_post, :web_message |
6061
| display | An optional parameter to the authorization request to determine how the authorization and consent page | no | nil | one of: :page, :popup, :touch, :wap |
6162
| prompt | An optional parameter to the authrization request to determine what pages the user will be shown | no | nil | one of: :none, :login, :consent, :select_account |

lib/omniauth/strategies/openid_connect.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class OpenIDConnect
4040
option :client_x509_signing_key
4141
option :scope, [:openid]
4242
option :response_type, 'code' # ['code', 'id_token']
43+
option :require_state, true
4344
option :state
4445
option :response_mode # [:query, :fragment, :form_post, :web_message]
4546
option :display, nil # [:page, :popup, :touch, :wap]
@@ -114,7 +115,7 @@ def request_phase
114115
def callback_phase
115116
error = params['error_reason'] || params['error']
116117
error_description = params['error_description'] || params['error_reason']
117-
invalid_state = params['state'].to_s.empty? || params['state'] != stored_state
118+
invalid_state = (options.require_state && params['state'].to_s.empty?) || params['state'] != stored_state
118119

119120
raise CallbackError, error: params['error'], reason: error_description, uri: params['error_uri'] if error
120121
raise CallbackError, error: :csrf_detected, reason: "Invalid 'state' parameter" if invalid_state

test/lib/omniauth/strategies/openid_connect_test.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,65 @@ def test_callback_phase_with_discovery # rubocop:disable Metrics/AbcSize
278278
strategy.callback_phase
279279
end
280280

281+
def test_callback_phase_with_no_state_without_state_verification # rubocop:disable Metrics/AbcSize
282+
code = SecureRandom.hex(16)
283+
nonce = SecureRandom.hex(16)
284+
285+
strategy.options.require_state = false
286+
287+
request.stubs(:params).returns('code' => code)
288+
request.stubs(:path).returns('')
289+
290+
strategy.options.client_options.host = 'example.com'
291+
strategy.options.discovery = true
292+
293+
issuer = stub('OpenIDConnect::Discovery::Issuer')
294+
issuer.stubs(:issuer).returns('https://example.com/')
295+
::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
296+
297+
config = stub('OpenIDConnect::Discovery::Provder::Config')
298+
config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
299+
config.stubs(:token_endpoint).returns('https://example.com/token')
300+
config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
301+
config.stubs(:jwks_uri).returns('https://example.com/jwks')
302+
config.stubs(:jwks).returns(JSON::JWK::Set.new(jwks['keys']))
303+
304+
::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
305+
306+
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
307+
id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
308+
id_token.stubs(:verify!).with(issuer: 'https://example.com/', client_id: @identifier, nonce: nonce).returns(true)
309+
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
310+
311+
strategy.unstub(:user_info)
312+
access_token = stub('OpenIDConnect::AccessToken')
313+
access_token.stubs(:access_token)
314+
access_token.stubs(:refresh_token)
315+
access_token.stubs(:expires_in)
316+
access_token.stubs(:scope)
317+
access_token.stubs(:id_token).returns(jwt.to_s)
318+
client.expects(:access_token!).at_least_once.returns(access_token)
319+
access_token.expects(:userinfo!).returns(user_info)
320+
321+
strategy.call!('rack.session' => { 'omniauth.nonce' => nonce })
322+
strategy.callback_phase
323+
end
324+
325+
def test_callback_phase_with_invalid_state_without_state_verification
326+
code = SecureRandom.hex(16)
327+
state = SecureRandom.hex(16)
328+
nonce = SecureRandom.hex(16)
329+
330+
strategy.options.require_state = false
331+
332+
request.stubs(:params).returns('code' => code, 'state' => 'foobar')
333+
request.stubs(:path).returns('')
334+
335+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
336+
strategy.expects(:fail!)
337+
strategy.callback_phase
338+
end
339+
281340
def test_callback_phase_with_error
282341
state = SecureRandom.hex(16)
283342
request.stubs(:params).returns('error' => 'invalid_request')

0 commit comments

Comments
 (0)