github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "gopkg.in/mgo.v2" 11 "gopkg.in/mgo.v2/bson" 12 "gopkg.in/mgo.v2/txn" 13 14 "github.com/juju/juju/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.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 permissions for user %q", id) 52 } 53 return result, nil 54 } 55 56 // controllerUserPermission returns a Permission for the given Subject and User. 57 func (st *State) controllerUserPermission(objectGlobalKey, subjectGlobalKey string) (*userPermission, error) { 58 result := &userPermission{} 59 60 permissions, closer := st.getCollection(permissionsC) 61 defer closer() 62 63 id := permissionID(objectGlobalKey, subjectGlobalKey) 64 err := permissions.FindId(id).One(&result.doc) 65 if err == mgo.ErrNotFound { 66 return nil, errors.NotFoundf("user permissions for user %q", id) 67 } 68 return result, nil 69 } 70 71 // isReadOnly returns whether or not the user has write access or only 72 // read access to the model. 73 func (p *userPermission) isReadOnly() bool { 74 return stringToAccess(p.doc.Access) == permission.UndefinedAccess || stringToAccess(p.doc.Access) == permission.ReadAccess 75 } 76 77 // isAdmin is a convenience method that 78 // returns whether or not the user has permission.AdminAccess. 79 func (p *userPermission) isAdmin() bool { 80 return stringToAccess(p.doc.Access) == permission.AdminAccess 81 } 82 83 // isReadWrite is a convenience method that 84 // returns whether or not the user has permission.WriteAccess. 85 func (p *userPermission) isReadWrite() bool { 86 return stringToAccess(p.doc.Access) == permission.WriteAccess 87 } 88 89 func (p *userPermission) access() permission.Access { 90 return stringToAccess(p.doc.Access) 91 } 92 93 func permissionID(objectGlobalKey, subjectGlobalKey string) string { 94 // example: e#:deadbeef#us#jim 95 // e: object global key 96 // deadbeef: object uuid 97 // us#jim: subject global key 98 // the first element (e in this example) is the global key for the object 99 // (model in this example) 100 // the second, is the : prefixed model uuid 101 // the third, in this example is a user with name jim, hence the globalKey 102 // ( a user global key) being us#jim. 103 // another example, now with controller and user maria: 104 // c#:deadbeef#us#maria 105 // c: object global key, in this case controller. 106 // :deadbeef controller uuid 107 // us#maria: its the user global key for maria. 108 // if this where for model, it would be e#us#maria 109 return fmt.Sprintf("%s#%s", objectGlobalKey, subjectGlobalKey) 110 } 111 112 func updatePermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op { 113 return txn.Op{ 114 C: permissionsC, 115 Id: permissionID(objectGlobalKey, subjectGlobalKey), 116 Assert: txn.DocExists, 117 Update: bson.D{{"$set", bson.D{{"access", accessToString(access)}}}}, 118 } 119 } 120 121 func removePermissionOp(objectGlobalKey, subjectGlobalKey string) txn.Op { 122 return txn.Op{ 123 C: permissionsC, 124 Id: permissionID(objectGlobalKey, subjectGlobalKey), 125 Assert: txn.DocExists, 126 Remove: true, 127 } 128 129 } 130 func createPermissionOp(objectGlobalKey, subjectGlobalKey string, access permission.Access) txn.Op { 131 doc := &permissionDoc{ 132 ID: permissionID(objectGlobalKey, subjectGlobalKey), 133 SubjectGlobalKey: subjectGlobalKey, 134 ObjectGlobalKey: objectGlobalKey, 135 Access: accessToString(access), 136 } 137 return txn.Op{ 138 C: permissionsC, 139 Id: permissionID(objectGlobalKey, subjectGlobalKey), 140 Assert: txn.DocMissing, 141 Insert: doc, 142 } 143 }