mirror of
https://github.com/h44z/wg-portal.git
synced 2026-05-28 17:06:18 +00:00
feat: add support for PKCE (#686)
This commit is contained in:
@@ -47,6 +47,11 @@ const (
|
||||
AuthenticatorTypeOidc AuthenticatorType = "oidc"
|
||||
)
|
||||
|
||||
const (
|
||||
pkceMethodS256 = "S256" // SHA-256 hashing
|
||||
pkceMethodPlain = "plain" // plain text
|
||||
)
|
||||
|
||||
// AuthenticatorOauth is the interface for all OAuth authenticators.
|
||||
type AuthenticatorOauth interface {
|
||||
// GetName returns the name of the authenticator.
|
||||
@@ -70,6 +75,10 @@ type AuthenticatorOauth interface {
|
||||
GetAllowedUserGroups() []string
|
||||
// GetLogoutUrl returns an IdP logout URL if supported by the provider.
|
||||
GetLogoutUrl(idTokenHint, postLogoutRedirectUri string) (string, bool)
|
||||
// PKCEAuthCodeOptions returns PKCE options for the authorization request and the verifier for the token exchange.
|
||||
PKCEAuthCodeOptions() ([]oauth2.AuthCodeOption, string)
|
||||
// PKCETokenOptions returns PKCE options for the token exchange.
|
||||
PKCETokenOptions(verifier string) []oauth2.AuthCodeOption
|
||||
}
|
||||
|
||||
// AuthenticatorLdap is the interface for all LDAP authenticators.
|
||||
@@ -448,30 +457,34 @@ func (a *Authenticator) passwordAuthentication(
|
||||
|
||||
// OauthLoginStep1 starts the oauth authentication flow by returning the authentication URL, state and nonce.
|
||||
func (a *Authenticator) OauthLoginStep1(_ context.Context, providerId string) (
|
||||
authCodeUrl, state, nonce string,
|
||||
authCodeUrl, state, nonce, codeVerifier string,
|
||||
err error,
|
||||
) {
|
||||
oauthProvider, ok := a.oauthAuthenticators[providerId]
|
||||
if !ok {
|
||||
return "", "", "", fmt.Errorf("missing oauth provider %s", providerId)
|
||||
return "", "", "", "", fmt.Errorf("missing oauth provider %s", providerId)
|
||||
}
|
||||
|
||||
// Prepare authentication flow, set state cookies
|
||||
state, err = a.randString(16)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("failed to generate state: %w", err)
|
||||
return "", "", "", "", fmt.Errorf("failed to generate state: %w", err)
|
||||
}
|
||||
|
||||
// Generate PKCE code verifier and challenge if enabled. Otherwise, options will be empty.
|
||||
authCodeOptions, codeVerifier := oauthProvider.PKCEAuthCodeOptions()
|
||||
|
||||
switch oauthProvider.GetType() {
|
||||
case AuthenticatorTypeOAuth:
|
||||
authCodeUrl = oauthProvider.AuthCodeURL(state)
|
||||
authCodeUrl = oauthProvider.AuthCodeURL(state, authCodeOptions...)
|
||||
case AuthenticatorTypeOidc:
|
||||
nonce, err = a.randString(16)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("failed to generate nonce: %w", err)
|
||||
return "", "", "", "", fmt.Errorf("failed to generate nonce: %w", err)
|
||||
}
|
||||
|
||||
authCodeUrl = oauthProvider.AuthCodeURL(state, oidc.Nonce(nonce))
|
||||
authCodeOptions = append(authCodeOptions, oidc.Nonce(nonce))
|
||||
authCodeUrl = oauthProvider.AuthCodeURL(state, authCodeOptions...)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -531,13 +544,16 @@ func isAnyAllowedUserGroup(userGroups, allowedUserGroups []string) bool {
|
||||
|
||||
// OauthLoginStep2 finishes the oauth authentication flow by exchanging the code for an access token and
|
||||
// fetching the user information.
|
||||
func (a *Authenticator) OauthLoginStep2(ctx context.Context, providerId, nonce, code string) (*domain.User, string, error) {
|
||||
func (a *Authenticator) OauthLoginStep2(
|
||||
ctx context.Context,
|
||||
providerId, nonce, code, codeVerifier string,
|
||||
) (*domain.User, string, error) {
|
||||
oauthProvider, ok := a.oauthAuthenticators[providerId]
|
||||
if !ok {
|
||||
return nil, "", fmt.Errorf("missing oauth provider %s", providerId)
|
||||
}
|
||||
|
||||
oauth2Token, err := oauthProvider.Exchange(ctx, code)
|
||||
oauth2Token, err := oauthProvider.Exchange(ctx, code, oauthProvider.PKCETokenOptions(codeVerifier)...)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("unable to exchange code: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user