diff --git a/docs/grpc/index.html b/docs/grpc/index.html index e8243fc07d..340535914d 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -357,6 +357,10 @@

Table of Contents

EDecisionResponse.Decision +
  • + EEntity.Category +
  • +
  • @@ -2106,7 +2110,7 @@

    Entity

    email_address string -

    +

    one of the entity options must be set

    @@ -2151,6 +2155,13 @@

    Entity

    + + category + Entity.Category + +

    + + @@ -2533,6 +2544,35 @@

    DecisionResponse.Decision

    +

    Entity.Category

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameNumberDescription
    CATEGORY_UNSPECIFIED0

    CATEGORY_SUBJECT1

    CATEGORY_ENVIRONMENT2

    + diff --git a/docs/openapi/authorization/authorization.swagger.json b/docs/openapi/authorization/authorization.swagger.json index 84d16fe172..43493bf79a 100644 --- a/docs/openapi/authorization/authorization.swagger.json +++ b/docs/openapi/authorization/authorization.swagger.json @@ -128,6 +128,15 @@ ], "default": "DECISION_UNSPECIFIED" }, + "EntityCategory": { + "type": "string", + "enum": [ + "CATEGORY_UNSPECIFIED", + "CATEGORY_SUBJECT", + "CATEGORY_ENVIRONMENT" + ], + "default": "CATEGORY_UNSPECIFIED" + }, "authorizationDecisionRequest": { "type": "object", "properties": { @@ -194,7 +203,8 @@ "title": "ephemeral id for tracking between request and response" }, "emailAddress": { - "type": "string" + "type": "string", + "title": "one of the entity options must be set" }, "userName": { "type": "string" @@ -213,6 +223,9 @@ }, "clientId": { "type": "string" + }, + "category": { + "$ref": "#/definitions/EntityCategory" } }, "title": "PE (Person Entity) or NPE (Non-Person Entity)" diff --git a/docs/openapi/entityresolution/entity_resolution.swagger.json b/docs/openapi/entityresolution/entity_resolution.swagger.json index 288eda816d..45cb881517 100644 --- a/docs/openapi/entityresolution/entity_resolution.swagger.json +++ b/docs/openapi/entityresolution/entity_resolution.swagger.json @@ -82,6 +82,15 @@ } }, "definitions": { + "EntityCategory": { + "type": "string", + "enum": [ + "CATEGORY_UNSPECIFIED", + "CATEGORY_SUBJECT", + "CATEGORY_ENVIRONMENT" + ], + "default": "CATEGORY_UNSPECIFIED" + }, "authorizationEntity": { "type": "object", "properties": { @@ -90,7 +99,8 @@ "title": "ephemeral id for tracking between request and response" }, "emailAddress": { - "type": "string" + "type": "string", + "title": "one of the entity options must be set" }, "userName": { "type": "string" @@ -109,6 +119,9 @@ }, "clientId": { "type": "string" + }, + "category": { + "$ref": "#/definitions/EntityCategory" } }, "title": "PE (Person Entity) or NPE (Non-Person Entity)" diff --git a/examples/cmd/authorization.go b/examples/cmd/authorization.go index f7ac1d705c..9d3364e21b 100644 --- a/examples/cmd/authorization.go +++ b/examples/cmd/authorization.go @@ -35,11 +35,13 @@ func authorizationExamples() error { // model two groups of entities; user bob and user alice entityChains := []*authorization.EntityChain{{ - Id: "ec1", // ec1 is an arbitrary tracking id to match results to request - Entities: []*authorization.Entity{{EntityType: &authorization.Entity_EmailAddress{EmailAddress: "bob@example.org"}}}, + Id: "ec1", // ec1 is an arbitrary tracking id to match results to request + Entities: []*authorization.Entity{{EntityType: &authorization.Entity_EmailAddress{EmailAddress: "bob@example.org"}, + Category: authorization.Entity_CATEGORY_SUBJECT}}, }, { - Id: "ec2", // ec2 is an arbitrary tracking id to match results to request - Entities: []*authorization.Entity{{EntityType: &authorization.Entity_UserName{UserName: "alice@example.org"}}}, + Id: "ec2", // ec2 is an arbitrary tracking id to match results to request + Entities: []*authorization.Entity{{EntityType: &authorization.Entity_UserName{UserName: "alice@example.org"}, + Category: authorization.Entity_CATEGORY_SUBJECT}}, }} // TODO Get attribute value ids diff --git a/protocol/go/authorization/authorization.pb.go b/protocol/go/authorization/authorization.pb.go index 3c15afd138..8ab0e31352 100644 --- a/protocol/go/authorization/authorization.pb.go +++ b/protocol/go/authorization/authorization.pb.go @@ -23,6 +23,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type Entity_Category int32 + +const ( + Entity_CATEGORY_UNSPECIFIED Entity_Category = 0 + Entity_CATEGORY_SUBJECT Entity_Category = 1 + Entity_CATEGORY_ENVIRONMENT Entity_Category = 2 +) + +// Enum value maps for Entity_Category. +var ( + Entity_Category_name = map[int32]string{ + 0: "CATEGORY_UNSPECIFIED", + 1: "CATEGORY_SUBJECT", + 2: "CATEGORY_ENVIRONMENT", + } + Entity_Category_value = map[string]int32{ + "CATEGORY_UNSPECIFIED": 0, + "CATEGORY_SUBJECT": 1, + "CATEGORY_ENVIRONMENT": 2, + } +) + +func (x Entity_Category) Enum() *Entity_Category { + p := new(Entity_Category) + *p = x + return p +} + +func (x Entity_Category) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Entity_Category) Descriptor() protoreflect.EnumDescriptor { + return file_authorization_authorization_proto_enumTypes[0].Descriptor() +} + +func (Entity_Category) Type() protoreflect.EnumType { + return &file_authorization_authorization_proto_enumTypes[0] +} + +func (x Entity_Category) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Entity_Category.Descriptor instead. +func (Entity_Category) EnumDescriptor() ([]byte, []int) { + return file_authorization_authorization_proto_rawDescGZIP(), []int{1, 0} +} + type DecisionResponse_Decision int32 const ( @@ -56,11 +105,11 @@ func (x DecisionResponse_Decision) String() string { } func (DecisionResponse_Decision) Descriptor() protoreflect.EnumDescriptor { - return file_authorization_authorization_proto_enumTypes[0].Descriptor() + return file_authorization_authorization_proto_enumTypes[1].Descriptor() } func (DecisionResponse_Decision) Type() protoreflect.EnumType { - return &file_authorization_authorization_proto_enumTypes[0] + return &file_authorization_authorization_proto_enumTypes[1] } func (x DecisionResponse_Decision) Number() protoreflect.EnumNumber { @@ -146,6 +195,7 @@ type Entity struct { // *Entity_Custom // *Entity_ClientId EntityType isEntity_EntityType `protobuf_oneof:"entity_type"` + Category Entity_Category `protobuf:"varint,9,opt,name=category,proto3,enum=authorization.Entity_Category" json:"category,omitempty"` } func (x *Entity) Reset() { @@ -243,11 +293,19 @@ func (x *Entity) GetClientId() string { return "" } +func (x *Entity) GetCategory() Entity_Category { + if x != nil { + return x.Category + } + return Entity_CATEGORY_UNSPECIFIED +} + type isEntity_EntityType interface { isEntity_EntityType() } type Entity_EmailAddress struct { + // one of the entity options must be set EmailAddress string `protobuf:"bytes,2,opt,name=email_address,json=emailAddress,proto3,oneof"` } @@ -1178,7 +1236,7 @@ var file_authorization_authorization_proto_rawDesc = []byte{ 0x69, 0x63, 0x79, 0x2f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x29, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6a, 0x77, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, 0x77, 0x74, 0x22, 0xb7, 0x02, 0x0a, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, 0x77, 0x74, 0x22, 0xc9, 0x03, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, @@ -1197,164 +1255,173 @@ var file_authorization_authorization_proto_rawDesc = []byte{ 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x00, 0x52, 0x06, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x42, 0x0a, 0x0c, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x12, 0x32, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, - 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x0b, 0x45, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0xcf, 0x01, 0x0a, - 0x0f, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x0c, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x51, 0x0a, 0x13, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0xce, - 0x02, 0x0a, 0x10, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x49, - 0x64, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x64, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x20, 0x0a, 0x0b, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0x4c, 0x0a, 0x08, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, - 0x14, 0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x45, 0x43, 0x49, 0x53, - 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x45, - 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x22, - 0x62, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x10, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x22, 0x66, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x12, 0x64, - 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x11, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x16, - 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, - 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x1c, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x63, - 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x68, 0x69, 0x65, - 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x1a, - 0x77, 0x69, 0x74, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, - 0x65, 0x48, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, - 0x06, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x42, 0x1f, 0x0a, 0x1d, 0x5f, 0x77, 0x69, 0x74, 0x68, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x68, - 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x22, 0x63, 0x0a, 0x12, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1b, - 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, - 0x71, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x71, 0x6e, 0x73, 0x22, 0x7b, 0x0a, - 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x71, 0x6e, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x71, 0x6e, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x47, 0x65, - 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0c, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xc1, 0x01, 0x0a, - 0x14, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x2c, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x51, 0x0a, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x22, 0x54, 0x0a, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, + 0x18, 0x0a, 0x14, 0x43, 0x41, 0x54, 0x45, 0x47, 0x4f, 0x52, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x41, 0x54, + 0x45, 0x47, 0x4f, 0x52, 0x59, 0x5f, 0x53, 0x55, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, + 0x18, 0x0a, 0x14, 0x43, 0x41, 0x54, 0x45, 0x47, 0x4f, 0x52, 0x59, 0x5f, 0x45, 0x4e, 0x56, 0x49, + 0x52, 0x4f, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x42, 0x0d, 0x0a, 0x0b, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x42, 0x0a, 0x0c, 0x45, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x12, 0x32, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x0b, + 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0xcf, + 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x0d, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, + 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x51, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x22, 0x6e, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x50, - 0x0a, 0x11, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x44, - 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x10, - 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, - 0x22, 0x6d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4e, 0x0a, 0x12, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x11, 0x64, 0x65, - 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x32, - 0x96, 0x03, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x72, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, - 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8d, 0x01, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7a, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x25, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x22, 0xce, 0x02, 0x0a, 0x10, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, + 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x64, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x62, 0x6c, 0x69, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x4c, 0x0a, 0x08, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x18, 0x0a, 0x14, 0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x45, 0x43, + 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, + 0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x54, 0x10, + 0x02, 0x22, 0x62, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x64, 0x65, 0x63, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x10, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x66, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, + 0x12, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x11, 0x64, 0x65, 0x63, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0xfa, 0x01, + 0x0a, 0x16, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x05, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, + 0x73, 0x63, 0x6f, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x1c, 0x77, 0x69, 0x74, 0x68, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x68, + 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, + 0x52, 0x1a, 0x77, 0x69, 0x74, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, + 0x69, 0x76, 0x65, 0x48, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x88, 0x01, 0x01, 0x42, + 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x42, 0x1f, 0x0a, 0x1d, 0x5f, 0x77, 0x69, + 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, + 0x5f, 0x68, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68, 0x79, 0x22, 0x63, 0x0a, 0x12, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x30, 0x0a, + 0x14, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x5f, 0x66, 0x71, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x71, 0x6e, 0x73, 0x22, + 0x7b, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x71, + 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x71, 0x6e, 0x73, 0x22, 0x60, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0xb2, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, - 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x12, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x41, 0x58, - 0x58, 0xaa, 0x02, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0xca, 0x02, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0xe2, 0x02, 0x19, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x52, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xc1, + 0x01, 0x0a, 0x14, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x2c, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, + 0x51, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x12, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x50, 0x0a, 0x11, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x10, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x22, 0x6d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4e, 0x0a, 0x12, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x11, + 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x73, 0x32, 0x96, 0x03, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x72, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x76, 0x31, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8d, + 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, + 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7a, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x25, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x42, 0xb2, 0x01, 0x0a, 0x11, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x42, 0x12, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x6f, 0x2f, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, + 0x41, 0x58, 0x58, 0xaa, 0x02, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x19, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1369,59 +1436,61 @@ func file_authorization_authorization_proto_rawDescGZIP() []byte { return file_authorization_authorization_proto_rawDescData } -var file_authorization_authorization_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_authorization_authorization_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_authorization_authorization_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_authorization_authorization_proto_goTypes = []interface{}{ - (DecisionResponse_Decision)(0), // 0: authorization.DecisionResponse.Decision - (*Token)(nil), // 1: authorization.Token - (*Entity)(nil), // 2: authorization.Entity - (*EntityCustom)(nil), // 3: authorization.EntityCustom - (*EntityChain)(nil), // 4: authorization.EntityChain - (*DecisionRequest)(nil), // 5: authorization.DecisionRequest - (*DecisionResponse)(nil), // 6: authorization.DecisionResponse - (*GetDecisionsRequest)(nil), // 7: authorization.GetDecisionsRequest - (*GetDecisionsResponse)(nil), // 8: authorization.GetDecisionsResponse - (*GetEntitlementsRequest)(nil), // 9: authorization.GetEntitlementsRequest - (*EntityEntitlements)(nil), // 10: authorization.EntityEntitlements - (*ResourceAttribute)(nil), // 11: authorization.ResourceAttribute - (*GetEntitlementsResponse)(nil), // 12: authorization.GetEntitlementsResponse - (*TokenDecisionRequest)(nil), // 13: authorization.TokenDecisionRequest - (*GetDecisionsByTokenRequest)(nil), // 14: authorization.GetDecisionsByTokenRequest - (*GetDecisionsByTokenResponse)(nil), // 15: authorization.GetDecisionsByTokenResponse - (*anypb.Any)(nil), // 16: google.protobuf.Any - (*policy.Action)(nil), // 17: policy.Action + (Entity_Category)(0), // 0: authorization.Entity.Category + (DecisionResponse_Decision)(0), // 1: authorization.DecisionResponse.Decision + (*Token)(nil), // 2: authorization.Token + (*Entity)(nil), // 3: authorization.Entity + (*EntityCustom)(nil), // 4: authorization.EntityCustom + (*EntityChain)(nil), // 5: authorization.EntityChain + (*DecisionRequest)(nil), // 6: authorization.DecisionRequest + (*DecisionResponse)(nil), // 7: authorization.DecisionResponse + (*GetDecisionsRequest)(nil), // 8: authorization.GetDecisionsRequest + (*GetDecisionsResponse)(nil), // 9: authorization.GetDecisionsResponse + (*GetEntitlementsRequest)(nil), // 10: authorization.GetEntitlementsRequest + (*EntityEntitlements)(nil), // 11: authorization.EntityEntitlements + (*ResourceAttribute)(nil), // 12: authorization.ResourceAttribute + (*GetEntitlementsResponse)(nil), // 13: authorization.GetEntitlementsResponse + (*TokenDecisionRequest)(nil), // 14: authorization.TokenDecisionRequest + (*GetDecisionsByTokenRequest)(nil), // 15: authorization.GetDecisionsByTokenRequest + (*GetDecisionsByTokenResponse)(nil), // 16: authorization.GetDecisionsByTokenResponse + (*anypb.Any)(nil), // 17: google.protobuf.Any + (*policy.Action)(nil), // 18: policy.Action } var file_authorization_authorization_proto_depIdxs = []int32{ - 16, // 0: authorization.Entity.claims:type_name -> google.protobuf.Any - 3, // 1: authorization.Entity.custom:type_name -> authorization.EntityCustom - 16, // 2: authorization.EntityCustom.extension:type_name -> google.protobuf.Any - 2, // 3: authorization.EntityChain.entities:type_name -> authorization.Entity - 17, // 4: authorization.DecisionRequest.actions:type_name -> policy.Action - 4, // 5: authorization.DecisionRequest.entity_chains:type_name -> authorization.EntityChain - 11, // 6: authorization.DecisionRequest.resource_attributes:type_name -> authorization.ResourceAttribute - 17, // 7: authorization.DecisionResponse.action:type_name -> policy.Action - 0, // 8: authorization.DecisionResponse.decision:type_name -> authorization.DecisionResponse.Decision - 5, // 9: authorization.GetDecisionsRequest.decision_requests:type_name -> authorization.DecisionRequest - 6, // 10: authorization.GetDecisionsResponse.decision_responses:type_name -> authorization.DecisionResponse - 2, // 11: authorization.GetEntitlementsRequest.entities:type_name -> authorization.Entity - 11, // 12: authorization.GetEntitlementsRequest.scope:type_name -> authorization.ResourceAttribute - 10, // 13: authorization.GetEntitlementsResponse.entitlements:type_name -> authorization.EntityEntitlements - 17, // 14: authorization.TokenDecisionRequest.actions:type_name -> policy.Action - 1, // 15: authorization.TokenDecisionRequest.tokens:type_name -> authorization.Token - 11, // 16: authorization.TokenDecisionRequest.resource_attributes:type_name -> authorization.ResourceAttribute - 13, // 17: authorization.GetDecisionsByTokenRequest.decision_requests:type_name -> authorization.TokenDecisionRequest - 6, // 18: authorization.GetDecisionsByTokenResponse.decision_responses:type_name -> authorization.DecisionResponse - 7, // 19: authorization.AuthorizationService.GetDecisions:input_type -> authorization.GetDecisionsRequest - 14, // 20: authorization.AuthorizationService.GetDecisionsByToken:input_type -> authorization.GetDecisionsByTokenRequest - 9, // 21: authorization.AuthorizationService.GetEntitlements:input_type -> authorization.GetEntitlementsRequest - 8, // 22: authorization.AuthorizationService.GetDecisions:output_type -> authorization.GetDecisionsResponse - 15, // 23: authorization.AuthorizationService.GetDecisionsByToken:output_type -> authorization.GetDecisionsByTokenResponse - 12, // 24: authorization.AuthorizationService.GetEntitlements:output_type -> authorization.GetEntitlementsResponse - 22, // [22:25] is the sub-list for method output_type - 19, // [19:22] is the sub-list for method input_type - 19, // [19:19] is the sub-list for extension type_name - 19, // [19:19] is the sub-list for extension extendee - 0, // [0:19] is the sub-list for field type_name + 17, // 0: authorization.Entity.claims:type_name -> google.protobuf.Any + 4, // 1: authorization.Entity.custom:type_name -> authorization.EntityCustom + 0, // 2: authorization.Entity.category:type_name -> authorization.Entity.Category + 17, // 3: authorization.EntityCustom.extension:type_name -> google.protobuf.Any + 3, // 4: authorization.EntityChain.entities:type_name -> authorization.Entity + 18, // 5: authorization.DecisionRequest.actions:type_name -> policy.Action + 5, // 6: authorization.DecisionRequest.entity_chains:type_name -> authorization.EntityChain + 12, // 7: authorization.DecisionRequest.resource_attributes:type_name -> authorization.ResourceAttribute + 18, // 8: authorization.DecisionResponse.action:type_name -> policy.Action + 1, // 9: authorization.DecisionResponse.decision:type_name -> authorization.DecisionResponse.Decision + 6, // 10: authorization.GetDecisionsRequest.decision_requests:type_name -> authorization.DecisionRequest + 7, // 11: authorization.GetDecisionsResponse.decision_responses:type_name -> authorization.DecisionResponse + 3, // 12: authorization.GetEntitlementsRequest.entities:type_name -> authorization.Entity + 12, // 13: authorization.GetEntitlementsRequest.scope:type_name -> authorization.ResourceAttribute + 11, // 14: authorization.GetEntitlementsResponse.entitlements:type_name -> authorization.EntityEntitlements + 18, // 15: authorization.TokenDecisionRequest.actions:type_name -> policy.Action + 2, // 16: authorization.TokenDecisionRequest.tokens:type_name -> authorization.Token + 12, // 17: authorization.TokenDecisionRequest.resource_attributes:type_name -> authorization.ResourceAttribute + 14, // 18: authorization.GetDecisionsByTokenRequest.decision_requests:type_name -> authorization.TokenDecisionRequest + 7, // 19: authorization.GetDecisionsByTokenResponse.decision_responses:type_name -> authorization.DecisionResponse + 8, // 20: authorization.AuthorizationService.GetDecisions:input_type -> authorization.GetDecisionsRequest + 15, // 21: authorization.AuthorizationService.GetDecisionsByToken:input_type -> authorization.GetDecisionsByTokenRequest + 10, // 22: authorization.AuthorizationService.GetEntitlements:input_type -> authorization.GetEntitlementsRequest + 9, // 23: authorization.AuthorizationService.GetDecisions:output_type -> authorization.GetDecisionsResponse + 16, // 24: authorization.AuthorizationService.GetDecisionsByToken:output_type -> authorization.GetDecisionsByTokenResponse + 13, // 25: authorization.AuthorizationService.GetEntitlements:output_type -> authorization.GetEntitlementsResponse + 23, // [23:26] is the sub-list for method output_type + 20, // [20:23] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_authorization_authorization_proto_init() } @@ -1626,7 +1695,7 @@ func file_authorization_authorization_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_authorization_authorization_proto_rawDesc, - NumEnums: 1, + NumEnums: 2, NumMessages: 15, NumExtensions: 0, NumServices: 1, diff --git a/service/authorization/authorization.go b/service/authorization/authorization.go index f9a3fc4b07..5a4e99df4b 100644 --- a/service/authorization/authorization.go +++ b/service/authorization/authorization.go @@ -269,8 +269,13 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *authoriza auditECEntitlements := make([]audit.EntityChainEntitlement, 0) auditEntityDecisions := make([]audit.EntityDecision, 0) - entityAttrValues := make(map[string][]string) + // Entitlements for environment entites in chain + envEntityAttrValues := make(map[string][]string) + // Entitlements for sbuject entities in chain + subjectEntityAttrValues := make(map[string][]string) + + //nolint:nestif // handle empty entity / attr list if len(entities) == 0 || len(allPertinentFqnsRA.GetAttributeValueFqns()) == 0 { as.logger.WarnContext(ctx, "Empty entity list and/or entity data attribute list") } else { @@ -282,12 +287,23 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *authoriza // TODO this might cause errors if multiple entities dont have ids // currently just adding each entity returned to same list - for _, e := range ecEntitlements.GetEntitlements() { + for idx, e := range ecEntitlements.GetEntitlements() { + entityID := e.GetEntityId() + if entityID == "" { + entityID = EntityIDPrefix + fmt.Sprint(idx) + } auditECEntitlements = append(auditECEntitlements, audit.EntityChainEntitlement{ - EntityID: e.GetEntityId(), + EntityID: entityID, AttributeValueReferences: e.GetAttributeValueFqns(), }) - entityAttrValues[e.GetEntityId()] = e.GetAttributeValueFqns() + entityCategory := entities[idx].GetCategory() + + // If entity type unspecified, include in access decision to err on the side of caution + if entityCategory == authorization.Entity_CATEGORY_SUBJECT || entityCategory == authorization.Entity_CATEGORY_UNSPECIFIED { + subjectEntityAttrValues[entityID] = e.GetAttributeValueFqns() + } else { + envEntityAttrValues[entityID] = e.GetAttributeValueFqns() + } } } @@ -296,7 +312,7 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *authoriza decisions, err := accessPDP.DetermineAccess( ctx, attrVals, - entityAttrValues, + subjectEntityAttrValues, attrDefs, ) if err != nil { @@ -314,7 +330,7 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *authoriza } // Add entity decision to audit list - entityEntitlementFqns := entityAttrValues[entityID] + entityEntitlementFqns := subjectEntityAttrValues[entityID] if entityEntitlementFqns == nil { entityEntitlementFqns = []string{} } diff --git a/service/authorization/authorization.proto b/service/authorization/authorization.proto index 596fbaf0a7..2bb0d24fbe 100644 --- a/service/authorization/authorization.proto +++ b/service/authorization/authorization.proto @@ -18,6 +18,7 @@ message Entity { string id = 1; // ephemeral id for tracking between request and response // Standard entity types supported by the platform oneof entity_type { + // one of the entity options must be set string email_address = 2; string user_name = 3; string remote_claims_url = 4; @@ -26,6 +27,12 @@ message Entity { EntityCustom custom = 7; string client_id = 8; } + enum Category { + CATEGORY_UNSPECIFIED = 0; + CATEGORY_SUBJECT = 1; + CATEGORY_ENVIRONMENT = 2; + } + Category category = 9; } // Entity type for custom entities beyond the standard types diff --git a/service/authorization/authorization_test.go b/service/authorization/authorization_test.go index 31c2b168a4..f6b82d385f 100644 --- a/service/authorization/authorization_test.go +++ b/service/authorization/authorization_test.go @@ -203,7 +203,7 @@ func Test_GetDecisionsAllOf_Pass(t *testing.T) { { Id: "ec1", Entities: []*authorization.Entity{ - {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}}, + {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, }, }, }, @@ -236,7 +236,7 @@ func Test_GetDecisionsAllOf_Pass(t *testing.T) { { Id: "ec1", Entities: []*authorization.Entity{ - {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}}, + {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, }, }, }, @@ -250,7 +250,7 @@ func Test_GetDecisionsAllOf_Pass(t *testing.T) { { Id: "ec1", Entities: []*authorization.Entity{ - {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}}, + {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, }, }, }, @@ -343,7 +343,7 @@ func Test_GetDecisions_AllOf_Fail(t *testing.T) { { Id: "ec1", Entities: []*authorization.Entity{ - {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}}, + {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, }, }, }, @@ -388,6 +388,192 @@ func Test_GetDecisions_AllOf_Fail(t *testing.T) { assert.Equal(t, authorization.DecisionResponse_DECISION_DENY, resp.GetDecisionResponses()[0].GetDecision()) } +// Subject entitled and environment entity not entitled -- still pass +func Test_GetDecisionsAllOfWithEnvironmental_Pass(t *testing.T) { + logger := logger.CreateTestLogger() + + listAttributeResp = attr.ListAttributesResponse{} + + attrDef := policy.Attribute{ + Name: mockAttrName, + Namespace: &policy.Namespace{ + Name: mockNamespace, + }, + Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF, + Values: []*policy.Value{ + { + Value: mockAttrValue1, + }, + }, + } + getAttributesByValueFqnsResponse = attr.GetAttributeValuesByFqnsResponse{FqnAttributeValues: map[string]*attr.GetAttributeValuesByFqnsResponse_AttributeAndValue{ + "https://www.example.org/attr/foo/value/value1": { + Attribute: &attrDef, + Value: &policy.Value{ + Fqn: mockFqn1, + }, + }, + }} + userRepresentation := map[string]interface{}{ + "A": "B", + "C": "D", + } + userStruct, _ := structpb.NewStruct(userRepresentation) + resolveEntitiesResp = entityresolution.ResolveEntitiesResponse{ + EntityRepresentations: []*entityresolution.EntityRepresentation{{ + OriginalId: "e1", + AdditionalProps: []*structpb.Struct{ + userStruct, + }, + }, + }, + } + + testTokenSource := oauth2.StaticTokenSource(&oauth2.Token{ + AccessToken: "AccessToken", + Expiry: time.Now().Add(1 * time.Hour), + }) + + ctxb := context.Background() + + testrego := rego.New( + rego.Query("data.example.p"), + rego.Module("example.rego", + `package example + p = {"e2":["https://www.example.org/attr/foo/value/value1"], "e1":[]} { true }`, + )) + + // Run evaluation. + prepared, err := testrego.PrepareForEval(ctxb) + require.NoError(t, err) + + // set the request + req := authorization.GetDecisionsRequest{DecisionRequests: []*authorization.DecisionRequest{ + { + Actions: []*policy.Action{}, + EntityChains: []*authorization.EntityChain{ + { + Id: "ec1", + Entities: []*authorization.Entity{ + {Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "opentdf"}, Category: authorization.Entity_CATEGORY_ENVIRONMENT}, + {Id: "e2", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, + }, + }, + }, + ResourceAttributes: []*authorization.ResourceAttribute{ + {AttributeValueFqns: []string{mockFqn1}}, + }, + }, + }} + + as := AuthorizationService{logger: logger, sdk: &otdf.SDK{ + Attributes: &myAttributesClient{}, EntityResoution: &myERSClient{}}, + tokenSource: &testTokenSource, eval: prepared} + + resp, err := as.GetDecisions(ctxb, &req) + + require.NoError(t, err) + assert.NotNil(t, resp) + + // one entitlement, one attribute value throughout + slog.Debug(resp.String()) + assert.Len(t, resp.GetDecisionResponses(), 1) + assert.Equal(t, authorization.DecisionResponse_DECISION_PERMIT, resp.GetDecisionResponses()[0].GetDecision()) +} + +// Subject not entitled and environment entity entitled -- still fail +func Test_GetDecisionsAllOfWithEnvironmental_Fail(t *testing.T) { + logger := logger.CreateTestLogger() + + listAttributeResp = attr.ListAttributesResponse{} + + attrDef := policy.Attribute{ + Name: mockAttrName, + Namespace: &policy.Namespace{ + Name: mockNamespace, + }, + Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF, + Values: []*policy.Value{ + { + Value: mockAttrValue1, + }, + }, + } + getAttributesByValueFqnsResponse = attr.GetAttributeValuesByFqnsResponse{FqnAttributeValues: map[string]*attr.GetAttributeValuesByFqnsResponse_AttributeAndValue{ + "https://www.example.org/attr/foo/value/value1": { + Attribute: &attrDef, + Value: &policy.Value{ + Fqn: mockFqn1, + }, + }, + }} + userRepresentation := map[string]interface{}{ + "A": "B", + "C": "D", + } + userStruct, _ := structpb.NewStruct(userRepresentation) + resolveEntitiesResp = entityresolution.ResolveEntitiesResponse{ + EntityRepresentations: []*entityresolution.EntityRepresentation{{ + OriginalId: "e1", + AdditionalProps: []*structpb.Struct{ + userStruct, + }, + }, + }, + } + + testTokenSource := oauth2.StaticTokenSource(&oauth2.Token{ + AccessToken: "AccessToken", + Expiry: time.Now().Add(1 * time.Hour), + }) + + ctxb := context.Background() + + testrego := rego.New( + rego.Query("data.example.p"), + rego.Module("example.rego", + `package example + p = {"e2":["https://www.example.org/attr/foo/value/value1"], "e1":[]} { true }`, + )) + + // Run evaluation. + prepared, err := testrego.PrepareForEval(ctxb) + require.NoError(t, err) + + // set the request + req := authorization.GetDecisionsRequest{DecisionRequests: []*authorization.DecisionRequest{ + { + Actions: []*policy.Action{}, + EntityChains: []*authorization.EntityChain{ + { + Id: "ec1", + Entities: []*authorization.Entity{ + {Id: "e2", EntityType: &authorization.Entity_ClientId{ClientId: "opentdf"}, Category: authorization.Entity_CATEGORY_ENVIRONMENT}, + {Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "bob.smith"}, Category: authorization.Entity_CATEGORY_SUBJECT}, + }, + }, + }, + ResourceAttributes: []*authorization.ResourceAttribute{ + {AttributeValueFqns: []string{mockFqn1}}, + }, + }, + }} + + as := AuthorizationService{logger: logger, sdk: &otdf.SDK{ + Attributes: &myAttributesClient{}, EntityResoution: &myERSClient{}}, + tokenSource: &testTokenSource, eval: prepared} + + resp, err := as.GetDecisions(ctxb, &req) + + require.NoError(t, err) + assert.NotNil(t, resp) + + // one entitlement, one attribute value throughout + slog.Debug(resp.String()) + assert.Len(t, resp.GetDecisionResponses(), 1) + assert.Equal(t, authorization.DecisionResponse_DECISION_DENY, resp.GetDecisionResponses()[0].GetDecision()) +} + func Test_GetEntitlementsSimple(t *testing.T) { logger := logger.CreateTestLogger() @@ -452,7 +638,7 @@ func Test_GetEntitlementsSimple(t *testing.T) { tokenSource: &testTokenSource, eval: prepared} req := authorization.GetEntitlementsRequest{ - Entities: []*authorization.Entity{{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "testclient"}}}, + Entities: []*authorization.Entity{{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "testclient"}, Category: authorization.Entity_CATEGORY_ENVIRONMENT}}, Scope: &authorization.ResourceAttribute{AttributeValueFqns: []string{"https://www.example.org/attr/foo/value/value1"}}, } @@ -531,7 +717,7 @@ func Test_GetEntitlementsWithComprehensiveHierarchy(t *testing.T) { withHierarchy := true req := authorization.GetEntitlementsRequest{ - Entities: []*authorization.Entity{{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "testclient"}}}, + Entities: []*authorization.Entity{{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "testclient"}, Category: authorization.Entity_CATEGORY_ENVIRONMENT}}, Scope: &authorization.ResourceAttribute{AttributeValueFqns: []string{"https://www.example.org/attr/foo/value/value1"}}, WithComprehensiveHierarchy: &withHierarchy, } diff --git a/service/entityresolution/keycloak/keycloak_entity_resolution.go b/service/entityresolution/keycloak/keycloak_entity_resolution.go index d91636d051..60935fb3ec 100644 --- a/service/entityresolution/keycloak/keycloak_entity_resolution.go +++ b/service/entityresolution/keycloak/keycloak_entity_resolution.go @@ -25,7 +25,6 @@ const ErrTextNotFound = "resource not found" const ClientJwtSelector = "azp" const UsernameJwtSelector = "preferred_username" -const UsernameConditionalSelector = "client_id" const serviceAccountUsernamePrefix = "service-account-" @@ -357,38 +356,44 @@ func getEntitiesFromToken(ctx context.Context, kcConfig KeycloakConfig, jwtStrin if !okCast { return nil, errors.New("error casting extracted value to string") } - entities = append(entities, &authorization.Entity{EntityType: &authorization.Entity_ClientId{ClientId: extractedValueCasted}, Id: fmt.Sprintf("jwtentity-%d", entityID)}) + entities = append(entities, &authorization.Entity{ + EntityType: &authorization.Entity_ClientId{ClientId: extractedValueCasted}, + Id: fmt.Sprintf("jwtentity-%d", entityID), + Category: authorization.Entity_CATEGORY_ENVIRONMENT}) entityID++ - // extract preferred_username if client isnt present - _, okExtractConditional := claims[UsernameConditionalSelector] - if !okExtractConditional { //nolint:nestif // this case has many possible outcomes to handle - extractedValueUsername, okExp := claims[UsernameJwtSelector] - if !okExp { - return nil, errors.New("error extracting selector " + UsernameJwtSelector + " from jwt") - } - extractedValueUsernameCasted, okUsernameCast := extractedValueUsername.(string) - if !okUsernameCast { - return nil, errors.New("error casting extracted value to string") - } + extractedValueUsername, okExp := claims[UsernameJwtSelector] + if !okExp { + return nil, errors.New("error extracting selector " + UsernameJwtSelector + " from jwt") + } + extractedValueUsernameCasted, okUsernameCast := extractedValueUsername.(string) + if !okUsernameCast { + return nil, errors.New("error casting extracted value to string") + } - // double check for service account - if strings.HasPrefix(extractedValueUsernameCasted, serviceAccountUsernamePrefix) { - clientid, err := getServiceAccountClient(ctx, extractedValueUsernameCasted, kcConfig, logger) - if err != nil { - return nil, err - } - if clientid != "" { - entities = append(entities, &authorization.Entity{EntityType: &authorization.Entity_ClientId{ClientId: clientid}, Id: fmt.Sprintf("jwtentity-%d", entityID)}) - } else { - // if the returned clientId is empty, no client found, its not a serive account proceed with username - entities = append(entities, &authorization.Entity{EntityType: &authorization.Entity_UserName{UserName: extractedValueUsernameCasted}, Id: fmt.Sprintf("jwtentity-%d", entityID)}) - } + // double check for service account + if strings.HasPrefix(extractedValueUsernameCasted, serviceAccountUsernamePrefix) { + clientid, err := getServiceAccountClient(ctx, extractedValueUsernameCasted, kcConfig, logger) + if err != nil { + return nil, err + } + if clientid != "" { + entities = append(entities, &authorization.Entity{ + EntityType: &authorization.Entity_ClientId{ClientId: clientid}, + Id: fmt.Sprintf("jwtentity-%d", entityID), + Category: authorization.Entity_CATEGORY_SUBJECT}) } else { - entities = append(entities, &authorization.Entity{EntityType: &authorization.Entity_UserName{UserName: extractedValueUsernameCasted}, Id: fmt.Sprintf("jwtentity-%d", entityID)}) + // if the returned clientId is empty, no client found, its not a serive account proceed with username + entities = append(entities, &authorization.Entity{ + EntityType: &authorization.Entity_UserName{UserName: extractedValueUsernameCasted}, + Id: fmt.Sprintf("jwtentity-%d", entityID), + Category: authorization.Entity_CATEGORY_SUBJECT}) } } else { - logger.Debug("Did not find conditional value " + UsernameConditionalSelector + " in jwt, proceed") + entities = append(entities, &authorization.Entity{ + EntityType: &authorization.Entity_UserName{UserName: extractedValueUsernameCasted}, + Id: fmt.Sprintf("jwtentity-%d", entityID), + Category: authorization.Entity_CATEGORY_SUBJECT}) } return entities, nil diff --git a/service/entityresolution/keycloak/keycloak_entity_resolution_test.go b/service/entityresolution/keycloak/keycloak_entity_resolution_test.go index e0cf1e40cc..4024e8cb44 100644 --- a/service/entityresolution/keycloak/keycloak_entity_resolution_test.go +++ b/service/entityresolution/keycloak/keycloak_entity_resolution_test.go @@ -56,6 +56,10 @@ const byClientIDOpentdfSdkResp = `[ {"id": "opentdfsdkclient", "clientId":"opentdf-sdk"} ] ` +const byClientIDTDFEntityResResp = `[ +{"id": "tdf-entity-resolution", "clientId":"tdf-entity-resolution"} +] +` const clientCredentialsJwt = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0OXRmSjByRUo4c0YzUjJ3Yi05eENHVXhYUEQ4RTZldmNsRG1hZ05EM3lBIn0.eyJleHAiOjE3MTUwOTE2MDQsImlhdCI6MTcxNTA5MTMwNCwianRpIjoiMTE3MTYzMjYtNWQyNS00MjlmLWFjMDItNmU0MjE2OWFjMGJhIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4ODg4L2F1dGgvcmVhbG1zL29wZW50ZGYiLCJhdWQiOlsiaHR0cDovL2xvY2FsaG9zdDo4ODg4IiwicmVhbG0tbWFuYWdlbWVudCIsImFjY291bnQiXSwic3ViIjoiOTljOWVlZDItOTM1Ni00ZjE2LWIwODQtZTgyZDczZjViN2QyIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGRmLWVudGl0eS1yZXNvbHV0aW9uIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLW9wZW50ZGYiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJ2aWV3LXVzZXJzIiwidmlldy1jbGllbnRzIiwicXVlcnktY2xpZW50cyIsInF1ZXJ5LWdyb3VwcyIsInF1ZXJ5LXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudEhvc3QiOiIxOTIuMTY4LjI0MC4xIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LXRkZi1lbnRpdHktcmVzb2x1dGlvbiIsImNsaWVudEFkZHJlc3MiOiIxOTIuMTY4LjI0MC4xIiwiY2xpZW50X2lkIjoidGRmLWVudGl0eS1yZXNvbHV0aW9uIn0.h29QLo-QvIc67KKqU_e1-x6G_o5YQccOyW9AthMdB7xhn9C1dBrcScytaWq1RfETPmnM8MXGezqN4OpXrYr-zbkHhq9ha0Ib-M1VJXNgA5sbgKW9JxGQyudmYPgn4fimDCJtAsXo7C-e3mYNm6DJS0zhGQ3msmjLTcHmIPzWlj7VjtPgKhYV75b7yr_yZNBdHjf3EZqfynU2sL8bKa1w7DYDNQve7ThtD4MeKLiuOQHa3_23dECs_ptvPVks7pLGgRKfgGHBC-KQuopjtxIhwkz2vOWRzugDl0aBJMHfwBajYhgZ2YRlV9dqSxmy8BOj4OEXuHbiyfIpY0rCRpSrGg" const passwordPubClientJwt = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0OXRmSjByRUo4c0YzUjJ3Yi05eENHVXhYUEQ4RTZldmNsRG1hZ05EM3lBIn0.eyJleHAiOjE3MTUwOTE0ODAsImlhdCI6MTcxNTA5MTE4MCwianRpIjoiZmI5MmM2MTAtYmI0OC00ZDgyLTljZGQtOWFhZjllNzEyNzc3IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4ODg4L2F1dGgvcmVhbG1zL29wZW50ZGYiLCJhdWQiOlsiaHR0cDovL2xvY2FsaG9zdDo4ODg4IiwidGRmLWVudGl0eS1yZXNvbHV0aW9uIiwicmVhbG0tbWFuYWdlbWVudCIsImFjY291bnQiXSwic3ViIjoiMmU2YzE1ODAtY2ZkMy00M2FiLWIxNzMtZjZjM2JmOGZmNGUyIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGRmLWVudGl0eS1yZXNvbHV0aW9uLXB1YmxpYyIsInNlc3Npb25fc3RhdGUiOiIzN2E3YjdiOS0xZmNlLTQxMmYtOTI1OS1lYzUxMTY3MGVhMGYiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIi8qIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvcGVudGRmLW9yZy1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BlbnRkZiIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJ0ZGYtZW50aXR5LXJlc29sdXRpb24iOnsicm9sZXMiOlsiZW50aXR5LXJlc29sdXRpb24tdGVzdC1yb2xlIl19LCJyZWFsbS1tYW5hZ2VtZW50Ijp7InJvbGVzIjpbInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJxdWVyeS1jbGllbnRzIiwicXVlcnktZ3JvdXBzIiwicXVlcnktdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6IjM3YTdiN2I5LTFmY2UtNDEyZi05MjU5LWVjNTExNjcwZWEwZiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6InNhbXBsZSB1c2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2FtcGxlLXVzZXIiLCJnaXZlbl9uYW1lIjoic2FtcGxlIiwiZmFtaWx5X25hbWUiOiJ1c2VyIiwiZW1haWwiOiJzYW1wbGV1c2VyQHNhbXBsZS5jb20ifQ.Gd_OvPNY7UfY7sBKh55TcvWQHmAkYZ2Jb2VyK1lYgse9EBEa_y3uoepZYrGMGkmYdwApg4eauQjxzT_BZYVBc7u9ch3HY_IUuSh3A6FkDDXZIziByP63FYiI4vKTp0w7e2-oYAdaUTDJ1Y50-l_VvRWjdc4fqi-OKH4t8D1rlq0GJ-P7uOl44Ta43YdBMuXI146-eLqx_zLIC49Pg5Y7MD_Lv23QfGTHTP47ckUQueXoGegNLQNE9nPTuD6lNzHD5_MOqse4IKzoWVs_hs4S8SqVxVlN_ZWXkcGhPllfQtf1qxLyFm51eYH3LGxqyNbGr4nQc8djPV0yWqOTrg8IYQ" @@ -303,7 +307,10 @@ func Test_KCEntityResolutionNotFoundError(t *testing.T) { } func Test_JwtClientAndUsernameClientCredentials(t *testing.T) { - server := testServer(t, nil, nil, nil, nil, nil) + csqr := map[string]string{ + "clientId=tdf-entity-resolution": byClientIDTDFEntityResResp, + } + server := testServer(t, nil, nil, nil, nil, csqr) defer server.Close() var kcconfig = testKeycloakConfig(server) @@ -317,8 +324,11 @@ func Test_JwtClientAndUsernameClientCredentials(t *testing.T) { require.NoError(t, reserr) assert.Len(t, resp.GetEntityChains(), 1) - assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 1) + assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) + assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[0].GetEntities()[1].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernamePasswordPub(t *testing.T) { @@ -338,7 +348,9 @@ func Test_JwtClientAndUsernamePasswordPub(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution-public", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernamePasswordPriv(t *testing.T) { @@ -358,7 +370,9 @@ func Test_JwtClientAndUsernamePasswordPriv(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernameAuthPub(t *testing.T) { @@ -378,7 +392,9 @@ func Test_JwtClientAndUsernameAuthPub(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution-public", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernameAuthPriv(t *testing.T) { @@ -398,7 +414,9 @@ func Test_JwtClientAndUsernameAuthPriv(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernameImplicitPub(t *testing.T) { @@ -418,7 +436,9 @@ func Test_JwtClientAndUsernameImplicitPub(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution-public", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndUsernameImplicitPriv(t *testing.T) { @@ -438,7 +458,9 @@ func Test_JwtClientAndUsernameImplicitPriv(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[0].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtClientAndClientTokenExchange(t *testing.T) { @@ -461,7 +483,9 @@ func Test_JwtClientAndClientTokenExchange(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 1) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "opentdf", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "opentdf-sdk", resp.GetEntityChains()[0].GetEntities()[1].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) } func Test_JwtMultiple(t *testing.T) { @@ -484,11 +508,15 @@ func Test_JwtMultiple(t *testing.T) { assert.Len(t, resp.GetEntityChains(), 2) assert.Len(t, resp.GetEntityChains()[0].GetEntities(), 2) assert.Equal(t, "opentdf", resp.GetEntityChains()[0].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[0].GetEntities()[0].GetCategory()) assert.Equal(t, "opentdf-sdk", resp.GetEntityChains()[0].GetEntities()[1].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[0].GetEntities()[1].GetCategory()) assert.Len(t, resp.GetEntityChains()[1].GetEntities(), 2) assert.Equal(t, "tdf-entity-resolution", resp.GetEntityChains()[1].GetEntities()[0].GetClientId()) + assert.Equal(t, authorization.Entity_CATEGORY_ENVIRONMENT, resp.GetEntityChains()[1].GetEntities()[0].GetCategory()) assert.Equal(t, "sample-user", resp.GetEntityChains()[1].GetEntities()[1].GetUserName()) + assert.Equal(t, authorization.Entity_CATEGORY_SUBJECT, resp.GetEntityChains()[1].GetEntities()[1].GetCategory()) } func Test_KCEntityResolutionNotFoundInferEmail(t *testing.T) {