diff --git a/.golangci.yml b/.golangci.yml index 81b9bc1..a4141c1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -141,3 +141,10 @@ issues: - govet text: 'fieldalignment:' path: .*_test.go$ + + # We want to allow import gomega and ginkgo (+ all sub-packages) in tests files only + - linters: + - revive + text: '^dot-imports:' + source: . "github.com/onsi/(gomega|ginkgo)(/.*)?" + path: .*_test.go diff --git a/functions/is_authorization.go b/functions/is_authorization.go index e072b88..4192a15 100644 --- a/functions/is_authorization.go +++ b/functions/is_authorization.go @@ -40,13 +40,18 @@ func init() { }, nil), types.NewObject([]*types.StaticProperty{ types.NewStaticProperty("id", types.S), - types.NewStaticProperty("type", types.S), + types.NewStaticProperty("subjectType", types.S), }, nil), types.NewObject([]*types.StaticProperty{ types.NewStaticProperty("id", types.S), - types.NewStaticProperty("type", types.S), + types.NewStaticProperty("subjectType", types.S), types.NewStaticProperty("property", types.S), }, nil), + types.NewObject([]*types.StaticProperty{ + types.NewStaticProperty("id", types.S), + types.NewStaticProperty("subjectType", types.S), + types.NewStaticProperty("type", types.S), + }, nil), )), types.Named("resources", types.NewArray(nil, types.NewObject([]*types.StaticProperty{ types.NewStaticProperty("externalId", types.S), diff --git a/functions/is_authorization_test.go b/functions/is_authorization_test.go index f6b1118..11555f0 100644 --- a/functions/is_authorization_test.go +++ b/functions/is_authorization_test.go @@ -150,7 +150,7 @@ var _ = Describe("indy.is_authorized", func() { respTTL: durationpb.New(time.Minute * 90), decisionTimeMatcher: BeEquivalentTo("1645543102"), // All numbers are json.Number ie string ttlMatcher: BeEquivalentTo("5400"), - regoParam1: `{"id": "` + testAccessToken + `", "type": "token"}`, + regoParam1: `{"id": "` + testAccessToken + `", "subjectType": "token"}`, }), Entry("DigitalTwin id", &dtIDCase{ reqSubject: &authorizationpb.Subject{ @@ -164,7 +164,7 @@ var _ = Describe("indy.is_authorized", func() { respTTL: durationpb.New(time.Minute * 90), decisionTimeMatcher: BeEquivalentTo("1645543102"), // All numbers are json.Number ie string ttlMatcher: BeEquivalentTo("5400"), - regoParam1: `{"id": "gid:AAAAFezuHiJHiUeRjrIJV8k3oKo", "type": "id"}`, + regoParam1: `{"id": "gid:AAAAFezuHiJHiUeRjrIJV8k3oKo", "subjectType": "id"}`, }), Entry("DigitalTwin property", &dtIDCase{ reqSubject: &authorizationpb.Subject{ @@ -179,7 +179,22 @@ var _ = Describe("indy.is_authorized", func() { respTTL: durationpb.New(time.Minute * 90), decisionTimeMatcher: BeEquivalentTo("1645543102"), // All numbers are json.Number ie string ttlMatcher: BeEquivalentTo("5400"), - regoParam1: `{"id": "sam@sung.com", "type": "property", "property": "email"}`, + regoParam1: `{"id": "sam@sung.com", "subjectType": "property", "property": "email"}`, + }), + Entry("DigitalTwin externalID", &dtIDCase{ + reqSubject: &authorizationpb.Subject{ + Subject: &authorizationpb.Subject_ExternalId{ + ExternalId: &authorizationpb.ExternalID{ + Type: "Person", + ExternalId: "some-external-id", + }, + }, + }, + respDecisionTime: timestamppb.New(time.Date(2022, 02, 22, 15, 18, 22, 0, time.UTC)), + respTTL: durationpb.New(time.Minute * 90), + decisionTimeMatcher: BeEquivalentTo("1645543102"), // All numbers are json.Number ie string + ttlMatcher: BeEquivalentTo("5400"), + regoParam1: `{"id": "some-external-id", "subjectType": "external_id", "type": "Person"}`, }), ) @@ -218,10 +233,10 @@ var _ = Describe("indy.is_authorized", func() { Entry("Empty resource_references", `{"id": "`+testAccessToken+`"}, [], {}`, "unable to call IsAuthorized client endpoint", "invalid IsAuthorizedRequest.Resources: value must contain between 1 and 32 items, inclusive"), - Entry("Invalid digital twin", `{"id": "abc", "type": "id"}, [{"externalId": "res1", "type": "Type", "actions": ["READ"]}, {"externalId": "res2", "type": "Type", "actions": ["READ"]}], {}`, + Entry("Invalid digital twin", `{"id": "abc", "subjectType": "id"}, [{"externalId": "res1", "type": "Type", "actions": ["READ"]}, {"externalId": "res2", "type": "Type", "actions": ["READ"]}], {}`, "unable to call IsAuthorized client endpoint", "invalid DigitalTwin.Id: value length must be between 27 and 100 runes"), - Entry("Invalid propertyType", `{"id": "", "type": "property", "property": ""}, [{"externalId": "res1", "type": "Type", "actions": ["READ"]}, {"externalId": "res2", "type": "Type", "actions": ["READ"]}], {}`, + Entry("Invalid propertyType", `{"id": "", "subjectType": "property", "property": ""}, [{"externalId": "res1", "type": "Type", "actions": ["READ"]}, {"externalId": "res2", "type": "Type", "actions": ["READ"]}], {}`, "unable to call IsAuthorized client endpoint", "invalid Property.Type: value length must be between 2 and 20 runes"), ) diff --git a/functions/option.go b/functions/option.go index 96ec95d..37b996f 100644 --- a/functions/option.go +++ b/functions/option.go @@ -26,6 +26,7 @@ const policyTagsKey = "policyTags" const subjectTypeToken = "token" const subjectTypeID = "id" const subjectTypeProperty = "property" +const subjectTypeExternalID = "external_id" var allowedKeyNames = [...]string{ inputParamsKey, @@ -174,6 +175,20 @@ func extractSubject(subjectValue ast.Value, pos int) (*authorizationpb.Subject, }, }, }, nil + case subjectTypeExternalID: + nodeTypeObject := subject.Get(ast.StringTerm("type")) + if nodeTypeObject == nil { + return nil, builtins.NewOperandTypeErr(pos, subjectValue, "type") + } + nodeType := nodeTypeObject.Value.(ast.String) + return &authorizationpb.Subject{ + Subject: &authorizationpb.Subject_ExternalId{ + ExternalId: &authorizationpb.ExternalID{ + Type: string(nodeType), + ExternalId: string(idValue), + }, + }, + }, nil } // Next line is unreachable. OPA will complain based on declaration of function, when types do not match. @@ -181,7 +196,7 @@ func extractSubject(subjectValue ast.Value, pos int) (*authorizationpb.Subject, } func getSubjectType(subject ast.Object) string { - typeObject := subject.Get(ast.StringTerm("type")) + typeObject := subject.Get(ast.StringTerm("subjectType")) if typeObject == nil { return subjectTypeToken } diff --git a/functions/what_authorization.go b/functions/what_authorization.go index d06aee9..51d69d8 100644 --- a/functions/what_authorization.go +++ b/functions/what_authorization.go @@ -36,13 +36,18 @@ func init() { }, nil), types.NewObject([]*types.StaticProperty{ types.NewStaticProperty("id", types.S), - types.NewStaticProperty("type", types.S), + types.NewStaticProperty("subjectType", types.S), }, nil), types.NewObject([]*types.StaticProperty{ types.NewStaticProperty("id", types.S), - types.NewStaticProperty("type", types.S), + types.NewStaticProperty("subjectType", types.S), types.NewStaticProperty("property", types.S), }, nil), + types.NewObject([]*types.StaticProperty{ + types.NewStaticProperty("id", types.S), + types.NewStaticProperty("subjectType", types.S), + types.NewStaticProperty("type", types.S), + }, nil), )), types.Named("resourcesTypes", types.NewArray(nil, types.NewAny( types.NewObject([]*types.StaticProperty{ diff --git a/functions/what_authorization_test.go b/functions/what_authorization_test.go index 8ec6ac4..0b26068 100644 --- a/functions/what_authorization_test.go +++ b/functions/what_authorization_test.go @@ -172,7 +172,7 @@ var _ = Describe("indy.what_authorized", func() { respTTL: durationpb.New(time.Minute * 90), decisionTimeMatcher: BeEquivalentTo("1645543102"), // All numbers are json.Number ie string ttlMatcher: BeEquivalentTo("5400"), - regoParam1: `{"id": "` + testAccessToken + `", "type": "token"}`, + regoParam1: `{"id": "` + testAccessToken + `", "subjectType": "token"}`, }), Entry("DigitalTwin", &dtIDCase{ reqSubject: &authorizationpb.Subject{ @@ -187,7 +187,7 @@ var _ = Describe("indy.what_authorized", func() { respTTL: nil, decisionTimeMatcher: BeEquivalentTo("0"), ttlMatcher: BeEquivalentTo("0"), - regoParam1: `{"id": "gid:AAAAFezuHiJHiUeRjrIJV8k3oKo", "type": "id"}`, + regoParam1: `{"id": "gid:AAAAFezuHiJHiUeRjrIJV8k3oKo", "subjectType": "id"}`, }), Entry("DigitalTwin property", &dtIDCase{ reqSubject: &authorizationpb.Subject{ @@ -203,7 +203,23 @@ var _ = Describe("indy.what_authorized", func() { respTTL: nil, decisionTimeMatcher: BeEquivalentTo("0"), ttlMatcher: BeEquivalentTo("0"), - regoParam1: `{"id": "sam@sung.com", "type": "property", "property": "email"}`, + regoParam1: `{"id": "sam@sung.com", "subjectType": "property", "property": "email"}`, + }), + Entry("DigitalTwin externalID", &dtIDCase{ + reqSubject: &authorizationpb.Subject{ + Subject: &authorizationpb.Subject_ExternalId{ + ExternalId: &authorizationpb.ExternalID{ + Type: "Person", + ExternalId: "some-external-id", + }, + }, + }, + // Test also nil values + respDecisionTime: nil, + respTTL: nil, + decisionTimeMatcher: BeEquivalentTo("0"), + ttlMatcher: BeEquivalentTo("0"), + regoParam1: `{"id": "some-external-id", "subjectType": "external_id", "type": "Person"}`, }), ) @@ -239,10 +255,10 @@ var _ = Describe("indy.what_authorized", func() { Entry("Empty resource_references", `{"id": "`+testAccessToken+`"}, [], {}`, "unable to call WhatAuthorized client endpoint", "invalid WhatAuthorizedRequest.ResourceTypes: value must contain between 1 and 10 items, inclusive"), - Entry("Invalid digital twin", `{"id": "abc", "type": "id"}, [{"type": "Type", "actions": ["READ"]}], {}`, + Entry("Invalid digital twin", `{"id": "abc", "subjectType": "id"}, [{"type": "Type", "actions": ["READ"]}], {}`, "unable to call WhatAuthorized client endpoint", "invalid DigitalTwin.Id: value length must be between 27 and 100 runes"), - Entry("Invalid propertyType", `{"id": "", "type": "property", "property": ""}, [{"type": "Type", "actions": ["READ"]}, {"type": "Type", "actions": ["READ"]}], {}`, + Entry("Invalid propertyType", `{"id": "", "subjectType": "property", "property": ""}, [{"type": "Type", "actions": ["READ"]}, {"type": "Type", "actions": ["READ"]}], {}`, "unable to call WhatAuthorized client endpoint", "invalid Property.Type: value length must be between 2 and 20 runes"), )