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:
Victor Vrantchan
2016-09-08 18:57:05 -04:00
committed by GitHub
parent a0a035f2c4
commit 05b1afd635
7 changed files with 93 additions and 89 deletions
+29 -25
View File
@@ -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
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+5 -5
View File
@@ -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 {
+7 -7
View File
@@ -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
}
+7 -7
View File
@@ -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)
}