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 }