mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 04:20:17 +00:00
a0c40ba462
* chore(license): update copyright notices Add CI check for non go files to check that the files contain a license Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * fix(ci): log failed files When the CI fails during check for license header, log the failed file to console so that someone can check on the actual file. Also simplify the grep check to make it more human readable and understandable Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>
657 lines
21 KiB
Go
657 lines
21 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package spicedb
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/absmach/magistrala/auth"
|
|
mglog "github.com/absmach/magistrala/logger"
|
|
"github.com/absmach/magistrala/pkg/errors"
|
|
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
|
|
"github.com/authzed/authzed-go/v1"
|
|
)
|
|
|
|
const defRetrieveAllLimit = 1000
|
|
|
|
var (
|
|
errInvalidSubject = errors.New("invalid subject kind")
|
|
errAddPolicies = errors.New("failed to add policies")
|
|
errRetrievePolicies = errors.New("failed to retrieve policies")
|
|
errRemovePolicies = errors.New("failed to remove the policies")
|
|
errNoPolicies = errors.New("no policies provided")
|
|
errPermission = errors.New("failed to check permission")
|
|
)
|
|
|
|
type policyAgent struct {
|
|
client *authzed.Client
|
|
permissionClient v1.PermissionsServiceClient
|
|
logger mglog.Logger
|
|
}
|
|
|
|
func NewPolicyAgent(client *authzed.Client, logger mglog.Logger) auth.PolicyAgent {
|
|
return &policyAgent{
|
|
client: client,
|
|
permissionClient: client.PermissionsServiceClient,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) CheckPolicy(ctx context.Context, pr auth.PolicyReq) error {
|
|
checkReq := v1.CheckPermissionRequest{
|
|
Resource: &v1.ObjectReference{ObjectType: pr.ObjectType, ObjectId: pr.Object},
|
|
Permission: pr.Permission,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
}
|
|
|
|
resp, err := pa.permissionClient.CheckPermission(ctx, &checkReq)
|
|
if err != nil {
|
|
return errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errPermission, err))
|
|
}
|
|
if resp.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION {
|
|
return nil
|
|
}
|
|
if reason, ok := v1.CheckPermissionResponse_Permissionship_name[int32(resp.Permissionship)]; ok {
|
|
return errors.Wrap(errors.ErrAuthorization, errors.New(reason))
|
|
}
|
|
return errors.ErrAuthorization
|
|
}
|
|
|
|
func (pa *policyAgent) AddPolicies(ctx context.Context, prs []auth.PolicyReq) error {
|
|
updates := []*v1.RelationshipUpdate{}
|
|
var preconds []*v1.Precondition
|
|
for _, pr := range prs {
|
|
precond, err := pa.addPolicyPreCondition(ctx, pr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
preconds = append(preconds, precond...)
|
|
updates = append(updates, &v1.RelationshipUpdate{
|
|
Operation: v1.RelationshipUpdate_OPERATION_CREATE,
|
|
Relationship: &v1.Relationship{
|
|
Resource: &v1.ObjectReference{ObjectType: pr.ObjectType, ObjectId: pr.Object},
|
|
Relation: pr.Relation,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
},
|
|
})
|
|
}
|
|
if len(updates) == 0 {
|
|
return errNoPolicies
|
|
}
|
|
_, err := pa.permissionClient.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{Updates: updates, OptionalPreconditions: preconds})
|
|
if err != nil {
|
|
return errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errAddPolicies, err))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pa *policyAgent) AddPolicy(ctx context.Context, pr auth.PolicyReq) error {
|
|
precond, err := pa.addPolicyPreCondition(ctx, pr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
updates := []*v1.RelationshipUpdate{
|
|
{
|
|
Operation: v1.RelationshipUpdate_OPERATION_CREATE,
|
|
Relationship: &v1.Relationship{
|
|
Resource: &v1.ObjectReference{ObjectType: pr.ObjectType, ObjectId: pr.Object},
|
|
Relation: pr.Relation,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
},
|
|
},
|
|
}
|
|
_, err = pa.permissionClient.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{Updates: updates, OptionalPreconditions: precond})
|
|
if err != nil {
|
|
return errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errAddPolicies, err))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pa *policyAgent) DeletePolicies(ctx context.Context, prs []auth.PolicyReq) error {
|
|
updates := []*v1.RelationshipUpdate{}
|
|
for _, pr := range prs {
|
|
updates = append(updates, &v1.RelationshipUpdate{
|
|
Operation: v1.RelationshipUpdate_OPERATION_DELETE,
|
|
Relationship: &v1.Relationship{
|
|
Resource: &v1.ObjectReference{ObjectType: pr.ObjectType, ObjectId: pr.Object},
|
|
Relation: pr.Relation,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
},
|
|
})
|
|
}
|
|
if len(updates) == 0 {
|
|
return errNoPolicies
|
|
}
|
|
_, err := pa.permissionClient.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{Updates: updates})
|
|
if err != nil {
|
|
return errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errRemovePolicies, err))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pa *policyAgent) DeletePolicy(ctx context.Context, pr auth.PolicyReq) error {
|
|
req := &v1.DeleteRelationshipsRequest{
|
|
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 _, err := pa.permissionClient.DeleteRelationships(ctx, req); err != nil {
|
|
return errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errRemovePolicies, err))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RetrieveObjects - Listing of things.
|
|
func (pa *policyAgent) RetrieveObjects(ctx context.Context, pr auth.PolicyReq, nextPageToken string, limit int32) ([]auth.PolicyRes, string, error) {
|
|
resourceReq := &v1.LookupResourcesRequest{
|
|
ResourceObjectType: pr.ObjectType,
|
|
Permission: pr.Permission,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
OptionalLimit: uint32(limit),
|
|
}
|
|
if nextPageToken != "" {
|
|
resourceReq.OptionalCursor = &v1.Cursor{Token: nextPageToken}
|
|
}
|
|
stream, err := pa.permissionClient.LookupResources(ctx, resourceReq)
|
|
if err != nil {
|
|
return nil, "", errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errRetrievePolicies, err))
|
|
}
|
|
resources := []*v1.LookupResourcesResponse{}
|
|
var token string
|
|
for {
|
|
resp, err := stream.Recv()
|
|
switch err {
|
|
case nil:
|
|
resources = append(resources, resp)
|
|
case io.EOF:
|
|
if len(resources) > 0 && resources[len(resources)-1].AfterResultCursor != nil {
|
|
token = resources[len(resources)-1].AfterResultCursor.Token
|
|
}
|
|
return objectsToAuthPolicies(resources), token, nil
|
|
default:
|
|
if len(resources) > 0 && resources[len(resources)-1].AfterResultCursor != nil {
|
|
token = resources[len(resources)-1].AfterResultCursor.Token
|
|
}
|
|
return objectsToAuthPolicies(resources), token, errors.Wrap(errors.ErrViewEntity, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) RetrieveAllObjects(ctx context.Context, pr auth.PolicyReq) ([]auth.PolicyRes, error) {
|
|
resourceReq := &v1.LookupResourcesRequest{
|
|
ResourceObjectType: pr.ObjectType,
|
|
Permission: pr.Permission,
|
|
Subject: &v1.SubjectReference{Object: &v1.ObjectReference{ObjectType: pr.SubjectType, ObjectId: pr.Subject}, OptionalRelation: pr.SubjectRelation},
|
|
}
|
|
stream, err := pa.permissionClient.LookupResources(ctx, resourceReq)
|
|
if err != nil {
|
|
return nil, errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errRetrievePolicies, err))
|
|
}
|
|
tuples := []auth.PolicyRes{}
|
|
for {
|
|
resp, err := stream.Recv()
|
|
switch {
|
|
case errors.Contains(err, io.EOF):
|
|
return tuples, nil
|
|
case err != nil:
|
|
return tuples, err
|
|
default:
|
|
tuples = append(tuples, auth.PolicyRes{Object: resp.ResourceObjectId})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) RetrieveAllObjectsCount(ctx context.Context, pr auth.PolicyReq) (int, error) {
|
|
var count int
|
|
nextPageToken := ""
|
|
for {
|
|
relationTuples, npt, err := pa.RetrieveObjects(ctx, pr, nextPageToken, defRetrieveAllLimit)
|
|
if err != nil {
|
|
return count, err
|
|
}
|
|
count = count + len(relationTuples)
|
|
if npt == "" {
|
|
break
|
|
}
|
|
nextPageToken = npt
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func (pa *policyAgent) RetrieveSubjects(ctx context.Context, pr auth.PolicyReq, nextPageToken string, limit int32) ([]auth.PolicyRes, string, error) {
|
|
subjectsReq := v1.LookupSubjectsRequest{
|
|
Resource: &v1.ObjectReference{ObjectType: pr.ObjectType, ObjectId: pr.Object},
|
|
Permission: pr.Permission,
|
|
SubjectObjectType: pr.SubjectType,
|
|
OptionalSubjectRelation: pr.SubjectRelation,
|
|
OptionalConcreteLimit: uint32(limit),
|
|
WildcardOption: v1.LookupSubjectsRequest_WILDCARD_OPTION_INCLUDE_WILDCARDS,
|
|
}
|
|
if nextPageToken != "" {
|
|
subjectsReq.OptionalCursor = &v1.Cursor{Token: nextPageToken}
|
|
}
|
|
stream, err := pa.permissionClient.LookupSubjects(ctx, &subjectsReq)
|
|
if err != nil {
|
|
return nil, "", errors.Wrap(errors.ErrMalformedEntity, errors.Wrap(errRetrievePolicies, err))
|
|
}
|
|
subjects := []*v1.LookupSubjectsResponse{}
|
|
var token string
|
|
for {
|
|
resp, err := stream.Recv()
|
|
|
|
switch err {
|
|
case nil:
|
|
subjects = append(subjects, resp)
|
|
case io.EOF:
|
|
if len(subjects) > 0 && subjects[len(subjects)-1].AfterResultCursor != nil {
|
|
token = subjects[len(subjects)-1].AfterResultCursor.Token
|
|
}
|
|
return subjectsToAuthPolicies(subjects), token, nil
|
|
default:
|
|
if len(subjects) > 0 && subjects[len(subjects)-1].AfterResultCursor != nil {
|
|
token = subjects[len(subjects)-1].AfterResultCursor.Token
|
|
}
|
|
return subjectsToAuthPolicies(subjects), token, errors.Wrap(errors.ErrViewEntity, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) RetrieveAllSubjects(ctx context.Context, pr auth.PolicyReq) ([]auth.PolicyRes, error) {
|
|
var tuples []auth.PolicyRes
|
|
nextPageToken := ""
|
|
for i := 0; ; i++ {
|
|
relationTuples, npt, err := pa.RetrieveSubjects(ctx, pr, nextPageToken, defRetrieveAllLimit)
|
|
if err != nil {
|
|
return tuples, err
|
|
}
|
|
tuples = append(tuples, relationTuples...)
|
|
if npt == "" || (len(tuples) < defRetrieveAllLimit) {
|
|
break
|
|
}
|
|
nextPageToken = npt
|
|
}
|
|
return tuples, nil
|
|
}
|
|
|
|
func (pa *policyAgent) RetrieveAllSubjectsCount(ctx context.Context, pr auth.PolicyReq) (int, error) {
|
|
var count int
|
|
nextPageToken := ""
|
|
for {
|
|
relationTuples, npt, err := pa.RetrieveSubjects(ctx, pr, nextPageToken, defRetrieveAllLimit)
|
|
if err != nil {
|
|
return count, err
|
|
}
|
|
count = count + len(relationTuples)
|
|
if npt == "" {
|
|
break
|
|
}
|
|
nextPageToken = npt
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func objectsToAuthPolicies(objects []*v1.LookupResourcesResponse) []auth.PolicyRes {
|
|
var policies []auth.PolicyRes
|
|
for _, obj := range objects {
|
|
policies = append(policies, auth.PolicyRes{
|
|
Object: obj.GetResourceObjectId(),
|
|
})
|
|
}
|
|
return policies
|
|
}
|
|
|
|
func subjectsToAuthPolicies(subjects []*v1.LookupSubjectsResponse) []auth.PolicyRes {
|
|
var policies []auth.PolicyRes
|
|
for _, sub := range subjects {
|
|
policies = append(policies, auth.PolicyRes{
|
|
Subject: sub.Subject.GetSubjectObjectId(),
|
|
})
|
|
}
|
|
return policies
|
|
}
|
|
|
|
func (pa *policyAgent) Watch(continueToken string) {
|
|
stream, err := pa.client.WatchServiceClient.Watch(context.Background(), &v1.WatchRequest{
|
|
OptionalObjectTypes: []string{},
|
|
OptionalStartCursor: &v1.ZedToken{Token: continueToken},
|
|
})
|
|
if err != nil {
|
|
pa.logger.Error(fmt.Sprintf("got error while watching: %s", err.Error()))
|
|
}
|
|
for {
|
|
watchResp, err := stream.Recv()
|
|
switch err {
|
|
case nil:
|
|
pa.publishToStream(watchResp)
|
|
case io.EOF:
|
|
pa.logger.Info("got EOF while watch streaming")
|
|
return
|
|
default:
|
|
pa.logger.Error(fmt.Sprintf("got error while watch streaming : %s", err.Error()))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) publishToStream(resp *v1.WatchResponse) {
|
|
pa.logger.Info(fmt.Sprintf("Publish next token %s", resp.ChangesThrough.Token))
|
|
|
|
for _, update := range resp.Updates {
|
|
operation := v1.RelationshipUpdate_Operation_name[int32(update.Operation)]
|
|
objectType := update.Relationship.Resource.ObjectType
|
|
objectID := update.Relationship.Resource.ObjectId
|
|
relation := update.Relationship.Relation
|
|
subjectType := update.Relationship.Subject.Object.ObjectType
|
|
subjectRelation := update.Relationship.Subject.OptionalRelation
|
|
subjectID := update.Relationship.Subject.Object.ObjectId
|
|
|
|
pa.logger.Info(fmt.Sprintf(`
|
|
Operation : %s object_type: %s object_id: %s relation: %s subject_type: %s subject_relation: %s subject_id: %s
|
|
`, operation, objectType, objectID, relation, subjectType, subjectRelation, subjectID))
|
|
}
|
|
}
|
|
|
|
func (pa *policyAgent) addPolicyPreCondition(ctx context.Context, pr auth.PolicyReq) ([]*v1.Precondition, error) {
|
|
// Checks are required for following ( -> means adding)
|
|
// 1.) user -> group (both user groups and channels)
|
|
// 2.) user -> thing
|
|
// 3.) group -> group (both for adding parent_group and channels)
|
|
// 4.) group (channel) -> thing
|
|
|
|
switch {
|
|
// 1.) user -> group (both user groups and channels)
|
|
// Checks :
|
|
// - USER with ANY RELATION to DOMAIN
|
|
// - GROUP with DOMAIN RELATION to DOMAIN
|
|
case pr.SubjectType == auth.UserType && pr.ObjectType == auth.GroupType:
|
|
return pa.userGroupPreConditions(ctx, pr)
|
|
|
|
// 2.) user -> thing
|
|
// Checks :
|
|
// - USER with ANY RELATION to DOMAIN
|
|
// - THING with DOMAIN RELATION to DOMAIN
|
|
case pr.SubjectType == auth.UserType && pr.ObjectType == auth.ThingType:
|
|
return pa.userThingPreConditions(ctx, pr)
|
|
|
|
// 3.) group -> group (both for adding parent_group and channels)
|
|
// Checks :
|
|
// - CHILD_GROUP with out PARENT_GROUP RELATION with any GROUP
|
|
case pr.SubjectType == auth.GroupType && pr.ObjectType == auth.GroupType:
|
|
return groupPreConditions(pr)
|
|
|
|
// 4.) group (channel) -> thing
|
|
// Checks :
|
|
// - GROUP (channel) with DOMAIN RELATION to DOMAIN
|
|
// - NO GROUP should not have PARENT_GROUP RELATION with GROUP (channel)
|
|
// - THING with DOMAIN RELATION to DOMAIN
|
|
case pr.SubjectType == auth.GroupType && pr.ObjectType == auth.ThingType:
|
|
return channelThingPreCondition(pr)
|
|
|
|
// Check thing and group not belongs to other domain before adding to domain
|
|
case pr.SubjectType == auth.DomainType && pr.Relation == auth.DomainRelation && (pr.ObjectType == auth.ThingType || pr.ObjectType == auth.GroupType):
|
|
preconds := []*v1.Precondition{
|
|
{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: pr.ObjectType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
return preconds, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (pa *policyAgent) userGroupPreConditions(ctx context.Context, pr auth.PolicyReq) ([]*v1.Precondition, error) {
|
|
var preconds []*v1.Precondition
|
|
isSuperAdmin := false
|
|
if err := pa.CheckPolicy(ctx, auth.PolicyReq{
|
|
Subject: pr.Subject,
|
|
SubjectType: pr.SubjectType,
|
|
Permission: auth.AdminPermission,
|
|
Object: auth.MagistralaObject,
|
|
ObjectType: auth.PlatformType,
|
|
}); err == nil {
|
|
isSuperAdmin = true
|
|
}
|
|
|
|
if !isSuperAdmin {
|
|
preconds = append(preconds, &v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.DomainType,
|
|
OptionalResourceId: pr.Domain,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.UserType,
|
|
OptionalSubjectId: pr.Subject,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
switch {
|
|
case pr.ObjectKind == auth.NewGroupKind || pr.ObjectKind == auth.NewChannelKind:
|
|
preconds = append(preconds,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
default:
|
|
preconds = append(preconds,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
return preconds, nil
|
|
}
|
|
|
|
func (pa *policyAgent) userThingPreConditions(ctx context.Context, pr auth.PolicyReq) ([]*v1.Precondition, error) {
|
|
var preconds []*v1.Precondition
|
|
isSuperAdmin := false
|
|
if err := pa.CheckPolicy(ctx, auth.PolicyReq{
|
|
Subject: pr.Subject,
|
|
SubjectType: pr.SubjectType,
|
|
Permission: auth.AdminPermission,
|
|
Object: auth.MagistralaObject,
|
|
ObjectType: auth.PlatformType,
|
|
}); err == nil {
|
|
isSuperAdmin = true
|
|
}
|
|
|
|
if !isSuperAdmin {
|
|
preconds = append(preconds, &v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.DomainType,
|
|
OptionalResourceId: pr.Domain,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.UserType,
|
|
OptionalSubjectId: pr.Subject,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
switch {
|
|
// For New thing
|
|
// - THING without DOMAIN RELATION to ANY DOMAIN
|
|
case pr.ObjectKind == auth.NewThingKind:
|
|
preconds = append(preconds,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.ThingType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
default:
|
|
// For existing thing
|
|
// - THING without DOMAIN RELATION to ANY DOMAIN
|
|
preconds = append(preconds,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.ThingType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
return preconds, nil
|
|
}
|
|
|
|
func groupPreConditions(pr auth.PolicyReq) ([]*v1.Precondition, error) {
|
|
// - PARENT_GROUP (subject) with DOMAIN RELATION to DOMAIN
|
|
precond := []*v1.Precondition{
|
|
{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Subject,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if pr.ObjectKind != auth.ChannelsKind {
|
|
precond = append(precond,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.ParentGroupRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.GroupType,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
switch {
|
|
// - NEW CHILD_GROUP (object) with out DOMAIN RELATION to ANY DOMAIN
|
|
case pr.ObjectType == auth.GroupType && pr.ObjectKind == auth.NewGroupKind:
|
|
precond = append(precond,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
default:
|
|
// - CHILD_GROUP (object) with DOMAIN RELATION to DOMAIN
|
|
precond = append(precond,
|
|
&v1.Precondition{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
return precond, nil
|
|
}
|
|
|
|
func channelThingPreCondition(pr auth.PolicyReq) ([]*v1.Precondition, error) {
|
|
if pr.SubjectKind != auth.ChannelsKind {
|
|
return nil, errInvalidSubject
|
|
}
|
|
precond := []*v1.Precondition{
|
|
{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalResourceId: pr.Subject,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.GroupType,
|
|
OptionalRelation: auth.ParentGroupRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.GroupType,
|
|
OptionalSubjectId: pr.Subject,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Operation: v1.Precondition_OPERATION_MUST_MATCH,
|
|
Filter: &v1.RelationshipFilter{
|
|
ResourceType: auth.ThingType,
|
|
OptionalResourceId: pr.Object,
|
|
OptionalRelation: auth.DomainRelation,
|
|
OptionalSubjectFilter: &v1.SubjectFilter{
|
|
SubjectType: auth.DomainType,
|
|
OptionalSubjectId: pr.Domain,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
return precond, nil
|
|
}
|