// CharmURL returns the charm URL for all given units or services. func (u *UniterAPIV3) CharmURL(args params.Entities) (params.StringBoolResults, error) { result := params.StringBoolResults{ Results: make([]params.StringBoolResult, len(args.Entities)), } accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) canAccess, err := accessUnitOrService() if err != nil { return params.StringBoolResults{}, err } for i, entity := range args.Entities { tag, err := names.ParseTag(entity.Tag) if err != nil { result.Results[i].Error = common.ServerError(common.ErrPerm) continue } err = common.ErrPerm if canAccess(tag) { var unitOrService state.Entity unitOrService, err = u.st.FindEntity(tag) if err == nil { charmURLer := unitOrService.(interface { CharmURL() (*charm.URL, bool) }) curl, ok := charmURLer.CharmURL() if curl != nil { result.Results[i].Result = curl.String() result.Results[i].Ok = ok } } } result.Results[i].Error = common.ServerError(err) } return result, nil }
// stateForRequestAuthenticatedAgent is like stateForRequestAuthenticated // except that it also verifies that the authenticated entity is an agent. func (ctxt *httpContext) stateForRequestAuthenticatedAgent(r *http.Request) (*state.State, state.Entity, error) { authFunc := common.AuthEither( common.AuthFuncForTagKind(names.MachineTagKind), common.AuthFuncForTagKind(names.UnitTagKind), ) st, entity, err := ctxt.stateForRequestAuthenticated(r) if err != nil { return nil, nil, errors.Trace(err) } if ok, err := checkPermissions(entity.Tag(), authFunc); !ok { return nil, nil, err } return st, entity, nil }
func (s *commonSuite) TestAuthEither(c *gc.C) { for i, test := range authEitherTests { c.Logf("test %d: %s", i, test.about) authEither := common.AuthEither(test.a, test.b) either, err := authEither() if test.err == "" { c.Assert(err, jc.ErrorIsNil) ok := either(test.tag) c.Assert(ok, gc.Equals, test.expect) } else { c.Assert(err, gc.ErrorMatches, test.err) c.Assert(either, gc.IsNil) } } }
// CharmModifiedVersion returns the most CharmModifiedVersion for all given // units or services. func (u *UniterAPIV3) CharmModifiedVersion(args params.Entities) (params.IntResults, error) { results := params.IntResults{ Results: make([]params.IntResult, len(args.Entities)), } accessUnitOrService := common.AuthEither(u.accessUnit, u.accessService) canAccess, err := accessUnitOrService() if err != nil { return results, err } for i, entity := range args.Entities { ver, err := u.charmModifiedVersion(entity.Tag, canAccess) if err != nil { results.Results[i].Error = common.ServerError(err) continue } results.Results[i].Result = ver } return results, nil }
// NewUniterAPI creates a new instance of the Uniter API. func NewUniterAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*UniterAPI, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } accessUnit := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } accessService := func() (common.AuthFunc, error) { switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: entity, err := st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } serviceName := entity.ServiceName() serviceTag := names.NewServiceTag(serviceName) return func(tag names.Tag) bool { return tag == serviceTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &UniterAPI{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), StatusSetter: common.NewStatusSetter(st, accessUnit), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, }, nil }
// NewUniterAPIV4 creates a new instance of the Uniter API, version 3. func NewUniterAPIV4(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*UniterAPIV3, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } var unit *state.Unit var err error switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: unit, err = st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } accessUnit := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } accessService := func() (common.AuthFunc, error) { switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: entity, err := st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } applicationName := entity.ApplicationName() applicationTag := names.NewApplicationTag(applicationName) return func(tag names.Tag) bool { return tag == applicationTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } accessMachine := func() (common.AuthFunc, error) { switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: entity, err := st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } machineId, err := entity.AssignedMachineId() if err != nil { return nil, errors.Trace(err) } machineTag := names.NewMachineTag(machineId) return func(tag names.Tag) bool { return tag == machineTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } storageAPI, err := newStorageAPI(getStorageState(st), resources, accessUnit) if err != nil { return nil, err } msAPI, err := meterstatus.NewMeterStatusAPI(st, resources, authorizer) if err != nil { return nil, errors.Annotate(err, "could not create meter status API handler") } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &UniterAPIV3{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), ModelWatcher: common.NewModelWatcher(st, resources, authorizer), RebootRequester: common.NewRebootRequester(st, accessMachine), LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), MeterStatus: msAPI, // TODO(fwereade): so *every* unit should be allowed to get/set its // own status *and* its service's? This is not a pleasing arrangement. StatusAPI: NewStatusAPI(st, accessUnitOrService), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, unit: unit, StorageAPI: *storageAPI, }, nil }
// NewFirewallerAPI creates a new server-side FirewallerAPI facade. func NewFirewallerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*FirewallerAPI, error) { if !authorizer.AuthModelManager() { // Firewaller must run as environment manager. return nil, common.ErrPerm } // Set up the various authorization checkers. accessEnviron := common.AuthFuncForTagKind(names.ModelTagKind) accessUnit := common.AuthFuncForTagKind(names.UnitTagKind) accessService := common.AuthFuncForTagKind(names.ApplicationTagKind) accessMachine := common.AuthFuncForTagKind(names.MachineTagKind) accessUnitOrService := common.AuthEither(accessUnit, accessService) accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine) // Life() is supported for units, services or machines. lifeGetter := common.NewLifeGetter( st, accessUnitServiceOrMachine, ) // ModelConfig() and WatchForModelConfigChanges() are allowed // with unrestriced access. modelWatcher := common.NewModelWatcher( st, resources, authorizer, ) // Watch() is supported for applications only. entityWatcher := common.NewAgentEntityWatcher( st, resources, accessService, ) // WatchUnits() is supported for machines. unitsWatcher := common.NewUnitsWatcher(st, resources, accessMachine, ) // WatchModelMachines() is allowed with unrestricted access. machinesWatcher := common.NewModelMachinesWatcher( st, resources, authorizer, ) // InstanceId() is supported for machines. instanceIdGetter := common.NewInstanceIdGetter( st, accessMachine, ) environConfigGetter := stateenvirons.EnvironConfigGetter{st} cloudSpecAPI := cloudspec.NewCloudSpec(environConfigGetter.CloudSpec, common.AuthFuncForTag(st.ModelTag())) return &FirewallerAPI{ LifeGetter: lifeGetter, ModelWatcher: modelWatcher, AgentEntityWatcher: entityWatcher, UnitsWatcher: unitsWatcher, ModelMachinesWatcher: machinesWatcher, InstanceIdGetter: instanceIdGetter, CloudSpecAPI: cloudSpecAPI, st: st, resources: resources, authorizer: authorizer, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, accessEnviron: accessEnviron, }, nil }
// newUniterBaseAPI creates a new instance of the uniter base API. func newUniterBaseAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*uniterBaseAPI, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } var unit *state.Unit var err error switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: unit, err = st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } accessUnit := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } accessService := func() (common.AuthFunc, error) { switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: entity, err := st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } serviceName := entity.ServiceName() serviceTag := names.NewServiceTag(serviceName) return func(tag names.Tag) bool { return tag == serviceTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } accessMachine := func() (common.AuthFunc, error) { machineId, err := unit.AssignedMachineId() if err != nil { return nil, errors.Trace(err) } machine, err := st.Machine(machineId) if err != nil { return nil, errors.Trace(err) } return func(tag names.Tag) bool { return tag == machine.Tag() }, nil } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &uniterBaseAPI{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), RebootRequester: common.NewRebootRequester(st, accessMachine), LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), // TODO(fwereade): so *every* unit should be allowed to get/set its // own status *and* its service's? This is not a pleasing arrangement. StatusAPI: NewStatusAPI(st, accessUnitOrService), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, unit: unit, }, nil }
// NewFirewallerAPI creates a new server-side FirewallerAPI facade. func NewFirewallerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*FirewallerAPI, error) { if !authorizer.AuthEnvironManager() { // Firewaller must run as environment manager. return nil, common.ErrPerm } // Set up the various authorization checkers. accessEnviron := common.AuthFuncForTagKind(names.EnvironTagKind) accessUnit := common.AuthFuncForTagKind(names.UnitTagKind) accessService := common.AuthFuncForTagKind(names.ServiceTagKind) accessMachine := common.AuthFuncForTagKind(names.MachineTagKind) accessUnitOrService := common.AuthEither(accessUnit, accessService) accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine) // Life() is supported for units, services or machines. lifeGetter := common.NewLifeGetter( st, accessUnitServiceOrMachine, ) // EnvironConfig() and WatchForEnvironConfigChanges() are allowed // with unrestriced access. environWatcher := common.NewEnvironWatcher( st, resources, authorizer, ) // Watch() is supported for services only. entityWatcher := common.NewAgentEntityWatcher( st, resources, accessService, ) // WatchUnits() is supported for machines. unitsWatcher := common.NewUnitsWatcher(st, resources, accessMachine, ) // WatchEnvironMachines() is allowed with unrestricted access. machinesWatcher := common.NewEnvironMachinesWatcher( st, resources, authorizer, ) // InstanceId() is supported for machines. instanceIdGetter := common.NewInstanceIdGetter( st, accessMachine, ) return &FirewallerAPI{ LifeGetter: lifeGetter, EnvironWatcher: environWatcher, AgentEntityWatcher: entityWatcher, UnitsWatcher: unitsWatcher, EnvironMachinesWatcher: machinesWatcher, InstanceIdGetter: instanceIdGetter, st: st, resources: resources, authorizer: authorizer, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, accessEnviron: accessEnviron, }, nil }