From 0d0a0a9a269e9107ff894a27cd14b50a823bb6ab Mon Sep 17 00:00:00 2001 From: Alex Snaps Date: Tue, 15 Oct 2024 09:29:20 -0400 Subject: [PATCH] Abstracted expressions.Value away somewhat Signed-off-by: Alex Snaps --- controllers/auth_config_controller.go | 47 ++++++++++--------- pkg/evaluators/authorization/authzed.go | 14 +++--- pkg/evaluators/authorization/authzed_test.go | 20 ++++---- .../authorization/kubernetes_authz.go | 20 ++++---- .../authorization/kubernetes_authz_test.go | 15 +++--- pkg/evaluators/cache.go | 6 +-- pkg/evaluators/config.go | 5 +- pkg/evaluators/identity_extension.go | 7 ++- pkg/evaluators/identity_extension_test.go | 24 +++++----- pkg/evaluators/identity_test.go | 4 +- pkg/evaluators/metadata/generic_http.go | 3 +- pkg/evaluators/metadata/generic_http_test.go | 6 +-- pkg/evaluators/metadata_test.go | 2 +- pkg/evaluators/response/dynamic_json_test.go | 4 +- pkg/evaluators/response/plain.go | 4 +- pkg/evaluators/response/plain_test.go | 9 +++- pkg/evaluators/response/wristband_test.go | 4 +- pkg/expressions/cel/expressions.go | 11 +++++ pkg/json/json.go | 3 +- pkg/service/auth_pipeline_test.go | 4 +- pkg/service/auth_test.go | 2 +- 21 files changed, 119 insertions(+), 95 deletions(-) diff --git a/controllers/auth_config_controller.go b/controllers/auth_config_controller.go index bc998fd7..e5cf0b97 100644 --- a/controllers/auth_config_controller.go +++ b/controllers/auth_config_controller.go @@ -19,6 +19,7 @@ package controllers import ( "context" "fmt" + "github.com/kuadrant/authorino/pkg/expressions" "sort" "sync" @@ -182,13 +183,13 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf 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{ + extendedProperties = append(extendedProperties, evaluators.NewIdentityExtension(propertyName, &json.JSONValue{ Static: property.Value, Pattern: property.Selector, }, false)) } for propertyName, property := range identity.Overrides { - extendedProperties = append(extendedProperties, evaluators.NewIdentityExtension(propertyName, json.JSONValue{ + extendedProperties = append(extendedProperties, evaluators.NewIdentityExtension(propertyName, &json.JSONValue{ Static: property.Value, Pattern: property.Selector, }, true)) @@ -212,7 +213,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ttl = api.EvaluatorDefaultCacheTTL } translatedIdentity.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&identity.Cache.Key), + getJsonFromStaticDynamic(&identity.Cache.Key), ttl, ) } @@ -310,7 +311,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ttl = api.EvaluatorDefaultCacheTTL } translatedMetadata.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&metadata.Cache.Key), + getJsonFromStaticDynamic(&metadata.Cache.Key), ttl, ) } @@ -383,7 +384,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf ttl = api.EvaluatorDefaultCacheTTL } translatedAuthorization.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&authorization.Cache.Key), + getJsonFromStaticDynamic(&authorization.Cache.Key), ttl, ) } @@ -444,17 +445,17 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf resourceAttributes := authorization.KubernetesSubjectAccessReview.ResourceAttributes if resourceAttributes != nil { authorinoResourceAttributes = &authorization_evaluators.KubernetesAuthzResourceAttributes{ - 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}, + 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.KubernetesSubjectAccessReview.Groups, authorinoResourceAttributes) + translatedAuthorization.KubernetesAuthz, err = authorization_evaluators.NewKubernetesAuthz(&authorinoUser, authorization.KubernetesSubjectAccessReview.Groups, authorinoResourceAttributes) if err != nil { return nil, err } @@ -475,7 +476,7 @@ func (r *AuthConfigReconciler) translateAuthConfig(ctx context.Context, authConf Endpoint: authzed.Endpoint, Insecure: authzed.Insecure, SharedSecret: sharedSecret, - Permission: *getJsonFromStaticDynamic(&authzed.Permission), + Permission: getJsonFromStaticDynamic(&authzed.Permission), } translatedAuthzed.Subject, translatedAuthzed.SubjectKind = spiceDBObjectToJsonValues(authzed.Subject) translatedAuthzed.Resource, translatedAuthzed.ResourceKind = spiceDBObjectToJsonValues(authzed.Resource) @@ -627,7 +628,7 @@ func injectResponseConfig(ctx context.Context, authConfig *api.AuthConfig, succe for claimName, claim := range wristband.CustomClaims { customClaims = append(customClaims, json.JSONProperty{ Name: claimName, - Value: json.JSONValue{ + Value: &json.JSONValue{ Static: claim.Value, Pattern: claim.Selector, }, @@ -652,7 +653,7 @@ func injectResponseConfig(ctx context.Context, authConfig *api.AuthConfig, succe for propertyName, property := range successResponse.Json.Properties { jsonProperties = append(jsonProperties, json.JSONProperty{ Name: propertyName, - Value: json.JSONValue{ + Value: &json.JSONValue{ Static: property.Value, Pattern: property.Selector, }, @@ -664,7 +665,7 @@ func injectResponseConfig(ctx context.Context, authConfig *api.AuthConfig, succe // plain case api.PlainAuthResponse: translatedResponse.Plain = &response_evaluators.Plain{ - JSONValue: json.JSONValue{ + Value: &json.JSONValue{ Static: successResponse.Plain.Value, Pattern: successResponse.Plain.Selector, }, @@ -683,7 +684,7 @@ func injectCache(cache *api.EvaluatorCaching, translatedResponse *evaluators.Res ttl = api.EvaluatorDefaultCacheTTL } translatedResponse.Cache = evaluators.NewEvaluatorCache( - *getJsonFromStaticDynamic(&cache.Key), + getJsonFromStaticDynamic(&cache.Key), ttl, ) } @@ -838,7 +839,7 @@ func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, ht for name, param := range http.Parameters { params = append(params, json.JSONProperty{ Name: name, - Value: json.JSONValue{ + Value: &json.JSONValue{ Static: param.Value, Pattern: param.Selector, }, @@ -849,7 +850,7 @@ func (r *AuthConfigReconciler) buildGenericHttpEvaluator(ctx context.Context, ht for name, header := range http.Headers { headers = append(headers, json.JSONProperty{ Name: name, - Value: json.JSONValue{ + Value: &json.JSONValue{ Static: header.Value, Pattern: header.Selector, }, @@ -981,7 +982,7 @@ func buildAuthorinoDenyWithValues(denyWithSpec *api.DenyWithSpec) *evaluators.De headers := make([]json.JSONProperty, 0, len(denyWithSpec.Headers)) for name, header := range denyWithSpec.Headers { - headers = append(headers, json.JSONProperty{Name: name, Value: json.JSONValue{Static: header.Value, Pattern: header.Selector}}) + headers = append(headers, json.JSONProperty{Name: name, Value: &json.JSONValue{Static: header.Value, Pattern: header.Selector}}) } return &evaluators.DenyWithValues{ @@ -1003,13 +1004,13 @@ func getJsonFromStaticDynamic(value *api.ValueOrSelector) *json.JSONValue { } } -func spiceDBObjectToJsonValues(obj *api.SpiceDBObject) (name json.JSONValue, kind json.JSONValue) { +func spiceDBObjectToJsonValues(obj *api.SpiceDBObject) (name expressions.Value, kind expressions.Value) { if obj == nil { return } - name = *getJsonFromStaticDynamic(&obj.Name) - kind = *getJsonFromStaticDynamic(&obj.Kind) + name = getJsonFromStaticDynamic(&obj.Name) + kind = getJsonFromStaticDynamic(&obj.Kind) return name, kind } diff --git a/pkg/evaluators/authorization/authzed.go b/pkg/evaluators/authorization/authzed.go index 1759b17b..5bc00ee5 100644 --- a/pkg/evaluators/authorization/authzed.go +++ b/pkg/evaluators/authorization/authzed.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/kuadrant/authorino/pkg/auth" - "github.com/kuadrant/authorino/pkg/json" + "github.com/kuadrant/authorino/pkg/expressions" "google.golang.org/grpc" insecuregrpc "google.golang.org/grpc/credentials/insecure" @@ -19,11 +19,11 @@ type Authzed struct { Insecure bool SharedSecret string - Subject json.JSONValue - SubjectKind json.JSONValue - Resource json.JSONValue - ResourceKind json.JSONValue - Permission json.JSONValue + Subject expressions.Value + SubjectKind expressions.Value + Resource expressions.Value + ResourceKind expressions.Value + Permission expressions.Value } type permissionResponse struct { @@ -86,7 +86,7 @@ func (a *Authzed) Call(pipeline auth.AuthPipeline, ctx gocontext.Context) (inter return obj, nil } -func authzedObjectFor(name, kind json.JSONValue, authJSON string) (*authzedpb.ObjectReference, error) { +func authzedObjectFor(name, kind expressions.Value, authJSON string) (*authzedpb.ObjectReference, error) { objectId, err := name.ResolveFor(authJSON) if err != nil { return nil, err diff --git a/pkg/evaluators/authorization/authzed_test.go b/pkg/evaluators/authorization/authzed_test.go index dd133654..ad29f482 100644 --- a/pkg/evaluators/authorization/authzed_test.go +++ b/pkg/evaluators/authorization/authzed_test.go @@ -52,11 +52,11 @@ func TestAuthzedCallAuthorized(t *testing.T) { Endpoint: testAuthzedServerEndpoint, Insecure: true, SharedSecret: "secret", - Subject: json.JSONValue{Static: "1"}, - SubjectKind: json.JSONValue{Static: "user"}, - Resource: json.JSONValue{Static: "123"}, - ResourceKind: json.JSONValue{Static: "post"}, - Permission: json.JSONValue{Static: "read"}, + Subject: &json.JSONValue{Static: "1"}, + SubjectKind: &json.JSONValue{Static: "user"}, + Resource: &json.JSONValue{Static: "123"}, + ResourceKind: &json.JSONValue{Static: "post"}, + Permission: &json.JSONValue{Static: "read"}, } obj, err := authzed.Call(pipelineMock, ctx) @@ -91,11 +91,11 @@ func TestAuthzedCallForbidden(t *testing.T) { Endpoint: testAuthzedServerEndpoint, Insecure: true, SharedSecret: "secret", - Subject: json.JSONValue{Static: "1"}, - SubjectKind: json.JSONValue{Static: "user"}, - Resource: json.JSONValue{Static: "123"}, - ResourceKind: json.JSONValue{Static: "post"}, - Permission: json.JSONValue{Static: "read"}, + Subject: &json.JSONValue{Static: "1"}, + SubjectKind: &json.JSONValue{Static: "user"}, + Resource: &json.JSONValue{Static: "123"}, + ResourceKind: &json.JSONValue{Static: "post"}, + Permission: &json.JSONValue{Static: "read"}, } obj, err := authzed.Call(pipelineMock, ctx) diff --git a/pkg/evaluators/authorization/kubernetes_authz.go b/pkg/evaluators/authorization/kubernetes_authz.go index a382248b..6f9aa704 100644 --- a/pkg/evaluators/authorization/kubernetes_authz.go +++ b/pkg/evaluators/authorization/kubernetes_authz.go @@ -3,11 +3,11 @@ package authorization import ( gocontext "context" "fmt" + "github.com/kuadrant/authorino/pkg/expressions" "strings" "github.com/kuadrant/authorino/pkg/auth" "github.com/kuadrant/authorino/pkg/context" - "github.com/kuadrant/authorino/pkg/json" "github.com/kuadrant/authorino/pkg/log" kubeAuthz "k8s.io/api/authorization/v1" @@ -21,7 +21,7 @@ type kubernetesSubjectAccessReviewer interface { SubjectAccessReviews() kubeAuthzClient.SubjectAccessReviewInterface } -func NewKubernetesAuthz(user json.JSONValue, groups []string, resourceAttributes *KubernetesAuthzResourceAttributes) (*KubernetesAuthz, error) { +func NewKubernetesAuthz(user expressions.Value, groups []string, resourceAttributes *KubernetesAuthzResourceAttributes) (*KubernetesAuthz, error) { config, err := rest.InClusterConfig() if err != nil { return nil, err @@ -41,16 +41,16 @@ func NewKubernetesAuthz(user json.JSONValue, groups []string, resourceAttributes } type KubernetesAuthzResourceAttributes struct { - Namespace json.JSONValue - Group json.JSONValue - Resource json.JSONValue - Name json.JSONValue - SubResource json.JSONValue - Verb json.JSONValue + Namespace expressions.Value + Group expressions.Value + Resource expressions.Value + Name expressions.Value + SubResource expressions.Value + Verb expressions.Value } type KubernetesAuthz struct { - User json.JSONValue + User expressions.Value Groups []string ResourceAttributes *KubernetesAuthzResourceAttributes @@ -63,7 +63,7 @@ func (k *KubernetesAuthz) Call(pipeline auth.AuthPipeline, ctx gocontext.Context } authJSON := pipeline.GetAuthorizationJSON() - jsonValueToStr := func(value json.JSONValue) (string, error) { + jsonValueToStr := func(value expressions.Value) (string, error) { resolved, err := value.ResolveFor(authJSON) if err != nil { return "", err diff --git a/pkg/evaluators/authorization/kubernetes_authz_test.go b/pkg/evaluators/authorization/kubernetes_authz_test.go index f1c29e33..4fa1b576 100644 --- a/pkg/evaluators/authorization/kubernetes_authz_test.go +++ b/pkg/evaluators/authorization/kubernetes_authz_test.go @@ -2,6 +2,7 @@ package authorization import ( "context" + "github.com/kuadrant/authorino/pkg/expressions" "testing" mock_auth "github.com/kuadrant/authorino/pkg/auth/mocks" @@ -58,7 +59,7 @@ func (client *k8sAuthorizationClientMock) GetRequest() kubeAuthz.SubjectAccessRe return client.request } -func newKubernetesAuthz(user json.JSONValue, groups []string, resourceAttributes *KubernetesAuthzResourceAttributes, subjectAccessReviewResponseStatus kubeAuthz.SubjectAccessReviewStatus) *KubernetesAuthz { +func newKubernetesAuthz(user expressions.Value, groups []string, resourceAttributes *KubernetesAuthzResourceAttributes, subjectAccessReviewResponseStatus kubeAuthz.SubjectAccessReviewStatus) *KubernetesAuthz { return &KubernetesAuthz{ User: user, Groups: groups, @@ -80,7 +81,7 @@ func TestKubernetesAuthzNonResource_Allowed(t *testing.T) { pipelineMock.EXPECT().GetHttp().Return(request) kubernetesAuth := newKubernetesAuthz( - json.JSONValue{Pattern: "auth.identity.username"}, + &json.JSONValue{Pattern: "auth.identity.username"}, []string{}, nil, kubeAuthz.SubjectAccessReviewStatus{Allowed: true, Reason: ""}, @@ -108,7 +109,7 @@ func TestKubernetesAuthzNonResource_Denied(t *testing.T) { pipelineMock.EXPECT().GetHttp().Return(request) kubernetesAuth := newKubernetesAuthz( - json.JSONValue{Pattern: "auth.identity.username"}, + &json.JSONValue{Pattern: "auth.identity.username"}, []string{}, nil, kubeAuthz.SubjectAccessReviewStatus{Allowed: false, Reason: "some-reason"}, @@ -133,9 +134,9 @@ func TestKubernetesAuthzResource_Allowed(t *testing.T) { pipelineMock.EXPECT().GetAuthorizationJSON().Return(`{"context":{"request":{"http":{"method":"GET","path":"/hello"}}},"auth":{"identity":{"username":"john"}}}`) kubernetesAuth := newKubernetesAuthz( - json.JSONValue{Pattern: "auth.identity.username"}, + &json.JSONValue{Pattern: "auth.identity.username"}, []string{}, - &KubernetesAuthzResourceAttributes{Namespace: json.JSONValue{Static: "default"}}, + &KubernetesAuthzResourceAttributes{Namespace: &json.JSONValue{Static: "default"}}, kubeAuthz.SubjectAccessReviewStatus{Allowed: true, Reason: ""}, ) authorized, err := kubernetesAuth.Call(pipelineMock, context.TODO()) @@ -157,9 +158,9 @@ func TestKubernetesAuthzResource_Denied(t *testing.T) { pipelineMock.EXPECT().GetAuthorizationJSON().Return(`{"context":{"request":{"http":{"method":"GET","path":"/hello"}}},"auth":{"identity":{"username":"john"}}}`) kubernetesAuth := newKubernetesAuthz( - json.JSONValue{Pattern: "auth.identity.username"}, + &json.JSONValue{Pattern: "auth.identity.username"}, []string{}, - &KubernetesAuthzResourceAttributes{Namespace: json.JSONValue{Static: "default"}}, + &KubernetesAuthzResourceAttributes{Namespace: &json.JSONValue{Static: "default"}}, kubeAuthz.SubjectAccessReviewStatus{Allowed: false, Reason: "some-reason"}, ) authorized, err := kubernetesAuth.Call(pipelineMock, context.TODO()) diff --git a/pkg/evaluators/cache.go b/pkg/evaluators/cache.go index b5bd3a75..1bf03f52 100644 --- a/pkg/evaluators/cache.go +++ b/pkg/evaluators/cache.go @@ -4,7 +4,7 @@ import ( gojson "encoding/json" "time" - "github.com/kuadrant/authorino/pkg/json" + "github.com/kuadrant/authorino/pkg/expressions" "github.com/coocood/freecache" gocache "github.com/eko/gocache/cache" @@ -20,7 +20,7 @@ type EvaluatorCache interface { Shutdown() error } -func NewEvaluatorCache(keyTemplate json.JSONValue, ttl int) EvaluatorCache { +func NewEvaluatorCache(keyTemplate expressions.Value, ttl int) EvaluatorCache { duration := time.Duration(ttl) * time.Second cacheClient := freecache.NewCache(EvaluatorCacheSize * 1024 * 1024) cacheStore := cache_store.NewFreecache(cacheClient, &cache_store.Options{Expiration: duration}) @@ -33,7 +33,7 @@ func NewEvaluatorCache(keyTemplate json.JSONValue, ttl int) EvaluatorCache { // evaluatorCache caches JSON values (objects, arrays, strings, etc) type evaluatorCache struct { - keyTemplate json.JSONValue + keyTemplate expressions.Value store *gocache.Cache } diff --git a/pkg/evaluators/config.go b/pkg/evaluators/config.go index 3d0f58c4..a2b8c13b 100644 --- a/pkg/evaluators/config.go +++ b/pkg/evaluators/config.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/kuadrant/authorino/pkg/auth" + "github.com/kuadrant/authorino/pkg/expressions" "github.com/kuadrant/authorino/pkg/json" "github.com/kuadrant/authorino/pkg/jsonexp" @@ -74,7 +75,7 @@ type DenyWith struct { type DenyWithValues struct { Code int32 - Message *json.JSONValue + Message expressions.Value Headers []json.JSONProperty - Body *json.JSONValue + Body expressions.Value } diff --git a/pkg/evaluators/identity_extension.go b/pkg/evaluators/identity_extension.go index f57e1ed9..63dc87a9 100644 --- a/pkg/evaluators/identity_extension.go +++ b/pkg/evaluators/identity_extension.go @@ -1,8 +1,11 @@ package evaluators -import "github.com/kuadrant/authorino/pkg/json" +import ( + "github.com/kuadrant/authorino/pkg/expressions" + "github.com/kuadrant/authorino/pkg/json" +) -func NewIdentityExtension(name string, value json.JSONValue, overwrite bool) IdentityExtension { +func NewIdentityExtension(name string, value expressions.Value, overwrite bool) IdentityExtension { return IdentityExtension{ JSONProperty: json.JSONProperty{ Name: name, diff --git a/pkg/evaluators/identity_extension_test.go b/pkg/evaluators/identity_extension_test.go index 922c1765..34ee0f2b 100644 --- a/pkg/evaluators/identity_extension_test.go +++ b/pkg/evaluators/identity_extension_test.go @@ -23,62 +23,62 @@ func TestResolveIdentityExtension(t *testing.T) { }{ { name: "static value for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Static: "foo"}, false), + input: NewIdentityExtension("username", &json.JSONValue{Static: "foo"}, false), expected: "beth", }, { name: "static value for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Static: "foo"}, false), + input: NewIdentityExtension("uid", &json.JSONValue{Static: "foo"}, false), expected: "foo", }, { name: "static value for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Static: "foo"}, true), + input: NewIdentityExtension("username", &json.JSONValue{Static: "foo"}, true), expected: "foo", }, { name: "static value for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Static: "foo"}, true), + input: NewIdentityExtension("uid", &json.JSONValue{Static: "foo"}, true), expected: "foo", }, { name: "existing pattern for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Pattern: "auth.identity.sub"}, false), + input: NewIdentityExtension("username", &json.JSONValue{Pattern: "auth.identity.sub"}, false), expected: "beth", }, { name: "existing pattern for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Pattern: "auth.identity.sub"}, false), + input: NewIdentityExtension("uid", &json.JSONValue{Pattern: "auth.identity.sub"}, false), expected: "1234567890", }, { name: "existing pattern for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Pattern: "auth.identity.sub"}, true), + input: NewIdentityExtension("username", &json.JSONValue{Pattern: "auth.identity.sub"}, true), expected: "1234567890", }, { name: "existing pattern for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Pattern: "auth.identity.sub"}, true), + input: NewIdentityExtension("uid", &json.JSONValue{Pattern: "auth.identity.sub"}, true), expected: "1234567890", }, { name: "missing pattern for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Pattern: "auth.identity.full_name"}, false), + input: NewIdentityExtension("username", &json.JSONValue{Pattern: "auth.identity.full_name"}, false), expected: "beth", }, { name: "missing pattern for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Pattern: "auth.identity.full_name"}, false), + input: NewIdentityExtension("uid", &json.JSONValue{Pattern: "auth.identity.full_name"}, false), expected: "", }, { name: "missing pattern for existing property without overwrite", - input: NewIdentityExtension("username", json.JSONValue{Pattern: "auth.identity.full_name"}, true), + input: NewIdentityExtension("username", &json.JSONValue{Pattern: "auth.identity.full_name"}, true), expected: "", }, { name: "missing pattern for missing property without overwrite", - input: NewIdentityExtension("uid", json.JSONValue{Pattern: "auth.identity.full_name"}, true), + input: NewIdentityExtension("uid", &json.JSONValue{Pattern: "auth.identity.full_name"}, true), expected: "", }, } diff --git a/pkg/evaluators/identity_test.go b/pkg/evaluators/identity_test.go index 8e16f6f2..39620adf 100644 --- a/pkg/evaluators/identity_test.go +++ b/pkg/evaluators/identity_test.go @@ -41,8 +41,8 @@ func TestIdentityConfig_ResolveExtendedProperties(t *testing.T) { Name: "test", KubernetesAuth: &identity.KubernetesAuth{}, ExtendedProperties: []IdentityExtension{ - NewIdentityExtension("prop1", json.JSONValue{Static: "value1"}, true), - NewIdentityExtension("prop2", json.JSONValue{Pattern: "auth.identity.sub"}, true), + NewIdentityExtension("prop1", &json.JSONValue{Static: "value1"}, true), + NewIdentityExtension("prop2", &json.JSONValue{Pattern: "auth.identity.sub"}, true), }, } diff --git a/pkg/evaluators/metadata/generic_http.go b/pkg/evaluators/metadata/generic_http.go index 80adec26..5e4be206 100644 --- a/pkg/evaluators/metadata/generic_http.go +++ b/pkg/evaluators/metadata/generic_http.go @@ -5,6 +5,7 @@ import ( gocontext "context" gojson "encoding/json" "fmt" + "github.com/kuadrant/authorino/pkg/expressions" "io" "net/http" "net/url" @@ -23,7 +24,7 @@ import ( type GenericHttp struct { Endpoint string Method string - Body *json.JSONValue + Body expressions.Value Parameters []json.JSONProperty Headers []json.JSONProperty ContentType string diff --git a/pkg/evaluators/metadata/generic_http_test.go b/pkg/evaluators/metadata/generic_http_test.go index b00ecbda..3f56a117 100644 --- a/pkg/evaluators/metadata/generic_http_test.go +++ b/pkg/evaluators/metadata/generic_http_test.go @@ -80,7 +80,7 @@ func TestGenericHttpCallWithPOST(t *testing.T) { metadata := &GenericHttp{ Endpoint: endpoint, Method: "POST", - Parameters: []json.JSONProperty{{Name: "user", Value: json.JSONValue{Pattern: "auth.identity.user"}}}, + Parameters: []json.JSONProperty{{Name: "user", Value: &json.JSONValue{Pattern: "auth.identity.user"}}}, ContentType: "application/x-www-form-urlencoded", SharedSecret: "secret", AuthCredentials: sharedCredsMock, @@ -226,8 +226,8 @@ func TestGenericHttpCallWithCustomHeaders(t *testing.T) { Endpoint: endpoint, Method: "GET", Headers: []json.JSONProperty{ - {Name: "X-Requested-By", Value: json.JSONValue{Static: "authorino"}}, - {Name: "Content-Type", Value: json.JSONValue{Static: "to-be-overwritten"}}, + {Name: "X-Requested-By", Value: &json.JSONValue{Static: "authorino"}}, + {Name: "Content-Type", Value: &json.JSONValue{Static: "to-be-overwritten"}}, }, AuthCredentials: sharedCredsMock, } diff --git a/pkg/evaluators/metadata_test.go b/pkg/evaluators/metadata_test.go index c2cf70e0..66caeba3 100644 --- a/pkg/evaluators/metadata_test.go +++ b/pkg/evaluators/metadata_test.go @@ -59,7 +59,7 @@ func TestMetadataCaching(t *testing.T) { assert.NilError(t, err) // With caching of metadata - cache := NewEvaluatorCache(json.JSONValue{Static: "x"}, 2) // 2 seconds ttl + cache := NewEvaluatorCache(&json.JSONValue{Static: "x"}, 2) // 2 seconds ttl metadataConfig.Cache = cache defer metadataConfig.Clean(context.TODO()) diff --git a/pkg/evaluators/response/dynamic_json_test.go b/pkg/evaluators/response/dynamic_json_test.go index 47d48b93..1b064e6c 100644 --- a/pkg/evaluators/response/dynamic_json_test.go +++ b/pkg/evaluators/response/dynamic_json_test.go @@ -17,8 +17,8 @@ func TestDynamicJSONCall(t *testing.T) { defer ctrl.Finish() jsonProperties := []json.JSONProperty{ - {Name: "prop1", Value: json.JSONValue{Static: "value1"}}, - {Name: "prop2", Value: json.JSONValue{Pattern: "auth.identity.username"}}, + {Name: "prop1", Value: &json.JSONValue{Static: "value1"}}, + {Name: "prop2", Value: &json.JSONValue{Pattern: "auth.identity.username"}}, } jsonResponseEvaluator := NewDynamicJSONResponse(jsonProperties) diff --git a/pkg/evaluators/response/plain.go b/pkg/evaluators/response/plain.go index 6e1e61d6..6b3611b6 100644 --- a/pkg/evaluators/response/plain.go +++ b/pkg/evaluators/response/plain.go @@ -4,11 +4,11 @@ import ( "context" "github.com/kuadrant/authorino/pkg/auth" - "github.com/kuadrant/authorino/pkg/json" + "github.com/kuadrant/authorino/pkg/expressions" ) type Plain struct { - json.JSONValue + expressions.Value } func (p *Plain) Call(pipeline auth.AuthPipeline, ctx context.Context) (interface{}, error) { diff --git a/pkg/evaluators/response/plain_test.go b/pkg/evaluators/response/plain_test.go index 76ad5ee1..83ca2436 100644 --- a/pkg/evaluators/response/plain_test.go +++ b/pkg/evaluators/response/plain_test.go @@ -3,6 +3,7 @@ package response import ( "context" "fmt" + "github.com/kuadrant/authorino/pkg/json" "testing" mock_auth "github.com/kuadrant/authorino/pkg/auth/mocks" @@ -16,7 +17,9 @@ func TestPlainCallWithStaticValue(t *testing.T) { defer ctrl.Finish() ev := Plain{} - ev.Static = "value1" + ev.Value = &json.JSONValue{ + Static: "value1", + } pipelineMock := mock_auth.NewMockAuthPipeline(ctrl) pipelineMock.EXPECT().GetAuthorizationJSON().Return(`{"auth":{"identity":{"username":"john"}}}`) @@ -32,7 +35,9 @@ func TestPlainCallWithPattern(t *testing.T) { defer ctrl.Finish() ev := Plain{} - ev.Pattern = "auth.identity.username" + ev.Value = &json.JSONValue{ + Pattern: "auth.identity.username", + } pipelineMock := mock_auth.NewMockAuthPipeline(ctrl) pipelineMock.EXPECT().GetAuthorizationJSON().Return(`{"auth":{"identity":{"username":"john"}}}`) diff --git a/pkg/evaluators/response/wristband_test.go b/pkg/evaluators/response/wristband_test.go index 354ee91e..aebd8b7c 100644 --- a/pkg/evaluators/response/wristband_test.go +++ b/pkg/evaluators/response/wristband_test.go @@ -160,11 +160,11 @@ func TestWristbandCall(t *testing.T) { claims := []json.JSONProperty{ { Name: "sta", - Value: json.JSONValue{Static: "foo"}, + Value: &json.JSONValue{Static: "foo"}, }, { Name: "dyn", - Value: json.JSONValue{Pattern: "auth.identity"}, + Value: &json.JSONValue{Pattern: "auth.identity"}, }, } signingKey, _ := NewSigningKey("my-signing-key", "ES256", []byte(ellipticCurveSigningKey)) diff --git a/pkg/expressions/cel/expressions.go b/pkg/expressions/cel/expressions.go index 1663e83a..c1247758 100644 --- a/pkg/expressions/cel/expressions.go +++ b/pkg/expressions/cel/expressions.go @@ -50,6 +50,17 @@ type Expression struct { source string } +func NewExpression(source string) (*Expression, error) { + program, err := Compile(source, false) + if err != nil { + return nil, err + } + return &Expression{ + program: program, + source: source, + }, nil +} + func (e *Expression) ResolveFor(json string) (interface{}, error) { input, err := AuthJsonToCel(json) if err != nil { diff --git a/pkg/json/json.go b/pkg/json/json.go index 4fe110d6..1011b6dd 100644 --- a/pkg/json/json.go +++ b/pkg/json/json.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "github.com/kuadrant/authorino/pkg/expressions" "io" "mime" "net/http" @@ -23,7 +24,7 @@ var ( // a pattern for a value fetched dynamically from the authorization JSON type JSONProperty struct { Name string - Value JSONValue + Value expressions.Value } type JSONValue struct { diff --git a/pkg/service/auth_pipeline_test.go b/pkg/service/auth_pipeline_test.go index 446ddad7..d3feadf9 100644 --- a/pkg/service/auth_pipeline_test.go +++ b/pkg/service/auth_pipeline_test.go @@ -340,8 +340,8 @@ func TestEvaluateWithCustomDenyOptions(t *testing.T) { Unauthenticated: &evaluators.DenyWithValues{ Code: 302, Headers: []json.JSONProperty{ - {Name: "X-Static-Header", Value: json.JSONValue{Static: "some-value"}}, - {Name: "Location", Value: json.JSONValue{Pattern: "https://my-app.io/login?redirect_to=https://{context.request.http.host}{context.request.http.path}"}}, + {Name: "X-Static-Header", Value: &json.JSONValue{Static: "some-value"}}, + {Name: "Location", Value: &json.JSONValue{Pattern: "https://my-app.io/login?redirect_to=https://{context.request.http.host}{context.request.http.path}"}}, }, Body: &json.JSONValue{ Static: authConfigStaticResponse, diff --git a/pkg/service/auth_test.go b/pkg/service/auth_test.go index 26366e04..d23ce0f7 100644 --- a/pkg/service/auth_test.go +++ b/pkg/service/auth_test.go @@ -256,7 +256,7 @@ func TestAuthServiceRawHTTPAuthorization_WithHeaders(t *testing.T) { Wrapper: "httpHeader", WrapperKey: "x-auth-data", DynamicJSON: &response.DynamicJSON{ - Properties: []json.JSONProperty{{Name: "headers", Value: json.JSONValue{Pattern: "context.request.http.headers"}}}, + Properties: []json.JSONProperty{{Name: "headers", Value: &json.JSONValue{Pattern: "context.request.http.headers"}}}, }, }} indexMock := mock_index.NewMockIndex(mockController)