refactor: reuse generic OIDC provider logic in Apple provider
Address review feedback: - Wire OIDCOptions through NewOIDCProvider instead of constructing OIDCProvider manually - Default AuthRequestResponseMode to form_post instead of overriding GetLoginURL - Drop the ValidateSession override in favour of the generic OIDC one - Use options.AppleProvider constant in client secret validation - Regenerate alpha config docs (appleConfig, authStyle) - Fix CHANGELOG entry to reference #3293 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: LYJW131 <lyjw2007@gmail.com>
This commit is contained in:
parent
33252dd11c
commit
15dfd6e617
|
|
@ -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.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
|
| `metricsServer` | _[Server](#server)_ | MetricsServer is used to configure the HTTP(S) server for metrics.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>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<br/>yet working.** [This feature is tracked in<br/>#925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926) |
|
| `providers` | _[Providers](#providers)_ | Providers is used to configure your provider. **Multiple-providers is not<br/>yet working.** [This feature is tracked in<br/>#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
|
### AzureOptions
|
||||||
|
|
||||||
(**Appears on:** [Provider](#provider))
|
(**Appears on:** [Provider](#provider))
|
||||||
|
|
@ -552,6 +565,7 @@ character.
|
||||||
| `audienceClaims` | _[]string_ | AudienceClaim allows to define any claim that is verified against the client id<br/>By default `aud` claim is used for verification. |
|
| `audienceClaims` | _[]string_ | AudienceClaim allows to define any claim that is verified against the client id<br/>By default `aud` claim is used for verification. |
|
||||||
| `extraAudiences` | _[]string_ | ExtraAudiences is a list of additional audiences that are allowed<br/>to pass verification in addition to the client id. |
|
| `extraAudiences` | _[]string_ | ExtraAudiences is a list of additional audiences that are allowed<br/>to pass verification in addition to the client id. |
|
||||||
| `enabledSigningAlgs` | _[]string_ | EnabledSigningAlgs is a list of allowed JWT signing algorithms.<br/>When discovery is enabled, the effective set is the intersection<br/>between this list and the provider's discovered supported algorithms.<br/>By default `RS256` is used if nothing has been discovered or specified. |
|
| `enabledSigningAlgs` | _[]string_ | EnabledSigningAlgs is a list of allowed JWT signing algorithms.<br/>When discovery is enabled, the effective set is the intersection<br/>between this list and the provider's discovered supported algorithms.<br/>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.<br/>Possible values are:<br/> - "inParams" (or "params"): sends credentials in the POST body as application/x-www-form-urlencoded parameters<br/> - "inHeader" (or "header"): sends credentials using HTTP Basic Authorization<br/> - "" (empty, default): auto-detect by trying both ways<br/>Some providers like Apple require "inParams". |
|
||||||
|
|
||||||
### Provider
|
### Provider
|
||||||
|
|
||||||
|
|
@ -574,6 +588,7 @@ Provider holds all configuration for a single provider
|
||||||
| `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. |
|
| `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. |
|
||||||
| `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider<br/>or providers utilize OIDC configurations. |
|
| `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider<br/>or providers utilize OIDC configurations. |
|
||||||
| `loginGovConfig` | _[LoginGovOptions](#logingovoptions)_ | LoginGovConfig holds all configurations for LoginGov provider. |
|
| `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.<br/>This value is required for all providers. |
|
| `id` | _string_ | ID should be a unique identifier for the provider.<br/>This value is required for all providers. |
|
||||||
| `provider` | _[ProviderType](#providertype)_ | Type is the OAuth provider<br/>must be set from the supported providers group,<br/>otherwise 'Google' is set as default |
|
| `provider` | _[ProviderType](#providertype)_ | Type is the OAuth provider<br/>must be set from the supported providers group,<br/>otherwise 'Google' is set as default |
|
||||||
| `name` | _string_ | Name is the providers display name<br/>if set, it will be shown to the users in the login page. |
|
| `name` | _string_ | Name is the providers display name<br/>if set, it will be shown to the users in the login page. |
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func providerRequiresClientSecret(provider options.Provider) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apple uses a private key to dynamically generate client_secret JWTs
|
// Apple uses a private key to dynamically generate client_secret JWTs
|
||||||
if provider.Type == "apple" {
|
if provider.Type == options.AppleProvider {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package providers
|
package providers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
|
@ -11,11 +10,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"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/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -63,16 +59,20 @@ func NewAppleProvider(p *ProviderData, appleOpts options.AppleOptions, oidcOpts
|
||||||
validateURL: nil,
|
validateURL: nil,
|
||||||
scope: appleDefaultScope,
|
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{
|
provider := &AppleProvider{
|
||||||
OIDCProvider: &OIDCProvider{
|
OIDCProvider: oidcProvider,
|
||||||
ProviderData: p,
|
TeamID: appleOpts.TeamID,
|
||||||
SkipNonce: true, // Apple doesn't use nonce in the standard way
|
KeyID: appleOpts.KeyID,
|
||||||
AuthStyle: oauth2.AuthStyleInParams, // Apple requires credentials in POST body
|
|
||||||
},
|
|
||||||
TeamID: appleOpts.TeamID,
|
|
||||||
KeyID: appleOpts.KeyID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.initialize(appleOpts); err != nil {
|
if err := provider.initialize(appleOpts); err != nil {
|
||||||
|
|
@ -167,34 +167,3 @@ func (p *AppleProvider) generateClientSecret() (string, error) {
|
||||||
|
|
||||||
return token.SignedString(p.PrivateKey)
|
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 != ""
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue