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  }