diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fa2df03..0058991 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -15,6 +15,7 @@ en: openid_connect_overrides_email: "On every login, override the user's email using the openid-connect value. Works the same as the `auth_overrides_email` setting, but is specific to OpenID Connect logins." openid_connect_claims: "Explicitly define the claims for use with providers that don't pass data back based on scopes. (JSON)" openid_connect_match_by_email: "Use email address to match OpenID Connect authentications to existing Discourse user accounts." + openid_connect_use_pkce: "Enable Proof Key for Code Exchange (PKCE) for OpenID Connect authentication." login: omniauth_error: openid_connect_discovery_error: Unable to fetch configuration from identity provider. Please try again. diff --git a/config/settings.yml b/config/settings.yml index 2f563af..2452fc7 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -35,3 +35,5 @@ discourse_openid_connect: textarea: true openid_connect_match_by_email: default: true + openid_connect_use_pkce: + default: false diff --git a/lib/openid_connect_authenticator.rb b/lib/openid_connect_authenticator.rb index 9496ca3..7bb870a 100644 --- a/lib/openid_connect_authenticator.rb +++ b/lib/openid_connect_authenticator.rb @@ -1,4 +1,6 @@ # frozen_string_literal: true +require "base64" +require "openssl" class OpenIDConnectAuthenticator < Auth::ManagedAuthenticator def name @@ -107,6 +109,14 @@ def register_middleware(omniauth) passthrough_authorize_options: SiteSetting.openid_connect_authorize_parameters.split("|"), claims: SiteSetting.openid_connect_claims, + pkce: SiteSetting.openid_connect_use_pkce, + pkce_options: { + code_verifier: -> { generate_code_verifier }, + code_challenge: ->(code_verifier) do + generate_code_challenge(code_verifier) + end, + code_challenge_method: "S256", + }, ) opts[:client_options][:connection_opts] = { @@ -128,6 +138,14 @@ def register_middleware(omniauth) } end + def generate_code_verifier + Base64.urlsafe_encode64(OpenSSL::Random.random_bytes(32)).tr("=", "") + end + + def generate_code_challenge(code_verifier) + Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier)).tr("+/", "-_").tr("=", "") + end + def request_timeout_seconds GlobalSetting.openid_connect_request_timeout_seconds end