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

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/url"
    10  	"reflect"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/juju/clock"
    15  	"github.com/juju/errors"
    16  	"github.com/juju/names/v5"
    17  	"github.com/juju/rpcreflect"
    18  
    19  	"github.com/juju/juju/apiserver/authentication"
    20  	"github.com/juju/juju/apiserver/common"
    21  	"github.com/juju/juju/apiserver/facade"
    22  	"github.com/juju/juju/core/cache"
    23  	coredatabase "github.com/juju/juju/core/database"
    24  	"github.com/juju/juju/core/leadership"
    25  	"github.com/juju/juju/core/lease"
    26  	"github.com/juju/juju/core/multiwatcher"
    27  	"github.com/juju/juju/core/permission"
    28  	"github.com/juju/juju/rpc"
    29  	"github.com/juju/juju/rpc/params"
    30  	"github.com/juju/juju/state"
    31  )
    32  
    33  type objectKey struct {
    34  	name    string
    35  	version int
    36  	objId   string
    37  }
    38  
    39  // apiHandler represents a single client's connection to the state
    40  // after it has logged in. It contains an rpc.Root which it
    41  // uses to dispatch API calls appropriately.
    42  type apiHandler struct {
    43  	state     *state.State
    44  	model     *state.Model
    45  	rpcConn   *rpc.Conn
    46  	resources *common.Resources
    47  	shared    *sharedServerContext
    48  
    49  	// authInfo represents the authentication info established with this client
    50  	// connection.
    51  	authInfo authentication.AuthInfo
    52  
    53  	// An empty modelUUID means that the user has logged in through the
    54  	// root of the API server rather than the /model/:model-uuid/api
    55  	// path, logins processed with v2 or later will only offer the
    56  	// user manager and model manager api endpoints from here.
    57  	modelUUID string
    58  
    59  	// connectionID is shared between the API observer (including API
    60  	// requests and responses in the agent log) and the audit logger.
    61  	connectionID uint64
    62  
    63  	// serverHost is the host:port of the API server that the client
    64  	// connected to.
    65  	serverHost string
    66  }
    67  
    68  var _ = (*apiHandler)(nil)
    69  
    70  var (
    71  	// maxClientPingInterval defines the timeframe until the ping timeout
    72  	// closes the monitored connection. TODO(mue): Idea by Roger:
    73  	// Move to API (e.g. params) so that the pinging there may
    74  	// depend on the interval.
    75  	maxClientPingInterval = 3 * time.Minute
    76  )
    77  
    78  // newAPIHandler returns a new apiHandler.
    79  func newAPIHandler(srv *Server, st *state.State, rpcConn *rpc.Conn, modelUUID string, connectionID uint64, serverHost string) (*apiHandler, error) {
    80  	m, err := st.Model()
    81  	if err != nil {
    82  		if !errors.IsNotFound(err) {
    83  			return nil, errors.Trace(err)
    84  		}
    85  
    86  		// If this model used to be hosted on this controller but got
    87  		// migrated allow clients to connect and wait for a login
    88  		// request to decide whether the users should be redirected to
    89  		// the new controller for this model or not.
    90  		if _, migErr := st.CompletedMigration(); migErr != nil {
    91  			return nil, errors.Trace(err) // return original NotFound error
    92  		}
    93  	}
    94  
    95  	r := &apiHandler{
    96  		state:        st,
    97  		model:        m,
    98  		resources:    common.NewResources(),
    99  		shared:       srv.shared,
   100  		rpcConn:      rpcConn,
   101  		modelUUID:    modelUUID,
   102  		connectionID: connectionID,
   103  		serverHost:   serverHost,
   104  	}
   105  
   106  	if err := r.resources.RegisterNamed("machineID", common.StringResource(srv.tag.Id())); err != nil {
   107  		return nil, errors.Trace(err)
   108  	}
   109  	if err := r.resources.RegisterNamed("dataDir", common.StringResource(srv.dataDir)); err != nil {
   110  		return nil, errors.Trace(err)
   111  	}
   112  	if err := r.resources.RegisterNamed("logDir", common.StringResource(srv.logDir)); err != nil {
   113  		return nil, errors.Trace(err)
   114  	}
   115  
   116  	// Facades involved with managing application offers need the auth context
   117  	// to mint and validate macaroons.
   118  	offerAccessEndpoint := &url.URL{
   119  		Scheme: "https",
   120  		Host:   serverHost,
   121  		Path:   localOfferAccessLocationPath,
   122  	}
   123  
   124  	controllerConfig, err := st.ControllerConfig()
   125  	if err != nil {
   126  		return nil, errors.Annotate(err, "unable to get controller config")
   127  	}
   128  	loginTokenRefreshURL := controllerConfig.LoginTokenRefreshURL()
   129  	if loginTokenRefreshURL != "" {
   130  		offerAccessEndpoint, err = url.Parse(loginTokenRefreshURL)
   131  		if err != nil {
   132  			return nil, errors.Trace(err)
   133  		}
   134  	}
   135  	offerAuthCtxt, err := srv.offerAuthCtxt.WithDischargeURL(offerAccessEndpoint.String())
   136  	if err != nil {
   137  		return nil, errors.Trace(err)
   138  	}
   139  	if err := r.resources.RegisterNamed(
   140  		"offerAccessAuthContext", common.ValueResource{Value: offerAuthCtxt},
   141  	); err != nil {
   142  		return nil, errors.Trace(err)
   143  	}
   144  	return r, nil
   145  }
   146  
   147  // Resources returns the common resources.
   148  func (r *apiHandler) Resources() *common.Resources {
   149  	return r.resources
   150  }
   151  
   152  // State returns the underlying state.
   153  func (r *apiHandler) State() *state.State {
   154  	return r.state
   155  }
   156  
   157  // SharedContext returns the server shared context.
   158  func (r *apiHandler) SharedContext() *sharedServerContext {
   159  	return r.shared
   160  }
   161  
   162  // Authorizer returns the authorizer used for accessing API method calls.
   163  func (r *apiHandler) Authorizer() facade.Authorizer {
   164  	return r
   165  }
   166  
   167  func (r *apiHandler) getRpcConn() *rpc.Conn {
   168  	return r.rpcConn
   169  }
   170  
   171  // Kill implements rpc.Killer, cleaning up any resources that need
   172  // cleaning up to ensure that all outstanding requests return.
   173  func (r *apiHandler) Kill() {
   174  	r.resources.StopAll()
   175  }
   176  
   177  // srvCaller is our implementation of the rpcreflect.MethodCaller interface.
   178  // It lives just long enough to encapsulate the methods that should be
   179  // available for an RPC call and allow the RPC code to instantiate an object
   180  // and place a call on its method.
   181  type srvCaller struct {
   182  	objMethod rpcreflect.ObjMethod
   183  	creator   func(id string) (reflect.Value, error)
   184  }
   185  
   186  // ParamsType defines the parameters that should be supplied to this function.
   187  // See rpcreflect.MethodCaller for more detail.
   188  func (s *srvCaller) ParamsType() reflect.Type {
   189  	return s.objMethod.Params
   190  }
   191  
   192  // ResultType defines the object that is returned from the function.`
   193  // See rpcreflect.MethodCaller for more detail.
   194  func (s *srvCaller) ResultType() reflect.Type {
   195  	return s.objMethod.Result
   196  }
   197  
   198  // Call takes the object Id and an instance of ParamsType to create an object and place
   199  // a call on its method. It then returns an instance of ResultType.
   200  func (s *srvCaller) Call(ctx context.Context, objId string, arg reflect.Value) (reflect.Value, error) {
   201  	objVal, err := s.creator(objId)
   202  	if err != nil {
   203  		return reflect.Value{}, err
   204  	}
   205  	return s.objMethod.Call(ctx, objVal, arg)
   206  }
   207  
   208  // apiRoot implements basic method dispatching to the facade registry.
   209  type apiRoot struct {
   210  	clock           clock.Clock
   211  	state           *state.State
   212  	shared          *sharedServerContext
   213  	facades         *facade.Registry
   214  	resources       *common.Resources
   215  	authorizer      facade.Authorizer
   216  	objectMutex     sync.RWMutex
   217  	objectCache     map[objectKey]reflect.Value
   218  	requestRecorder facade.RequestRecorder
   219  }
   220  
   221  type apiRootHandler interface {
   222  	// State returns the underlying state.
   223  	State() *state.State
   224  	// SharedContext returns the server shared context.
   225  	SharedContext() *sharedServerContext
   226  	// Resources returns the common resources.
   227  	Resources() *common.Resources
   228  	// Authorizer returns the authorizer used for accessing API method calls.
   229  	Authorizer() facade.Authorizer
   230  }
   231  
   232  // newAPIRoot returns a new apiRoot.
   233  func newAPIRoot(clock clock.Clock,
   234  	facades *facade.Registry,
   235  	root apiRootHandler,
   236  	requestRecorder facade.RequestRecorder,
   237  ) (*apiRoot, error) {
   238  	st := root.State()
   239  	r := &apiRoot{
   240  		clock:           clock,
   241  		state:           st,
   242  		shared:          root.SharedContext(),
   243  		facades:         facades,
   244  		resources:       root.Resources(),
   245  		authorizer:      root.Authorizer(),
   246  		objectCache:     make(map[objectKey]reflect.Value),
   247  		requestRecorder: requestRecorder,
   248  	}
   249  	// Ensure that the model being requested is in our model cache.
   250  	// Client connections need it for status (or very soon will), and agents
   251  	// require it for model config and others.
   252  	// In all real cases we have a state object, but some test code avoids passing one
   253  	// in, in order to just probe endpoints.
   254  	if st != nil {
   255  		_, err := r.cachedModel(st.ModelUUID())
   256  		if err != nil {
   257  			return nil, errors.Annotate(err, "model cache")
   258  		}
   259  	}
   260  	return r, nil
   261  }
   262  
   263  // restrictAPIRoot calls restrictAPIRootDuringMaintenance, and
   264  // then restricts the result further to the controller or model
   265  // facades, depending on the type of login.
   266  func restrictAPIRoot(
   267  	srv *Server,
   268  	apiRoot rpc.Root,
   269  	model *state.Model,
   270  	auth authResult,
   271  ) (rpc.Root, error) {
   272  	if !auth.controllerMachineLogin {
   273  		// Controller agents are allowed to
   274  		// connect even during maintenance.
   275  		restrictedRoot, err := restrictAPIRootDuringMaintenance(
   276  			srv, apiRoot, model, auth.tag,
   277  		)
   278  		if err != nil {
   279  			return nil, errors.Trace(err)
   280  		}
   281  		apiRoot = restrictedRoot
   282  	}
   283  	if auth.controllerOnlyLogin {
   284  		apiRoot = restrictRoot(apiRoot, controllerFacadesOnly)
   285  	} else {
   286  		apiRoot = restrictRoot(apiRoot, modelFacadesOnly)
   287  		if model.Type() == state.ModelTypeCAAS {
   288  			apiRoot = restrictRoot(apiRoot, caasModelFacadesOnly)
   289  		}
   290  	}
   291  	return apiRoot, nil
   292  }
   293  
   294  // restrictAPIRootDuringMaintenance restricts the API root during
   295  // maintenance events (upgrade or migration), depending
   296  // on the authenticated client.
   297  func restrictAPIRootDuringMaintenance(
   298  	srv *Server,
   299  	apiRoot rpc.Root,
   300  	model *state.Model,
   301  	authTag names.Tag,
   302  ) (rpc.Root, error) {
   303  	describeLogin := func() string {
   304  		if authTag == nil {
   305  			return "anonymous login"
   306  		}
   307  		return fmt.Sprintf("login for %s", names.ReadableString(authTag))
   308  	}
   309  
   310  	if !srv.upgradeComplete() {
   311  		if _, ok := authTag.(names.UserTag); ok {
   312  			// Users get access to a limited set of functionality
   313  			// while an upgrade is in progress.
   314  			return restrictRoot(apiRoot, upgradeMethodsOnly), nil
   315  		}
   316  		// Agent and anonymous logins are blocked during upgrade.
   317  		return nil, errors.Errorf("%s blocked because upgrade is in progress", describeLogin())
   318  	}
   319  
   320  	// For user logins, we limit access during migrations.
   321  	if _, ok := authTag.(names.UserTag); ok {
   322  		switch model.MigrationMode() {
   323  		case state.MigrationModeImporting:
   324  			// The user is not able to access a model that is currently being
   325  			// imported until the model has been activated.
   326  			apiRoot = restrictAll(apiRoot, errors.New("migration in progress, model is importing"))
   327  		case state.MigrationModeExporting:
   328  			// The user is not allowed to change anything in a model that is
   329  			// currently being moved to another controller.
   330  			apiRoot = restrictRoot(apiRoot, migrationClientMethodsOnly)
   331  		}
   332  	}
   333  
   334  	return apiRoot, nil
   335  }
   336  
   337  // Kill implements rpc.Killer, stopping the root's resources.
   338  func (r *apiRoot) Kill() {
   339  	r.resources.StopAll()
   340  }
   341  
   342  // FindMethod looks up the given rootName and version in our facade registry
   343  // and returns a MethodCaller that will be used by the RPC code to place calls on
   344  // that facade.
   345  // FindMethod uses the global registry apiserver/common.Facades.
   346  // For more information about how FindMethod should work, see rpc/server.go and
   347  // rpc/rpcreflect/value.go
   348  func (r *apiRoot) FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error) {
   349  	goType, objMethod, err := r.lookupMethod(rootName, version, methodName)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	creator := func(id string) (reflect.Value, error) {
   355  		objKey := objectKey{name: rootName, version: version, objId: id}
   356  		r.objectMutex.RLock()
   357  		objValue, ok := r.objectCache[objKey]
   358  		r.objectMutex.RUnlock()
   359  		if ok {
   360  			return objValue, nil
   361  		}
   362  		r.objectMutex.Lock()
   363  		defer r.objectMutex.Unlock()
   364  		if objValue, ok := r.objectCache[objKey]; ok {
   365  			return objValue, nil
   366  		}
   367  		// Now that we have the write lock, check one more time in case
   368  		// someone got the write lock before us.
   369  		factory, err := r.facades.GetFactory(rootName, version)
   370  		if err != nil {
   371  			// We don't check for IsNotFound here, because it
   372  			// should have already been handled in the GetType
   373  			// check.
   374  			return reflect.Value{}, err
   375  		}
   376  		obj, err := factory(r.facadeContext(objKey))
   377  		if err != nil {
   378  			return reflect.Value{}, err
   379  		}
   380  		objValue = reflect.ValueOf(obj)
   381  		if !objValue.Type().AssignableTo(goType) {
   382  			return reflect.Value{}, errors.Errorf(
   383  				"internal error, %s(%d) claimed to return %s but returned %T",
   384  				rootName, version, goType, obj)
   385  		}
   386  		if goType.Kind() == reflect.Interface {
   387  			// If the original function wanted to return an
   388  			// interface type, the indirection in the factory via
   389  			// an interface{} strips the original interface
   390  			// information off. So here we have to create the
   391  			// interface again, and assign it.
   392  			asInterface := reflect.New(goType).Elem()
   393  			asInterface.Set(objValue)
   394  			objValue = asInterface
   395  		}
   396  		r.objectCache[objKey] = objValue
   397  		return objValue, nil
   398  	}
   399  	return &srvCaller{
   400  		creator:   creator,
   401  		objMethod: objMethod,
   402  	}, nil
   403  }
   404  
   405  func (r *apiRoot) lookupMethod(rootName string, version int, methodName string) (reflect.Type, rpcreflect.ObjMethod, error) {
   406  	goType, err := r.facades.GetType(rootName, version)
   407  	if err != nil {
   408  		if errors.IsNotFound(err) {
   409  			return nil, rpcreflect.ObjMethod{}, &rpcreflect.CallNotImplementedError{
   410  				RootMethod: rootName,
   411  				Version:    version,
   412  			}
   413  		}
   414  		return nil, rpcreflect.ObjMethod{}, err
   415  	}
   416  	rpcType := rpcreflect.ObjTypeOf(goType)
   417  	objMethod, err := rpcType.Method(methodName)
   418  	if err != nil {
   419  		if err == rpcreflect.ErrMethodNotFound {
   420  			return nil, rpcreflect.ObjMethod{}, &rpcreflect.CallNotImplementedError{
   421  				RootMethod: rootName,
   422  				Version:    version,
   423  				Method:     methodName,
   424  			}
   425  		}
   426  		return nil, rpcreflect.ObjMethod{}, err
   427  	}
   428  	return goType, objMethod, nil
   429  }
   430  
   431  func (r *apiRoot) dispose(key objectKey) {
   432  	r.objectMutex.Lock()
   433  	defer r.objectMutex.Unlock()
   434  	delete(r.objectCache, key)
   435  }
   436  
   437  func (r *apiRoot) cachedModel(uuid string) (*cache.Model, error) {
   438  	model, err := r.shared.controller.WaitForModel(uuid, r.clock)
   439  	if err != nil {
   440  		// Check the database...
   441  		exists, err2 := r.state.ModelExists(uuid)
   442  		if err2 != nil {
   443  			return nil, errors.Trace(err2)
   444  		}
   445  		if exists {
   446  			return nil, errors.Trace(err)
   447  		}
   448  		return nil, errors.NotFoundf("model %q", uuid)
   449  	}
   450  	return model, nil
   451  }
   452  
   453  func (r *apiRoot) facadeContext(key objectKey) *facadeContext {
   454  	return &facadeContext{
   455  		r:   r,
   456  		key: key,
   457  	}
   458  }
   459  
   460  // facadeContext implements facade.Context
   461  type facadeContext struct {
   462  	r   *apiRoot
   463  	key objectKey
   464  }
   465  
   466  // Cancel is part of the facade.Context interface.
   467  func (ctx *facadeContext) Cancel() <-chan struct{} {
   468  	return ctx.r.shared.cancel
   469  }
   470  
   471  // Auth is part of the facade.Context interface.
   472  func (ctx *facadeContext) Auth() facade.Authorizer {
   473  	return ctx.r.authorizer
   474  }
   475  
   476  // Dispose is part of the facade.Context interface.
   477  func (ctx *facadeContext) Dispose() {
   478  	ctx.r.dispose(ctx.key)
   479  }
   480  
   481  // Resources is part of the facade.Context interface.
   482  func (ctx *facadeContext) Resources() facade.Resources {
   483  	return ctx.r.resources
   484  }
   485  
   486  // Presence implements facade.Context.
   487  func (ctx *facadeContext) Presence() facade.Presence {
   488  	return ctx
   489  }
   490  
   491  // ModelPresence implements facade.ModelPresence.
   492  func (ctx *facadeContext) ModelPresence(modelUUID string) facade.ModelPresence {
   493  	return ctx.r.shared.presence.Connections().ForModel(modelUUID)
   494  }
   495  
   496  // Hub implements facade.Context.
   497  func (ctx *facadeContext) Hub() facade.Hub {
   498  	return ctx.r.shared.centralHub
   499  }
   500  
   501  // Controller implements facade.Context.
   502  func (ctx *facadeContext) Controller() *cache.Controller {
   503  	return ctx.r.shared.controller
   504  }
   505  
   506  // CachedModel implements facade.Context.
   507  func (ctx *facadeContext) CachedModel(uuid string) (*cache.Model, error) {
   508  	return ctx.r.cachedModel(uuid)
   509  }
   510  
   511  // State is part of the facade.Context interface.
   512  func (ctx *facadeContext) State() *state.State {
   513  	return ctx.r.state
   514  }
   515  
   516  // StatePool is part of the facade.Context interface.
   517  func (ctx *facadeContext) StatePool() *state.StatePool {
   518  	return ctx.r.shared.statePool
   519  }
   520  
   521  // MultiwatcherFactory is part of the facade.Context interface.
   522  func (ctx *facadeContext) MultiwatcherFactory() multiwatcher.Factory {
   523  	return ctx.r.shared.multiwatcherFactory
   524  }
   525  
   526  // ID is part of the facade.Context interface.
   527  func (ctx *facadeContext) ID() string {
   528  	return ctx.key.objId
   529  }
   530  
   531  // RequestRecorder defines a metrics collector for outbound requests.
   532  func (ctx *facadeContext) RequestRecorder() facade.RequestRecorder {
   533  	return ctx.r.requestRecorder
   534  }
   535  
   536  // LeadershipClaimer is part of the facade.Context interface.
   537  func (ctx *facadeContext) LeadershipClaimer(modelUUID string) (leadership.Claimer, error) {
   538  	claimer, err := ctx.r.shared.leaseManager.Claimer(
   539  		lease.ApplicationLeadershipNamespace,
   540  		modelUUID,
   541  	)
   542  	if err != nil {
   543  		return nil, errors.Trace(err)
   544  	}
   545  	return leadershipClaimer{claimer}, nil
   546  }
   547  
   548  // LeadershipRevoker is part of the facade.Context interface.
   549  func (ctx *facadeContext) LeadershipRevoker(modelUUID string) (leadership.Revoker, error) {
   550  	revoker, err := ctx.r.shared.leaseManager.Revoker(
   551  		lease.ApplicationLeadershipNamespace,
   552  		modelUUID,
   553  	)
   554  	if err != nil {
   555  		return nil, errors.Trace(err)
   556  	}
   557  	return leadershipRevoker{revoker}, nil
   558  }
   559  
   560  // LeadershipChecker is part of the facade.Context interface.
   561  func (ctx *facadeContext) LeadershipChecker() (leadership.Checker, error) {
   562  	checker, err := ctx.r.shared.leaseManager.Checker(
   563  		lease.ApplicationLeadershipNamespace,
   564  		ctx.State().ModelUUID(),
   565  	)
   566  	if err != nil {
   567  		return nil, errors.Trace(err)
   568  	}
   569  	return leadershipChecker{checker}, nil
   570  }
   571  
   572  // LeadershipPinner is part of the facade.Context interface.
   573  // Pinning functionality is only available with the Raft leases implementation.
   574  func (ctx *facadeContext) LeadershipPinner(modelUUID string) (leadership.Pinner, error) {
   575  	pinner, err := ctx.r.shared.leaseManager.Pinner(
   576  		lease.ApplicationLeadershipNamespace,
   577  		modelUUID,
   578  	)
   579  	if err != nil {
   580  		return nil, errors.Trace(err)
   581  	}
   582  	return leadershipPinner{pinner}, nil
   583  }
   584  
   585  // LeadershipReader is part of the facade.Context interface.
   586  // It returns a reader that can be used to return all application leaders
   587  // in the model.
   588  func (ctx *facadeContext) LeadershipReader(modelUUID string) (leadership.Reader, error) {
   589  	reader, err := ctx.r.shared.leaseManager.Reader(
   590  		lease.ApplicationLeadershipNamespace,
   591  		modelUUID,
   592  	)
   593  	if err != nil {
   594  		return nil, errors.Trace(err)
   595  	}
   596  	return leadershipReader{reader}, nil
   597  }
   598  
   599  // SingularClaimer is part of the facade.Context interface.
   600  func (ctx *facadeContext) SingularClaimer() (lease.Claimer, error) {
   601  	return ctx.r.shared.leaseManager.Claimer(
   602  		lease.SingularControllerNamespace,
   603  		ctx.State().ModelUUID(),
   604  	)
   605  }
   606  
   607  func (ctx *facadeContext) HTTPClient(purpose facade.HTTPClientPurpose) facade.HTTPClient {
   608  	switch purpose {
   609  	case facade.CharmhubHTTPClient:
   610  		return ctx.r.shared.charmhubHTTPClient
   611  	default:
   612  		return nil
   613  	}
   614  }
   615  
   616  // ControllerDB returns a TrackedDB reference for the controller database.
   617  func (ctx *facadeContext) ControllerDB() (coredatabase.TrackedDB, error) {
   618  	db, err := ctx.r.shared.dbGetter.GetDB(coredatabase.ControllerNS)
   619  	return db, errors.Trace(err)
   620  }
   621  
   622  // adminRoot dispatches API calls to those available to an anonymous connection
   623  // which has not logged in, which here is the admin facade.
   624  type adminRoot struct {
   625  	*apiHandler
   626  	adminAPIs map[int]interface{}
   627  }
   628  
   629  // newAdminRoot creates a new AnonRoot which dispatches to the given Admin API implementation.
   630  func newAdminRoot(h *apiHandler, adminAPIs map[int]interface{}) *adminRoot {
   631  	r := &adminRoot{
   632  		apiHandler: h,
   633  		adminAPIs:  adminAPIs,
   634  	}
   635  	return r
   636  }
   637  
   638  func (r *adminRoot) FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error) {
   639  	if rootName != "Admin" {
   640  		return nil, &rpcreflect.CallNotImplementedError{
   641  			RootMethod: rootName,
   642  			Version:    version,
   643  		}
   644  	}
   645  	if api, ok := r.adminAPIs[version]; ok {
   646  		return rpcreflect.ValueOf(reflect.ValueOf(api)).FindMethod(rootName, 0, methodName)
   647  	}
   648  	return nil, &rpc.RequestError{
   649  		Code:    params.CodeNotSupported,
   650  		Message: "this version of Juju does not support login from old clients",
   651  	}
   652  }
   653  
   654  // AuthMachineAgent returns whether the current client is a machine agent.
   655  // TODO(controlleragent) - add AuthControllerAgent function
   656  func (r *apiHandler) AuthMachineAgent() bool {
   657  	_, isMachine := r.GetAuthTag().(names.MachineTag)
   658  	_, isControllerAgent := r.GetAuthTag().(names.ControllerAgentTag)
   659  	return isMachine || isControllerAgent
   660  }
   661  
   662  // AuthModelAgent return whether the current client is a model agent
   663  func (r *apiHandler) AuthModelAgent() bool {
   664  	_, isModel := r.GetAuthTag().(names.ModelTag)
   665  	return isModel
   666  }
   667  
   668  // AuthApplicationAgent returns whether the current client is an application operator.
   669  func (r *apiHandler) AuthApplicationAgent() bool {
   670  	_, isApp := r.GetAuthTag().(names.ApplicationTag)
   671  	return isApp
   672  }
   673  
   674  // AuthUnitAgent returns whether the current client is a unit agent.
   675  func (r *apiHandler) AuthUnitAgent() bool {
   676  	_, isUnit := r.GetAuthTag().(names.UnitTag)
   677  	return isUnit
   678  }
   679  
   680  // AuthOwner returns whether the authenticated user's tag matches the
   681  // given entity tag.
   682  func (r *apiHandler) AuthOwner(tag names.Tag) bool {
   683  	return r.GetAuthTag() == tag
   684  }
   685  
   686  // AuthController returns whether the authenticated user is a
   687  // machine with running the ManageEnviron job.
   688  func (r *apiHandler) AuthController() bool {
   689  	type hasIsManager interface {
   690  		IsManager() bool
   691  	}
   692  	m, ok := r.authInfo.Entity.(hasIsManager)
   693  	return ok && m.IsManager()
   694  }
   695  
   696  // AuthClient returns whether the authenticated entity is a client
   697  // user.
   698  func (r *apiHandler) AuthClient() bool {
   699  	_, isUser := r.GetAuthTag().(names.UserTag)
   700  	return isUser
   701  }
   702  
   703  // GetAuthTag returns the tag of the authenticated entity, if any.
   704  func (r *apiHandler) GetAuthTag() names.Tag {
   705  	if r.authInfo.Entity == nil {
   706  		return nil
   707  	}
   708  	return r.authInfo.Entity.Tag()
   709  }
   710  
   711  // ConnectedModel returns the UUID of the model authenticated
   712  // against. It's possible for it to be empty if the login was made
   713  // directly to the root of the API instead of a model endpoint, but
   714  // that method is deprecated.
   715  func (r *apiHandler) ConnectedModel() string {
   716  	return r.modelUUID
   717  }
   718  
   719  // HasPermission is responsible for reporting if the logged in user is
   720  // able to perform operation x on target y. It uses the authentication mechanism
   721  // of the user to interrogate their permissions. If the entity does not have
   722  // permission to perform the operation then the authentication provider is asked
   723  // to provide a permission error. All permissions errors returned satisfy
   724  // errors.Is(err, ErrorEntityMissingPermission) to distinguish before errors and
   725  // no permissions errors. If error is nil then the user has permission.
   726  func (r *apiHandler) HasPermission(operation permission.Access, target names.Tag) error {
   727  	return r.EntityHasPermission(r.GetAuthTag(), operation, target)
   728  }
   729  
   730  // EntityHasPermission is responsible for reporting if the supplied entity is
   731  // able to perform operation x on target y. It uses the authentication mechanism
   732  // of the user to interrogate their permissions. If the entity does not have
   733  // permission to perform the operation then the authentication provider is asked
   734  // to provide a permission error. All permissions errors returned satisfy
   735  // errors.Is(err, ErrorEntityMissingPermission) to distinguish before errors and
   736  // no permissions errors. If error is nil then the user has permission.
   737  func (r *apiHandler) EntityHasPermission(entity names.Tag, operation permission.Access, target names.Tag) error {
   738  	var userAccessFunc common.UserAccessFunc = func(entity names.UserTag, subject names.Tag) (permission.Access, error) {
   739  		if r.authInfo.Delegator == nil {
   740  			return permission.NoAccess, fmt.Errorf("permissions %w for auth info", errors.NotImplemented)
   741  		}
   742  		return r.authInfo.Delegator.SubjectPermissions(authentication.TagToEntity(entity), subject)
   743  	}
   744  	has, err := common.HasPermission(userAccessFunc, entity, operation, target)
   745  	if err != nil && !errors.Is(err, errors.NotFound) {
   746  		return fmt.Errorf("checking entity %q has permission: %w", entity, err)
   747  	}
   748  	if !has && r.authInfo.Delegator != nil {
   749  		err = r.authInfo.Delegator.PermissionError(target, operation)
   750  	}
   751  	if !has {
   752  		return errors.WithType(err, authentication.ErrorEntityMissingPermission)
   753  	}
   754  
   755  	return nil
   756  }
   757  
   758  // DescribeFacades returns the list of available Facades and their Versions
   759  func DescribeFacades(registry *facade.Registry) []params.FacadeVersions {
   760  	facades := registry.List()
   761  	result := make([]params.FacadeVersions, len(facades))
   762  	for i, f := range facades {
   763  		result[i].Name = f.Name
   764  		result[i].Versions = f.Versions
   765  	}
   766  	return result
   767  }