1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2024-12-10 11:10:27 +02:00
oauth2-proxy/pkg/providers/oidc/verifier_test.go
2023-10-24 16:37:57 +02:00

250 lines
7.1 KiB
Go
Executable File

package oidc
import (
"context"
"crypto/rand"
"crypto/rsa"
"encoding/json"
"fmt"
"github.com/coreos/go-oidc/v3/oidc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"gopkg.in/square/go-jose.v2"
)
var _ = Describe("Verify", func() {
ctx := context.Background()
It("Succeeds with default aud behavior", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"aud"},
ClientID: "1226737",
ExtraAudiences: []string{},
}, payload{
Iss: "https://foo",
Aud: "1226737",
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"1226737"}))
})
It("Fails with default aud behavior", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"aud"},
ClientID: "7817818",
ExtraAudiences: []string{},
}, payload{
Iss: "https://foo",
Aud: "1226737",
})
Expect(err).To(MatchError("audience from claim aud with value [1226737] does not match with " +
"any of allowed audiences map[7817818:{}]"))
Expect(result).To(BeNil())
})
It("Succeeds with extra audiences", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"aud"},
ClientID: "7817818",
ExtraAudiences: []string{"xyz", "1226737"},
}, payload{
Iss: "https://foo",
Aud: "1226737",
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"1226737"}))
})
It("Fails with extra audiences", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"aud"},
ClientID: "7817818",
ExtraAudiences: []string{"xyz", "abc"},
}, payload{
Iss: "https://foo",
Aud: "1226737",
})
Expect(err).To(MatchError("audience from claim aud with value [1226737] does not match with any " +
"of allowed audiences map[7817818:{} abc:{} xyz:{}]"))
Expect(result).To(BeNil())
})
It("Succeeds with non default aud behavior", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id"},
ClientID: "1226737",
ExtraAudiences: []string{},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"1226737"}))
})
It("Fails with non default aud behavior", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id"},
ClientID: "7817818",
ExtraAudiences: []string{},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
})
Expect(err).To(MatchError("audience from claim client_id with value [1226737] does not match with " +
"any of allowed audiences map[7817818:{}]"))
Expect(result).To(BeNil())
})
It("Succeeds with non default aud behavior and extra audiences", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id"},
ClientID: "7817818",
ExtraAudiences: []string{"xyz", "1226737"},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"1226737"}))
})
It("Fails with non default aud behavior and extra audiences", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id"},
ClientID: "7817818",
ExtraAudiences: []string{"xyz", "abc"},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
})
Expect(err).To(MatchError("audience from claim client_id with value [1226737] does not match with any " +
"of allowed audiences map[7817818:{} abc:{} xyz:{}]"))
Expect(result).To(BeNil())
})
It("Fails if audience claim does not exist", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"not_exists"},
ClientID: "7817818",
ExtraAudiences: []string{"xyz", "abc"},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
Aud: "1226737",
})
Expect(err).To(MatchError("audience claims [not_exists] do not exist in claims: " +
"map[aud:1226737 client_id:1226737 iss:https://foo]"))
Expect(result).To(BeNil())
})
It("Succeeds with multiple audiences", func() {
var result, err = verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id", "aud"},
ClientID: "123456789",
ExtraAudiences: []string{"1226737"},
}, payload{
Iss: "https://foo",
ClientID: "123456789",
Aud: []string{"1226737", "123456789"},
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"123456789"}))
})
It("Succeeds if aud claim match", func() {
result, err := verify(ctx, IDTokenVerificationOptions{
AudienceClaims: []string{"client_id", "aud"},
ClientID: "1226737",
ExtraAudiences: []string{"xyz", "abc"},
}, payload{
Iss: "https://foo",
ClientID: "1226737",
Aud: "1226737",
})
Expect(err).ToNot(HaveOccurred())
Expect(result.Issuer).To(Equal("https://foo"))
Expect(result.Audience).To(Equal([]string{"1226737"}))
})
})
type payload struct {
Iss string `json:"iss,omitempty"`
Aud interface{} `json:"aud,omitempty"`
ClientID string `json:"client_id,omitempty"`
}
type jwtToken struct {
PrivateKey jose.JSONWebKey
PublicKey jose.JSONWebKey
Token string
}
type testVerifier struct {
jwk jose.JSONWebKey
}
func (t *testVerifier) VerifySignature(_ context.Context, jwt string) ([]byte, error) {
jws, err := jose.ParseSigned(jwt)
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
}
return jws.Verify(&t.jwk)
}
func verify(ctx context.Context, verificationOptions IDTokenVerificationOptions, payload payload) (*oidc.IDToken, error) {
config := &oidc.Config{
ClientID: "1226737",
SkipClientIDCheck: true,
SkipExpiryCheck: true, // required to not run in expired Token error during testing
}
rawToken, err := json.Marshal(payload)
if err != nil {
return nil, err
}
token, _ := createToken(rawToken)
verifier := NewVerifier(oidc.NewVerifier("https://foo", &testVerifier{jwk: token.PublicKey}, config), verificationOptions)
return verifier.Verify(ctx, token.Token)
}
func createToken(payload []byte) (*jwtToken, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1028)
if err != nil {
return nil, err
}
privateWebKey := jose.JSONWebKey{Key: privateKey, Algorithm: string(jose.RS256), KeyID: ""}
publicWebKey := jose.JSONWebKey{Key: privateKey.Public(), Use: "sig", Algorithm: string(jose.RS256), KeyID: ""}
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: privateWebKey}, nil)
if err != nil {
return nil, err
}
jws, err := signer.Sign(payload)
if err != nil {
return nil, err
}
data, err := jws.CompactSerialize()
if err != nil {
return nil, err
}
return &jwtToken{
PrivateKey: privateWebKey,
PublicKey: publicWebKey,
Token: data,
}, nil
}