diff --git a/docs/docs/configuration/alpha_config.md b/docs/docs/configuration/alpha_config.md index 680741ba..c4b18edd 100644 --- a/docs/docs/configuration/alpha_config.md +++ b/docs/docs/configuration/alpha_config.md @@ -312,6 +312,19 @@ They may change between releases without notice. | `metricsServer` | _[Server](#server)_ | MetricsServer is used to configure the HTTP(S) server for metrics.
You may choose to run both HTTP and HTTPS servers simultaneously.
This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
To use the secure server you must configure a TLS certificate and key. | | `providers` | _[Providers](#providers)_ | Providers is used to configure your provider. **Multiple-providers is not
yet working.** [This feature is tracked in
#925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926) | +### AppleOptions + +(**Appears on:** [Provider](#provider)) + + + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `teamID` | _string_ | TeamID is the 10-character Apple Developer Team ID | +| `keyID` | _string_ | KeyID is the 10-character identifier for the private key | +| `privateKey` | _string_ | PrivateKey is the PEM-encoded ES256 private key content (from .p8 file) | +| `privateKeyFile` | _string_ | PrivateKeyFile is the path to the .p8 private key file | + ### AzureOptions (**Appears on:** [Provider](#provider)) @@ -552,6 +565,7 @@ character. | `audienceClaims` | _[]string_ | AudienceClaim allows to define any claim that is verified against the client id
By default `aud` claim is used for verification. | | `extraAudiences` | _[]string_ | ExtraAudiences is a list of additional audiences that are allowed
to pass verification in addition to the client id. | | `enabledSigningAlgs` | _[]string_ | EnabledSigningAlgs is a list of allowed JWT signing algorithms.
When discovery is enabled, the effective set is the intersection
between this list and the provider's discovered supported algorithms.
By default `RS256` is used if nothing has been discovered or specified. | +| `authStyle` | _string_ | AuthStyle specifies how the endpoint wants the client ID & client secret sent.
Possible values are:
- "inParams" (or "params"): sends credentials in the POST body as application/x-www-form-urlencoded parameters
- "inHeader" (or "header"): sends credentials using HTTP Basic Authorization
- "" (empty, default): auto-detect by trying both ways
Some providers like Apple require "inParams". | ### Provider @@ -574,6 +588,7 @@ Provider holds all configuration for a single provider | `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. | | `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider
or providers utilize OIDC configurations. | | `loginGovConfig` | _[LoginGovOptions](#logingovoptions)_ | LoginGovConfig holds all configurations for LoginGov provider. | +| `appleConfig` | _[AppleOptions](#appleoptions)_ | AppleConfig holds all configurations for Apple provider. | | `id` | _string_ | ID should be a unique identifier for the provider.
This value is required for all providers. | | `provider` | _[ProviderType](#providertype)_ | Type is the OAuth provider
must be set from the supported providers group,
otherwise 'Google' is set as default | | `name` | _string_ | Name is the providers display name
if set, it will be shown to the users in the login page. | diff --git a/pkg/validation/providers.go b/pkg/validation/providers.go index 47b8c880..a0d222f2 100644 --- a/pkg/validation/providers.go +++ b/pkg/validation/providers.go @@ -107,7 +107,7 @@ func providerRequiresClientSecret(provider options.Provider) bool { } // Apple uses a private key to dynamically generate client_secret JWTs - if provider.Type == "apple" { + if provider.Type == options.AppleProvider { return false } diff --git a/providers/apple.go b/providers/apple.go index b0ec76dc..75c1b25b 100644 --- a/providers/apple.go +++ b/providers/apple.go @@ -1,7 +1,6 @@ package providers import ( - "context" "crypto/ecdsa" "crypto/x509" "encoding/pem" @@ -11,11 +10,8 @@ import ( "os" "time" - "github.com/coreos/go-oidc/v3/oidc" "github.com/golang-jwt/jwt/v5" "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" - "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" - "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" "golang.org/x/oauth2" ) @@ -63,16 +59,20 @@ func NewAppleProvider(p *ProviderData, appleOpts options.AppleOptions, oidcOpts validateURL: nil, scope: appleDefaultScope, }) - p.getAuthorizationHeaderFunc = makeOIDCHeader + // Apple returns the authorization code via form POST rather than query + // parameters, so default the response mode accordingly + if p.AuthRequestResponseMode == "" { + p.AuthRequestResponseMode = "form_post" + } + + oidcProvider := NewOIDCProvider(p, oidcOpts) + // Apple requires the client credentials in the POST body + oidcProvider.AuthStyle = oauth2.AuthStyleInParams provider := &AppleProvider{ - OIDCProvider: &OIDCProvider{ - ProviderData: p, - SkipNonce: true, // Apple doesn't use nonce in the standard way - AuthStyle: oauth2.AuthStyleInParams, // Apple requires credentials in POST body - }, - TeamID: appleOpts.TeamID, - KeyID: appleOpts.KeyID, + OIDCProvider: oidcProvider, + TeamID: appleOpts.TeamID, + KeyID: appleOpts.KeyID, } if err := provider.initialize(appleOpts); err != nil { @@ -167,34 +167,3 @@ func (p *AppleProvider) generateClientSecret() (string, error) { return token.SignedString(p.PrivateKey) } - -// GetLoginURL returns the Apple authorization URL with required parameters -func (p *AppleProvider) GetLoginURL(redirectURI, state, nonce string, extraParams url.Values) string { - // Apple requires response_mode=form_post for web clients - if extraParams.Get("response_mode") == "" { - extraParams.Set("response_mode", "form_post") - } - return p.OIDCProvider.GetLoginURL(redirectURI, state, nonce, extraParams) -} - -// ValidateSession validates the session's ID token -func (p *AppleProvider) ValidateSession(ctx context.Context, s *sessions.SessionState) bool { - ctx = oidc.ClientContext(ctx, requests.DefaultHTTPClient) - - // Validate ID token if present - if s.IDToken != "" && p.Verifier != nil { - if _, err := p.Verifier.Verify(ctx, s.IDToken); err != nil { - return false - } - // ID token is valid - Apple doesn't provide a token validation endpoint - return true - } - - // Fallback to access token validation if ValidateURL is set - if p.ValidateURL != nil && p.ValidateURL.String() != "" { - return validateToken(ctx, p, s.AccessToken, makeOIDCHeader(s.AccessToken)) - } - - // No validation possible, but session exists with valid data - return s.AccessToken != "" -}