authorize: support authenticating with idp tokens (#5484)

* identity: add support for verifying access and identity tokens

* allow overriding with policy option

* authenticate: add verify endpoints

* wip

* implement session creation

* add verify test

* implement idp token login

* fix tests

* add pr permission

* make session ids route-specific

* rename method

* add test

* add access token test

* test for newUserFromIDPClaims

* more tests

* make the session id per-idp

* use type for

* add test

* remove nil checks
This commit is contained in:
Caleb Doxsey 2025-02-18 13:02:06 -07:00 committed by GitHub
parent 6e22b7a19a
commit b9fd926618
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 2791 additions and 885 deletions

View file

@ -15,6 +15,7 @@ import (
"os"
"path/filepath"
"reflect"
"slices"
"strings"
"time"
@ -152,12 +153,13 @@ type Options struct {
// Identity provider configuration variables as specified by RFC6749
// https://openid.net/specs/openid-connect-basic-1_0.html#RFC6749
ClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"`
ClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"`
ClientSecretFile string `mapstructure:"idp_client_secret_file" yaml:"idp_client_secret_file,omitempty"`
Provider string `mapstructure:"idp_provider" yaml:"idp_provider,omitempty"`
ProviderURL string `mapstructure:"idp_provider_url" yaml:"idp_provider_url,omitempty"`
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
ClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"`
ClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"`
ClientSecretFile string `mapstructure:"idp_client_secret_file" yaml:"idp_client_secret_file,omitempty"`
Provider string `mapstructure:"idp_provider" yaml:"idp_provider,omitempty"`
ProviderURL string `mapstructure:"idp_provider_url" yaml:"idp_provider_url,omitempty"`
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
IDPAccessTokenAllowedAudiences *[]string `mapstructure:"idp_access_token_allowed_audiences" yaml:"idp_access_token_allowed_audiences,omitempty"`
// RequestParams are custom request params added to the signin request as
// part of an Oauth2 code flow.
@ -194,6 +196,13 @@ type Options struct {
// List of JWT claims to insert as x-pomerium-claim-* headers on proxied requests
JWTClaimsHeaders JWTClaimHeaders `mapstructure:"jwt_claims_headers" yaml:"jwt_claims_headers,omitempty"`
// BearerTokenFormat indicates how authorization bearer tokens are interepreted. Possible values:
// - "default": Only Bearer tokens prefixed with Pomerium- will be interpreted by Pomerium.
// - "idp_access_token": The Bearer token will be interpreted as an IdP access token.
// - "idp_identity_token": The Bearer token will be interpreted as an IdP identity token.
// When unset "default" will be used.
BearerTokenFormat *BearerTokenFormat `mapstructure:"bearer_token_format" yaml:"bearer_token_format,omitempty"`
// Allowlist of group names/IDs to include in the Pomerium JWT.
JWTGroupsFilter JWTGroupsFilter
@ -1487,6 +1496,12 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
set(&o.ProviderURL, settings.IdpProviderUrl)
setSlice(&o.Scopes, settings.Scopes)
setMap(&o.RequestParams, settings.RequestParams)
if settings.IdpAccessTokenAllowedAudiences != nil {
values := slices.Clone(settings.IdpAccessTokenAllowedAudiences.Values)
o.IDPAccessTokenAllowedAudiences = &values
} else {
o.IDPAccessTokenAllowedAudiences = nil
}
setSlice(&o.AuthorizeURLStrings, settings.AuthorizeServiceUrls)
set(&o.AuthorizeInternalURLString, settings.AuthorizeInternalServiceUrl)
set(&o.OverrideCertificateName, settings.OverrideCertificateName)
@ -1495,6 +1510,7 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
set(&o.SigningKey, settings.SigningKey)
setMap(&o.SetResponseHeaders, settings.SetResponseHeaders)
setMap(&o.JWTClaimsHeaders, settings.JwtClaimsHeaders)
o.BearerTokenFormat = BearerTokenFormatFromPB(settings.BearerTokenFormat)
if len(settings.JwtGroupsFilter) > 0 {
o.JWTGroupsFilter = NewJWTGroupsFilter(settings.JwtGroupsFilter)
}
@ -1591,6 +1607,13 @@ func (o *Options) ToProto() *config.Config {
copySrcToOptionalDest(&settings.IdpProviderUrl, &o.ProviderURL)
settings.Scopes = o.Scopes
settings.RequestParams = o.RequestParams
if o.IDPAccessTokenAllowedAudiences != nil {
settings.IdpAccessTokenAllowedAudiences = &config.Settings_StringList{
Values: slices.Clone(*o.IDPAccessTokenAllowedAudiences),
}
} else {
settings.IdpAccessTokenAllowedAudiences = nil
}
settings.AuthorizeServiceUrls = o.AuthorizeURLStrings
copySrcToOptionalDest(&settings.AuthorizeInternalServiceUrl, &o.AuthorizeInternalURLString)
copySrcToOptionalDest(&settings.OverrideCertificateName, &o.OverrideCertificateName)
@ -1599,6 +1622,7 @@ func (o *Options) ToProto() *config.Config {
copySrcToOptionalDest(&settings.SigningKey, valueOrFromFileBase64(o.SigningKey, o.SigningKeyFile))
settings.SetResponseHeaders = o.SetResponseHeaders
settings.JwtClaimsHeaders = o.JWTClaimsHeaders
settings.BearerTokenFormat = o.BearerTokenFormat.ToPB()
settings.JwtGroupsFilter = o.JWTGroupsFilter.ToSlice()
copyOptionalDuration(&settings.DefaultUpstreamTimeout, o.DefaultUpstreamTimeout)
copySrcToOptionalDest(&settings.MetricsAddress, &o.MetricsAddr)