Skip to content

Commit d8559a2

Browse files
authored
Add optional on_login_success callback (#90)
This adds a new `on_login_success` configuration option. If this option is set to a `Proc` and the login was successful, the `Proc` will be called in the context of the `RpiAuth::AuthController#callback` action, i.e. `current_user` will be available. This is intended to allow apps to record successful logins. I'm not convinced that using `instance_exec` is the most sensible approach, but I decided it was better to be consistent with the way the `success_redirect` option is implemented. If the `Proc` raises an exception, this will be rescued and the exception will be logged as a warning in the Rails log. This is so that the login will still complete successfully, even if there was a problem recording it. The immediate motivation for adding this is so we can record successful *student* logins in `experience-cs` in order to be able to calculate the "active users" metric described in [this issue][1]. Unfortunately while this information is available in the `profile` app database for regular users; it's not available for student users. [1]: https://github.com/RaspberryPiFoundation/experience-cs/issues/727
2 parents 2c5cedb + 46ab585 commit d8559a2

File tree

6 files changed

+65
-1
lines changed

6 files changed

+65
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Add optional `on_login_success` callback (#90)
13+
1214
### Fixed
1315

1416
### Removed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ link_to 'Log out', rpi_auth_logout_path, params: { returnTo: '/thanks-dude' }
170170

171171
This has to be a relative URL, i.e. it has to start with a slash. This is to ensure there's no open redirect.
172172

173+
### Callback on successful login
174+
175+
If the RpiAuth configuration option `on_login_success` is set to a `Proc`, this will be called in the context of the `RpiAuth::AuthController#callback` action, i.e. `current_user` will be available. This is intended to allow apps to record successful logins.
176+
173177
### Globbed/catch-all routes
174178

175179
If your app has a catch-all route at the end of the routing table, you must

app/controllers/rpi_auth/auth_controller.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ def callback
2727
auth = request.env['omniauth.auth']
2828
self.current_user = RpiAuth.user_model.from_omniauth(auth)
2929

30+
run_login_success_callback
31+
3032
redirect_to ensure_relative_url(login_redirect_path)
3133
end
3234

@@ -53,6 +55,16 @@ def failure
5355

5456
private
5557

58+
def run_login_success_callback
59+
return unless RpiAuth.configuration.on_login_success.is_a?(Proc)
60+
61+
begin
62+
instance_exec(&RpiAuth.configuration.on_login_success)
63+
rescue StandardError => e
64+
Rails.logger.warn("Caught #{e} while processing on_login_success proc.")
65+
end
66+
end
67+
5668
def login_redirect_path
5769
unless RpiAuth.configuration.success_redirect.is_a?(Proc)
5870
return RpiAuth.configuration.success_redirect || request.env['omniauth.origin']

lib/rpi_auth/configuration.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class Configuration
1919
:session_keys_to_persist,
2020
:success_redirect,
2121
:user_model,
22-
:setup
22+
:setup,
23+
:on_login_success
2324

2425
def initialize
2526
@bypass_auth = false

spec/dummy/spec/requests/auth_request_spec.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
require 'spec_helper'
44

5+
class Foo
6+
cattr_accessor :successful_logins
7+
self.successful_logins = []
8+
end
9+
510
RSpec.describe 'Authentication' do
611
let(:user) do
712
User.new(
@@ -311,6 +316,42 @@
311316
end
312317
end
313318
end
319+
320+
context 'when on_login_success is set as a proc in config' do
321+
before do
322+
allow(Rails.logger).to receive(:warn).and_call_original
323+
324+
RpiAuth.configuration.on_login_success = lambda do
325+
Rails.logger.warn "Successful login: #{current_user.user_id}"
326+
end
327+
end
328+
329+
it 'calls the proc making the current user available' do
330+
post '/auth/rpi'
331+
follow_redirect!
332+
333+
expect(Rails.logger).to have_received(:warn).with(
334+
"Successful login: #{user.user_id}"
335+
)
336+
end
337+
338+
context 'when the proc raises an exception' do
339+
before do
340+
RpiAuth.configuration.on_login_success = lambda do
341+
raise 'boom!'
342+
end
343+
end
344+
345+
it 'logs a warning error' do
346+
post '/auth/rpi'
347+
follow_redirect!
348+
349+
expect(Rails.logger).to have_received(:warn).with(
350+
'Caught boom! while processing on_login_success proc.'
351+
)
352+
end
353+
end
354+
end
314355
end
315356

316357
describe 'and toggling the scope at runtime' do

spec/rpi_auth/configuration_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,8 @@
110110
it_behaves_like 'sets up the token url defaults'
111111
end
112112
end
113+
114+
it 'sets on_login_success to nil by default' do
115+
expect(configuration.on_login_success).to be_nil
116+
end
113117
end

0 commit comments

Comments
 (0)