mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 07:14:46 +00:00
NOISSUE - Seperate PAT from policy (#3330)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com> Signed-off-by: Arvindh <arvindh91@gmail.com> Co-authored-by: Arvindh <arvindh91@gmail.com>
This commit is contained in:
+145
-37
@@ -147,11 +147,6 @@ type PolicyReq struct {
|
|||||||
Permission string `protobuf:"bytes,7,opt,name=permission,proto3" json:"permission,omitempty"`
|
Permission string `protobuf:"bytes,7,opt,name=permission,proto3" json:"permission,omitempty"`
|
||||||
Object string `protobuf:"bytes,8,opt,name=object,proto3" json:"object,omitempty"`
|
Object string `protobuf:"bytes,8,opt,name=object,proto3" json:"object,omitempty"`
|
||||||
ObjectType string `protobuf:"bytes,9,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"`
|
ObjectType string `protobuf:"bytes,9,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"`
|
||||||
PatId string `protobuf:"bytes,10,opt,name=pat_id,json=patId,proto3" json:"pat_id,omitempty"`
|
|
||||||
Operation string `protobuf:"bytes,11,opt,name=operation,proto3" json:"operation,omitempty"`
|
|
||||||
UserId string `protobuf:"bytes,12,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
|
||||||
EntityId string `protobuf:"bytes,13,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
|
||||||
EntityType string `protobuf:"bytes,14,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -249,41 +244,142 @@ func (x *PolicyReq) GetObjectType() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PolicyReq) GetPatId() string {
|
type PATReq struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
PatId string `protobuf:"bytes,1,opt,name=pat_id,json=patId,proto3" json:"pat_id,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
|
Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"`
|
||||||
|
UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||||
|
EntityId string `protobuf:"bytes,5,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
EntityType string `protobuf:"bytes,6,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PATReq) Reset() {
|
||||||
|
*x = PATReq{}
|
||||||
|
mi := &file_auth_v1_auth_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PATReq) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PATReq) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *PATReq) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_auth_v1_auth_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use PATReq.ProtoReflect.Descriptor instead.
|
||||||
|
func (*PATReq) Descriptor() ([]byte, []int) {
|
||||||
|
return file_auth_v1_auth_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PATReq) GetPatId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.PatId
|
return x.PatId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PolicyReq) GetOperation() string {
|
func (x *PATReq) GetDomain() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Domain
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PATReq) GetOperation() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Operation
|
return x.Operation
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PolicyReq) GetUserId() string {
|
func (x *PATReq) GetUserId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.UserId
|
return x.UserId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PolicyReq) GetEntityId() string {
|
func (x *PATReq) GetEntityId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EntityId
|
return x.EntityId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *PolicyReq) GetEntityType() string {
|
func (x *PATReq) GetEntityType() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EntityType
|
return x.EntityType
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthZReq struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
PolicyReq *PolicyReq `protobuf:"bytes,1,opt,name=policy_req,json=policyReq,proto3" json:"policy_req,omitempty"`
|
||||||
|
PatReq *PATReq `protobuf:"bytes,2,opt,name=pat_req,json=patReq,proto3,oneof" json:"pat_req,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AuthZReq) Reset() {
|
||||||
|
*x = AuthZReq{}
|
||||||
|
mi := &file_auth_v1_auth_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AuthZReq) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AuthZReq) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AuthZReq) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_auth_v1_auth_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AuthZReq.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AuthZReq) Descriptor() ([]byte, []int) {
|
||||||
|
return file_auth_v1_auth_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AuthZReq) GetPolicyReq() *PolicyReq {
|
||||||
|
if x != nil {
|
||||||
|
return x.PolicyReq
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AuthZReq) GetPatReq() *PATReq {
|
||||||
|
if x != nil {
|
||||||
|
return x.PatReq
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type AuthZRes struct {
|
type AuthZRes struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
||||||
@@ -294,7 +390,7 @@ type AuthZRes struct {
|
|||||||
|
|
||||||
func (x *AuthZRes) Reset() {
|
func (x *AuthZRes) Reset() {
|
||||||
*x = AuthZRes{}
|
*x = AuthZRes{}
|
||||||
mi := &file_auth_v1_auth_proto_msgTypes[3]
|
mi := &file_auth_v1_auth_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -306,7 +402,7 @@ func (x *AuthZRes) String() string {
|
|||||||
func (*AuthZRes) ProtoMessage() {}
|
func (*AuthZRes) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AuthZRes) ProtoReflect() protoreflect.Message {
|
func (x *AuthZRes) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_auth_v1_auth_proto_msgTypes[3]
|
mi := &file_auth_v1_auth_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -319,7 +415,7 @@ func (x *AuthZRes) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AuthZRes.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AuthZRes.ProtoReflect.Descriptor instead.
|
||||||
func (*AuthZRes) Descriptor() ([]byte, []int) {
|
func (*AuthZRes) Descriptor() ([]byte, []int) {
|
||||||
return file_auth_v1_auth_proto_rawDescGZIP(), []int{3}
|
return file_auth_v1_auth_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AuthZRes) GetAuthorized() bool {
|
func (x *AuthZRes) GetAuthorized() bool {
|
||||||
@@ -347,7 +443,7 @@ const file_auth_v1_auth_proto_rawDesc = "" +
|
|||||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x17\n" +
|
"\x02id\x18\x01 \x01(\tR\x02id\x12\x17\n" +
|
||||||
"\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1b\n" +
|
"\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1b\n" +
|
||||||
"\tuser_role\x18\x03 \x01(\rR\buserRole\x12\x1a\n" +
|
"\tuser_role\x18\x03 \x01(\rR\buserRole\x12\x1a\n" +
|
||||||
"\bverified\x18\x04 \x01(\bR\bverified\"\xaf\x03\n" +
|
"\bverified\x18\x04 \x01(\bR\bverified\"\xa3\x02\n" +
|
||||||
"\tPolicyReq\x12\x16\n" +
|
"\tPolicyReq\x12\x16\n" +
|
||||||
"\x06domain\x18\x01 \x01(\tR\x06domain\x12!\n" +
|
"\x06domain\x18\x01 \x01(\tR\x06domain\x12!\n" +
|
||||||
"\fsubject_type\x18\x02 \x01(\tR\vsubjectType\x12!\n" +
|
"\fsubject_type\x18\x02 \x01(\tR\vsubjectType\x12!\n" +
|
||||||
@@ -360,21 +456,28 @@ const file_auth_v1_auth_proto_rawDesc = "" +
|
|||||||
"permission\x12\x16\n" +
|
"permission\x12\x16\n" +
|
||||||
"\x06object\x18\b \x01(\tR\x06object\x12\x1f\n" +
|
"\x06object\x18\b \x01(\tR\x06object\x12\x1f\n" +
|
||||||
"\vobject_type\x18\t \x01(\tR\n" +
|
"\vobject_type\x18\t \x01(\tR\n" +
|
||||||
"objectType\x12\x15\n" +
|
"objectType\"\xac\x01\n" +
|
||||||
"\x06pat_id\x18\n" +
|
"\x06PATReq\x12\x15\n" +
|
||||||
" \x01(\tR\x05patId\x12\x1c\n" +
|
"\x06pat_id\x18\x01 \x01(\tR\x05patId\x12\x16\n" +
|
||||||
"\toperation\x18\v \x01(\tR\toperation\x12\x17\n" +
|
"\x06domain\x18\x02 \x01(\tR\x06domain\x12\x1c\n" +
|
||||||
"\auser_id\x18\f \x01(\tR\x06userId\x12\x1b\n" +
|
"\toperation\x18\x03 \x01(\tR\toperation\x12\x17\n" +
|
||||||
"\tentity_id\x18\r \x01(\tR\bentityId\x12\x1f\n" +
|
"\auser_id\x18\x04 \x01(\tR\x06userId\x12\x1b\n" +
|
||||||
"\ventity_type\x18\x0e \x01(\tR\n" +
|
"\tentity_id\x18\x05 \x01(\tR\bentityId\x12\x1f\n" +
|
||||||
"entityType\":\n" +
|
"\ventity_type\x18\x06 \x01(\tR\n" +
|
||||||
|
"entityType\"x\n" +
|
||||||
|
"\bAuthZReq\x121\n" +
|
||||||
|
"\n" +
|
||||||
|
"policy_req\x18\x01 \x01(\v2\x12.auth.v1.PolicyReqR\tpolicyReq\x12-\n" +
|
||||||
|
"\apat_req\x18\x02 \x01(\v2\x0f.auth.v1.PATReqH\x00R\x06patReq\x88\x01\x01B\n" +
|
||||||
|
"\n" +
|
||||||
|
"\b_pat_req\":\n" +
|
||||||
"\bAuthZRes\x12\x1e\n" +
|
"\bAuthZRes\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"authorized\x18\x01 \x01(\bR\n" +
|
"authorized\x18\x01 \x01(\bR\n" +
|
||||||
"authorized\x12\x0e\n" +
|
"authorized\x12\x0e\n" +
|
||||||
"\x02id\x18\x02 \x01(\tR\x02id2{\n" +
|
"\x02id\x18\x02 \x01(\tR\x02id2z\n" +
|
||||||
"\vAuthService\x124\n" +
|
"\vAuthService\x123\n" +
|
||||||
"\tAuthorize\x12\x12.auth.v1.PolicyReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
|
"\tAuthorize\x12\x11.auth.v1.AuthZReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
|
||||||
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
|
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -389,23 +492,27 @@ func file_auth_v1_auth_proto_rawDescGZIP() []byte {
|
|||||||
return file_auth_v1_auth_proto_rawDescData
|
return file_auth_v1_auth_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_auth_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
var file_auth_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_auth_v1_auth_proto_goTypes = []any{
|
var file_auth_v1_auth_proto_goTypes = []any{
|
||||||
(*AuthNReq)(nil), // 0: auth.v1.AuthNReq
|
(*AuthNReq)(nil), // 0: auth.v1.AuthNReq
|
||||||
(*AuthNRes)(nil), // 1: auth.v1.AuthNRes
|
(*AuthNRes)(nil), // 1: auth.v1.AuthNRes
|
||||||
(*PolicyReq)(nil), // 2: auth.v1.PolicyReq
|
(*PolicyReq)(nil), // 2: auth.v1.PolicyReq
|
||||||
(*AuthZRes)(nil), // 3: auth.v1.AuthZRes
|
(*PATReq)(nil), // 3: auth.v1.PATReq
|
||||||
|
(*AuthZReq)(nil), // 4: auth.v1.AuthZReq
|
||||||
|
(*AuthZRes)(nil), // 5: auth.v1.AuthZRes
|
||||||
}
|
}
|
||||||
var file_auth_v1_auth_proto_depIdxs = []int32{
|
var file_auth_v1_auth_proto_depIdxs = []int32{
|
||||||
2, // 0: auth.v1.AuthService.Authorize:input_type -> auth.v1.PolicyReq
|
2, // 0: auth.v1.AuthZReq.policy_req:type_name -> auth.v1.PolicyReq
|
||||||
0, // 1: auth.v1.AuthService.Authenticate:input_type -> auth.v1.AuthNReq
|
3, // 1: auth.v1.AuthZReq.pat_req:type_name -> auth.v1.PATReq
|
||||||
3, // 2: auth.v1.AuthService.Authorize:output_type -> auth.v1.AuthZRes
|
4, // 2: auth.v1.AuthService.Authorize:input_type -> auth.v1.AuthZReq
|
||||||
1, // 3: auth.v1.AuthService.Authenticate:output_type -> auth.v1.AuthNRes
|
0, // 3: auth.v1.AuthService.Authenticate:input_type -> auth.v1.AuthNReq
|
||||||
2, // [2:4] is the sub-list for method output_type
|
5, // 4: auth.v1.AuthService.Authorize:output_type -> auth.v1.AuthZRes
|
||||||
0, // [0:2] is the sub-list for method input_type
|
1, // 5: auth.v1.AuthService.Authenticate:output_type -> auth.v1.AuthNRes
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
4, // [4:6] is the sub-list for method output_type
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
2, // [2:4] is the sub-list for method input_type
|
||||||
0, // [0:0] is the sub-list for field type_name
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_auth_v1_auth_proto_init() }
|
func init() { file_auth_v1_auth_proto_init() }
|
||||||
@@ -413,13 +520,14 @@ func file_auth_v1_auth_proto_init() {
|
|||||||
if File_auth_v1_auth_proto != nil {
|
if File_auth_v1_auth_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
file_auth_v1_auth_proto_msgTypes[4].OneofWrappers = []any{}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_auth_v1_auth_proto_rawDesc), len(file_auth_v1_auth_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_auth_v1_auth_proto_rawDesc), len(file_auth_v1_auth_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 4,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const (
|
|||||||
// AuthService is a service that provides authentication
|
// AuthService is a service that provides authentication
|
||||||
// and authorization functionalities for SuperMQ services.
|
// and authorization functionalities for SuperMQ services.
|
||||||
type AuthServiceClient interface {
|
type AuthServiceClient interface {
|
||||||
Authorize(ctx context.Context, in *PolicyReq, opts ...grpc.CallOption) (*AuthZRes, error)
|
Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error)
|
||||||
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
|
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
|
|||||||
return &authServiceClient{cc}
|
return &authServiceClient{cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *authServiceClient) Authorize(ctx context.Context, in *PolicyReq, opts ...grpc.CallOption) (*AuthZRes, error) {
|
func (c *authServiceClient) Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
out := new(AuthZRes)
|
out := new(AuthZRes)
|
||||||
err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, cOpts...)
|
err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, cOpts...)
|
||||||
@@ -72,7 +72,7 @@ func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts
|
|||||||
// AuthService is a service that provides authentication
|
// AuthService is a service that provides authentication
|
||||||
// and authorization functionalities for SuperMQ services.
|
// and authorization functionalities for SuperMQ services.
|
||||||
type AuthServiceServer interface {
|
type AuthServiceServer interface {
|
||||||
Authorize(context.Context, *PolicyReq) (*AuthZRes, error)
|
Authorize(context.Context, *AuthZReq) (*AuthZRes, error)
|
||||||
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
|
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
|
||||||
mustEmbedUnimplementedAuthServiceServer()
|
mustEmbedUnimplementedAuthServiceServer()
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ type AuthServiceServer interface {
|
|||||||
// pointer dereference when methods are called.
|
// pointer dereference when methods are called.
|
||||||
type UnimplementedAuthServiceServer struct{}
|
type UnimplementedAuthServiceServer struct{}
|
||||||
|
|
||||||
func (UnimplementedAuthServiceServer) Authorize(context.Context, *PolicyReq) (*AuthZRes, error) {
|
func (UnimplementedAuthServiceServer) Authorize(context.Context, *AuthZReq) (*AuthZRes, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedAuthServiceServer) Authenticate(context.Context, *AuthNReq) (*AuthNRes, error) {
|
func (UnimplementedAuthServiceServer) Authenticate(context.Context, *AuthNReq) (*AuthNRes, error) {
|
||||||
@@ -112,7 +112,7 @@ func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(PolicyReq)
|
in := new(AuthZReq)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec fu
|
|||||||
FullMethod: AuthService_Authorize_FullMethodName,
|
FullMethod: AuthService_Authorize_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(AuthServiceServer).Authorize(ctx, req.(*PolicyReq))
|
return srv.(AuthServiceServer).Authorize(ctx, req.(*AuthZReq))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,27 +70,35 @@ func decodeIdentifyResponse(_ context.Context, grpcRes any) (any, error) {
|
|||||||
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified()}, nil
|
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.PolicyReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
|
func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var authReqData authReq
|
var authReqData authReq
|
||||||
|
|
||||||
if req != nil {
|
if req != nil {
|
||||||
authReqData = authReq{
|
policyReq := req.GetPolicyReq()
|
||||||
Domain: req.GetDomain(),
|
patReq := req.GetPatReq()
|
||||||
SubjectType: req.GetSubjectType(),
|
|
||||||
Subject: req.GetSubject(),
|
if policyReq != nil {
|
||||||
SubjectKind: req.GetSubjectKind(),
|
authReqData = authReq{
|
||||||
Relation: req.GetRelation(),
|
Domain: policyReq.GetDomain(),
|
||||||
Permission: req.GetPermission(),
|
SubjectType: policyReq.GetSubjectType(),
|
||||||
ObjectType: req.GetObjectType(),
|
Subject: policyReq.GetSubject(),
|
||||||
Object: req.GetObject(),
|
SubjectKind: policyReq.GetSubjectKind(),
|
||||||
UserID: req.GetUserId(),
|
Relation: policyReq.GetRelation(),
|
||||||
PatID: req.GetPatId(),
|
Permission: policyReq.GetPermission(),
|
||||||
EntityType: req.GetEntityType(),
|
ObjectType: policyReq.GetObjectType(),
|
||||||
Operation: req.GetOperation(),
|
Object: policyReq.GetObject(),
|
||||||
EntityID: req.GetEntityId(),
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if patReq != nil {
|
||||||
|
authReqData.UserID = patReq.GetUserId()
|
||||||
|
authReqData.PatID = patReq.GetPatId()
|
||||||
|
authReqData.EntityType = patReq.GetEntityType()
|
||||||
|
authReqData.Operation = patReq.GetOperation()
|
||||||
|
authReqData.EntityID = patReq.GetEntityId()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,19 +119,29 @@ func decodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
|
|||||||
func encodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
func encodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
||||||
req := grpcReq.(authReq)
|
req := grpcReq.(authReq)
|
||||||
|
|
||||||
return &grpcAuthV1.PolicyReq{
|
authZReq := &grpcAuthV1.AuthZReq{
|
||||||
Domain: req.Domain,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: req.SubjectType,
|
Domain: req.Domain,
|
||||||
Subject: req.Subject,
|
SubjectType: req.SubjectType,
|
||||||
SubjectKind: req.SubjectKind,
|
Subject: req.Subject,
|
||||||
Relation: req.Relation,
|
SubjectKind: req.SubjectKind,
|
||||||
Permission: req.Permission,
|
Relation: req.Relation,
|
||||||
ObjectType: req.ObjectType,
|
Permission: req.Permission,
|
||||||
Object: req.Object,
|
ObjectType: req.ObjectType,
|
||||||
UserId: req.UserID,
|
Object: req.Object,
|
||||||
PatId: req.PatID,
|
},
|
||||||
EntityType: req.EntityType,
|
}
|
||||||
Operation: req.Operation,
|
|
||||||
EntityId: req.EntityID,
|
if req.PatID != "" {
|
||||||
}, nil
|
authZReq.PatReq = &grpcAuthV1.PATReq{
|
||||||
|
PatId: req.PatID,
|
||||||
|
Domain: req.Domain,
|
||||||
|
Operation: req.Operation,
|
||||||
|
UserId: req.UserID,
|
||||||
|
EntityId: req.EntityID,
|
||||||
|
EntityType: req.EntityType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return authZReq, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,22 @@ func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
|
|||||||
return authorizeRes{}, err
|
return authorizeRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pat *auth.PATAuthz
|
||||||
|
if req.PatID != "" {
|
||||||
|
entityType, err := auth.ParseEntityType(req.EntityType)
|
||||||
|
if err != nil {
|
||||||
|
return authorizeRes{authorized: false}, err
|
||||||
|
}
|
||||||
|
pat = &auth.PATAuthz{
|
||||||
|
PatID: req.PatID,
|
||||||
|
UserID: req.UserID,
|
||||||
|
EntityType: entityType,
|
||||||
|
EntityID: req.EntityID,
|
||||||
|
Operation: req.Operation,
|
||||||
|
Domain: req.Domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := svc.Authorize(ctx, policies.Policy{
|
err := svc.Authorize(ctx, policies.Policy{
|
||||||
Domain: req.Domain,
|
Domain: req.Domain,
|
||||||
SubjectType: req.SubjectType,
|
SubjectType: req.SubjectType,
|
||||||
@@ -44,12 +60,7 @@ func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
|
|||||||
Permission: req.Permission,
|
Permission: req.Permission,
|
||||||
ObjectType: req.ObjectType,
|
ObjectType: req.ObjectType,
|
||||||
Object: req.Object,
|
Object: req.Object,
|
||||||
PatID: req.PatID,
|
}, pat)
|
||||||
Operation: req.Operation,
|
|
||||||
UserID: req.UserID,
|
|
||||||
EntityType: req.EntityType,
|
|
||||||
EntityID: req.EntityID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authorizeRes{authorized: false}, err
|
return authorizeRes{authorized: false}, err
|
||||||
}
|
}
|
||||||
|
|||||||
+135
-101
@@ -129,20 +129,22 @@ func TestAuthorize(t *testing.T) {
|
|||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
token string
|
token string
|
||||||
authRequest *grpcAuthV1.PolicyReq
|
authRequest *grpcAuthV1.AuthZReq
|
||||||
authResponse *grpcAuthV1.AuthZRes
|
authResponse *grpcAuthV1.AuthZRes
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "authorize user with authorized token",
|
desc: "authorize user with authorized token",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: id,
|
||||||
Object: authoritiesObj,
|
SubjectType: usersType,
|
||||||
ObjectType: usersType,
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||||
err: nil,
|
err: nil,
|
||||||
@@ -150,13 +152,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with unauthorized token",
|
desc: "authorize user with unauthorized token",
|
||||||
token: inValidToken,
|
token: inValidToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: id,
|
||||||
Object: authoritiesObj,
|
SubjectType: usersType,
|
||||||
ObjectType: usersType,
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: svcerr.ErrAuthorization,
|
err: svcerr.ErrAuthorization,
|
||||||
@@ -164,13 +168,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with empty subject",
|
desc: "authorize user with empty subject",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: "",
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: "",
|
||||||
Object: authoritiesObj,
|
SubjectType: usersType,
|
||||||
ObjectType: usersType,
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingPolicySub,
|
err: apiutil.ErrMissingPolicySub,
|
||||||
@@ -178,13 +184,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with empty subject type",
|
desc: "authorize user with empty subject type",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: "",
|
Subject: id,
|
||||||
Object: authoritiesObj,
|
SubjectType: "",
|
||||||
ObjectType: usersType,
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingPolicySub,
|
err: apiutil.ErrMissingPolicySub,
|
||||||
@@ -192,13 +200,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with empty object",
|
desc: "authorize user with empty object",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: id,
|
||||||
Object: "",
|
SubjectType: usersType,
|
||||||
ObjectType: usersType,
|
Object: "",
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingPolicyObj,
|
err: apiutil.ErrMissingPolicyObj,
|
||||||
@@ -206,13 +216,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with empty object type",
|
desc: "authorize user with empty object type",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: id,
|
||||||
Object: authoritiesObj,
|
SubjectType: usersType,
|
||||||
ObjectType: "",
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: "",
|
||||||
Permission: adminPermission,
|
Relation: memberRelation,
|
||||||
|
Permission: adminPermission,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingPolicyObj,
|
err: apiutil.ErrMissingPolicyObj,
|
||||||
@@ -220,13 +232,15 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with empty permission",
|
desc: "authorize user with empty permission",
|
||||||
token: validToken,
|
token: validToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: usersType,
|
Subject: id,
|
||||||
Object: authoritiesObj,
|
SubjectType: usersType,
|
||||||
ObjectType: usersType,
|
Object: authoritiesObj,
|
||||||
Relation: memberRelation,
|
ObjectType: usersType,
|
||||||
Permission: "",
|
Relation: memberRelation,
|
||||||
|
Permission: "",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMalformedPolicyPer,
|
err: apiutil.ErrMalformedPolicyPer,
|
||||||
@@ -234,19 +248,24 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with valid PAT token",
|
desc: "authorize user with valid PAT token",
|
||||||
token: validPATToken,
|
token: validPATToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: policies.UserType,
|
Subject: id,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectType: policies.UserType,
|
||||||
Permission: policies.ViewPermission,
|
SubjectKind: policies.UsersKind,
|
||||||
PatId: id,
|
Permission: policies.ViewPermission,
|
||||||
ObjectType: policies.ClientType,
|
ObjectType: policies.ClientType,
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: "view",
|
Object: clientID,
|
||||||
Object: clientID,
|
},
|
||||||
UserId: id,
|
PatReq: &grpcAuthV1.PATReq{
|
||||||
EntityId: clientID,
|
PatId: id,
|
||||||
EntityType: auth.ClientsScopeStr,
|
Domain: domainID,
|
||||||
|
Operation: "view",
|
||||||
|
UserId: id,
|
||||||
|
EntityId: clientID,
|
||||||
|
EntityType: auth.ClientsScopeStr,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||||
err: nil,
|
err: nil,
|
||||||
@@ -254,19 +273,24 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize user with unauthorized PAT token",
|
desc: "authorize user with unauthorized PAT token",
|
||||||
token: inValidToken,
|
token: inValidToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: policies.UserType,
|
Subject: id,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectType: policies.UserType,
|
||||||
Permission: policies.ViewPermission,
|
SubjectKind: policies.UsersKind,
|
||||||
PatId: id,
|
Permission: policies.ViewPermission,
|
||||||
ObjectType: policies.ClientType,
|
ObjectType: policies.ClientType,
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: "view",
|
Object: clientID,
|
||||||
Object: clientID,
|
},
|
||||||
UserId: id,
|
PatReq: &grpcAuthV1.PATReq{
|
||||||
EntityId: clientID,
|
PatId: id,
|
||||||
EntityType: auth.ClientsScopeStr,
|
Domain: domainID,
|
||||||
|
Operation: "view",
|
||||||
|
UserId: id,
|
||||||
|
EntityId: clientID,
|
||||||
|
EntityType: auth.ClientsScopeStr,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: svcerr.ErrAuthorization,
|
err: svcerr.ErrAuthorization,
|
||||||
@@ -274,18 +298,23 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize PAT with missing user id",
|
desc: "authorize PAT with missing user id",
|
||||||
token: validPATToken,
|
token: validPATToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: policies.UserType,
|
Subject: id,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectType: policies.UserType,
|
||||||
Permission: policies.ViewPermission,
|
SubjectKind: policies.UsersKind,
|
||||||
PatId: id,
|
Permission: policies.ViewPermission,
|
||||||
ObjectType: policies.ClientType,
|
ObjectType: policies.ClientType,
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: "view",
|
Object: clientID,
|
||||||
Object: clientID,
|
},
|
||||||
EntityId: clientID,
|
PatReq: &grpcAuthV1.PATReq{
|
||||||
EntityType: auth.ClientsScopeStr,
|
PatId: id,
|
||||||
|
Domain: domainID,
|
||||||
|
Operation: "view",
|
||||||
|
EntityId: clientID,
|
||||||
|
EntityType: auth.ClientsScopeStr,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingUserID,
|
err: apiutil.ErrMissingUserID,
|
||||||
@@ -293,18 +322,23 @@ func TestAuthorize(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "authorize PAT with missing entity id",
|
desc: "authorize PAT with missing entity id",
|
||||||
token: validPATToken,
|
token: validPATToken,
|
||||||
authRequest: &grpcAuthV1.PolicyReq{
|
authRequest: &grpcAuthV1.AuthZReq{
|
||||||
Subject: id,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: policies.UserType,
|
Subject: id,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectType: policies.UserType,
|
||||||
Permission: policies.ViewPermission,
|
SubjectKind: policies.UsersKind,
|
||||||
PatId: id,
|
Permission: policies.ViewPermission,
|
||||||
ObjectType: policies.ClientType,
|
ObjectType: policies.ClientType,
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: "view",
|
Object: clientID,
|
||||||
Object: clientID,
|
},
|
||||||
UserId: id,
|
PatReq: &grpcAuthV1.PATReq{
|
||||||
EntityType: auth.ClientsScopeStr,
|
PatId: id,
|
||||||
|
Domain: domainID,
|
||||||
|
Operation: "view",
|
||||||
|
UserId: id,
|
||||||
|
EntityType: auth.ClientsScopeStr,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||||
err: apiutil.ErrMissingID,
|
err: apiutil.ErrMissingID,
|
||||||
@@ -312,7 +346,7 @@ func TestAuthorize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
svcCall := svc.On("Authorize", mock.Anything, mock.Anything).Return(tc.err)
|
svcCall := svc.On("Authorize", mock.Anything, mock.Anything, mock.Anything).Return(tc.err)
|
||||||
ar, err := grpcClient.Authorize(context.Background(), tc.authRequest)
|
ar, err := grpcClient.Authorize(context.Background(), tc.authRequest)
|
||||||
if ar != nil {
|
if ar != nil {
|
||||||
assert.Equal(t, tc.authResponse, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.authResponse, ar))
|
assert.Equal(t, tc.authResponse, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.authResponse, ar))
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func (s *authGrpcServer) Authenticate(ctx context.Context, req *grpcAuthV1.AuthN
|
|||||||
return res.(*grpcAuthV1.AuthNRes), nil
|
return res.(*grpcAuthV1.AuthNRes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *authGrpcServer) Authorize(ctx context.Context, req *grpcAuthV1.PolicyReq) (*grpcAuthV1.AuthZRes, error) {
|
func (s *authGrpcServer) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq) (*grpcAuthV1.AuthZRes, error) {
|
||||||
_, res, err := s.authorize.ServeGRPC(ctx, req)
|
_, res, err := s.authorize.ServeGRPC(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, grpcapi.EncodeError(err)
|
return nil, grpcapi.EncodeError(err)
|
||||||
@@ -64,26 +64,38 @@ func encodeAuthenticateResponse(_ context.Context, grpcRes any) (any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
||||||
req := grpcReq.(*grpcAuthV1.PolicyReq)
|
req := grpcReq.(*grpcAuthV1.AuthZReq)
|
||||||
if req == nil {
|
if req == nil {
|
||||||
return authReq{}, nil
|
return authReq{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return authReq{
|
policyReq := req.GetPolicyReq()
|
||||||
Domain: req.GetDomain(),
|
patReq := req.GetPatReq()
|
||||||
SubjectType: req.GetSubjectType(),
|
|
||||||
SubjectKind: req.GetSubjectKind(),
|
if policyReq == nil {
|
||||||
Subject: req.GetSubject(),
|
return authReq{}, nil
|
||||||
Relation: req.GetRelation(),
|
}
|
||||||
Permission: req.GetPermission(),
|
|
||||||
ObjectType: req.GetObjectType(),
|
authRequest := authReq{
|
||||||
Object: req.GetObject(),
|
Domain: policyReq.GetDomain(),
|
||||||
UserID: req.GetUserId(),
|
SubjectType: policyReq.GetSubjectType(),
|
||||||
PatID: req.GetPatId(),
|
SubjectKind: policyReq.GetSubjectKind(),
|
||||||
EntityType: req.GetEntityType(),
|
Subject: policyReq.GetSubject(),
|
||||||
Operation: req.GetOperation(),
|
Relation: policyReq.GetRelation(),
|
||||||
EntityID: req.GetEntityId(),
|
Permission: policyReq.GetPermission(),
|
||||||
}, nil
|
ObjectType: policyReq.GetObjectType(),
|
||||||
|
Object: policyReq.GetObject(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if patReq != nil {
|
||||||
|
authRequest.UserID = patReq.GetUserId()
|
||||||
|
authRequest.PatID = patReq.GetPatId()
|
||||||
|
authRequest.EntityType = patReq.GetEntityType()
|
||||||
|
authRequest.Operation = patReq.GetOperation()
|
||||||
|
authRequest.EntityID = patReq.GetEntityId()
|
||||||
|
}
|
||||||
|
|
||||||
|
return authRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
|
func encodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ func (lm *loggingMiddleware) RetrieveJWKS() (jwks []auth.PublicKeyInfo) {
|
|||||||
return lm.svc.RetrieveJWKS()
|
return lm.svc.RetrieveJWKS()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy) (err error) {
|
func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) (err error) {
|
||||||
defer func(begin time.Time) {
|
defer func(begin time.Time) {
|
||||||
args := []any{
|
args := []any{
|
||||||
slog.String("duration", time.Since(begin).String()),
|
slog.String("duration", time.Since(begin).String()),
|
||||||
@@ -125,6 +125,18 @@ func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
|||||||
),
|
),
|
||||||
slog.String("permission", pr.Permission),
|
slog.String("permission", pr.Permission),
|
||||||
}
|
}
|
||||||
|
if patAuthz != nil {
|
||||||
|
args = append(args,
|
||||||
|
slog.Group("pat",
|
||||||
|
slog.String("pat_id", patAuthz.PatID),
|
||||||
|
slog.String("user_id", patAuthz.UserID),
|
||||||
|
slog.String("entity_type", patAuthz.EntityType.String()),
|
||||||
|
slog.String("entity_id", patAuthz.EntityID),
|
||||||
|
slog.String("operation", patAuthz.Operation),
|
||||||
|
slog.String("domain", patAuthz.Domain),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
args = append(args, slog.String("error", err.Error()))
|
args = append(args, slog.String("error", err.Error()))
|
||||||
lm.logger.Warn("Authorize failed", args...)
|
lm.logger.Warn("Authorize failed", args...)
|
||||||
@@ -132,7 +144,7 @@ func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
|||||||
}
|
}
|
||||||
lm.logger.Info("Authorize completed successfully", args...)
|
lm.logger.Info("Authorize completed successfully", args...)
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
return lm.svc.Authorize(ctx, pr)
|
return lm.svc.Authorize(ctx, pr, patAuthz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lm *loggingMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (pa auth.PAT, err error) {
|
func (lm *loggingMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (pa auth.PAT, err error) {
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ func (ms *metricsMiddleware) RetrieveJWKS() []auth.PublicKeyInfo {
|
|||||||
return ms.svc.RetrieveJWKS()
|
return ms.svc.RetrieveJWKS()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *metricsMiddleware) Authorize(ctx context.Context, pr policies.Policy) error {
|
func (ms *metricsMiddleware) Authorize(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error {
|
||||||
defer func(begin time.Time) {
|
defer func(begin time.Time) {
|
||||||
ms.counter.With("method", "authorize").Add(1)
|
ms.counter.With("method", "authorize").Add(1)
|
||||||
ms.latency.With("method", "authorize").Observe(time.Since(begin).Seconds())
|
ms.latency.With("method", "authorize").Observe(time.Since(begin).Seconds())
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
return ms.svc.Authorize(ctx, pr)
|
return ms.svc.Authorize(ctx, pr, patAuthz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *metricsMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (auth.PAT, error) {
|
func (ms *metricsMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (auth.PAT, error) {
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ func (tm *tracingMiddleware) RetrieveJWKS() []auth.PublicKeyInfo {
|
|||||||
return tm.svc.RetrieveJWKS()
|
return tm.svc.RetrieveJWKS()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *tracingMiddleware) Authorize(ctx context.Context, pr policies.Policy) error {
|
func (tm *tracingMiddleware) Authorize(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error {
|
||||||
ctx, span := tm.tracer.Start(ctx, "authorize", trace.WithAttributes(
|
attributes := []attribute.KeyValue{
|
||||||
attribute.String("subject", pr.Subject),
|
attribute.String("subject", pr.Subject),
|
||||||
attribute.String("subject_type", pr.SubjectType),
|
attribute.String("subject_type", pr.SubjectType),
|
||||||
attribute.String("subject_relation", pr.SubjectRelation),
|
attribute.String("subject_relation", pr.SubjectRelation),
|
||||||
@@ -74,10 +74,23 @@ func (tm *tracingMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
|||||||
attribute.String("object_type", pr.ObjectType),
|
attribute.String("object_type", pr.ObjectType),
|
||||||
attribute.String("relation", pr.Relation),
|
attribute.String("relation", pr.Relation),
|
||||||
attribute.String("permission", pr.Permission),
|
attribute.String("permission", pr.Permission),
|
||||||
))
|
}
|
||||||
|
|
||||||
|
if patAuthz != nil {
|
||||||
|
attributes = append(attributes,
|
||||||
|
attribute.String("pat_id", patAuthz.PatID),
|
||||||
|
attribute.String("pat_user_id", patAuthz.UserID),
|
||||||
|
attribute.String("pat_entity_type", patAuthz.EntityType.String()),
|
||||||
|
attribute.String("pat_entity_id", patAuthz.EntityID),
|
||||||
|
attribute.String("pat_operation", patAuthz.Operation),
|
||||||
|
attribute.String("pat_domain", patAuthz.Domain),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, span := tm.tracer.Start(ctx, "authorize", trace.WithAttributes(attributes...))
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
return tm.svc.Authorize(ctx, pr)
|
return tm.svc.Authorize(ctx, pr, patAuthz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *tracingMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (auth.PAT, error) {
|
func (tm *tracingMiddleware) CreatePAT(ctx context.Context, token, name, description string, duration time.Duration) (auth.PAT, error) {
|
||||||
|
|||||||
+15
-8
@@ -11,6 +11,7 @@ package mocks
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/absmach/supermq/auth"
|
||||||
"github.com/absmach/supermq/pkg/policies"
|
"github.com/absmach/supermq/pkg/policies"
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
@@ -43,16 +44,16 @@ func (_m *Authz) EXPECT() *Authz_Expecter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authorize provides a mock function for the type Authz
|
// Authorize provides a mock function for the type Authz
|
||||||
func (_mock *Authz) Authorize(ctx context.Context, pr policies.Policy) error {
|
func (_mock *Authz) Authorize(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error {
|
||||||
ret := _mock.Called(ctx, pr)
|
ret := _mock.Called(ctx, pr, patAuthz)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Authorize")
|
panic("no return value specified for Authorize")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if returnFunc, ok := ret.Get(0).(func(context.Context, policies.Policy) error); ok {
|
if returnFunc, ok := ret.Get(0).(func(context.Context, policies.Policy, *auth.PATAuthz) error); ok {
|
||||||
r0 = returnFunc(ctx, pr)
|
r0 = returnFunc(ctx, pr, patAuthz)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
@@ -67,11 +68,12 @@ type Authz_Authorize_Call struct {
|
|||||||
// Authorize is a helper method to define mock.On call
|
// Authorize is a helper method to define mock.On call
|
||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - pr policies.Policy
|
// - pr policies.Policy
|
||||||
func (_e *Authz_Expecter) Authorize(ctx interface{}, pr interface{}) *Authz_Authorize_Call {
|
// - patAuthz *auth.PATAuthz
|
||||||
return &Authz_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr)}
|
func (_e *Authz_Expecter) Authorize(ctx interface{}, pr interface{}, patAuthz interface{}) *Authz_Authorize_Call {
|
||||||
|
return &Authz_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr, patAuthz)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Authz_Authorize_Call) Run(run func(ctx context.Context, pr policies.Policy)) *Authz_Authorize_Call {
|
func (_c *Authz_Authorize_Call) Run(run func(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz)) *Authz_Authorize_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
var arg0 context.Context
|
var arg0 context.Context
|
||||||
if args[0] != nil {
|
if args[0] != nil {
|
||||||
@@ -81,9 +83,14 @@ func (_c *Authz_Authorize_Call) Run(run func(ctx context.Context, pr policies.Po
|
|||||||
if args[1] != nil {
|
if args[1] != nil {
|
||||||
arg1 = args[1].(policies.Policy)
|
arg1 = args[1].(policies.Policy)
|
||||||
}
|
}
|
||||||
|
var arg2 *auth.PATAuthz
|
||||||
|
if args[2] != nil {
|
||||||
|
arg2 = args[2].(*auth.PATAuthz)
|
||||||
|
}
|
||||||
run(
|
run(
|
||||||
arg0,
|
arg0,
|
||||||
arg1,
|
arg1,
|
||||||
|
arg2,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
@@ -94,7 +101,7 @@ func (_c *Authz_Authorize_Call) Return(err error) *Authz_Authorize_Call {
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Authz_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr policies.Policy) error) *Authz_Authorize_Call {
|
func (_c *Authz_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error) *Authz_Authorize_Call {
|
||||||
_c.Call.Return(run)
|
_c.Call.Return(run)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-8
@@ -114,16 +114,16 @@ func (_c *Service_AddScope_Call) RunAndReturn(run func(ctx context.Context, toke
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authorize provides a mock function for the type Service
|
// Authorize provides a mock function for the type Service
|
||||||
func (_mock *Service) Authorize(ctx context.Context, pr policies.Policy) error {
|
func (_mock *Service) Authorize(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error {
|
||||||
ret := _mock.Called(ctx, pr)
|
ret := _mock.Called(ctx, pr, patAuthz)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Authorize")
|
panic("no return value specified for Authorize")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if returnFunc, ok := ret.Get(0).(func(context.Context, policies.Policy) error); ok {
|
if returnFunc, ok := ret.Get(0).(func(context.Context, policies.Policy, *auth.PATAuthz) error); ok {
|
||||||
r0 = returnFunc(ctx, pr)
|
r0 = returnFunc(ctx, pr, patAuthz)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
@@ -138,11 +138,12 @@ type Service_Authorize_Call struct {
|
|||||||
// Authorize is a helper method to define mock.On call
|
// Authorize is a helper method to define mock.On call
|
||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - pr policies.Policy
|
// - pr policies.Policy
|
||||||
func (_e *Service_Expecter) Authorize(ctx interface{}, pr interface{}) *Service_Authorize_Call {
|
// - patAuthz *auth.PATAuthz
|
||||||
return &Service_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr)}
|
func (_e *Service_Expecter) Authorize(ctx interface{}, pr interface{}, patAuthz interface{}) *Service_Authorize_Call {
|
||||||
|
return &Service_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr, patAuthz)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Service_Authorize_Call) Run(run func(ctx context.Context, pr policies.Policy)) *Service_Authorize_Call {
|
func (_c *Service_Authorize_Call) Run(run func(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz)) *Service_Authorize_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
var arg0 context.Context
|
var arg0 context.Context
|
||||||
if args[0] != nil {
|
if args[0] != nil {
|
||||||
@@ -152,9 +153,14 @@ func (_c *Service_Authorize_Call) Run(run func(ctx context.Context, pr policies.
|
|||||||
if args[1] != nil {
|
if args[1] != nil {
|
||||||
arg1 = args[1].(policies.Policy)
|
arg1 = args[1].(policies.Policy)
|
||||||
}
|
}
|
||||||
|
var arg2 *auth.PATAuthz
|
||||||
|
if args[2] != nil {
|
||||||
|
arg2 = args[2].(*auth.PATAuthz)
|
||||||
|
}
|
||||||
run(
|
run(
|
||||||
arg0,
|
arg0,
|
||||||
arg1,
|
arg1,
|
||||||
|
arg2,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
@@ -165,7 +171,7 @@ func (_c *Service_Authorize_Call) Return(err error) *Service_Authorize_Call {
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Service_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr policies.Policy) error) *Service_Authorize_Call {
|
func (_c *Service_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr policies.Policy, patAuthz *auth.PATAuthz) error) *Service_Authorize_Call {
|
||||||
_c.Call.Return(run)
|
_c.Call.Return(run)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -69,6 +69,7 @@ const (
|
|||||||
DashboardType
|
DashboardType
|
||||||
MessagesType
|
MessagesType
|
||||||
DomainsType
|
DomainsType
|
||||||
|
UsersType
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -78,6 +79,7 @@ const (
|
|||||||
DashboardsStr = "dashboards"
|
DashboardsStr = "dashboards"
|
||||||
MessagesStr = "messages"
|
MessagesStr = "messages"
|
||||||
DomainsStr = "domains"
|
DomainsStr = "domains"
|
||||||
|
UsersStr = "users"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (et EntityType) String() string {
|
func (et EntityType) String() string {
|
||||||
@@ -94,6 +96,8 @@ func (et EntityType) String() string {
|
|||||||
return MessagesStr
|
return MessagesStr
|
||||||
case DomainsType:
|
case DomainsType:
|
||||||
return DomainsStr
|
return DomainsStr
|
||||||
|
case UsersType:
|
||||||
|
return UsersStr
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("unknown domain entity type %d", et)
|
return fmt.Sprintf("unknown domain entity type %d", et)
|
||||||
}
|
}
|
||||||
@@ -113,6 +117,8 @@ func ParseEntityType(et string) (EntityType, error) {
|
|||||||
return MessagesType, nil
|
return MessagesType, nil
|
||||||
case DomainsStr:
|
case DomainsStr:
|
||||||
return DomainsType, nil
|
return DomainsType, nil
|
||||||
|
case UsersStr:
|
||||||
|
return UsersType, nil
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("unknown domain entity type %s", et)
|
return 0, fmt.Errorf("unknown domain entity type %s", et)
|
||||||
}
|
}
|
||||||
@@ -280,6 +286,16 @@ func (s *Scope) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PATAuthz represents the PAT authorization request fields.
|
||||||
|
type PATAuthz struct {
|
||||||
|
PatID string
|
||||||
|
UserID string
|
||||||
|
EntityType EntityType
|
||||||
|
EntityID string
|
||||||
|
Operation string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
// PAT represents Personal Access Token.
|
// PAT represents Personal Access Token.
|
||||||
type PAT struct {
|
type PAT struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
|
|||||||
+7
-11
@@ -56,7 +56,7 @@ type Authz interface {
|
|||||||
// `object`. Authorize returns a non-nil error if the subject has
|
// `object`. Authorize returns a non-nil error if the subject has
|
||||||
// no relation on the object (which simply means the operation is
|
// no relation on the object (which simply means the operation is
|
||||||
// denied).
|
// denied).
|
||||||
Authorize(ctx context.Context, pr policies.Policy) error
|
Authorize(ctx context.Context, pr policies.Policy, patAuthz *PATAuthz) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authn specifies an API that must be fulfilled by the domain service
|
// Authn specifies an API that must be fulfilled by the domain service
|
||||||
@@ -205,13 +205,9 @@ func (svc service) RetrieveJWKS() []PublicKeyInfo {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc service) Authorize(ctx context.Context, pr policies.Policy) error {
|
func (svc service) Authorize(ctx context.Context, pr policies.Policy, patAuthz *PATAuthz) error {
|
||||||
if pr.PatID != "" {
|
if patAuthz != nil {
|
||||||
entityType, err := ParseEntityType(pr.EntityType)
|
if err := svc.AuthorizePAT(ctx, patAuthz.UserID, patAuthz.PatID, patAuthz.EntityType, patAuthz.Domain, patAuthz.Operation, patAuthz.EntityID); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := svc.AuthorizePAT(ctx, pr.UserID, pr.PatID, entityType, pr.Domain, pr.Operation, pr.EntityID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,7 +332,7 @@ func (svc service) checkUserRole(ctx context.Context, key Key) (err error) {
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return errRoleAuth
|
return errRoleAuth
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -347,7 +343,7 @@ func (svc service) checkUserRole(ctx context.Context, key Key) (err error) {
|
|||||||
Permission: policies.MembershipPermission,
|
Permission: policies.MembershipPermission,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return errRoleAuth
|
return errRoleAuth
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -364,7 +360,7 @@ func (svc service) getUserRole(ctx context.Context, userID string) (role Role) {
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err == nil {
|
}, nil); err == nil {
|
||||||
rl = AdminRole
|
rl = AdminRole
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+105
-72
@@ -648,19 +648,20 @@ func TestAuthorize(t *testing.T) {
|
|||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
policyReq policies.Policy
|
policyReq policies.Policy
|
||||||
|
patAuthz *auth.PATAuthz
|
||||||
|
checkDomainPolicyReq policies.Policy
|
||||||
checkPolicyReq policies.Policy
|
checkPolicyReq policies.Policy
|
||||||
patEntityType auth.EntityType
|
patErr error
|
||||||
patScopeErr error
|
|
||||||
expectPATCheck bool
|
|
||||||
expectCheckPolicy bool
|
|
||||||
parseReq string
|
parseReq string
|
||||||
parseRes auth.Key
|
parseRes auth.Key
|
||||||
parseErr error
|
parseErr error
|
||||||
callBackErr error
|
callBackErr error
|
||||||
checkPolicyErr error
|
checkPolicyErr error
|
||||||
checkDomainPolicyErr error
|
checkDomainPolicyErr error
|
||||||
|
authorizePATErr error
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
|
|
||||||
{
|
{
|
||||||
desc: "authorize a user key successfully",
|
desc: "authorize a user key successfully",
|
||||||
policyReq: policies.Policy{
|
policyReq: policies.Policy{
|
||||||
@@ -677,41 +678,51 @@ func TestAuthorize(t *testing.T) {
|
|||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
},
|
},
|
||||||
expectCheckPolicy: true,
|
checkDomainPolicyReq: policies.Policy{
|
||||||
err: nil,
|
Subject: userID,
|
||||||
|
SubjectType: policies.UserType,
|
||||||
|
Object: validID,
|
||||||
|
ObjectType: policies.DomainType,
|
||||||
|
Permission: policies.MembershipPermission,
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "authorize with PAT scope successfully",
|
desc: "authorize with PAT successfully",
|
||||||
policyReq: policies.Policy{
|
policyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: policies.SuperMQObject,
|
Subject: userID,
|
||||||
ObjectType: policies.PlatformType,
|
Object: validID,
|
||||||
Permission: policies.AdminPermission,
|
ObjectType: policies.ClientType,
|
||||||
PatID: validID,
|
Permission: policies.ViewPermission,
|
||||||
UserID: userID,
|
|
||||||
EntityType: auth.ChannelsScopeStr,
|
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: auth.OpListChannels,
|
},
|
||||||
EntityID: auth.AnyIDs,
|
patAuthz: &auth.PATAuthz{
|
||||||
|
PatID: validID,
|
||||||
|
UserID: userID,
|
||||||
|
EntityType: auth.ClientsType,
|
||||||
|
EntityID: validID,
|
||||||
|
Operation: "read",
|
||||||
|
Domain: domainID,
|
||||||
|
},
|
||||||
|
checkDomainPolicyReq: policies.Policy{
|
||||||
|
Subject: userID,
|
||||||
|
SubjectType: policies.UserType,
|
||||||
|
Object: domainID,
|
||||||
|
ObjectType: policies.DomainType,
|
||||||
|
Permission: policies.MembershipPermission,
|
||||||
},
|
},
|
||||||
checkPolicyReq: policies.Policy{
|
checkPolicyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: policies.SuperMQObject,
|
Subject: userID,
|
||||||
ObjectType: policies.PlatformType,
|
Object: validID,
|
||||||
Permission: policies.AdminPermission,
|
ObjectType: policies.ClientType,
|
||||||
PatID: validID,
|
Permission: policies.ViewPermission,
|
||||||
UserID: userID,
|
|
||||||
EntityType: auth.ChannelsScopeStr,
|
|
||||||
Domain: domainID,
|
Domain: domainID,
|
||||||
Operation: auth.OpListChannels,
|
|
||||||
EntityID: auth.AnyIDs,
|
|
||||||
},
|
},
|
||||||
patEntityType: auth.ChannelsType,
|
err: nil,
|
||||||
expectPATCheck: true,
|
|
||||||
expectCheckPolicy: true,
|
|
||||||
err: nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "authorize with PAT scope check failure",
|
desc: "authorize with PAT scope check failure",
|
||||||
@@ -721,12 +732,14 @@ func TestAuthorize(t *testing.T) {
|
|||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
PatID: validID,
|
},
|
||||||
UserID: userID,
|
patAuthz: &auth.PATAuthz{
|
||||||
EntityType: auth.ChannelsScopeStr,
|
PatID: validID,
|
||||||
Domain: domainID,
|
UserID: userID,
|
||||||
Operation: auth.OpListChannels,
|
EntityType: auth.ChannelsType,
|
||||||
EntityID: auth.AnyIDs,
|
Domain: domainID,
|
||||||
|
Operation: auth.OpListChannels,
|
||||||
|
EntityID: auth.AnyIDs,
|
||||||
},
|
},
|
||||||
checkPolicyReq: policies.Policy{
|
checkPolicyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
@@ -734,17 +747,9 @@ func TestAuthorize(t *testing.T) {
|
|||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
PatID: validID,
|
|
||||||
UserID: userID,
|
|
||||||
EntityType: auth.ChannelsScopeStr,
|
|
||||||
Domain: domainID,
|
|
||||||
Operation: auth.OpListChannels,
|
|
||||||
EntityID: auth.AnyIDs,
|
|
||||||
},
|
},
|
||||||
patEntityType: auth.ChannelsType,
|
patErr: svcerr.ErrAuthorization,
|
||||||
patScopeErr: repoerr.ErrNotFound,
|
err: svcerr.ErrAuthorization,
|
||||||
expectPATCheck: true,
|
|
||||||
err: svcerr.ErrAuthorization,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "authorize with invalid PAT entity type",
|
desc: "authorize with invalid PAT entity type",
|
||||||
@@ -754,12 +759,14 @@ func TestAuthorize(t *testing.T) {
|
|||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
PatID: validID,
|
},
|
||||||
UserID: userID,
|
patAuthz: &auth.PATAuthz{
|
||||||
EntityType: "invalid",
|
PatID: validID,
|
||||||
Domain: domainID,
|
UserID: userID,
|
||||||
Operation: auth.OpListChannels,
|
EntityType: auth.EntityType(100),
|
||||||
EntityID: auth.AnyIDs,
|
Domain: domainID,
|
||||||
|
Operation: auth.OpListChannels,
|
||||||
|
EntityID: auth.AnyIDs,
|
||||||
},
|
},
|
||||||
checkPolicyReq: policies.Policy{
|
checkPolicyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
@@ -767,32 +774,55 @@ func TestAuthorize(t *testing.T) {
|
|||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
PatID: validID,
|
|
||||||
UserID: userID,
|
|
||||||
EntityType: "invalid",
|
|
||||||
Domain: domainID,
|
|
||||||
Operation: auth.OpListChannels,
|
|
||||||
EntityID: auth.AnyIDs,
|
|
||||||
},
|
},
|
||||||
err: errors.New("unknown domain entity type invalid"),
|
patErr: errors.New("unknown domain entity type invalid"),
|
||||||
|
err: errors.New("unknown domain entity type invalid"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
desc: "authorize invalid platform object",
|
desc: "authorize with PAT but PAT authorization fails",
|
||||||
policyReq: policies.Policy{
|
policyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: "invalid",
|
Subject: userID,
|
||||||
ObjectType: policies.PlatformType,
|
Object: validID,
|
||||||
Permission: policies.AdminPermission,
|
ObjectType: policies.ClientType,
|
||||||
|
Permission: policies.ViewPermission,
|
||||||
},
|
},
|
||||||
checkPolicyReq: policies.Policy{
|
patAuthz: &auth.PATAuthz{
|
||||||
|
PatID: validID,
|
||||||
|
UserID: userID,
|
||||||
|
EntityType: auth.ClientsType,
|
||||||
|
EntityID: validID,
|
||||||
|
Operation: "read",
|
||||||
|
Domain: domainID,
|
||||||
|
},
|
||||||
|
checkPolicyReq: policies.Policy{},
|
||||||
|
authorizePATErr: svcerr.ErrAuthorization,
|
||||||
|
err: svcerr.ErrAuthorization,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
desc: "authorize with PAT - PAT authorization fails but policy check not reached",
|
||||||
|
policyReq: policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: "invalid",
|
Subject: userID,
|
||||||
ObjectType: policies.PlatformType,
|
Object: validID,
|
||||||
Permission: policies.AdminPermission,
|
ObjectType: policies.ClientType,
|
||||||
|
Permission: policies.ViewPermission,
|
||||||
},
|
},
|
||||||
err: svcerr.ErrMalformedEntity,
|
patAuthz: &auth.PATAuthz{
|
||||||
|
PatID: validID,
|
||||||
|
UserID: userID,
|
||||||
|
EntityType: auth.ClientsType,
|
||||||
|
EntityID: validID,
|
||||||
|
Operation: "write",
|
||||||
|
Domain: domainID,
|
||||||
|
},
|
||||||
|
checkPolicyReq: policies.Policy{},
|
||||||
|
authorizePATErr: svcerr.ErrAuthorization,
|
||||||
|
err: svcerr.ErrAuthorization,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "authorize with policy check error",
|
desc: "authorize with policy check error",
|
||||||
@@ -810,23 +840,26 @@ func TestAuthorize(t *testing.T) {
|
|||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
},
|
},
|
||||||
checkPolicyErr: repoerr.ErrNotFound,
|
checkPolicyErr: repoerr.ErrNotFound,
|
||||||
expectCheckPolicy: true,
|
err: svcerr.ErrAuthorization,
|
||||||
err: svcerr.ErrAuthorization,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
var policyCall *mock.Call
|
var policyCall *mock.Call
|
||||||
if tc.expectCheckPolicy {
|
if tc.checkPolicyReq != (policies.Policy{}) {
|
||||||
policyCall = pEvaluator.On("CheckPolicy", mock.Anything, tc.checkPolicyReq).Return(tc.checkPolicyErr)
|
policyCall = pEvaluator.On("CheckPolicy", mock.Anything, tc.checkPolicyReq).Return(tc.checkPolicyErr)
|
||||||
}
|
}
|
||||||
var patCall *mock.Call
|
var patCall *mock.Call
|
||||||
if tc.expectPATCheck {
|
if tc.patAuthz != nil {
|
||||||
patCall = patsrepo.On("CheckScope", mock.Anything, tc.policyReq.UserID, tc.policyReq.PatID, tc.patEntityType, tc.policyReq.Domain, tc.policyReq.Operation, tc.policyReq.EntityID).Return(tc.patScopeErr)
|
patErr := tc.patErr
|
||||||
|
if patErr == nil {
|
||||||
|
patErr = tc.authorizePATErr
|
||||||
|
}
|
||||||
|
patCall = patsrepo.On("CheckScope", mock.Anything, tc.patAuthz.UserID, tc.patAuthz.PatID, tc.patAuthz.EntityType, tc.patAuthz.Domain, tc.patAuthz.Operation, tc.patAuthz.EntityID).Return(patErr)
|
||||||
}
|
}
|
||||||
repoCall := krepo.On("Remove", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
repoCall := krepo.On("Remove", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||||
err := svc.Authorize(context.Background(), tc.policyReq)
|
err := svc.Authorize(context.Background(), tc.policyReq, tc.patAuthz)
|
||||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
|
||||||
if policyCall != nil {
|
if policyCall != nil {
|
||||||
policyCall.Unset()
|
policyCall.Unset()
|
||||||
|
|||||||
@@ -326,9 +326,8 @@ func (am *authorizationMiddleware) RemoveParentGroup(ctx context.Context, sessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, req smqauthz.PolicyReq) error {
|
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, req smqauthz.PolicyReq) error {
|
||||||
req.UserID = session.UserID
|
|
||||||
req.PatID = session.PatID
|
|
||||||
req.Domain = session.DomainID
|
req.Domain = session.DomainID
|
||||||
|
|
||||||
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -336,14 +335,24 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.
|
|||||||
|
|
||||||
req.Permission = perm.String()
|
req.Permission = perm.String()
|
||||||
|
|
||||||
req.EntityID = req.Object
|
var pat *smqauthz.PATReq
|
||||||
req.EntityType = auth.ChannelsType.String()
|
if session.PatID != "" {
|
||||||
req.Operation = am.entitiesOps.OperationName(entityType, op)
|
entityID := req.Object
|
||||||
if op == operations.OpListUserChannels || op == dOperations.OpCreateDomainChannels || op == dOperations.OpListDomainChannels {
|
opName := am.entitiesOps.OperationName(entityType, op)
|
||||||
req.EntityID = auth.AnyIDs
|
if op == operations.OpListUserChannels || op == dOperations.OpCreateDomainChannels || op == dOperations.OpListDomainChannels {
|
||||||
|
entityID = auth.AnyIDs
|
||||||
|
}
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: entityID,
|
||||||
|
EntityType: auth.ChannelsType.String(),
|
||||||
|
Operation: opName,
|
||||||
|
Domain: session.DomainID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
if err := am.authz.Authorize(ctx, req, pat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +369,7 @@ func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -257,8 +257,6 @@ func (am *authorizationMiddleware) RemoveParentGroup(ctx context.Context, sessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, req smqauthz.PolicyReq) error {
|
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, req smqauthz.PolicyReq) error {
|
||||||
req.UserID = session.UserID
|
|
||||||
req.PatID = session.PatID
|
|
||||||
req.Domain = session.DomainID
|
req.Domain = session.DomainID
|
||||||
|
|
||||||
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
||||||
@@ -268,14 +266,24 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.
|
|||||||
|
|
||||||
req.Permission = perm.String()
|
req.Permission = perm.String()
|
||||||
|
|
||||||
req.EntityID = req.Object
|
var pat *smqauthz.PATReq
|
||||||
req.EntityType = auth.ClientsType.String()
|
if session.PatID != "" {
|
||||||
req.Operation = am.entitiesOps.OperationName(entityType, op)
|
entityID := req.Object
|
||||||
if op == operations.OpListUserClients || op == dOperations.OpCreateDomainClients || op == dOperations.OpListDomainClients {
|
opName := am.entitiesOps.OperationName(entityType, op)
|
||||||
req.EntityID = auth.AnyIDs
|
if op == operations.OpListUserClients || op == dOperations.OpCreateDomainClients || op == dOperations.OpListDomainClients {
|
||||||
|
entityID = auth.AnyIDs
|
||||||
|
}
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: entityID,
|
||||||
|
EntityType: auth.ClientsType.String(),
|
||||||
|
Operation: opName,
|
||||||
|
Domain: session.DomainID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
if err := am.authz.Authorize(ctx, req, pat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +300,7 @@ func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+1
-1
@@ -412,7 +412,7 @@ func createAdminPolicy(ctx context.Context, userID string, authz smqauthz.Author
|
|||||||
Permission: policies.AdministratorRelation,
|
Permission: policies.AdministratorRelation,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
err := policyService.AddPolicy(ctx, policies.Policy{
|
err := policyService.AddPolicy(ctx, policies.Policy{
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
Subject: userID,
|
Subject: userID,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/absmach/supermq/auth"
|
||||||
"github.com/absmach/supermq/domains"
|
"github.com/absmach/supermq/domains"
|
||||||
"github.com/absmach/supermq/domains/operations"
|
"github.com/absmach/supermq/domains/operations"
|
||||||
"github.com/absmach/supermq/pkg/authn"
|
"github.com/absmach/supermq/pkg/authn"
|
||||||
@@ -61,7 +62,7 @@ func (am *authorizationMiddleware) RetrieveDomain(ctx context.Context, session a
|
|||||||
return am.svc.RetrieveDomain(ctx, session, id, withRoles)
|
return am.svc.RetrieveDomain(ctx, session, id, withRoles)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpRetrieveDomain, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpRetrieveDomain, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -75,7 +76,7 @@ func (am *authorizationMiddleware) RetrieveDomain(ctx context.Context, session a
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) UpdateDomain(ctx context.Context, session authn.Session, id string, d domains.DomainReq) (domains.Domain, error) {
|
func (am *authorizationMiddleware) UpdateDomain(ctx context.Context, session authn.Session, id string, d domains.DomainReq) (domains.Domain, error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpUpdateDomain, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpUpdateDomain, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -89,7 +90,7 @@ func (am *authorizationMiddleware) UpdateDomain(ctx context.Context, session aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) EnableDomain(ctx context.Context, session authn.Session, id string) (domains.Domain, error) {
|
func (am *authorizationMiddleware) EnableDomain(ctx context.Context, session authn.Session, id string) (domains.Domain, error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpEnableDomain, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpEnableDomain, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -103,7 +104,7 @@ func (am *authorizationMiddleware) EnableDomain(ctx context.Context, session aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) DisableDomain(ctx context.Context, session authn.Session, id string) (domains.Domain, error) {
|
func (am *authorizationMiddleware) DisableDomain(ctx context.Context, session authn.Session, id string) (domains.Domain, error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpDisableDomain, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpDisableDomain, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -125,7 +126,7 @@ func (am *authorizationMiddleware) FreezeDomain(ctx context.Context, session aut
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return domains.Domain{}, err
|
return domains.Domain{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ func (am *authorizationMiddleware) ListDomains(ctx context.Context, session auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) SendInvitation(ctx context.Context, session authn.Session, invitation domains.Invitation) (domains.Invitation, error) {
|
func (am *authorizationMiddleware) SendInvitation(ctx context.Context, session authn.Session, invitation domains.Invitation) (domains.Invitation, error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpSendDomainInvitation, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpSendDomainInvitation, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -151,6 +152,10 @@ func (am *authorizationMiddleware) SendInvitation(ctx context.Context, session a
|
|||||||
return domains.Invitation{}, err
|
return domains.Invitation{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := am.checkAdmin(ctx, session); err != nil {
|
||||||
|
return domains.Invitation{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return am.svc.SendInvitation(ctx, session, invitation)
|
return am.svc.SendInvitation(ctx, session, invitation)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +164,7 @@ func (am *authorizationMiddleware) ListInvitations(ctx context.Context, session
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
|
func (am *authorizationMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpListDomainInvitations, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpListDomainInvitations, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -181,7 +186,7 @@ func (am *authorizationMiddleware) RejectInvitation(ctx context.Context, session
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) DeleteInvitation(ctx context.Context, session authn.Session, inviteeUserID, domainID string) (err error) {
|
func (am *authorizationMiddleware) DeleteInvitation(ctx context.Context, session authn.Session, inviteeUserID, domainID string) (err error) {
|
||||||
if err := am.authorize(ctx, policies.DomainType, operations.OpDeleteDomainInvitation, authz.PolicyReq{
|
if err := am.authorize(ctx, session, policies.DomainType, operations.OpDeleteDomainInvitation, authz.PolicyReq{
|
||||||
Subject: session.DomainUserID,
|
Subject: session.DomainUserID,
|
||||||
SubjectType: policies.UserType,
|
SubjectType: policies.UserType,
|
||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
@@ -194,7 +199,9 @@ func (am *authorizationMiddleware) DeleteInvitation(ctx context.Context, session
|
|||||||
return am.svc.DeleteInvitation(ctx, session, inviteeUserID, domainID)
|
return am.svc.DeleteInvitation(ctx, session, inviteeUserID, domainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) authorize(ctx context.Context, entityType string, op permissions.Operation, authReq authz.PolicyReq) error {
|
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, authReq authz.PolicyReq) error {
|
||||||
|
authReq.Domain = session.DomainID
|
||||||
|
|
||||||
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -202,13 +209,57 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, entityType str
|
|||||||
|
|
||||||
authReq.Permission = perm.String()
|
authReq.Permission = perm.String()
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, authReq); err != nil {
|
var pat *smqauthz.PATReq
|
||||||
|
if session.PatID != "" {
|
||||||
|
entityID := authReq.Object
|
||||||
|
opName := am.entitiesOps.OperationName(entityType, op)
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: entityID,
|
||||||
|
EntityType: auth.DomainsType.String(),
|
||||||
|
Operation: opName,
|
||||||
|
Domain: session.DomainID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := am.authz.Authorize(ctx, authReq, pat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkAdmin checks if the given user is a domain or platform administrator.
|
||||||
|
func (am *authorizationMiddleware) checkAdmin(ctx context.Context, session authn.Session) error {
|
||||||
|
req := smqauthz.PolicyReq{
|
||||||
|
SubjectType: policies.UserType,
|
||||||
|
SubjectKind: policies.UsersKind,
|
||||||
|
Subject: session.DomainUserID,
|
||||||
|
Permission: policies.AdminPermission,
|
||||||
|
ObjectType: policies.DomainType,
|
||||||
|
Object: session.DomainID,
|
||||||
|
}
|
||||||
|
if err := am.authz.Authorize(ctx, req, nil); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req = smqauthz.PolicyReq{
|
||||||
|
SubjectType: policies.UserType,
|
||||||
|
SubjectKind: policies.UsersKind,
|
||||||
|
Subject: session.UserID,
|
||||||
|
Permission: policies.AdminPermission,
|
||||||
|
ObjectType: policies.PlatformType,
|
||||||
|
Object: policies.SuperMQObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := am.authz.Authorize(ctx, req, nil); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return svcerr.ErrAuthorization
|
||||||
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session authn.Session) error {
|
func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session authn.Session) error {
|
||||||
if session.Role != authn.AdminRole {
|
if session.Role != authn.AdminRole {
|
||||||
return svcerr.ErrSuperAdminAction
|
return svcerr.ErrSuperAdminAction
|
||||||
@@ -219,7 +270,7 @@ func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -376,15 +376,13 @@ func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, pr smqauthz.PolicyReq) error {
|
func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.Session, entityType string, op permissions.Operation, pr smqauthz.PolicyReq) error {
|
||||||
pr.UserID = session.UserID
|
|
||||||
pr.PatID = session.PatID
|
|
||||||
pr.Domain = session.DomainID
|
pr.Domain = session.DomainID
|
||||||
|
|
||||||
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
perm, err := am.entitiesOps.GetPermission(entityType, op)
|
||||||
@@ -393,14 +391,24 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.
|
|||||||
}
|
}
|
||||||
pr.Permission = perm.String()
|
pr.Permission = perm.String()
|
||||||
|
|
||||||
pr.EntityID = pr.Object
|
var pat *smqauthz.PATReq
|
||||||
pr.EntityType = auth.GroupsType.String()
|
if session.PatID != "" {
|
||||||
pr.Operation = am.entitiesOps.OperationName(entityType, op)
|
entityID := pr.Object
|
||||||
if op == dOperations.OpListDomainGroups || op == dOperations.OpCreateDomainGroups {
|
opName := am.entitiesOps.OperationName(entityType, op)
|
||||||
pr.EntityID = auth.AnyIDs
|
if op == dOperations.OpListDomainGroups || op == dOperations.OpCreateDomainGroups {
|
||||||
|
entityID = auth.AnyIDs
|
||||||
|
}
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: entityID,
|
||||||
|
EntityType: auth.GroupsType.String(),
|
||||||
|
Operation: opName,
|
||||||
|
Domain: session.DomainID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, pr); err != nil {
|
if err := am.authz.Authorize(ctx, pr, pat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ option go_package = "github.com/absmach/supermq/api/grpc/auth/v1";
|
|||||||
// AuthService is a service that provides authentication
|
// AuthService is a service that provides authentication
|
||||||
// and authorization functionalities for SuperMQ services.
|
// and authorization functionalities for SuperMQ services.
|
||||||
service AuthService {
|
service AuthService {
|
||||||
rpc Authorize(PolicyReq) returns (AuthZRes) {}
|
rpc Authorize(AuthZReq) returns (AuthZRes) {}
|
||||||
rpc Authenticate(AuthNReq) returns (AuthNRes) {}
|
rpc Authenticate(AuthNReq) returns (AuthNRes) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +35,20 @@ message PolicyReq {
|
|||||||
string permission = 7;
|
string permission = 7;
|
||||||
string object = 8;
|
string object = 8;
|
||||||
string object_type = 9;
|
string object_type = 9;
|
||||||
string pat_id = 10;
|
}
|
||||||
string operation = 11;
|
|
||||||
string user_id = 12;
|
message PATReq {
|
||||||
string entity_id = 13;
|
string pat_id = 1;
|
||||||
string entity_type = 14;
|
string domain = 2;
|
||||||
|
string operation = 3;
|
||||||
|
string user_id = 4;
|
||||||
|
string entity_id = 5;
|
||||||
|
string entity_type = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AuthZReq {
|
||||||
|
PolicyReq policy_req = 1;
|
||||||
|
optional PATReq pat_req = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthZRes {
|
message AuthZRes {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (am *authorizationMiddleware) RetrieveAll(ctx context.Context, session smqa
|
|||||||
ObjectType: objectType,
|
ObjectType: objectType,
|
||||||
Object: object,
|
Object: object,
|
||||||
}
|
}
|
||||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
if err := am.authz.Authorize(ctx, req, nil); err != nil {
|
||||||
return journal.JournalsPage{}, err
|
return journal.JournalsPage{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ func (am *authorizationMiddleware) RetrieveClientTelemetry(ctx context.Context,
|
|||||||
Object: clientID,
|
Object: clientID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
if err := am.authz.Authorize(ctx, req, nil); err != nil {
|
||||||
return journal.ClientTelemetry{}, err
|
return journal.ClientTelemetry{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-34
@@ -46,7 +46,7 @@ func NewAuthorization(ctx context.Context, cfg grpcclient.Config, domainsAuthz p
|
|||||||
}, client, nil
|
}, client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a authorization) Authorize(ctx context.Context, pr authz.PolicyReq) error {
|
func (a authorization) Authorize(ctx context.Context, pr authz.PolicyReq, pat *authz.PATReq) error {
|
||||||
if pr.SubjectType == policies.UserType && (pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ClientType || pr.ObjectType == policies.DomainType) {
|
if pr.SubjectType == policies.UserType && (pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ClientType || pr.ObjectType == policies.DomainType) {
|
||||||
domainID := pr.Domain
|
domainID := pr.Domain
|
||||||
if domainID == "" {
|
if domainID == "" {
|
||||||
@@ -60,21 +60,29 @@ func (a authorization) Authorize(ctx context.Context, pr authz.PolicyReq) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req := grpcAuthV1.PolicyReq{
|
req := grpcAuthV1.AuthZReq{
|
||||||
Domain: pr.Domain,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: pr.SubjectType,
|
Domain: pr.Domain,
|
||||||
SubjectKind: pr.SubjectKind,
|
SubjectType: pr.SubjectType,
|
||||||
SubjectRelation: pr.SubjectRelation,
|
SubjectKind: pr.SubjectKind,
|
||||||
Subject: pr.Subject,
|
SubjectRelation: pr.SubjectRelation,
|
||||||
Relation: pr.Relation,
|
Subject: pr.Subject,
|
||||||
Permission: pr.Permission,
|
Relation: pr.Relation,
|
||||||
Object: pr.Object,
|
Permission: pr.Permission,
|
||||||
ObjectType: pr.ObjectType,
|
Object: pr.Object,
|
||||||
PatId: pr.PatID,
|
ObjectType: pr.ObjectType,
|
||||||
Operation: pr.Operation,
|
},
|
||||||
UserId: pr.UserID,
|
}
|
||||||
EntityId: pr.EntityID,
|
|
||||||
EntityType: pr.EntityType,
|
if pat != nil {
|
||||||
|
req.PatReq = &grpcAuthV1.PATReq{
|
||||||
|
PatId: pat.PatID,
|
||||||
|
Domain: pat.Domain,
|
||||||
|
Operation: pat.Operation,
|
||||||
|
UserId: pat.UserID,
|
||||||
|
EntityId: pat.EntityID,
|
||||||
|
EntityType: pat.EntityType,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := a.authSvcClient.Authorize(ctx, &req)
|
res, err := a.authSvcClient.Authorize(ctx, &req)
|
||||||
@@ -95,32 +103,38 @@ func (a authorization) checkDomain(ctx context.Context, subjectType, subject, do
|
|||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case domains.FreezeStatus:
|
case domains.FreezeStatus:
|
||||||
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.PolicyReq{
|
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.AuthZReq{
|
||||||
Subject: subject,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: subjectType,
|
Subject: subject,
|
||||||
Permission: policies.AdminPermission,
|
SubjectType: subjectType,
|
||||||
Object: policies.SuperMQObject,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
Object: policies.SuperMQObject,
|
||||||
|
ObjectType: policies.PlatformType,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
case domains.DisabledStatus:
|
case domains.DisabledStatus:
|
||||||
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.PolicyReq{
|
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.AuthZReq{
|
||||||
Subject: subject,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: subjectType,
|
Subject: subject,
|
||||||
Permission: policies.AdminPermission,
|
SubjectType: subjectType,
|
||||||
Object: domainID,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.DomainType,
|
Object: domainID,
|
||||||
|
ObjectType: policies.DomainType,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
case domains.EnabledStatus:
|
case domains.EnabledStatus:
|
||||||
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.PolicyReq{
|
_, err := a.authSvcClient.Authorize(ctx, &grpcAuthV1.AuthZReq{
|
||||||
Subject: subject,
|
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||||
SubjectType: subjectType,
|
Subject: subject,
|
||||||
Permission: policies.MembershipPermission,
|
SubjectType: subjectType,
|
||||||
Object: domainID,
|
Permission: policies.MembershipPermission,
|
||||||
ObjectType: policies.DomainType,
|
Object: domainID,
|
||||||
|
ObjectType: policies.DomainType,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|||||||
+21
-8
@@ -42,17 +42,30 @@ type PolicyReq struct {
|
|||||||
// Permission contains the permission. Supported permissions are admin, delete, edit, share, view,
|
// Permission contains the permission. Supported permissions are admin, delete, edit, share, view,
|
||||||
// membership, create, admin_only, edit_only, view_only, membership_only, ext_admin, ext_edit, ext_view.
|
// membership, create, admin_only, edit_only, view_only, membership_only, ext_admin, ext_edit, ext_view.
|
||||||
Permission string `json:"permission,omitempty"`
|
Permission string `json:"permission,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// PAT authorization fields
|
// PATReq represents a Personal Access Token authorization request.
|
||||||
UserID string `json:"user_id,omitempty"`
|
type PATReq struct {
|
||||||
PatID string `json:"pat_id,omitempty"`
|
// PatID contains the personal access token ID.
|
||||||
EntityType string `json:"entity_type,omitempty"`
|
PatID string `json:"pat_id"`
|
||||||
DomainID string `json:"domain_id,omitempty"`
|
|
||||||
Operation string `json:"operation,omitempty"`
|
// Domain contains the domain ID.
|
||||||
EntityID string `json:"entity_id,omitempty"`
|
Domain string `json:"domain"`
|
||||||
|
|
||||||
|
// Operation contains the operation type for PAT authorization.
|
||||||
|
Operation string `json:"operation"`
|
||||||
|
|
||||||
|
// UserID contains the user ID for PAT authorization.
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
|
||||||
|
// EntityID contains the entity ID for PAT authorization.
|
||||||
|
EntityID string `json:"entity_id"`
|
||||||
|
|
||||||
|
// EntityType contains the entity type for PAT authorization.
|
||||||
|
EntityType string `json:"entity_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authz is supermq authorization library.
|
// Authz is supermq authorization library.
|
||||||
type Authorization interface {
|
type Authorization interface {
|
||||||
Authorize(ctx context.Context, pr PolicyReq) error
|
Authorize(ctx context.Context, pr PolicyReq, pat *PATReq) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,16 +43,16 @@ func (_m *Authorization) EXPECT() *Authorization_Expecter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authorize provides a mock function for the type Authorization
|
// Authorize provides a mock function for the type Authorization
|
||||||
func (_mock *Authorization) Authorize(ctx context.Context, pr authz.PolicyReq) error {
|
func (_mock *Authorization) Authorize(ctx context.Context, pr authz.PolicyReq, pat *authz.PATReq) error {
|
||||||
ret := _mock.Called(ctx, pr)
|
ret := _mock.Called(ctx, pr, pat)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Authorize")
|
panic("no return value specified for Authorize")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if returnFunc, ok := ret.Get(0).(func(context.Context, authz.PolicyReq) error); ok {
|
if returnFunc, ok := ret.Get(0).(func(context.Context, authz.PolicyReq, *authz.PATReq) error); ok {
|
||||||
r0 = returnFunc(ctx, pr)
|
r0 = returnFunc(ctx, pr, pat)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
@@ -67,11 +67,12 @@ type Authorization_Authorize_Call struct {
|
|||||||
// Authorize is a helper method to define mock.On call
|
// Authorize is a helper method to define mock.On call
|
||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - pr authz.PolicyReq
|
// - pr authz.PolicyReq
|
||||||
func (_e *Authorization_Expecter) Authorize(ctx interface{}, pr interface{}) *Authorization_Authorize_Call {
|
// - pat *authz.PATReq
|
||||||
return &Authorization_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr)}
|
func (_e *Authorization_Expecter) Authorize(ctx interface{}, pr interface{}, pat interface{}) *Authorization_Authorize_Call {
|
||||||
|
return &Authorization_Authorize_Call{Call: _e.mock.On("Authorize", ctx, pr, pat)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Authorization_Authorize_Call) Run(run func(ctx context.Context, pr authz.PolicyReq)) *Authorization_Authorize_Call {
|
func (_c *Authorization_Authorize_Call) Run(run func(ctx context.Context, pr authz.PolicyReq, pat *authz.PATReq)) *Authorization_Authorize_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
var arg0 context.Context
|
var arg0 context.Context
|
||||||
if args[0] != nil {
|
if args[0] != nil {
|
||||||
@@ -81,9 +82,14 @@ func (_c *Authorization_Authorize_Call) Run(run func(ctx context.Context, pr aut
|
|||||||
if args[1] != nil {
|
if args[1] != nil {
|
||||||
arg1 = args[1].(authz.PolicyReq)
|
arg1 = args[1].(authz.PolicyReq)
|
||||||
}
|
}
|
||||||
|
var arg2 *authz.PATReq
|
||||||
|
if args[2] != nil {
|
||||||
|
arg2 = args[2].(*authz.PATReq)
|
||||||
|
}
|
||||||
run(
|
run(
|
||||||
arg0,
|
arg0,
|
||||||
arg1,
|
arg1,
|
||||||
|
arg2,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
@@ -94,7 +100,7 @@ func (_c *Authorization_Authorize_Call) Return(err error) *Authorization_Authori
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Authorization_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr authz.PolicyReq) error) *Authorization_Authorize_Call {
|
func (_c *Authorization_Authorize_Call) RunAndReturn(run func(ctx context.Context, pr authz.PolicyReq, pat *authz.PATReq) error) *Authorization_Authorize_Call {
|
||||||
_c.Call.Return(run)
|
_c.Call.Return(run)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,19 +49,6 @@ type Policy struct {
|
|||||||
// Permission contains the permission. Supported permissions are admin, delete, edit, share, view,
|
// Permission contains the permission. Supported permissions are admin, delete, edit, share, view,
|
||||||
// membership, create, admin_only, edit_only, view_only, membership_only, ext_admin, ext_edit, ext_view.
|
// membership, create, admin_only, edit_only, view_only, membership_only, ext_admin, ext_edit, ext_view.
|
||||||
Permission string `json:"permission,omitempty"`
|
Permission string `json:"permission,omitempty"`
|
||||||
|
|
||||||
// PAT authorization fields
|
|
||||||
|
|
||||||
// PatID contains the personal access token ID.
|
|
||||||
PatID string `json:"pat_id,omitempty"`
|
|
||||||
// Operation contains the operation type for PAT authorization.
|
|
||||||
Operation string `json:"operation,omitempty"`
|
|
||||||
// UserID contains the user ID for PAT authorization.
|
|
||||||
UserID string `json:"user_id,omitempty"`
|
|
||||||
// EntityType contains the entity type for PAT authorization.
|
|
||||||
EntityType string `json:"entity_type,omitempty"`
|
|
||||||
// EntityID contains the entity ID for PAT authorization.
|
|
||||||
EntityID string `json:"entity_id,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr Policy) String() string {
|
func (pr Policy) String() string {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/absmach/supermq/auth"
|
"github.com/absmach/supermq/auth"
|
||||||
"github.com/absmach/supermq/pkg/authn"
|
"github.com/absmach/supermq/pkg/authn"
|
||||||
@@ -293,8 +294,6 @@ func (ram RoleManagerAuthorizationMiddleware) RoleRemoveMembers(ctx context.Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ram RoleManagerAuthorizationMiddleware) authorize(ctx context.Context, session authn.Session, op permissions.RoleOperation, pr smqauthz.PolicyReq) error {
|
func (ram RoleManagerAuthorizationMiddleware) authorize(ctx context.Context, session authn.Session, op permissions.RoleOperation, pr smqauthz.PolicyReq) error {
|
||||||
pr.UserID = session.UserID
|
|
||||||
pr.PatID = session.PatID
|
|
||||||
pr.Domain = session.DomainID
|
pr.Domain = session.DomainID
|
||||||
|
|
||||||
perm, err := ram.ops.GetPermission(op)
|
perm, err := ram.ops.GetPermission(op)
|
||||||
@@ -304,19 +303,31 @@ func (ram RoleManagerAuthorizationMiddleware) authorize(ctx context.Context, ses
|
|||||||
|
|
||||||
pr.Permission = perm.String()
|
pr.Permission = perm.String()
|
||||||
|
|
||||||
pr.EntityID = pr.Object
|
var pat *smqauthz.PATReq
|
||||||
opName := ram.ops.OperationName(op)
|
if session.PatID != "" {
|
||||||
switch pr.ObjectType {
|
opName := ram.ops.OperationName(op)
|
||||||
case policies.GroupType:
|
var patEntityType string
|
||||||
pr.EntityType = auth.GroupsType.String()
|
switch pr.ObjectType {
|
||||||
case policies.ClientType:
|
case policies.GroupType:
|
||||||
pr.EntityType = auth.ClientsType.String()
|
patEntityType = auth.GroupsType.String()
|
||||||
case policies.ChannelType:
|
case policies.ClientType:
|
||||||
pr.EntityType = auth.ChannelsType.String()
|
patEntityType = auth.ClientsType.String()
|
||||||
|
case policies.ChannelType:
|
||||||
|
patEntityType = auth.ChannelsType.String()
|
||||||
|
default:
|
||||||
|
return errors.Wrap(errors.ErrAuthorization, fmt.Errorf("unsupported entity type for PAT: %s", pr.ObjectType))
|
||||||
|
}
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: pr.Object,
|
||||||
|
EntityType: patEntityType,
|
||||||
|
Operation: auth.RoleOperationPrefix + opName,
|
||||||
|
Domain: session.DomainID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pr.Operation = auth.RoleOperationPrefix + opName
|
|
||||||
|
|
||||||
if err := ram.authz.Authorize(ctx, pr); err != nil {
|
if err := ram.authz.Authorize(ctx, pr, pat); err != nil {
|
||||||
return errors.Wrap(errors.ErrAuthorization, err)
|
return errors.Wrap(errors.ErrAuthorization, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +349,7 @@ func (ram RoleManagerAuthorizationMiddleware) validateMembers(ctx context.Contex
|
|||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return errors.Wrap(errors.ErrMissingMember, err)
|
return errors.Wrap(errors.ErrMissingMember, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,7 +364,7 @@ func (ram RoleManagerAuthorizationMiddleware) validateMembers(ctx context.Contex
|
|||||||
SubjectKind: policies.UsersKind,
|
SubjectKind: policies.UsersKind,
|
||||||
Object: session.DomainID,
|
Object: session.DomainID,
|
||||||
ObjectType: policies.DomainType,
|
ObjectType: policies.DomainType,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return errors.Wrap(errors.ErrMissingDomainMember, err)
|
return errors.Wrap(errors.ErrMissingDomainMember, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
|
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
|
||||||
|
"github.com/absmach/supermq/auth"
|
||||||
"github.com/absmach/supermq/pkg/authn"
|
"github.com/absmach/supermq/pkg/authn"
|
||||||
smqauthz "github.com/absmach/supermq/pkg/authz"
|
smqauthz "github.com/absmach/supermq/pkg/authz"
|
||||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||||
@@ -190,7 +191,7 @@ func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, session
|
|||||||
Permission: policies.AdminPermission,
|
Permission: policies.AdminPermission,
|
||||||
ObjectType: policies.PlatformType,
|
ObjectType: policies.PlatformType,
|
||||||
Object: policies.SuperMQObject,
|
Object: policies.SuperMQObject,
|
||||||
}); err != nil {
|
}, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -207,7 +208,19 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, session authn.
|
|||||||
Object: obj,
|
Object: obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
var pat *smqauthz.PATReq
|
||||||
|
if session.PatID != "" {
|
||||||
|
pat = &smqauthz.PATReq{
|
||||||
|
UserID: session.UserID,
|
||||||
|
PatID: session.PatID,
|
||||||
|
EntityID: subj,
|
||||||
|
EntityType: auth.UsersType.String(),
|
||||||
|
Operation: perm,
|
||||||
|
Domain: domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := am.authz.Authorize(ctx, req, pat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user