Update user properties (#143)
* renamed NeedsPasswordReset field for clarity This field was not obvious when it should be set or checked. This makes it a bit more obious. The property should only be set if the password request was requested by an admin. Having this property checked should - invalidate current user auth token - force user to reset password on their next login - NOT send a password reset email * add GravatarURL property we considered uploading and storing an image url in the future as well * Add a user property to save the user's job role/position
This commit is contained in:
+29
-25
@@ -29,31 +29,35 @@ type UserService interface {
|
||||
|
||||
// User is the model struct which represents a kolide user
|
||||
type User struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Username string `gorm:"not null;unique_index:idx_user_unique_username"`
|
||||
Password []byte `gorm:"not null"`
|
||||
Salt string `gorm:"not null"`
|
||||
Name string
|
||||
Email string `gorm:"not null;unique_index:idx_user_unique_email"`
|
||||
Admin bool `gorm:"not null"`
|
||||
Enabled bool `gorm:"not null"`
|
||||
NeedsPasswordReset bool
|
||||
ID uint `gorm:"primary_key"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Username string `gorm:"not null;unique_index:idx_user_unique_username"`
|
||||
Password []byte `gorm:"not null"`
|
||||
Salt string `gorm:"not null"`
|
||||
Name string
|
||||
Email string `gorm:"not null;unique_index:idx_user_unique_email"`
|
||||
Admin bool `gorm:"not null"`
|
||||
Enabled bool `gorm:"not null"`
|
||||
AdminForcedPasswordReset bool
|
||||
GravatarURL string
|
||||
Position string // job role
|
||||
}
|
||||
|
||||
// UserPayload is used to modify an existing user
|
||||
type UserPayload struct {
|
||||
Username *string `json:"username"`
|
||||
Name *string `json:"name"`
|
||||
Email *string `json:"email"`
|
||||
Admin *bool `json:"admin"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
NeedsPasswordReset *bool `json:"needs_password_reset"`
|
||||
Password *string `json:"password"`
|
||||
Username *string `json:"username"`
|
||||
Name *string `json:"name"`
|
||||
Email *string `json:"email"`
|
||||
Admin *bool `json:"admin"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
AdminForcedPasswordReset *bool `json:"force_password_reset"`
|
||||
Password *string `json:"password"`
|
||||
// modify params
|
||||
CurrentPassword *string `json:"current_password"`
|
||||
NewPassword *string `json:"new_password"`
|
||||
GravatarURL *string `json:"gravatar_url"`
|
||||
Position *string `json:"position"`
|
||||
}
|
||||
|
||||
// NewUser is a wrapper around the creation of a new user.
|
||||
@@ -66,13 +70,13 @@ func NewUser(username, password, email string, admin, needsPasswordReset bool) (
|
||||
return nil, err
|
||||
}
|
||||
user := User{
|
||||
Username: username,
|
||||
Password: hash,
|
||||
Salt: salt,
|
||||
Email: email,
|
||||
Admin: admin,
|
||||
Enabled: true,
|
||||
NeedsPasswordReset: needsPasswordReset,
|
||||
Username: username,
|
||||
Password: hash,
|
||||
Salt: salt,
|
||||
Email: email,
|
||||
Admin: admin,
|
||||
Enabled: true,
|
||||
AdminForcedPasswordReset: needsPasswordReset,
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func makeLoginEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
NeedsPasswordReset: user.NeedsPasswordReset,
|
||||
NeedsPasswordReset: user.AdminForcedPasswordReset,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
+43
-43
@@ -15,14 +15,14 @@ type createUserRequest struct {
|
||||
}
|
||||
|
||||
type createUserResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
NeedsPasswordReset bool `json:"needs_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
AdminForcedPasswordReset bool `json:"force_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r createUserResponse) error() error { return r.Err }
|
||||
@@ -35,12 +35,12 @@ func makeCreateUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return createUserResponse{Err: err}, nil
|
||||
}
|
||||
return createUserResponse{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
NeedsPasswordReset: user.NeedsPasswordReset,
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
AdminForcedPasswordReset: user.AdminForcedPasswordReset,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -54,14 +54,14 @@ type getUserRequest struct {
|
||||
}
|
||||
|
||||
type getUserResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
NeedsPasswordReset bool `json:"needs_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
AdminForcedPasswordReset bool `json:"force_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getUserResponse) error() error { return r.Err }
|
||||
@@ -74,12 +74,12 @@ func makeGetUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return getUserResponse{Err: err}, nil
|
||||
}
|
||||
return getUserResponse{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
NeedsPasswordReset: user.NeedsPasswordReset,
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
AdminForcedPasswordReset: user.AdminForcedPasswordReset,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -166,14 +166,14 @@ type modifyUserRequest struct {
|
||||
}
|
||||
|
||||
type modifyUserResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
NeedsPasswordReset bool `json:"needs_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Admin bool `json:"admin"`
|
||||
Enabled bool `json:"enabled"`
|
||||
AdminForcedPasswordReset bool `json:"force_password_reset"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r modifyUserResponse) error() error { return r.Err }
|
||||
@@ -189,13 +189,13 @@ func makeModifyUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
_ = req
|
||||
|
||||
return modifyUserResponse{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
NeedsPasswordReset: user.NeedsPasswordReset,
|
||||
Err: err,
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Admin: user.Admin,
|
||||
Enabled: user.Enabled,
|
||||
AdminForcedPasswordReset: user.AdminForcedPasswordReset,
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ func (vc *viewerContext) IsLoggedIn() bool {
|
||||
// CanPerformActions returns a bool indicating the current user's ability to
|
||||
// perform the most basic actions on the site
|
||||
func (vc *viewerContext) CanPerformActions() bool {
|
||||
return vc.IsLoggedIn() && !vc.user.NeedsPasswordReset
|
||||
return vc.IsLoggedIn() && !vc.user.AdminForcedPasswordReset
|
||||
}
|
||||
|
||||
// CanPerformReadActionsOnUser returns a bool indicating the current user's
|
||||
|
||||
@@ -158,11 +158,11 @@ func createTestUsers(t *testing.T, ds kolide.Datastore) {
|
||||
ctx := context.Background()
|
||||
for _, tt := range testUsers {
|
||||
payload := kolide.UserPayload{
|
||||
Username: tt.Username,
|
||||
Password: tt.Password,
|
||||
Email: tt.Email,
|
||||
Admin: tt.Admin,
|
||||
NeedsPasswordReset: tt.NeedsPasswordReset,
|
||||
Username: tt.Username,
|
||||
Password: tt.Password,
|
||||
Email: tt.Email,
|
||||
Admin: tt.Admin,
|
||||
AdminForcedPasswordReset: tt.AdminForcedPasswordReset,
|
||||
}
|
||||
_, err := svc.NewUser(ctx, payload)
|
||||
if err != nil {
|
||||
|
||||
@@ -75,13 +75,13 @@ func userFromPayload(p kolide.UserPayload, keySize, cost int) (*kolide.User, err
|
||||
}
|
||||
|
||||
return &kolide.User{
|
||||
Username: *p.Username,
|
||||
Email: *p.Email,
|
||||
Admin: falseIfNil(p.Admin),
|
||||
NeedsPasswordReset: falseIfNil(p.NeedsPasswordReset),
|
||||
Salt: salt,
|
||||
Enabled: true,
|
||||
Password: hashed,
|
||||
Username: *p.Username,
|
||||
Email: *p.Email,
|
||||
Admin: falseIfNil(p.Admin),
|
||||
AdminForcedPasswordReset: falseIfNil(p.AdminForcedPasswordReset),
|
||||
Salt: salt,
|
||||
Enabled: true,
|
||||
Password: hashed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,11 @@ func TestCreateUser(t *testing.T) {
|
||||
|
||||
for _, tt := range createUserTests {
|
||||
payload := kolide.UserPayload{
|
||||
Username: tt.Username,
|
||||
Password: tt.Password,
|
||||
Email: tt.Email,
|
||||
Admin: tt.Admin,
|
||||
NeedsPasswordReset: tt.NeedsPasswordReset,
|
||||
Username: tt.Username,
|
||||
Password: tt.Password,
|
||||
Email: tt.Email,
|
||||
Admin: tt.Admin,
|
||||
AdminForcedPasswordReset: tt.NeedsPasswordReset,
|
||||
}
|
||||
user, err := svc.NewUser(ctx, payload)
|
||||
switch err.(type) {
|
||||
@@ -64,11 +64,11 @@ func TestCreateUser(t *testing.T) {
|
||||
t.Errorf("expected err, got nil")
|
||||
}
|
||||
|
||||
if have, want := user.NeedsPasswordReset, *tt.NeedsPasswordReset; have != want {
|
||||
if have, want := user.AdminForcedPasswordReset, *tt.NeedsPasswordReset; have != want {
|
||||
t.Errorf("have %v want %v", have, want)
|
||||
}
|
||||
|
||||
if have, want := user.NeedsPasswordReset, *tt.NeedsPasswordReset; have != want {
|
||||
if have, want := user.AdminForcedPasswordReset, *tt.NeedsPasswordReset; have != want {
|
||||
t.Errorf("have %v want %v", have, want)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user