From e3c4b7a2885ad7d2d911b93a44efcc19c0e2d7f2 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 27 Feb 2024 12:19:43 -0500 Subject: [PATCH 1/3] instantiate attributes service with in-memory connection as well --- cmd/start.go | 4 ++-- services/policy/attributes/attributes.go | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index 14e83268db..0ef72242ef 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -142,7 +142,7 @@ func RegisterServices(_ config.Config, otdf *server.OpenTDFServer, dbClient *db. } slog.Info("registering attributes server") - err = attr.NewAttributesServer(dbClient, otdf.GrpcServer, otdf.Mux) + err = attr.NewAttributesServer(dbClient, otdf.GrpcServer, otdf.GrpcInProcess.GetGrpcServer(), otdf.Mux) if err != nil { return fmt.Errorf("could not register attributes service: %w", err) } @@ -166,7 +166,7 @@ func RegisterServices(_ config.Config, otdf *server.OpenTDFServer, dbClient *db. } slog.Info("registering authorization server") - err = authorization.NewAuthorizationServer(otdf.GrpcServer, otdf.Mux) + err = authorization.NewAuthorizationServer(otdf.GrpcServer, otdf.GrpcInProcess.Conn(), otdf.Mux) if err != nil { return fmt.Errorf("could not register authorization service: %w", err) } diff --git a/services/policy/attributes/attributes.go b/services/policy/attributes/attributes.go index 65655d9c60..b56ff958d9 100644 --- a/services/policy/attributes/attributes.go +++ b/services/policy/attributes/attributes.go @@ -18,11 +18,14 @@ type AttributesService struct { dbClient *policydb.PolicyDbClient } -func NewAttributesServer(dbClient *db.Client, g *grpc.Server, s *runtime.ServeMux) error { +func NewAttributesServer(dbClient *db.Client, g *grpc.Server, grpcInprocess *grpc.Server, s *runtime.ServeMux) error { as := &AttributesService{ dbClient: policydb.NewClient(*dbClient), } attr.RegisterAttributesServiceServer(g, as) + if grpcInprocess != nil { + attr.RegisterAttributesServiceServer(grpcInprocess, as) + } err := attr.RegisterAttributesServiceHandlerServer(context.Background(), s, as) if err != nil { return fmt.Errorf("failed to register attributes service handler: %w", err) From 53ee1ef75a18fbd03192d4d57a6cf492d91387b1 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 27 Feb 2024 12:21:32 -0500 Subject: [PATCH 2/3] update commented example of DecisionRequest in proto that comments service/client generated code to match the real proto definition --- docs/grpc/index.html | 2 +- .../authorization/authorization.swagger.json | 2 +- protocol/go/authorization/authorization.pb.go | 16 ++-- .../authorization/DecisionRequest.java | 32 +++---- services/authorization/authorization.proto | 84 +++++++++---------- 5 files changed, 55 insertions(+), 81 deletions(-) diff --git a/docs/grpc/index.html b/docs/grpc/index.html index 051664f713..6840a8b4c5 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -746,7 +746,7 @@

Action

DecisionRequest

-

Example Request Get Decisions to answer the question - Do Bob (represented by entity chain ec1)

and Alice (represented by entity chain ec2) have TRANSMIT authorization for

2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ?

{

"actions": [

{

"standard": "STANDARD_ACTION_TRANSMIT"

}

],

"entityChains": [

{

"id": "ec1",

"entities": [

{

"emailAddress": "bob@example.org"

}

]

},

{

"id": "ec2",

"entities": [

{

"userName": "alice@example.org"

}

]

}

],

"resourceAttributes": [

{

"attributeValueReferences": [

{

"attributeFqn": "http://www.example.org/attr/foo/value/bar"

}

]

},

{

"attributeValueReferences": [

{

"attributeFqn": "http://www.example.org/attr/foo/value/bar"

},

{

"attributeFqn": "http://www.example.org/attr/color/value/red"

}

]

}

]

}

+

Example Request Get Decisions to answer the question - Do Bob (represented by entity chain ec1)

and Alice (represented by entity chain ec2) have TRANSMIT authorization for

2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ?

{

"actions": [

{

"standard": "STANDARD_ACTION_TRANSMIT"

}

],

"entityChains": [

{

"id": "ec1",

"entities": [

{

"emailAddress": "bob@example.org"

}

]

},

{

"id": "ec2",

"entities": [

{

"userName": "alice@example.org"

}

]

}

],

"resourceAttributes": [

{

"attributeFqns": [

"https://www.example.org/attr/foo/value/value1"

]

},

{

"attributeFqns": [

"https://example.net/attr/attr1/value/value1",

"https://example.net/attr/attr1/value/value2"

]

}

]

}

diff --git a/docs/openapi/authorization/authorization.swagger.json b/docs/openapi/authorization/authorization.swagger.json index 7a8ac21eb2..436fbc05d5 100644 --- a/docs/openapi/authorization/authorization.swagger.json +++ b/docs/openapi/authorization/authorization.swagger.json @@ -130,7 +130,7 @@ } } }, - "description": "{\n\"actions\": [\n{\n\"standard\": \"STANDARD_ACTION_TRANSMIT\"\n}\n],\n\"entityChains\": [\n{\n\"id\": \"ec1\",\n\"entities\": [\n{\n\"emailAddress\": \"bob@example.org\"\n}\n]\n},\n{\n\"id\": \"ec2\",\n\"entities\": [\n{\n\"userName\": \"alice@example.org\"\n}\n]\n}\n],\n\"resourceAttributes\": [\n{\n\"attributeValueReferences\": [\n{\n\"attributeFqn\": \"http://www.example.org/attr/foo/value/bar\"\n}\n]\n},\n{\n\"attributeValueReferences\": [\n{\n\"attributeFqn\": \"http://www.example.org/attr/foo/value/bar\"\n},\n{\n\"attributeFqn\": \"http://www.example.org/attr/color/value/red\"\n}\n]\n}\n]\n}", + "description": "{\n\"actions\": [\n{\n\"standard\": \"STANDARD_ACTION_TRANSMIT\"\n}\n],\n\"entityChains\": [\n{\n\"id\": \"ec1\",\n\"entities\": [\n{\n\"emailAddress\": \"bob@example.org\"\n}\n]\n},\n{\n\"id\": \"ec2\",\n\"entities\": [\n{\n\"userName\": \"alice@example.org\"\n}\n]\n}\n],\n\"resourceAttributes\": [\n{\n\"attributeFqns\": [\n\"https://www.example.org/attr/foo/value/value1\"\n]\n},\n{\n\"attributeFqns\": [\n\"https://example.net/attr/attr1/value/value1\",\n\"https://example.net/attr/attr1/value/value2\"\n]\n}\n]\n}", "title": "Example Request Get Decisions to answer the question - Do Bob (represented by entity chain ec1)\nand Alice (represented by entity chain ec2) have TRANSMIT authorization for\n2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ?" }, "authorizationDecisionResponse": { diff --git a/protocol/go/authorization/authorization.pb.go b/protocol/go/authorization/authorization.pb.go index 3b0c9cd1fc..eb76189c01 100644 --- a/protocol/go/authorization/authorization.pb.go +++ b/protocol/go/authorization/authorization.pb.go @@ -485,20 +485,14 @@ func (*Action_Custom) isAction_Value() {} // ], // "resourceAttributes": [ // { -// "attributeValueReferences": [ -// { -// "attributeFqn": "http://www.example.org/attr/foo/value/bar" -// } +// "attributeFqns": [ +// "https://www.example.org/attr/foo/value/value1" // ] // }, // { -// "attributeValueReferences": [ -// { -// "attributeFqn": "http://www.example.org/attr/foo/value/bar" -// }, -// { -// "attributeFqn": "http://www.example.org/attr/color/value/red" -// } +// "attributeFqns": [ +// "https://example.net/attr/attr1/value/value1", +// "https://example.net/attr/attr1/value/value2" // ] // } // ] diff --git a/sdkjava/src/main/java/io/opentdf/platform/authorization/DecisionRequest.java b/sdkjava/src/main/java/io/opentdf/platform/authorization/DecisionRequest.java index a441fb9508..64296b8cdd 100644 --- a/sdkjava/src/main/java/io/opentdf/platform/authorization/DecisionRequest.java +++ b/sdkjava/src/main/java/io/opentdf/platform/authorization/DecisionRequest.java @@ -37,20 +37,14 @@ *], *"resourceAttributes": [ *{ - *"attributeValueReferences": [ - *{ - *"attributeFqn": "http://www.example.org/attr/foo/value/bar" - *} + *"attributeFqns": [ + *"https://www.example.org/attr/foo/value/value1" *] *}, *{ - *"attributeValueReferences": [ - *{ - *"attributeFqn": "http://www.example.org/attr/foo/value/bar" - *}, - *{ - *"attributeFqn": "http://www.example.org/attr/color/value/red" - *} + *"attributeFqns": [ + *"https://example.net/attr/attr1/value/value1", + *"https://example.net/attr/attr1/value/value2" *] *} *] @@ -435,20 +429,14 @@ protected Builder newBuilderForType( *], *"resourceAttributes": [ *{ - *"attributeValueReferences": [ - *{ - *"attributeFqn": "http://www.example.org/attr/foo/value/bar" - *} + *"attributeFqns": [ + *"https://www.example.org/attr/foo/value/value1" *] *}, *{ - *"attributeValueReferences": [ - *{ - *"attributeFqn": "http://www.example.org/attr/foo/value/bar" - *}, - *{ - *"attributeFqn": "http://www.example.org/attr/color/value/red" - *} + *"attributeFqns": [ + *"https://example.net/attr/attr1/value/value1", + *"https://example.net/attr/attr1/value/value2" *] *} *] diff --git a/services/authorization/authorization.proto b/services/authorization/authorization.proto index d4fa2944e2..37bd50dd9a 100644 --- a/services/authorization/authorization.proto +++ b/services/authorization/authorization.proto @@ -49,52 +49,44 @@ message Action { and Alice (represented by entity chain ec2) have TRANSMIT authorization for 2 resources; resource1 (attr-set-1) defined by attributes foo:bar resource2 (attr-set-2) defined by attribute foo:bar, color:red ? - { - "actions": [ - { - "standard": "STANDARD_ACTION_TRANSMIT" - } - ], - "entityChains": [ - { - "id": "ec1", - "entities": [ - { - "emailAddress": "bob@example.org" - } - ] - }, - { - "id": "ec2", - "entities": [ - { - "userName": "alice@example.org" - } - ] - } - ], - "resourceAttributes": [ - { - "attributeValueReferences": [ - { - "attributeFqn": "http://www.example.org/attr/foo/value/bar" - } - ] - }, - { - "attributeValueReferences": [ - { - "attributeFqn": "http://www.example.org/attr/foo/value/bar" - }, - { - "attributeFqn": "http://www.example.org/attr/color/value/red" - } - ] - } - ] - } - - + { + "actions": [ + { + "standard": "STANDARD_ACTION_TRANSMIT" + } + ], + "entityChains": [ + { + "id": "ec1", + "entities": [ + { + "emailAddress": "bob@example.org" + } + ] + }, + { + "id": "ec2", + "entities": [ + { + "userName": "alice@example.org" + } + ] + } + ], + "resourceAttributes": [ + { + "attributeFqns": [ + "https://www.example.org/attr/foo/value/value1" + ] + }, + { + "attributeFqns": [ + "https://example.net/attr/attr1/value/value1", + "https://example.net/attr/attr1/value/value2" + ] + } + ] +} */ message DecisionRequest { From abcce4730f57b7adf1cf8addb551ba597fba2592 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 27 Feb 2024 12:21:59 -0500 Subject: [PATCH 3/3] make the attribute fqns request with the in-memory client connection and log the received attributes --- services/authorization/authorization.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/services/authorization/authorization.go b/services/authorization/authorization.go index 145151fff2..9c544f7e8d 100644 --- a/services/authorization/authorization.go +++ b/services/authorization/authorization.go @@ -4,18 +4,24 @@ import ( "context" "fmt" "log/slog" + "strings" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/opentdf/platform/protocol/go/authorization" + attr "github.com/opentdf/platform/protocol/go/policy/attributes" + "github.com/opentdf/platform/services" "google.golang.org/grpc" ) type AuthorizationService struct { authorization.UnimplementedAuthorizationServiceServer + cc *grpc.ClientConn } -func NewAuthorizationServer(g *grpc.Server, s *runtime.ServeMux) error { - as := &AuthorizationService{} +func NewAuthorizationServer(g *grpc.Server, cc *grpc.ClientConn, s *runtime.ServeMux) error { + as := &AuthorizationService{ + cc: cc, + } authorization.RegisterAuthorizationServiceServer(g, as) err := authorization.RegisterAuthorizationServiceHandlerServer(context.Background(), s, as) if err != nil { @@ -27,13 +33,25 @@ func NewAuthorizationServer(g *grpc.Server, s *runtime.ServeMux) error { func (as AuthorizationService) GetDecisions(ctx context.Context, req *authorization.GetDecisionsRequest) (*authorization.GetDecisionsResponse, error) { slog.Debug("getting decisions") + attrClient := attr.NewAttributesServiceClient(as.cc) + // Temporary canned echo response with permit decision for all requested decision/entity/ra combos rsp := &authorization.GetDecisionsResponse{ DecisionResponses: make([]*authorization.DecisionResponse, 0), } for _, dr := range req.DecisionRequests { for _, ra := range dr.ResourceAttributes { + slog.Debug("getting resource attributes", slog.String("FQNs", strings.Join(ra.AttributeFqns, ", "))) + + attrs, err := attrClient.GetAttributesByValueFqns(ctx, &attr.GetAttributesByValueFqnsRequest{ + Fqns: ra.AttributeFqns, + }) + if err != nil { + // TODO: should all decisions in a request fail if one FQN lookup fails? + return nil, services.HandleError(err, services.ErrGetRetrievalFailed, slog.String("fqns", strings.Join(ra.AttributeFqns, ", "))) + } for _, ec := range dr.EntityChains { + fmt.Printf("\nTODO: make access decision here with these fully qualified attributes: %+v\n", attrs) decision := &authorization.DecisionResponse{ Decision: authorization.DecisionResponse_DECISION_PERMIT, EntityChainId: ec.Id,