github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/userpermission.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/mgo/v3"
    11  	"github.com/juju/mgo/v3/bson"
    12  	"github.com/juju/mgo/v3/txn"
    13  
    14  	"github.com/juju/juju/core/permission"
    15  )
    16  
    17  // permission represents the permission a user has
    18  // on a given scope.
    19  type userPermission struct {
    20  	doc permissionDoc
    21  }
    22  
    23  type permissionDoc struct {
    24  	ID string `bson:"_id"`
    25  	// ObjectGlobalKey holds the id for the object of the permission.
    26  	// ie. a model globalKey or a controller globalKey.
    27  	ObjectGlobalKey string `bson:"object-global-key"`
    28  	// SubjectGlobalKey holds the id for the user/group that is given permission.
    29  	SubjectGlobalKey string `bson:"subject-global-key"`
    30  	// Access is the permission level.
    31  	Access string `bson:"access"`
    32  }
    33  
    34  func stringToAccess(a string) permission.Access {
    35  	return permission.Access(a)
    36  }
    37  
    38  func accessToString(a permission.Access) string {
    39  	return string(a)
    40  }
    41  
    42  // userPermission returns a Permission for the given Subject and User.
    43  func (st *State) userPermission(objectGlobalKey, subjectGlobalKey string) (*userPermission, error) {
    44  	result := &userPermission{}
    45  	permissions, closer := st.db().GetCollection(permissionsC)
    46  	defer closer()
    47  
    48  	id := permissionID(objectGlobalKey, subjectGlobalKey)
    49  	err := permissions.FindId(id).One(&result.doc)
    50  	if err == mgo.ErrNotFound {
    51  		return nil, errors.NotFoundf("user permission for %q on %q", subjectGlobalKey, objectGlobalKey)
    52  	}
    53  	return result, nil
    54  }
    55  
    56  // usersPermissions returns all permissions for a given object.
    57  func (st *State) usersPermissions(objectGlobalKey string) ([]*userPermission, error) {
    58  	permissions, closer := st.db().GetCollection(permissionsC)
    59  	defer closer()
    60  
    61  	var matchingPermissions []permissionDoc
    62  	findExpr := fmt.Sprintf("^%s#.*$", objectGlobalKey)
    63  	if err := permissions.Find(
    64  		bson.D{{"_id", bson.D{{"$regex", findExpr}}}},
    65  	).All(&matchingPermissions); err != nil {
    66  		return nil, err
    67  	}
    68  	var result []*userPermission
    69  	for _, pDoc := range matchingPermissions {
    70  		result = append(result, &userPermission{doc: pDoc})
    71  	}
    72  	return result, nil
    73  }
    74  
    75  func (p *userPermission) access() permission.Access {
    76  	return stringToAccess(p.doc.Access)
    77  }
    78  
    79  func permissionID(objectGlobalKey, subjectGlobalKey string) string {
    80  	// example: e#deadbeef#us#jim
    81  	// e: object global key
    82  	// deadbeef: object uuid
    83  	// us#jim: subject global key
    84  	// the first element (e in this example) is the global key for the object
    85  	// (model in this example)
    86  	// the second, is the : prefixed model uuid
    87  	// the third, in this example is a user with name jim, hence the globalKey
    88  	// ( a user global key) being us#jim.
    89  	// another example, now with controller and user maria:
    90  	// c#:deadbeef#us#maria
    91  	// c: object global key, in this case controller.
    92  	// :deadbeef controller uuid
    93  	// us#maria: its the user global key for maria.
    94  	// if this where for model, it would be e#us#maria
    95  	return fmt.Sprintf("%s#%s", objectGlobalKey, subjectGlobalKey)
    96  }
    97  
    98  func updatePermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op {
    99  	return txn.Op{
   100  		C:      permissionsC,
   101  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   102  		Assert: txn.DocExists,
   103  		Update: bson.D{{"$set", bson.D{{"access", accessToString(access)}}}},
   104  	}
   105  }
   106  
   107  func removePermissionOp(objectGlobalKey, subjectGlobalKey string) txn.Op {
   108  	return txn.Op{
   109  		C:      permissionsC,
   110  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   111  		Assert: txn.DocExists,
   112  		Remove: true,
   113  	}
   114  
   115  }
   116  func createPermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op {
   117  	doc := makePermissionDoc(objectGlobalKey, subjectGlobalKey, access)
   118  	return txn.Op{
   119  		C:      permissionsC,
   120  		Id:     permissionID(objectGlobalKey, subjectGlobalKey),
   121  		Assert: txn.DocMissing,
   122  		Insert: doc,
   123  	}
   124  }
   125  
   126  func makePermissionDoc(objectGlobalKey, subjectGlobalKey string, access permission.Access) *permissionDoc {
   127  	return &permissionDoc{
   128  		ID:               permissionID(objectGlobalKey, subjectGlobalKey),
   129  		SubjectGlobalKey: subjectGlobalKey,
   130  		ObjectGlobalKey:  objectGlobalKey,
   131  		Access:           accessToString(access),
   132  	}
   133  }