Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ER-413 Gov one login Integration #917

Merged
merged 139 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
ba2c305
wip
jack-coggin Oct 20, 2023
1bb0192
add option for gov one login
jack-coggin Oct 24, 2023
606eee6
fix merge conflicts
jack-coggin Oct 24, 2023
b2b8263
remove existing sign in options from home page
jack-coggin Oct 24, 2023
1c0fb29
wip
jack-coggin Oct 27, 2023
a51cb32
update auth service specs
jack-coggin Oct 27, 2023
0f0c329
Merge branch 'main' into one-login
jack-coggin Oct 30, 2023
efd8bcf
remove user facing gov one login changes
jack-coggin Oct 30, 2023
2c66f36
update auth service specs
jack-coggin Oct 30, 2023
e2f22d5
remove mock client assertion in gov one auth service
jack-coggin Oct 30, 2023
2e66545
revert gemfile.lock changes
jack-coggin Oct 31, 2023
4e82e2c
reinstall dependencies
jack-coggin Oct 31, 2023
8e0d363
remove gemfile.lock
jack-coggin Oct 31, 2023
e0af9ed
add finding users by gov one id token
jack-coggin Oct 31, 2023
426f648
verify gov one redirect state and decode id token
jack-coggin Oct 31, 2023
93f7080
update gemfile.lock
jack-coggin Nov 1, 2023
48f4ae5
update migration number
jack-coggin Nov 1, 2023
7313839
update localisations and add all text to cms
jack-coggin Nov 1, 2023
5cf8cc6
update localisations
jack-coggin Nov 1, 2023
66170de
rubocop
jack-coggin Nov 1, 2023
51b8acd
update omniauth callbacks controller
jack-coggin Nov 1, 2023
70816b5
update credentials
jack-coggin Nov 2, 2023
d4c6be6
update application config
jack-coggin Nov 2, 2023
c6c8eca
rubocop
jack-coggin Nov 2, 2023
a83da4e
update env.example
jack-coggin Nov 6, 2023
04a8a15
add gov one env variables to docker dev compose
jack-coggin Nov 6, 2023
773178d
add feature flag and revert changes to application_helper
jack-coggin Nov 7, 2023
d6243c2
Merge branch 'main' into one-login
jack-coggin Nov 7, 2023
c12af1b
fix error from merge
jack-coggin Nov 7, 2023
dcf4cf3
rubocop
jack-coggin Nov 7, 2023
e4f9f4f
refactor gov one auth service
jack-coggin Nov 8, 2023
ceaa9dd
add gov one documentation and refactor service
jack-coggin Nov 9, 2023
60597a7
refactor gov one helper and update yard
jack-coggin Nov 9, 2023
368e8ab
rubocop
jack-coggin Nov 9, 2023
d297b42
update gov one auth service spec
jack-coggin Nov 10, 2023
7294ab7
update devise config
jack-coggin Nov 10, 2023
1eaf6ed
update gov one helper and spec
jack-coggin Nov 10, 2023
6ca601a
Helper methods with encoded URIs and specs
peterdavidhamilton Nov 10, 2023
abf9063
Merge remote-tracking branch 'origin/main' into one-login
peterdavidhamilton Nov 10, 2023
d95d246
Update CI envs
peterdavidhamilton Nov 10, 2023
974be47
refactor gov one service and helper
jack-coggin Nov 10, 2023
bc7ddbe
Refactor to use a constant and reduce number of variables
peterdavidhamilton Nov 10, 2023
f597681
refactor gov one auth service and specs for service and helper
jack-coggin Nov 13, 2023
919dea4
fix merge conflicts
jack-coggin Nov 13, 2023
c035a0f
remove typos
jack-coggin Nov 13, 2023
818839b
remove unneeded env variables from docker compose and ci workflow
jack-coggin Nov 13, 2023
48297ce
enable one login by default except for production
jack-coggin Nov 14, 2023
dffa921
update application gov_one_login? check
jack-coggin Nov 14, 2023
5af4ec3
update account page for one login
jack-coggin Nov 14, 2023
0c96676
Merge branch 'main' into one-login-bridging-page
jack-coggin Nov 14, 2023
adaa702
create gov one bridging page
jack-coggin Nov 14, 2023
a15457b
update gov one helper and specs
jack-coggin Nov 14, 2023
226345e
wip
jack-coggin Nov 15, 2023
8410f8f
update bridging page
jack-coggin Nov 15, 2023
b7a8ff5
update homepage
jack-coggin Nov 16, 2023
36ee42d
update gov one helper and specs
jack-coggin Nov 16, 2023
3ece9e2
Merge branch 'main' into one-login
jack-coggin Nov 16, 2023
e35f97e
Remove .env.example whitespace
jack-coggin Nov 16, 2023
385e30a
Merge branch 'one-login' into one-login-bridging-page
jack-coggin Nov 16, 2023
2cf7064
update application_helper links, gov_one_helper spec and revert chang…
jack-coggin Nov 16, 2023
784f116
skip whats_new_page_spec and update locales
jack-coggin Nov 16, 2023
4451a12
use content from cms
jack-coggin Nov 16, 2023
dadd4b8
update helper spec
jack-coggin Nov 16, 2023
7b776be
add route alias for bridging page
jack-coggin Nov 16, 2023
9765caf
extract homepage cta to partial
jack-coggin Nov 16, 2023
6d74e30
remove unnecessary route alias
jack-coggin Nov 16, 2023
65a4a22
resolve merge conflicts:
jack-coggin Nov 16, 2023
dd05c11
Retest local dev with encoded redirect params
peterdavidhamilton Nov 16, 2023
59bc741
Highlight duplication in the service spec with a little refactor
peterdavidhamilton Nov 17, 2023
bda11ba
Users::OmniauthCallbacksController
peterdavidhamilton Nov 17, 2023
5c6a727
update helper and service specs
jack-coggin Nov 17, 2023
6729f63
update locales
jack-coggin Nov 17, 2023
f262a40
fix merge conflicts and update locales
jack-coggin Nov 17, 2023
703d642
update locales
jack-coggin Nov 17, 2023
e17b30e
update locales
jack-coggin Nov 17, 2023
391c35b
convert sso auth uri to string in navbar
jack-coggin Nov 17, 2023
2b4f1a5
update system spec
jack-coggin Nov 17, 2023
208c212
update gov one info system spec
jack-coggin Nov 17, 2023
3b7ba6a
styling tweaks
jack-coggin Nov 20, 2023
b556ac3
change div width
jack-coggin Nov 20, 2023
2d46c4f
update for onboarding tech checklist
jack-coggin Nov 20, 2023
6feb326
check for session state and nonce on one-login redirect
jack-coggin Nov 21, 2023
771550c
mock session nonce in controller spec
jack-coggin Nov 21, 2023
a484a83
rubocop
jack-coggin Nov 21, 2023
f781f19
update account page for one login move
jack-coggin Nov 21, 2023
26e7c5f
css update
jack-coggin Nov 21, 2023
7f29b86
remove change password spec
jack-coggin Nov 22, 2023
b81ec38
update bot spec
jack-coggin Nov 22, 2023
4a353bc
minor styling updates
jack-coggin Nov 23, 2023
16bb158
add terms and conditions page
jack-coggin Nov 27, 2023
f2ead42
update localisations and specs
jack-coggin Nov 27, 2023
85baa09
update callbacks controller
jack-coggin Nov 27, 2023
30d50e6
Merge branch 'one-login' into ER-876-gov-one-t-and-c-page
jack-coggin Nov 27, 2023
28f80d5
update specs
jack-coggin Nov 27, 2023
d50aed7
Refactor .find_or_create_from_gov_one spec for dry lazy loading
peterdavidhamilton Nov 30, 2023
f529817
refactor gov one jwks to remove memoization
jack-coggin Dec 1, 2023
dad5b3a
add feature flag to redirect
jack-coggin Dec 1, 2023
1c9fd7c
update sign_in_spec
jack-coggin Dec 1, 2023
0c6fa46
update locales, rename controller method
jack-coggin Dec 4, 2023
93923c3
Merge branch 'one-login' into one-login-bridging-page
jack-coggin Dec 4, 2023
948fa98
use feature flag in application_helper links
jack-coggin Dec 4, 2023
932ba80
nest gov one info locales
jack-coggin Dec 4, 2023
9c8bdda
simplify gov_one_info spec
jack-coggin Dec 4, 2023
a21cd78
remove link assertion from gov_one_info spec
jack-coggin Dec 4, 2023
b915b6a
update authentication_spec
jack-coggin Dec 4, 2023
d1b61eb
update sign_in system spec
jack-coggin Dec 5, 2023
879fbed
merge bridging page and terms and conditions page
jack-coggin Dec 5, 2023
1f0dd1e
wip
jack-coggin Dec 5, 2023
64f70f6
merge account-page changes
jack-coggin Dec 5, 2023
3eb81be
revert change_password spec changes
jack-coggin Dec 5, 2023
9df3ed6
update change_password spec
jack-coggin Dec 6, 2023
3eb13d5
dry up auth service spec
jack-coggin Dec 6, 2023
a59d6c4
update seed_snippets_spec locales count
jack-coggin Dec 6, 2023
8e54060
fix merge conflicts
jack-coggin Dec 6, 2023
39d565c
fix merge conflicts
jack-coggin Dec 6, 2023
2397612
udpate Gemfile.lock
jack-coggin Dec 7, 2023
ae583a6
update seeds_snippets_spec locales
jack-coggin Dec 7, 2023
e19270b
remove print to console
jack-coggin Dec 7, 2023
7d7f435
add request spec for terms and conditions
jack-coggin Dec 8, 2023
d461b51
update account page to use feature flag and add system spec
jack-coggin Dec 11, 2023
776d8d5
update locales content
jack-coggin Dec 11, 2023
76a6e62
refactor id_token verification and update specs
jack-coggin Dec 15, 2023
49a5799
rubocop
jack-coggin Dec 15, 2023
ea0210d
update id token verification
jack-coggin Dec 18, 2023
7154861
rubocop
jack-coggin Dec 18, 2023
d10cee5
update spec
jack-coggin Dec 18, 2023
ba70fee
add feature flag to homepage changes
jack-coggin Dec 18, 2023
6b7bcc4
revert changes to front_page_spec
jack-coggin Dec 18, 2023
273096c
add feature flag to homepage hero
jack-coggin Dec 18, 2023
143491e
add error checks for gov one login auth responses
jack-coggin Dec 19, 2023
c49d448
add markdown file for gov one adr and tech checklist
jack-coggin Dec 20, 2023
f85fd2b
update markdown checkmark for github
jack-coggin Dec 20, 2023
ae48ab9
update one login info markdown and add adr
jack-coggin Dec 20, 2023
e4bc64a
update sitemap
jack-coggin Dec 20, 2023
9bd4c17
fix typo
jack-coggin Dec 20, 2023
40f12ad
revert unwanted adr changes
jack-coggin Dec 20, 2023
409328b
Merge remote-tracking branch 'origin/main' into one-login
jack-coggin Dec 21, 2023
eb41289
update seed snippets spec locales
jack-coggin Dec 21, 2023
27fb9b1
put domain back to app in docker compose
jack-coggin Dec 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .yardopts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
--markup markdown
-
cms/*.md
gov_one_login/*.md
data/*.md
uml/*.md
adr/*.md
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ gem 'bootsnap', require: false

# User authentication
gem 'devise'
gem 'jwt'
gem 'omniauth_openid_connect'
gem 'omniauth-rails_csrf_protection'

# HTML abstraction markup language
gem 'slim-rails'
Expand Down
61 changes: 61 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,21 @@ GEM
tzinfo (~> 2.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
ahoy_matey (5.0.2)
activesupport (>= 6.1)
device_detector (>= 1)
safely_block (>= 0.4)
ast (2.4.2)
attr_required (1.0.1)
backports (3.24.1)
base64 (0.1.1)
bcrypt (3.1.20)
better_errors (2.10.1)
erubi (>= 1.0.0)
rack (>= 0.9.0)
rouge (>= 1.0.0)
bindata (2.4.15)
bindex (0.8.1)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
Expand Down Expand Up @@ -185,6 +188,8 @@ GEM
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-follow_redirects (0.3.0)
faraday (>= 1, < 3)
faraday-net_http (3.0.2)
ffi (1.16.3)
ffi-compiler (1.0.1)
Expand Down Expand Up @@ -277,6 +282,12 @@ GEM
jsbundling-rails (1.2.1)
railties (>= 6.0.0)
json (2.6.3)
json-jwt (1.16.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
faraday (~> 2.0)
faraday-follow_redirects
jwt (2.7.1)
language_server-protocol (3.17.0.3)
launchy (2.5.2)
Expand Down Expand Up @@ -320,6 +331,29 @@ GEM
racc (~> 1.4)
notifications-ruby-client (5.4.0)
jwt (>= 1.5, < 3)
omniauth (2.1.1)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
omniauth_openid_connect (0.7.1)
omniauth (>= 1.9, < 3)
openid_connect (~> 2.2)
openid_connect (2.2.0)
activemodel
attr_required (>= 1.0.0)
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.16)
net-smtp
rack-oauth2 (~> 2.2)
swd (~> 2.0)
tzinfo
validate_email
validate_url
webfinger (~> 2.0)
orm_adapter (0.5.0)
os (1.1.4)
pagy (6.2.0)
Expand Down Expand Up @@ -354,6 +388,15 @@ GEM
raabro (1.4.0)
racc (1.7.3)
rack (2.2.8)
rack-oauth2 (2.2.0)
activesupport
attr_required
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (3.1.0)
rack (~> 2.2, >= 2.2.4)
rack-test (2.1.0)
rack (>= 1.3)
rails (7.0.8)
Expand Down Expand Up @@ -513,6 +556,11 @@ GEM
stimulus-rails (1.3.0)
railties (>= 6.0.0)
stringio (3.0.8)
swd (2.0.2)
activesupport (>= 3)
attr_required (>= 0.0.5)
faraday (~> 2.0)
faraday-follow_redirects
temple (0.10.3)
thor (1.3.0)
tilt (2.3.0)
Expand All @@ -529,6 +577,12 @@ GEM
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.5.0)
validate_email (0.1.6)
activemodel (>= 3.0)
mail (>= 2.2.5)
validate_url (1.0.15)
activemodel (>= 3.0.0)
public_suffix
view_component (3.6.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
Expand All @@ -540,6 +594,10 @@ GEM
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webfinger (2.1.2)
activesupport
faraday (~> 2.0)
faraday-follow_redirects
webrick (1.8.1)
websocket (1.2.10)
websocket-driver (0.7.6)
Expand Down Expand Up @@ -598,7 +656,10 @@ DEPENDENCIES
importmap-rails
jbuilder
jsbundling-rails
jwt
launchy
omniauth-rails_csrf_protection
omniauth_openid_connect
pg
pry-byebug
pry-doc
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ The status of GovUK notify can be checked here: <https://status.notifications.se
For more information the Notify team can be contacted here: <https://www.notifications.service.gov.uk/support>,
or in the UK Government digital slack workspace in the `#govuk-notify` channel.

---

# One Login

<https://signin.integration.account.gov.uk/sign-in-or-create>

---

Expand Down
19 changes: 19 additions & 0 deletions adr/0017-gov-one-login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# GOV.UK One Login

* Status: accepted

## Context and Problem Statement
The integration of GOV.UK One Login user authentication is a requirement of the service going live. This single sign on will allow users to login to the service using their GOV.UK One Login account.

## Decision Drivers
* GOV.UK One Login reccomends using an off-the-shelf OIDC library
* We currently use Devise for user authentication
* Omniauth would allow us to use Devise and integrate with GOV.UK One Login

## Considered Options
* [omniauth](https://github.com/omniauth/omniauth)
* [omniauth_openid_connect](https://github.com/omniauth/omniauth_openid_connect)

## Decision Outcome
Chosen option: [omniauth_openid_connect](https://github.com/omniauth/omniauth_openid_connect)

1 change: 1 addition & 0 deletions adr/ADR.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This log lists the architectural decisions for EYFS Recovery
* [ADR-0014](0014-user-tracking.md) - Use Hotjar for tracking user journeys
* [ADR-0015](0015-background-jobs.md) - Use Que for processing background jobs
* [ADR-0016](0016-devise-security-and-pwned-passwords-gems.md) - Use Devise Security and Devise Pwned Password gems
* [ADR-0017](0017-gov-one-login.md) - GOV.UK One Login

<!-- adrlogstop -->

Expand Down
4 changes: 4 additions & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,7 @@ ul>li>ul>li {
#available h2 .govuk-tag {
margin-left: govuk-spacing(1);
}

.text-secondary {
color: $govuk-secondary-text-colour;
}
6 changes: 5 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ def authenticate_registered_user!
authenticate_user! unless user_signed_in?
return true if current_user.registration_complete?

redirect_to edit_registration_name_path, notice: 'Please complete registration'
if Rails.application.gov_one_login?
redirect_to edit_registration_terms_and_conditions_path, notice: 'Please complete registration'
else
redirect_to edit_registration_name_path, notice: 'Please complete registration'
end
end

def configure_permitted_parameters
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/gov_one_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class GovOneController < ApplicationController
layout 'hero'

def show
redirect_to my_modules_path if current_user
end
end
35 changes: 35 additions & 0 deletions app/controllers/registration/terms_and_conditions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Registration
class TermsAndConditionsController < BaseController
def edit; end

def update
form.terms_and_conditions_agreed_at = user_params[:terms_and_conditions_agreed_at]

if form.save
if current_user.registration_complete?
redirect_to user_path, notice: t(:details_updated)
else
redirect_to edit_registration_name_path
end
else
render :edit, status: :unprocessable_entity
end
end

private

# @return [Hash]
def user_params
params.require(:user).permit(:terms_and_conditions_agreed_at)
end

# @return [Registration::NameForm]
def form
@form ||=
TermsAndConditionsForm.new(
user: current_user,
terms_and_conditions_agreed_at: current_user.terms_and_conditions_agreed_at,
)
end
end
end
104 changes: 104 additions & 0 deletions app/controllers/users/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Controller handling OmniAuth callbacks for user authentication.
# This controller uses the GovOneAuthService to retrieve user informaton and create or sign in an user based on the email address or gov one id

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# This method is called by Devise after successful Gov One Login authentication
# @return [nil]
def openid_connect
if params['error'].present?
Rails.logger.error("Authentication error: #{params['error']}, #{params['error_description']}")
return error_redirect
end

return error_redirect unless session_params? && valid_params?

auth_service = GovOneAuthService.new(code: params['code'])
tokens_response = auth_service.tokens
return error_redirect unless valid_tokens?(tokens_response)

id_token = auth_service.decode_id_token(tokens_response['id_token'])[0]
return error_redirect unless valid_id_token?(id_token)

session[:id_token] = tokens_response['id_token']
gov_one_id = id_token['sub']

user_info_response = auth_service.user_info(tokens_response['access_token'])
email = user_info_response['email']
return error_redirect unless valid_user_info?(user_info_response, gov_one_id)

gov_user = User.find_or_create_from_gov_one(email: email, gov_one_id: gov_one_id)

delete_session_params
sign_in_and_redirect gov_user if gov_user
end

private

# @return [Boolean]
def valid_params?
params['code'].present? && params['state'].present? && params['state'] == session[:gov_one_auth_state]
end

# @return [Boolean]
def session_params?
session[:gov_one_auth_state].present? && session[:gov_one_auth_nonce].present?
end

# @param tokens_response [Hash]
# @return [Boolean]
def valid_tokens?(tokens_response)
tokens_response.present? &&
tokens_response['access_token'].present? &&
tokens_response['id_token'].present? &&
tokens_response['error'].blank?
end

# @param id_token [Hash]
# @return [Boolean]
def valid_id_token?(id_token)
id_token.present? &&
id_token['nonce'] == session[:gov_one_auth_nonce] &&
id_token['iss'] == "#{Rails.application.config.gov_one_base_uri}/" &&
id_token['aud'] == Rails.application.config.gov_one_client_id
end

# @param user_info_response [Hash]
# @return [Boolean]
def valid_user_info?(user_info_response, gov_one_id)
user_info_response.present? &&
user_info_response['email'].present? &&
user_info_response['sub'] == gov_one_id &&
user_info_response['error'].blank?
end

# @return [nil]
def error_redirect
flash[:alert] = 'There was a problem signing in. Please try again.'
redirect_to root_path
end

# @return [nil]
def delete_session_params
session.delete(:gov_one_auth_state)
session.delete(:gov_one_auth_nonce)
end

# @return [String]
def after_sign_in_path_for(resource)
if resource.registration_complete?
if resource.display_whats_new?
resource.display_whats_new = false
resource.save!
static_path('whats-new')
elsif !resource.email_preferences_complete?
static_path('email-preferences')
else
my_modules_path
end
elsif resource.private_beta_registration_complete?
static_path('new-registration')
else
edit_registration_terms_and_conditions_path
end
end
end
2 changes: 2 additions & 0 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def after_sign_in_path_for(resource)
end
elsif resource.private_beta_registration_complete?
static_path('new-registration')
elsif Rails.application.gov_one_login?
edit_registration_terms_and_conditions_path
else
edit_registration_name_path
end
Expand Down
14 changes: 14 additions & 0 deletions app/forms/registration/terms_and_conditions_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Registration
class TermsAndConditionsForm < BaseForm
attr_accessor :terms_and_conditions_agreed_at

validates :terms_and_conditions_agreed_at, presence: true

# @return [Boolean]
def save
return false unless valid?

user.update!(terms_and_conditions_agreed_at: terms_and_conditions_agreed_at)
end
end
end
Loading
Loading