Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/go-cmp v0.7.0
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251205182537-ff5553e56f33
github.com/openshift/api v0.0.0-20251106190826-ebe535b08719
github.com/openshift/api v0.0.0-20260113121726-a0ffeb320368
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13
github.com/openshift/library-go v0.0.0-20251107090138-0de9712313a5
github.com/openshift/multi-operator-manager v0.0.0-20241205181422-20aa3906b99d
github.com/spf13/cobra v1.9.1
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251205182537-ff5553e56f33 h1:LJf6kWZQ36iako7WXRzdEa5XKrnyrAX8GBhlAcKRaZQ=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20251205182537-ff5553e56f33/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift/api v0.0.0-20251106190826-ebe535b08719 h1:KEwYyKaJniwhoyLB75tAMmJn9pMlk0PUlRfrsXYOhwM=
github.com/openshift/api v0.0.0-20251106190826-ebe535b08719/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/api v0.0.0-20260113121726-a0ffeb320368 h1:oTY7plngzWWEHjzOd+aVbfo2P37My5BJRC1cKcAQ1Uw=
github.com/openshift/api v0.0.0-20260113121726-a0ffeb320368/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee h1:+Sp5GGnjHDhT/a/nQ1xdp43UscBMr7G5wxsYotyhzJ4=
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE=
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235 h1:9JBeIXmnHlpXTQPi7LPmu1jdxznBhAE7bb1K+3D8gxY=
github.com/openshift/client-go v0.0.0-20251015124057-db0dee36e235/go.mod h1:L49W6pfrZkfOE5iC1PqEkuLkXG4W0BX4w8b+L2Bv7fM=
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13 h1:6rd4zSo2UaWQcAPZfHK9yzKVqH0BnMv1hqMzqXZyTds=
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13/go.mod h1:YvOmPmV7wcJxpfhTDuFqqs2Xpb3M3ovsM6Qs/i2ptq4=
github.com/openshift/library-go v0.0.0-20251107090138-0de9712313a5 h1:Gq8jCFgSrilZ2ZHjQleFZWlblikc1aaRZ0hqs+yvrP4=
github.com/openshift/library-go v0.0.0-20251107090138-0de9712313a5/go.mod h1:OlFFws1AO51uzfc48MsStGE4SFMWlMZD0+f5a/zCtKI=
github.com/openshift/multi-operator-manager v0.0.0-20241205181422-20aa3906b99d h1:Rzx23P63JFNNz5D23ubhC0FCN5rK8CeJhKcq5QKcdyU=
Expand Down
67 changes: 61 additions & 6 deletions pkg/controllers/externaloidc/externaloidc_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func (c *externalOIDCController) generateAuthConfig(auth configv1.Authentication
func generateJWTForProvider(provider configv1.OIDCProvider, configMapLister corev1listers.ConfigMapLister, featureGates featuregates.FeatureGate, serviceAccountIssuer string) (apiserverv1beta1.JWTAuthenticator, error) {
out := apiserverv1beta1.JWTAuthenticator{}

issuer, err := generateIssuer(provider.Issuer, configMapLister, serviceAccountIssuer)
issuer, err := generateIssuer(provider.Issuer, featureGates, configMapLister, serviceAccountIssuer)
if err != nil {
return apiserverv1beta1.JWTAuthenticator{}, fmt.Errorf("generating issuer for provider %q: %v", provider.Name, err)
}
Expand All @@ -188,19 +188,27 @@ func generateJWTForProvider(provider configv1.OIDCProvider, configMapLister core
return apiserverv1beta1.JWTAuthenticator{}, fmt.Errorf("generating claimMappings for provider %q: %v", provider.Name, err)
}

claimValidationRules, err := generateClaimValidationRules(provider.ClaimValidationRules...)
claimValidationRules, err := generateClaimValidationRules(featureGates, provider.ClaimValidationRules...)
if err != nil {
return apiserverv1beta1.JWTAuthenticator{}, fmt.Errorf("generating claimValidationRules for provider %q: %v", provider.Name, err)
}

var userValidationRules []apiserverv1beta1.UserValidationRule
if featureGates.Enabled(features.FeatureGateExternalOIDCWithUpstreamParity) {
userValidationRules, err = generateUserValidationRules(featureGates, provider.UserValidationRules)
if err != nil {
return apiserverv1beta1.JWTAuthenticator{}, fmt.Errorf("generating userValidationRules for provider %q: %v", provider.Name, err)
}
}
out.Issuer = issuer
out.ClaimMappings = claimMappings
out.ClaimValidationRules = claimValidationRules
out.UserValidationRules = userValidationRules

return out, nil
}

func generateIssuer(issuer configv1.TokenIssuer, configMapLister corev1listers.ConfigMapLister, serviceAccountIssuer string) (apiserverv1beta1.Issuer, error) {
func generateIssuer(issuer configv1.TokenIssuer, featureGates featuregates.FeatureGate, configMapLister corev1listers.ConfigMapLister, serviceAccountIssuer string) (apiserverv1beta1.Issuer, error) {
out := apiserverv1beta1.Issuer{}

if len(serviceAccountIssuer) > 0 {
Expand All @@ -215,6 +223,7 @@ func generateIssuer(issuer configv1.TokenIssuer, configMapLister corev1listers.C
for _, audience := range issuer.Audiences {
out.Audiences = append(out.Audiences, string(audience))
}
out.DiscoveryURL = &issuer.DiscoveryURL

if len(issuer.CertificateAuthority.Name) > 0 {
ca, err := getCertificateAuthorityFromConfigMap(issuer.CertificateAuthority.Name, configMapLister)
Expand Down Expand Up @@ -394,11 +403,11 @@ func generateExtraMapping(extraMapping configv1.ExtraMapping) (apiserverv1beta1.
return out, nil
}

func generateClaimValidationRules(claimValidationRules ...configv1.TokenClaimValidationRule) ([]apiserverv1beta1.ClaimValidationRule, error) {
func generateClaimValidationRules(featureGates featuregates.FeatureGate, claimValidationRules ...configv1.TokenClaimValidationRule) ([]apiserverv1beta1.ClaimValidationRule, error) {
out := []apiserverv1beta1.ClaimValidationRule{}
errs := []error{}
for _, claimValidationRule := range claimValidationRules {
rule, err := generateClaimValidationRule(claimValidationRule)
rule, err := generateClaimValidationRule(claimValidationRule, featureGates)
if err != nil {
errs = append(errs, fmt.Errorf("generating claimValidationRule: %v", err))
continue
Expand All @@ -414,7 +423,7 @@ func generateClaimValidationRules(claimValidationRules ...configv1.TokenClaimVal
return out, nil
}

func generateClaimValidationRule(claimValidationRule configv1.TokenClaimValidationRule) (apiserverv1beta1.ClaimValidationRule, error) {
func generateClaimValidationRule(claimValidationRule configv1.TokenClaimValidationRule, featureGates featuregates.FeatureGate) (apiserverv1beta1.ClaimValidationRule, error) {
out := apiserverv1beta1.ClaimValidationRule{}

// Currently, the authentications.config.openshift.io CRD only allows setting a claim and required value for the
Expand All @@ -428,13 +437,59 @@ func generateClaimValidationRule(claimValidationRule configv1.TokenClaimValidati

out.Claim = claimValidationRule.RequiredClaim.Claim
out.RequiredValue = claimValidationRule.RequiredClaim.RequiredValue
case configv1.TokenValidationRuleTypeCEL:
if len(claimValidationRule.CEL.Expression) == 0 {
return apiserverv1beta1.ClaimValidationRule{}, fmt.Errorf("claimValidationRule.type is %s and expression is not set", configv1.TokenValidationRuleTypeCEL)
}

// validate CEL expression
if err := validateCELExpression(&authenticationcel.ClaimMappingExpression{
Expression: claimValidationRule.CEL.Expression,
}); err != nil {
return apiserverv1beta1.ClaimValidationRule{}, fmt.Errorf("invalid CEL expression: %v", err)
}

out.Expression = claimValidationRule.CEL.Expression
out.Message = claimValidationRule.CEL.Message

default:
return apiserverv1beta1.ClaimValidationRule{}, fmt.Errorf("unknown claimValidationRule type %q", claimValidationRule.Type)
}

return out, nil
}

func generateUserValidationRule(rule configv1.TokenUserValidationRule, featureGates featuregates.FeatureGate) (apiserverv1beta1.UserValidationRule, error) {
if len(rule.Expression) == 0 {
return apiserverv1beta1.UserValidationRule{}, fmt.Errorf("userValidationRule expression must be non-empty")
}

return apiserverv1beta1.UserValidationRule{
Expression: rule.Expression,
Message: rule.Message,
}, nil
}

func generateUserValidationRules(featureGates featuregates.FeatureGate, rules []configv1.TokenUserValidationRule) ([]apiserverv1beta1.UserValidationRule, error) {
out := []apiserverv1beta1.UserValidationRule{}
errs := []error{}

for _, r := range rules {
uvr, err := generateUserValidationRule(r, featureGates)
if err != nil {
errs = append(errs, fmt.Errorf("generating userValidationRule: %v", err))
continue
}
out = append(out, uvr)
}

if len(errs) > 0 {
return nil, errors.Join(errs...)
}

return out, nil
}

// getExpectedApplyConfig serializes the input authConfig into JSON and creates an apply configuration
// for a configmap with the serialized authConfig in the right key.
func getExpectedApplyConfig(authConfig apiserverv1beta1.AuthenticationConfiguration) (*corev1ac.ConfigMapApplyConfiguration, error) {
Expand Down
Loading