github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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 "github.com/juju/errors" 8 "github.com/juju/names/v5" 9 10 "github.com/juju/juju/apiserver/authentication" 11 "github.com/juju/juju/apiserver/facade" 12 "github.com/juju/juju/core/permission" 13 ) 14 15 // EveryoneTagName represents a special group that encompasses 16 // all external users. 17 const EveryoneTagName = "everyone@external" 18 19 // UserAccessFunc represents a func that can answer the question about what 20 // level of access a user entity has for a given subject tag. 21 type UserAccessFunc func(names.UserTag, names.Tag) (permission.Access, error) 22 23 // HasPermission returns true if the specified user has the specified 24 // permission on target. 25 func HasPermission( 26 accessGetter UserAccessFunc, utag names.Tag, 27 requestedPermission permission.Access, target names.Tag, 28 ) (bool, error) { 29 var validate func(permission.Access) error 30 switch target.Kind() { 31 case names.ControllerTagKind: 32 validate = permission.ValidateControllerAccess 33 case names.ModelTagKind: 34 validate = permission.ValidateModelAccess 35 case names.ApplicationOfferTagKind: 36 validate = permission.ValidateOfferAccess 37 case names.CloudTagKind: 38 validate = permission.ValidateCloudAccess 39 default: 40 return false, nil 41 } 42 if err := validate(requestedPermission); err != nil { 43 return false, nil 44 } 45 46 userTag, ok := utag.(names.UserTag) 47 if !ok { 48 // lets not reveal more than is strictly necessary 49 return false, nil 50 } 51 52 userAccess, err := GetPermission(accessGetter, userTag, target) 53 if err != nil && !errors.IsNotFound(err) { 54 return false, errors.Annotatef(err, "while obtaining %s user", target.Kind()) 55 } 56 // returning this kind of information would be too much information to reveal too. 57 if errors.IsNotFound(err) || userAccess == permission.NoAccess { 58 return false, nil 59 } 60 61 modelPermission := userAccess.EqualOrGreaterModelAccessThan(requestedPermission) && target.Kind() == names.ModelTagKind 62 controllerPermission := userAccess.EqualOrGreaterControllerAccessThan(requestedPermission) && target.Kind() == names.ControllerTagKind 63 offerPermission := userAccess.EqualOrGreaterOfferAccessThan(requestedPermission) && target.Kind() == names.ApplicationOfferTagKind 64 cloudPermission := userAccess.EqualOrGreaterCloudAccessThan(requestedPermission) && target.Kind() == names.CloudTagKind 65 if !controllerPermission && !modelPermission && !offerPermission && !cloudPermission { 66 return false, nil 67 } 68 return true, nil 69 } 70 71 // GetPermission returns the permission a user has on the specified target. 72 func GetPermission(accessGetter UserAccessFunc, userTag names.UserTag, target names.Tag) (permission.Access, error) { 73 userAccess, err := accessGetter(userTag, target) 74 if err != nil && !errors.IsNotFound(err) { 75 return permission.NoAccess, errors.Annotatef(err, "while obtaining %s user", target.Kind()) 76 } 77 // there is a special case for external users, a group called everyone@external 78 if !userTag.IsLocal() { 79 // TODO(perrito666) remove the following section about everyone group 80 // when groups are implemented. 81 everyoneTag := names.NewUserTag(EveryoneTagName) 82 everyoneAccess, err := accessGetter(everyoneTag, target) 83 if err != nil && !errors.IsNotFound(err) { 84 return permission.NoAccess, errors.Trace(err) 85 } 86 if userAccess == permission.NoAccess && everyoneAccess != permission.NoAccess { 87 userAccess = everyoneAccess 88 } 89 if everyoneAccess.EqualOrGreaterControllerAccessThan(userAccess) { 90 userAccess = everyoneAccess 91 } 92 } 93 return userAccess, nil 94 } 95 96 // HasModelAdmin reports whether or not a user has admin access to the 97 // specified model. A user has model access if they are a controller 98 // superuser, or if they have been explicitly granted admin access to the 99 // model. 100 func HasModelAdmin( 101 authorizer facade.Authorizer, 102 controllerTag names.ControllerTag, 103 modelTag names.ModelTag, 104 ) (bool, error) { 105 // superusers have admin for all models. 106 err := authorizer.HasPermission(permission.SuperuserAccess, controllerTag) 107 if err != nil && !errors.Is(err, authentication.ErrorEntityMissingPermission) { 108 return false, err 109 } 110 111 if err == nil { 112 return true, nil 113 } 114 115 err = authorizer.HasPermission(permission.AdminAccess, modelTag) 116 if err != nil && !errors.Is(err, authentication.ErrorEntityMissingPermission) { 117 return false, err 118 } 119 return err == nil, nil 120 }