Skip to content

Commit cfa92aa

Browse files
authored
Allow OmniAuth Setup Phase to be configured (#76)
The [OmniAuth Setup Phase][1] allows for "request-time modification of an OmniAuth strategy". We're intending to use this in Experience CS so that we can optionally include the [`student` scope][2] to allow students to login. The Profile app uses the presence of the `student` scope in the login request to decide whether to display the student login form (i.e. the form containing the school code textbox). We want to allow students (as well as non-students) to login to Experience CS and so need a way of changing the `scope` accordingly. By default the `scope` is fixed at Rails [initialization time in the `RpiAuth::Engine`][3] but we need to be able to toggle it at runtime depending on whether user is a student or not. By utilising OmniAuth's setup phase we can toggle the `scope` based on something we set in the app (e.g. we might set something in the session to indicate that we want the student login flow). I initially added logic in this Gem to add the `student` scope if a specific value was set in the session but later decided that it should be up to the consuming apps to use this `setup` phase as they see fit. [1]: https://github.com/omniauth/omniauth/wiki/Setup-Phase [2]: https://github.com/RaspberryPiFoundation/documentation/blob/a92f03446a347d2d1acea48c50ea37f15293a9b6/docs/technology/codebases-and-products/accounts/profile-app/custom-oidc-scopes.md#available-custom-scopes [3]: https://github.com/RaspberryPiFoundation/rpi-auth/blob/b7771ee120254e4c6f2d90c5025be5714daeb542/lib/rpi_auth/engine.rb#L31
2 parents 97e40f8 + dd0e884 commit cfa92aa

File tree

5 files changed

+75
-24
lines changed

5 files changed

+75
-24
lines changed

lib/rpi_auth/configuration.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class Configuration
1818
:scope,
1919
:session_keys_to_persist,
2020
:success_redirect,
21-
:user_model
21+
:user_model,
22+
:setup
2223

2324
def initialize
2425
@bypass_auth = false

lib/rpi_auth/engine.rb

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,32 @@ class Engine < ::Rails::Engine
2323
initializer 'RpiAuth.add_middleware' do |app| # rubocop:disable Metrics/BlockLength
2424
next unless RpiAuth.configuration
2525

26+
openid_connect_options = {
27+
name: :rpi,
28+
setup: RpiAuth.configuration.setup,
29+
issuer: RpiAuth.configuration.issuer,
30+
scope: RpiAuth.configuration.scope,
31+
callback_path: CALLBACK_PATH,
32+
response_type: RpiAuth.configuration.response_type,
33+
client_auth_method: RpiAuth.configuration.client_auth_method,
34+
client_options: {
35+
identifier: RpiAuth.configuration.auth_client_id,
36+
secret: RpiAuth.configuration.auth_client_secret,
37+
scheme: RpiAuth.configuration.token_endpoint.scheme,
38+
host: RpiAuth.configuration.token_endpoint.host,
39+
port: RpiAuth.configuration.token_endpoint.port,
40+
authorization_endpoint: RpiAuth.configuration.authorization_endpoint,
41+
token_endpoint: RpiAuth.configuration.token_endpoint,
42+
jwks_uri: RpiAuth.configuration.jwks_uri,
43+
redirect_uri: URI.join(RpiAuth.configuration.host_url, CALLBACK_PATH)
44+
},
45+
extra_authorize_params: { brand: RpiAuth.configuration.brand },
46+
allow_authorize_params: [:login_options],
47+
origin_param: 'returnTo'
48+
}
49+
2650
app.middleware.use OmniAuth::Builder do
27-
provider(
28-
:openid_connect,
29-
name: :rpi,
30-
issuer: RpiAuth.configuration.issuer,
31-
scope: RpiAuth.configuration.scope,
32-
callback_path: CALLBACK_PATH,
33-
response_type: RpiAuth.configuration.response_type,
34-
client_auth_method: RpiAuth.configuration.client_auth_method,
35-
client_options: {
36-
identifier: RpiAuth.configuration.auth_client_id,
37-
secret: RpiAuth.configuration.auth_client_secret,
38-
scheme: RpiAuth.configuration.token_endpoint.scheme,
39-
host: RpiAuth.configuration.token_endpoint.host,
40-
port: RpiAuth.configuration.token_endpoint.port,
41-
authorization_endpoint: RpiAuth.configuration.authorization_endpoint,
42-
token_endpoint: RpiAuth.configuration.token_endpoint,
43-
jwks_uri: RpiAuth.configuration.jwks_uri,
44-
redirect_uri: URI.join(RpiAuth.configuration.host_url, CALLBACK_PATH)
45-
},
46-
extra_authorize_params: { brand: RpiAuth.configuration.brand },
47-
allow_authorize_params: [:login_options],
48-
origin_param: 'returnTo'
49-
)
51+
provider(:openid_connect, openid_connect_options)
5052

5153
OmniAuth.config.on_failure = RpiAuth::AuthController.action(:failure)
5254

spec/dummy/config/initializers/rpi_auth.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
RpiAuth.configure do |config|
2+
config.setup = lambda do |env|
3+
request = Rack::Request.new(env)
4+
5+
if custom_scope = request.params['add-custom-scope']
6+
env['omniauth.strategy'].options[:scope] += [custom_scope]
7+
end
8+
end
29
config.auth_url = 'http://localhost:9001'
310
config.auth_client_id = 'gem-dev'
411
config.auth_client_secret = 'secret'

spec/dummy/spec/requests/auth_request_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,5 +312,35 @@
312312
end
313313
end
314314
end
315+
316+
describe 'and toggling the scope at runtime' do
317+
let(:custom_scope) { 'custom-scope' }
318+
319+
before do
320+
OmniAuth.config.test_mode = false
321+
end
322+
323+
it 'does not append a custom scope' do
324+
post '/auth/rpi'
325+
326+
scopes = extract_scopes_from_redirect_location(response)
327+
328+
expect(scopes).not_to include(custom_scope)
329+
end
330+
331+
it 'appends a custom scope' do
332+
post "/auth/rpi?add-custom-scope=#{custom_scope}"
333+
334+
scopes = extract_scopes_from_redirect_location(response)
335+
336+
expect(scopes).to include(custom_scope)
337+
end
338+
339+
def extract_scopes_from_redirect_location(response)
340+
location = response.headers['location']
341+
params = CGI.parse(URI.parse(location).query)
342+
params['scope'].first.split
343+
end
344+
end
315345
end
316346
end

spec/support/omniauth.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
# frozen_string_literal: true
22

33
require 'omniauth'
4+
5+
RSpec.configure do |config|
6+
config.around do |example|
7+
original_value = OmniAuth.config.test_mode
8+
begin
9+
example.run
10+
ensure
11+
OmniAuth.config.test_mode = original_value
12+
end
13+
end
14+
end

0 commit comments

Comments
 (0)