Discover signature algorithms from OIDC provider (#1662)

This commit is contained in:
Joel Speed
2022-05-29 13:48:09 +01:00
committed by GitHub
parent c900c51a1b
commit d3f428a1a6
7 changed files with 97 additions and 39 deletions
+25 -16
View File
@@ -11,12 +11,13 @@ import (
// providerJSON resresents the information we need from an OIDC discovery
type providerJSON struct {
Issuer string `json:"issuer"`
AuthURL string `json:"authorization_endpoint"`
TokenURL string `json:"token_endpoint"`
JWKsURL string `json:"jwks_uri"`
UserInfoURL string `json:"userinfo_endpoint"`
CodeChallengeAlgs []string `json:"code_challenge_methods_supported"`
Issuer string `json:"issuer"`
AuthURL string `json:"authorization_endpoint"`
TokenURL string `json:"token_endpoint"`
JWKsURL string `json:"jwks_uri"`
UserInfoURL string `json:"userinfo_endpoint"`
CodeChallengeAlgs []string `json:"code_challenge_methods_supported"`
SupportedSigningAlgs []string `json:"id_token_signing_alg_values_supported"`
}
// Endpoints represents the endpoints discovered as part of the OIDC discovery process
@@ -39,6 +40,7 @@ type PKCE struct {
type DiscoveryProvider interface {
Endpoints() Endpoints
PKCE() PKCE
SupportedSigningAlgs() []string
}
// NewProvider allows a user to perform an OIDC discovery and returns the DiscoveryProvider.
@@ -63,21 +65,23 @@ func NewProvider(ctx context.Context, issuerURL string, skipIssuerVerification b
}
return &discoveryProvider{
authURL: p.AuthURL,
tokenURL: p.TokenURL,
jwksURL: p.JWKsURL,
userInfoURL: p.UserInfoURL,
codeChallengeAlgs: p.CodeChallengeAlgs,
authURL: p.AuthURL,
tokenURL: p.TokenURL,
jwksURL: p.JWKsURL,
userInfoURL: p.UserInfoURL,
codeChallengeAlgs: p.CodeChallengeAlgs,
supportedSigningAlgs: p.SupportedSigningAlgs,
}, nil
}
// discoveryProvider holds the discovered endpoints
type discoveryProvider struct {
authURL string
tokenURL string
jwksURL string
userInfoURL string
codeChallengeAlgs []string
authURL string
tokenURL string
jwksURL string
userInfoURL string
codeChallengeAlgs []string
supportedSigningAlgs []string
}
// Endpoints returns the discovered endpoints needed for an authentication provider.
@@ -96,3 +100,8 @@ func (p *discoveryProvider) PKCE() PKCE {
CodeChallengeAlgs: p.codeChallengeAlgs,
}
}
// SupportedSigningAlgs returns the discovered provider signing algorithms.
func (p *discoveryProvider) SupportedSigningAlgs() []string {
return p.supportedSigningAlgs
}
+39
View File
@@ -103,6 +103,25 @@ var _ = Describe("Provider", func() {
Expect(provider.PKCE().CodeChallengeAlgs).To(ConsistOf("S256", "plain"))
})
It("with signing algorithms supported on the provider, should populate signature information", func() {
m, err := mockoidc.NewServer(nil)
Expect(err).ToNot(HaveOccurred())
m.AddMiddleware(newSigningAlgsIssuerMiddleware(m))
ln, err := net.Listen("tcp", "127.0.0.1:0")
Expect(err).ToNot(HaveOccurred())
Expect(m.Start(ln, nil)).To(Succeed())
defer func() {
Expect(m.Shutdown()).To(Succeed())
}()
provider, err := NewProvider(context.Background(), m.Issuer(), false)
Expect(err).ToNot(HaveOccurred())
Expect(provider.SupportedSigningAlgs()).To(ConsistOf("RS256", "HS256"))
})
})
func newInvalidIssuerMiddleware(m *mockoidc.MockOIDC) func(http.Handler) http.Handler {
@@ -144,6 +163,26 @@ func newCodeChallengeIssuerMiddleware(m *mockoidc.MockOIDC) func(http.Handler) h
}
}
func newSigningAlgsIssuerMiddleware(m *mockoidc.MockOIDC) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
p := providerJSON{
Issuer: m.Issuer(),
AuthURL: m.AuthorizationEndpoint(),
TokenURL: m.TokenEndpoint(),
JWKsURL: m.JWKSEndpoint(),
UserInfoURL: m.UserinfoEndpoint(),
SupportedSigningAlgs: []string{"RS256", "HS256"},
}
data, err := json.Marshal(p)
if err != nil {
rw.WriteHeader(500)
}
rw.Write(data)
})
}
}
func newBadRequestMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+15 -6
View File
@@ -43,6 +43,10 @@ type ProviderVerifierOptions struct {
// SkipIssuerVerification skips verification of ID token issuers.
// When false, ID Token Issuers must match the OIDC discovery URL.
SkipIssuerVerification bool
// SupportedSigningAlgs is the list of signature algorithms supported by the
// provider.
SupportedSigningAlgs []string
}
// validate checks that the required options are present before attempting to create
@@ -76,9 +80,10 @@ func (p ProviderVerifierOptions) toVerificationOptions() IDTokenVerificationOpti
// toOIDCConfig returns an oidc.Config based on the configured options.
func (p ProviderVerifierOptions) toOIDCConfig() *oidc.Config {
return &oidc.Config{
ClientID: p.ClientID,
SkipIssuerCheck: p.SkipIssuerVerification,
SkipClientIDCheck: true,
ClientID: p.ClientID,
SkipIssuerCheck: p.SkipIssuerVerification,
SkipClientIDCheck: true,
SupportedSigningAlgs: p.SupportedSigningAlgs,
}
}
@@ -112,21 +117,25 @@ type verifierBuilder func(*oidc.Config) *oidc.IDTokenVerifier
func getVerifierBuilder(ctx context.Context, opts ProviderVerifierOptions) (verifierBuilder, DiscoveryProvider, error) {
if opts.SkipDiscovery {
// Instead of discovering the JWKs URK, it needs to be specified in the opts already
return newVerifierBuilder(ctx, opts.IssuerURL, opts.JWKsURL), nil, nil
return newVerifierBuilder(ctx, opts.IssuerURL, opts.JWKsURL, opts.SupportedSigningAlgs), nil, nil
}
provider, err := NewProvider(ctx, opts.IssuerURL, opts.SkipIssuerVerification)
if err != nil {
return nil, nil, fmt.Errorf("error while discovery OIDC configuration: %v", err)
}
verifierBuilder := newVerifierBuilder(ctx, opts.IssuerURL, provider.Endpoints().JWKsURL)
verifierBuilder := newVerifierBuilder(ctx, opts.IssuerURL, provider.Endpoints().JWKsURL, provider.SupportedSigningAlgs())
return verifierBuilder, provider, nil
}
// newVerifierBuilder returns a function to create a IDToken verifier from an OIDC config.
func newVerifierBuilder(ctx context.Context, issuerURL, jwksURL string) verifierBuilder {
func newVerifierBuilder(ctx context.Context, issuerURL, jwksURL string, supportedSigningAlgs []string) verifierBuilder {
keySet := oidc.NewRemoteKeySet(ctx, jwksURL)
return func(oidcConfig *oidc.Config) *oidc.IDTokenVerifier {
if len(supportedSigningAlgs) > 0 {
oidcConfig.SupportedSigningAlgs = supportedSigningAlgs
}
return oidc.NewVerifier(issuerURL, keySet, oidcConfig)
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/golang-jwt/jwt"
"github.com/oauth2-proxy/mockoidc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"