Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions service/authorization/v2/authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"buf.build/go/protovalidate"
"github.com/opentdf/platform/lib/identifier"
authzV2 "github.com/opentdf/platform/protocol/go/authorization/v2"
"github.com/opentdf/platform/protocol/go/entity"
"github.com/opentdf/platform/protocol/go/policy"
Expand All @@ -23,6 +24,7 @@ var (
sampleResourceFQN = "https://example.com/attr/hier/value/highest"
sampleResourceFQN2 = "https://example.com/attr/hier/value/lowest"
sampleRegisteredResourceFQN = "https://example.com/reg_res/system/value/internal"
sampleObligationValueFQN = "https://example.com/obl/drm/value/prevent_print"

// Good multi-resource requests that should pass validation
goodMultiResourceRequests = []struct {
Expand Down Expand Up @@ -353,6 +355,62 @@ var (
},
expectedValidationError: "registered_resource_value_fqn",
},
{
name: "too many obligations",
request: &authzV2.GetDecisionMultiResourceRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_EntityChain{
EntityChain: &entity.EntityChain{
EphemeralId: "1234",
Entities: []*entity.Entity{
{
EphemeralId: "chained-1",
EntityType: &entity.Entity_EmailAddress{EmailAddress: "[email protected]"},
Category: entity.Entity_CATEGORY_SUBJECT,
},
},
},
},
},
Action: sampleActionCreate,
Resources: []*authzV2.Resource{
{
Resource: &authzV2.Resource_AttributeValues_{
AttributeValues: &authzV2.Resource_AttributeValues{
Fqns: []string{sampleResourceFQN},
},
},
},
{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
},
FulfillableObligationFqns: getTooManyObligations(),
},
expectedValidationError: "obligation_value_fqns_valid",
},
{
name: "invalid obligation",
request: &authzV2.GetDecisionMultiResourceRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
Action: sampleActionCreate,
Resources: []*authzV2.Resource{
{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
},
FulfillableObligationFqns: []string{"missing.scheme/obl/name/value/val"},
},
expectedValidationError: "obligation_value_fqns_valid",
},
}
)

Expand Down Expand Up @@ -418,6 +476,10 @@ func Test_Resource_ManyAttributeValues(t *testing.T) {

func Test_GetDecisionRequest_Succeeds(t *testing.T) {
v := getValidator()
fiftyObligations := make([]string, 50)
for i := range 50 {
fiftyObligations[i] = sampleObligationValueFQN
}

cases := []struct {
name string
Expand Down Expand Up @@ -558,6 +620,40 @@ func Test_GetDecisionRequest_Succeeds(t *testing.T) {
},
},
},
{
name: "entity: registered resource, action: create, resource: registered, obligations - 1",
request: &authzV2.GetDecisionRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
Action: sampleActionCreate,
Resource: &authzV2.Resource{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
FulfillableObligationFqns: []string{sampleObligationValueFQN},
},
},
{
name: "entity: registered resource, action: create, resource: registered, obligations - 50",
request: &authzV2.GetDecisionRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
Action: sampleActionCreate,
Resource: &authzV2.Resource{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
FulfillableObligationFqns: fiftyObligations,
},
},
}

for _, tc := range cases {
Expand All @@ -570,6 +666,7 @@ func Test_GetDecisionRequest_Succeeds(t *testing.T) {

func Test_GetDecisionRequest_Fails(t *testing.T) {
v := getValidator()

cases := []struct {
name string
request *authzV2.GetDecisionRequest
Expand Down Expand Up @@ -771,6 +868,40 @@ func Test_GetDecisionRequest_Fails(t *testing.T) {
},
expectedValidationError: "entities",
},
{
name: "too many obligations",
request: &authzV2.GetDecisionRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
Action: sampleActionCreate,
Resource: &authzV2.Resource{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
FulfillableObligationFqns: getTooManyObligations(),
},
},
{
name: "invalid obligation format",
request: &authzV2.GetDecisionRequest{
EntityIdentifier: &authzV2.EntityIdentifier{
Identifier: &authzV2.EntityIdentifier_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
Action: sampleActionCreate,
Resource: &authzV2.Resource{
Resource: &authzV2.Resource_RegisteredResourceValueFqn{
RegisteredResourceValueFqn: sampleRegisteredResourceFQN,
},
},
FulfillableObligationFqns: []string{"invalid-format"},
},
},
}

for _, tc := range cases {
Expand All @@ -791,6 +922,7 @@ func Test_GetDecisionMultiResourceRequest_Succeeds(t *testing.T) {
// All known good cases should pass
for _, tc := range goodMultiResourceRequests {
t.Run(tc.name, func(t *testing.T) {
tc.request.FulfillableObligationFqns = getRandomValidObligationValueFQNsList()
err := v.Validate(tc.request)
require.NoError(t, err, "validation should succeed for request: %s", tc.name)
})
Expand Down Expand Up @@ -874,6 +1006,7 @@ func Test_GetDecisionBulkRequest_Succeeds(t *testing.T) {
clonedReq.Action = &policy.Action{
Name: actions[rand.Intn(len(actions))],
}
clonedReq.FulfillableObligationFqns = getRandomValidObligationValueFQNsList()
reqs[j] = clonedReq
}
for j := firstCount; j < firstCount+secondCount; j++ {
Expand All @@ -882,6 +1015,7 @@ func Test_GetDecisionBulkRequest_Succeeds(t *testing.T) {
clonedReq.Action = &policy.Action{
Name: actions[rand.Intn(len(actions))],
}
clonedReq.FulfillableObligationFqns = getRandomValidObligationValueFQNsList()
reqs[j] = clonedReq
}

Expand Down Expand Up @@ -1503,3 +1637,41 @@ func Test_RollupSingleResourceDecision_WithNilChecks(t *testing.T) {
assert.Contains(t, err.Error(), "no decision results returned")
})
}

// Helpers

func getRandomValidObligationValueFQNsList() []string {
count := rand.Intn(50)
randomList := make([]string, count)
for i := range count {
randomList[i] = getRandomObligationValueFQN()
}
return randomList
}

func getTooManyObligations() []string {
tooMany := make([]string, 51)
for i := range tooMany {
tooMany[i] = getRandomObligationValueFQN()
}
return tooMany
}

const charset = "abcdefghijklmnopqrstuvwxyz"

func randString(length int) string {
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}

// builds a random FQN for an obligation value that matches
// https://<namespace>.com/obl/<name>/value/<value>
func getRandomObligationValueFQN() string {
namespace := "https://" + randString(5) + ".com"
name := randString(5)
value := randString(5)
return identifier.BuildOblValFQN(namespace, name, value)
}
2 changes: 1 addition & 1 deletion service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ require (
github.com/opentdf/platform/lib/flattening v0.1.3
github.com/opentdf/platform/lib/identifier v0.1.0
github.com/opentdf/platform/lib/ocrypto v0.6.0
github.com/opentdf/platform/protocol/go v0.10.0
github.com/opentdf/platform/protocol/go v0.11.0
github.com/opentdf/platform/sdk v0.7.0
github.com/pressly/goose/v3 v3.24.3
github.com/spf13/cobra v1.9.1
Expand Down
4 changes: 2 additions & 2 deletions service/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ github.com/opentdf/platform/lib/identifier v0.1.0 h1:R6Q9z+iSRTIUWm87s9xIImf4u7B
github.com/opentdf/platform/lib/identifier v0.1.0/go.mod h1:/tHnLlSVOq3qmbIYSvKrtuZchQfagenv4wG5twl4oRs=
github.com/opentdf/platform/lib/ocrypto v0.6.0 h1:CvluMv44dZ4vD0oLpJEoKnm4/BGJzaH8HTcTd8I0kWg=
github.com/opentdf/platform/lib/ocrypto v0.6.0/go.mod h1:sYhoBL1bQYgQVSSNpxU13RsrE5JAk8BABT1hfr9L3j8=
github.com/opentdf/platform/protocol/go v0.10.0 h1:7tlpFXXzOQRHAYMvBcMTYMT56wHR+6BezH2Fumjth6c=
github.com/opentdf/platform/protocol/go v0.10.0/go.mod h1:GRycoDGDxaz91sOvGZFWVEKJLluZFg2wM3NJmhucDHo=
github.com/opentdf/platform/protocol/go v0.11.0 h1:HJWV9QOF3ERpiiXJbEJn0IV/B36FQ2gHt9hJnbfd1xo=
github.com/opentdf/platform/protocol/go v0.11.0/go.mod h1:GRycoDGDxaz91sOvGZFWVEKJLluZFg2wM3NJmhucDHo=
github.com/opentdf/platform/sdk v0.7.0 h1:8hczDycXGY1ucdIXSrP17oW/Eyu3vsb4LEX4hc7tvVY=
github.com/opentdf/platform/sdk v0.7.0/go.mod h1:CTJR1NXeYe896M1/VN0h+1Ff54SdBtxv4z18BGTi8yk=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
Expand Down
Loading