Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions app/controllers/one_login_jwks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class OneLoginJwksController < ApplicationController
def show
jwk = Rails.application.config.x.one_login.public_key_jwk
render json: JWT::JWK::Set.new(jwk).export
end
end
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,7 @@ class Application < Rails::Application

I18n.available_locales = %i[en cy]
I18n.default_locale = :en

JWT.configuration.jwk.kid_generator_type = :rfc7638_thumbprint
end
end
5 changes: 4 additions & 1 deletion config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
private_key_pem = private_key_pem.gsub('\n', "\n")

private_key = OpenSSL::PKey::RSA.new(private_key_pem)

public_key_jwk = JWT::JWK.new(private_key.public_key, use: "sig")
Rails.application.config.x.one_login.public_key_jwk = public_key_jwk
end

Rails.application.config.middleware.use OmniAuth::Builder do
Expand All @@ -16,7 +19,7 @@
idp_base_url: Settings.govuk_one_login.base_url,
private_key: private_key,
redirect_uri: "/auth/govuk_one_login/callback",
private_key_kid: "", # TODO: we'll need to set this when we switch to using a JWKS endpoint
private_key_kid: public_key_jwk&.kid,
signing_algorithm: "ES256",
scope: "openid email",
ui_locales: "en cy",
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
get "/submission" => "submission_status#status", as: :status
get "/.well-known/security.txt" => redirect("https://vulnerability-reporting.service.security.gov.uk/.well-known/security.txt")

get "/govuk-one-login-jwks", to: "one_login_jwks#show", as: :one_login_jwks

form_id_constraints = { form_id: UrlPatterns::FORM_ID_REGEX }
form_constraints = {
**form_id_constraints,
Expand Down
60 changes: 60 additions & 0 deletions spec/initializers/omniauth_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require "rails_helper"

RSpec.describe "omniauth initializer" do
let(:initializer_path) { Rails.root.join("config/initializers/omniauth.rb") }

let(:one_login_settings) do
double(
private_key: private_key_setting,
client_id: "test-client-id",
base_url: "https://oidc.integration.account.gov.uk",
)
end

before do
allow(Settings).to receive(:govuk_one_login).and_return(one_login_settings)
allow(Rails.application.config.middleware).to receive(:use)
allow(OmniAuth::GovukOneLogin::IdpConfiguration).to receive(:new).and_return(instance_double(OmniAuth::GovukOneLogin::IdpConfiguration))
end

around do |example|
original_public_key_jwk = Rails.application.config.x.one_login.public_key_jwk
original_idp_configuration = Rails.application.config.x.one_login.idp_configuration
example.run
ensure
Rails.application.config.x.one_login.public_key_jwk = original_public_key_jwk
Rails.application.config.x.one_login.idp_configuration = original_idp_configuration
end

context "when the private key is present" do
let(:rsa_private_key) { OpenSSL::PKey::RSA.generate(2048) }
let(:private_key_setting) { Base64.encode64(rsa_private_key.to_pem) }

before { load initializer_path }

it "sets Rails.application.config.x.one_login.public_key_jwk" do
expect(Rails.application.config.x.one_login.public_key_jwk).to be_a(JWT::JWK::RSA)
end

it "sets the JWK use to 'sig'" do
expect(Rails.application.config.x.one_login.public_key_jwk[:use]).to eq("sig")
end

it "sets the JWK kid" do
expect(Rails.application.config.x.one_login.public_key_jwk.kid).to be_a(String)
end
end

context "when the private key is absent" do
let(:private_key_setting) { nil }

before do
Rails.application.config.x.one_login.public_key_jwk = nil
load initializer_path
end

it "does not set Rails.application.config.x.one_login.public_key_jwk" do
expect(Rails.application.config.x.one_login.public_key_jwk).to be_nil
end
end
end
34 changes: 34 additions & 0 deletions spec/requests/one_login_jwks_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "rails_helper"
require "base64"

RSpec.describe OneLoginJwksController, type: :request do
describe "GET #show" do
before do
public_key = OpenSSL::PKey::RSA.generate(2048).public_key
public_key_jwk = JWT::JWK.new(public_key, use: "sig")

one_login_config = ActiveSupport::OrderedOptions.new
one_login_config.public_key_jwk = public_key_jwk

allow(Rails.application.config.x).to receive(:one_login).and_return(one_login_config)
end

it "returns the JWKS JSON" do
get one_login_jwks_path

expect(response).to have_http_status(:ok)
expect(response.content_type).to eq("application/json; charset=utf-8")
expect(response.parsed_body).to match({
"keys" => [
{
"e" => "AQAB",
"kty" => "RSA",
"use" => "sig",
"kid" => a_kind_of(String),
"n" => a_kind_of(String),
},
],
})
end
end
end