diff --git a/kolide/users.go b/kolide/users.go index 66b9540b59..b6e466bcba 100644 --- a/kolide/users.go +++ b/kolide/users.go @@ -26,6 +26,10 @@ type UserService interface { // User returns a valid User given a User ID User(ctx context.Context, id uint) (*User, error) + // AuthenticatedUser returns the current user + // from the viewer context + AuthenticatedUser(ctx context.Context) (*User, error) + // Users returns all users Users(ctx context.Context) ([]*User, error) diff --git a/server/endpoint_users.go b/server/endpoint_users.go index b75b13336e..50abcc2318 100644 --- a/server/endpoint_users.go +++ b/server/endpoint_users.go @@ -86,6 +86,23 @@ func makeGetUserEndpoint(svc kolide.Service) endpoint.Endpoint { } } +func makeGetSessionUserEndpoint(svc kolide.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + user, err := svc.AuthenticatedUser(ctx) + if err != nil { + return getUserResponse{Err: err}, nil + } + return getUserResponse{ + ID: user.ID, + Username: user.Username, + Email: user.Email, + Admin: user.Admin, + Enabled: user.Enabled, + AdminForcedPasswordReset: user.AdminForcedPasswordReset, + }, nil + } +} + //////////////////////////////////////////////////////////////////////////////// // List Users //////////////////////////////////////////////////////////////////////////////// diff --git a/server/handler.go b/server/handler.go index 2c0a40da83..07b9e8d683 100644 --- a/server/handler.go +++ b/server/handler.go @@ -51,6 +51,16 @@ func attachAPIRoutes(router *mux.Router, ctx context.Context, svc kolide.Service ), ).Methods("POST") + router.Handle("/api/v1/kolide/me", + kithttp.NewServer( + ctx, + makeGetSessionUserEndpoint(svc), + decodeNoParamsRequest, + encodeResponse, + opts..., + ), + ).Methods("GET") + router.Handle("/api/v1/kolide/users", kithttp.NewServer( ctx, diff --git a/server/handler_test.go b/server/handler_test.go index 76fa665cb9..a3e53db090 100644 --- a/server/handler_test.go +++ b/server/handler_test.go @@ -1,6 +1,7 @@ package server import ( + "fmt" "net/http/httptest" "testing" @@ -58,6 +59,10 @@ func TestAPIRoutes(t *testing.T) { verb: "POST", uri: "/api/v1/kolide/reset_password", }, + { + verb: "GET", + uri: "/api/v1/kolide/me", + }, { verb: "GET", uri: "/api/v1/kolide/queries/1", @@ -113,12 +118,13 @@ func TestAPIRoutes(t *testing.T) { } for _, route := range routes { - recorder := httptest.NewRecorder() - handler.ServeHTTP( - recorder, - httptest.NewRequest(route.verb, route.uri, nil), - ) - assert.NotEqual(t, 404, recorder.Code) + t.Run(fmt.Sprintf(": %v", route.uri), func(st *testing.T) { + recorder := httptest.NewRecorder() + handler.ServeHTTP( + recorder, + httptest.NewRequest(route.verb, route.uri, nil), + ) + assert.NotEqual(st, 404, recorder.Code) + }) } - } diff --git a/server/logging_users.go b/server/logging_users.go index 3299aae9e0..f99d136186 100644 --- a/server/logging_users.go +++ b/server/logging_users.go @@ -92,6 +92,30 @@ func (mw loggingMiddleware) User(ctx context.Context, id uint) (*kolide.User, er return user, err } +func (mw loggingMiddleware) AuthenticatedUser(ctx context.Context) (*kolide.User, error) { + var ( + user *kolide.User + err error + username = "none" + ) + + defer func(begin time.Time) { + _ = mw.logger.Log( + "method", "User", + "user", username, + "err", err, + "took", time.Since(begin), + ) + }(time.Now()) + + user, err = mw.Service.AuthenticatedUser(ctx) + + if user != nil { + username = user.Username + } + return user, err +} + func (mw loggingMiddleware) ResetPassword(ctx context.Context, token, password string) error { var err error diff --git a/server/service_users.go b/server/service_users.go index 3a5e21f51f..f0411d3305 100644 --- a/server/service_users.go +++ b/server/service_users.go @@ -92,6 +92,14 @@ func (svc service) User(ctx context.Context, id uint) (*kolide.User, error) { return svc.ds.UserByID(id) } +func (svc service) AuthenticatedUser(ctx context.Context) (*kolide.User, error) { + vc, err := viewerContextFromContext(ctx) + if err != nil { + return nil, err + } + return vc.user, nil +} + func (svc service) Users(ctx context.Context) ([]*kolide.User, error) { return svc.ds.Users() } diff --git a/server/service_users_test.go b/server/service_users_test.go index 7579f07878..98bb3524dc 100644 --- a/server/service_users_test.go +++ b/server/service_users_test.go @@ -15,6 +15,22 @@ import ( "golang.org/x/net/context" ) +func TestAuthenticatedUser(t *testing.T) { + ds, err := datastore.New("inmem", "") + assert.Nil(t, err) + createTestUsers(t, ds) + svc, err := NewService(ds, kitlog.NewNopLogger(), config.TestConfig(), nil) + assert.Nil(t, err) + admin1, err := ds.User("admin1") + assert.Nil(t, err) + + ctx := context.Background() + ctx = context.WithValue(ctx, "viewerContext", &viewerContext{user: admin1}) + user, err := svc.AuthenticatedUser(ctx) + assert.Nil(t, err) + assert.Equal(t, user, admin1) +} + func TestRequestPasswordReset(t *testing.T) { ds, err := datastore.New("inmem", "") assert.Nil(t, err)