-
Notifications
You must be signed in to change notification settings - Fork 99
CNTRLPLANE-333: Add generation logic for new uid
and extra
fields in the Authentication CR
#763
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
CNTRLPLANE-333: Add generation logic for new uid
and extra
fields in the Authentication CR
#763
Conversation
uid
and extra
fields in the Authentication CRuid
and extra
fields in the Authentication CR
@everettraven: This pull request references CNTRLPLANE-333 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.19.0" version, but no target version was set. In response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
1cedc4b
to
042cceb
Compare
40c4b3c
to
2d8d6a2
Compare
uid
and extra
fields in the Authentication CRuid
and extra
fields in the Authentication CR
@@ -111,7 +118,7 @@ func (c *externalOIDCController) sync(ctx context.Context, syncCtx factory.SyncC | |||
return nil | |||
} | |||
|
|||
if err := validateAuthConfig(*authConfig); err != nil { | |||
if err := validateAuthConfig(*authConfig, []string{auth.Spec.ServiceAccountIssuer}); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment explaining why we're adding the ServiceAccountIssuer as a disallowed issuer for the OIDC config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually something I missed in cleaning up the vendoring of the KAS validation logic.
We should however still check this when generating the issuer URL so I'll move this check to the right place.
if extraMapping.Key == "" { | ||
return out, fmt.Errorf("extra mapping must set a key, but none was provided: %v", extraMapping) | ||
} | ||
|
||
if extraMapping.ValueExpression == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, use string length comparisons.
// Currently, the authentications.config.openshift.io CRD only allows setting a claim for the mapping | ||
// and does not allow setting a CEL expression like the upstream. This is likely to change in the future, | ||
// but for now just set the claim. | ||
if usernameClaimMapping.Claim == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK it's an openshift convention to use len(str) ==/> 0
comparisons instead of str ==/!= ""
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I'll update this to follow conventions.
case uid.Claim != "" && uid.Expression == "": | ||
out.Claim = uid.Claim | ||
case uid.Expression != "" && uid.Claim == "": | ||
out.Expression = uid.Expression | ||
case uid.Claim != "" && uid.Expression != "": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, use string length comparisons.
}{ | ||
{ | ||
name: "auth resource not found", | ||
expectError: true, | ||
featureGates: featuregates.NewFeatureGate( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would only create featureGates in the tests that they're needed to make it easier to follow each test case. For example this makes me think, why do we need FeatureGateExternalOIDCWithAdditionalClaimMappings
as disabled for the test? What about ExternalOIDC
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would only create featureGates in the tests that they're needed to make it easier to follow each test case.
I originally tried that, but without explicitly setting it for each test we break the expectations that we in our actual implementation that we will always have access to feature gates and that the features.FeatureGateExternalOIDCWithAdditionalClaimMappings
feature has been registered in that set of feature gates.
Instead of changing the expectations of the implementation in the controller, which I felt were correct, I opted for changing the structure of the tests to be more in line with what the actual state of the world would look like.
For example this makes me think, why do we need FeatureGateExternalOIDCWithAdditionalClaimMappings as disabled for the test?
Anywhere it is disabled is not reliant on it being enabled to function.
What about ExternalOIDC?
There is no logic within the controller itself that is gated on the ExternalOIDC
feature gate being enabled.
@@ -685,7 +685,7 @@ func prepareExternalOIDC( | |||
return nil, nil, err | |||
} | |||
|
|||
if !featureGates.Enabled(features.FeatureGateExternalOIDC) { | |||
if !(featureGates.Enabled(features.FeatureGateExternalOIDC) || featureGates.Enabled(features.FeatureGateExternalOIDCWithAdditionalClaimMappings)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, personal preference, feel free to ignore:
if !(featureGates.Enabled(features.FeatureGateExternalOIDC) || featureGates.Enabled(features.FeatureGateExternalOIDCWithAdditionalClaimMappings)) { | |
if !featureGates.Enabled(features.FeatureGateExternalOIDC) && !featureGates.Enabled(features.FeatureGateExternalOIDCWithAdditionalClaimMappings) { |
return &authConfig, nil | ||
} | ||
|
||
func generateJWTForProvider(provider configv1.OIDCProvider, configMapLister corev1listers.ConfigMapLister, featureGates featuregates.FeatureGate) (apiserverv1beta1.JWTAuthenticator, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel it's a more common pattern to return (*obj, error) so that you can return nil, err
where no valid object is returned. Sometimes this can mess up non-simple error checking with multiple conditions and cause confusion, as it's much easier to distinguish the nil pointer from a zero value for complex types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It generally is, but I decided to break from this pattern to avoid having to litter nil
checks everywhere to prevent panics.
The type this bubbles up to and populates is not a pointer so doing the (*obj, error)
pattern means that every call to these methods would need to essentially do:
obj, err := generateThing(...)
if err != nil {
handleErr()
}
if obj == nil {
handleNilObj()
}
doStuffWithNonPointerObj(*obj)
While I understand the point about distinguishing between nil
and zero value, I don't think we actually care about the difference between nil
and zero value in this case. We really only care if we got an error and if we did we assume that the generation for the provider was unsuccessful.
/retest-required |
Because openshift/api#2352 has merged, we will no longer be able to create an Holding until I get that taken care of. |
/hold cancel |
out.URL = issuer.URL | ||
out.AudienceMatchPolicy = apiserverv1beta1.AudienceMatchPolicyMatchAny | ||
|
||
caData, ok := caConfigMap.Data["ca-bundle.crt"] | ||
if !ok || len(caData) == 0 { | ||
return nil, fmt.Errorf("configmap %s/%s key \"ca-bundle.crt\" missing or empty", configNamespace, provider.Issuer.CertificateAuthority.Name) | ||
} | ||
for _, audience := range issuer.Audiences { | ||
out.Audiences = append(out.Audiences, string(audience)) | ||
} | ||
|
||
jwt.Issuer.CertificateAuthority = caData | ||
if len(issuer.CertificateAuthority.Name) > 0 { | ||
ca, err := getCertificateAuthorityFromConfigMap(issuer.CertificateAuthority.Name, configMapLister) | ||
if err != nil { | ||
return out, fmt.Errorf("getting CertificateAuthority for issuer: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're sticking to returning objects rather than pointers, let's at least make sure we return empty objects when we encounter an error. We can only set the values to out
when we're ready to return the valid result. I'm worried that this might cause confusion if there's an error but some valid values in the result.
This pattern occurs in other places in this file as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is reasonable.
My thinking was along the lines of "if an error is returned, ignore any returned values", but I can understand the potential for confusion there.
Signed-off-by: Bryce Palmer <[email protected]>
Signed-off-by: Bryce Palmer <[email protected]>
a0beebc
to
6bbed73
Compare
Should be ready to go, removing hold. /hold cancel |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: everettraven, liouk The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
1 similar comment
/retest-required |
1 similar comment
/retest-required |
Signed-off-by: Bryce Palmer <[email protected]>
New changes are detected. LGTM label has been removed. |
/retest |
Signed-off-by: Bryce Palmer <[email protected]>
Signed-off-by: Bryce Palmer <[email protected]>
@everettraven: The following tests failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
No description provided.