github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/testing/fakeauthorizer.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names/v5"
    11  
    12  	"github.com/juju/juju/apiserver/authentication"
    13  	apiservererrors "github.com/juju/juju/apiserver/errors"
    14  	"github.com/juju/juju/core/permission"
    15  )
    16  
    17  // FakeAuthorizer implements the facade.Authorizer interface.
    18  type FakeAuthorizer struct {
    19  	Tag           names.Tag
    20  	Controller    bool
    21  	ModelUUID     string
    22  	AdminTag      names.UserTag
    23  	HasConsumeTag names.UserTag
    24  	HasWriteTag   names.UserTag
    25  }
    26  
    27  func (fa FakeAuthorizer) AuthOwner(tag names.Tag) bool {
    28  	return fa.Tag == tag
    29  }
    30  
    31  func (fa FakeAuthorizer) AuthController() bool {
    32  	return fa.Controller
    33  }
    34  
    35  // AuthMachineAgent returns whether the current client is a machine agent.
    36  func (fa FakeAuthorizer) AuthMachineAgent() bool {
    37  	// TODO(controlleragent) - add AuthControllerAgent function
    38  	_, isMachine := fa.GetAuthTag().(names.MachineTag)
    39  	_, isController := fa.GetAuthTag().(names.ControllerAgentTag)
    40  	return isMachine || isController
    41  }
    42  
    43  // AuthApplicationAgent returns whether the current client is an application operator.
    44  func (fa FakeAuthorizer) AuthApplicationAgent() bool {
    45  	_, isApp := fa.GetAuthTag().(names.ApplicationTag)
    46  	return isApp
    47  }
    48  
    49  // AuthModelAgent returns true if the authenticated entity is a model agent
    50  func (fa FakeAuthorizer) AuthModelAgent() bool {
    51  	_, isModel := fa.GetAuthTag().(names.ModelTag)
    52  	return isModel
    53  }
    54  
    55  // AuthUnitAgent returns whether the current client is a unit agent.
    56  func (fa FakeAuthorizer) AuthUnitAgent() bool {
    57  	_, isUnit := fa.GetAuthTag().(names.UnitTag)
    58  	return isUnit
    59  }
    60  
    61  // AuthClient returns whether the authenticated entity is a client
    62  // user.
    63  func (fa FakeAuthorizer) AuthClient() bool {
    64  	_, isUser := fa.GetAuthTag().(names.UserTag)
    65  	return isUser
    66  }
    67  
    68  func (fa FakeAuthorizer) GetAuthTag() names.Tag {
    69  	return fa.Tag
    70  }
    71  
    72  // HasPermission returns true if the logged in user is admin or has a name equal to
    73  // the pre-set admin tag.
    74  func (fa FakeAuthorizer) HasPermission(operation permission.Access, target names.Tag) error {
    75  	if fa.Tag.Kind() == names.UserTagKind {
    76  		ut := fa.Tag.(names.UserTag)
    77  		emptyTag := names.UserTag{}
    78  		if fa.AdminTag != emptyTag && ut == fa.AdminTag {
    79  			return nil
    80  		}
    81  		if ut == fa.HasWriteTag && (operation == permission.WriteAccess || operation == permission.ReadAccess) {
    82  			return nil
    83  		}
    84  
    85  		uTag := fa.Tag.(names.UserTag)
    86  		var err error
    87  		res := nameBasedHasPermission(uTag.Name(), operation, target)
    88  		if !res {
    89  			err = errors.WithType(apiservererrors.ErrPerm, authentication.ErrorEntityMissingPermission)
    90  		}
    91  		return err
    92  	}
    93  	return errors.WithType(apiservererrors.ErrPerm, authentication.ErrorEntityMissingPermission)
    94  }
    95  
    96  // nameBasedHasPermission provides a way for tests to fake the expected outcomes of the
    97  // authentication.
    98  // setting permissionname as the name that user will always have the given permission.
    99  // setting permissionnamemodeltagstring as the name will make that user have the given
   100  // permission only in that model.
   101  func nameBasedHasPermission(name string, operation permission.Access, target names.Tag) bool {
   102  	var perm permission.Access
   103  	switch {
   104  	case strings.HasPrefix(name, string(permission.SuperuserAccess)):
   105  		return operation == permission.SuperuserAccess
   106  	case strings.HasPrefix(name, string(permission.AddModelAccess)):
   107  		return operation == permission.AddModelAccess
   108  	case strings.HasPrefix(name, string(permission.LoginAccess)):
   109  		return operation == permission.LoginAccess
   110  	case strings.HasPrefix(name, string(permission.AdminAccess)):
   111  		perm = permission.AdminAccess
   112  	case strings.HasPrefix(name, string(permission.WriteAccess)):
   113  		perm = permission.WriteAccess
   114  	case strings.HasPrefix(name, string(permission.ConsumeAccess)):
   115  		perm = permission.ConsumeAccess
   116  	case strings.HasPrefix(name, string(permission.ReadAccess)):
   117  		perm = permission.ReadAccess
   118  	default:
   119  		return false
   120  	}
   121  	name = name[len(perm):]
   122  	if len(name) == 0 && perm == permission.AdminAccess {
   123  		return true
   124  	}
   125  	if len(name) == 0 {
   126  		return operation == perm
   127  	}
   128  	if name[0] == '-' {
   129  		name = name[1:]
   130  	}
   131  	targetTag, err := names.ParseTag(name)
   132  	if err != nil {
   133  		return false
   134  	}
   135  	return operation == perm && targetTag.String() == target.String()
   136  }
   137  
   138  // ConnectedModel returns the UUID of the model the current client is
   139  // connected to.
   140  func (fa FakeAuthorizer) ConnectedModel() string {
   141  	return fa.ModelUUID
   142  }
   143  
   144  // EntityHasPermission returns true if the passed entity is admin or has a name equal to
   145  // the pre-set admin tag.
   146  func (fa FakeAuthorizer) EntityHasPermission(entity names.Tag, operation permission.Access, _ names.Tag) error {
   147  	if entity.Kind() == names.UserTagKind && entity.Id() == "admin" {
   148  		return nil
   149  	}
   150  	emptyTag := names.UserTag{}
   151  	if fa.AdminTag != emptyTag && entity == fa.AdminTag {
   152  		return nil
   153  	}
   154  	if operation == permission.ConsumeAccess && fa.HasConsumeTag != emptyTag && entity == fa.HasConsumeTag {
   155  		return nil
   156  	}
   157  	return errors.WithType(apiservererrors.ErrPerm, authentication.ErrorEntityMissingPermission)
   158  }