mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 06:40:19 +00:00
MG-1529 - User Removal (#2122)
Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
This commit is contained in:
@@ -178,6 +178,32 @@ paths:
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
summary: Delete a user
|
||||
description: |
|
||||
Delete a specific user that is identifier by the user ID.
|
||||
tags:
|
||||
- Users
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/UserID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"204":
|
||||
description: User deleted.
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"405":
|
||||
description: Method not allowed.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/users/{userID}/tags:
|
||||
patch:
|
||||
operationId: updateUserTags
|
||||
|
||||
+395
-378
File diff suppressed because it is too large
Load Diff
+9
-5
@@ -23,8 +23,8 @@ service AuthService {
|
||||
rpc Authorize(AuthorizeReq) returns (AuthorizeRes) {}
|
||||
rpc AddPolicy(AddPolicyReq) returns (AddPolicyRes) {}
|
||||
rpc AddPolicies(AddPoliciesReq) returns (AddPoliciesRes) {}
|
||||
rpc DeletePolicyFilter(DeletePolicyFilterReq) returns (DeletePolicyFilterRes) {}
|
||||
rpc DeletePolicies(DeletePoliciesReq) returns (DeletePoliciesRes) {}
|
||||
rpc DeletePolicyFilter(DeletePolicyFilterReq) returns (DeletePolicyRes) {}
|
||||
rpc DeletePolicies(DeletePoliciesReq) returns (DeletePolicyRes) {}
|
||||
rpc ListObjects(ListObjectsReq) returns (ListObjectsRes) {}
|
||||
rpc ListAllObjects(ListObjectsReq) returns (ListObjectsRes) {}
|
||||
rpc CountObjects(CountObjectsReq) returns (CountObjectsRes) {}
|
||||
@@ -32,6 +32,7 @@ service AuthService {
|
||||
rpc ListAllSubjects(ListSubjectsReq) returns (ListSubjectsRes) {}
|
||||
rpc CountSubjects(CountSubjectsReq) returns (CountSubjectsRes) {}
|
||||
rpc ListPermissions(ListPermissionsReq) returns (ListPermissionsRes) {}
|
||||
rpc DeleteEntityPolicies(DeleteEntityPoliciesReq) returns (DeletePolicyRes) {}
|
||||
}
|
||||
|
||||
// If a token is not carrying any information itself, the type
|
||||
@@ -115,8 +116,6 @@ message DeletePolicyFilterReq {
|
||||
string object_type = 10;
|
||||
}
|
||||
|
||||
message DeletePolicyFilterRes { bool deleted = 1; }
|
||||
|
||||
message DeletePoliciesReq {
|
||||
repeated DeletePolicyReq deletePoliciesReq = 1;
|
||||
}
|
||||
@@ -134,7 +133,7 @@ message DeletePolicyReq {
|
||||
string object_type = 10;
|
||||
}
|
||||
|
||||
message DeletePoliciesRes { bool deleted = 1; }
|
||||
message DeletePolicyRes { bool deleted = 1; }
|
||||
|
||||
message ListObjectsReq {
|
||||
string domain = 1;
|
||||
@@ -219,3 +218,8 @@ message ListPermissionsRes {
|
||||
string object_type = 6;
|
||||
repeated string permissions = 7;
|
||||
}
|
||||
|
||||
message DeleteEntityPoliciesReq{
|
||||
string entity_type = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
+68
-30
@@ -24,22 +24,23 @@ const svcName = "magistrala.AuthService"
|
||||
var _ magistrala.AuthServiceClient = (*grpcClient)(nil)
|
||||
|
||||
type grpcClient struct {
|
||||
issue endpoint.Endpoint
|
||||
refresh endpoint.Endpoint
|
||||
identify endpoint.Endpoint
|
||||
authorize endpoint.Endpoint
|
||||
addPolicy endpoint.Endpoint
|
||||
addPolicies endpoint.Endpoint
|
||||
deletePolicyFilter endpoint.Endpoint
|
||||
deletePolicies endpoint.Endpoint
|
||||
listObjects endpoint.Endpoint
|
||||
listAllObjects endpoint.Endpoint
|
||||
countObjects endpoint.Endpoint
|
||||
listSubjects endpoint.Endpoint
|
||||
listAllSubjects endpoint.Endpoint
|
||||
countSubjects endpoint.Endpoint
|
||||
listPermissions endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
issue endpoint.Endpoint
|
||||
refresh endpoint.Endpoint
|
||||
identify endpoint.Endpoint
|
||||
authorize endpoint.Endpoint
|
||||
addPolicy endpoint.Endpoint
|
||||
addPolicies endpoint.Endpoint
|
||||
deletePolicyFilter endpoint.Endpoint
|
||||
deletePolicies endpoint.Endpoint
|
||||
listObjects endpoint.Endpoint
|
||||
listAllObjects endpoint.Endpoint
|
||||
countObjects endpoint.Endpoint
|
||||
listSubjects endpoint.Endpoint
|
||||
listAllSubjects endpoint.Endpoint
|
||||
countSubjects endpoint.Endpoint
|
||||
listPermissions endpoint.Endpoint
|
||||
deleteEntityPolicies endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// NewClient returns new gRPC client instance.
|
||||
@@ -99,7 +100,7 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServ
|
||||
"DeletePolicyFilter",
|
||||
encodeDeletePolicyFilterRequest,
|
||||
decodeDeletePolicyFilterResponse,
|
||||
magistrala.DeletePolicyFilterRes{},
|
||||
magistrala.DeletePolicyRes{},
|
||||
).Endpoint(),
|
||||
deletePolicies: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -107,7 +108,7 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServ
|
||||
"DeletePolicies",
|
||||
encodeDeletePoliciesRequest,
|
||||
decodeDeletePoliciesResponse,
|
||||
magistrala.DeletePoliciesRes{},
|
||||
magistrala.DeletePolicyRes{},
|
||||
).Endpoint(),
|
||||
listObjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -165,6 +166,14 @@ func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServ
|
||||
decodeListPermissionsResponse,
|
||||
magistrala.ListPermissionsRes{},
|
||||
).Endpoint(),
|
||||
deleteEntityPolicies: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"DeleteEntityPolicies",
|
||||
encodeDeleteEntityPoliciesRequest,
|
||||
decodeDeleteEntityPoliciesResponse,
|
||||
magistrala.DeletePolicyRes{},
|
||||
).Endpoint(),
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
@@ -379,7 +388,7 @@ func encodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface
|
||||
return &magistrala.AddPoliciesReq{AddPoliciesReq: addPolicies}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyFilterRes, error) {
|
||||
func (client grpcClient) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -395,16 +404,16 @@ func (client grpcClient) DeletePolicyFilter(ctx context.Context, in *magistrala.
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.DeletePolicyFilterRes{}, decodeError(err)
|
||||
return &magistrala.DeletePolicyRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
dpr := res.(deletePolicyFilterRes)
|
||||
return &magistrala.DeletePolicyFilterRes{Deleted: dpr.deleted}, nil
|
||||
dpr := res.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: dpr.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePolicyFilterResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.DeletePolicyFilterRes)
|
||||
return deletePolicyFilterRes{deleted: res.GetDeleted()}, nil
|
||||
res := grpcRes.(*magistrala.DeletePolicyRes)
|
||||
return deletePolicyRes{deleted: res.GetDeleted()}, nil
|
||||
}
|
||||
|
||||
func encodeDeletePolicyFilterRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -422,7 +431,7 @@ func encodeDeletePolicyFilterRequest(_ context.Context, grpcReq interface{}) (in
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) {
|
||||
func (client grpcClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
r := policiesReq{}
|
||||
@@ -444,16 +453,16 @@ func (client grpcClient) DeletePolicies(ctx context.Context, in *magistrala.Dele
|
||||
}
|
||||
res, err := client.deletePolicies(ctx, r)
|
||||
if err != nil {
|
||||
return &magistrala.DeletePoliciesRes{}, decodeError(err)
|
||||
return &magistrala.DeletePolicyRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
dpr := res.(deletePoliciesRes)
|
||||
return &magistrala.DeletePoliciesRes{Deleted: dpr.deleted}, nil
|
||||
dpr := res.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: dpr.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.DeletePoliciesRes)
|
||||
return deletePoliciesRes{deleted: res.GetDeleted()}, nil
|
||||
res := grpcRes.(*magistrala.DeletePolicyRes)
|
||||
return deletePolicyRes{deleted: res.GetDeleted()}, nil
|
||||
}
|
||||
|
||||
func encodeDeletePoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -730,6 +739,35 @@ func encodeListPermissionsRequest(_ context.Context, grpcReq interface{}) (inter
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) DeleteEntityPolicies(ctx context.Context, in *magistrala.DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.deleteEntityPolicies(ctx, deleteEntityPoliciesReq{
|
||||
EntityType: in.GetEntityType(),
|
||||
ID: in.GetId(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.DeletePolicyRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
dpr := res.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: dpr.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeleteEntityPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.DeletePolicyRes)
|
||||
return deletePolicyRes{deleted: res.GetDeleted()}, nil
|
||||
}
|
||||
|
||||
func encodeDeleteEntityPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(deleteEntityPoliciesReq)
|
||||
return &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: req.EntityType,
|
||||
Id: req.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeError(err error) error {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
|
||||
@@ -155,7 +155,7 @@ func deletePolicyFilterEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(policyReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return deletePolicyFilterRes{}, err
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
|
||||
err := svc.DeletePolicyFilter(ctx, auth.PolicyReq{
|
||||
@@ -170,9 +170,9 @@ func deletePolicyFilterEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return deletePolicyFilterRes{}, err
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
return deletePolicyFilterRes{deleted: true}, nil
|
||||
return deletePolicyRes{deleted: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func deletePoliciesEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
reqs := request.(policiesReq)
|
||||
if err := reqs.validate(); err != nil {
|
||||
return deletePoliciesRes{}, err
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
|
||||
prs := []auth.PolicyReq{}
|
||||
@@ -200,9 +200,9 @@ func deletePoliciesEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
if err := svc.DeletePolicies(ctx, prs); err != nil {
|
||||
return deletePoliciesRes{}, err
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
return deletePoliciesRes{deleted: true}, nil
|
||||
return deletePolicyRes{deleted: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,3 +349,18 @@ func listPermissionsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func deleteEntityPoliciesEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(deleteEntityPoliciesReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
|
||||
if err := svc.DeleteEntityPolicies(ctx, req.EntityType, req.ID); err != nil {
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
|
||||
return deletePolicyRes{deleted: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ func TestDeletePolicyFilter(t *testing.T) {
|
||||
desc string
|
||||
token string
|
||||
deletePolicyFilterReq *magistrala.DeletePolicyFilterReq
|
||||
deletePolicyFilterRes *magistrala.DeletePolicyFilterRes
|
||||
deletePolicyFilterRes *magistrala.DeletePolicyRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -485,7 +485,7 @@ func TestDeletePolicyFilter(t *testing.T) {
|
||||
Relation: readRelation,
|
||||
Permission: readRelation,
|
||||
},
|
||||
deletePolicyFilterRes: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyFilterRes: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -499,7 +499,7 @@ func TestDeletePolicyFilter(t *testing.T) {
|
||||
Relation: readRelation,
|
||||
Permission: readRelation,
|
||||
},
|
||||
deletePolicyFilterRes: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyFilterRes: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
}
|
||||
@@ -524,7 +524,7 @@ func TestDeletePolicies(t *testing.T) {
|
||||
desc string
|
||||
token string
|
||||
deletePoliciesReq *magistrala.DeletePoliciesReq
|
||||
deletePoliciesRes *magistrala.DeletePoliciesRes
|
||||
deletePoliciesRes *magistrala.DeletePolicyRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -542,7 +542,7 @@ func TestDeletePolicies(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -560,7 +560,7 @@ func TestDeletePolicies(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{Deleted: false},
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
}
|
||||
@@ -1010,3 +1010,53 @@ func TestListPermissions(t *testing.T) {
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteEntityPolicies(t *testing.T) {
|
||||
conn, err := grpc.Dial(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
client := grpcapi.NewClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
deleteEntityPoliciesReq *magistrala.DeleteEntityPoliciesReq
|
||||
deletePolicyRes *magistrala.DeletePolicyRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete valid req",
|
||||
token: validToken,
|
||||
deleteEntityPoliciesReq: &magistrala.DeleteEntityPoliciesReq{
|
||||
Id: id,
|
||||
EntityType: usersType,
|
||||
},
|
||||
deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete invalid req with invalid token",
|
||||
token: inValidToken,
|
||||
deleteEntityPoliciesReq: &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: usersType,
|
||||
},
|
||||
deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "delete invalid req with invalid token",
|
||||
token: inValidToken,
|
||||
deleteEntityPoliciesReq: &magistrala.DeleteEntityPoliciesReq{
|
||||
Id: id,
|
||||
},
|
||||
deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
err: apiutil.ErrMissingPolicyEntityType,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
repoCall := svc.On("DeleteEntityPolicies", mock.Anything, tc.deleteEntityPoliciesReq.EntityType, tc.deleteEntityPoliciesReq.Id).Return(tc.err)
|
||||
dpr, err := client.DeleteEntityPolicies(context.Background(), tc.deleteEntityPoliciesReq)
|
||||
assert.Equal(t, tc.deletePolicyRes.GetDeleted(), dpr.GetDeleted(), fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.deletePolicyRes.GetDeleted(), dpr.GetDeleted()))
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,3 +158,19 @@ type listPermissionsReq struct {
|
||||
Object string
|
||||
FilterPermissions []string
|
||||
}
|
||||
|
||||
type deleteEntityPoliciesReq struct {
|
||||
EntityType string
|
||||
ID string
|
||||
}
|
||||
|
||||
func (req deleteEntityPoliciesReq) validate() error {
|
||||
if req.ID == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
if req.EntityType == "" {
|
||||
return apiutil.ErrMissingPolicyEntityType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ type addPoliciesRes struct {
|
||||
added bool
|
||||
}
|
||||
|
||||
type deletePolicyFilterRes struct {
|
||||
deleted bool
|
||||
}
|
||||
|
||||
type deletePoliciesRes struct {
|
||||
type deletePolicyRes struct {
|
||||
deleted bool
|
||||
}
|
||||
|
||||
|
||||
+50
-23
@@ -20,21 +20,22 @@ var _ magistrala.AuthServiceServer = (*grpcServer)(nil)
|
||||
|
||||
type grpcServer struct {
|
||||
magistrala.UnimplementedAuthServiceServer
|
||||
issue kitgrpc.Handler
|
||||
refresh kitgrpc.Handler
|
||||
identify kitgrpc.Handler
|
||||
authorize kitgrpc.Handler
|
||||
addPolicy kitgrpc.Handler
|
||||
addPolicies kitgrpc.Handler
|
||||
deletePolicyFilter kitgrpc.Handler
|
||||
deletePolicies kitgrpc.Handler
|
||||
listObjects kitgrpc.Handler
|
||||
listAllObjects kitgrpc.Handler
|
||||
countObjects kitgrpc.Handler
|
||||
listSubjects kitgrpc.Handler
|
||||
listAllSubjects kitgrpc.Handler
|
||||
countSubjects kitgrpc.Handler
|
||||
listPermissions kitgrpc.Handler
|
||||
issue kitgrpc.Handler
|
||||
refresh kitgrpc.Handler
|
||||
identify kitgrpc.Handler
|
||||
authorize kitgrpc.Handler
|
||||
addPolicy kitgrpc.Handler
|
||||
addPolicies kitgrpc.Handler
|
||||
deletePolicyFilter kitgrpc.Handler
|
||||
deletePolicies kitgrpc.Handler
|
||||
listObjects kitgrpc.Handler
|
||||
listAllObjects kitgrpc.Handler
|
||||
countObjects kitgrpc.Handler
|
||||
listSubjects kitgrpc.Handler
|
||||
listAllSubjects kitgrpc.Handler
|
||||
countSubjects kitgrpc.Handler
|
||||
listPermissions kitgrpc.Handler
|
||||
deleteEntityPolicies kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewServer returns new AuthServiceServer instance.
|
||||
@@ -115,6 +116,11 @@ func NewServer(svc auth.Service) magistrala.AuthServiceServer {
|
||||
decodeListPermissionsRequest,
|
||||
encodeListPermissionsResponse,
|
||||
),
|
||||
deleteEntityPolicies: kitgrpc.NewServer(
|
||||
(deleteEntityPoliciesEndpoint(svc)),
|
||||
decodeDeleteEntityPoliciesRequest,
|
||||
encodeDeleteEntityPoliciesResponse,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,20 +172,20 @@ func (s *grpcServer) AddPolicies(ctx context.Context, req *magistrala.AddPolicie
|
||||
return res.(*magistrala.AddPoliciesRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DeletePolicyFilter(ctx context.Context, req *magistrala.DeletePolicyFilterReq) (*magistrala.DeletePolicyFilterRes, error) {
|
||||
func (s *grpcServer) DeletePolicyFilter(ctx context.Context, req *magistrala.DeletePolicyFilterReq) (*magistrala.DeletePolicyRes, error) {
|
||||
_, res, err := s.deletePolicyFilter.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.DeletePolicyFilterRes), nil
|
||||
return res.(*magistrala.DeletePolicyRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DeletePolicies(ctx context.Context, req *magistrala.DeletePoliciesReq) (*magistrala.DeletePoliciesRes, error) {
|
||||
func (s *grpcServer) DeletePolicies(ctx context.Context, req *magistrala.DeletePoliciesReq) (*magistrala.DeletePolicyRes, error) {
|
||||
_, res, err := s.deletePolicies.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.DeletePoliciesRes), nil
|
||||
return res.(*magistrala.DeletePolicyRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListObjects(ctx context.Context, req *magistrala.ListObjectsReq) (*magistrala.ListObjectsRes, error) {
|
||||
@@ -238,6 +244,14 @@ func (s *grpcServer) ListPermissions(ctx context.Context, req *magistrala.ListPe
|
||||
return res.(*magistrala.ListPermissionsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DeleteEntityPolicies(ctx context.Context, req *magistrala.DeleteEntityPoliciesReq) (*magistrala.DeletePolicyRes, error) {
|
||||
_, res, err := s.deleteEntityPolicies.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.DeletePolicyRes), nil
|
||||
}
|
||||
|
||||
func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.IssueReq)
|
||||
return issueReq{
|
||||
@@ -351,8 +365,8 @@ func decodeDeletePolicyFilterRequest(_ context.Context, grpcReq interface{}) (in
|
||||
}
|
||||
|
||||
func encodeDeletePolicyFilterResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(deletePolicyFilterRes)
|
||||
return &magistrala.DeletePolicyFilterRes{Deleted: res.deleted}, nil
|
||||
res := grpcRes.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -375,8 +389,8 @@ func decodeDeletePoliciesRequest(_ context.Context, grpcReq interface{}) (interf
|
||||
}
|
||||
|
||||
func encodeDeletePoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(deletePoliciesRes)
|
||||
return &magistrala.DeletePoliciesRes{Deleted: res.deleted}, nil
|
||||
res := grpcRes.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeListObjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
@@ -479,6 +493,19 @@ func encodeListPermissionsResponse(_ context.Context, grpcRes interface{}) (inte
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeDeleteEntityPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.DeleteEntityPoliciesReq)
|
||||
return deleteEntityPoliciesReq{
|
||||
EntityType: req.GetEntityType(),
|
||||
ID: req.GetId(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeDeleteEntityPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil
|
||||
}
|
||||
|
||||
func encodeError(err error) error {
|
||||
switch {
|
||||
case errors.Contains(err, nil):
|
||||
|
||||
@@ -490,3 +490,20 @@ func (lm *loggingMiddleware) ListUserDomains(ctx context.Context, token, userID
|
||||
}(time.Now())
|
||||
return lm.svc.ListUserDomains(ctx, token, userID, page)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) DeleteEntityPolicies(ctx context.Context, entityType, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("entity_type", entityType),
|
||||
slog.String("id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Delete entity policies failed to complete successfully", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Delete entity policies completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.DeleteEntityPolicies(ctx, entityType, id)
|
||||
}
|
||||
|
||||
@@ -239,3 +239,11 @@ func (ms *metricsMiddleware) ListUserDomains(ctx context.Context, token, userID
|
||||
}(time.Now())
|
||||
return ms.svc.ListUserDomains(ctx, token, userID, page)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) DeleteEntityPolicies(ctx context.Context, entityType, id string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "delete_entity_policies").Add(1)
|
||||
ms.latency.With("method", "delete_entity_policies").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.DeleteEntityPolicies(ctx, entityType, id)
|
||||
}
|
||||
|
||||
@@ -199,4 +199,7 @@ type DomainsRepository interface {
|
||||
|
||||
// CheckPolicy check policy in domains database.
|
||||
CheckPolicy(ctx context.Context, pc Policy) error
|
||||
|
||||
// DeleteUserPolicies deletes user policies from domains database.
|
||||
DeleteUserPolicies(ctx context.Context, id string) (err error)
|
||||
}
|
||||
|
||||
@@ -227,6 +227,10 @@ func (es *eventStore) DeletePolicyFilter(ctx context.Context, pr auth.PolicyReq)
|
||||
return es.svc.DeletePolicyFilter(ctx, pr)
|
||||
}
|
||||
|
||||
func (es *eventStore) DeleteEntityPolicies(ctx context.Context, entityType, id string) error {
|
||||
return es.svc.DeleteEntityPolicies(ctx, entityType, id)
|
||||
}
|
||||
|
||||
func (es *eventStore) DeletePolicies(ctx context.Context, prs []auth.PolicyReq) error {
|
||||
return es.svc.DeletePolicies(ctx, prs)
|
||||
}
|
||||
|
||||
@@ -71,16 +71,16 @@ func (m *AuthClient) AddPolicies(ctx context.Context, in *magistrala.AddPolicies
|
||||
return ret.Get(0).(*magistrala.AddPoliciesRes), ret.Error(1)
|
||||
}
|
||||
|
||||
func (m *AuthClient) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyFilterRes, error) {
|
||||
func (m *AuthClient) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ret := m.Called(ctx, in)
|
||||
|
||||
return ret.Get(0).(*magistrala.DeletePolicyFilterRes), ret.Error(1)
|
||||
return ret.Get(0).(*magistrala.DeletePolicyRes), ret.Error(1)
|
||||
}
|
||||
|
||||
func (m *AuthClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) {
|
||||
func (m *AuthClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ret := m.Called(ctx, in)
|
||||
|
||||
return ret.Get(0).(*magistrala.DeletePoliciesRes), ret.Error(1)
|
||||
return ret.Get(0).(*magistrala.DeletePolicyRes), ret.Error(1)
|
||||
}
|
||||
|
||||
func (m *AuthClient) ListObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) {
|
||||
@@ -124,3 +124,9 @@ func (m *AuthClient) ListPermissions(ctx context.Context, in *magistrala.ListPer
|
||||
|
||||
return ret.Get(0).(*magistrala.ListPermissionsRes), ret.Error(1)
|
||||
}
|
||||
|
||||
func (m *AuthClient) DeleteEntityPolicies(ctx context.Context, in *magistrala.DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ret := m.Called(ctx, in)
|
||||
|
||||
return ret.Get(0).(*magistrala.DeletePolicyRes), ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -127,6 +127,24 @@ func (_m *Authz) CountSubjects(ctx context.Context, pr auth.PolicyReq) (uint64,
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteEntityPolicies provides a mock function with given fields: ctx, entityType, id
|
||||
func (_m *Authz) DeleteEntityPolicies(ctx context.Context, entityType string, id string) error {
|
||||
ret := _m.Called(ctx, entityType, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteEntityPolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, entityType, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeletePolicies provides a mock function with given fields: ctx, prs
|
||||
func (_m *Authz) DeletePolicies(ctx context.Context, prs []auth.PolicyReq) error {
|
||||
ret := _m.Called(ctx, prs)
|
||||
|
||||
@@ -78,6 +78,24 @@ func (_m *DomainsRepository) DeletePolicies(ctx context.Context, pcs ...auth.Pol
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteUserPolicies provides a mock function with given fields: ctx, id
|
||||
func (_m *DomainsRepository) DeleteUserPolicies(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteUserPolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ListDomains provides a mock function with given fields: ctx, pm
|
||||
func (_m *DomainsRepository) ListDomains(ctx context.Context, pm auth.Page) (auth.DomainsPage, error) {
|
||||
ret := _m.Called(ctx, pm)
|
||||
|
||||
@@ -201,6 +201,24 @@ func (_m *Service) CreateDomain(ctx context.Context, token string, d auth.Domain
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteEntityPolicies provides a mock function with given fields: ctx, entityType, id
|
||||
func (_m *Service) DeleteEntityPolicies(ctx context.Context, entityType string, id string) error {
|
||||
ret := _m.Called(ctx, entityType, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteEntityPolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, entityType, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeletePolicies provides a mock function with given fields: ctx, prs
|
||||
func (_m *Service) DeletePolicies(ctx context.Context, prs []auth.PolicyReq) error {
|
||||
ret := _m.Called(ctx, prs)
|
||||
|
||||
@@ -170,6 +170,9 @@ type Authz interface {
|
||||
|
||||
// ListPermissions lists permission betweeen given subject and object .
|
||||
ListPermissions(ctx context.Context, pr PolicyReq, filterPermission []string) (Permissions, error)
|
||||
|
||||
// DeleteEntityPolicies deletes all policies for the given entity.
|
||||
DeleteEntityPolicies(ctx context.Context, entityType, id string) error
|
||||
}
|
||||
|
||||
// PolicyAgent facilitates the communication to authorization
|
||||
|
||||
@@ -390,6 +390,16 @@ func (repo domainRepo) DeletePolicies(ctx context.Context, pcs ...auth.Policy) (
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (repo domainRepo) DeleteUserPolicies(ctx context.Context, id string) (err error) {
|
||||
q := "DELETE FROM policies WHERE subject_id = $1;"
|
||||
|
||||
if _, err := repo.db.ExecContext(ctx, q, id); err != nil {
|
||||
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo domainRepo) processRows(rows *sqlx.Rows) ([]auth.Domain, error) {
|
||||
var items []auth.Domain
|
||||
for rows.Next() {
|
||||
|
||||
@@ -1091,3 +1091,58 @@ func TestCheckPolicy(t *testing.T) {
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteUserPolicies(t *testing.T) {
|
||||
repo := postgres.NewDomainRepository(database)
|
||||
|
||||
domain := auth.Domain{
|
||||
ID: domainID,
|
||||
Name: "test",
|
||||
Alias: "test",
|
||||
Tags: []string{"test"},
|
||||
Metadata: map[string]interface{}{
|
||||
"test": "test",
|
||||
},
|
||||
CreatedBy: userID,
|
||||
UpdatedBy: userID,
|
||||
Status: auth.EnabledStatus,
|
||||
Permission: "admin",
|
||||
}
|
||||
|
||||
policy := auth.Policy{
|
||||
SubjectType: auth.UserType,
|
||||
SubjectID: userID,
|
||||
SubjectRelation: "admin",
|
||||
Relation: "admin",
|
||||
ObjectType: auth.DomainType,
|
||||
ObjectID: domainID,
|
||||
}
|
||||
|
||||
_, err := repo.Save(context.Background(), domain)
|
||||
require.Nil(t, err, fmt.Sprintf("failed to save domain %s", domain.ID))
|
||||
|
||||
err = repo.SavePolicies(context.Background(), policy)
|
||||
require.Nil(t, err, fmt.Sprintf("failed to save policy %s", policy.SubjectID))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete valid user policy",
|
||||
id: userID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete invalid user policy",
|
||||
id: inValid,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := repo.DeleteUserPolicies(context.Background(), tc.id)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
+74
-1
@@ -14,7 +14,10 @@ import (
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
)
|
||||
|
||||
const recoveryDuration = 5 * time.Minute
|
||||
const (
|
||||
recoveryDuration = 5 * time.Minute
|
||||
defLimit = 100
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrExpiry indicates that the token is expired.
|
||||
@@ -32,6 +35,8 @@ var (
|
||||
errRollbackPolicy = errors.New("failed to rollback policy")
|
||||
errRemoveLocalPolicy = errors.New("failed to remove from local policy copy")
|
||||
errRemovePolicyEngine = errors.New("failed to remove from policy engine")
|
||||
// errInvalidEntityType indicates invalid entity type.
|
||||
errInvalidEntityType = errors.New("invalid entity type")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -999,3 +1004,71 @@ func DecodeDomainUserID(domainUserID string) (string, string) {
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
|
||||
func (svc service) DeleteEntityPolicies(ctx context.Context, entityType, id string) (err error) {
|
||||
switch entityType {
|
||||
case ThingType:
|
||||
req := PolicyReq{
|
||||
Object: id,
|
||||
ObjectType: ThingType,
|
||||
}
|
||||
|
||||
return svc.DeletePolicyFilter(ctx, req)
|
||||
case UserType:
|
||||
domainsPage, err := svc.domains.ListDomains(ctx, Page{SubjectID: id, Limit: defLimit})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if domainsPage.Total > defLimit {
|
||||
for i := defLimit; i < int(domainsPage.Total); i += defLimit {
|
||||
page := Page{SubjectID: id, Offset: uint64(i), Limit: defLimit}
|
||||
dp, err := svc.domains.ListDomains(ctx, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domainsPage.Domains = append(domainsPage.Domains, dp.Domains...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, domain := range domainsPage.Domains {
|
||||
policy := PolicyReq{
|
||||
Subject: EncodeDomainUserID(domain.ID, id),
|
||||
SubjectType: UserType,
|
||||
}
|
||||
if err := svc.agent.DeletePolicyFilter(ctx, policy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
req := PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: UserType,
|
||||
}
|
||||
if err := svc.agent.DeletePolicyFilter(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := svc.domains.DeleteUserPolicies(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
case GroupType:
|
||||
req := PolicyReq{
|
||||
SubjectType: GroupType,
|
||||
Subject: id,
|
||||
}
|
||||
if err := svc.DeletePolicyFilter(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = PolicyReq{
|
||||
Object: id,
|
||||
ObjectType: GroupType,
|
||||
}
|
||||
return svc.DeletePolicyFilter(ctx, req)
|
||||
default:
|
||||
return errInvalidEntityType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,16 +158,27 @@ func (pa *policyAgent) DeletePolicyFilter(ctx context.Context, pr auth.PolicyReq
|
||||
RelationshipFilter: &v1.RelationshipFilter{
|
||||
ResourceType: pr.ObjectType,
|
||||
OptionalResourceId: pr.Object,
|
||||
OptionalRelation: pr.Relation,
|
||||
OptionalSubjectFilter: &v1.SubjectFilter{
|
||||
OptionalSubjectId: pr.Subject,
|
||||
SubjectType: pr.SubjectType,
|
||||
OptionalRelation: &v1.SubjectFilter_RelationFilter{
|
||||
Relation: pr.SubjectRelation,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if pr.Relation != "" {
|
||||
req.RelationshipFilter.OptionalRelation = pr.Relation
|
||||
}
|
||||
|
||||
if pr.SubjectType != "" {
|
||||
req.RelationshipFilter.OptionalSubjectFilter = &v1.SubjectFilter{
|
||||
SubjectType: pr.SubjectType,
|
||||
}
|
||||
if pr.Subject != "" {
|
||||
req.RelationshipFilter.OptionalSubjectFilter.OptionalSubjectId = pr.Subject
|
||||
}
|
||||
if pr.SubjectRelation != "" {
|
||||
req.RelationshipFilter.OptionalSubjectFilter.OptionalRelation = &v1.SubjectFilter_RelationFilter{
|
||||
Relation: pr.SubjectRelation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := pa.permissionClient.DeleteRelationships(ctx, req); err != nil {
|
||||
return errors.Wrap(errRemovePolicies, handleSpicedbError(err))
|
||||
}
|
||||
|
||||
@@ -303,3 +303,12 @@ func (tm *tracingMiddleware) ListUserDomains(ctx context.Context, token, userID
|
||||
defer span.End()
|
||||
return tm.svc.ListUserDomains(ctx, token, userID, p)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) DeleteEntityPolicies(ctx context.Context, entityType, id string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "delete_entity_policies", trace.WithAttributes(
|
||||
attribute.String("entity_type", entityType),
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.DeleteEntityPolicies(ctx, entityType, id)
|
||||
}
|
||||
|
||||
+63
-25
@@ -123,21 +123,22 @@ var AuthzService_ServiceDesc = grpc.ServiceDesc{
|
||||
}
|
||||
|
||||
const (
|
||||
AuthService_Issue_FullMethodName = "/magistrala.AuthService/Issue"
|
||||
AuthService_Refresh_FullMethodName = "/magistrala.AuthService/Refresh"
|
||||
AuthService_Identify_FullMethodName = "/magistrala.AuthService/Identify"
|
||||
AuthService_Authorize_FullMethodName = "/magistrala.AuthService/Authorize"
|
||||
AuthService_AddPolicy_FullMethodName = "/magistrala.AuthService/AddPolicy"
|
||||
AuthService_AddPolicies_FullMethodName = "/magistrala.AuthService/AddPolicies"
|
||||
AuthService_DeletePolicyFilter_FullMethodName = "/magistrala.AuthService/DeletePolicyFilter"
|
||||
AuthService_DeletePolicies_FullMethodName = "/magistrala.AuthService/DeletePolicies"
|
||||
AuthService_ListObjects_FullMethodName = "/magistrala.AuthService/ListObjects"
|
||||
AuthService_ListAllObjects_FullMethodName = "/magistrala.AuthService/ListAllObjects"
|
||||
AuthService_CountObjects_FullMethodName = "/magistrala.AuthService/CountObjects"
|
||||
AuthService_ListSubjects_FullMethodName = "/magistrala.AuthService/ListSubjects"
|
||||
AuthService_ListAllSubjects_FullMethodName = "/magistrala.AuthService/ListAllSubjects"
|
||||
AuthService_CountSubjects_FullMethodName = "/magistrala.AuthService/CountSubjects"
|
||||
AuthService_ListPermissions_FullMethodName = "/magistrala.AuthService/ListPermissions"
|
||||
AuthService_Issue_FullMethodName = "/magistrala.AuthService/Issue"
|
||||
AuthService_Refresh_FullMethodName = "/magistrala.AuthService/Refresh"
|
||||
AuthService_Identify_FullMethodName = "/magistrala.AuthService/Identify"
|
||||
AuthService_Authorize_FullMethodName = "/magistrala.AuthService/Authorize"
|
||||
AuthService_AddPolicy_FullMethodName = "/magistrala.AuthService/AddPolicy"
|
||||
AuthService_AddPolicies_FullMethodName = "/magistrala.AuthService/AddPolicies"
|
||||
AuthService_DeletePolicyFilter_FullMethodName = "/magistrala.AuthService/DeletePolicyFilter"
|
||||
AuthService_DeletePolicies_FullMethodName = "/magistrala.AuthService/DeletePolicies"
|
||||
AuthService_ListObjects_FullMethodName = "/magistrala.AuthService/ListObjects"
|
||||
AuthService_ListAllObjects_FullMethodName = "/magistrala.AuthService/ListAllObjects"
|
||||
AuthService_CountObjects_FullMethodName = "/magistrala.AuthService/CountObjects"
|
||||
AuthService_ListSubjects_FullMethodName = "/magistrala.AuthService/ListSubjects"
|
||||
AuthService_ListAllSubjects_FullMethodName = "/magistrala.AuthService/ListAllSubjects"
|
||||
AuthService_CountSubjects_FullMethodName = "/magistrala.AuthService/CountSubjects"
|
||||
AuthService_ListPermissions_FullMethodName = "/magistrala.AuthService/ListPermissions"
|
||||
AuthService_DeleteEntityPolicies_FullMethodName = "/magistrala.AuthService/DeleteEntityPolicies"
|
||||
)
|
||||
|
||||
// AuthServiceClient is the client API for AuthService service.
|
||||
@@ -153,8 +154,8 @@ type AuthServiceClient interface {
|
||||
Authorize(ctx context.Context, in *AuthorizeReq, opts ...grpc.CallOption) (*AuthorizeRes, error)
|
||||
AddPolicy(ctx context.Context, in *AddPolicyReq, opts ...grpc.CallOption) (*AddPolicyRes, error)
|
||||
AddPolicies(ctx context.Context, in *AddPoliciesReq, opts ...grpc.CallOption) (*AddPoliciesRes, error)
|
||||
DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyFilterRes, error)
|
||||
DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePoliciesRes, error)
|
||||
DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyRes, error)
|
||||
DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error)
|
||||
ListObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error)
|
||||
ListAllObjects(ctx context.Context, in *ListObjectsReq, opts ...grpc.CallOption) (*ListObjectsRes, error)
|
||||
CountObjects(ctx context.Context, in *CountObjectsReq, opts ...grpc.CallOption) (*CountObjectsRes, error)
|
||||
@@ -162,6 +163,7 @@ type AuthServiceClient interface {
|
||||
ListAllSubjects(ctx context.Context, in *ListSubjectsReq, opts ...grpc.CallOption) (*ListSubjectsRes, error)
|
||||
CountSubjects(ctx context.Context, in *CountSubjectsReq, opts ...grpc.CallOption) (*CountSubjectsRes, error)
|
||||
ListPermissions(ctx context.Context, in *ListPermissionsReq, opts ...grpc.CallOption) (*ListPermissionsRes, error)
|
||||
DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error)
|
||||
}
|
||||
|
||||
type authServiceClient struct {
|
||||
@@ -232,9 +234,9 @@ func (c *authServiceClient) AddPolicies(ctx context.Context, in *AddPoliciesReq,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyFilterRes, error) {
|
||||
func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePolicyFilterReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeletePolicyFilterRes)
|
||||
out := new(DeletePolicyRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_DeletePolicyFilter_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -242,9 +244,9 @@ func (c *authServiceClient) DeletePolicyFilter(ctx context.Context, in *DeletePo
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePoliciesRes, error) {
|
||||
func (c *authServiceClient) DeletePolicies(ctx context.Context, in *DeletePoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeletePoliciesRes)
|
||||
out := new(DeletePolicyRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_DeletePolicies_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -322,6 +324,16 @@ func (c *authServiceClient) ListPermissions(ctx context.Context, in *ListPermiss
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) DeleteEntityPolicies(ctx context.Context, in *DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*DeletePolicyRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeletePolicyRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_DeleteEntityPolicies_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AuthServiceServer is the server API for AuthService service.
|
||||
// All implementations must embed UnimplementedAuthServiceServer
|
||||
// for forward compatibility
|
||||
@@ -335,8 +347,8 @@ type AuthServiceServer interface {
|
||||
Authorize(context.Context, *AuthorizeReq) (*AuthorizeRes, error)
|
||||
AddPolicy(context.Context, *AddPolicyReq) (*AddPolicyRes, error)
|
||||
AddPolicies(context.Context, *AddPoliciesReq) (*AddPoliciesRes, error)
|
||||
DeletePolicyFilter(context.Context, *DeletePolicyFilterReq) (*DeletePolicyFilterRes, error)
|
||||
DeletePolicies(context.Context, *DeletePoliciesReq) (*DeletePoliciesRes, error)
|
||||
DeletePolicyFilter(context.Context, *DeletePolicyFilterReq) (*DeletePolicyRes, error)
|
||||
DeletePolicies(context.Context, *DeletePoliciesReq) (*DeletePolicyRes, error)
|
||||
ListObjects(context.Context, *ListObjectsReq) (*ListObjectsRes, error)
|
||||
ListAllObjects(context.Context, *ListObjectsReq) (*ListObjectsRes, error)
|
||||
CountObjects(context.Context, *CountObjectsReq) (*CountObjectsRes, error)
|
||||
@@ -344,6 +356,7 @@ type AuthServiceServer interface {
|
||||
ListAllSubjects(context.Context, *ListSubjectsReq) (*ListSubjectsRes, error)
|
||||
CountSubjects(context.Context, *CountSubjectsReq) (*CountSubjectsRes, error)
|
||||
ListPermissions(context.Context, *ListPermissionsReq) (*ListPermissionsRes, error)
|
||||
DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error)
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
|
||||
@@ -369,10 +382,10 @@ func (UnimplementedAuthServiceServer) AddPolicy(context.Context, *AddPolicyReq)
|
||||
func (UnimplementedAuthServiceServer) AddPolicies(context.Context, *AddPoliciesReq) (*AddPoliciesRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddPolicies not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) DeletePolicyFilter(context.Context, *DeletePolicyFilterReq) (*DeletePolicyFilterRes, error) {
|
||||
func (UnimplementedAuthServiceServer) DeletePolicyFilter(context.Context, *DeletePolicyFilterReq) (*DeletePolicyRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeletePolicyFilter not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) DeletePolicies(context.Context, *DeletePoliciesReq) (*DeletePoliciesRes, error) {
|
||||
func (UnimplementedAuthServiceServer) DeletePolicies(context.Context, *DeletePoliciesReq) (*DeletePolicyRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeletePolicies not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) ListObjects(context.Context, *ListObjectsReq) (*ListObjectsRes, error) {
|
||||
@@ -396,6 +409,9 @@ func (UnimplementedAuthServiceServer) CountSubjects(context.Context, *CountSubje
|
||||
func (UnimplementedAuthServiceServer) ListPermissions(context.Context, *ListPermissionsReq) (*ListPermissionsRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListPermissions not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) DeleteEntityPolicies(context.Context, *DeleteEntityPoliciesReq) (*DeletePolicyRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteEntityPolicies not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
|
||||
|
||||
// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -679,6 +695,24 @@ func _AuthService_ListPermissions_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthService_DeleteEntityPolicies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteEntityPoliciesReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).DeleteEntityPolicies(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_DeleteEntityPolicies_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).DeleteEntityPolicies(ctx, req.(*DeleteEntityPoliciesReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -746,6 +780,10 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListPermissions",
|
||||
Handler: _AuthService_ListPermissions_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteEntityPolicies",
|
||||
Handler: _AuthService_DeleteEntityPolicies_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth.proto",
|
||||
|
||||
@@ -45,6 +45,7 @@ type remotes struct {
|
||||
CertsURL string `toml:"certs_url"`
|
||||
InvitationsURL string `toml:"invitations_url"`
|
||||
JournalURL string `toml:"journal_url"`
|
||||
HostURL string `toml:"host_url"`
|
||||
TLSVerification bool `toml:"tls_verification"`
|
||||
}
|
||||
|
||||
@@ -115,6 +116,7 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
|
||||
CertsURL: defCertsURL,
|
||||
InvitationsURL: defInvitationsURL,
|
||||
JournalURL: defJournalURL,
|
||||
HostURL: defURL,
|
||||
TLSVerification: defTLSVerification,
|
||||
},
|
||||
Filter: filter{
|
||||
@@ -205,6 +207,10 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
|
||||
sdkConf.JournalURL = config.Remotes.JournalURL
|
||||
}
|
||||
|
||||
if sdkConf.HostURL == "" && config.Remotes.HostURL != "" {
|
||||
sdkConf.HostURL = config.Remotes.HostURL
|
||||
}
|
||||
|
||||
sdkConf.TLSVerification = config.Remotes.TLSVerification || sdkConf.TLSVerification
|
||||
|
||||
return sdkConf, nil
|
||||
|
||||
+19
-2
@@ -338,7 +338,24 @@ var cmdUsers = []cobra.Command{
|
||||
logJSON(user)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Use: "delete <user_id> <user_auth_token>",
|
||||
Short: "Delete user",
|
||||
Long: "Delete user by id\n" +
|
||||
"Usage:\n" +
|
||||
"\tmagistrala-cli users delete <user_id> $USERTOKEN - delete user with <user_id>\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
if err := sdk.DeleteUser(args[0], args[1]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "channels <user_id> <user_auth_token>",
|
||||
Short: "List channels",
|
||||
@@ -451,7 +468,7 @@ var cmdUsers = []cobra.Command{
|
||||
// NewUsersCmd returns users command.
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "users [create | get | update | token | password | enable | disable | channels | things | groups]",
|
||||
Use: "users [create | get | update | token | password | enable | disable | delete | channels | things | groups]",
|
||||
Short: "Users management",
|
||||
Long: `Users management: create accounts and tokens"`,
|
||||
}
|
||||
|
||||
@@ -12,13 +12,10 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const defURL string = "http://localhost"
|
||||
|
||||
func main() {
|
||||
msgContentType := string(sdk.CTJSONSenML)
|
||||
sdkConf := sdk.Config{
|
||||
MsgContentType: sdk.ContentType(msgContentType),
|
||||
HostURL: defURL,
|
||||
}
|
||||
|
||||
// Root
|
||||
|
||||
+18
-13
@@ -64,19 +64,21 @@ const (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"MG_USERS_LOG_LEVEL" envDefault:"info"`
|
||||
AdminEmail string `env:"MG_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
|
||||
AdminPassword string `env:"MG_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
|
||||
PassRegexText string `env:"MG_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
|
||||
ResetURL string `env:"MG_TOKEN_RESET_ENDPOINT" envDefault:"/reset-request"`
|
||||
JaegerURL url.URL `env:"MG_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
|
||||
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
|
||||
InstanceID string `env:"MG_USERS_INSTANCE_ID" envDefault:""`
|
||||
ESURL string `env:"MG_ES_URL" envDefault:"nats://localhost:4222"`
|
||||
TraceRatio float64 `env:"MG_JAEGER_TRACE_RATIO" envDefault:"1.0"`
|
||||
SelfRegister bool `env:"MG_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
|
||||
OAuthUIRedirectURL string `env:"MG_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
|
||||
OAuthUIErrorURL string `env:"MG_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
|
||||
LogLevel string `env:"MG_USERS_LOG_LEVEL" envDefault:"info"`
|
||||
AdminEmail string `env:"MG_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
|
||||
AdminPassword string `env:"MG_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
|
||||
PassRegexText string `env:"MG_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
|
||||
ResetURL string `env:"MG_TOKEN_RESET_ENDPOINT" envDefault:"/reset-request"`
|
||||
JaegerURL url.URL `env:"MG_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
|
||||
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
|
||||
InstanceID string `env:"MG_USERS_INSTANCE_ID" envDefault:""`
|
||||
ESURL string `env:"MG_ES_URL" envDefault:"nats://localhost:4222"`
|
||||
TraceRatio float64 `env:"MG_JAEGER_TRACE_RATIO" envDefault:"1.0"`
|
||||
SelfRegister bool `env:"MG_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
|
||||
OAuthUIRedirectURL string `env:"MG_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
|
||||
OAuthUIErrorURL string `env:"MG_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
|
||||
DeleteInterval time.Duration `env:"MG_USERS_DELETE_INTERVAL" envDefault:"24h"`
|
||||
DeleteAfter time.Duration `env:"MG_USERS_DELETE_AFTER" envDefault:"720h"`
|
||||
PassRegex *regexp.Regexp
|
||||
}
|
||||
|
||||
@@ -248,6 +250,9 @@ func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db
|
||||
if err := createAdminPolicy(ctx, clientID, authClient); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
users.NewDeleteHandler(ctx, cRepo, authClient, c.DeleteInterval, c.DeleteAfter, logger)
|
||||
|
||||
return csvc, gsvc, err
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ user_token = ""
|
||||
bootstrap_url = "http://localhost:9013"
|
||||
certs_url = "http://localhost:9019"
|
||||
domains_url = "http://localhost:8189"
|
||||
host_url = "http://localhost"
|
||||
http_adapter_url = "http://localhost:8008"
|
||||
invitations_url = "http://localhost:9020"
|
||||
reader_url = "http://localhost:9011"
|
||||
|
||||
@@ -193,6 +193,8 @@ MG_USERS_INSTANCE_ID=
|
||||
MG_USERS_ALLOW_SELF_REGISTER=true
|
||||
MG_OAUTH_UI_REDIRECT_URL=http://localhost:9095${MG_UI_PATH_PREFIX}/tokens/secure
|
||||
MG_OAUTH_UI_ERROR_URL=http://localhost:9095${MG_UI_PATH_PREFIX}/error
|
||||
MG_USERS_DELETE_INTERVAL=24h
|
||||
MG_USERS_DELETE_AFTER=720h
|
||||
|
||||
### Email utility
|
||||
MG_EMAIL_HOST=smtp.mailtrap.io
|
||||
|
||||
@@ -449,6 +449,8 @@ services:
|
||||
MG_GOOGLE_STATE: ${MG_GOOGLE_STATE}
|
||||
MG_OAUTH_UI_REDIRECT_URL: ${MG_OAUTH_UI_REDIRECT_URL}
|
||||
MG_OAUTH_UI_ERROR_URL: ${MG_OAUTH_UI_ERROR_URL}
|
||||
MG_USERS_DELETE_INTERVAL: ${MG_USERS_DELETE_INTERVAL}
|
||||
MG_USERS_DELETE_AFTER: ${MG_USERS_DELETE_AFTER}
|
||||
ports:
|
||||
- ${MG_USERS_HTTP_PORT}:${MG_USERS_HTTP_PORT}
|
||||
networks:
|
||||
|
||||
@@ -66,6 +66,9 @@ var (
|
||||
// ErrMalformedPolicyAct indicates missing policies action.
|
||||
ErrMalformedPolicyAct = errors.New("malformed policy action")
|
||||
|
||||
// ErrMissingPolicyEntityType indicates missing policies entity type.
|
||||
ErrMissingPolicyEntityType = errors.New("missing policy entity type")
|
||||
|
||||
// ErrMalformedPolicyPer indicates missing policies relation.
|
||||
ErrMalformedPolicyPer = errors.New("malformed policy permission")
|
||||
|
||||
|
||||
+11
-37
@@ -581,54 +581,28 @@ func (svc service) Unassign(ctx context.Context, token, groupID, relation, membe
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc service) DeleteGroup(ctx context.Context, token, groupID string) error {
|
||||
func (svc service) DeleteGroup(ctx context.Context, token, id string) error {
|
||||
res, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := svc.authorizeKind(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.DeletePermission, auth.GroupType, groupID); err != nil {
|
||||
if _, err := svc.authorizeKind(ctx, res.GetDomainId(), auth.UserType, auth.UsersKind, res.GetId(), auth.DeletePermission, auth.GroupType, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove policy of child groups
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.GroupType,
|
||||
Subject: groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}); err != nil {
|
||||
deleteRes, err := svc.auth.DeleteEntityPolicies(ctx, &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: auth.GroupType,
|
||||
Id: id,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrDeletePolicies, err)
|
||||
}
|
||||
|
||||
// Remove policy of things
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.GroupType,
|
||||
Subject: groupID,
|
||||
ObjectType: auth.ThingType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrDeletePolicies, err)
|
||||
if !deleteRes.Deleted {
|
||||
return svcerr.ErrAuthorization
|
||||
}
|
||||
|
||||
// Remove policy from domain
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.DomainType,
|
||||
Object: groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrDeletePolicies, err)
|
||||
}
|
||||
|
||||
// Remove group from database
|
||||
if err := svc.groups.Delete(ctx, groupID); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
// Remove policy of users
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.UserType,
|
||||
Object: groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrDeletePolicies, err)
|
||||
if err := svc.groups.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+46
-153
@@ -66,7 +66,7 @@ func TestCreateGroup(t *testing.T) {
|
||||
repoErr error
|
||||
addPolResp *magistrala.AddPoliciesRes
|
||||
addPolErr error
|
||||
deletePolResp *magistrala.DeletePoliciesRes
|
||||
deletePolResp *magistrala.DeletePolicyRes
|
||||
deletePolErr error
|
||||
err error
|
||||
}{
|
||||
@@ -1666,7 +1666,7 @@ func TestAssign(t *testing.T) {
|
||||
repoErr error
|
||||
addParentPoliciesRes *magistrala.AddPoliciesRes
|
||||
addParentPoliciesErr error
|
||||
deleteParentPoliciesRes *magistrala.DeletePoliciesRes
|
||||
deleteParentPoliciesRes *magistrala.DeletePolicyRes
|
||||
deleteParentPoliciesErr error
|
||||
repoParentGroupErr error
|
||||
err error
|
||||
@@ -1890,7 +1890,7 @@ func TestAssign(t *testing.T) {
|
||||
addPoliciesRes: &magistrala.AddPoliciesRes{
|
||||
Added: true,
|
||||
},
|
||||
deleteParentPoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deleteParentPoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deleteParentPoliciesErr: svcerr.ErrAuthorization,
|
||||
@@ -2069,13 +2069,13 @@ func TestUnassign(t *testing.T) {
|
||||
idErr error
|
||||
authzResp *magistrala.AuthorizeRes
|
||||
authzErr error
|
||||
deletePoliciesRes *magistrala.DeletePoliciesRes
|
||||
deletePoliciesRes *magistrala.DeletePolicyRes
|
||||
deletePoliciesErr error
|
||||
repoResp mggroups.Page
|
||||
repoErr error
|
||||
addParentPoliciesRes *magistrala.AddPoliciesRes
|
||||
addParentPoliciesErr error
|
||||
deleteParentPoliciesRes *magistrala.DeletePoliciesRes
|
||||
deleteParentPoliciesRes *magistrala.DeletePolicyRes
|
||||
deleteParentPoliciesErr error
|
||||
repoParentGroupErr error
|
||||
err error
|
||||
@@ -2094,7 +2094,7 @@ func TestUnassign(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
},
|
||||
@@ -2112,7 +2112,7 @@ func TestUnassign(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
},
|
||||
@@ -2137,7 +2137,7 @@ func TestUnassign(t *testing.T) {
|
||||
validGroup,
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
repoParentGroupErr: nil,
|
||||
@@ -2156,7 +2156,7 @@ func TestUnassign(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
},
|
||||
@@ -2242,7 +2242,7 @@ func TestUnassign(t *testing.T) {
|
||||
validGroup,
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deletePoliciesErr: svcerr.ErrAuthorization,
|
||||
@@ -2269,7 +2269,7 @@ func TestUnassign(t *testing.T) {
|
||||
validGroup,
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
repoParentGroupErr: repoerr.ErrConflict,
|
||||
@@ -2296,7 +2296,7 @@ func TestUnassign(t *testing.T) {
|
||||
validGroup,
|
||||
},
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
repoParentGroupErr: repoerr.ErrConflict,
|
||||
@@ -2364,7 +2364,7 @@ func TestUnassign(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deletePoliciesRes: &magistrala.DeletePoliciesRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deletePoliciesErr: svcerr.ErrAuthorization,
|
||||
@@ -2468,23 +2468,17 @@ func TestDeleteGroup(t *testing.T) {
|
||||
svc := groups.NewService(repo, idProvider, authsvc)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
groupID string
|
||||
idResp *magistrala.IdentityRes
|
||||
idErr error
|
||||
authzResp *magistrala.AuthorizeRes
|
||||
authzErr error
|
||||
deleteChildPoliciesRes *magistrala.DeletePolicyFilterRes
|
||||
deleteChildPoliciesErr error
|
||||
deleteThingsPoliciesRes *magistrala.DeletePolicyFilterRes
|
||||
deleteThingsPoliciesErr error
|
||||
deleteDomainsPoliciesRes *magistrala.DeletePolicyFilterRes
|
||||
deleteDomainsPoliciesErr error
|
||||
deleteUsersPoliciesRes *magistrala.DeletePolicyFilterRes
|
||||
deleteUsersPoliciesErr error
|
||||
repoErr error
|
||||
err error
|
||||
desc string
|
||||
token string
|
||||
groupID string
|
||||
idResp *magistrala.IdentityRes
|
||||
idErr error
|
||||
authzResp *magistrala.AuthorizeRes
|
||||
authzErr error
|
||||
deletePoliciesRes *magistrala.DeletePolicyRes
|
||||
deletePoliciesErr error
|
||||
repoErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "successfully",
|
||||
@@ -2497,26 +2491,18 @@ func TestDeleteGroup(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteThingsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteDomainsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteUsersPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with invalid token",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{},
|
||||
idErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "unsuccessfully with invalid token",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{},
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{},
|
||||
idErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with authorization error",
|
||||
@@ -2529,11 +2515,12 @@ func TestDeleteGroup(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: false,
|
||||
},
|
||||
authzErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{},
|
||||
authzErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with failed to remove child group policy",
|
||||
desc: "unsuccessfully with failed to remove policy",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{
|
||||
@@ -2543,80 +2530,11 @@ func TestDeleteGroup(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deleteChildPoliciesErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with failed to remove things policy",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{
|
||||
Id: testsutil.GenerateUUID(t),
|
||||
DomainId: testsutil.GenerateUUID(t),
|
||||
},
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteThingsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deleteThingsPoliciesErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with failed to remove domain policy",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{
|
||||
Id: testsutil.GenerateUUID(t),
|
||||
DomainId: testsutil.GenerateUUID(t),
|
||||
},
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteThingsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteDomainsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deleteDomainsPoliciesErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with failed to remove user policy",
|
||||
token: token,
|
||||
groupID: testsutil.GenerateUUID(t),
|
||||
idResp: &magistrala.IdentityRes{
|
||||
Id: testsutil.GenerateUUID(t),
|
||||
DomainId: testsutil.GenerateUUID(t),
|
||||
},
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteThingsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteDomainsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteUsersPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: false,
|
||||
},
|
||||
deleteUsersPoliciesErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
deletePoliciesErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unsuccessfully with repo err",
|
||||
@@ -2629,13 +2547,7 @@ func TestDeleteGroup(t *testing.T) {
|
||||
authzResp: &magistrala.AuthorizeRes{
|
||||
Authorized: true,
|
||||
},
|
||||
deleteChildPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteThingsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
Deleted: true,
|
||||
},
|
||||
deleteDomainsPoliciesRes: &magistrala.DeletePolicyFilterRes{
|
||||
deletePoliciesRes: &magistrala.DeletePolicyRes{
|
||||
Deleted: true,
|
||||
},
|
||||
repoErr: repoerr.ErrNotFound,
|
||||
@@ -2655,36 +2567,17 @@ func TestDeleteGroup(t *testing.T) {
|
||||
Object: tc.groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}).Return(tc.authzResp, tc.authzErr)
|
||||
authcall2 := authsvc.On("DeletePolicyFilter", context.Background(), &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.GroupType,
|
||||
Subject: tc.groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}).Return(tc.deleteChildPoliciesRes, tc.deleteChildPoliciesErr)
|
||||
authcall3 := authsvc.On("DeletePolicyFilter", context.Background(), &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.GroupType,
|
||||
Subject: tc.groupID,
|
||||
ObjectType: auth.ThingType,
|
||||
}).Return(tc.deleteThingsPoliciesRes, tc.deleteThingsPoliciesErr)
|
||||
authcall4 := authsvc.On("DeletePolicyFilter", context.Background(), &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.DomainType,
|
||||
Object: tc.groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}).Return(tc.deleteDomainsPoliciesRes, tc.deleteDomainsPoliciesErr)
|
||||
authcall5 := repo.On("Delete", context.Background(), tc.groupID).Return(tc.repoErr)
|
||||
authcall6 := authsvc.On("DeletePolicyFilter", context.Background(), &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.UserType,
|
||||
Object: tc.groupID,
|
||||
ObjectType: auth.GroupType,
|
||||
}).Return(tc.deleteUsersPoliciesRes, tc.deleteUsersPoliciesErr)
|
||||
authcall2 := authsvc.On("DeleteEntityPolicies", context.Background(), &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: auth.GroupType,
|
||||
Id: tc.groupID,
|
||||
}).Return(tc.deletePoliciesRes, tc.deletePoliciesErr)
|
||||
repocall := repo.On("Delete", context.Background(), tc.groupID).Return(tc.repoErr)
|
||||
err := svc.DeleteGroup(context.Background(), tc.token, tc.groupID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("expected error %v to contain %v", err, tc.err))
|
||||
authcall.Unset()
|
||||
authcall1.Unset()
|
||||
authcall2.Unset()
|
||||
authcall3.Unset()
|
||||
authcall4.Unset()
|
||||
authcall5.Unset()
|
||||
authcall6.Unset()
|
||||
repocall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,9 @@ type Repository interface {
|
||||
|
||||
// ChangeStatus changes client status to enabled or disabled
|
||||
ChangeStatus(ctx context.Context, client Client) (Client, error)
|
||||
|
||||
// Delete deletes client with given id
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
// Validate returns an error if client representation is invalid.
|
||||
|
||||
@@ -320,6 +320,20 @@ func (repo *Repository) update(ctx context.Context, client clients.Client, query
|
||||
return clients.Client{}, repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
func (repo *Repository) Delete(ctx context.Context, id string) error {
|
||||
q := "DELETE FROM clients AS c WHERE c.id = $1 ;"
|
||||
|
||||
result, err := repo.DB.ExecContext(ctx, q, id)
|
||||
if err != nil {
|
||||
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
|
||||
}
|
||||
if rows, _ := result.RowsAffected(); rows == 0 {
|
||||
return repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DBClient struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name,omitempty"`
|
||||
|
||||
@@ -1798,6 +1798,43 @@ func TestUpdateRole(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
_, err := db.Exec("DELETE FROM clients")
|
||||
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
||||
})
|
||||
repo := &postgres.Repository{database}
|
||||
|
||||
client := generateClient(t, mgclients.EnabledStatus, mgclients.UserRole, repo)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete client successfully",
|
||||
id: client.ID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete client with invalid id",
|
||||
id: testsutil.GenerateUUID(t),
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "delete client with empty id",
|
||||
id: "",
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := repo.Delete(context.Background(), tc.id)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func findClients(clis []mgclients.Client, query string, offset, limit uint64) []mgclients.Client {
|
||||
rclients := []mgclients.Client{}
|
||||
for _, client := range clis {
|
||||
|
||||
@@ -19,6 +19,8 @@ const (
|
||||
EnabledStatus Status = iota
|
||||
// DisabledStatus represents disabled Client.
|
||||
DisabledStatus
|
||||
// DeletedStatus represents a client that will be deleted.
|
||||
DeletedStatus
|
||||
|
||||
// AllStatus is used for querying purposes to list clients irrespective
|
||||
// of their status - both enabled and disabled. It is never stored in the
|
||||
@@ -31,6 +33,7 @@ const (
|
||||
const (
|
||||
Disabled = "disabled"
|
||||
Enabled = "enabled"
|
||||
Deleted = "deleted"
|
||||
All = "all"
|
||||
Unknown = "unknown"
|
||||
)
|
||||
@@ -42,6 +45,8 @@ func (s Status) String() string {
|
||||
return Disabled
|
||||
case EnabledStatus:
|
||||
return Enabled
|
||||
case DeletedStatus:
|
||||
return Deleted
|
||||
case AllStatus:
|
||||
return All
|
||||
default:
|
||||
@@ -56,6 +61,8 @@ func ToStatus(status string) (Status, error) {
|
||||
return EnabledStatus, nil
|
||||
case Disabled:
|
||||
return DisabledStatus, nil
|
||||
case Deleted:
|
||||
return DeletedStatus, nil
|
||||
case All:
|
||||
return AllStatus, nil
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ func TestStatusString(t *testing.T) {
|
||||
status: clients.DisabledStatus,
|
||||
expected: "disabled",
|
||||
},
|
||||
{
|
||||
desc: "Deleted",
|
||||
status: clients.DeletedStatus,
|
||||
expected: "deleted",
|
||||
},
|
||||
{
|
||||
desc: "All",
|
||||
status: clients.AllStatus,
|
||||
@@ -66,6 +71,12 @@ func TestToStatus(t *testing.T) {
|
||||
expetcted: clients.DisabledStatus,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Deleted",
|
||||
status: "deleted",
|
||||
expetcted: clients.DeletedStatus,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "All",
|
||||
status: "all",
|
||||
@@ -108,6 +119,12 @@ func TestStatusMarshalJSON(t *testing.T) {
|
||||
status: clients.DisabledStatus,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Deleted",
|
||||
expected: []byte(`"deleted"`),
|
||||
status: clients.DeletedStatus,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "All",
|
||||
expected: []byte(`"all"`),
|
||||
@@ -150,6 +167,12 @@ func TestStatusUnmarshalJSON(t *testing.T) {
|
||||
status: []byte(`"disabled"`),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Deleted",
|
||||
expected: clients.DeletedStatus,
|
||||
status: []byte(`"deleted"`),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "All",
|
||||
expected: clients.AllStatus,
|
||||
@@ -193,6 +216,12 @@ func TestUserMarshalJSON(t *testing.T) {
|
||||
user: clients.Client{Status: clients.DisabledStatus},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Deleted",
|
||||
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"deleted"}`),
|
||||
user: clients.Client{Status: clients.DeletedStatus},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "All",
|
||||
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"all"}`),
|
||||
|
||||
@@ -140,7 +140,7 @@ func TestCreateChannel(t *testing.T) {
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil)
|
||||
authCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePoliciesRes{Deleted: false}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: false}, nil)
|
||||
repoCall := grepo.On("Save", mock.Anything, mock.Anything).Return(convertChannel(sdk.Channel{}), tc.err)
|
||||
rChannel, err := mgsdk.CreateChannel(tc.channel, validToken)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
@@ -771,7 +771,7 @@ func TestDeleteChannel(t *testing.T) {
|
||||
authCall1.Unset()
|
||||
repoCall.Unset()
|
||||
|
||||
authCall = auth.On("DeletePolicyFilter", mock.Anything, mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyFilterRes{Deleted: true}, nil)
|
||||
authCall = auth.On("DeleteEntityPolicies", mock.Anything, mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil)
|
||||
authCall1 = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall = grepo.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
@@ -260,6 +260,13 @@ type SDK interface {
|
||||
// fmt.Println(user)
|
||||
DisableUser(id, token string) (User, errors.SDKError)
|
||||
|
||||
// DeleteUser deletes a user with the given id.
|
||||
//
|
||||
// example:
|
||||
// err := sdk.DeleteUser("userID", "token")
|
||||
// fmt.Println(err)
|
||||
DeleteUser(id, token string) errors.SDKError
|
||||
|
||||
// CreateToken receives credentials and returns user token.
|
||||
//
|
||||
// example:
|
||||
|
||||
@@ -65,12 +65,6 @@ func generateUUID(t *testing.T) string {
|
||||
return ulid
|
||||
}
|
||||
|
||||
func convertClientsPage(cp sdk.UsersPage) mgclients.ClientsPage {
|
||||
return mgclients.ClientsPage{
|
||||
Clients: convertClients(cp.Users),
|
||||
}
|
||||
}
|
||||
|
||||
func convertThingsPage(cp sdk.ThingsPage) mgclients.ClientsPage {
|
||||
return mgclients.ClientsPage{
|
||||
Clients: convertThings(cp.Things...),
|
||||
|
||||
+17
-17
@@ -186,7 +186,7 @@ func TestCreateThing(t *testing.T) {
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil)
|
||||
authCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePoliciesRes{Deleted: false}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: false}, nil)
|
||||
repoCall3 := cRepo.On("Save", mock.Anything, mock.Anything).Return(convertThings(tc.response), tc.repoErr)
|
||||
rThing, err := mgsdk.CreateThing(tc.client, tc.token)
|
||||
|
||||
@@ -275,7 +275,7 @@ func TestCreateThings(t *testing.T) {
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil)
|
||||
authCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePoliciesRes{Deleted: false}, nil)
|
||||
authCall3 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: false}, nil)
|
||||
repoCall1 := cRepo.On("Save", mock.Anything, mock.Anything).Return(convertThings(tc.response...), tc.err)
|
||||
if len(tc.things) > 0 {
|
||||
repoCall1 = cRepo.On("Save", mock.Anything, mock.Anything, mock.Anything).Return(convertThings(tc.response...), tc.err)
|
||||
@@ -1272,27 +1272,27 @@ func TestDeleteThing(t *testing.T) {
|
||||
Status: mgclients.EnabledStatus.String(),
|
||||
}
|
||||
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, nil)
|
||||
repoCall2 := cRepo.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
repoCall4 := cache.On("Remove", mock.Anything, thing.ID).Return(nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: false}, nil)
|
||||
repoCall := cRepo.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
cacheCall := cache.On("Remove", mock.Anything, thing.ID).Return(nil)
|
||||
err := mgsdk.DeleteThing("wrongID", validToken)
|
||||
assert.Equal(t, err, errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden), fmt.Sprintf("Delete thing with wrong id: expected %v got %v", svcerr.ErrNotFound, err))
|
||||
authCall.Unset()
|
||||
authCall1.Unset()
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
|
||||
repoCall = auth.On("DeletePolicyFilter", mock.Anything, mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyFilterRes{Deleted: true}, nil)
|
||||
repoCall1 = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
repoCall2 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall3 := cRepo.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
authCall = auth.On("DeleteEntityPolicies", mock.Anything, mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil)
|
||||
authCall1 = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall2 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall = cRepo.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
err = mgsdk.DeleteThing(thing.ID, validToken)
|
||||
assert.Nil(t, err, fmt.Sprintf("Delete thing with correct id: expected %v got %v", nil, err))
|
||||
ok := repoCall3.Parent.AssertCalled(t, "Delete", mock.Anything, thing.ID)
|
||||
ok := repoCall.Parent.AssertCalled(t, "Delete", mock.Anything, thing.ID)
|
||||
assert.True(t, ok, "Delete was not called on deleting thing with correct id")
|
||||
authCall.Unset()
|
||||
authCall1.Unset()
|
||||
authCall2.Unset()
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
repoCall4.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
|
||||
@@ -344,3 +344,9 @@ func (sdk mgSDK) changeClientStatus(token, id, status string) (User, errors.SDKE
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (sdk mgSDK) DeleteUser(id, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.usersURL, usersEndpoint, id)
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, nil, nil, http.StatusNoContent)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
+59
-90
@@ -181,7 +181,7 @@ func TestCreateClient(t *testing.T) {
|
||||
repoCall = auth.On("Identify", mock.Anything, mock.Anything).Return(&magistrala.IdentityRes{}, svcerr.ErrAuthentication)
|
||||
}
|
||||
repoCall1 := auth.On("AddPolicies", mock.Anything, mock.Anything).Return(&magistrala.AddPoliciesRes{Added: true}, nil)
|
||||
repoCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePoliciesRes{Deleted: true}, nil)
|
||||
repoCall2 := auth.On("DeletePolicies", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil)
|
||||
repoCall3 := crepo.On("Save", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.err)
|
||||
rClient, err := mgsdk.CreateUser(tc.client, tc.token)
|
||||
tc.response.ID = rClient.ID
|
||||
@@ -957,7 +957,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
repoCall = auth.On("Identify", mock.Anything, mock.Anything).Return(&magistrala.IdentityRes{}, svcerr.ErrAuthentication)
|
||||
}
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall2 := auth.On("DeletePolicyFilter", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyFilterRes{Deleted: true}, nil)
|
||||
repoCall2 := auth.On("DeletePolicyFilter", mock.Anything, mock.Anything).Return(&magistrala.DeletePolicyRes{Deleted: true}, nil)
|
||||
repoCall3 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&magistrala.AddPolicyRes{Added: true}, nil)
|
||||
repoCall4 := crepo.On("UpdateRole", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.err)
|
||||
uClient, err := mgsdk.UpdateUserRole(tc.client, tc.token)
|
||||
@@ -1051,59 +1051,6 @@ func TestEnableClient(t *testing.T) {
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
}
|
||||
|
||||
cases2 := []struct {
|
||||
desc string
|
||||
token string
|
||||
status string
|
||||
metadata sdk.Metadata
|
||||
response sdk.UsersPage
|
||||
size uint64
|
||||
}{
|
||||
{
|
||||
desc: "list enabled clients",
|
||||
status: mgclients.EnabledStatus.String(),
|
||||
size: 2,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{enabledClient1, endisabledClient1},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list disabled clients",
|
||||
status: mgclients.DisabledStatus.String(),
|
||||
size: 1,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{disabledClient1},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list enabled and disabled clients",
|
||||
status: mgclients.AllStatus.String(),
|
||||
size: 3,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{enabledClient1, disabledClient1, endisabledClient1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases2 {
|
||||
pm := sdk.PageMetadata{
|
||||
Total: 100,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
Status: tc.status,
|
||||
}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{UserId: validID}, nil)
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall2 := crepo.On("RetrieveAll", mock.Anything, mock.Anything).Return(convertClientsPage(tc.response), nil)
|
||||
clientsPage, err := mgsdk.Users(pm, validToken)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(clientsPage.Users))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableClient(t *testing.T) {
|
||||
@@ -1180,57 +1127,79 @@ func TestDisableClient(t *testing.T) {
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
cases2 := []struct {
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
ts, crepo, _, auth := setupUsers()
|
||||
defer ts.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
enabledClient1 := sdk.User{ID: testsutil.GenerateUUID(t), Credentials: sdk.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mgclients.EnabledStatus.String()}
|
||||
deletedClient1 := sdk.User{ID: testsutil.GenerateUUID(t), Credentials: sdk.Credentials{Identity: "client3@example.com", Secret: "password"}, Status: mgclients.DeletedStatus.String()}
|
||||
deletedenabledClient1 := enabledClient1
|
||||
deletedenabledClient1.Status = mgclients.DisabledStatus.String()
|
||||
deletedenabledClient1.ID = testsutil.GenerateUUID(t)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
status string
|
||||
metadata sdk.Metadata
|
||||
response sdk.UsersPage
|
||||
size uint64
|
||||
client sdk.User
|
||||
response sdk.User
|
||||
repoErr error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "list enabled clients",
|
||||
status: mgclients.EnabledStatus.String(),
|
||||
size: 2,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{enabledClient1, disenabledClient1},
|
||||
},
|
||||
desc: "delete enabled client",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
response: deletedenabledClient1,
|
||||
err: nil,
|
||||
repoErr: nil,
|
||||
},
|
||||
{
|
||||
desc: "list disabled clients",
|
||||
status: mgclients.DisabledStatus.String(),
|
||||
size: 1,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{disabledClient1},
|
||||
},
|
||||
desc: "delete disabled client",
|
||||
id: deletedClient1.ID,
|
||||
token: validToken,
|
||||
client: deletedClient1,
|
||||
response: sdk.User{},
|
||||
repoErr: sdk.ErrFailedDisable,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "list enabled and disabled clients",
|
||||
status: mgclients.AllStatus.String(),
|
||||
size: 3,
|
||||
response: sdk.UsersPage{
|
||||
Users: []sdk.User{enabledClient1, disabledClient1, disenabledClient1},
|
||||
},
|
||||
desc: "delete non-existing client",
|
||||
id: wrongID,
|
||||
client: sdk.User{},
|
||||
token: validToken,
|
||||
response: sdk.User{},
|
||||
repoErr: sdk.ErrFailedDisable,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrViewEntity, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases2 {
|
||||
pm := sdk.PageMetadata{
|
||||
Total: 100,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
Status: tc.status,
|
||||
}
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{UserId: validID}, nil)
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall2 := crepo.On("RetrieveAll", mock.Anything, mock.Anything).Return(convertClientsPage(tc.response), nil)
|
||||
page, err := mgsdk.Users(pm, validToken)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(page.Users))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
repoCall2 := crepo.On("RetrieveByID", mock.Anything, tc.id).Return(convertClient(tc.client), tc.repoErr)
|
||||
repoCall3 := crepo.On("ChangeStatus", mock.Anything, mock.Anything).Return(convertClient(tc.response), tc.repoErr)
|
||||
err := mgsdk.DeleteUser(tc.id, tc.token)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
|
||||
if tc.err == nil {
|
||||
ok := repoCall.Parent.AssertCalled(t, "Identify", mock.Anything, mock.Anything)
|
||||
assert.True(t, ok, fmt.Sprintf("Identify was not called on %s", tc.desc))
|
||||
ok = repoCall2.Parent.AssertCalled(t, "RetrieveByID", mock.Anything, tc.id)
|
||||
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
||||
ok = repoCall3.Parent.AssertCalled(t, "ChangeStatus", mock.Anything, mock.Anything)
|
||||
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
|
||||
}
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,6 +766,26 @@ func (_m *SDK) DeleteThing(id string, token string) errors.SDKError {
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteUser provides a mock function with given fields: id, token
|
||||
func (_m *SDK) DeleteUser(id string, token string) errors.SDKError {
|
||||
ret := _m.Called(id, token)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteUser")
|
||||
}
|
||||
|
||||
var r0 errors.SDKError
|
||||
if rf, ok := ret.Get(0).(func(string, string) errors.SDKError); ok {
|
||||
r0 = rf(id, token)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(errors.SDKError)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DisableChannel provides a mock function with given fields: id, token
|
||||
func (_m *SDK) DisableChannel(id string, token string) (sdk.Channel, errors.SDKError) {
|
||||
ret := _m.Called(id, token)
|
||||
|
||||
@@ -33,9 +33,6 @@ type Repository interface {
|
||||
|
||||
// RetrieveBySecret retrieves a client based on the secret (key).
|
||||
RetrieveBySecret(ctx context.Context, key string) (mgclients.Client, error)
|
||||
|
||||
// Delete deletes client with given id
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
// NewRepository instantiates a PostgreSQL
|
||||
@@ -124,17 +121,3 @@ func (repo clientRepo) RetrieveBySecret(ctx context.Context, key string) (mgclie
|
||||
|
||||
return mgclients.Client{}, repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
func (repo clientRepo) Delete(ctx context.Context, id string) error {
|
||||
q := "DELETE FROM clients AS c WHERE c.id = $1 ;"
|
||||
|
||||
result, err := repo.DB.ExecContext(ctx, q, id)
|
||||
if err != nil {
|
||||
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
|
||||
}
|
||||
if rows, _ := result.RowsAffected(); rows == 0 {
|
||||
return repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ var (
|
||||
invalidName = strings.Repeat("m", maxNameSize+10)
|
||||
clientIdentity = "client-identity@example.com"
|
||||
clientName = "client name"
|
||||
invalidClientID = "invalidClientID"
|
||||
invalidDomainID = strings.Repeat("m", maxNameSize+10)
|
||||
namesgen = namegenerator.NewGenerator()
|
||||
)
|
||||
@@ -365,51 +364,3 @@ func TestClientsRetrieveBySecret(t *testing.T) {
|
||||
assert.Equal(t, res, tc.response, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, res))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
_, err := db.Exec("DELETE FROM clients")
|
||||
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
||||
})
|
||||
repo := postgres.NewRepository(database)
|
||||
|
||||
client := clients.Client{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: clientName,
|
||||
Credentials: clients.Credentials{
|
||||
Identity: clientIdentity,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
|
||||
_, err := repo.Save(context.Background(), client)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete client successfully",
|
||||
id: client.ID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete client with invalid id",
|
||||
id: invalidClientID,
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "delete client with empty id",
|
||||
id: "",
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := repo.Delete(context.Background(), tc.id)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
+7
-25
@@ -438,43 +438,25 @@ func (svc service) DeleteClient(ctx context.Context, token, id string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove from cache
|
||||
if err := svc.clientCache.Remove(ctx, id); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
// Remove policy of groups
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.GroupType,
|
||||
Object: id,
|
||||
ObjectType: auth.ThingType,
|
||||
}); err != nil {
|
||||
deleteRes, err := svc.auth.DeleteEntityPolicies(ctx, &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: auth.ThingType,
|
||||
Id: id,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
// Remove policy from domain
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.DomainType,
|
||||
Object: id,
|
||||
ObjectType: auth.ThingType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
if !deleteRes.Deleted {
|
||||
return svcerr.ErrAuthorization
|
||||
}
|
||||
|
||||
// Remove thing from database
|
||||
if err := svc.clients.Delete(ctx, id); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
// Remove policy of users
|
||||
if _, err := svc.auth.DeletePolicyFilter(ctx, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: auth.UserType,
|
||||
Object: id,
|
||||
ObjectType: auth.ThingType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+39
-82
@@ -65,7 +65,7 @@ func TestCreateThings(t *testing.T) {
|
||||
token string
|
||||
authResponse *magistrala.AuthorizeRes
|
||||
addPolicyResponse *magistrala.AddPoliciesRes
|
||||
deletePolicyRes *magistrala.DeletePoliciesRes
|
||||
deletePolicyRes *magistrala.DeletePolicyRes
|
||||
authorizeErr error
|
||||
identifyErr error
|
||||
addPolicyErr error
|
||||
@@ -320,7 +320,7 @@ func TestCreateThings(t *testing.T) {
|
||||
authResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
addPolicyResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
saveErr: repoerr.ErrConflict,
|
||||
deletePolicyRes: &magistrala.DeletePoliciesRes{Deleted: false},
|
||||
deletePolicyRes: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
deletePolicyErr: svcerr.ErrInvalidPolicy,
|
||||
err: repoerr.ErrConflict,
|
||||
},
|
||||
@@ -1609,33 +1609,27 @@ func TestDeleteClient(t *testing.T) {
|
||||
invalidClientID := "invalidClientID"
|
||||
_ = invalidClientID
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
deletePolicyResponse *magistrala.DeletePolicyFilterRes
|
||||
deletePolicyResponse1 *magistrala.DeletePolicyFilterRes
|
||||
deletePolicyResponse2 *magistrala.DeletePolicyFilterRes
|
||||
clientID string
|
||||
identifyErr error
|
||||
authorizeErr error
|
||||
removeErr error
|
||||
deleteErr error
|
||||
deletePolicyErr error
|
||||
deletePolicyErr1 error
|
||||
deletePolicyErr2 error
|
||||
err error
|
||||
desc string
|
||||
token string
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
deletePolicyResponse *magistrala.DeletePolicyRes
|
||||
clientID string
|
||||
identifyErr error
|
||||
authorizeErr error
|
||||
removeErr error
|
||||
deleteErr error
|
||||
deletePolicyErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "Delete client with authorized token",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse1: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse2: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
err: nil,
|
||||
desc: "Delete client with authorized token",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with unauthorized token",
|
||||
@@ -1655,15 +1649,14 @@ func TestDeleteClient(t *testing.T) {
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with repo error ",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse1: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deleteErr: repoerr.ErrRemoveEntity,
|
||||
err: repoerr.ErrRemoveEntity,
|
||||
desc: "Delete client with repo error ",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
deleteErr: repoerr.ErrRemoveEntity,
|
||||
err: repoerr.ErrRemoveEntity,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with cache error ",
|
||||
@@ -1675,60 +1668,26 @@ func TestDeleteClient(t *testing.T) {
|
||||
err: repoerr.ErrRemoveEntity,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with failed to delete groups policy",
|
||||
desc: "Delete client with failed to delete policy",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
deletePolicyErr: errRemovePolicies,
|
||||
err: errRemovePolicies,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with failed to delete domains policy",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse1: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyErr1: errRemovePolicies,
|
||||
err: errRemovePolicies,
|
||||
},
|
||||
{
|
||||
desc: "Delete client with failed to delete users policy",
|
||||
token: validToken,
|
||||
clientID: client.ID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse1: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyResponse2: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyErr2: errRemovePolicies,
|
||||
err: errRemovePolicies,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr)
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr)
|
||||
repoCall2 := cache.On("Remove", mock.Anything, tc.clientID).Return(tc.removeErr)
|
||||
repoCall3 := auth.On("DeletePolicyFilter", context.Background(), &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: authsvc.GroupType,
|
||||
Object: tc.clientID,
|
||||
ObjectType: authsvc.ThingType,
|
||||
repoCall3 := auth.On("DeleteEntityPolicies", context.Background(), &magistrala.DeleteEntityPoliciesReq{
|
||||
EntityType: authsvc.ThingType,
|
||||
Id: tc.clientID,
|
||||
}).Return(tc.deletePolicyResponse, tc.deletePolicyErr)
|
||||
repoCall4 := auth.On("DeletePolicyFilter", mock.Anything, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: authsvc.DomainType,
|
||||
Object: tc.clientID,
|
||||
ObjectType: authsvc.ThingType,
|
||||
}).Return(tc.deletePolicyResponse1, tc.deletePolicyErr1)
|
||||
repoCall5 := cRepo.On("Delete", context.Background(), tc.clientID).Return(tc.deleteErr)
|
||||
repoCall6 := auth.On("DeletePolicyFilter", mock.Anything, &magistrala.DeletePolicyFilterReq{
|
||||
SubjectType: authsvc.UserType,
|
||||
Object: tc.clientID,
|
||||
ObjectType: authsvc.ThingType,
|
||||
}).Return(tc.deletePolicyResponse2, tc.deletePolicyErr2)
|
||||
repoCall4 := cRepo.On("Delete", context.Background(), tc.clientID).Return(tc.deleteErr)
|
||||
err := svc.DeleteClient(context.Background(), tc.token, tc.clientID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
@@ -1736,8 +1695,6 @@ func TestDeleteClient(t *testing.T) {
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
repoCall4.Unset()
|
||||
repoCall5.Unset()
|
||||
repoCall6.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1832,7 +1789,7 @@ func TestUnShare(t *testing.T) {
|
||||
userID string
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
deletePoliciesResponse *magistrala.DeletePoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePolicyRes
|
||||
identifyErr error
|
||||
authorizeErr error
|
||||
deletePoliciesErr error
|
||||
@@ -1844,7 +1801,7 @@ func TestUnShare(t *testing.T) {
|
||||
clientID: clientID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -1870,7 +1827,7 @@ func TestUnShare(t *testing.T) {
|
||||
clientID: clientID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{},
|
||||
deletePoliciesErr: svcerr.ErrInvalidPolicy,
|
||||
err: svcerr.ErrInvalidPolicy,
|
||||
},
|
||||
@@ -1880,7 +1837,7 @@ func TestUnShare(t *testing.T) {
|
||||
clientID: clientID,
|
||||
identifyResponse: &magistrala.IdentityRes{Id: validID, DomainId: testsutil.GenerateUUID(t)},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: false},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ func (repo singleUserRepo) AddPolicies(ctx context.Context, in *magistrala.AddPo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (repo singleUserRepo) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyFilterRes, error) {
|
||||
func (repo singleUserRepo) DeletePolicyFilter(ctx context.Context, in *magistrala.DeletePolicyFilterReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (repo singleUserRepo) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) {
|
||||
func (repo singleUserRepo) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -97,3 +97,7 @@ func (repo singleUserRepo) CountSubjects(ctx context.Context, in *magistrala.Cou
|
||||
func (repo singleUserRepo) ListPermissions(ctx context.Context, in *magistrala.ListPermissionsReq, opts ...grpc.CallOption) (*magistrala.ListPermissionsRes, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (repo singleUserRepo) DeleteEntityPolicies(ctx context.Context, in *magistrala.DeleteEntityPoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ The service is configured using the environment variables presented in the follo
|
||||
| MG_EMAIL_TEMPLATE | Email template for sending emails with password reset link | email.tmpl |
|
||||
| MG_USERS_ES_URL | Event store URL | <nats://localhost:4222> |
|
||||
| MG_JAEGER_URL | Jaeger server URL | <http://localhost:14268/api/traces> |
|
||||
| MG_OAUTH_UI_REDIRECT_URL | OAuth UI redirect URL | <http://localhost:9095/domains> |
|
||||
| MG_OAUTH_UI_ERROR_URL | OAuth UI error URL | <http://localhost:9095/error> |
|
||||
| MG_USERS_DELETE_INTERVAL | Interval for deleting users | 24h |
|
||||
| MG_USERS_DELETE_AFTER | Time after which users are deleted | 720h |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server. | true |
|
||||
| MG_USERS_INSTANCE_ID | Magistrala instance ID | "" |
|
||||
@@ -107,6 +111,10 @@ MG_USERS_ES_URL=nats://localhost:4222 \
|
||||
MG_JAEGER_URL=http://localhost:14268/api/traces \
|
||||
MG_JAEGER_TRACE_RATIO=1.0 \
|
||||
MG_SEND_TELEMETRY=true \
|
||||
MG_OAUTH_UI_REDIRECT_URL=http://localhost:9095/domains \
|
||||
MG_OAUTH_UI_ERROR_URL=http://localhost:9095/error \
|
||||
MG_USERS_DELETE_INTERVAL=24h \
|
||||
MG_USERS_DELETE_AFTER=720h \
|
||||
MG_USERS_INSTANCE_ID="" \
|
||||
$GOBIN/magistrala-users
|
||||
```
|
||||
|
||||
@@ -124,6 +124,13 @@ func clientsHandler(svc users.Service, r *chi.Mux, logger *slog.Logger, pr *rege
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "disable_client").ServeHTTP)
|
||||
|
||||
r.Delete("/{id}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
deleteClientEndpoint(svc),
|
||||
decodeChangeClientStatus,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "delete_client").ServeHTTP)
|
||||
})
|
||||
|
||||
r.Route("/password", func(r chi.Router) {
|
||||
|
||||
@@ -1734,6 +1734,74 @@ func TestDisableClient(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteClient(t *testing.T) {
|
||||
us, svc, _ := newUsersServer()
|
||||
defer us.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
client mgclients.Client
|
||||
response mgclients.Client
|
||||
token string
|
||||
status int
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete user with valid token",
|
||||
client: client,
|
||||
response: mgclients.Client{
|
||||
ID: client.ID,
|
||||
},
|
||||
token: validToken,
|
||||
status: http.StatusNoContent,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete user with invalid token",
|
||||
client: client,
|
||||
token: inValidToken,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "delete user with empty id",
|
||||
client: mgclients.Client{
|
||||
ID: "",
|
||||
},
|
||||
token: validToken,
|
||||
status: http.StatusMethodNotAllowed,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "delete user with invalid id",
|
||||
client: mgclients.Client{
|
||||
ID: "invalid",
|
||||
},
|
||||
token: validToken,
|
||||
status: http.StatusForbidden,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
data := toJSON(tc.client)
|
||||
req := testRequest{
|
||||
client: us.Client(),
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/users/%s", us.URL, tc.client.ID),
|
||||
contentType: contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(data),
|
||||
}
|
||||
|
||||
repoCall := svc.On("DeleteClient", mock.Anything, mock.Anything, mock.Anything).Return(tc.err)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListUsersByUserGroupId(t *testing.T) {
|
||||
us, svc, _ := newUsersServer()
|
||||
defer us.Close()
|
||||
|
||||
+17
-2
@@ -360,7 +360,7 @@ func enableClientEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deleteClientRes{Client: client}, nil
|
||||
return changeClientStatusClientRes{Client: client}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +376,22 @@ func disableClientEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deleteClientRes{Client: client}, nil
|
||||
return changeClientStatusClientRes{Client: client}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func deleteClientEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(changeClientStatusReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
if err := svc.DeleteClient(ctx, req.token, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deleteClientRes{true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -413,3 +413,20 @@ func (lm *loggingMiddleware) OAuthCallback(ctx context.Context, client mgclients
|
||||
}(time.Now())
|
||||
return lm.svc.OAuthCallback(ctx, client)
|
||||
}
|
||||
|
||||
// DeleteClient logs the delete_client request. It logs the client id and token and the time it took to complete the request.
|
||||
func (lm *loggingMiddleware) DeleteClient(ctx context.Context, token, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("user_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Delete user failed to complete successfully", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Delete user completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.DeleteClient(ctx, token, id)
|
||||
}
|
||||
|
||||
@@ -199,3 +199,12 @@ func (ms *metricsMiddleware) OAuthCallback(ctx context.Context, client mgclients
|
||||
}(time.Now())
|
||||
return ms.svc.OAuthCallback(ctx, client)
|
||||
}
|
||||
|
||||
// DeleteClient instruments DeleteClient method with metrics.
|
||||
func (ms *metricsMiddleware) DeleteClient(ctx context.Context, token, id string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "delete_client").Add(1)
|
||||
ms.latency.With("method", "delete_client").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.DeleteClient(ctx, token, id)
|
||||
}
|
||||
|
||||
+32
-5
@@ -18,9 +18,16 @@ var (
|
||||
_ magistrala.Response = (*tokenRes)(nil)
|
||||
_ magistrala.Response = (*viewClientRes)(nil)
|
||||
_ magistrala.Response = (*createClientRes)(nil)
|
||||
_ magistrala.Response = (*deleteClientRes)(nil)
|
||||
_ magistrala.Response = (*changeClientStatusClientRes)(nil)
|
||||
_ magistrala.Response = (*clientsPageRes)(nil)
|
||||
_ magistrala.Response = (*viewMembersRes)(nil)
|
||||
_ magistrala.Response = (*passwResetReqRes)(nil)
|
||||
_ magistrala.Response = (*passwChangeRes)(nil)
|
||||
_ magistrala.Response = (*assignUsersRes)(nil)
|
||||
_ magistrala.Response = (*unassignUsersRes)(nil)
|
||||
_ magistrala.Response = (*updateClientRes)(nil)
|
||||
_ magistrala.Response = (*tokenRes)(nil)
|
||||
_ magistrala.Response = (*deleteClientRes)(nil)
|
||||
)
|
||||
|
||||
type pageRes struct {
|
||||
@@ -139,19 +146,19 @@ func (res viewMembersRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type deleteClientRes struct {
|
||||
type changeClientStatusClientRes struct {
|
||||
mgclients.Client `json:",inline"`
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Code() int {
|
||||
func (res changeClientStatusClientRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Headers() map[string]string {
|
||||
func (res changeClientStatusClientRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Empty() bool {
|
||||
func (res changeClientStatusClientRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -212,3 +219,23 @@ func (res unassignUsersRes) Headers() map[string]string {
|
||||
func (res unassignUsersRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type deleteClientRes struct {
|
||||
deleted bool
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Code() int {
|
||||
if res.deleted {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res deleteClientRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ type Service interface {
|
||||
// DisableClient logically disables the client identified with the provided ID.
|
||||
DisableClient(ctx context.Context, token, id string) (clients.Client, error)
|
||||
|
||||
// DeleteClient deletes client with given ID.
|
||||
DeleteClient(ctx context.Context, token, id string) error
|
||||
|
||||
// Identify returns the client id from the given token.
|
||||
Identify(ctx context.Context, tkn string) (string, error)
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// The DeleteHandler is a cron job that runs periodically to delete users that have been marked as deleted
|
||||
// for a certain period of time together with the user's policies from the auth service.
|
||||
// The handler runs in a separate goroutine and checks for users that have been marked as deleted for a certain period of time.
|
||||
// If the user has been marked as deleted for more than the specified period,
|
||||
// the handler deletes the user's policies from the auth service and deletes the user from the database.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
mgclients "github.com/absmach/magistrala/pkg/clients"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/users/postgres"
|
||||
)
|
||||
|
||||
const defLimit = uint64(100)
|
||||
|
||||
type handler struct {
|
||||
clients postgres.Repository
|
||||
auth magistrala.AuthServiceClient
|
||||
checkInterval time.Duration
|
||||
deleteAfter time.Duration
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewDeleteHandler(ctx context.Context, clients postgres.Repository, auth magistrala.AuthServiceClient, defCheckInterval, deleteAfter time.Duration, logger *slog.Logger) {
|
||||
handler := &handler{
|
||||
clients: clients,
|
||||
auth: auth,
|
||||
checkInterval: defCheckInterval,
|
||||
deleteAfter: deleteAfter,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(handler.checkInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
handler.handle(ctx)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *handler) handle(ctx context.Context) {
|
||||
pm := mgclients.Page{Limit: defLimit, Offset: 0, Status: mgclients.DeletedStatus}
|
||||
|
||||
for {
|
||||
dbUsers, err := h.clients.RetrieveAll(ctx, pm)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to retrieve users", slog.Any("error", err))
|
||||
break
|
||||
}
|
||||
if dbUsers.Total == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for _, u := range dbUsers.Clients {
|
||||
if time.Since(u.UpdatedAt) < h.deleteAfter {
|
||||
continue
|
||||
}
|
||||
|
||||
deleteRes, err := h.auth.DeleteEntityPolicies(ctx, &magistrala.DeleteEntityPoliciesReq{
|
||||
Id: u.ID,
|
||||
EntityType: auth.UserType,
|
||||
})
|
||||
if err != nil {
|
||||
h.logger.Error("failed to delete user policies", slog.Any("error", err))
|
||||
continue
|
||||
}
|
||||
if !deleteRes.Deleted {
|
||||
h.logger.Error("failed to delete user policies", slog.Any("error", svcerr.ErrAuthorization))
|
||||
continue
|
||||
}
|
||||
|
||||
if err := h.clients.Delete(ctx, u.ID); err != nil {
|
||||
h.logger.Error("failed to delete user", slog.Any("error", err))
|
||||
continue
|
||||
}
|
||||
|
||||
h.logger.Info("user deleted", slog.Group("user",
|
||||
slog.String("id", u.ID),
|
||||
slog.String("name", u.Name),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
resetSecret = clientPrefix + "reset_secret"
|
||||
sendPasswordReset = clientPrefix + "send_password_reset"
|
||||
oauthCallback = clientPrefix + "oauth_callback"
|
||||
deleteClient = clientPrefix + "delete"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -43,6 +44,7 @@ var (
|
||||
_ events.Event = (*resetSecretEvent)(nil)
|
||||
_ events.Event = (*sendPasswordResetEvent)(nil)
|
||||
_ events.Event = (*oauthCallbackEvent)(nil)
|
||||
_ events.Event = (*deleteClientEvent)(nil)
|
||||
)
|
||||
|
||||
type createClientEvent struct {
|
||||
@@ -386,3 +388,14 @@ func (oce oauthCallbackEvent) Encode() (map[string]interface{}, error) {
|
||||
"client_id": oce.clientID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type deleteClientEvent struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (dce deleteClientEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": deleteClient,
|
||||
"id": dce.id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -312,3 +312,15 @@ func (es *eventStore) OAuthCallback(ctx context.Context, client mgclients.Client
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) DeleteClient(ctx context.Context, token, id string) error {
|
||||
if err := es.svc.DeleteClient(ctx, token, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := deleteClientEvent{
|
||||
id: id,
|
||||
}
|
||||
|
||||
return es.Publish(ctx, event)
|
||||
}
|
||||
|
||||
@@ -63,6 +63,24 @@ func (_m *Repository) CheckSuperAdmin(ctx context.Context, adminID string) error
|
||||
return r0
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, id
|
||||
func (_m *Repository) Delete(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// RetrieveAll provides a mock function with given fields: ctx, pm
|
||||
func (_m *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
|
||||
ret := _m.Called(ctx, pm)
|
||||
|
||||
@@ -19,6 +19,24 @@ type Service struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// DeleteClient provides a mock function with given fields: ctx, token, id
|
||||
func (_m *Service) DeleteClient(ctx context.Context, token string, id string) error {
|
||||
ret := _m.Called(ctx, token, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteClient")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, token, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DisableClient provides a mock function with given fields: ctx, token, id
|
||||
func (_m *Service) DisableClient(ctx context.Context, token string, id string) (clients.Client, error) {
|
||||
ret := _m.Called(ctx, token, id)
|
||||
|
||||
+18
-2
@@ -435,8 +435,10 @@ func (svc service) changeClientStatus(ctx context.Context, token string, client
|
||||
if err != nil {
|
||||
return mgclients.Client{}, err
|
||||
}
|
||||
if err := svc.checkSuperAdmin(ctx, tokenUserID); err != nil {
|
||||
return mgclients.Client{}, err
|
||||
if tokenUserID != client.ID {
|
||||
if err := svc.checkSuperAdmin(ctx, tokenUserID); err != nil {
|
||||
return mgclients.Client{}, err
|
||||
}
|
||||
}
|
||||
dbClient, err := svc.clients.RetrieveByID(ctx, client.ID)
|
||||
if err != nil {
|
||||
@@ -454,6 +456,20 @@ func (svc service) changeClientStatus(ctx context.Context, token string, client
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (svc service) DeleteClient(ctx context.Context, token, id string) error {
|
||||
client := mgclients.Client{
|
||||
ID: id,
|
||||
UpdatedAt: time.Now(),
|
||||
Status: mgclients.DeletedStatus,
|
||||
}
|
||||
|
||||
if _, err := svc.changeClientStatus(ctx, token, client); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc service) ListMembers(ctx context.Context, token, objectKind, objectID string, pm mgclients.Page) (mgclients.MembersPage, error) {
|
||||
res, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
|
||||
+136
-150
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/absmach/magistrala/users/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -66,7 +65,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
client mgclients.Client
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
addPoliciesResponse *magistrala.AddPoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePolicyRes
|
||||
token string
|
||||
identifyErr error
|
||||
addPoliciesResponseErr error
|
||||
@@ -85,7 +84,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
desc: "register existing client",
|
||||
client: client,
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
token: validToken,
|
||||
saveErr: repoerr.ErrConflict,
|
||||
err: repoerr.ErrConflict,
|
||||
@@ -144,7 +143,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
},
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
saveErr: errors.ErrMalformedEntity,
|
||||
err: errors.ErrMalformedEntity,
|
||||
token: validToken,
|
||||
@@ -159,7 +158,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
},
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -172,7 +171,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
},
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: repoerr.ErrMalformedEntity,
|
||||
},
|
||||
{
|
||||
@@ -186,7 +185,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
Status: mgclients.AllStatus,
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: svcerr.ErrInvalidStatus,
|
||||
},
|
||||
{
|
||||
@@ -200,7 +199,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
Role: 2,
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
err: svcerr.ErrInvalidRole,
|
||||
},
|
||||
{
|
||||
@@ -241,7 +240,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
Role: mgclients.AdminRole,
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: false},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
deletePoliciesResponseErr: svcerr.ErrConflict,
|
||||
saveErr: repoerr.ErrConflict,
|
||||
err: svcerr.ErrConflict,
|
||||
@@ -257,7 +256,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
Role: mgclients.AdminRole,
|
||||
},
|
||||
addPoliciesResponse: &magistrala.AddPoliciesRes{Added: true},
|
||||
deletePoliciesResponse: &magistrala.DeletePoliciesRes{Deleted: false},
|
||||
deletePoliciesResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
saveErr: repoerr.ErrConflict,
|
||||
err: svcerr.ErrConflict,
|
||||
},
|
||||
@@ -292,7 +291,7 @@ func TestRegisterClient(t *testing.T) {
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
addPoliciesResponse *magistrala.AddPoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePolicyRes
|
||||
token string
|
||||
identifyErr error
|
||||
authorizeErr error
|
||||
@@ -1005,7 +1004,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
membershipAuthReq *magistrala.AuthorizeReq
|
||||
superAdminAuthRes *magistrala.AuthorizeRes
|
||||
membershipAuthRes *magistrala.AuthorizeRes
|
||||
deletePolicyFilterResponse *magistrala.DeletePolicyFilterRes
|
||||
deletePolicyFilterResponse *magistrala.DeletePolicyRes
|
||||
addPolicyResponse *magistrala.AddPolicyRes
|
||||
updateRoleResponse mgclients.Client
|
||||
token string
|
||||
@@ -1095,7 +1094,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
superAdminAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
membershipAuthReq: membershipAuthReq,
|
||||
membershipAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
updateRoleResponse: client2,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
@@ -1108,7 +1107,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
superAdminAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
membershipAuthReq: membershipAuthReq,
|
||||
membershipAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
updateRoleResponse: mgclients.Client{},
|
||||
token: validToken,
|
||||
deletePolicyErr: svcerr.ErrAuthorization,
|
||||
@@ -1122,7 +1121,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
superAdminAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
membershipAuthReq: membershipAuthReq,
|
||||
membershipAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
updateRoleResponse: mgclients.Client{},
|
||||
token: validToken,
|
||||
deletePolicyErr: svcerr.ErrMalformedEntity,
|
||||
@@ -1137,7 +1136,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
membershipAuthReq: membershipAuthReq,
|
||||
membershipAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
addPolicyResponse: &magistrala.AddPolicyRes{Added: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyFilterRes{Deleted: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyRes{Deleted: true},
|
||||
updateRoleResponse: mgclients.Client{},
|
||||
token: validToken,
|
||||
updateRoleErr: svcerr.ErrAuthentication,
|
||||
@@ -1152,7 +1151,7 @@ func TestUpdateClientRole(t *testing.T) {
|
||||
membershipAuthReq: membershipAuthReq,
|
||||
membershipAuthRes: &magistrala.AuthorizeRes{Authorized: true},
|
||||
addPolicyResponse: &magistrala.AddPolicyRes{Added: true},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyFilterRes{Deleted: false},
|
||||
deletePolicyFilterResponse: &magistrala.DeletePolicyRes{Deleted: false},
|
||||
updateRoleResponse: mgclients.Client{},
|
||||
token: validToken,
|
||||
updateRoleErr: svcerr.ErrAuthentication,
|
||||
@@ -1375,17 +1374,14 @@ func TestEnableClient(t *testing.T) {
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "enable disabled client with failed to authorize",
|
||||
id: disabledClient1.ID,
|
||||
token: validToken,
|
||||
client: disabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: disabledClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: false},
|
||||
retrieveByIDResponse: mgclients.Client{},
|
||||
changeStatusResponse: mgclients.Client{},
|
||||
response: mgclients.Client{},
|
||||
identifyErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
desc: "enable disabled client with failed to authorize",
|
||||
id: disabledClient1.ID,
|
||||
token: validToken,
|
||||
client: disabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: disabledClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: false},
|
||||
identifyErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "enable disabled client with normal user token",
|
||||
@@ -1453,72 +1449,6 @@ func TestEnableClient(t *testing.T) {
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
}
|
||||
|
||||
cases2 := []struct {
|
||||
desc string
|
||||
status mgclients.Status
|
||||
size uint64
|
||||
response mgclients.ClientsPage
|
||||
}{
|
||||
{
|
||||
desc: "list enabled clients",
|
||||
status: mgclients.EnabledStatus,
|
||||
size: 2,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 2,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{enabledClient1, endisabledClient1},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list disabled clients",
|
||||
status: mgclients.DisabledStatus,
|
||||
size: 1,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{disabledClient1},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list enabled and disabled clients",
|
||||
status: mgclients.AllStatus,
|
||||
size: 3,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 3,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{enabledClient1, disabledClient1, endisabledClient1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases2 {
|
||||
pm := mgclients.Page{
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
Status: tc.status,
|
||||
}
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{UserId: client.ID}, nil)
|
||||
authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.response, nil)
|
||||
|
||||
page, err := svc.ListClients(context.Background(), validToken, pm)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(page.Clients))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
authCall.Unset()
|
||||
authCall1.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableClient(t *testing.T) {
|
||||
@@ -1582,7 +1512,7 @@ func TestDisableClient(t *testing.T) {
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: enabledClient1.ID},
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: validID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: false},
|
||||
checkSuperAdminErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
@@ -1643,71 +1573,128 @@ func TestDisableClient(t *testing.T) {
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
cases2 := []struct {
|
||||
desc string
|
||||
status mgclients.Status
|
||||
size uint64
|
||||
response mgclients.ClientsPage
|
||||
func TestDeleteClient(t *testing.T) {
|
||||
svc, cRepo, auth, _ := newService(true)
|
||||
|
||||
enabledClient1 := mgclients.Client{ID: testsutil.GenerateUUID(t), Credentials: mgclients.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mgclients.EnabledStatus}
|
||||
deletedClient1 := mgclients.Client{ID: testsutil.GenerateUUID(t), Credentials: mgclients.Credentials{Identity: "client3@example.com", Secret: "password"}, Status: mgclients.DeletedStatus}
|
||||
disenabledClient1 := enabledClient1
|
||||
disenabledClient1.Status = mgclients.DeletedStatus
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
client mgclients.Client
|
||||
identifyResponse *magistrala.IdentityRes
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
retrieveByIDResponse mgclients.Client
|
||||
changeStatusResponse mgclients.Client
|
||||
response mgclients.Client
|
||||
identifyErr error
|
||||
authorizeErr error
|
||||
retrieveByIDErr error
|
||||
changeStatusErr error
|
||||
checkSuperAdminErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list enabled clients",
|
||||
status: mgclients.EnabledStatus,
|
||||
size: 1,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{enabledClient1},
|
||||
},
|
||||
desc: "delete enabled client",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: enabledClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
retrieveByIDResponse: enabledClient1,
|
||||
changeStatusResponse: disenabledClient1,
|
||||
response: disenabledClient1,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list disabled clients",
|
||||
status: mgclients.DisabledStatus,
|
||||
size: 2,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 2,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{disenabledClient1, disabledClient1},
|
||||
},
|
||||
desc: "delete enabled client with invalid token",
|
||||
id: enabledClient1.ID,
|
||||
token: inValidToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{},
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "list enabled and disabled clients",
|
||||
status: mgclients.AllStatus,
|
||||
size: 3,
|
||||
response: mgclients.ClientsPage{
|
||||
Page: mgclients.Page{
|
||||
Total: 3,
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
},
|
||||
Clients: []mgclients.Client{enabledClient1, disabledClient1, disenabledClient1},
|
||||
},
|
||||
desc: "delete enabled client with failed to authorize",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: deletedClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "delete enabled client with normal user token",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: validID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: false},
|
||||
checkSuperAdminErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "delete enabled client with failed to retrieve client by ID",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: enabledClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
retrieveByIDResponse: mgclients.Client{},
|
||||
retrieveByIDErr: repoerr.ErrNotFound,
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "delete already deleted client",
|
||||
id: deletedClient1.ID,
|
||||
token: validToken,
|
||||
client: deletedClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: deletedClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
retrieveByIDResponse: deletedClient1,
|
||||
err: errors.ErrStatusAlreadyAssigned,
|
||||
},
|
||||
{
|
||||
desc: "delete enabled client with failed to change status",
|
||||
id: enabledClient1.ID,
|
||||
token: validToken,
|
||||
client: enabledClient1,
|
||||
identifyResponse: &magistrala.IdentityRes{UserId: enabledClient1.ID},
|
||||
authorizeResponse: &magistrala.AuthorizeRes{Authorized: true},
|
||||
retrieveByIDResponse: enabledClient1,
|
||||
changeStatusResponse: mgclients.Client{},
|
||||
changeStatusErr: repoerr.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases2 {
|
||||
pm := mgclients.Page{
|
||||
Offset: 0,
|
||||
Limit: 100,
|
||||
Status: tc.status,
|
||||
}
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: validToken}).Return(&magistrala.IdentityRes{UserId: client.ID}, nil)
|
||||
authCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(&magistrala.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.response, nil)
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(tc.identifyResponse, tc.identifyErr)
|
||||
repoCall1 := auth.On("Authorize", context.Background(), mock.Anything).Return(tc.authorizeResponse, tc.authorizeErr)
|
||||
repoCall2 := cRepo.On("CheckSuperAdmin", context.Background(), mock.Anything).Return(tc.checkSuperAdminErr)
|
||||
repoCall3 := cRepo.On("RetrieveByID", context.Background(), tc.id).Return(tc.retrieveByIDResponse, tc.retrieveByIDErr)
|
||||
repoCall4 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.changeStatusResponse, tc.changeStatusErr)
|
||||
|
||||
page, err := svc.ListClients(context.Background(), validToken, pm)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(page.Clients))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
authCall.Unset()
|
||||
authCall1.Unset()
|
||||
err := svc.DeleteClient(context.Background(), tc.token, tc.id)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
if tc.err == nil {
|
||||
ok := repoCall3.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.id)
|
||||
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
||||
ok = repoCall4.Parent.AssertCalled(t, "ChangeStatus", context.Background(), mock.Anything)
|
||||
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
|
||||
}
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
repoCall4.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2603,7 +2590,7 @@ func TestOAuthCallback(t *testing.T) {
|
||||
addPoliciesErr error
|
||||
saveResponse mgclients.Client
|
||||
saveErr error
|
||||
deletePoliciesResponse *magistrala.DeletePoliciesRes
|
||||
deletePoliciesResponse *magistrala.DeletePolicyRes
|
||||
deletePoliciesErr error
|
||||
authorizeResponse *magistrala.AuthorizeRes
|
||||
authorizeErr error
|
||||
@@ -2728,7 +2715,6 @@ func TestOAuthCallback(t *testing.T) {
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
id := tc.saveResponse.ID
|
||||
if tc.retrieveByIdentityResponse.ID != "" {
|
||||
|
||||
@@ -202,3 +202,11 @@ func (tm *tracingMiddleware) OAuthCallback(ctx context.Context, client mgclients
|
||||
|
||||
return tm.svc.OAuthCallback(ctx, client)
|
||||
}
|
||||
|
||||
// DeleteClient traces the "DeleteClient" operation of the wrapped clients.Service.
|
||||
func (tm *tracingMiddleware) DeleteClient(ctx context.Context, token, id string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_delete_client", trace.WithAttributes(attribute.String("id", id)))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.DeleteClient(ctx, token, id)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user