diff --git a/.env.example b/.env.example index 380f3789d..ae0b13f45 100644 --- a/.env.example +++ b/.env.example @@ -82,15 +82,10 @@ E2E=true # Deployment environment ENVIRONMENT= +# Gov One Authentication GOV_ONE_LOGIN=true - -# Base URI for Gov One Login requests GOV_ONE_BASE_URI=https://oidc.integration.account.gov.uk -# Redirect URIs for Gov One Login redirects -# Replace localhost:3000 with the correct application root path -GOV_ONE_REDIRECT_URI=http://localhost:3000/users/auth/openid_connect/callback -GOV_ONE_LOGOUT_REDIRECT_URI=http://localhost:3000/users/sign_out # DISPLAY SERVICE_UNAVAILABLE PAGE MAINTENANCE = true \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cea13948..919fd8ca5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,8 +34,6 @@ jobs: DOMAIN: recovery.app BOT_TOKEN: bot_token GOV_ONE_BASE_URI: https://oidc.test.account.gov.uk - GOV_ONE_REDIRECT_URI: https://recovery.app/users/auth/openid_connect/callback - GOV_ONE_LOGOUT_REDIRECT_URI: https://recovery.app/users/sign_out services: postgres: diff --git a/app/helpers/gov_one_helper.rb b/app/helpers/gov_one_helper.rb index 488e8d8fc..575622145 100644 --- a/app/helpers/gov_one_helper.rb +++ b/app/helpers/gov_one_helper.rb @@ -7,12 +7,12 @@ def login_uri client_id: Rails.application.config.gov_one_client_id, nonce: SecureRandom.uuid, state: SecureRandom.uuid, - redirect_uri: Rails.application.config.gov_one_redirect_uri, + redirect_uri: GovOneAuthService::CALLBACKS[:login], } session[:gov_one_auth_state] = params[:state] - gov_one_uri('authorize', params).to_s + gov_one_uri(:login, params).to_s end # @return [String] @@ -20,19 +20,19 @@ def logout_uri params = { id_token_hint: session[:id_token], state: SecureRandom.uuid, - post_logout_redirect_uri: Rails.application.config.gov_one_logout_redirect_uri, + post_logout_redirect_uri: GovOneAuthService::CALLBACKS[:logout], } - gov_one_uri('logout', params).to_s + gov_one_uri(:logout, params).to_s end private - # @param endpoint [String] + # @param endpoint [Symbol] # @param params [Hash] # @return [URI::HTTP, URI::HTTPS] def gov_one_uri(endpoint, params) - uri = URI.parse("#{ENV['GOV_ONE_BASE_URI']}/#{endpoint}") + uri = URI.parse(GovOneAuthService::ENDPOINTS[endpoint]) uri.query = URI.encode_www_form(params) uri end diff --git a/app/services/gov_one_auth_service.rb b/app/services/gov_one_auth_service.rb index 93029da85..e806fc691 100644 --- a/app/services/gov_one_auth_service.rb +++ b/app/services/gov_one_auth_service.rb @@ -1,22 +1,34 @@ -# Service for interacting with Gov One Login -# This service is initialised with an authorisation code and can be used to: +# # - exchange an authorisation code for tokens (access and id) # - exchange an access token for user info # - decode an id token to get the user's gov one id # -# More information on the Gov One Login integration environment can be found here: -# https://docs.sign-in.service.gov.uk/integrate-with-integration-environment/ - +# @see https://docs.sign-in.service.gov.uk/ class GovOneAuthService + # @return [Hash{Symbol => String}] + CALLBACKS = { + login: "#{Rails.application.config.service_url}/users/auth/openid_connect/callback", + logout: "#{Rails.application.config.service_url}/users/sign_out", + }.freeze + + # @return [Hash{Symbol => String}] + ENDPOINTS = { + login: "#{Rails.application.config.gov_one_base_uri}/authorize", + logout: "#{Rails.application.config.gov_one_base_uri}/logout", + token: "#{Rails.application.config.gov_one_base_uri}/token", + userinfo: "#{Rails.application.config.gov_one_base_uri}/userinfo", + jwks: "#{Rails.application.config.gov_one_base_uri}/.well-known/jwks.json", + }.freeze + extend Dry::Initializer - option :code, Types::String + option :code, Types::Strict::String + # POST /token # @return [Hash] def tokens - http = build_http(token_uri) - - token_request = Net::HTTP::Post.new(token_uri.path, { 'Content-Type' => 'application/x-www-form-urlencoded' }) + uri, http = build_http(ENDPOINTS[:token]) + token_request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/x-www-form-urlencoded' }) token_request.set_form_data(token_body) token_response = http.request(token_request) @@ -26,12 +38,12 @@ def tokens {} end + # GET /userinfo # @param access_token [String] # @return [Hash] def user_info(access_token) - http = build_http(userinfo_uri) - - userinfo_request = Net::HTTP::Get.new(userinfo_uri.path, { 'Authorization' => "Bearer #{access_token}" }) + uri, http = build_http(ENDPOINTS[:userinfo]) + userinfo_request = Net::HTTP::Get.new(uri.path, { 'Authorization' => "Bearer #{access_token}" }) userinfo_response = http.request(userinfo_request) JSON.parse(userinfo_response.body) @@ -52,34 +64,18 @@ def decode_id_token(token) private - # @return [URI] - def token_uri - gov_one_uri('token') - end - - # @return [URI] - def userinfo_uri - gov_one_uri('userinfo') - end - - # @param endpoint [String] - # @return [URI] - def gov_one_uri(endpoint) - URI.parse("#{Rails.application.config.gov_one_base_uri}/#{endpoint}") - end - - # @param uri [URI] - # @return [Net::HTTP] - def build_http(uri) + # @param address [String] + # @return [Array] + def build_http(address) + uri = URI.parse(address) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true unless Rails.env.test? - http + [uri, http] end # @return [Hash] def jwks - uri = gov_one_uri('.well-known/jwks.json') - http = build_http(uri) + uri, http = build_http(ENDPOINTS[:jwks]) response = http.request(Net::HTTP::Get.new(uri.path)) JSON.parse(response.body) end @@ -89,7 +85,7 @@ def jwt_assertion rsa_private = OpenSSL::PKey::RSA.new(Rails.application.config.gov_one_private_key) payload = { - aud: token_uri.to_s, + aud: ENDPOINTS[:token], iss: Rails.application.config.gov_one_client_id, sub: Rails.application.config.gov_one_client_id, exp: Time.zone.now.to_i + 5 * 60, @@ -105,7 +101,7 @@ def token_body { grant_type: 'authorization_code', code: code, - redirect_uri: ENV['GOV_ONE_REDIRECT_URI'], + redirect_uri: CALLBACKS[:login], client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', client_assertion: jwt_assertion, } diff --git a/app/views/gov_one/info.html.slim b/app/views/gov_one/info.html.slim index da7a2602f..309f98ce8 100644 --- a/app/views/gov_one/info.html.slim +++ b/app/views/gov_one/info.html.slim @@ -1,14 +1,14 @@ = render 'learning/cms_debug' - content_for :page_title do - = html_title t('gov-one.info.title') + = html_title t('gov_one.title') .govuk-grid-row .govuk-grid-column-one-half - = m('gov-one-info.body') + = m('gov_one.body') - if current_user - = govuk_button_link_to t('gov-one-info.sign-out-button'), logout_uri + = govuk_button_link_to t('gov_one.links.sign_out'), logout_uri - else - = govuk_button_link_to t('gov-one-info.sign-in-button'), login_uri + = govuk_button_link_to t('gov_one.links.sign_in'), login_uri \ No newline at end of file diff --git a/config/application.rb b/config/application.rb index 02cdc1841..62ccd629c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,6 +32,8 @@ class Application < Rails::Application end config.service_name = 'Early years child development training' + config.service_url = (Rails.env.production? ? 'https://' : 'http://') + ENV.fetch('DOMAIN', 'child-development-training') + config.internal_mailbox = ENV.fetch('INTERNAL_MAILBOX', 'child-development.training@education.gov.uk') config.middleware.use Grover::Middleware config.active_record.yaml_column_permitted_classes = [Symbol] @@ -69,11 +71,9 @@ class Application < Rails::Application config.contentful_environment = ENV.fetch('CONTENTFUL_ENVIRONMENT', credentials.dig(:contentful, :environment)) # Gov one - config.gov_one_base_uri = ENV.fetch('GOV_ONE_BASE_URI', '#GOV_ONE_BASE_URI_env_var_missing') - config.gov_one_redirect_uri = ENV.fetch('GOV_ONE_REDIRECT_URI', '#GOV_ONE_REDIRECT_URI_env_var_missing') - config.gov_one_logout_redirect_uri = ENV.fetch('GOV_ONE_LOGOUT_REDIRECT_URI', '#GOV_ONE_LOGOUT_REDIRECT_URI_env_var_missing') - config.gov_one_private_key = ENV.fetch('GOV_ONE_PRIVATE_KEY', credentials.dig(:gov_one, :private_key)) - config.gov_one_client_id = ENV.fetch('GOV_ONE_CLIENT_ID', credentials.dig(:gov_one, :client_id)) + config.gov_one_base_uri = ENV.fetch('GOV_ONE_BASE_URI', '#GOV_ONE_BASE_URI_env_var_missing') + config.gov_one_private_key = ENV.fetch('GOV_ONE_PRIVATE_KEY', credentials.dig(:gov_one, :private_key)) + config.gov_one_client_id = ENV.fetch('GOV_ONE_CLIENT_ID', credentials.dig(:gov_one, :client_id)) # @return [Boolean] def live? diff --git a/config/locales/en.yml b/config/locales/en.yml index e3f7c11b4..776d69931 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -571,15 +571,15 @@ en: %{criteria} # /gov-one/info - gov-one: - info: - title: Gov One Login - body: | - # Gov One Login - - This is some information about Gov One Login... - sign-in-button: Sign in with Gov One Login - sign-out-button: Sign out of Gov One Login + gov_one: + title: Gov One Login + body: | + # Gov One Login + + This is some information about Gov One Login... + links: + sign_in: Sign in with Gov One Login + sign_out: Sign out of Gov One Login # /settings/cookie-policy cookie_policy: diff --git a/config/sitemap.rb b/config/sitemap.rb index bfdaecb7f..901358c90 100644 --- a/config/sitemap.rb +++ b/config/sitemap.rb @@ -14,8 +14,7 @@ # } # ] # -protocol = Rails.env.production? ? 'https://' : 'http://' -SitemapGenerator::Sitemap.default_host = protocol + ENV['DOMAIN'] +SitemapGenerator::Sitemap.default_host = Rails.application.config.service_url SitemapGenerator::Sitemap.compress = false # Run this command to update /public/sitemap.xml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 6f104f3b5..8e3a4eeed 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -19,12 +19,9 @@ services: # app config - DATABASE_URL=postgres://postgres:password@db:5432/early_years_foundation_recovery_development - RAILS_ENV=development - - DOMAIN=app:3000 + - DOMAIN=localhost:3000 # put back to app - RAILS_SERVE_STATIC_FILES=true - # gov one login - - GOV_ONE_BASE_URI=https://oidc.integration.account.gov.uk - - GOV_ONE_REDIRECT_URI=http://localhost:3000/users/auth/openid_connect/callback - - GOV_ONE_LOGOUT_REDIRECT_URI=http://localhost:3000/users/sign_out + - GOV_ONE_BASE_URI=https://oidc.integration.account.gov.uk volumes: - .:/srv tty: true diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 7b61fe942..47551644c 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -15,7 +15,5 @@ services: - BOT_TOKEN=bot_token - TIMEOUT_MINUTES=25 - GOV_ONE_BASE_URI=https://oidc.test.account.gov.uk - - GOV_ONE_REDIRECT_URI=http://recovery.app/users/auth/openid_connect/callback - - GOV_ONE_LOGOUT_REDIRECT_URI=http://recovery.app/users/sign_out tty: true stdin_open: true