Beispiel #1
0
// EnvironmentsForUser returns a list of enviroments that the user
// is able to access.
func (st *State) EnvironmentsForUser(user names.UserTag) ([]*UserEnvironment, error) {
	// Since there are no groups at this stage, the simplest way to get all
	// the environments that a particular user can see is to look through the
	// environment user collection. A raw collection is required to support
	// queries across multiple environments.
	envUsers, userCloser := st.getRawCollection(envUsersC)
	defer userCloser()

	// TODO: consider adding an index to the envUsers collection on the username.
	var userSlice []envUserDoc
	err := envUsers.Find(bson.D{{"user", user.Username()}}).All(&userSlice)
	if err != nil {
		return nil, err
	}

	var result []*UserEnvironment
	for _, doc := range userSlice {
		envTag := names.NewEnvironTag(doc.EnvUUID)
		env, err := st.GetEnvironment(envTag)
		if err != nil {
			return nil, errors.Trace(err)
		}
		result = append(result, &UserEnvironment{Environment: env, LastConnection: doc.LastConnection})
	}

	return result, nil
}
Beispiel #2
0
// AddEnvironmentUser adds a new user to the database.
func (st *State) AddEnvironmentUser(user, createdBy names.UserTag, displayName string) (*EnvironmentUser, error) {
	// Ensure local user exists in state before adding them as an environment user.
	if user.IsLocal() {
		localUser, err := st.User(user)
		if err != nil {
			return nil, errors.Annotate(err, fmt.Sprintf("user %q does not exist locally", user.Name()))
		}
		if displayName == "" {
			displayName = localUser.DisplayName()
		}
	}

	// Ensure local createdBy user exists.
	if createdBy.IsLocal() {
		if _, err := st.User(createdBy); err != nil {
			return nil, errors.Annotate(err, fmt.Sprintf("createdBy user %q does not exist locally", createdBy.Name()))
		}
	}

	envuuid := st.EnvironUUID()
	op, doc := createEnvUserOpAndDoc(envuuid, user, createdBy, displayName)
	err := st.runTransaction([]txn.Op{op})
	if err == txn.ErrAborted {
		err = errors.AlreadyExistsf("environment user %q", user.Username())
	}
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &EnvironmentUser{st: st, doc: *doc}, nil
}
Beispiel #3
0
// createUniqueOwnerEnvNameOp returns the operation needed to create
// an userenvnameC document with the given owner and environment name.
func createUniqueOwnerEnvNameOp(owner names.UserTag, envName string) txn.Op {
	return txn.Op{
		C:      userenvnameC,
		Id:     userEnvNameIndex(owner.Username(), envName),
		Assert: txn.DocMissing,
		Insert: bson.M{},
	}
}
Beispiel #4
0
// User returns the state User for the given name.
func (st *State) User(tag names.UserTag) (*User, error) {
	if !tag.IsLocal() {
		return nil, errors.NotFoundf("user %q", tag.Username())
	}
	user := &User{st: st}
	if err := st.getUser(tag.Name(), &user.doc); err != nil {
		return nil, errors.Trace(err)
	}
	return user, nil
}
Beispiel #5
0
// EnvironmentUser returns the environment user.
func (st *State) EnvironmentUser(user names.UserTag) (*EnvironmentUser, error) {
	envUser := &EnvironmentUser{st: st}
	envUsers, closer := st.getCollection(envUsersC)
	defer closer()

	id := envUserID(st.EnvironTag().Id(), user.Username())
	err := envUsers.FindId(id).One(&envUser.doc)
	if err == mgo.ErrNotFound {
		return nil, errors.NotFoundf("envUser %q", user.Username())
	}
	return envUser, nil
}
Beispiel #6
0
// EnvironmentUser returns the environment user.
func (st *State) EnvironmentUser(user names.UserTag) (*EnvironmentUser, error) {
	envUser := &EnvironmentUser{st: st}
	envUsers, closer := st.getCollection(envUsersC)
	defer closer()

	username := strings.ToLower(user.Username())
	err := envUsers.FindId(username).One(&envUser.doc)
	if err == mgo.ErrNotFound {
		return nil, errors.NotFoundf("environment user %q", user.Username())
	}
	// DateCreated is inserted as UTC, but read out as local time. So we
	// convert it back to UTC here.
	envUser.doc.DateCreated = envUser.doc.DateCreated.UTC()
	return envUser, nil
}
Beispiel #7
0
// createEnvironmentOp returns the operation needed to create
// an environment document with the given name and UUID.
func createEnvironmentOp(st *State, owner names.UserTag, name, uuid, server string) txn.Op {
	doc := &environmentDoc{
		UUID:       uuid,
		Name:       name,
		Life:       Alive,
		Owner:      owner.Username(),
		ServerUUID: server,
	}
	return txn.Op{
		C:      environmentsC,
		Id:     uuid,
		Assert: txn.DocMissing,
		Insert: doc,
	}
}
Beispiel #8
0
// RemoveEnvironmentUser removes a user from the database.
func (st *State) RemoveEnvironmentUser(user names.UserTag) error {
	ops := []txn.Op{{
		C:      envUsersC,
		Id:     envUserID(user),
		Assert: txn.DocExists,
		Remove: true,
	}}
	err := st.runTransaction(ops)
	if err == txn.ErrAborted {
		err = errors.NewNotFound(err, fmt.Sprintf("env user %q does not exist", user.Username()))
	}
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Beispiel #9
0
func createEnvUserOp(envuuid string, user, createdBy names.UserTag, displayName string) txn.Op {
	creatorname := createdBy.Username()
	doc := &envUserDoc{
		ID:          envUserID(user),
		EnvUUID:     envuuid,
		UserName:    user.Username(),
		DisplayName: displayName,
		CreatedBy:   creatorname,
		DateCreated: nowToTheSecond(),
	}
	return txn.Op{
		C:      envUsersC,
		Id:     envUserID(user),
		Assert: txn.DocMissing,
		Insert: doc,
	}
}
Beispiel #10
0
// AddEnvironmentUser adds a new user to the database.
func (st *State) AddEnvironmentUser(user, createdBy names.UserTag, displayName string) (*EnvironmentUser, error) {

	// Ensure local user exists in state before adding them as an environment user.
	if user.Provider() == names.LocalProvider {
		if _, err := st.User(user.Name()); err != nil {
			return nil, errors.Annotate(err, fmt.Sprintf("user %q does not exist locally", user.Name()))
		}
	}

	// Ensure local createdBy user exists.
	if createdBy.Provider() == names.LocalProvider {
		if _, err := st.User(createdBy.Name()); err != nil {
			return nil, errors.Annotate(err, fmt.Sprintf("createdBy user %q does not exist locally", createdBy.Name()))
		}
	}

	username := user.Username()
	envuuid := st.EnvironTag().Id()
	id := envUserID(envuuid, username)
	envUser := &EnvironmentUser{
		st: st,
		doc: envUserDoc{
			ID:          id,
			EnvUUID:     envuuid,
			UserName:    username,
			DisplayName: displayName,
			CreatedBy:   createdBy.Username(),
			DateCreated: nowToTheSecond(),
		}}

	ops := []txn.Op{{
		C:      envUsersC,
		Id:     id,
		Assert: txn.DocMissing,
		Insert: &envUser.doc,
	}}
	err := st.runTransaction(ops)
	if err == txn.ErrAborted {
		err = errors.New("env user already exists")
	}
	if err != nil {
		return nil, errors.Trace(err)
	}
	return envUser, nil
}
Beispiel #11
0
// IsSystemAdministrator returns true if the user specified has access to the
// state server environment (the system environment).
func (st *State) IsSystemAdministrator(user names.UserTag) (bool, error) {
	ssinfo, err := st.StateServerInfo()
	if err != nil {
		return false, errors.Annotate(err, "could not get state server info")
	}

	serverUUID := ssinfo.EnvironmentTag.Id()

	envUsers, userCloser := st.getRawCollection(envUsersC)
	defer userCloser()

	count, err := envUsers.Find(bson.D{
		{"env-uuid", serverUUID},
		{"user", user.Username()},
	}).Count()
	if err != nil {
		return false, errors.Trace(err)
	}
	return count == 1, nil
}
Beispiel #12
0
func createEnvUserOpAndDoc(envuuid string, user, createdBy names.UserTag, displayName string) (txn.Op, *envUserDoc) {
	username := user.Username()
	creatorname := createdBy.Username()
	id := envUserID(envuuid, username)
	doc := &envUserDoc{
		ID:          id,
		EnvUUID:     envuuid,
		UserName:    username,
		DisplayName: displayName,
		CreatedBy:   creatorname,
		DateCreated: nowToTheSecond(),
	}
	op := txn.Op{
		C:      envUsersC,
		Id:     id,
		Assert: txn.DocMissing,
		Insert: doc,
	}
	return op, doc
}
Beispiel #13
0
// authCheck checks if the user is acting on their own behalf, or if they
// are an administrator acting on behalf of another user.
func (em *EnvironmentManagerAPI) authCheck(user names.UserTag) error {
	// Since we know this is a user tag (because AuthClient is true),
	// we just do the type assertion to the UserTag.
	apiUser, _ := em.authorizer.GetAuthTag().(names.UserTag)
	isAdmin, err := em.state.IsSystemAdministrator(apiUser)
	if err != nil {
		return errors.Trace(err)
	}
	if isAdmin {
		logger.Tracef("%q is a system admin", apiUser.Username())
		return nil
	}

	// We can't just compare the UserTags themselves as the provider part
	// may be unset, and gets replaced with 'local'. We must compare against
	// the Username of the user tag.
	if apiUser.Username() == user.Username() {
		return nil
	}
	return common.ErrPerm
}
Beispiel #14
0
// envUserID returns the document id of the environment user
func envUserID(user names.UserTag) string {
	username := user.Username()
	return strings.ToLower(username)
}
Beispiel #15
0
// NewEnvironment creates a new environment with its own UUID and
// prepares it for use. Environment and State instances for the new
// environment are returned.
//
// The state server environment's UUID is attached to the new
// environment's document. Having the server UUIDs stored with each
// environment document means that we have a way to represent external
// environments, perhaps for future use around cross environment
// relations.
func (st *State) NewEnvironment(cfg *config.Config, owner names.UserTag) (_ *Environment, _ *State, err error) {
	if owner.IsLocal() {
		if _, err := st.User(owner); err != nil {
			return nil, nil, errors.Annotate(err, "cannot create environment")
		}
	}

	ssEnv, err := st.StateServerEnvironment()
	if err != nil {
		return nil, nil, errors.Annotate(err, "could not load state server environment")
	}

	uuid, ok := cfg.UUID()
	if !ok {
		return nil, nil, errors.Errorf("environment uuid was not supplied")
	}
	newState, err := st.ForEnviron(names.NewEnvironTag(uuid))
	if err != nil {
		return nil, nil, errors.Annotate(err, "could not create state for new environment")
	}
	defer func() {
		if err != nil {
			newState.Close()
		}
	}()

	ops, err := newState.envSetupOps(cfg, uuid, ssEnv.UUID(), owner)
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to create new environment")
	}
	err = newState.runTransactionNoEnvAliveAssert(ops)
	if err == txn.ErrAborted {

		// We have a  unique key restriction on the "owner" and "name" fields,
		// which will cause the insert to fail if there is another record with
		// the same "owner" and "name" in the collection. If the txn is
		// aborted, check if it is due to the unique key restriction.
		environments, closer := st.getCollection(environmentsC)
		defer closer()
		envCount, countErr := environments.Find(bson.D{
			{"owner", owner.Username()},
			{"name", cfg.Name()}},
		).Count()
		if countErr != nil {
			err = errors.Trace(countErr)
		} else if envCount > 0 {
			err = errors.AlreadyExistsf("environment %q for %s", cfg.Name(), owner.Username())
		} else {
			err = errors.New("environment already exists")
		}
	}
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	newEnv, err := newState.Environment()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	return newEnv, newState, nil
}