Skip to content

Commit e1ec493

Browse files
committed
Allow OmniAuth Setup Phase to be configured
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
1 parent 97e40f8 commit e1ec493

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ class Engine < ::Rails::Engine
2323
initializer 'RpiAuth.add_middleware' do |app| # rubocop:disable Metrics/BlockLength
2424
next unless RpiAuth.configuration
2525

26+
# rubocop:disable Metrics/BlockLength
2627
app.middleware.use OmniAuth::Builder do
2728
provider(
2829
:openid_connect,
2930
name: :rpi,
31+
setup: RpiAuth.configuration.setup,
3032
issuer: RpiAuth.configuration.issuer,
3133
scope: RpiAuth.configuration.scope,
3234
callback_path: CALLBACK_PATH,
@@ -47,6 +49,7 @@ class Engine < ::Rails::Engine
4749
allow_authorize_params: [:login_options],
4850
origin_param: 'returnTo'
4951
)
52+
# rubocop:enable Metrics/BlockLength
5053

5154
OmniAuth.config.on_failure = RpiAuth::AuthController.action(:failure)
5255

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

0 commit comments

Comments
 (0)