From fe120779514c89e187de2ea73ea2935a6adeccf1 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Mon, 26 Aug 2024 15:23:29 -0400 Subject: [PATCH 01/15] wip Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index fd0f89e9..8bc19af8 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -22,7 +22,7 @@ import ( "sort" "sync" - api "github.com/kuadrant/authorino/api/v1beta1" + api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/auth" "github.com/kuadrant/authorino/pkg/evaluators" authorization_evaluators "github.com/kuadrant/authorino/pkg/evaluators/authorization" @@ -163,13 +163,16 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedIdentityConfigs := make([]auth.AuthConfigEvaluator, 0) ctxWithLogger = log.IntoContext(ctx, log.FromContext(ctx).WithName("identity")) - authConfigIdentityConfigs := authConfig.Spec.Identity + authConfigIdentityConfigs := authConfig.Spec.Authentication if len(authConfigIdentityConfigs) == 0 { - authConfigIdentityConfigs = append(authConfigIdentityConfigs, &api.Identity{ - Name: "anonymous", - Anonymous: &api.Identity_Anonymous{}, - }) + authConfigIdentityConfigs["anonymous"] = api.AuthenticationSpec{ + CommonEvaluatorSpec: api.CommonEvaluatorSpec{}, + Credentials: api.Credentials{}, + AuthenticationMethodSpec: api.AuthenticationMethodSpec{ + AnonymousAccess: &api.AnonymousAccessSpec{}, + }, + } } for _, identity := range authConfigIdentityConfigs { From f02f01d615594129077faafff21fbd95b3153972 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:10:14 -0400 Subject: [PATCH 02/15] wip: done with ExtendedProperties Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 114 +++++++-------- controllers/auth_config_controller_test.go | 131 ++++++++++-------- .../auth_config_status_updater_test.go | 4 +- 3 files changed, 133 insertions(+), 116 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 8bc19af8..10b04ae0 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -22,6 +22,7 @@ import ( "sort" "sync" + old "github.com/kuadrant/authorino/api/v1beta1" api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/auth" "github.com/kuadrant/authorino/pkg/evaluators" @@ -175,17 +176,23 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } } - for _, identity := range authConfigIdentityConfigs { - extendedProperties := make([]evaluators.IdentityExtension, len(identity.ExtendedProperties)) - for i, property := range identity.ExtendedProperties { - extendedProperties[i] = evaluators.NewIdentityExtension(property.Name, json.JSONValue{ + for identityCfgName, identity := range authConfigIdentityConfigs { + extendedProperties := make([]evaluators.IdentityExtension, len(identity.Defaults)+len(identity.Overrides)) + for propertyName, property := range identity.Defaults { + extendedProperties = append(extendedProperties, evaluators.NewIdentityExtension(propertyName, json.JSONValue{ Static: property.Value, - Pattern: property.ValueFrom.AuthJSON, - }, property.Overwrite) + Pattern: property.Selector, + }, false)) + } + for propertyName, property := range identity.Overrides { + extendedProperties = append(extendedProperties, evaluators.NewIdentityExtension(propertyName, json.JSONValue{ + Static: property.Value, + Pattern: property.Selector, + }, true)) } translatedIdentity := &evaluators.IdentityConfig{ - Name: identity.Name, + Name: identityCfgName, Priority: identity.Priority, Conditions: buildJSONExpression(authConfig, identity.Conditions, jsonexp.All), ExtendedProperties: extendedProperties, @@ -195,7 +202,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if identity.Cache != nil { ttl := identity.Cache.TTL if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + ttl = old.EvaluatorDefaultCacheTTL } translatedIdentity.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&identity.Cache.Key), @@ -207,7 +214,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf switch identity.GetType() { // oauth2 - case api.IdentityOAuth2: + case old.IdentityOAuth2: oauth2Identity := identity.OAuth2 secret := &v1.Secret{} @@ -227,11 +234,11 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) // oidc - case api.IdentityOidc: + case old.IdentityOidc: translatedIdentity.OIDC = identity_evaluators.NewOIDC(identity.Oidc.Endpoint, authCred, identity.Oidc.TTL, ctxWithLogger) // apiKey - case api.IdentityApiKey: + case old.IdentityApiKey: namespace := authConfig.Namespace if identity.APIKey.AllNamespaces && r.ClusterWide() { namespace = "" @@ -243,7 +250,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedIdentity.APIKey = identity_evaluators.NewApiKeyIdentity(identity.Name, selector, namespace, authCred, r.Client, ctxWithLogger) // MTLS - case api.IdentityMTLS: + case old.IdentityMTLS: namespace := authConfig.Namespace if identity.MTLS.AllNamespaces && r.ClusterWide() { namespace = "" @@ -255,20 +262,20 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedIdentity.MTLS = identity_evaluators.NewMTLSIdentity(identity.Name, selector, namespace, r.Client, ctxWithLogger) // kubernetes auth - case api.IdentityKubernetesAuth: + case old.IdentityKubernetesAuth: if k8sAuthConfig, err := identity_evaluators.NewKubernetesAuthIdentity(authCred, identity.KubernetesAuth.Audiences); err != nil { return nil, err } else { translatedIdentity.KubernetesAuth = k8sAuthConfig } - case api.IdentityPlain: + case old.IdentityPlain: translatedIdentity.Plain = &identity_evaluators.Plain{Pattern: identity.Plain.AuthJSON} - case api.IdentityAnonymous: + case old.IdentityAnonymous: translatedIdentity.Noop = &identity_evaluators.Noop{AuthCredentials: authCred} - case api.TypeUnknown: + case old.TypeUnknown: return nil, fmt.Errorf("unknown identity type %v", identity) } @@ -289,7 +296,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if metadata.Cache != nil { ttl := metadata.Cache.TTL if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + ttl = old.EvaluatorDefaultCacheTTL } translatedMetadata.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&metadata.Cache.Key), @@ -299,7 +306,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf switch metadata.GetType() { // uma - case api.MetadataUma: + case old.MetadataUma: secret := &v1.Secret{} if err := r.Client.Get(ctx, types.NamespacedName{ Namespace: authConfig.Namespace, @@ -319,7 +326,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // user_info - case api.MetadataUserinfo: + case old.MetadataUserinfo: translatedMetadata.UserInfo = &metadata_evaluators.UserInfo{} if idConfig, err := findIdentityConfigByName(identityConfigs, metadata.UserInfo.IdentitySource); err != nil { @@ -329,14 +336,14 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // generic http - case api.MetadataGenericHTTP: + case old.MetadataGenericHTTP: ev, err := r.buildGenericHttpEvaluator(ctx, metadata.GenericHTTP, authConfig.Namespace) if err != nil { return nil, err } translatedMetadata.GenericHTTP = ev - case api.TypeUnknown: + case old.TypeUnknown: return nil, fmt.Errorf("unknown metadata type %v", metadata) } @@ -357,7 +364,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if authorization.Cache != nil { ttl := authorization.Cache.TTL if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + ttl = old.EvaluatorDefaultCacheTTL } translatedAuthorization.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&authorization.Cache.Key), @@ -367,7 +374,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf switch authorization.GetType() { // opa - case api.AuthorizationOPA: + case old.AuthorizationOPA: policyName := authConfig.GetNamespace() + "/" + authConfig.GetName() + "/" + authorization.Name opa := authorization.OPA externalRegistry := opa.ExternalRegistry @@ -398,12 +405,12 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // json - case api.AuthorizationJSONPatternMatching: + case old.AuthorizationJSONPatternMatching: translatedAuthorization.JSON = &authorization_evaluators.JSONPatternMatching{ Rules: buildJSONExpression(authConfig, authorization.JSON.Rules, jsonexp.All), } - case api.AuthorizationKubernetesAuthz: + case old.AuthorizationKubernetesAuthz: user := authorization.KubernetesAuthz.User authorinoUser := json.JSONValue{Static: user.Value, Pattern: user.ValueFrom.AuthJSON} @@ -426,7 +433,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf return nil, err } - case api.AuthorizationAuthzed: + case old.AuthorizationAuthzed: authzed := authorization.Authzed secret := &v1.Secret{} @@ -449,7 +456,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedAuthorization.Authzed = translatedAuthzed - case api.TypeUnknown: + case old.TypeUnknown: return nil, fmt.Errorf("unknown authorization type %v", authorization) } @@ -471,7 +478,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if response.Cache != nil { ttl := response.Cache.TTL if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + ttl = old.EvaluatorDefaultCacheTTL } translatedResponse.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&response.Cache.Key), @@ -481,7 +488,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf switch response.GetType() { // wristband - case api.ResponseWristband: + case old.ResponseWristband: wristband := response.Wristband signingKeys := make([]jose.JSONWebKey, 0) @@ -529,7 +536,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // dynamic json - case api.ResponseDynamicJSON: + case old.ResponseDynamicJSON: jsonProperties := make([]json.JSONProperty, 0) for _, property := range response.JSON.Properties { @@ -545,7 +552,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) // plain - case api.ResponsePlain: + case old.ResponsePlain: translatedResponse.Plain = &response_evaluators.Plain{ JSONValue: json.JSONValue{ Static: response.Plain.Value, @@ -553,7 +560,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf }, } - case api.TypeUnknown: + case old.TypeUnknown: return nil, fmt.Errorf("unknown response type %v", response) } @@ -572,14 +579,14 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf switch callback.GetType() { // http - case api.CallbackHTTP: + case old.CallbackHTTP: ev, err := r.buildGenericHttpEvaluator(ctx, callback.HTTP, authConfig.Namespace) if err != nil { return nil, err } translatedCallback.HTTP = ev - case api.TypeUnknown: + case old.TypeUnknown: return nil, fmt.Errorf("unknown callback type %v", callback) } @@ -646,7 +653,7 @@ func (r *AuthConfigReconciler) bootstrapIndex(ctx context.Context) error { return nil } - authConfigList := api.AuthConfigList{} + authConfigList := old.AuthConfigList{} listOptions := []client.ListOption{} if r.LabelSelector != nil { listOptions = append(listOptions, client.MatchingLabelsSelector{Selector: r.LabelSelector}) @@ -701,7 +708,7 @@ func (r *AuthConfigReconciler) ClusterWide() bool { func (r *AuthConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&api.AuthConfig{}, builder.WithPredicates(LabelSelectorPredicate(r.LabelSelector))). + For(&old.AuthConfig{}, builder.WithPredicates(LabelSelectorPredicate(r.LabelSelector))). Complete(r) } @@ -712,7 +719,7 @@ func (r *AuthConfigReconciler) Ready(includes, _ []string, _ bool) error { for id, status := range r.StatusReport.ReadAll() { switch status.Reason { - case api.StatusReasonReconciled: + case old.StatusReasonReconciled: continue default: return fmt.Errorf("authconfig is not ready: %s (reason: %s)", id, status.Reason) @@ -721,7 +728,7 @@ func (r *AuthConfigReconciler) Ready(includes, _ []string, _ bool) error { return nil } -func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, http *api.Metadata_GenericHTTP, namespace string) (*metadata_evaluators.GenericHttp, error) { +func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, http *old.Metadata_GenericHTTP, namespace string) (*metadata_evaluators.GenericHttp, error) { var sharedSecret string if sharedSecretRef := http.SharedSecret; sharedSecretRef != nil { secret := &v1.Secret{} @@ -805,24 +812,24 @@ func findIdentityConfigByName(identityConfigs []evaluators.IdentityConfig, name return nil, fmt.Errorf("missing identity config %v", name) } -func buildJSONExpression(authConfig *api.AuthConfig, patterns []api.JSONPattern, op func(...jsonexp.Expression) jsonexp.Expression) jsonexp.Expression { +func buildJSONExpression(authConfig *api.AuthConfig, patterns []api.PatternExpressionOrRef, op func(...jsonexp.Expression) jsonexp.Expression) jsonexp.Expression { var expression []jsonexp.Expression for _, pattern := range patterns { // patterns or refs expression = append(expression, buildJSONExpressionPatterns(authConfig, pattern)...) // all if len(pattern.All) > 0 { - p := make([]api.JSONPattern, len(pattern.All)) + p := make([]api.PatternExpressionOrRef, len(pattern.All)) for i, ptn := range pattern.All { - p[i] = ptn.JSONPattern + p[i] = ptn.PatternExpressionOrRef } expression = append(expression, buildJSONExpression(authConfig, p, jsonexp.All)) } // any if len(pattern.Any) > 0 { - p := make([]api.JSONPattern, len(pattern.Any)) + p := make([]api.PatternExpressionOrRef, len(pattern.Any)) for i, ptn := range pattern.Any { - p[i] = ptn.JSONPattern + p[i] = ptn.PatternExpressionOrRef } expression = append(expression, buildJSONExpression(authConfig, p, jsonexp.Any)) } @@ -830,13 +837,12 @@ func buildJSONExpression(authConfig *api.AuthConfig, patterns []api.JSONPattern, return op(expression...) } -func buildJSONExpressionPatterns(authConfig *api.AuthConfig, pattern api.JSONPattern) []jsonexp.Expression { - expressionsToAdd := api.JSONPatternExpressions{} - - if expressionsByRef, found := authConfig.Spec.Patterns[pattern.JSONPatternName]; found { +func buildJSONExpressionPatterns(authConfig *api.AuthConfig, pattern api.PatternExpressionOrRef) []jsonexp.Expression { + expressionsToAdd := api.PatternExpressions{} + if expressionsByRef, found := authConfig.Spec.NamedPatterns[pattern.PatternRef.Name]; found { expressionsToAdd = append(expressionsToAdd, expressionsByRef...) - } else if pattern.JSONPatternExpression.Operator != "" { - expressionsToAdd = append(expressionsToAdd, pattern.JSONPatternExpression) + } else if pattern.PatternExpression.Operator != "" { + expressionsToAdd = append(expressionsToAdd, pattern.PatternExpression) } expressions := make([]jsonexp.Expression, len(expressionsToAdd)) @@ -846,7 +852,7 @@ func buildJSONExpressionPatterns(authConfig *api.AuthConfig, pattern api.JSONPat return expressions } -func buildJSONExpressionPattern(expression api.JSONPatternExpression) jsonexp.Expression { +func buildJSONExpressionPattern(expression api.PatternExpression) jsonexp.Expression { return jsonexp.Pattern{ Selector: expression.Selector, Operator: jsonexp.OperatorFromString(string(expression.Operator)), @@ -854,7 +860,7 @@ func buildJSONExpressionPattern(expression api.JSONPatternExpression) jsonexp.Ex } } -func buildAuthorinoDenyWithValues(denyWithSpec *api.DenyWithSpec) *evaluators.DenyWithValues { +func buildAuthorinoDenyWithValues(denyWithSpec *old.DenyWithSpec) *evaluators.DenyWithValues { if denyWithSpec == nil { return nil } @@ -872,18 +878,18 @@ func buildAuthorinoDenyWithValues(denyWithSpec *api.DenyWithSpec) *evaluators.De } } -func getJsonFromStaticDynamic(value *api.StaticOrDynamicValue) *json.JSONValue { +func getJsonFromStaticDynamic(value *api.ValueOrSelector) *json.JSONValue { if value == nil { return nil } return &json.JSONValue{ Static: value.Value, - Pattern: value.ValueFrom.AuthJSON, + Pattern: value.Selector, } } -func authzedObjectToJsonValues(obj *api.AuthzedObject) (name json.JSONValue, kind json.JSONValue) { +func authzedObjectToJsonValues(obj *old.AuthzedObject) (name json.JSONValue, kind json.JSONValue) { if obj == nil { return } diff --git a/controllers/auth_config_controller_test.go b/controllers/auth_config_controller_test.go index e1ac0b46..392ab37a 100644 --- a/controllers/auth_config_controller_test.go +++ b/controllers/auth_config_controller_test.go @@ -6,7 +6,8 @@ import ( "os" "testing" - api "github.com/kuadrant/authorino/api/v1beta1" + old "github.com/kuadrant/authorino/api/v1beta1" + api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/evaluators" "github.com/kuadrant/authorino/pkg/httptest" "github.com/kuadrant/authorino/pkg/index" @@ -40,56 +41,46 @@ func TestMain(m *testing.M) { } func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { - return api.AuthConfig{ - TypeMeta: metav1.TypeMeta{ - Kind: "AuthConfig", - APIVersion: "authorino.kuadrant.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "auth-config-1", - Namespace: "authorino", - Labels: authConfigLabels, - }, - Spec: api.AuthConfigSpec{ - Hosts: []string{"echo-api"}, - Identity: []*api.Identity{ - { - Name: "keycloak", - Oidc: &api.Identity_OidcConfig{ - Endpoint: "http://127.0.0.1:9001/auth/realms/demo", - }, - ExtendedProperties: []api.ExtendedProperty{ - { - JsonProperty: api.JsonProperty{ - Name: "source", - Value: runtime.RawExtension{Raw: []byte(`"test"`)}, - }, + spec := old.AuthConfigSpec{ + Hosts: []string{"echo-api"}, + Identity: []*old.Identity{ + { + Name: "keycloak", + Oidc: &old.Identity_OidcConfig{ + Endpoint: "http://127.0.0.1:9001/auth/realms/demo", + }, + ExtendedProperties: []old.ExtendedProperty{ + { + JsonProperty: old.JsonProperty{ + Name: "source", + Value: runtime.RawExtension{Raw: []byte(`"test"`)}, }, }, }, }, - Metadata: []*api.Metadata{ - { - Name: "userinfo", - UserInfo: &api.Metadata_UserInfo{ - IdentitySource: "keycloak", - }, + }, + Metadata: []*old.Metadata{ + { + Name: "userinfo", + UserInfo: &old.Metadata_UserInfo{ + IdentitySource: "keycloak", }, - { - Name: "resource-data", - UMA: &api.Metadata_UMA{ - Endpoint: "http://127.0.0.1:9001/auth/realms/demo", - Credentials: &v1.LocalObjectReference{ - Name: "secret", - }, + }, + { + Name: "resource-data", + UMA: &old.Metadata_UMA{ + Endpoint: "http://127.0.0.1:9001/auth/realms/demo", + Credentials: &v1.LocalObjectReference{ + Name: "secret", }, }, }, - Authorization: []*api.Authorization{ - { - Name: "main-policy", - OPA: &api.Authorization_OPA{ - InlineRego: ` + }, + Authorization: []*old.Authorization{ + { + Name: "main-policy", + OPA: &old.Authorization_OPA{ + InlineRego: ` method = object.get(input.context.request.http, "method", "") path = object.get(input.context.request.http, "path", "") @@ -97,18 +88,17 @@ func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { method == "GET" path = "/allow" }`, - }, }, - { - Name: "some-extra-rules", - JSON: &api.Authorization_JSONPatternMatching{ - Rules: []api.JSONPattern{ - { - JSONPatternExpression: api.JSONPatternExpression{ - Selector: "context.identity.role", - Operator: "eq", - Value: "admin", - }, + }, + { + Name: "some-extra-rules", + JSON: &old.Authorization_JSONPatternMatching{ + Rules: []old.JSONPattern{ + { + JSONPatternExpression: old.JSONPatternExpression{ + Selector: "context.identity.role", + Operator: "eq", + Value: "admin", }, }, }, @@ -116,6 +106,27 @@ func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { }, }, } + return api.AuthConfig{ + TypeMeta: metav1.TypeMeta{ + Kind: "AuthConfig", + APIVersion: "authorino.kuadrant.io/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "auth-config-1", + Namespace: "authorino", + Labels: authConfigLabels, + }, + Spec: api.AuthConfigSpec{ + Hosts: []string{"echo-api"}, + NamedPatterns: nil, + Conditions: nil, + Authentication: nil, + Metadata: nil, + Authorization: nil, + Response: nil, + Callbacks: nil, + }, + } } func newTestOAuthClientSecret() v1.Secret { @@ -387,26 +398,26 @@ func TestBootstrapIndex(t *testing.T) { indexMock := mock_index.NewMockIndex(mockController) authConfig := newTestAuthConfig(map[string]string{"scope": "in"}) - authConfig.Status.Summary = api.Summary{ + authConfig.Status.Summary = api.AuthConfigStatusSummary{ Ready: true, HostsReady: authConfig.Spec.Hosts, NumHostsReady: fmt.Sprintf("%d/%d", len(authConfig.Spec.Hosts), len(authConfig.Spec.Hosts)), - NumIdentitySources: int64(len(authConfig.Spec.Identity)), + NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response)), + NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), FestivalWristbandEnabled: false, } authConfigOutOfScope := newTestAuthConfig(map[string]string{"scope": "out"}) - authConfigOutOfScope.Status.Summary = api.Summary{ + authConfigOutOfScope.Status.Summary = api.AuthConfigStatusSummary{ Ready: true, HostsReady: authConfig.Spec.Hosts, NumHostsReady: fmt.Sprintf("%d/%d", len(authConfig.Spec.Hosts), len(authConfig.Spec.Hosts)), - NumIdentitySources: int64(len(authConfig.Spec.Identity)), + NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response)), + NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), FestivalWristbandEnabled: false, } diff --git a/controllers/auth_config_status_updater_test.go b/controllers/auth_config_status_updater_test.go index 01125609..c35eecea 100644 --- a/controllers/auth_config_status_updater_test.go +++ b/controllers/auth_config_status_updater_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - api "github.com/kuadrant/authorino/api/v1beta1" + api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/log" "github.com/golang/mock/gomock" @@ -176,7 +176,7 @@ func mockStatusUpdateAuthConfigWithLabelsAndHosts(labels map[string]string, host return api.AuthConfig{ TypeMeta: metav1.TypeMeta{ Kind: "AuthConfig", - APIVersion: "authorino.kuadrant.io/v1beta1", + APIVersion: "authorino.kuadrant.io/v1beta2", }, ObjectMeta: metav1.ObjectMeta{ Name: "auth-config-1", From a2dc46488166b16674b30aed5e79e412c8f7b03a Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:15:20 -0400 Subject: [PATCH 03/15] wip: done with eof utility functions Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 10b04ae0..cab17724 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -451,8 +451,8 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf SharedSecret: sharedSecret, Permission: *getJsonFromStaticDynamic(&authzed.Permission), } - translatedAuthzed.Subject, translatedAuthzed.SubjectKind = authzedObjectToJsonValues(authzed.Subject) - translatedAuthzed.Resource, translatedAuthzed.ResourceKind = authzedObjectToJsonValues(authzed.Resource) + translatedAuthzed.Subject, translatedAuthzed.SubjectKind = spiceDBObjectToJsonValues(authzed.Subject) + translatedAuthzed.Resource, translatedAuthzed.ResourceKind = spiceDBObjectToJsonValues(authzed.Resource) translatedAuthorization.Authzed = translatedAuthzed @@ -860,14 +860,14 @@ func buildJSONExpressionPattern(expression api.PatternExpression) jsonexp.Expres } } -func buildAuthorinoDenyWithValues(denyWithSpec *old.DenyWithSpec) *evaluators.DenyWithValues { +func buildAuthorinoDenyWithValues(denyWithSpec *api.DenyWithSpec) *evaluators.DenyWithValues { if denyWithSpec == nil { return nil } headers := make([]json.JSONProperty, 0, len(denyWithSpec.Headers)) - for _, header := range denyWithSpec.Headers { - headers = append(headers, json.JSONProperty{Name: header.Name, Value: json.JSONValue{Static: header.Value, Pattern: header.ValueFrom.AuthJSON}}) + for name, header := range denyWithSpec.Headers { + headers = append(headers, json.JSONProperty{Name: name, Value: json.JSONValue{Static: header.Value, Pattern: header.Selector}}) } return &evaluators.DenyWithValues{ @@ -889,7 +889,7 @@ func getJsonFromStaticDynamic(value *api.ValueOrSelector) *json.JSONValue { } } -func authzedObjectToJsonValues(obj *old.AuthzedObject) (name json.JSONValue, kind json.JSONValue) { +func spiceDBObjectToJsonValues(obj *api.SpiceDBObject) (name json.JSONValue, kind json.JSONValue) { if obj == nil { return } From 4dd6f3d5065cd464810d0f56c0b5d00b553478bc Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:25:34 -0400 Subject: [PATCH 04/15] wip: done with AuthCredentials Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 55 ++++++++++++++++++--------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index cab17724..e6e1b87e 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -210,7 +210,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) } - authCred := auth.NewAuthCredential(identity.Credentials.KeySelector, string(identity.Credentials.In)) + authCred := newAuthCredential(identity.Credentials) switch identity.GetType() { // oauth2 @@ -394,7 +394,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf externalSource := &authorization_evaluators.OPAExternalSource{ Endpoint: externalRegistry.Endpoint, SharedSecret: sharedSecret, - AuthCredentials: auth.NewAuthCredential(externalRegistry.Credentials.KeySelector, string(externalRegistry.Credentials.In)), + AuthCredentials: newAuthCredential(externalRegistry.Credentials), TTL: externalRegistry.TTL, } @@ -569,24 +569,24 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedCallbackConfigs := make([]auth.AuthConfigEvaluator, 0) - for _, callback := range authConfig.Spec.Callbacks { + for name, callback := range authConfig.Spec.Callbacks { translatedCallback := &evaluators.CallbackConfig{ - Name: callback.Name, + Name: name, Priority: callback.Priority, Conditions: buildJSONExpression(authConfig, callback.Conditions, jsonexp.All), Metrics: callback.Metrics, } - switch callback.GetType() { + switch callback.GetMethod() { // http - case old.CallbackHTTP: - ev, err := r.buildGenericHttpEvaluator(ctx, callback.HTTP, authConfig.Namespace) + case api.HttpCallback: + ev, err := r.buildGenericHttpEvaluator(ctx, callback.Http, authConfig.Namespace) if err != nil { return nil, err } translatedCallback.HTTP = ev - case old.TypeUnknown: + case api.UnknownCallbackMethod: return nil, fmt.Errorf("unknown callback type %v", callback) } @@ -728,7 +728,7 @@ func (r *AuthConfigReconciler) Ready(includes, _ []string, _ bool) error { return nil } -func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, http *old.Metadata_GenericHTTP, namespace string) (*metadata_evaluators.GenericHttp, error) { +func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, http *api.HttpEndpointSpec, namespace string) (*metadata_evaluators.GenericHttp, error) { var sharedSecret string if sharedSecretRef := http.SharedSecret; sharedSecretRef != nil { secret := &v1.Secret{} @@ -754,27 +754,27 @@ func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, ht var body *json.JSONValue if b := http.Body; b != nil { - body = &json.JSONValue{Static: b.Value, Pattern: b.ValueFrom.AuthJSON} + body = &json.JSONValue{Static: b.Value, Pattern: b.Selector} } params := make([]json.JSONProperty, 0, len(http.Parameters)) - for _, param := range http.Parameters { + for name, param := range http.Parameters { params = append(params, json.JSONProperty{ - Name: param.Name, + Name: name, Value: json.JSONValue{ Static: param.Value, - Pattern: param.ValueFrom.AuthJSON, + Pattern: param.Selector, }, }) } headers := make([]json.JSONProperty, 0, len(http.Headers)) - for _, header := range http.Headers { + for name, header := range http.Headers { headers = append(headers, json.JSONProperty{ - Name: header.Name, + Name: name, Value: json.JSONValue{ Static: header.Value, - Pattern: header.ValueFrom.AuthJSON, + Pattern: header.Selector, }, }) } @@ -785,7 +785,7 @@ func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, ht } ev := &metadata_evaluators.GenericHttp{ - Endpoint: http.Endpoint, + Endpoint: http.Url, Method: method, Body: body, Parameters: params, @@ -797,12 +797,31 @@ func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, ht } if sharedSecret != "" || oauth2ClientCredentialsConfig != nil { - ev.AuthCredentials = auth.NewAuthCredential(http.Credentials.KeySelector, string(http.Credentials.In)) + ev.AuthCredentials = newAuthCredential(http.Credentials) } return ev, nil } +func newAuthCredential(creds api.Credentials) *auth.AuthCredential { + var in, key string + switch creds.GetType() { + case api.AuthorizationHeaderCredentials: + in = "authorization_header" + key = creds.AuthorizationHeader.Prefix + case api.CustomHeaderCredentials: + in = "custom_header" + key = creds.CustomHeader.Name + case api.QueryStringCredentials: + in = "query" + key = creds.QueryString.Name + case api.CookieCredentials: + in = "cookie" + key = creds.Cookie.Name + } + return auth.NewAuthCredential(key, in) +} + func findIdentityConfigByName(identityConfigs []evaluators.IdentityConfig, name string) (*evaluators.IdentityConfig, error) { for _, id := range identityConfigs { if id.Name == name { From 5d5e7740e465213a74106a7ae06a77d0f9c7b36f Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:31:55 -0400 Subject: [PATCH 05/15] wip: done with Identities Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index e6e1b87e..9a8f411a 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -212,10 +212,10 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf authCred := newAuthCredential(identity.Credentials) - switch identity.GetType() { + switch identity.GetMethod() { // oauth2 - case old.IdentityOAuth2: - oauth2Identity := identity.OAuth2 + case api.OAuth2TokenIntrospectionAuthentication: + oauth2Identity := identity.OAuth2TokenIntrospection secret := &v1.Secret{} if err := r.Client.Get(ctx, types.NamespacedName{ @@ -226,7 +226,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } translatedIdentity.OAuth2 = identity_evaluators.NewOAuth2Identity( - oauth2Identity.TokenIntrospectionUrl, + oauth2Identity.Url, oauth2Identity.TokenTypeHint, string(secret.Data["clientID"]), string(secret.Data["clientSecret"]), @@ -234,48 +234,48 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) // oidc - case old.IdentityOidc: - translatedIdentity.OIDC = identity_evaluators.NewOIDC(identity.Oidc.Endpoint, authCred, identity.Oidc.TTL, ctxWithLogger) + case api.JwtAuthentication: + translatedIdentity.OIDC = identity_evaluators.NewOIDC(identity.Jwt.IssuerUrl, authCred, identity.Jwt.TTL, ctxWithLogger) // apiKey - case old.IdentityApiKey: + case api.ApiKeyAuthentication: namespace := authConfig.Namespace - if identity.APIKey.AllNamespaces && r.ClusterWide() { + if identity.ApiKey.AllNamespaces && r.ClusterWide() { namespace = "" } - selector, err := metav1.LabelSelectorAsSelector(identity.APIKey.Selector) + selector, err := metav1.LabelSelectorAsSelector(identity.ApiKey.Selector) if err != nil { return nil, err } - translatedIdentity.APIKey = identity_evaluators.NewApiKeyIdentity(identity.Name, selector, namespace, authCred, r.Client, ctxWithLogger) + translatedIdentity.APIKey = identity_evaluators.NewApiKeyIdentity(identityCfgName, selector, namespace, authCred, r.Client, ctxWithLogger) // MTLS - case old.IdentityMTLS: + case api.X509ClientCertificateAuthentication: namespace := authConfig.Namespace - if identity.MTLS.AllNamespaces && r.ClusterWide() { + if identity.X509ClientCertificate.AllNamespaces && r.ClusterWide() { namespace = "" } - selector, err := metav1.LabelSelectorAsSelector(identity.MTLS.Selector) + selector, err := metav1.LabelSelectorAsSelector(identity.X509ClientCertificate.Selector) if err != nil { return nil, err } - translatedIdentity.MTLS = identity_evaluators.NewMTLSIdentity(identity.Name, selector, namespace, r.Client, ctxWithLogger) + translatedIdentity.MTLS = identity_evaluators.NewMTLSIdentity(identityCfgName, selector, namespace, r.Client, ctxWithLogger) // kubernetes auth - case old.IdentityKubernetesAuth: - if k8sAuthConfig, err := identity_evaluators.NewKubernetesAuthIdentity(authCred, identity.KubernetesAuth.Audiences); err != nil { + case api.KubernetesTokenReviewAuthentication: + if k8sAuthConfig, err := identity_evaluators.NewKubernetesAuthIdentity(authCred, identity.KubernetesTokenReview.Audiences); err != nil { return nil, err } else { translatedIdentity.KubernetesAuth = k8sAuthConfig } - case old.IdentityPlain: - translatedIdentity.Plain = &identity_evaluators.Plain{Pattern: identity.Plain.AuthJSON} + case api.PlainIdentityAuthentication: + translatedIdentity.Plain = &identity_evaluators.Plain{Pattern: identity.Plain.Selector} - case old.IdentityAnonymous: + case api.AnonymousAccessAuthentication: translatedIdentity.Noop = &identity_evaluators.Noop{AuthCredentials: authCred} - case old.TypeUnknown: + case api.UnknownAuthenticationMethod: return nil, fmt.Errorf("unknown identity type %v", identity) } @@ -285,9 +285,9 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedMetadataConfigs := make([]auth.AuthConfigEvaluator, 0) - for _, metadata := range authConfig.Spec.Metadata { + for name, metadata := range authConfig.Spec.Metadata { translatedMetadata := &evaluators.MetadataConfig{ - Name: metadata.Name, + Name: name, Priority: metadata.Priority, Conditions: buildJSONExpression(authConfig, metadata.Conditions, jsonexp.All), Metrics: metadata.Metrics, From 30285900d102623a7c2508f6f7adf3951266fbcf Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:33:06 -0400 Subject: [PATCH 06/15] wip: done with Metadata Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 9a8f411a..9e8ddf92 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -304,19 +304,19 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) } - switch metadata.GetType() { + switch metadata.GetMethod() { // uma - case old.MetadataUma: + case api.UmaResourceMetadata: secret := &v1.Secret{} if err := r.Client.Get(ctx, types.NamespacedName{ Namespace: authConfig.Namespace, - Name: metadata.UMA.Credentials.Name}, + Name: metadata.Uma.Credentials.Name}, secret); err != nil { return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. } if uma, err := metadata_evaluators.NewUMAMetadata( - metadata.UMA.Endpoint, + metadata.Uma.Endpoint, string(secret.Data["clientID"]), string(secret.Data["clientSecret"]), ); err != nil { @@ -326,7 +326,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // user_info - case old.MetadataUserinfo: + case api.UserInfoMetadata: translatedMetadata.UserInfo = &metadata_evaluators.UserInfo{} if idConfig, err := findIdentityConfigByName(identityConfigs, metadata.UserInfo.IdentitySource); err != nil { @@ -336,14 +336,14 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // generic http - case old.MetadataGenericHTTP: - ev, err := r.buildGenericHttpEvaluator(ctx, metadata.GenericHTTP, authConfig.Namespace) + case api.HttpMetadata: + ev, err := r.buildGenericHttpEvaluator(ctx, metadata.Http, authConfig.Namespace) if err != nil { return nil, err } translatedMetadata.GenericHTTP = ev - case old.TypeUnknown: + case api.UnknownMetadataMethod: return nil, fmt.Errorf("unknown metadata type %v", metadata) } From 4e0b30a206fad406d4a938e64b59951da541348b Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:46:08 -0400 Subject: [PATCH 07/15] wip: done with Authorization Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 52 ++++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 9e8ddf92..0f16465e 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -353,9 +353,10 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedAuthorizationConfigs := make([]auth.AuthConfigEvaluator, 0) ctxWithLogger = log.IntoContext(ctx, log.FromContext(ctx).WithName("authorization")) - for index, authorization := range authConfig.Spec.Authorization { + authzIndex := 0 + for authzName, authorization := range authConfig.Spec.Authorization { translatedAuthorization := &evaluators.AuthorizationConfig{ - Name: authorization.Name, + Name: authzName, Priority: authorization.Priority, Conditions: buildJSONExpression(authConfig, authorization.Conditions, jsonexp.All), Metrics: authorization.Metrics, @@ -372,12 +373,12 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) } - switch authorization.GetType() { + switch authorization.GetMethod() { // opa - case old.AuthorizationOPA: - policyName := authConfig.GetNamespace() + "/" + authConfig.GetName() + "/" + authorization.Name - opa := authorization.OPA - externalRegistry := opa.ExternalRegistry + case api.OpaAuthorization: + policyName := authConfig.GetNamespace() + "/" + authConfig.GetName() + "/" + authzName + opa := authorization.Opa + externalRegistry := opa.External secret := &v1.Secret{} var sharedSecret string @@ -392,49 +393,49 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } externalSource := &authorization_evaluators.OPAExternalSource{ - Endpoint: externalRegistry.Endpoint, + Endpoint: externalRegistry.Url, SharedSecret: sharedSecret, AuthCredentials: newAuthCredential(externalRegistry.Credentials), TTL: externalRegistry.TTL, } var err error - translatedAuthorization.OPA, err = authorization_evaluators.NewOPAAuthorization(policyName, opa.InlineRego, externalSource, opa.AllValues, index, ctxWithLogger) + translatedAuthorization.OPA, err = authorization_evaluators.NewOPAAuthorization(policyName, opa.Rego, externalSource, opa.AllValues, authzIndex, ctxWithLogger) if err != nil { return nil, err } // json - case old.AuthorizationJSONPatternMatching: + case api.PatternMatchingAuthorization: translatedAuthorization.JSON = &authorization_evaluators.JSONPatternMatching{ - Rules: buildJSONExpression(authConfig, authorization.JSON.Rules, jsonexp.All), + Rules: buildJSONExpression(authConfig, authorization.PatternMatching.Patterns, jsonexp.All), } - case old.AuthorizationKubernetesAuthz: - user := authorization.KubernetesAuthz.User - authorinoUser := json.JSONValue{Static: user.Value, Pattern: user.ValueFrom.AuthJSON} + case api.KubernetesSubjectAccessReviewAuthorization: + user := authorization.KubernetesSubjectAccessReview.User + authorinoUser := json.JSONValue{Static: user.Value, Pattern: user.Selector} var authorinoResourceAttributes *authorization_evaluators.KubernetesAuthzResourceAttributes - resourceAttributes := authorization.KubernetesAuthz.ResourceAttributes + resourceAttributes := authorization.KubernetesSubjectAccessReview.ResourceAttributes if resourceAttributes != nil { authorinoResourceAttributes = &authorization_evaluators.KubernetesAuthzResourceAttributes{ - Namespace: json.JSONValue{Static: resourceAttributes.Namespace.Value, Pattern: resourceAttributes.Namespace.ValueFrom.AuthJSON}, - Group: json.JSONValue{Static: resourceAttributes.Group.Value, Pattern: resourceAttributes.Group.ValueFrom.AuthJSON}, - Resource: json.JSONValue{Static: resourceAttributes.Resource.Value, Pattern: resourceAttributes.Resource.ValueFrom.AuthJSON}, - Name: json.JSONValue{Static: resourceAttributes.Name.Value, Pattern: resourceAttributes.Name.ValueFrom.AuthJSON}, - SubResource: json.JSONValue{Static: resourceAttributes.SubResource.Value, Pattern: resourceAttributes.SubResource.ValueFrom.AuthJSON}, - Verb: json.JSONValue{Static: resourceAttributes.Verb.Value, Pattern: resourceAttributes.Verb.ValueFrom.AuthJSON}, + Namespace: json.JSONValue{Static: resourceAttributes.Namespace.Value, Pattern: resourceAttributes.Namespace.Selector}, + Group: json.JSONValue{Static: resourceAttributes.Group.Value, Pattern: resourceAttributes.Group.Selector}, + Resource: json.JSONValue{Static: resourceAttributes.Resource.Value, Pattern: resourceAttributes.Resource.Selector}, + Name: json.JSONValue{Static: resourceAttributes.Name.Value, Pattern: resourceAttributes.Name.Selector}, + SubResource: json.JSONValue{Static: resourceAttributes.SubResource.Value, Pattern: resourceAttributes.SubResource.Selector}, + Verb: json.JSONValue{Static: resourceAttributes.Verb.Value, Pattern: resourceAttributes.Verb.Selector}, } } var err error - translatedAuthorization.KubernetesAuthz, err = authorization_evaluators.NewKubernetesAuthz(authorinoUser, authorization.KubernetesAuthz.Groups, authorinoResourceAttributes) + translatedAuthorization.KubernetesAuthz, err = authorization_evaluators.NewKubernetesAuthz(authorinoUser, authorization.KubernetesSubjectAccessReview.Groups, authorinoResourceAttributes) if err != nil { return nil, err } - case old.AuthorizationAuthzed: - authzed := authorization.Authzed + case api.SpiceDBAuthorization: + authzed := authorization.SpiceDB secret := &v1.Secret{} var sharedSecret string @@ -456,11 +457,12 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedAuthorization.Authzed = translatedAuthzed - case old.TypeUnknown: + case api.UnknownAuthorizationMethod: return nil, fmt.Errorf("unknown authorization type %v", authorization) } interfacedAuthorizationConfigs = append(interfacedAuthorizationConfigs, translatedAuthorization) + authzIndex++ } interfacedResponseConfigs := make([]auth.AuthConfigEvaluator, 0) From 4f9efb3eeae66c85b55ce63849d8aa0d5ec5891b Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 09:51:21 -0400 Subject: [PATCH 08/15] wip: done with deniesWith Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 0f16465e..36a914c6 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -571,9 +571,9 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedCallbackConfigs := make([]auth.AuthConfigEvaluator, 0) - for name, callback := range authConfig.Spec.Callbacks { + for callbackName, callback := range authConfig.Spec.Callbacks { translatedCallback := &evaluators.CallbackConfig{ - Name: name, + Name: callbackName, Priority: callback.Priority, Conditions: buildJSONExpression(authConfig, callback.Conditions, jsonexp.All), Metrics: callback.Metrics, @@ -606,9 +606,11 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // denyWith - if denyWith := authConfig.Spec.DenyWith; denyWith != nil { - translatedAuthConfig.Unauthenticated = buildAuthorinoDenyWithValues(denyWith.Unauthenticated) - translatedAuthConfig.Unauthorized = buildAuthorinoDenyWithValues(denyWith.Unauthorized) + if denyWith := authConfig.Spec.Response.Unauthenticated; denyWith != nil { + translatedAuthConfig.Unauthenticated = buildAuthorinoDenyWithValues(denyWith) + } + if denyWith := authConfig.Spec.Response.Unauthorized; denyWith != nil { + translatedAuthConfig.Unauthorized = buildAuthorinoDenyWithValues(denyWith) } return translatedAuthConfig, nil From c243383139fe753313dda2d502a511f2e5b908a1 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 10:01:25 -0400 Subject: [PATCH 09/15] wip: done with response Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 55 +++++++++++++++++++-------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 36a914c6..1acfe1d5 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -467,13 +467,36 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedResponseConfigs := make([]auth.AuthConfigEvaluator, 0) - for _, response := range authConfig.Spec.Response { + for responseName, headerResponse := range authConfig.Spec.Response.Success.Headers { translatedResponse := evaluators.NewResponseConfig( - response.Name, + responseName, + headerResponse.Priority, + buildJSONExpression(authConfig, headerResponse.Conditions, jsonexp.All), + "httpHeader", + headerResponse.Key, + headerResponse.Metrics, + ) + + if headerResponse.Cache != nil { + ttl := headerResponse.Cache.TTL + if ttl == 0 { + ttl = old.EvaluatorDefaultCacheTTL + } + translatedResponse.Cache = evaluators.NewEvaluatorCache( + *getJsonFromStaticDynamic(&headerResponse.Cache.Key), + ttl, + ) + } + interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) + } + + for responseName, response := range authConfig.Spec.Response.Success.DynamicMetadata { + translatedResponse := evaluators.NewResponseConfig( + responseName, response.Priority, buildJSONExpression(authConfig, response.Conditions, jsonexp.All), - string(response.Wrapper), - response.WrapperKey, + "envoyDynamicMetadata", + response.Key, response.Metrics, ) @@ -488,9 +511,9 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ) } - switch response.GetType() { + switch response.GetMethod() { // wristband - case old.ResponseWristband: + case api.WristbandAuthResponse: wristband := response.Wristband signingKeys := make([]jose.JSONWebKey, 0) @@ -516,12 +539,12 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } customClaims := make([]json.JSONProperty, 0) - for _, claim := range wristband.CustomClaims { + for claimName, claim := range wristband.CustomClaims { customClaims = append(customClaims, json.JSONProperty{ - Name: claim.Name, + Name: claimName, Value: json.JSONValue{ Static: claim.Value, - Pattern: claim.ValueFrom.AuthJSON, + Pattern: claim.Selector, }, }) } @@ -538,15 +561,15 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // dynamic json - case old.ResponseDynamicJSON: + case api.JsonAuthResponse: jsonProperties := make([]json.JSONProperty, 0) - for _, property := range response.JSON.Properties { + for propertyName, property := range response.Json.Properties { jsonProperties = append(jsonProperties, json.JSONProperty{ - Name: property.Name, + Name: propertyName, Value: json.JSONValue{ Static: property.Value, - Pattern: property.ValueFrom.AuthJSON, + Pattern: property.Selector, }, }) } @@ -554,15 +577,15 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) // plain - case old.ResponsePlain: + case api.PlainAuthResponse: translatedResponse.Plain = &response_evaluators.Plain{ JSONValue: json.JSONValue{ Static: response.Plain.Value, - Pattern: response.Plain.ValueFrom.AuthJSON, + Pattern: response.Plain.Selector, }, } - case old.TypeUnknown: + case api.UnknownAuthResponseMethod: return nil, fmt.Errorf("unknown response type %v", response) } From 920b7560aa2fefcf78d2ba86036253e01d1025bb Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 10:05:33 -0400 Subject: [PATCH 10/15] wip: done with 'old' api Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 1acfe1d5..a4bde94b 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -22,7 +22,6 @@ import ( "sort" "sync" - old "github.com/kuadrant/authorino/api/v1beta1" api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/auth" "github.com/kuadrant/authorino/pkg/evaluators" @@ -202,7 +201,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if identity.Cache != nil { ttl := identity.Cache.TTL if ttl == 0 { - ttl = old.EvaluatorDefaultCacheTTL + ttl = api.EvaluatorDefaultCacheTTL } translatedIdentity.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&identity.Cache.Key), @@ -296,7 +295,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if metadata.Cache != nil { ttl := metadata.Cache.TTL if ttl == 0 { - ttl = old.EvaluatorDefaultCacheTTL + ttl = api.EvaluatorDefaultCacheTTL } translatedMetadata.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&metadata.Cache.Key), @@ -365,7 +364,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if authorization.Cache != nil { ttl := authorization.Cache.TTL if ttl == 0 { - ttl = old.EvaluatorDefaultCacheTTL + ttl = api.EvaluatorDefaultCacheTTL } translatedAuthorization.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&authorization.Cache.Key), @@ -480,7 +479,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if headerResponse.Cache != nil { ttl := headerResponse.Cache.TTL if ttl == 0 { - ttl = old.EvaluatorDefaultCacheTTL + ttl = api.EvaluatorDefaultCacheTTL } translatedResponse.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&headerResponse.Cache.Key), @@ -503,7 +502,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf if response.Cache != nil { ttl := response.Cache.TTL if ttl == 0 { - ttl = old.EvaluatorDefaultCacheTTL + ttl = api.EvaluatorDefaultCacheTTL } translatedResponse.Cache = evaluators.NewEvaluatorCache( *getJsonFromStaticDynamic(&response.Cache.Key), @@ -680,7 +679,7 @@ func (r *AuthConfigReconciler) bootstrapIndex(ctx context.Context) error { return nil } - authConfigList := old.AuthConfigList{} + authConfigList := api.AuthConfigList{} listOptions := []client.ListOption{} if r.LabelSelector != nil { listOptions = append(listOptions, client.MatchingLabelsSelector{Selector: r.LabelSelector}) @@ -735,7 +734,7 @@ func (r *AuthConfigReconciler) ClusterWide() bool { func (r *AuthConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&old.AuthConfig{}, builder.WithPredicates(LabelSelectorPredicate(r.LabelSelector))). + For(&api.AuthConfig{}, builder.WithPredicates(LabelSelectorPredicate(r.LabelSelector))). Complete(r) } @@ -746,7 +745,7 @@ func (r *AuthConfigReconciler) Ready(includes, _ []string, _ bool) error { for id, status := range r.StatusReport.ReadAll() { switch status.Reason { - case old.StatusReasonReconciled: + case api.StatusReasonReconciled: continue default: return fmt.Errorf("authconfig is not ready: %s (reason: %s)", id, status.Reason) From 965ea4b9a35725c45abde2b545b29773bc56e82e Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 10:30:56 -0400 Subject: [PATCH 11/15] wip: done with tests Signed-off-by: Alex Snaps --- controllers/auth_config_controller_test.go | 90 ++++++++++------------ controllers/auth_config_status_updater.go | 22 +++--- 2 files changed, 52 insertions(+), 60 deletions(-) diff --git a/controllers/auth_config_controller_test.go b/controllers/auth_config_controller_test.go index 392ab37a..f286364f 100644 --- a/controllers/auth_config_controller_test.go +++ b/controllers/auth_config_controller_test.go @@ -6,7 +6,6 @@ import ( "os" "testing" - old "github.com/kuadrant/authorino/api/v1beta1" api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/evaluators" "github.com/kuadrant/authorino/pkg/httptest" @@ -41,46 +40,46 @@ func TestMain(m *testing.M) { } func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { - spec := old.AuthConfigSpec{ + spec := api.AuthConfigSpec{ Hosts: []string{"echo-api"}, - Identity: []*old.Identity{ - { - Name: "keycloak", - Oidc: &old.Identity_OidcConfig{ - Endpoint: "http://127.0.0.1:9001/auth/realms/demo", + Authentication: map[string]api.AuthenticationSpec{ + "keycloak": { + AuthenticationMethodSpec: api.AuthenticationMethodSpec{ + Jwt: &api.JwtAuthenticationSpec{ + IssuerUrl: "http://127.0.0.1:9001/auth/realms/demo", + }, }, - ExtendedProperties: []old.ExtendedProperty{ - { - JsonProperty: old.JsonProperty{ - Name: "source", - Value: runtime.RawExtension{Raw: []byte(`"test"`)}, - }, + Defaults: map[string]api.ValueOrSelector{ + "source": { + Value: runtime.RawExtension{Raw: []byte(`"test"`)}, }, }, }, }, - Metadata: []*old.Metadata{ - { - Name: "userinfo", - UserInfo: &old.Metadata_UserInfo{ - IdentitySource: "keycloak", + Metadata: map[string]api.MetadataSpec{ + "userinfo": { + MetadataMethodSpec: api.MetadataMethodSpec{ + UserInfo: &api.UserInfoMetadataSpec{ + IdentitySource: "keycloak", + }, }, }, - { - Name: "resource-data", - UMA: &old.Metadata_UMA{ - Endpoint: "http://127.0.0.1:9001/auth/realms/demo", - Credentials: &v1.LocalObjectReference{ - Name: "secret", + "resource-data": { + MetadataMethodSpec: api.MetadataMethodSpec{ + Uma: &api.UmaMetadataSpec{ + Endpoint: "http://127.0.0.1:9001/auth/realms/demo", + Credentials: &v1.LocalObjectReference{ + Name: "secret", + }, }, }, }, }, - Authorization: []*old.Authorization{ - { - Name: "main-policy", - OPA: &old.Authorization_OPA{ - InlineRego: ` + Authorization: map[string]api.AuthorizationSpec{ + "main-policy": { + AuthorizationMethodSpec: api.AuthorizationMethodSpec{ + Opa: &api.OpaAuthorizationSpec{ + Rego: ` method = object.get(input.context.request.http, "method", "") path = object.get(input.context.request.http, "path", "") @@ -88,17 +87,19 @@ func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { method == "GET" path = "/allow" }`, + }, }, }, - { - Name: "some-extra-rules", - JSON: &old.Authorization_JSONPatternMatching{ - Rules: []old.JSONPattern{ - { - JSONPatternExpression: old.JSONPatternExpression{ - Selector: "context.identity.role", - Operator: "eq", - Value: "admin", + "some-extra-rules": { + AuthorizationMethodSpec: api.AuthorizationMethodSpec{ + PatternMatching: &api.PatternMatchingAuthorizationSpec{ + Patterns: []api.PatternExpressionOrRef{ + { + PatternExpression: api.PatternExpression{ + Selector: "context.identity.role", + Operator: "eq", + Value: "admin", + }, }, }, }, @@ -109,23 +110,14 @@ func newTestAuthConfig(authConfigLabels map[string]string) api.AuthConfig { return api.AuthConfig{ TypeMeta: metav1.TypeMeta{ Kind: "AuthConfig", - APIVersion: "authorino.kuadrant.io/v1beta1", + APIVersion: "authorino.kuadrant.io/v1beta2", }, ObjectMeta: metav1.ObjectMeta{ Name: "auth-config-1", Namespace: "authorino", Labels: authConfigLabels, }, - Spec: api.AuthConfigSpec{ - Hosts: []string{"echo-api"}, - NamedPatterns: nil, - Conditions: nil, - Authentication: nil, - Metadata: nil, - Authorization: nil, - Response: nil, - Callbacks: nil, - }, + Spec: spec, } } diff --git a/controllers/auth_config_status_updater.go b/controllers/auth_config_status_updater.go index 8fc68d84..2804d3c7 100644 --- a/controllers/auth_config_status_updater.go +++ b/controllers/auth_config_status_updater.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - api "github.com/kuadrant/authorino/api/v1beta1" + api "github.com/kuadrant/authorino/api/v1beta2" "github.com/kuadrant/authorino/pkg/log" "github.com/kuadrant/authorino/pkg/utils" @@ -105,11 +105,11 @@ func (u *AuthConfigStatusUpdater) SetupWithManager(mgr ctrl.Manager) error { Complete(u) } -func updateStatusConditions(currentConditions []api.Condition, newCondition api.Condition) ([]api.Condition, bool) { +func updateStatusConditions(currentConditions []api.AuthConfigStatusCondition, newCondition api.AuthConfigStatusCondition) ([]api.AuthConfigStatusCondition, bool) { newCondition.LastTransitionTime = metav1.Now() if currentConditions == nil { - return []api.Condition{newCondition}, true + return []api.AuthConfigStatusCondition{newCondition}, true } for i, condition := range currentConditions { @@ -122,7 +122,7 @@ func updateStatusConditions(currentConditions []api.Condition, newCondition api. newCondition.LastTransitionTime = condition.LastTransitionTime } - res := make([]api.Condition, len(currentConditions)) + res := make([]api.AuthConfigStatusCondition, len(currentConditions)) copy(res, currentConditions) res[i] = newCondition return res, true @@ -143,7 +143,7 @@ func updateStatusAvailable(authConfig *api.AuthConfig, available bool) (changed message = "" } - authConfig.Status.Conditions, changed = updateStatusConditions(authConfig.Status.Conditions, api.Condition{ + authConfig.Status.Conditions, changed = updateStatusConditions(authConfig.Status.Conditions, api.AuthConfigStatusCondition{ Type: api.StatusConditionAvailable, Status: status, Reason: reason, @@ -164,7 +164,7 @@ func updateStatusReady(authConfig *api.AuthConfig, ready bool, reason, message s reason = api.StatusReasonUnknown } - authConfig.Status.Conditions, changed = updateStatusConditions(authConfig.Status.Conditions, api.Condition{ + authConfig.Status.Conditions, changed = updateStatusConditions(authConfig.Status.Conditions, api.AuthConfigStatusCondition{ Type: api.StatusConditionReady, Status: status, Reason: reason, @@ -181,14 +181,14 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c newLinkedHosts = []string{} } - new := api.Summary{ + new := api.AuthConfigStatusSummary{ Ready: authConfig.Status.Ready(), HostsReady: newLinkedHosts, NumHostsReady: fmt.Sprintf("%d/%d", len(newLinkedHosts), len(authConfig.Spec.Hosts)), - NumIdentitySources: int64(len(authConfig.Spec.Identity)), + NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response)), + NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), FestivalWristbandEnabled: issuingWristbands(authConfig), } @@ -213,8 +213,8 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c } func issuingWristbands(authConfig *api.AuthConfig) bool { - for _, responseConfig := range authConfig.Spec.Response { - if responseConfig.GetType() == api.ResponseWristband { + for _, responseConfig := range authConfig.Spec.Response.Success.DynamicMetadata { + if responseConfig.GetMethod() == api.WristbandAuthResponse { return true } } From 4b244a44a886ab3eaa928a33433f36bf992200d1 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 10:43:52 -0400 Subject: [PATCH 12/15] Tentative at dealing with no opa.External provided Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 36 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index a4bde94b..78a97be6 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -377,25 +377,31 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf case api.OpaAuthorization: policyName := authConfig.GetNamespace() + "/" + authConfig.GetName() + "/" + authzName opa := authorization.Opa - externalRegistry := opa.External secret := &v1.Secret{} - var sharedSecret string - if externalRegistry.SharedSecret != nil { - if err := r.Client.Get(ctx, types.NamespacedName{ - Namespace: authConfig.Namespace, - Name: externalRegistry.SharedSecret.Name}, - secret); err != nil { - return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. + var ( + sharedSecret string + externalSource *authorization_evaluators.OPAExternalSource + ) + + if opa.External != nil { + externalRegistry := opa.External + if externalRegistry.SharedSecret != nil { + if err := r.Client.Get(ctx, types.NamespacedName{ + Namespace: authConfig.Namespace, + Name: externalRegistry.SharedSecret.Name}, + secret); err != nil { + return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. + } + sharedSecret = string(secret.Data[externalRegistry.SharedSecret.Key]) } - sharedSecret = string(secret.Data[externalRegistry.SharedSecret.Key]) - } - externalSource := &authorization_evaluators.OPAExternalSource{ - Endpoint: externalRegistry.Url, - SharedSecret: sharedSecret, - AuthCredentials: newAuthCredential(externalRegistry.Credentials), - TTL: externalRegistry.TTL, + externalSource = &authorization_evaluators.OPAExternalSource{ + Endpoint: externalRegistry.Url, + SharedSecret: sharedSecret, + AuthCredentials: newAuthCredential(externalRegistry.Credentials), + TTL: externalRegistry.TTL, + } } var err error From 11a32e6aaf560f85919bc92ee43148b0b6a69b27 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 10:51:24 -0400 Subject: [PATCH 13/15] Tentative at dealing with no Response provided Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 223 +++++++++++---------- controllers/auth_config_controller_test.go | 10 +- controllers/auth_config_status_updater.go | 14 +- 3 files changed, 133 insertions(+), 114 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 78a97be6..03e91261 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -166,6 +166,9 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf authConfigIdentityConfigs := authConfig.Spec.Authentication if len(authConfigIdentityConfigs) == 0 { + if authConfigIdentityConfigs == nil { + authConfigIdentityConfigs = make(map[string]api.AuthenticationSpec) + } authConfigIdentityConfigs["anonymous"] = api.AuthenticationSpec{ CommonEvaluatorSpec: api.CommonEvaluatorSpec{}, Credentials: api.Credentials{}, @@ -472,129 +475,133 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedResponseConfigs := make([]auth.AuthConfigEvaluator, 0) - for responseName, headerResponse := range authConfig.Spec.Response.Success.Headers { - translatedResponse := evaluators.NewResponseConfig( - responseName, - headerResponse.Priority, - buildJSONExpression(authConfig, headerResponse.Conditions, jsonexp.All), - "httpHeader", - headerResponse.Key, - headerResponse.Metrics, - ) + if authConfig.Spec.Response != nil { + for responseName, headerResponse := range authConfig.Spec.Response.Success.Headers { + translatedResponse := evaluators.NewResponseConfig( + responseName, + headerResponse.Priority, + buildJSONExpression(authConfig, headerResponse.Conditions, jsonexp.All), + "httpHeader", + headerResponse.Key, + headerResponse.Metrics, + ) - if headerResponse.Cache != nil { - ttl := headerResponse.Cache.TTL - if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + if headerResponse.Cache != nil { + ttl := headerResponse.Cache.TTL + if ttl == 0 { + ttl = api.EvaluatorDefaultCacheTTL + } + translatedResponse.Cache = evaluators.NewEvaluatorCache( + *getJsonFromStaticDynamic(&headerResponse.Cache.Key), + ttl, + ) } - translatedResponse.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&headerResponse.Cache.Key), - ttl, - ) + interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } - interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } - for responseName, response := range authConfig.Spec.Response.Success.DynamicMetadata { - translatedResponse := evaluators.NewResponseConfig( - responseName, - response.Priority, - buildJSONExpression(authConfig, response.Conditions, jsonexp.All), - "envoyDynamicMetadata", - response.Key, - response.Metrics, - ) + if authConfig.Spec.Response != nil { + for responseName, response := range authConfig.Spec.Response.Success.DynamicMetadata { + translatedResponse := evaluators.NewResponseConfig( + responseName, + response.Priority, + buildJSONExpression(authConfig, response.Conditions, jsonexp.All), + "envoyDynamicMetadata", + response.Key, + response.Metrics, + ) - if response.Cache != nil { - ttl := response.Cache.TTL - if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL + if response.Cache != nil { + ttl := response.Cache.TTL + if ttl == 0 { + ttl = api.EvaluatorDefaultCacheTTL + } + translatedResponse.Cache = evaluators.NewEvaluatorCache( + *getJsonFromStaticDynamic(&response.Cache.Key), + ttl, + ) } - translatedResponse.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&response.Cache.Key), - ttl, - ) - } - switch response.GetMethod() { - // wristband - case api.WristbandAuthResponse: - wristband := response.Wristband - signingKeys := make([]jose.JSONWebKey, 0) + switch response.GetMethod() { + // wristband + case api.WristbandAuthResponse: + wristband := response.Wristband + signingKeys := make([]jose.JSONWebKey, 0) - for _, signingKeyRef := range wristband.SigningKeyRefs { - secret := &v1.Secret{} - secretName := types.NamespacedName{ - Namespace: authConfig.Namespace, - Name: signingKeyRef.Name, - } - if err := r.Client.Get(ctx, secretName, secret); err != nil { - return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. - } else { - if signingKey, err := response_evaluators.NewSigningKey( - signingKeyRef.Name, - string(signingKeyRef.Algorithm), - secret.Data["key.pem"], - ); err != nil { - return nil, err + for _, signingKeyRef := range wristband.SigningKeyRefs { + secret := &v1.Secret{} + secretName := types.NamespacedName{ + Namespace: authConfig.Namespace, + Name: signingKeyRef.Name, + } + if err := r.Client.Get(ctx, secretName, secret); err != nil { + return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. } else { - signingKeys = append(signingKeys, *signingKey) + if signingKey, err := response_evaluators.NewSigningKey( + signingKeyRef.Name, + string(signingKeyRef.Algorithm), + secret.Data["key.pem"], + ); err != nil { + return nil, err + } else { + signingKeys = append(signingKeys, *signingKey) + } } } - } - customClaims := make([]json.JSONProperty, 0) - for claimName, claim := range wristband.CustomClaims { - customClaims = append(customClaims, json.JSONProperty{ - Name: claimName, - Value: json.JSONValue{ - Static: claim.Value, - Pattern: claim.Selector, - }, - }) - } + customClaims := make([]json.JSONProperty, 0) + for claimName, claim := range wristband.CustomClaims { + customClaims = append(customClaims, json.JSONProperty{ + Name: claimName, + Value: json.JSONValue{ + Static: claim.Value, + Pattern: claim.Selector, + }, + }) + } - if authorinoWristband, err := response_evaluators.NewWristbandConfig( - wristband.Issuer, - customClaims, - wristband.TokenDuration, - signingKeys, - ); err != nil { - return nil, err - } else { - translatedResponse.Wristband = authorinoWristband - } + if authorinoWristband, err := response_evaluators.NewWristbandConfig( + wristband.Issuer, + customClaims, + wristband.TokenDuration, + signingKeys, + ); err != nil { + return nil, err + } else { + translatedResponse.Wristband = authorinoWristband + } - // dynamic json - case api.JsonAuthResponse: - jsonProperties := make([]json.JSONProperty, 0) + // dynamic json + case api.JsonAuthResponse: + jsonProperties := make([]json.JSONProperty, 0) + + for propertyName, property := range response.Json.Properties { + jsonProperties = append(jsonProperties, json.JSONProperty{ + Name: propertyName, + Value: json.JSONValue{ + Static: property.Value, + Pattern: property.Selector, + }, + }) + } - for propertyName, property := range response.Json.Properties { - jsonProperties = append(jsonProperties, json.JSONProperty{ - Name: propertyName, - Value: json.JSONValue{ - Static: property.Value, - Pattern: property.Selector, - }, - }) - } + translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) - translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) + // plain + case api.PlainAuthResponse: + translatedResponse.Plain = &response_evaluators.Plain{ + JSONValue: json.JSONValue{ + Static: response.Plain.Value, + Pattern: response.Plain.Selector, + }, + } - // plain - case api.PlainAuthResponse: - translatedResponse.Plain = &response_evaluators.Plain{ - JSONValue: json.JSONValue{ - Static: response.Plain.Value, - Pattern: response.Plain.Selector, - }, + case api.UnknownAuthResponseMethod: + return nil, fmt.Errorf("unknown response type %v", response) } - case api.UnknownAuthResponseMethod: - return nil, fmt.Errorf("unknown response type %v", response) + interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } - - interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } interfacedCallbackConfigs := make([]auth.AuthConfigEvaluator, 0) @@ -634,11 +641,13 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // denyWith - if denyWith := authConfig.Spec.Response.Unauthenticated; denyWith != nil { - translatedAuthConfig.Unauthenticated = buildAuthorinoDenyWithValues(denyWith) - } - if denyWith := authConfig.Spec.Response.Unauthorized; denyWith != nil { - translatedAuthConfig.Unauthorized = buildAuthorinoDenyWithValues(denyWith) + if authConfig.Spec.Response != nil { + if denyWith := authConfig.Spec.Response.Unauthenticated; denyWith != nil { + translatedAuthConfig.Unauthenticated = buildAuthorinoDenyWithValues(denyWith) + } + if denyWith := authConfig.Spec.Response.Unauthorized; denyWith != nil { + translatedAuthConfig.Unauthorized = buildAuthorinoDenyWithValues(denyWith) + } } return translatedAuthConfig, nil diff --git a/controllers/auth_config_controller_test.go b/controllers/auth_config_controller_test.go index f286364f..84e58631 100644 --- a/controllers/auth_config_controller_test.go +++ b/controllers/auth_config_controller_test.go @@ -170,7 +170,7 @@ func TestReconcileAuthConfigOk(t *testing.T) { config := authConfigIndex.Get("echo-api") assert.Check(t, config != nil) idConfig, _ := config.IdentityConfigs[0].(*evaluators.IdentityConfig) - assert.Equal(t, idConfig.ExtendedProperties[0].Name, "source") + assert.Equal(t, idConfig.ExtendedProperties[1].Name, "source") // TODO(@guicassolato): assert other fields of the AuthConfig } @@ -390,6 +390,10 @@ func TestBootstrapIndex(t *testing.T) { indexMock := mock_index.NewMockIndex(mockController) authConfig := newTestAuthConfig(map[string]string{"scope": "in"}) + expectedNumResponseItems := 0 + if authConfig.Spec.Response != nil { + expectedNumResponseItems = len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers) + } authConfig.Status.Summary = api.AuthConfigStatusSummary{ Ready: true, HostsReady: authConfig.Spec.Hosts, @@ -397,7 +401,7 @@ func TestBootstrapIndex(t *testing.T) { NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), + NumResponseItems: int64(expectedNumResponseItems), FestivalWristbandEnabled: false, } @@ -409,7 +413,7 @@ func TestBootstrapIndex(t *testing.T) { NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), + NumResponseItems: int64(expectedNumResponseItems), FestivalWristbandEnabled: false, } diff --git a/controllers/auth_config_status_updater.go b/controllers/auth_config_status_updater.go index 2804d3c7..5793d9bd 100644 --- a/controllers/auth_config_status_updater.go +++ b/controllers/auth_config_status_updater.go @@ -181,6 +181,10 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c newLinkedHosts = []string{} } + numResponseItems := 0 + if authConfig.Spec.Response != nil { + numResponseItems = len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers) + } new := api.AuthConfigStatusSummary{ Ready: authConfig.Status.Ready(), HostsReady: newLinkedHosts, @@ -188,7 +192,7 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c NumIdentitySources: int64(len(authConfig.Spec.Authentication)), NumMetadataSources: int64(len(authConfig.Spec.Metadata)), NumAuthorizationPolicies: int64(len(authConfig.Spec.Authorization)), - NumResponseItems: int64(len(authConfig.Spec.Response.Success.DynamicMetadata) + len(authConfig.Spec.Response.Success.Headers)), + NumResponseItems: int64(numResponseItems), FestivalWristbandEnabled: issuingWristbands(authConfig), } @@ -213,9 +217,11 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c } func issuingWristbands(authConfig *api.AuthConfig) bool { - for _, responseConfig := range authConfig.Spec.Response.Success.DynamicMetadata { - if responseConfig.GetMethod() == api.WristbandAuthResponse { - return true + if authConfig.Spec.Response != nil { + for _, responseConfig := range authConfig.Spec.Response.Success.DynamicMetadata { + if responseConfig.GetMethod() == api.WristbandAuthResponse { + return true + } } } return false From 3d43aefb5c7c9b703ba06ea504c7d1e55743e6cc Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Wed, 4 Sep 2024 19:20:50 -0400 Subject: [PATCH 14/15] Review feedback Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 49 ++++++++++------------- controllers/auth_config_status_updater.go | 5 +++ 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 03e91261..7b32f40c 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -475,8 +475,8 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedResponseConfigs := make([]auth.AuthConfigEvaluator, 0) - if authConfig.Spec.Response != nil { - for responseName, headerResponse := range authConfig.Spec.Response.Success.Headers { + if responseConfig := authConfig.Spec.Response; responseConfig != nil { + for responseName, headerResponse := range responseConfig.Success.Headers { translatedResponse := evaluators.NewResponseConfig( responseName, headerResponse.Priority, @@ -486,22 +486,11 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf headerResponse.Metrics, ) - if headerResponse.Cache != nil { - ttl := headerResponse.Cache.TTL - if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL - } - translatedResponse.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&headerResponse.Cache.Key), - ttl, - ) - } + injectCache(headerResponse.Cache, translatedResponse) interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } - } - if authConfig.Spec.Response != nil { - for responseName, response := range authConfig.Spec.Response.Success.DynamicMetadata { + for responseName, response := range responseConfig.Success.DynamicMetadata { translatedResponse := evaluators.NewResponseConfig( responseName, response.Priority, @@ -511,16 +500,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf response.Metrics, ) - if response.Cache != nil { - ttl := response.Cache.TTL - if ttl == 0 { - ttl = api.EvaluatorDefaultCacheTTL - } - translatedResponse.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&response.Cache.Key), - ttl, - ) - } + injectCache(response.Cache, translatedResponse) switch response.GetMethod() { // wristband @@ -641,11 +621,11 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf } // denyWith - if authConfig.Spec.Response != nil { - if denyWith := authConfig.Spec.Response.Unauthenticated; denyWith != nil { + if responseConfig := authConfig.Spec.Response; responseConfig != nil { + if denyWith := responseConfig.Unauthenticated; denyWith != nil { translatedAuthConfig.Unauthenticated = buildAuthorinoDenyWithValues(denyWith) } - if denyWith := authConfig.Spec.Response.Unauthorized; denyWith != nil { + if denyWith := responseConfig.Unauthorized; denyWith != nil { translatedAuthConfig.Unauthorized = buildAuthorinoDenyWithValues(denyWith) } } @@ -653,6 +633,19 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf return translatedAuthConfig, nil } +func injectCache(cache *api.EvaluatorCaching, translatedResponse *evaluators.ResponseConfig) { + if cache != nil { + ttl := cache.TTL + if ttl == 0 { + ttl = api.EvaluatorDefaultCacheTTL + } + translatedResponse.Cache = evaluators.NewEvaluatorCache( + *getJsonFromStaticDynamic(&cache.Key), + ttl, + ) + } +} + func (r *AuthConfigReconciler) addToIndex(ctx context.Context, resourceNamespace, resourceId string, authConfig *evaluators.AuthConfig, hosts []string) (linkedHosts, looseHosts []string, err error) { logger := log.FromContext(ctx) linkedHosts = []string{} diff --git a/controllers/auth_config_status_updater.go b/controllers/auth_config_status_updater.go index 5793d9bd..d21f499a 100644 --- a/controllers/auth_config_status_updater.go +++ b/controllers/auth_config_status_updater.go @@ -218,6 +218,11 @@ func updateStatusSummary(authConfig *api.AuthConfig, newLinkedHosts []string) (c func issuingWristbands(authConfig *api.AuthConfig) bool { if authConfig.Spec.Response != nil { + for _, responseConfig := range authConfig.Spec.Response.Success.Headers { + if responseConfig.GetMethod() == api.WristbandAuthResponse { + return true + } + } for _, responseConfig := range authConfig.Spec.Response.Success.DynamicMetadata { if responseConfig.GetMethod() == api.WristbandAuthResponse { return true From b64deefe145bfd98f4454e48d3eb8be86a7cb9e8 Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Thu, 5 Sep 2024 07:22:12 -0400 Subject: [PATCH 15/15] Inject response config Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 188 ++++++++++++++------------ 1 file changed, 99 insertions(+), 89 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index 7b32f40c..cca5ff1f 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -476,108 +476,37 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf interfacedResponseConfigs := make([]auth.AuthConfigEvaluator, 0) if responseConfig := authConfig.Spec.Response; responseConfig != nil { - for responseName, headerResponse := range responseConfig.Success.Headers { + for responseName, headerSuccessResponse := range responseConfig.Success.Headers { translatedResponse := evaluators.NewResponseConfig( responseName, - headerResponse.Priority, - buildJSONExpression(authConfig, headerResponse.Conditions, jsonexp.All), + headerSuccessResponse.Priority, + buildJSONExpression(authConfig, headerSuccessResponse.Conditions, jsonexp.All), "httpHeader", - headerResponse.Key, - headerResponse.Metrics, + headerSuccessResponse.Key, + headerSuccessResponse.Metrics, ) - injectCache(headerResponse.Cache, translatedResponse) + injectCache(headerSuccessResponse.Cache, translatedResponse) + if err := injectResponseConfig(ctx, authConfig, headerSuccessResponse.SuccessResponseSpec, r, translatedResponse); err != nil { + return nil, err + } + interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) } - for responseName, response := range responseConfig.Success.DynamicMetadata { + for responseName, successResponse := range responseConfig.Success.DynamicMetadata { translatedResponse := evaluators.NewResponseConfig( responseName, - response.Priority, - buildJSONExpression(authConfig, response.Conditions, jsonexp.All), + successResponse.Priority, + buildJSONExpression(authConfig, successResponse.Conditions, jsonexp.All), "envoyDynamicMetadata", - response.Key, - response.Metrics, + successResponse.Key, + successResponse.Metrics, ) - injectCache(response.Cache, translatedResponse) - - switch response.GetMethod() { - // wristband - case api.WristbandAuthResponse: - wristband := response.Wristband - signingKeys := make([]jose.JSONWebKey, 0) - - for _, signingKeyRef := range wristband.SigningKeyRefs { - secret := &v1.Secret{} - secretName := types.NamespacedName{ - Namespace: authConfig.Namespace, - Name: signingKeyRef.Name, - } - if err := r.Client.Get(ctx, secretName, secret); err != nil { - return nil, err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. - } else { - if signingKey, err := response_evaluators.NewSigningKey( - signingKeyRef.Name, - string(signingKeyRef.Algorithm), - secret.Data["key.pem"], - ); err != nil { - return nil, err - } else { - signingKeys = append(signingKeys, *signingKey) - } - } - } - - customClaims := make([]json.JSONProperty, 0) - for claimName, claim := range wristband.CustomClaims { - customClaims = append(customClaims, json.JSONProperty{ - Name: claimName, - Value: json.JSONValue{ - Static: claim.Value, - Pattern: claim.Selector, - }, - }) - } - - if authorinoWristband, err := response_evaluators.NewWristbandConfig( - wristband.Issuer, - customClaims, - wristband.TokenDuration, - signingKeys, - ); err != nil { - return nil, err - } else { - translatedResponse.Wristband = authorinoWristband - } - - // dynamic json - case api.JsonAuthResponse: - jsonProperties := make([]json.JSONProperty, 0) - - for propertyName, property := range response.Json.Properties { - jsonProperties = append(jsonProperties, json.JSONProperty{ - Name: propertyName, - Value: json.JSONValue{ - Static: property.Value, - Pattern: property.Selector, - }, - }) - } - - translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) - - // plain - case api.PlainAuthResponse: - translatedResponse.Plain = &response_evaluators.Plain{ - JSONValue: json.JSONValue{ - Static: response.Plain.Value, - Pattern: response.Plain.Selector, - }, - } - - case api.UnknownAuthResponseMethod: - return nil, fmt.Errorf("unknown response type %v", response) + injectCache(successResponse.Cache, translatedResponse) + if err := injectResponseConfig(ctx, authConfig, successResponse, r, translatedResponse); err != nil { + return nil, err } interfacedResponseConfigs = append(interfacedResponseConfigs, translatedResponse) @@ -633,6 +562,87 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf return translatedAuthConfig, nil } +func injectResponseConfig(ctx context.Context, authConfig *api.AuthConfig, successResponse api.SuccessResponseSpec, r *AuthConfigReconciler, translatedResponse *evaluators.ResponseConfig) error { + switch successResponse.GetMethod() { + // wristband + case api.WristbandAuthResponse: + wristband := successResponse.Wristband + signingKeys := make([]jose.JSONWebKey, 0) + + for _, signingKeyRef := range wristband.SigningKeyRefs { + secret := &v1.Secret{} + secretName := types.NamespacedName{ + Namespace: authConfig.Namespace, + Name: signingKeyRef.Name, + } + if err := r.Client.Get(ctx, secretName, secret); err != nil { + return err // TODO: Review this error, perhaps we don't need to return an error, just reenqueue. + } else { + if signingKey, err := response_evaluators.NewSigningKey( + signingKeyRef.Name, + string(signingKeyRef.Algorithm), + secret.Data["key.pem"], + ); err != nil { + return err + } else { + signingKeys = append(signingKeys, *signingKey) + } + } + } + + customClaims := make([]json.JSONProperty, 0) + for claimName, claim := range wristband.CustomClaims { + customClaims = append(customClaims, json.JSONProperty{ + Name: claimName, + Value: json.JSONValue{ + Static: claim.Value, + Pattern: claim.Selector, + }, + }) + } + + if authorinoWristband, err := response_evaluators.NewWristbandConfig( + wristband.Issuer, + customClaims, + wristband.TokenDuration, + signingKeys, + ); err != nil { + return err + } else { + translatedResponse.Wristband = authorinoWristband + } + + // dynamic json + case api.JsonAuthResponse: + jsonProperties := make([]json.JSONProperty, 0) + + for propertyName, property := range successResponse.Json.Properties { + jsonProperties = append(jsonProperties, json.JSONProperty{ + Name: propertyName, + Value: json.JSONValue{ + Static: property.Value, + Pattern: property.Selector, + }, + }) + } + + translatedResponse.DynamicJSON = response_evaluators.NewDynamicJSONResponse(jsonProperties) + + // plain + case api.PlainAuthResponse: + translatedResponse.Plain = &response_evaluators.Plain{ + JSONValue: json.JSONValue{ + Static: successResponse.Plain.Value, + Pattern: successResponse.Plain.Selector, + }, + } + + case api.UnknownAuthResponseMethod: + return fmt.Errorf("unknown successResponse type %v", successResponse) + } + return nil +} + func injectCache(cache *api.EvaluatorCaching, translatedResponse *evaluators.ResponseConfig) { if cache != nil { ttl := cache.TTL