2022-02-16 10:15:36 +00:00
package oidc
import (
"context"
"time"
2024-03-04 01:42:00 +01:00
"github.com/golang-jwt/jwt/v5"
2022-02-16 10:15:36 +00:00
"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 )
2024-03-04 01:42:00 +01:00
modifyClaims func ( claims * jwt . RegisteredClaims )
2022-02-16 10:15:36 +00:00
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 ( )
2024-03-04 01:42:00 +01:00
claims := jwt . RegisteredClaims {
Audience : jwt . ClaimStrings { m . Config ( ) . ClientID } ,
2022-02-16 10:15:36 +00:00
Issuer : m . Issuer ( ) ,
2024-03-04 01:42:00 +01:00
ExpiresAt : jwt . NewNumericDate ( now . Add ( 1 * time . Hour ) ) ,
IssuedAt : jwt . NewNumericDate ( now ) ,
2022-02-16 10:15:36 +00:00
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 {
2024-03-04 01:42:00 +01:00
modifyClaims : func ( j * jwt . RegisteredClaims ) {
j . Audience = jwt . ClaimStrings { "OtherClient" }
2022-02-16 10:15:36 +00:00
} ,
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" }
} ,
2024-03-04 01:42:00 +01:00
modifyClaims : func ( j * jwt . RegisteredClaims ) {
j . Audience = jwt . ClaimStrings { "ExtraIssuer" }
2022-02-16 10:15:36 +00:00
} ,
} ) ,
Entry ( "when the issuer is mismatched" , & verifierTableInput {
2024-03-04 01:42:00 +01:00
modifyClaims : func ( j * jwt . RegisteredClaims ) {
2022-02-16 10:15:36 +00:00
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
} ,
2024-03-04 01:42:00 +01:00
modifyClaims : func ( j * jwt . RegisteredClaims ) {
2022-02-16 10:15:36 +00:00
j . Issuer = "OtherIssuer"
} ,
} ) ,
Entry ( "when the token has expired" , & verifierTableInput {
2024-03-04 01:42:00 +01:00
modifyClaims : func ( j * jwt . RegisteredClaims ) {
j . ExpiresAt = jwt . NewNumericDate ( time . Now ( ) . Add ( - 1 * time . Hour ) )
2022-02-16 10:15:36 +00:00
} ,
expectedError : "failed to verify token: oidc: token is expired" ,
} ) ,
)
} )