diff --git a/api/principal.proto b/api/principal.proto index 0f989cc..2be84ed 100644 --- a/api/principal.proto +++ b/api/principal.proto @@ -55,15 +55,28 @@ message Principal { bytes claims = 4 [ (capabilities.field_rule) = { message: "must have pii access" - and: { - rule: {direction: RESPONSE} - rule: {may: { - capabilities: {pii: true} - scope: {on_principal: {field: 1}} - }} + or : { + rule: { + and: { + rule: {direction: REQUEST} + rule : {auth_status: SUPER} + } + } + rule: { + and: { + rule: {direction: RESPONSE} + rule: {may: { + capabilities: {pii: true} + scope: {on_principal: {field: 1}} + }} + } + } } } ]; + // If present, indicates that the principal represents all users whose + // email address are in the given domain. + string email_domain = 5; string refresh_token = 66 [ (capabilities.field_rule).never = true ]; @@ -81,6 +94,8 @@ message LoadRequest { ID ID = 1; // Load a Principal by email address. string email = 2; + // Load a domain-level Principal. + string email_domain = 3; } } diff --git a/api/principal/principal.pb.go b/api/principal/principal.pb.go index 3ecbfd8..017b85b 100644 --- a/api/principal/principal.pb.go +++ b/api/principal/principal.pb.go @@ -157,7 +157,10 @@ type Principal struct { Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` // OIDC claims as provided by an authentication server. - Claims []byte `protobuf:"bytes,4,opt,name=claims,proto3" json:"claims,omitempty"` + Claims []byte `protobuf:"bytes,4,opt,name=claims,proto3" json:"claims,omitempty"` + // If present, indicates that the principal represents all users whose + // email address are in the given domain. + EmailDomain string `protobuf:"bytes,5,opt,name=email_domain,json=emailDomain,proto3" json:"email_domain,omitempty"` RefreshToken string `protobuf:"bytes,66,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"` RefreshAfter *timestamppb.Timestamp `protobuf:"bytes,67,opt,name=refresh_after,json=refreshAfter,proto3" json:"refresh_after,omitempty"` RefreshStatus TokenStatus `protobuf:"varint,68,opt,name=refresh_status,json=refreshStatus,proto3,enum=cacheroach.principal.TokenStatus" json:"refresh_status,omitempty"` @@ -223,6 +226,13 @@ func (x *Principal) GetClaims() []byte { return nil } +func (x *Principal) GetEmailDomain() string { + if x != nil { + return x.EmailDomain + } + return "" +} + func (x *Principal) GetRefreshToken() string { if x != nil { return x.RefreshToken @@ -252,6 +262,7 @@ type LoadRequest struct { // Types that are assignable to Kind: // *LoadRequest_ID // *LoadRequest_Email + // *LoadRequest_EmailDomain Kind isLoadRequest_Kind `protobuf_oneof:"Kind"` } @@ -308,6 +319,13 @@ func (x *LoadRequest) GetEmail() string { return "" } +func (x *LoadRequest) GetEmailDomain() string { + if x, ok := x.GetKind().(*LoadRequest_EmailDomain); ok { + return x.EmailDomain + } + return "" +} + type isLoadRequest_Kind interface { isLoadRequest_Kind() } @@ -322,10 +340,17 @@ type LoadRequest_Email struct { Email string `protobuf:"bytes,2,opt,name=email,proto3,oneof"` } +type LoadRequest_EmailDomain struct { + // Load a domain-level Principal. + EmailDomain string `protobuf:"bytes,3,opt,name=email_domain,json=emailDomain,proto3,oneof"` +} + func (*LoadRequest_ID) isLoadRequest_Kind() {} func (*LoadRequest_Email) isLoadRequest_Kind() {} +func (*LoadRequest_EmailDomain) isLoadRequest_Kind() {} + type WatchRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -497,7 +522,7 @@ var file_principal_proto_rawDesc = []byte{ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x18, 0x0a, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x22, 0xb3, 0x03, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, + 0x61, 0x74, 0x61, 0x22, 0xd6, 0x03, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x28, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x6c, @@ -508,78 +533,83 @@ var file_principal_proto_rawDesc = []byte{ 0x2a, 0x22, 0x12, 0x0a, 0x02, 0x40, 0x02, 0x0a, 0x0c, 0x3a, 0x0a, 0x12, 0x02, 0x20, 0x01, 0x22, 0x04, 0x12, 0x02, 0x10, 0x01, 0x7a, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x70, 0x69, 0x69, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x06, 0x63, 0x6c, 0x61, - 0x69, 0x6d, 0x73, 0x12, 0x2b, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x42, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0x9a, 0xf5, 0x1a, 0x02, - 0x18, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x47, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x61, 0x66, 0x74, 0x65, - 0x72, 0x18, 0x43, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x42, 0x06, 0x9a, 0xf5, 0x1a, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x66, - 0x72, 0x65, 0x73, 0x68, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x0e, 0x72, 0x65, 0x66, - 0x72, 0x65, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x44, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x21, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x42, 0x06, 0x9a, 0xf5, 0x1a, 0x02, 0x18, 0x01, 0x52, 0x0d, 0x72, 0x65, - 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3a, 0x3c, 0x9a, 0xf5, 0x1a, - 0x38, 0x2a, 0x36, 0x0a, 0x02, 0x40, 0x02, 0x0a, 0x30, 0x3a, 0x0a, 0x12, 0x02, 0x08, 0x01, 0x22, - 0x04, 0x12, 0x02, 0x10, 0x01, 0x7a, 0x22, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, - 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, 0x59, 0x0a, 0x0b, 0x4c, 0x6f, 0x61, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, - 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x49, 0x44, 0x48, 0x00, - 0x52, 0x02, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x06, 0x0a, 0x04, - 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x7d, 0x0a, 0x0c, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, + 0x69, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x64, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2b, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x42, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0x9a, + 0xf5, 0x1a, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x47, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x18, 0x43, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x06, 0x9a, 0xf5, 0x1a, 0x02, 0x18, 0x01, 0x52, 0x0c, + 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x0e, + 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x44, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, + 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x06, 0x9a, 0xf5, 0x1a, 0x02, 0x18, 0x01, 0x52, + 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3a, 0x3c, + 0x9a, 0xf5, 0x1a, 0x38, 0x2a, 0x36, 0x0a, 0x02, 0x40, 0x02, 0x0a, 0x30, 0x3a, 0x0a, 0x12, 0x02, + 0x08, 0x01, 0x22, 0x04, 0x12, 0x02, 0x10, 0x01, 0x7a, 0x22, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, 0x7e, 0x0a, 0x0b, + 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x02, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x49, - 0x44, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x08, - 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x0d, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, - 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, - 0x70, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0x4f, 0x0a, 0x0e, 0x45, - 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, - 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, - 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, - 0x6c, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2a, 0x4c, 0x0a, 0x0b, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x49, - 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x49, 0x4e, - 0x47, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x45, 0x52, 0x4d, 0x41, 0x4e, 0x45, 0x4e, 0x54, - 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x03, 0x32, 0xda, 0x02, 0x0a, 0x0a, 0x50, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x58, 0x0a, 0x06, 0x45, 0x6e, 0x73, - 0x75, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, - 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, - 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, - 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, - 0x90, 0x02, 0x02, 0x12, 0x46, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, - 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, - 0x69, 0x70, 0x61, 0x6c, 0x22, 0x03, 0x90, 0x02, 0x01, 0x30, 0x01, 0x12, 0x55, 0x0a, 0x04, 0x4c, - 0x6f, 0x61, 0x64, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, - 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, - 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, 0x72, - 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, 0x09, 0x90, 0x02, 0x01, 0x9a, 0xf5, 0x1a, 0x02, - 0x30, 0x00, 0x12, 0x53, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x22, 0x2e, 0x63, 0x61, - 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, - 0x61, 0x6c, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x44, 0x48, 0x00, 0x52, 0x02, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, + 0x23, 0x0a, 0x0c, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x7d, 0x0a, 0x0c, + 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x09, + 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, + 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x49, 0x44, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x61, 0x6c, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x0d, 0x45, + 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x09, + 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, - 0x22, 0x03, 0x90, 0x02, 0x01, 0x30, 0x01, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x62, 0x76, 0x61, 0x77, 0x74, 0x65, 0x72, 0x2f, - 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x22, 0x4f, 0x0a, 0x0e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, + 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, + 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x61, 0x6c, 0x2a, 0x4c, 0x0a, 0x0b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, + 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x50, + 0x45, 0x52, 0x4d, 0x41, 0x4e, 0x45, 0x4e, 0x54, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, + 0x10, 0x03, 0x32, 0xda, 0x02, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, + 0x73, 0x12, 0x58, 0x0a, 0x06, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x61, + 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, + 0x61, 0x6c, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x02, 0x12, 0x46, 0x0a, 0x04, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x63, 0x61, + 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, + 0x61, 0x6c, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, 0x03, 0x90, 0x02, + 0x01, 0x30, 0x01, 0x12, 0x55, 0x0a, 0x04, 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x21, 0x2e, 0x63, 0x61, + 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, + 0x61, 0x6c, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, + 0x09, 0x90, 0x02, 0x01, 0x9a, 0xf5, 0x1a, 0x02, 0x30, 0x00, 0x12, 0x53, 0x0a, 0x05, 0x57, 0x61, + 0x74, 0x63, 0x68, 0x12, 0x22, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, 0x63, 0x68, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, + 0x6f, 0x61, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x2e, 0x50, + 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x22, 0x03, 0x90, 0x02, 0x01, 0x30, 0x01, 0x42, + 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, + 0x62, 0x76, 0x61, 0x77, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x6f, 0x61, + 0x63, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -714,6 +744,7 @@ func file_principal_proto_init() { file_principal_proto_msgTypes[2].OneofWrappers = []interface{}{ (*LoadRequest_ID)(nil), (*LoadRequest_Email)(nil), + (*LoadRequest_EmailDomain)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/doc/cacheroach_bootstrap.md b/doc/cacheroach_bootstrap.md index 59e1d8a..aac1a85 100644 --- a/doc/cacheroach_bootstrap.md +++ b/doc/cacheroach_bootstrap.md @@ -7,7 +7,7 @@ create a super-user principal using the server's HMAC key This command should be used to create an initial user on a newly-created cacheroach installation. It requires access to the server's HMAC key that is used to sign tokens. The resulting session will have superuser access; the resulting configuration file should be treated with the same security as the key. ``` -cacheroach bootstrap [flags] https://username[:password]@cacheroach.server/ +cacheroach bootstrap [flags] https://cacheroach.server/ ``` ### Options diff --git a/doc/cacheroach_principal_create.md b/doc/cacheroach_principal_create.md index 9729106..d81842d 100644 --- a/doc/cacheroach_principal_create.md +++ b/doc/cacheroach_principal_create.md @@ -9,8 +9,9 @@ cacheroach principal create [flags] ### Options ``` - -h, --help help for create - -o, --out string write a new configuration file, defaults to username.cfg + --emailDomain string create a unique principal that represents all principals with an email address in the given domain + -h, --help help for create + -o, --out string write a new configuration file, defaults to username.cfg ``` ### Options inherited from parent commands diff --git a/pkg/cmd/cli/principal.go b/pkg/cmd/cli/principal.go index 3b96919..5b8795c 100644 --- a/pkg/cmd/cli/principal.go +++ b/pkg/cmd/cli/principal.go @@ -35,7 +35,7 @@ func (c *CLI) principal() *cobra.Command { Short: "principal management", } - var createOut string + var createDomain, createOut string create := &cobra.Command{ Use: "create ", Short: "create a principal", @@ -55,8 +55,9 @@ func (c *CLI) principal() *cobra.Command { } req := &principal.EnsureRequest{ Principal: &principal.Principal{ - ID: principal.NewID(), - Claims: claimBytes, + ID: principal.NewID(), + Claims: claimBytes, + EmailDomain: createDomain, }, } prn, err := principal.NewPrincipalsClient(conn).Ensure(cmd.Context(), req) @@ -96,6 +97,9 @@ func (c *CLI) principal() *cobra.Command { return nil }, } + create.Flags().StringVar(&createDomain, "emailDomain", "", + "create a unique principal that represents all principals with "+ + "an email address in the given domain") create.Flags().StringVarP(&createOut, "out", "o", "", "write a new configuration file, defaults to username.cfg") @@ -116,7 +120,7 @@ func (c *CLI) principal() *cobra.Command { } out := newTabs() defer out.Close() - out.Printf("ID\tVersion\tLabel\tClaims\n") + out.Printf("ID\tVersion\tLabel\tDomain\tClaims\n") for { p, err := data.Recv() if errors.Is(err, io.EOF) { @@ -124,7 +128,7 @@ func (c *CLI) principal() *cobra.Command { } else if err != nil { return err } - out.Printf("%s\t%d\t%s\t%s\n", p.ID.AsUUID(), p.Version, p.Label, p.Claims) + out.Printf("%s\t%d\t%s\t%s\t%s\n", p.ID.AsUUID(), p.Version, p.Label, p.EmailDomain, p.Claims) } return nil }, diff --git a/pkg/store/principal/principal.go b/pkg/store/principal/principal.go index 84999c9..1c9d155 100644 --- a/pkg/store/principal/principal.go +++ b/pkg/store/principal/principal.go @@ -26,7 +26,6 @@ import ( "github.com/google/wire" "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/pgxpool" - "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" @@ -84,8 +83,10 @@ func (s *Server) Ensure( defer tx.Rollback(ctx) row := tx.QueryRow(ctx, - "INSERT INTO principals (principal, refresh_after, refresh_status, refresh_token, claims, version) "+ - "VALUES ($1, $2, $3, $4, $5, 1) "+ + "INSERT INTO principals ( "+ + "principal, email_domain, refresh_after, refresh_status, refresh_token, "+ + "claims, version"+ + ") VALUES ($1, $2, $3, $4, $5, $6, 1) "+ "ON CONFLICT (principal) "+ "DO UPDATE SET (refresh_after, refresh_status, refresh_token, claims, version) = "+ "("+ @@ -95,7 +96,8 @@ func (s *Server) Ensure( " IFNULL (excluded.claims, principals.claims),"+ " principals.version + 1"+ ") RETURNING name, refresh_after, refresh_status, refresh_token, claims, version", - p.ID, p.RefreshAfter.AsTime(), p.RefreshStatus, p.RefreshToken, p.Claims) + p.ID, strings.ToLower(p.EmailDomain), p.RefreshAfter.AsTime(), + p.RefreshStatus, p.RefreshToken, p.Claims) var pendingVersion int64 var refreshAfter time.Time @@ -128,7 +130,7 @@ func (s *Server) List(_ *emptypb.Empty, out principal.Principals_ListServer) err defer tx.Rollback(ctx) rows, err := tx.Query(ctx, - "SELECT principal, name, claims, version "+ + "SELECT principal, email_domain, name, claims, version "+ "FROM principals") if err != nil { return err @@ -139,7 +141,7 @@ func (s *Server) List(_ *emptypb.Empty, out principal.Principals_ListServer) err for rows.Next() { p := &principal.Principal{ID: &principal.ID{}} - if err := rows.Scan(p.ID, &p.Label, &p.Claims, &p.Version); err != nil { + if err := rows.Scan(p.ID, &p.EmailDomain, &p.Label, &p.Claims, &p.Version); err != nil { return err } @@ -153,35 +155,36 @@ func (s *Server) List(_ *emptypb.Empty, out principal.Principals_ListServer) err // Load implements principal.PrincipalsServer. func (s *Server) Load(ctx context.Context, req *principal.LoadRequest) (*principal.Principal, error) { - var id *principal.ID + var col string + var val interface{} + switch t := req.Kind.(type) { case *principal.LoadRequest_Email: - id = &principal.ID{} - row := s.DB.QueryRow(ctx, "SELECT principal FROM principals WHERE email = $1", strings.ToLower(t.Email)) - if err := row.Scan(id); errors.Is(err, pgx.ErrNoRows) { - return nil, status.Error(codes.NotFound, t.Email) - } else if err != nil { - return nil, err - } + col = "email" + val = strings.ToLower(t.Email) case *principal.LoadRequest_ID: - id = t.ID + col = "principal" + val = t.ID + case *principal.LoadRequest_EmailDomain: + col = "email_domain" + val = strings.ToLower(t.EmailDomain) default: return nil, status.Error(codes.Unimplemented, "unknown kind") } - ret := &principal.Principal{ID: id} + ret := &principal.Principal{ID: &principal.ID{}} err := util.Retry(ctx, func(ctx context.Context) error { var refreshAfter time.Time row := s.DB.QueryRow(ctx, - "SELECT name, refresh_after, refresh_status, refresh_token, claims, version "+ - "FROM principals "+ - "WHERE principal = $1", id) - err := row.Scan(&ret.Label, &refreshAfter, &ret.RefreshStatus, &ret.RefreshToken, - &ret.Claims, &ret.Version) + "SELECT principal, name, email_domain, refresh_after, refresh_status, refresh_token, "+ + "claims, version "+ + "FROM principals WHERE "+col+" = $1", val) + err := row.Scan(ret.ID, &ret.Label, &ret.EmailDomain, &refreshAfter, &ret.RefreshStatus, + &ret.RefreshToken, &ret.Claims, &ret.Version) ret.RefreshAfter = timestamppb.New(refreshAfter) return err }) if err == pgx.ErrNoRows { - return nil, status.Error(codes.NotFound, id.AsUUID().String()) + return nil, status.Error(codes.NotFound, req.String()) } return ret, err } diff --git a/pkg/store/principal/principal_test.go b/pkg/store/principal/principal_test.go index 843152c..fb3eec7 100644 --- a/pkg/store/principal/principal_test.go +++ b/pkg/store/principal/principal_test.go @@ -145,4 +145,27 @@ func TestPrincipal(t *testing.T) { a.True(errors.Is(err, util.ErrVersionSkew)) }) + t.Run("domain", func(t *testing.T) { + a := assert.New(t) + resp, err := rig.p.Ensure(ctx, &EnsureRequest{ + Principal: &Principal{EmailDomain: "Example.COM"}}) + if !a.NoError(err) { + return + } + a.Equal(int64(1), resp.Principal.Version) + + found, err := rig.p.Load(ctx, &LoadRequest{ + Kind: &LoadRequest_EmailDomain{EmailDomain: "example.com"}}) + if !a.NoError(err) { + return + } + a.Equal(resp.Principal.ID.String(), found.ID.String()) + a.Equal("example.com", found.EmailDomain) + + _, err = rig.p.Ensure(ctx, &EnsureRequest{ + Principal: &Principal{EmailDomain: "example.com"}}) + if a.NotNil(err) { + a.Contains(err.Error(), "duplicate key value") + } + }) } diff --git a/pkg/store/schema/schema.go b/pkg/store/schema/schema.go index 1396608..e66223f 100644 --- a/pkg/store/schema/schema.go +++ b/pkg/store/schema/schema.go @@ -125,6 +125,9 @@ CREATE TABLE IF NOT EXISTS principals ( region STRING NOT NULL DEFAULT IFNULL(crdb_internal.locality_value('region'), 'global') CHECK (length(region)>0), principal UUID NOT NULL UNIQUE, + -- A principal may be created to delegate access to all users within a given email domain. + email_domain STRING NOT NULL DEFAULT '', + refresh_after TIMESTAMPTZ NOT NULL DEFAULT 0::TIMESTAMPTZ, -- The time at which the claims must be revalidated refresh_status INT8 NOT NULL DEFAULT 0, -- Refresh state enum refresh_token STRING NOT NULL DEFAULT '', -- OAuth2 refresh token to achieve revalidation @@ -137,6 +140,7 @@ CREATE TABLE IF NOT EXISTS principals ( version INT8 NOT NULL CHECK (version > 0), PRIMARY KEY (region, principal), + UNIQUE INDEX (email_domain) WHERE email_domain != '', UNIQUE INDEX (email) WHERE email != '' ) `, ` diff --git a/pkg/store/token/token.go b/pkg/store/token/token.go index eb110e5..96c6dab 100644 --- a/pkg/store/token/token.go +++ b/pkg/store/token/token.go @@ -106,11 +106,15 @@ func (s *Server) Find(scope *session.Scope, server token.Tokens_FindServer) erro s.cache.Remove(cacheKey) } return util.RetryLoop(ctx, func(ctx context.Context, sideEffect *util.Marker) error { - rows, err := s.db.Query(ctx, - "SELECT session, tenant, path, capabilities, expires_at, note, name, super "+ - "FROM sessions "+ - "WHERE principal = $1 AND expires_at > now()", - sn.PrincipalId) + rows, err := s.db.Query(ctx, ` +WITH + dom AS (SELECT substring(email, '@(.*)$') as email_domain FROM principals WHERE principal = $1 AND email != ''), + prns AS (SELECT principal FROM principals JOIN dom USING (email_domain) UNION SELECT $1::UUID) +SELECT session, tenant, path, capabilities, expires_at, note, name, super +FROM sessions +JOIN prns USING (principal) +WHERE expires_at > now() +`, sn.PrincipalId) if err != nil { return err } diff --git a/pkg/store/token/token_test.go b/pkg/store/token/token_test.go index e46a0ce..a2e512a 100644 --- a/pkg/store/token/token_test.go +++ b/pkg/store/token/token_test.go @@ -31,6 +31,101 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) +// Check that a domain-level principal implicitly delegates to +// other principals with the name email domain. +func TestDomainInheritance(t *testing.T) { + a := assert.New(t) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + rig, cleanup, err := testRig(ctx) + if !a.NoError(err) { + return + } + defer cleanup() + + tID := tenant.NewID() + _, err = rig.tenants.Ensure(ctx, &tenant.EnsureRequest{Tenant: &tenant.Tenant{ + Label: "Some Tenant", + ID: tID, + }}) + if !a.NoError(err) { + return + } + + pID := principal.NewID() + _, err = rig.principals.Ensure(ctx, &principal.EnsureRequest{ + Principal: &principal.Principal{ + ID: pID, + Claims: []byte(`{"email":"user@example.com"}`), + }}) + if !a.NoError(err) { + return + } + + principalSession, err := rig.tokens.Issue(ctx, &IssueRequest{Template: &session.Session{ + PrincipalId: pID, + ExpiresAt: timestamppb.New(time.Now().Add(time.Hour)), + Capabilities: capabilities.All(), + Scope: &session.Scope{Kind: &session.Scope_OnPrincipal{OnPrincipal: pID}}, + }}) + if !a.NoError(err) { + return + } + + domainID := principal.NewID() + _, err = rig.principals.Ensure(ctx, &principal.EnsureRequest{ + Principal: &principal.Principal{ + Label: "Domain Principal", + ID: domainID, + EmailDomain: "example.com", + }}) + if !a.NoError(err) { + return + } + + domainSession, err := rig.tokens.Issue(ctx, &IssueRequest{Template: &session.Session{ + PrincipalId: domainID, + ExpiresAt: timestamppb.New(time.Now().Add(time.Hour)), + Capabilities: capabilities.All(), + Scope: &session.Scope{ + Kind: &session.Scope_OnLocation{ + OnLocation: &session.Location{ + TenantId: tID, + Path: "/*", + }}}}}) + if !a.NoError(err) { + return + } + + { + sink := &sink{ctx: session.WithSession(ctx, principalSession.Issued)} + err = rig.tokens.Find(&session.Scope{}, sink) + if !a.NoError(err) { + return + } + a.Len(sink.ret, 2) + } + + // Ensure that the domain-level session can will be invalidated. + _, err = rig.tokens.Invalidate(session.WithSession(ctx, domainSession.Issued), + &InvalidateRequest{Kind: &InvalidateRequest_ID{ID: domainSession.Issued.ID}}) + if !a.NoError(err) { + return + } + + rig.tokens.cache.Purge() + + { + sink := &sink{ctx: session.WithSession(ctx, principalSession.Issued)} + err = rig.tokens.Find(&session.Scope{}, sink) + if !a.NoError(err) { + return + } + a.Len(sink.ret, 1) + } +} + func TestTokenFlow(t *testing.T) { a := assert.New(t) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) @@ -47,7 +142,9 @@ func TestTokenFlow(t *testing.T) { Label: "Some Tenant", ID: tID, }}) - a.NoError(err) + if !a.NoError(err) { + return + } pID := principal.NewID() p := &principal.Principal{ @@ -55,7 +152,9 @@ func TestTokenFlow(t *testing.T) { ID: pID, } _, err = rig.principals.Ensure(ctx, &principal.EnsureRequest{Principal: p}) - a.NoError(err) + if !a.NoError(err) { + return + } tcs := []*session.Session{ {