mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
885db1a597
This PR refactors most of the codebase to use the new config patterns implemented in #149. Now the core service keeps a copy of the KolideConfig struct, and service methods can reference the configuration in that struct when they need it. The most significant refactoring is in the sessions code, separating the business logic from the storage layer.
122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package server
|
|
|
|
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)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
user, err = svc.ds.NewUser(user)
|
|
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)
|
|
}
|
|
|
|
func (svc service) ChangePassword(ctx context.Context, userID uint, old, new string) error {
|
|
user, err := svc.User(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := user.ValidatePassword(old); err != nil {
|
|
return fmt.Errorf("current password validation failed: %v", err)
|
|
}
|
|
hashed, salt, err := hashPassword(new, svc.config.Auth.SaltKeySize, svc.config.Auth.BcryptCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.Salt = salt
|
|
user.Password = hashed
|
|
return svc.saveUser(user)
|
|
}
|
|
|
|
func (svc service) UpdateAdminRole(ctx context.Context, userID uint, isAdmin bool) error {
|
|
user, err := svc.User(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.Admin = isAdmin
|
|
return svc.saveUser(user)
|
|
}
|
|
|
|
func (svc service) UpdateUserStatus(ctx context.Context, userID uint, password string, enabled bool) error {
|
|
user, err := svc.User(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.Enabled = enabled
|
|
return svc.saveUser(user)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
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,
|
|
}, 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
|
|
}
|