github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/useraccess.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 "strings" 9 "time" 10 11 "github.com/juju/errors" 12 "gopkg.in/juju/names.v2" 13 "gopkg.in/mgo.v2/txn" 14 15 "github.com/juju/juju/permission" 16 ) 17 18 type userAccessDoc struct { 19 ID string `bson:"_id"` 20 ObjectUUID string `bson:"object-uuid"` 21 UserName string `bson:"user"` 22 DisplayName string `bson:"displayname"` 23 CreatedBy string `bson:"createdby"` 24 DateCreated time.Time `bson:"datecreated"` 25 } 26 27 // UserAccessSpec defines the attributes that can be set when adding a new 28 // user access. 29 type UserAccessSpec struct { 30 User names.UserTag 31 CreatedBy names.UserTag 32 DisplayName string 33 Access permission.Access 34 } 35 36 // userAccessTarget defines the target of a user access granting. 37 type userAccessTarget struct { 38 uuid string 39 globalKey string 40 } 41 42 // AddModelUser adds a new user for the model identified by modelUUID to the database. 43 func (st *State) AddModelUser(modelUUID string, spec UserAccessSpec) (permission.UserAccess, error) { 44 if err := permission.ValidateModelAccess(spec.Access); err != nil { 45 return permission.UserAccess{}, errors.Annotate(err, "adding model user") 46 } 47 target := userAccessTarget{ 48 uuid: modelUUID, 49 globalKey: modelGlobalKey, 50 } 51 return st.addUserAccess(spec, target) 52 } 53 54 // AddControllerUser adds a new user for the curent controller to the database. 55 func (st *State) AddControllerUser(spec UserAccessSpec) (permission.UserAccess, error) { 56 if err := permission.ValidateControllerAccess(spec.Access); err != nil { 57 return permission.UserAccess{}, errors.Annotate(err, "adding controller user") 58 } 59 return st.addUserAccess(spec, userAccessTarget{globalKey: controllerGlobalKey}) 60 } 61 62 func (st *State) addUserAccess(spec UserAccessSpec, target userAccessTarget) (permission.UserAccess, error) { 63 // Ensure local user exists in state before adding them as an model user. 64 if spec.User.IsLocal() { 65 localUser, err := st.User(spec.User) 66 if err != nil { 67 return permission.UserAccess{}, errors.Annotate(err, fmt.Sprintf("user %q does not exist locally", spec.User.Name())) 68 } 69 if spec.DisplayName == "" { 70 spec.DisplayName = localUser.DisplayName() 71 } 72 } 73 74 // Ensure local createdBy user exists. 75 if spec.CreatedBy.IsLocal() { 76 if _, err := st.User(spec.CreatedBy); err != nil { 77 return permission.UserAccess{}, errors.Annotatef(err, "createdBy user %q does not exist locally", spec.CreatedBy.Name()) 78 } 79 } 80 var ( 81 ops []txn.Op 82 err error 83 targetTag names.Tag 84 ) 85 switch target.globalKey { 86 case modelGlobalKey: 87 ops = createModelUserOps( 88 target.uuid, 89 spec.User, 90 spec.CreatedBy, 91 spec.DisplayName, 92 st.NowToTheSecond(), 93 spec.Access) 94 targetTag = names.NewModelTag(target.uuid) 95 case controllerGlobalKey: 96 ops = createControllerUserOps( 97 st.ControllerUUID(), 98 spec.User, 99 spec.CreatedBy, 100 spec.DisplayName, 101 st.NowToTheSecond(), 102 spec.Access) 103 targetTag = st.controllerTag 104 default: 105 return permission.UserAccess{}, errors.NotSupportedf("user access global key %q", target.globalKey) 106 } 107 err = st.runTransactionFor(target.uuid, ops) 108 if err == txn.ErrAborted { 109 err = errors.AlreadyExistsf("user access %q", spec.User.Canonical()) 110 } 111 if err != nil { 112 return permission.UserAccess{}, errors.Trace(err) 113 } 114 return st.UserAccess(spec.User, targetTag) 115 } 116 117 // userAccessID returns the document id of the user access. 118 func userAccessID(user names.UserTag) string { 119 username := user.Canonical() 120 return strings.ToLower(username) 121 } 122 123 // NewModelUserAccess returns a new permission.UserAccess for the given userDoc and 124 // current Model. 125 func NewModelUserAccess(st *State, userDoc userAccessDoc) (permission.UserAccess, error) { 126 perm, err := st.userPermission(modelKey(userDoc.ObjectUUID), userGlobalKey(strings.ToLower(userDoc.UserName))) 127 if err != nil { 128 return permission.UserAccess{}, errors.Annotate(err, "obtaining model permission") 129 } 130 return newUserAccess(perm, userDoc, names.NewModelTag(userDoc.ObjectUUID)), nil 131 } 132 133 // NewControllerUserAccess returns a new permission.UserAccess for the given userDoc and 134 // current Controller. 135 func NewControllerUserAccess(st *State, userDoc userAccessDoc) (permission.UserAccess, error) { 136 perm, err := st.controllerUserPermission(controllerKey(st.ControllerUUID()), userGlobalKey(strings.ToLower(userDoc.UserName))) 137 if err != nil { 138 return permission.UserAccess{}, errors.Annotate(err, "obtaining controller permission") 139 } 140 return newUserAccess(perm, userDoc, names.NewControllerTag(userDoc.ObjectUUID)), nil 141 } 142 143 func newUserAccess(perm *userPermission, userDoc userAccessDoc, object names.Tag) permission.UserAccess { 144 return permission.UserAccess{ 145 UserID: userDoc.ID, 146 UserTag: names.NewUserTag(userDoc.UserName), 147 Object: object, 148 Access: perm.access(), 149 CreatedBy: names.NewUserTag(userDoc.CreatedBy), 150 DateCreated: userDoc.DateCreated.UTC(), 151 DisplayName: userDoc.DisplayName, 152 UserName: userDoc.UserName, 153 } 154 } 155 156 // UserAccess returns a new permission.UserAccess for the passed subject and target. 157 func (st *State) UserAccess(subject names.UserTag, target names.Tag) (permission.UserAccess, error) { 158 if subject.IsLocal() { 159 _, err := st.User(subject) 160 if err != nil { 161 return permission.UserAccess{}, errors.Trace(err) 162 } 163 } 164 165 var ( 166 userDoc userAccessDoc 167 err error 168 ) 169 switch target.Kind() { 170 case names.ModelTagKind: 171 userDoc, err = st.modelUser(target.Id(), subject) 172 if err == nil { 173 return NewModelUserAccess(st, userDoc) 174 } 175 case names.ControllerTagKind: 176 userDoc, err = st.controllerUser(subject) 177 if err == nil { 178 return NewControllerUserAccess(st, userDoc) 179 } 180 default: 181 return permission.UserAccess{}, errors.NotValidf("%q as a target", target.Kind()) 182 } 183 return permission.UserAccess{}, errors.Trace(err) 184 } 185 186 // SetUserAccess sets <access> level on <target> to <subject>. 187 func (st *State) SetUserAccess(subject names.UserTag, target names.Tag, access permission.Access) (permission.UserAccess, error) { 188 err := access.Validate() 189 if err != nil { 190 return permission.UserAccess{}, errors.Trace(err) 191 } 192 switch target.Kind() { 193 case names.ModelTagKind: 194 err = st.setModelAccess(access, userGlobalKey(userAccessID(subject)), target.Id()) 195 case names.ControllerTagKind: 196 err = st.setControllerAccess(access, userGlobalKey(userAccessID(subject))) 197 default: 198 return permission.UserAccess{}, errors.NotValidf("%q as a target", target.Kind()) 199 } 200 if err != nil { 201 return permission.UserAccess{}, errors.Trace(err) 202 } 203 return st.UserAccess(subject, target) 204 } 205 206 // RemoveUserAccess removes access for subject to the passed tag. 207 func (st *State) RemoveUserAccess(subject names.UserTag, target names.Tag) error { 208 switch target.Kind() { 209 case names.ModelTagKind: 210 return errors.Trace(st.removeModelUser(subject)) 211 case names.ControllerTagKind: 212 return errors.Trace(st.removeControllerUser(subject)) 213 } 214 return errors.NotValidf("%q as a target", target.Kind()) 215 }