1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2024-11-28 09:08:44 +02:00
oauth2-proxy/pkg/providers/oidc/provider_verifier_test.go
2022-02-19 15:37:56 +00:00

174 lines
5.5 KiB
Go

package oidc
import (
"context"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/oauth2-proxy/mockoidc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)
var _ = Describe("ProviderVerifier", func() {
var m *mockoidc.MockOIDC
BeforeEach(func() {
var err error
m, err = mockoidc.Run()
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
Expect(m.Shutdown()).To(Succeed())
})
type newProviderVerifierTableInput struct {
modifyOpts func(*ProviderVerifierOptions)
expectedError string
}
DescribeTable("when constructing the provider verifier", func(in *newProviderVerifierTableInput) {
opts := ProviderVerifierOptions{
AudienceClaims: []string{"aud"},
ClientID: m.Config().ClientID,
ExtraAudiences: []string{},
IssuerURL: m.Issuer(),
}
if in.modifyOpts != nil {
in.modifyOpts(&opts)
}
pv, err := NewProviderVerifier(context.Background(), opts)
if in.expectedError != "" {
Expect(err).To(MatchError(HavePrefix(in.expectedError)))
return
}
Expect(err).ToNot(HaveOccurred())
Expect(pv.DiscoveryEnabled()).ToNot(Equal(opts.SkipDiscovery), "DiscoveryEnabled should be the reverse of skip discovery")
Expect(pv.Provider()).ToNot(BeNil())
if pv.DiscoveryEnabled() {
endpoints := pv.Provider().Endpoints()
Expect(endpoints.AuthURL).To(Equal(m.AuthorizationEndpoint()))
Expect(endpoints.TokenURL).To(Equal(m.TokenEndpoint()))
Expect(endpoints.JWKsURL).To(Equal(m.JWKSEndpoint()))
Expect(endpoints.UserInfoURL).To(Equal(m.UserinfoEndpoint()))
}
},
Entry("should be succesfful when discovering the OIDC provider", &newProviderVerifierTableInput{
modifyOpts: func(_ *ProviderVerifierOptions) {},
}),
Entry("when the issuer URL is missing", &newProviderVerifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.IssuerURL = ""
},
expectedError: "invalid provider verifier options: missing required setting: issuer-url",
}),
Entry("when the issuer URL is invalid", &newProviderVerifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.IssuerURL = "invalid"
},
expectedError: "could not get verifier builder: error while discovery OIDC configuration: failed to discover OIDC configuration: error performing request: Get \"invalid/.well-known/openid-configuration\": unsupported protocol scheme \"\"",
}),
Entry("with skip discovery and the JWKs URL is missing", &newProviderVerifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.SkipDiscovery = true
p.JWKsURL = ""
},
expectedError: "invalid provider verifier options: missing required setting: jwks-url",
}),
Entry("should be succesfful when skipping discovery with the JWKs URL specified", &newProviderVerifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.SkipDiscovery = true
p.JWKsURL = m.JWKSEndpoint()
},
}),
)
type verifierTableInput struct {
modifyOpts func(*ProviderVerifierOptions)
modifyClaims func(*jwt.StandardClaims)
expectedError string
}
DescribeTable("when constructing the provider verifier", func(in *verifierTableInput) {
opts := ProviderVerifierOptions{
AudienceClaims: []string{"aud"},
ClientID: m.Config().ClientID,
ExtraAudiences: []string{},
IssuerURL: m.Issuer(),
}
if in.modifyOpts != nil {
in.modifyOpts(&opts)
}
pv, err := NewProviderVerifier(context.Background(), opts)
Expect(err).ToNot(HaveOccurred())
now := time.Now()
claims := jwt.StandardClaims{
Audience: m.Config().ClientID,
Issuer: m.Issuer(),
ExpiresAt: now.Add(1 * time.Hour).Unix(),
IssuedAt: now.Unix(),
Subject: "user",
}
if in.modifyClaims != nil {
in.modifyClaims(&claims)
}
rawIDToken, err := m.Keypair.SignJWT(claims)
Expect(err).ToNot(HaveOccurred())
idToken, err := pv.Verifier().Verify(context.Background(), rawIDToken)
if in.expectedError != "" {
Expect(err).To(MatchError(HavePrefix(in.expectedError)))
return
}
Expect(err).ToNot(HaveOccurred())
Expect(idToken.Issuer).To(Equal(claims.Issuer))
Expect(idToken.Audience).To(ConsistOf(claims.Audience))
Expect(idToken.Subject).To(Equal(claims.Subject))
},
Entry("with the default opts and claims", &verifierTableInput{}),
Entry("when the audience is mismatched", &verifierTableInput{
modifyClaims: func(j *jwt.StandardClaims) {
j.Audience = "OtherClient"
},
expectedError: "audience from claim aud with value [OtherClient] does not match with any of allowed audiences",
}),
Entry("when the audience is an extra audience", &verifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.ExtraAudiences = []string{"ExtraIssuer"}
},
modifyClaims: func(j *jwt.StandardClaims) {
j.Audience = "ExtraIssuer"
},
}),
Entry("when the issuer is mismatched", &verifierTableInput{
modifyClaims: func(j *jwt.StandardClaims) {
j.Issuer = "OtherIssuer"
},
expectedError: "failed to verify token: oidc: id token issued by a different provider",
}),
Entry("when the issuer is mismatched with skip issuer verification", &verifierTableInput{
modifyOpts: func(p *ProviderVerifierOptions) {
p.SkipIssuerVerification = true
},
modifyClaims: func(j *jwt.StandardClaims) {
j.Issuer = "OtherIssuer"
},
}),
Entry("when the token has expired", &verifierTableInput{
modifyClaims: func(j *jwt.StandardClaims) {
j.ExpiresAt = time.Now().Add(-1 * time.Hour).Unix()
},
expectedError: "failed to verify token: oidc: token is expired",
}),
)
})