github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/permissions.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "strings" 8 9 "github.com/juju/errors" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/permission" 13 "github.com/juju/juju/state" 14 ) 15 16 // EveryoneTagName represents a special group that encompasses 17 // all external users. 18 const EveryoneTagName = "everyone@external" 19 20 // UserAccess returns the access the user has on the model state 21 // and the host controller. 22 func UserAccess(st *state.State, utag names.UserTag) (modelUser, controllerUser permission.UserAccess, err error) { 23 var none permission.UserAccess 24 modelUser, err = st.UserAccess(utag, st.ModelTag()) 25 if err != nil && !errors.IsNotFound(err) { 26 return none, none, errors.Trace(err) 27 } 28 29 controllerUser, err = state.ControllerAccess(st, utag) 30 if err != nil && !errors.IsNotFound(err) { 31 return none, none, errors.Trace(err) 32 } 33 34 // TODO(perrito666) remove the following section about everyone group 35 // when groups are implemented, this accounts only for the lack of a local 36 // ControllerUser when logging in from an external user that has not been granted 37 // permissions on the controller but there are permissions for the special 38 // everyone group. 39 if !utag.IsLocal() { 40 controllerUser, err = maybeUseGroupPermission(st.UserAccess, controllerUser, st.ControllerTag(), utag) 41 if err != nil { 42 return none, none, errors.Annotatef(err, "obtaining ControllerUser for everyone group") 43 } 44 } 45 46 if permission.IsEmptyUserAccess(modelUser) && 47 permission.IsEmptyUserAccess(controllerUser) { 48 return none, none, errors.NotFoundf("model or controller user") 49 } 50 return modelUser, controllerUser, nil 51 } 52 53 // HasPermission returns true if the specified user has the specified 54 // permission on target. 55 func HasPermission(userGetter userAccessFunc, utag names.Tag, 56 requestedPermission permission.Access, target names.Tag) (bool, error) { 57 58 validForKind := false 59 switch requestedPermission { 60 case permission.LoginAccess, permission.AddModelAccess, permission.SuperuserAccess: 61 validForKind = target.Kind() == names.ControllerTagKind 62 case permission.ReadAccess, permission.WriteAccess, permission.AdminAccess: 63 validForKind = target.Kind() == names.ModelTagKind 64 } 65 66 if !validForKind { 67 return false, nil 68 } 69 70 userTag, ok := utag.(names.UserTag) 71 if !ok { 72 // lets not reveal more than is strictly necessary 73 return false, nil 74 } 75 76 user, err := userGetter(userTag, target) 77 if err != nil && !errors.IsNotFound(err) { 78 return false, errors.Annotatef(err, "while obtaining %s user", target.Kind()) 79 } 80 // there is a special case for external users, a group called everyone@external 81 if target.Kind() == names.ControllerTagKind && !userTag.IsLocal() { 82 controllerTag, ok := target.(names.ControllerTag) 83 if !ok { 84 return false, errors.NotValidf("controller tag") 85 } 86 87 // TODO(perrito666) remove the following section about everyone group 88 // when groups are implemented, this accounts only for the lack of a local 89 // ControllerUser when logging in from an external user that has not been granted 90 // permissions on the controller but there are permissions for the special 91 // everyone group. 92 user, err = maybeUseGroupPermission(userGetter, user, controllerTag, userTag) 93 if err != nil { 94 return false, errors.Trace(err) 95 } 96 if permission.IsEmptyUserAccess(user) { 97 return false, nil 98 } 99 } 100 // returning this kind of information would be too much information to reveal too. 101 if errors.IsNotFound(err) { 102 return false, nil 103 } 104 modelPermission := user.Access.EqualOrGreaterModelAccessThan(requestedPermission) && target.Kind() == names.ModelTagKind 105 controllerPermission := user.Access.EqualOrGreaterControllerAccessThan(requestedPermission) && target.Kind() == names.ControllerTagKind 106 if !controllerPermission && !modelPermission { 107 return false, nil 108 } 109 return true, nil 110 } 111 112 // maybeUseGroupPermission returns a permission.UserAccess updated 113 // with the group permissions that apply to it if higher than 114 // current. 115 // If the passed UserAccess is empty (controller user lacks permissions) 116 // but the group is not, a stand-in will be created to hold the group 117 // permissions. 118 func maybeUseGroupPermission( 119 userGetter userAccessFunc, 120 externalUser permission.UserAccess, 121 controllerTag names.ControllerTag, 122 userTag names.UserTag, 123 ) (permission.UserAccess, error) { 124 125 everyoneTag := names.NewUserTag(EveryoneTagName) 126 everyone, err := userGetter(everyoneTag, controllerTag) 127 if errors.IsNotFound(err) { 128 return externalUser, nil 129 } 130 if err != nil { 131 return permission.UserAccess{}, errors.Trace(err) 132 } 133 if permission.IsEmptyUserAccess(externalUser) && 134 !permission.IsEmptyUserAccess(everyone) { 135 externalUser = newControllerUserFromGroup(everyone, userTag) 136 } 137 138 if everyone.Access.EqualOrGreaterControllerAccessThan(externalUser.Access) { 139 externalUser.Access = everyone.Access 140 } 141 return externalUser, nil 142 } 143 144 type userAccessFunc func(names.UserTag, names.Tag) (permission.UserAccess, error) 145 146 // newControllerUserFromGroup returns a permission.UserAccess that serves 147 // as a stand-in for a user that has group access but no explicit user 148 // access. 149 func newControllerUserFromGroup(everyoneAccess permission.UserAccess, 150 userTag names.UserTag) permission.UserAccess { 151 everyoneAccess.UserTag = userTag 152 everyoneAccess.UserID = strings.ToLower(userTag.Canonical()) 153 everyoneAccess.UserName = userTag.Canonical() 154 return everyoneAccess 155 }