Skip to content

Commit b31c63c

Browse files
authored
Merge pull request #2070 from govuk-forms/log-user-out-when-they-submit
Log the user out of One Login when their form is submitted
2 parents 6f209b3 + cb1c4a1 commit b31c63c

16 files changed

Lines changed: 376 additions & 59 deletions

app/controllers/application_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,8 @@ def default_locale?(locale)
118118

119119
false
120120
end
121+
122+
def auth_service
123+
@auth_service ||= AuthService.new(session)
124+
end
121125
end

app/controllers/forms/check_your_answers_controller.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ def submit_answers
4343

4444
current_context.save_submission_details(submission_reference, requested_email_confirmation)
4545

46-
redirect_to :form_submitted
46+
if auth_service.logged_in?
47+
auth_service.store_return_params(form: current_context.form, mode: mode, locale: locale_param)
48+
redirect_to auth_service.logout_redirect_uri(omniauth_logged_out_url), allow_other_host: true
49+
else
50+
redirect_to :form_submitted
51+
end
4752
rescue FormSubmissionService::ConfirmationEmailToAddressError
4853
setup_check_your_answers
4954
email_confirmation_input.errors.add(:confirmation_email_address, :invalid_email)

app/controllers/forms/continue_to_one_login_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class ContinueToOneLoginController < BaseController
33
before_action :redirect_if_feature_disabled, :redirect_if_form_incomplete
44

55
def show
6-
Store::ReturnFromOneLoginStore.new(session).store_return_params(
6+
auth_service.store_return_params(
77
form: current_context.form,
88
mode: mode,
99
locale: locale_param,
Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
module Users
22
class OmniauthController < ApplicationController
3-
class OmniAuthLoggedInDataMissingError < StandardError; end
43
class OmniAuthFailure < StandardError; end
54

6-
rescue_from Store::ReturnFromOneLoginStore::MissingReturnParamsError do
7-
Rails.logger.warn("Missing return params in session for One Login callback")
8-
redirect_to error_404_path
9-
end
10-
115
def callback
12-
email = request.env.dig("omniauth.auth", "info", "email")
13-
if email.blank?
14-
raise OmniAuthLoggedInDataMissingError, "Email is missing in OmniAuth auth hash"
15-
end
16-
17-
return_from_one_login_store = Store::ReturnFromOneLoginStore.new(session)
18-
form_id = return_from_one_login_store.form_id
19-
path_params = return_from_one_login_store.get_path_params
6+
auth_hash = request.env["omniauth.auth"]
7+
auth_service.store_auth_details(auth_hash)
208

21-
Store::ConfirmationDetailsStore.new(session, form_id).save_copy_of_answers_email_address(email)
9+
path_params = auth_service.form_path_params
2210

2311
redirect_to check_your_answers_path(**path_params)
12+
rescue Store::ReturnFromOneLoginStore::MissingReturnParamsError
13+
Rails.logger.warn("Missing return params in session for One Login callback")
14+
redirect_to error_404_path
2415
end
2516

2617
def failure
2718
error = request.env["omniauth.error"]
2819
raise OmniAuthFailure, error
2920
end
21+
22+
def logged_out
23+
auth_service.clear_auth_session
24+
25+
path_params = auth_service.form_path_params
26+
redirect_to form_submitted_path(**path_params)
27+
end
3028
end
3129
end

app/lib/store/auth_store.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module Store
2+
class AuthStore
3+
AUTH_KEY = "auth".freeze
4+
TOKEN_KEY = "token".freeze
5+
6+
def initialize(store)
7+
@store = store
8+
end
9+
10+
def store_token(token)
11+
@store[AUTH_KEY] = {
12+
TOKEN_KEY => token,
13+
}
14+
end
15+
16+
def get_token
17+
@store.dig(AUTH_KEY, TOKEN_KEY)
18+
end
19+
20+
def clear
21+
@store.delete(AUTH_KEY)
22+
end
23+
24+
def logged_in?
25+
get_token.present?
26+
end
27+
end
28+
end

app/lib/store/return_from_one_login_store.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def store_return_params(form:, mode:, locale:)
2020
@store[RETURN_FROM_ONE_LOGIN_KEY][LAST_LOCALE_KEY] = locale
2121
end
2222

23-
def get_path_params
23+
def form_path_params
2424
raise MissingReturnParamsError if @store[RETURN_FROM_ONE_LOGIN_KEY].blank?
2525

2626
{

app/services/auth_service.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class AuthService
2+
class DataMissingError < StandardError; end
3+
4+
attr_reader :auth_store, :return_from_one_login_store
5+
6+
def initialize(store)
7+
@store = store
8+
@return_from_one_login_store = Store::ReturnFromOneLoginStore.new(store)
9+
@auth_store = Store::AuthStore.new(store)
10+
end
11+
12+
delegate :logged_in?, to: :auth_store
13+
delegate :store_return_params, :form_path_params, to: :return_from_one_login_store
14+
15+
def store_auth_details(auth_hash)
16+
form_id = @return_from_one_login_store.form_id
17+
18+
raise DataMissingError, "Auth hash is missing on request" if auth_hash.blank?
19+
20+
email = auth_hash.dig("info", "email")
21+
raise DataMissingError, "Email is missing in OmniAuth auth hash" if email.blank?
22+
23+
token = auth_hash.dig("credentials", "id_token")
24+
raise DataMissingError, "Token is missing in OmniAuth auth hash" if token.blank?
25+
26+
@auth_store.store_token(token)
27+
Store::ConfirmationDetailsStore.new(@store, form_id).save_copy_of_answers_email_address(email)
28+
end
29+
30+
def logout_redirect_uri(post_logout_redirect_uri)
31+
token = @auth_store.get_token
32+
logout_request = logout_utility.build_request(
33+
id_token_hint: token,
34+
post_logout_redirect_uri: url_without_params(post_logout_redirect_uri),
35+
)
36+
logout_request.redirect_uri
37+
end
38+
39+
def clear_auth_session
40+
@auth_store.clear
41+
end
42+
43+
private
44+
45+
def logout_utility
46+
@logout_utility ||= OmniAuth::GovukOneLogin::LogoutUtility.new(
47+
idp_configuration: Rails.application.config.x.one_login.idp_configuration,
48+
)
49+
end
50+
51+
def url_without_params(url)
52+
url = URI.parse(url)
53+
url.query = nil
54+
url.to_s
55+
end
56+
end

config/initializers/omniauth.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@
2828
# will call `Users::OmniauthController#failure` if there are any errors during the login process
2929
on_failure { |env| Users::OmniauthController.action(:failure).call(env) }
3030
end
31+
32+
# Store this globally so we only make a request to the One Login discovery endpoint once as the configuration should not regularly change
33+
Rails.application.config.x.one_login.idp_configuration = OmniAuth::GovukOneLogin::IdpConfiguration.new(idp_base_url: Settings.govuk_one_login.base_url)

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
get "/auth/govuk_one_login/callback", to: "users/omniauth#callback", as: :omniauth_callback
55
get "/auth/failure", to: "users/omniauth#failure", as: :omniauth_failure
6+
get "/auth/logged-out", to: "users/omniauth#logged_out", as: :omniauth_logged_out
67

78
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
89
# Can be used by load balancers and uptime monitors to verify that the app is live.

config/settings/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ submission_status_api:
1717
file_upload:
1818
poll_scan_status_wait_milliseconds: 50
1919
poll_scan_status_max_attempts: 2
20+
21+
govuk_one_login:
22+
base_url: http://example.com/one-login-mock/

0 commit comments

Comments
 (0)