Add AudienceMatchPolicy to AuthenticationConfiguration
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com> Kubernetes-commit: 19da90d6396ce9471f612d6e9a31f1b1c8d605b1
This commit is contained in:
parent
f980dbe8f0
commit
26996e3679
|
@ -180,8 +180,17 @@ type Issuer struct {
|
|||
URL string
|
||||
CertificateAuthority string
|
||||
Audiences []string
|
||||
AudienceMatchPolicy AudienceMatchPolicyType
|
||||
}
|
||||
|
||||
// AudienceMatchPolicyType is a set of valid values for Issuer.AudienceMatchPolicy
|
||||
type AudienceMatchPolicyType string
|
||||
|
||||
// Valid types for AudienceMatchPolicyType
|
||||
const (
|
||||
AudienceMatchPolicyMatchAny AudienceMatchPolicyType = "MatchAny"
|
||||
)
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
Claim string
|
||||
|
|
|
@ -225,8 +225,32 @@ type Issuer struct {
|
|||
// Required to be non-empty.
|
||||
// +required
|
||||
Audiences []string `json:"audiences"`
|
||||
|
||||
// audienceMatchPolicy defines how the "audiences" field is used to match the "aud" claim in the presented JWT.
|
||||
// Allowed values are:
|
||||
// 1. "MatchAny" when multiple audiences are specified and
|
||||
// 2. empty (or unset) or "MatchAny" when a single audience is specified.
|
||||
//
|
||||
// - MatchAny: the "aud" claim in the presented JWT must match at least one of the entries in the "audiences" field.
|
||||
// For example, if "audiences" is ["foo", "bar"], the "aud" claim in the presented JWT must contain either "foo" or "bar" (and may contain both).
|
||||
//
|
||||
// - "": The match policy can be empty (or unset) when a single audience is specified in the "audiences" field. The "aud" claim in the presented JWT must contain the single audience (and may contain others).
|
||||
//
|
||||
// For more nuanced audience validation, use claimValidationRules.
|
||||
// example: claimValidationRule[].expression: 'sets.equivalent(claims.aud, ["bar", "foo", "baz"])' to require an exact match.
|
||||
// +optional
|
||||
AudienceMatchPolicy AudienceMatchPolicyType `json:"audienceMatchPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// AudienceMatchPolicyType is a set of valid values for Issuer.AudienceMatchPolicy
|
||||
type AudienceMatchPolicyType string
|
||||
|
||||
// Valid types for AudienceMatchPolicyType
|
||||
const (
|
||||
// MatchAny means the "aud" claim in the presented JWT must match at least one of the entries in the "audiences" field.
|
||||
AudienceMatchPolicyMatchAny AudienceMatchPolicyType = "MatchAny"
|
||||
)
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
|
|
|
@ -582,6 +582,7 @@ func autoConvert_v1alpha1_Issuer_To_apiserver_Issuer(in *Issuer, out *apiserver.
|
|||
out.URL = in.URL
|
||||
out.CertificateAuthority = in.CertificateAuthority
|
||||
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
|
||||
out.AudienceMatchPolicy = apiserver.AudienceMatchPolicyType(in.AudienceMatchPolicy)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -594,6 +595,7 @@ func autoConvert_apiserver_Issuer_To_v1alpha1_Issuer(in *apiserver.Issuer, out *
|
|||
out.URL = in.URL
|
||||
out.CertificateAuthority = in.CertificateAuthority
|
||||
out.Audiences = *(*[]string)(unsafe.Pointer(&in.Audiences))
|
||||
out.AudienceMatchPolicy = AudienceMatchPolicyType(in.AudienceMatchPolicy)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ func validateIssuer(issuer api.Issuer, fldPath *field.Path) field.ErrorList {
|
|||
var allErrs field.ErrorList
|
||||
|
||||
allErrs = append(allErrs, validateURL(issuer.URL, fldPath.Child("url"))...)
|
||||
allErrs = append(allErrs, validateAudiences(issuer.Audiences, fldPath.Child("audiences"))...)
|
||||
allErrs = append(allErrs, validateAudiences(issuer.Audiences, issuer.AudienceMatchPolicy, fldPath.Child("audiences"), fldPath.Child("audienceMatchPolicy"))...)
|
||||
allErrs = append(allErrs, validateCertificateAuthority(issuer.CertificateAuthority, fldPath.Child("certificateAuthority"))...)
|
||||
|
||||
return allErrs
|
||||
|
@ -136,7 +136,7 @@ func validateURL(issuerURL string, fldPath *field.Path) field.ErrorList {
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func validateAudiences(audiences []string, fldPath *field.Path) field.ErrorList {
|
||||
func validateAudiences(audiences []string, audienceMatchPolicy api.AudienceMatchPolicyType, fldPath, audienceMatchPolicyFldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if len(audiences) == 0 {
|
||||
|
@ -157,6 +157,10 @@ func validateAudiences(audiences []string, fldPath *field.Path) field.ErrorList
|
|||
}
|
||||
}
|
||||
|
||||
if len(audienceMatchPolicy) > 0 && audienceMatchPolicy != api.AudienceMatchPolicyMatchAny {
|
||||
allErrs = append(allErrs, field.Invalid(audienceMatchPolicyFldPath, audienceMatchPolicy, "audienceMatchPolicy must be empty or MatchAny for single audience"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
|
|
@ -269,37 +269,46 @@ func TestValidateURL(t *testing.T) {
|
|||
|
||||
func TestValidateAudiences(t *testing.T) {
|
||||
fldPath := field.NewPath("issuer", "audiences")
|
||||
audienceMatchPolicyFldPath := field.NewPath("issuer", "audienceMatchPolicy")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
in []string
|
||||
want string
|
||||
name string
|
||||
in []string
|
||||
matchPolicy string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "audiences is empty",
|
||||
in: []string{},
|
||||
want: "issuer.audiences: Required value: at least one issuer.audiences is required",
|
||||
},
|
||||
{
|
||||
name: "at most one audiences is allowed",
|
||||
in: []string{"audience1", "audience2"},
|
||||
want: "issuer.audiences: Too many: 2: must have at most 1 items",
|
||||
},
|
||||
{
|
||||
name: "audience is empty",
|
||||
in: []string{""},
|
||||
want: "issuer.audiences[0]: Required value: audience can't be empty",
|
||||
},
|
||||
{
|
||||
name: "invalid match policy with single audience",
|
||||
in: []string{"audience"},
|
||||
matchPolicy: "MatchExact",
|
||||
want: `issuer.audienceMatchPolicy: Invalid value: "MatchExact": audienceMatchPolicy must be empty or MatchAny for single audience`,
|
||||
},
|
||||
{
|
||||
name: "valid audience",
|
||||
in: []string{"audience"},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "valid audience with MatchAny policy",
|
||||
in: []string{"audience"},
|
||||
matchPolicy: "MatchAny",
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := validateAudiences(tt.in, fldPath).ToAggregate()
|
||||
got := validateAudiences(tt.in, api.AudienceMatchPolicyType(tt.matchPolicy), fldPath, audienceMatchPolicyFldPath).ToAggregate()
|
||||
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
||||
t.Fatalf("Audiences validation mismatch (-want +got):\n%s", d)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue