feat: accept lists in the token audience claim

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
Mark Sagi-Kazar 2022-09-27 15:34:26 +02:00
parent 97fa1183bf
commit 3472f7a8e3
No known key found for this signature in database
GPG key ID: 31AB0439F4C5C90E
4 changed files with 35 additions and 22 deletions

View file

@ -180,7 +180,7 @@ func (issuer *TokenIssuer) CreateJWT(subject string, audience string, grantedAcc
claimSet := token.ClaimSet{ claimSet := token.ClaimSet{
Issuer: issuer.Issuer, Issuer: issuer.Issuer,
Subject: subject, Subject: subject,
Audience: audience, Audience: []string{audience},
Expiration: now.Add(exp).Unix(), Expiration: now.Add(exp).Unix(),
NotBefore: now.Unix(), NotBefore: now.Unix(),
IssuedAt: now.Unix(), IssuedAt: now.Unix(),

View file

@ -42,13 +42,13 @@ type ResourceActions struct {
// ClaimSet describes the main section of a JSON Web Token. // ClaimSet describes the main section of a JSON Web Token.
type ClaimSet struct { type ClaimSet struct {
// Public claims // Public claims
Issuer string `json:"iss"` Issuer string `json:"iss"`
Subject string `json:"sub"` Subject string `json:"sub"`
Audience string `json:"aud"` Audience WeakStringList `json:"aud"`
Expiration int64 `json:"exp"` Expiration int64 `json:"exp"`
NotBefore int64 `json:"nbf"` NotBefore int64 `json:"nbf"`
IssuedAt int64 `json:"iat"` IssuedAt int64 `json:"iat"`
JWTID string `json:"jti"` JWTID string `json:"jti"`
// Private claims // Private claims
Access []*ResourceActions `json:"access"` Access []*ResourceActions `json:"access"`
@ -141,8 +141,8 @@ func (t *Token) Verify(verifyOpts VerifyOptions) error {
} }
// Verify that the Audience claim is allowed. // Verify that the Audience claim is allowed.
if !contains(verifyOpts.AcceptedAudiences, t.Claims.Audience) { if !containsAny(verifyOpts.AcceptedAudiences, t.Claims.Audience) {
log.Infof("token intended for another audience: %q", t.Claims.Audience) log.Infof("token intended for another audience: %v", t.Claims.Audience)
return ErrInvalidToken return ErrInvalidToken
} }
@ -185,13 +185,15 @@ func (t *Token) Verify(verifyOpts VerifyOptions) error {
// VerifySigningKey attempts to get the key which was used to sign this token. // VerifySigningKey attempts to get the key which was used to sign this token.
// The token header should contain either of these 3 fields: // The token header should contain either of these 3 fields:
// `x5c` - The x509 certificate chain for the signing key. Needs to be //
// verified. // `x5c` - The x509 certificate chain for the signing key. Needs to be
// `jwk` - The JSON Web Key representation of the signing key. // verified.
// May contain its own `x5c` field which needs to be verified. // `jwk` - The JSON Web Key representation of the signing key.
// `kid` - The unique identifier for the key. This library interprets it // May contain its own `x5c` field which needs to be verified.
// as a libtrust fingerprint. The key itself can be looked up in // `kid` - The unique identifier for the key. This library interprets it
// the trustedKeys field of the given verify options. // as a libtrust fingerprint. The key itself can be looked up in
// the trustedKeys field of the given verify options.
//
// Each of these methods are tried in that order of preference until the // Each of these methods are tried in that order of preference until the
// signing key is found or an error is returned. // signing key is found or an error is returned.
func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (signingKey libtrust.PublicKey, err error) { func (t *Token) VerifySigningKey(verifyOpts VerifyOptions) (signingKey libtrust.PublicKey, err error) {

View file

@ -117,7 +117,7 @@ func makeTestToken(issuer, audience string, access []*ResourceActions, rootKey l
claimSet := &ClaimSet{ claimSet := &ClaimSet{
Issuer: issuer, Issuer: issuer,
Subject: "foo", Subject: "foo",
Audience: audience, Audience: []string{audience},
Expiration: exp.Unix(), Expiration: exp.Unix(),
NotBefore: now.Unix(), NotBefore: now.Unix(),
IssuedAt: now.Unix(), IssuedAt: now.Unix(),
@ -307,10 +307,10 @@ func writeTempRootCerts(rootKeys []libtrust.PrivateKey) (filename string, err er
// TestAccessController tests complete integration of the token auth package. // TestAccessController tests complete integration of the token auth package.
// It starts by mocking the options for a token auth accessController which // It starts by mocking the options for a token auth accessController which
// it creates. It then tries a few mock requests: // it creates. It then tries a few mock requests:
// - don't supply a token; should error with challenge // - don't supply a token; should error with challenge
// - supply an invalid token; should error with challenge // - supply an invalid token; should error with challenge
// - supply a token with insufficient access; should error with challenge // - supply a token with insufficient access; should error with challenge
// - supply a valid token; should not error // - supply a valid token; should not error
func TestAccessController(t *testing.T) { func TestAccessController(t *testing.T) {
// Make 2 keys; only the first is to be a trusted root key. // Make 2 keys; only the first is to be a trusted root key.
rootKeys, err := makeRootKeys(2) rootKeys, err := makeRootKeys(2)

View file

@ -56,3 +56,14 @@ func contains(ss []string, q string) bool {
return false return false
} }
// containsAny returns true if any of q is found in ss.
func containsAny(ss []string, q []string) bool {
for _, s := range ss {
if contains(q, s) {
return true
}
}
return false
}