mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
parent
f169b68bdf
commit
56b8772f13
16 changed files with 354 additions and 102 deletions
1
Makefile
1
Makefile
|
|
@ -137,6 +137,7 @@ deps:
|
|||
npm install
|
||||
go get github.com/jteeuwen/go-bindata/...
|
||||
go get github.com/Masterminds/glide
|
||||
go get github.com/groob/mockimpl
|
||||
glide install
|
||||
|
||||
distclean:
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ type UserService interface {
|
|||
|
||||
// ModifyUser updates a user's parameters given a UserPayload.
|
||||
ModifyUser(ctx context.Context, userID uint, p UserPayload) (user *User, err error)
|
||||
|
||||
// ChangeUserAdmin is used to modify the admin state of the user identified by id.
|
||||
ChangeUserAdmin(ctx context.Context, id uint, isAdmin bool) (*User, error)
|
||||
|
||||
// ChangeUserEnabled is used to enable/disable the user identified by id.
|
||||
ChangeUserEnabled(ctx context.Context, id uint, isEnabled bool) (*User, error)
|
||||
}
|
||||
|
||||
// User is the model struct which represents a kolide user
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ func makeGetAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
// only admin can see smtp settings
|
||||
if vc.IsAdmin() {
|
||||
smtpSettings = smtpSettingsFromAppConfig(config)
|
||||
if smtpSettings.SMTPPassword != "" {
|
||||
smtpSettings.SMTPPassword = "********"
|
||||
}
|
||||
}
|
||||
response := appConfigResponse{
|
||||
OrgInfo: &kolide.OrgInfo{
|
||||
|
|
@ -43,9 +46,6 @@ func makeGetAppConfigEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
},
|
||||
SMTPSettings: smtpSettings,
|
||||
}
|
||||
if response.SMTPSettings.SMTPPassword != "" {
|
||||
response.SMTPSettings.SMTPPassword = "********"
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func testGetAppConfig(t *testing.T, r *testResource) {
|
|||
|
||||
req, err := http.NewRequest("GET", r.server.URL+"/api/v1/kolide/config", nil)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -63,7 +63,7 @@ func testModifyAppConfig(t *testing.T, r *testResource) {
|
|||
require.Nil(t, err)
|
||||
req, err := http.NewRequest("PATCH", r.server.URL+"/api/v1/kolide/config", &buffer)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -92,7 +92,7 @@ func testModifyAppConfigWithValidationFail(t *testing.T, r *testResource) {
|
|||
require.Nil(t, err)
|
||||
req, err := http.NewRequest("PATCH", r.server.URL+"/api/v1/kolide/config", &buffer)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func testImportConfigWithGlob(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(testJSON)
|
||||
req, err := http.NewRequest("POST", r.server.URL+"/api/v1/kolide/osquery/config/import", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -48,7 +48,7 @@ func testImportConfigWithMissingGlob(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(testJSON)
|
||||
req, err := http.NewRequest("POST", r.server.URL+"/api/v1/kolide/osquery/config/import", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -73,7 +73,7 @@ func testImportConfig(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(testJSON)
|
||||
req, err := http.NewRequest("POST", r.server.URL+"/api/v1/kolide/osquery/config/import", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -93,7 +93,7 @@ func testImportConfigMissingExternal(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(testJSON)
|
||||
req, err := http.NewRequest("POST", r.server.URL+"/api/v1/kolide/osquery/config/import", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -180,72 +180,6 @@ const (
|
|||
admin
|
||||
)
|
||||
|
||||
func validateModifyUserRequest(next endpoint.Endpoint) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
r := request.(modifyUserRequest)
|
||||
vc, ok := viewer.FromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errNoContext
|
||||
}
|
||||
uid := requestUserIDFromContext(ctx)
|
||||
p := r.payload
|
||||
must := requireRoleForUserModification(p)
|
||||
|
||||
var badArgs []invalidArgument
|
||||
if !vc.IsAdmin() {
|
||||
for _, field := range must[admin] {
|
||||
badArgs = append(badArgs, invalidArgument{name: field, reason: "must be an admin"})
|
||||
}
|
||||
}
|
||||
if !vc.CanPerformWriteActionOnUser(uid) {
|
||||
for _, field := range must[self] {
|
||||
badArgs = append(badArgs, invalidArgument{name: field, reason: "no write permissions on user"})
|
||||
}
|
||||
}
|
||||
if len(badArgs) != 0 {
|
||||
return nil, permissionError{badArgs: badArgs}
|
||||
}
|
||||
return next(ctx, request)
|
||||
}
|
||||
}
|
||||
|
||||
// checks if fields were set in a user payload
|
||||
// returns a map of updated fields for each role required
|
||||
func requireRoleForUserModification(p kolide.UserPayload) map[permission][]string {
|
||||
must := make(map[permission][]string)
|
||||
adminFields := []string{}
|
||||
if p.Enabled != nil {
|
||||
adminFields = append(adminFields, "enabled")
|
||||
}
|
||||
if p.Admin != nil {
|
||||
adminFields = append(adminFields, "admin")
|
||||
}
|
||||
if len(adminFields) != 0 {
|
||||
must[admin] = adminFields
|
||||
}
|
||||
|
||||
selfFields := []string{}
|
||||
if p.Username != nil {
|
||||
selfFields = append(selfFields, "username")
|
||||
}
|
||||
if p.GravatarURL != nil {
|
||||
selfFields = append(selfFields, "gravatar_url")
|
||||
}
|
||||
if p.Position != nil {
|
||||
selfFields = append(selfFields, "position")
|
||||
}
|
||||
if p.Email != nil {
|
||||
selfFields = append(selfFields, "email")
|
||||
}
|
||||
if p.Password != nil {
|
||||
selfFields = append(selfFields, "password")
|
||||
}
|
||||
// self is always a must, otherwise
|
||||
// anyone can edit the field, and we don't have that requirement
|
||||
must[self] = selfFields
|
||||
return must
|
||||
}
|
||||
|
||||
func requestUserIDFromContext(ctx context.Context) uint {
|
||||
userID, ok := ctx.Value("request-id").(uint)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -107,17 +107,6 @@ func TestEndpointPermissions(t *testing.T) {
|
|||
requestID: admin1.ID,
|
||||
wantErr: permissionError{message: "no read permissions on user"},
|
||||
},
|
||||
{
|
||||
endpoint: validateModifyUserRequest(e),
|
||||
request: modifyUserRequest{},
|
||||
wantErr: errNoContext,
|
||||
},
|
||||
{
|
||||
endpoint: validateModifyUserRequest(e),
|
||||
request: modifyUserRequest{payload: kolide.UserPayload{Enabled: boolPtr(true)}},
|
||||
vc: &viewer.Viewer{User: user1},
|
||||
wantErr: permissionError{message: "unauthorized: must be an admin"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range endpointTests {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ func testGetOptions(t *testing.T, r *testResource) {
|
|||
|
||||
req, err := http.NewRequest("GET", r.server.URL+"/api/v1/kolide/options", nil)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -34,7 +34,7 @@ func testModifyOptions(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(inJson)
|
||||
req, err := http.NewRequest("PATCH", r.server.URL+"/api/v1/kolide/options", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
@ -55,7 +55,7 @@ func testModifyOptionsValidationFail(t *testing.T, r *testResource) {
|
|||
buff := bytes.NewBufferString(inJson)
|
||||
req, err := http.NewRequest("PATCH", r.server.URL+"/api/v1/kolide/options", buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ import (
|
|||
)
|
||||
|
||||
type testResource struct {
|
||||
server *httptest.Server
|
||||
userToken string
|
||||
ds kolide.Datastore
|
||||
server *httptest.Server
|
||||
adminToken string
|
||||
userToken string
|
||||
ds kolide.Datastore
|
||||
}
|
||||
|
||||
func setupEndpointTest(t *testing.T) *testResource {
|
||||
|
|
@ -80,7 +81,19 @@ func setupEndpointTest(t *testing.T) *testResource {
|
|||
Err string `json:"error,omitempty"`
|
||||
}{}
|
||||
json.NewDecoder(resp.Body).Decode(&jsn)
|
||||
test.adminToken = jsn.Token
|
||||
|
||||
// log in non admin user
|
||||
userParam.Username = "user1"
|
||||
userParam.Password = testUsers["user1"].PlaintextPassword
|
||||
marshalledUser, _ = json.Marshal(userParam)
|
||||
requestBody = &nopCloser{bytes.NewBuffer(marshalledUser)}
|
||||
resp, err = http.Post(test.server.URL+"/api/v1/kolide/login", "application/json", requestBody)
|
||||
require.Nil(t, err)
|
||||
err = json.NewDecoder(resp.Body).Decode(&jsn)
|
||||
require.Nil(t, err)
|
||||
test.userToken = jsn.Token
|
||||
|
||||
return test
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +114,10 @@ var testFunctions = [...]func(*testing.T, *testResource){
|
|||
testImportConfigMissingExternal,
|
||||
testImportConfigWithMissingGlob,
|
||||
testImportConfigWithGlob,
|
||||
testAdminUserSetAdmin,
|
||||
testNonAdminUserSetAdmin,
|
||||
testAdminUserSetEnabled,
|
||||
testNonAdminUserSetEnabled,
|
||||
}
|
||||
|
||||
func TestEndpoints(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,52 @@ func makeGetUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
}
|
||||
}
|
||||
|
||||
type adminUserRequest struct {
|
||||
ID uint `json:"id"`
|
||||
Admin bool `json:"admin"`
|
||||
}
|
||||
|
||||
type adminUserResponse struct {
|
||||
User *kolide.User `json:"user,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r adminUserResponse) error() error { return r.Err }
|
||||
|
||||
func makeAdminUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(adminUserRequest)
|
||||
user, err := svc.ChangeUserAdmin(ctx, req.ID, req.Admin)
|
||||
if err != nil {
|
||||
return adminUserResponse{Err: err}, nil
|
||||
}
|
||||
return adminUserResponse{User: user}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type enableUserRequest struct {
|
||||
ID uint `json:"id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type enableUserResponse struct {
|
||||
User *kolide.User `json:"user,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r enableUserResponse) error() error { return r.Err }
|
||||
|
||||
func makeEnableUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(enableUserRequest)
|
||||
user, err := svc.ChangeUserEnabled(ctx, req.ID, req.Enabled)
|
||||
if err != nil {
|
||||
return enableUserResponse{Err: err}, nil
|
||||
}
|
||||
return enableUserResponse{User: user}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func makeGetSessionUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
user, err := svc.AuthenticatedUser(ctx)
|
||||
|
|
|
|||
105
server/service/endpoint_users_test.go
Normal file
105
server/service/endpoint_users_test.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testAdminUserSetAdmin(t *testing.T, r *testResource) {
|
||||
user, err := r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.False(t, user.Admin)
|
||||
inJson := `{"admin":true}`
|
||||
buff := bytes.NewBufferString(inJson)
|
||||
path := fmt.Sprintf("/api/v1/kolide/users/%d/admin", user.ID)
|
||||
req, err := http.NewRequest("POST", r.server.URL+path, buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
var actual adminUserResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&actual)
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, actual.Err)
|
||||
require.NotNil(t, actual.User)
|
||||
assert.True(t, actual.User.Admin)
|
||||
user, err = r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.True(t, user.Admin)
|
||||
}
|
||||
|
||||
func testNonAdminUserSetAdmin(t *testing.T, r *testResource) {
|
||||
user, err := r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.False(t, user.Admin)
|
||||
inJson := `{"admin":true}`
|
||||
buff := bytes.NewBufferString(inJson)
|
||||
path := fmt.Sprintf("/api/v1/kolide/users/%d/admin", user.ID)
|
||||
req, err := http.NewRequest("POST", r.server.URL+path, buff)
|
||||
require.Nil(t, err)
|
||||
// user NOT admin
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, http.StatusServiceUnavailable, resp.StatusCode)
|
||||
rb := make([]byte, 500)
|
||||
resp.Body.Read(rb)
|
||||
user, err = r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.False(t, user.Admin)
|
||||
}
|
||||
|
||||
func testAdminUserSetEnabled(t *testing.T, r *testResource) {
|
||||
user, err := r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.True(t, user.Enabled)
|
||||
inJson := `{"enabled":false}`
|
||||
buff := bytes.NewBufferString(inJson)
|
||||
path := fmt.Sprintf("/api/v1/kolide/users/%d/enable", user.ID)
|
||||
req, err := http.NewRequest("POST", r.server.URL+path, buff)
|
||||
require.Nil(t, err)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.adminToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
var actual adminUserResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&actual)
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, actual.Err)
|
||||
require.NotNil(t, actual.User)
|
||||
assert.False(t, actual.User.Enabled)
|
||||
user, err = r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.False(t, user.Enabled)
|
||||
}
|
||||
|
||||
func testNonAdminUserSetEnabled(t *testing.T, r *testResource) {
|
||||
user, err := r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
assert.True(t, user.Enabled)
|
||||
inJson := `{"enabled":false}`
|
||||
buff := bytes.NewBufferString(inJson)
|
||||
path := fmt.Sprintf("/api/v1/kolide/users/%d/enable", user.ID)
|
||||
req, err := http.NewRequest("POST", r.server.URL+path, buff)
|
||||
require.Nil(t, err)
|
||||
// user NOT admin
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.userToken))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, http.StatusServiceUnavailable, resp.StatusCode)
|
||||
rb := make([]byte, 500)
|
||||
resp.Body.Read(rb)
|
||||
user, err = r.ds.User("user1")
|
||||
require.Nil(t, err)
|
||||
// shouldn't change
|
||||
assert.True(t, user.Enabled)
|
||||
}
|
||||
|
|
@ -25,6 +25,8 @@ type KolideEndpoints struct {
|
|||
GetUser endpoint.Endpoint
|
||||
ListUsers endpoint.Endpoint
|
||||
ModifyUser endpoint.Endpoint
|
||||
AdminUser endpoint.Endpoint
|
||||
EnableUser endpoint.Endpoint
|
||||
RequirePasswordReset endpoint.Endpoint
|
||||
PerformRequiredPasswordReset endpoint.Endpoint
|
||||
GetSessionsForUserInfo endpoint.Endpoint
|
||||
|
|
@ -94,7 +96,9 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint
|
|||
ChangePassword: authenticatedUser(jwtKey, svc, canPerformActions(makeChangePasswordEndpoint(svc))),
|
||||
GetUser: authenticatedUser(jwtKey, svc, canReadUser(makeGetUserEndpoint(svc))),
|
||||
ListUsers: authenticatedUser(jwtKey, svc, canPerformActions(makeListUsersEndpoint(svc))),
|
||||
ModifyUser: authenticatedUser(jwtKey, svc, validateModifyUserRequest(makeModifyUserEndpoint(svc))),
|
||||
ModifyUser: authenticatedUser(jwtKey, svc, canPerformActions(makeModifyUserEndpoint(svc))),
|
||||
AdminUser: authenticatedUser(jwtKey, svc, mustBeAdmin(makeAdminUserEndpoint(svc))),
|
||||
EnableUser: authenticatedUser(jwtKey, svc, mustBeAdmin(makeEnableUserEndpoint(svc))),
|
||||
RequirePasswordReset: authenticatedUser(jwtKey, svc, mustBeAdmin(makeRequirePasswordResetEndpoint(svc))),
|
||||
// PerformRequiredPasswordReset needs only to authenticate the
|
||||
// logged in user
|
||||
|
|
@ -158,6 +162,8 @@ type kolideHandlers struct {
|
|||
GetUser http.Handler
|
||||
ListUsers http.Handler
|
||||
ModifyUser http.Handler
|
||||
AdminUser http.Handler
|
||||
EnableUser http.Handler
|
||||
RequirePasswordReset http.Handler
|
||||
PerformRequiredPasswordReset http.Handler
|
||||
GetSessionsForUserInfo http.Handler
|
||||
|
|
@ -223,6 +229,8 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
|
|||
ModifyUser: newServer(e.ModifyUser, decodeModifyUserRequest),
|
||||
RequirePasswordReset: newServer(e.RequirePasswordReset, decodeRequirePasswordResetRequest),
|
||||
PerformRequiredPasswordReset: newServer(e.PerformRequiredPasswordReset, decodePerformRequiredPasswordResetRequest),
|
||||
EnableUser: newServer(e.EnableUser, decodeEnableUserRequest),
|
||||
AdminUser: newServer(e.AdminUser, decodeAdminUserRequest),
|
||||
GetSessionsForUserInfo: newServer(e.GetSessionsForUserInfo, decodeGetInfoAboutSessionsForUserRequest),
|
||||
DeleteSessionsForUser: newServer(e.DeleteSessionsForUser, decodeDeleteSessionsForUserRequest),
|
||||
GetSessionInfo: newServer(e.GetSessionInfo, decodeGetInfoAboutSessionRequest),
|
||||
|
|
@ -320,6 +328,8 @@ func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) {
|
|||
r.Handle("/api/v1/kolide/users", h.CreateUser).Methods("POST").Name("create_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}", h.GetUser).Methods("GET").Name("get_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}", h.ModifyUser).Methods("PATCH").Name("modify_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}/enable", h.EnableUser).Methods("POST").Name("enable_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}/admin", h.AdminUser).Methods("POST").Name("admin_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}/require_password_reset", h.RequirePasswordReset).Methods("POST").Name("require_password_reset")
|
||||
r.Handle("/api/v1/kolide/users/{id}/sessions", h.GetSessionsForUserInfo).Methods("GET").Name("get_session_for_user")
|
||||
r.Handle("/api/v1/kolide/users/{id}/sessions", h.DeleteSessionsForUser).Methods("DELETE").Name("delete_session_for_user")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,68 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (mw loggingMiddleware) ChangeUserAdmin(ctx context.Context, id uint, isAdmin bool) (*kolide.User, error) {
|
||||
var (
|
||||
loggedInUser = "unauthenticated"
|
||||
userName = "none"
|
||||
err error
|
||||
user *kolide.User
|
||||
)
|
||||
|
||||
vc, ok := viewer.FromContext(ctx)
|
||||
if ok {
|
||||
loggedInUser = vc.Username()
|
||||
}
|
||||
|
||||
defer func(begin time.Time) {
|
||||
_ = mw.logger.Log(
|
||||
"method", "ChangeUserAdmin",
|
||||
"user", userName,
|
||||
"changed_by", loggedInUser,
|
||||
"admin", isAdmin,
|
||||
"err", err,
|
||||
"took", time.Since(begin),
|
||||
)
|
||||
}(time.Now())
|
||||
|
||||
user, err = mw.Service.ChangeUserAdmin(ctx, id, isAdmin)
|
||||
if user != nil {
|
||||
userName = user.Username
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (mw loggingMiddleware) ChangeUserEnabled(ctx context.Context, id uint, isEnabled bool) (*kolide.User, error) {
|
||||
var (
|
||||
loggedInUser = "unauthenticated"
|
||||
userName = "none"
|
||||
err error
|
||||
user *kolide.User
|
||||
)
|
||||
|
||||
vc, ok := viewer.FromContext(ctx)
|
||||
if ok {
|
||||
loggedInUser = vc.Username()
|
||||
}
|
||||
|
||||
defer func(begin time.Time) {
|
||||
_ = mw.logger.Log(
|
||||
"method", "ChangeUserEnabled",
|
||||
"user", userName,
|
||||
"changed_by", loggedInUser,
|
||||
"enabled", isEnabled,
|
||||
"err", err,
|
||||
"took", time.Since(begin),
|
||||
)
|
||||
}(time.Now())
|
||||
|
||||
user, err = mw.Service.ChangeUserEnabled(ctx, id, isEnabled)
|
||||
if user != nil {
|
||||
userName = user.Username
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (mw loggingMiddleware) NewAdminCreatedUser(ctx context.Context, p kolide.UserPayload) (*kolide.User, error) {
|
||||
var (
|
||||
user *kolide.User
|
||||
|
|
|
|||
|
|
@ -8,6 +8,38 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (mw metricsMiddleware) ChangeUserAdmin(ctx context.Context, id uint, isAdmin bool) (*kolide.User, error) {
|
||||
var (
|
||||
user *kolide.User
|
||||
err error
|
||||
)
|
||||
|
||||
defer func(begin time.Time) {
|
||||
lvs := []string{"method", "ChangeUserAdmin", "error", fmt.Sprint(err != nil)}
|
||||
mw.requestCount.With(lvs...).Add(1)
|
||||
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
user, err = mw.Service.ChangeUserAdmin(ctx, id, isAdmin)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (mw metricsMiddleware) ChangeUserEnabled(ctx context.Context, id uint, isEnabled bool) (*kolide.User, error) {
|
||||
var (
|
||||
user *kolide.User
|
||||
err error
|
||||
)
|
||||
|
||||
defer func(begin time.Time) {
|
||||
lvs := []string{"method", "ChangeUserEnabled", "error", fmt.Sprint(err != nil)}
|
||||
mw.requestCount.With(lvs...).Add(1)
|
||||
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
user, err = mw.Service.ChangeUserEnabled(ctx, id, isEnabled)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (mw metricsMiddleware) NewUser(ctx context.Context, p kolide.UserPayload) (*kolide.User, error) {
|
||||
var (
|
||||
user *kolide.User
|
||||
|
|
|
|||
|
|
@ -49,6 +49,30 @@ func (svc service) newUser(p kolide.UserPayload) (*kolide.User, error) {
|
|||
return user, nil
|
||||
}
|
||||
|
||||
func (svc service) ChangeUserAdmin(ctx context.Context, id uint, isAdmin bool) (*kolide.User, error) {
|
||||
user, err := svc.ds.UserByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Admin = isAdmin
|
||||
if err = svc.saveUser(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (svc service) ChangeUserEnabled(ctx context.Context, id uint, isEnabled bool) (*kolide.User, error) {
|
||||
user, err := svc.ds.UserByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Enabled = isEnabled
|
||||
if err = svc.saveUser(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (svc service) ModifyUser(ctx context.Context, userID uint, p kolide.UserPayload) (*kolide.User, error) {
|
||||
user, err := svc.User(ctx, userID)
|
||||
if err != nil {
|
||||
|
|
@ -57,6 +81,14 @@ func (svc service) ModifyUser(ctx context.Context, userID uint, p kolide.UserPay
|
|||
|
||||
// the method assumes that the correct authorization
|
||||
// has been validated higher up the stack
|
||||
if p.Admin != nil {
|
||||
user.Admin = *p.Admin
|
||||
}
|
||||
|
||||
if p.Enabled != nil {
|
||||
user.Enabled = *p.Enabled
|
||||
}
|
||||
|
||||
if p.Username != nil {
|
||||
user.Username = *p.Username
|
||||
}
|
||||
|
|
@ -65,18 +97,10 @@ func (svc service) ModifyUser(ctx context.Context, userID uint, p kolide.UserPay
|
|||
user.Name = *p.Name
|
||||
}
|
||||
|
||||
if p.Admin != nil {
|
||||
user.Admin = *p.Admin
|
||||
}
|
||||
|
||||
if p.Email != nil {
|
||||
user.Email = *p.Email
|
||||
}
|
||||
|
||||
if p.Enabled != nil {
|
||||
user.Enabled = *p.Enabled
|
||||
}
|
||||
|
||||
if p.Position != nil {
|
||||
user.Position = *p.Position
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,32 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func decodeEnableUserRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
id, err := idFromRequest(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var req enableUserRequest
|
||||
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.ID = id
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeAdminUserRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
id, err := idFromRequest(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var req adminUserRequest
|
||||
if err = json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.ID = id
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeCreateUserRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var req createUserRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.payload); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue