func revokeControllerAccess(accessor *state.State, targetUserTag, apiUser names.UserTag, access permission.Access) error { controllerTag := accessor.ControllerTag() switch access { case permission.LoginAccess: // Revoking login access removes all access. err := accessor.RemoveUserAccess(targetUserTag, controllerTag) return errors.Annotate(err, "could not revoke controller access") case permission.AddModelAccess: // Revoking add-model access sets login. controllerUser, err := accessor.UserAccess(targetUserTag, controllerTag) if err != nil { return errors.Annotate(err, "could not look up controller access for user") } _, err = accessor.SetUserAccess(controllerUser.UserTag, controllerUser.Object, permission.LoginAccess) return errors.Annotate(err, "could not set controller access to read-only") case permission.SuperuserAccess: // Revoking superuser sets add-model. controllerUser, err := accessor.UserAccess(targetUserTag, controllerTag) if err != nil { return errors.Annotate(err, "could not look up controller access for user") } _, err = accessor.SetUserAccess(controllerUser.UserTag, controllerUser.Object, permission.AddModelAccess) return errors.Annotate(err, "could not set controller access to add-model") default: return errors.Errorf("don't know how to revoke %q access", access) } }
func grantControllerAccess(accessor *state.State, targetUserTag, apiUser names.UserTag, access permission.Access) error { _, err := accessor.AddControllerUser(state.UserAccessSpec{User: targetUserTag, CreatedBy: apiUser, Access: access}) if errors.IsAlreadyExists(err) { controllerTag := accessor.ControllerTag() controllerUser, err := accessor.UserAccess(targetUserTag, controllerTag) if errors.IsNotFound(err) { // Conflicts with prior check, must be inconsistent state. err = txn.ErrExcessiveContention } if err != nil { return errors.Annotate(err, "could not look up controller access for user") } // Only set access if greater access is being granted. if controllerUser.Access.EqualOrGreaterControllerAccessThan(access) { return errors.Errorf("user already has %q access or greater", access) } if _, err = accessor.SetUserAccess(controllerUser.UserTag, controllerUser.Object, access); err != nil { return errors.Annotate(err, "could not set controller access for user") } return nil } if err != nil { return errors.Trace(err) } return nil }
func NewUserManagerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*UserManagerAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } // Since we know this is a user tag (because AuthClient is true), // we just do the type assertion to the UserTag. apiUser, _ := authorizer.GetAuthTag().(names.UserTag) // Pretty much all of the user manager methods have special casing for admin // users, so look once when we start and remember if the user is an admin. isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag()) if err != nil { return nil, errors.Trace(err) } return &UserManagerAPI{ state: st, authorizer: authorizer, check: common.NewBlockChecker(st), apiUser: apiUser, isAdmin: isAdmin, }, nil }
// UserAccess returns the access the user has on the model state // and the host controller. func UserAccess(st *state.State, utag names.UserTag) (modelUser, controllerUser permission.UserAccess, err error) { var none permission.UserAccess modelUser, err = st.UserAccess(utag, st.ModelTag()) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } controllerUser, err = state.ControllerAccess(st, utag) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } // TODO(perrito666) remove the following section about everyone group // when groups are implemented, this accounts only for the lack of a local // ControllerUser when logging in from an external user that has not been granted // permissions on the controller but there are permissions for the special // everyone group. if !utag.IsLocal() { controllerUser, err = maybeUseGroupPermission(st.UserAccess, controllerUser, st.ControllerTag(), utag) if err != nil { return none, none, errors.Annotatef(err, "obtaining ControllerUser for everyone group") } } if permission.IsEmptyUserAccess(modelUser) && permission.IsEmptyUserAccess(controllerUser) { return none, none, errors.NotFoundf("model or controller user") } return modelUser, controllerUser, nil }
func checkAuth(authorizer facade.Authorizer, st *state.State) error { if !authorizer.AuthClient() { return errors.Trace(common.ErrPerm) } if isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag()); err != nil { return errors.Trace(err) } else if !isAdmin { // The entire facade is only accessible to controller administrators. return errors.Trace(common.ErrPerm) } return nil }
// InstanceConfig returns information from the environment config that // is needed for machine cloud-init (for non-controllers only). It // is exposed for testing purposes. // TODO(rog) fix environs/manual tests so they do not need to call this, or move this elsewhere. func InstanceConfig(st *state.State, machineId, nonce, dataDir string) (*instancecfg.InstanceConfig, error) { modelConfig, err := st.ModelConfig() if err != nil { return nil, errors.Annotate(err, "getting model config") } // Get the machine so we can get its series and arch. // If the Arch is not set in hardware-characteristics, // an error is returned. machine, err := st.Machine(machineId) if err != nil { return nil, errors.Annotate(err, "getting machine") } hc, err := machine.HardwareCharacteristics() if err != nil { return nil, errors.Annotate(err, "getting machine hardware characteristics") } if hc.Arch == nil { return nil, fmt.Errorf("arch is not set for %q", machine.Tag()) } // Find the appropriate tools information. agentVersion, ok := modelConfig.AgentVersion() if !ok { return nil, errors.New("no agent version set in model configuration") } environment, err := st.Model() if err != nil { return nil, errors.Annotate(err, "getting state model") } urlGetter := common.NewToolsURLGetter(environment.UUID(), st) configGetter := stateenvirons.EnvironConfigGetter{st} toolsFinder := common.NewToolsFinder(configGetter, st, urlGetter) findToolsResult, err := toolsFinder.FindTools(params.FindToolsParams{ Number: agentVersion, MajorVersion: -1, MinorVersion: -1, Series: machine.Series(), Arch: *hc.Arch, }) if err != nil { return nil, errors.Annotate(err, "finding tools") } if findToolsResult.Error != nil { return nil, errors.Annotate(findToolsResult.Error, "finding tools") } toolsList := findToolsResult.List // Get the API connection info; attempt all API addresses. apiHostPorts, err := st.APIHostPorts() if err != nil { return nil, errors.Annotate(err, "getting API addresses") } apiAddrs := make(set.Strings) for _, hostPorts := range apiHostPorts { for _, hp := range hostPorts { apiAddrs.Add(hp.NetAddr()) } } apiInfo := &api.Info{ Addrs: apiAddrs.SortedValues(), CACert: st.CACert(), ModelTag: st.ModelTag(), } auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo) _, apiInfo, err = auth.SetupAuthentication(machine) if err != nil { return nil, errors.Annotate(err, "setting up machine authentication") } icfg, err := instancecfg.NewInstanceConfig(st.ControllerTag(), machineId, nonce, modelConfig.ImageStream(), machine.Series(), apiInfo, ) if err != nil { return nil, errors.Annotate(err, "initializing instance config") } if dataDir != "" { icfg.DataDir = dataDir } if err := icfg.SetTools(toolsList); err != nil { return nil, errors.Trace(err) } err = instancecfg.FinishInstanceConfig(icfg, modelConfig) if err != nil { return nil, errors.Annotate(err, "finishing instance config") } return icfg, nil }