// merge applies the properties of the passed-in User to the User on which it // is called and returns a new User with these modifications applied. Think of // all Users as immutable sets of data. Merge allows you to perform the set // operations (desired grants and revokes) atomically func (u User) merge(n User) (User, error) { var out User if u.User != n.User { return out, authErr(http.StatusConflict, "Merging user data with conflicting usernames: %s %s", u.User, n.User) } out.User = u.User if n.Password != "" { hash, err := bcrypt.GenerateFromPassword([]byte(n.Password), bcrypt.DefaultCost) if err != nil { return User{}, err } out.Password = string(hash) } else { out.Password = u.Password } currentRoles := types.NewUnsafeSet(u.Roles...) for _, g := range n.Grant { if currentRoles.Contains(g) { plog.Noticef("granting duplicate role %s for user %s", g, n.User) return User{}, authErr(http.StatusConflict, fmt.Sprintf("Granting duplicate role %s for user %s", g, n.User)) } currentRoles.Add(g) } for _, r := range n.Revoke { if !currentRoles.Contains(r) { plog.Noticef("revoking ungranted role %s for user %s", r, n.User) return User{}, authErr(http.StatusConflict, fmt.Sprintf("Revoking ungranted role %s for user %s", r, n.User)) } currentRoles.Remove(r) } out.Roles = currentRoles.Values() sort.Strings(out.Roles) return out, nil }
func (s *store) createUserInternal(user User) (User, error) { if user.Password == "" { return user, authErr(http.StatusBadRequest, "Cannot create user %s with an empty password", user.User) } hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) if err != nil { return user, err } user.Password = string(hash) _, err = s.createResource("/users/"+user.User, user) if err != nil { if e, ok := err.(*etcderr.Error); ok { if e.ErrorCode == etcderr.EcodeNodeExist { return user, authErr(http.StatusConflict, "User %s already exists.", user.User) } } } return user, err }