fleet/server/service_users.go

122 lines
2.9 KiB
Go
Raw Normal View History

package server
2016-08-28 03:59:17 +00:00
import (
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/kolide/kolide-ose/kolide"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context"
)
func (svc service) NewUser(ctx context.Context, p kolide.UserPayload) (*kolide.User, error) {
user, err := userFromPayload(p, svc.config.Auth.SaltKeySize, svc.config.Auth.BcryptCost)
2016-08-28 03:59:17 +00:00
if err != nil {
return nil, err
}
user, err = svc.ds.NewUser(user)
2016-08-28 03:59:17 +00:00
if err != nil {
return nil, err
}
return user, nil
}
func (svc service) User(ctx context.Context, id uint) (*kolide.User, error) {
return svc.ds.UserByID(id)
2016-08-29 00:29:56 +00:00
}
func (svc service) ChangePassword(ctx context.Context, userID uint, old, new string) error {
user, err := svc.User(ctx, userID)
2016-08-29 00:29:56 +00:00
if err != nil {
return err
}
2016-08-29 17:04:07 +00:00
if err := user.ValidatePassword(old); err != nil {
return fmt.Errorf("current password validation failed: %v", err)
2016-08-29 17:04:07 +00:00
}
hashed, salt, err := hashPassword(new, svc.config.Auth.SaltKeySize, svc.config.Auth.BcryptCost)
2016-08-29 00:29:56 +00:00
if err != nil {
return err
}
user.Salt = salt
user.Password = hashed
return svc.saveUser(user)
2016-08-29 00:29:56 +00:00
}
func (svc service) UpdateAdminRole(ctx context.Context, userID uint, isAdmin bool) error {
user, err := svc.User(ctx, userID)
2016-08-29 17:04:07 +00:00
if err != nil {
return err
}
user.Admin = isAdmin
return svc.saveUser(user)
2016-08-29 17:04:07 +00:00
}
func (svc service) UpdateUserStatus(ctx context.Context, userID uint, password string, enabled bool) error {
user, err := svc.User(ctx, userID)
2016-08-29 17:04:07 +00:00
if err != nil {
return err
}
user.Enabled = enabled
return svc.saveUser(user)
2016-08-29 17:04:07 +00:00
}
2016-08-29 00:29:56 +00:00
// saves user in datastore.
// doesn't need to be exposed to the transport
// the service should expose actions for modifying a user instead
func (svc service) saveUser(user *kolide.User) error {
return svc.ds.SaveUser(user)
2016-08-29 00:29:56 +00:00
}
2016-08-28 03:59:17 +00:00
func userFromPayload(p kolide.UserPayload, keySize, cost int) (*kolide.User, error) {
hashed, salt, err := hashPassword(*p.Password, keySize, cost)
if err != nil {
return nil, err
}
return &kolide.User{
Username: *p.Username,
Email: *p.Email,
Admin: falseIfNil(p.Admin),
AdminForcedPasswordReset: falseIfNil(p.AdminForcedPasswordReset),
Salt: salt,
Enabled: true,
Password: hashed,
2016-08-28 03:59:17 +00:00
}, nil
}
func hashPassword(plaintext string, keySize, cost int) ([]byte, string, error) {
salt, err := generateRandomText(keySize)
if err != nil {
return nil, "", err
}
withSalt := []byte(fmt.Sprintf("%s%s", plaintext, salt))
hashed, err := bcrypt.GenerateFromPassword(withSalt, cost)
if err != nil {
return nil, "", err
}
return hashed, salt, nil
}
// generateRandomText return a string generated by filling in keySize bytes with
// random data and then base64 encoding those bytes
func generateRandomText(keySize int) (string, error) {
key := make([]byte, keySize)
_, err := rand.Read(key)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(key), nil
}
// helper to convert a bool pointer false
func falseIfNil(b *bool) bool {
if b == nil {
return false
}
return *b
}