mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Quick contexts additions (#739)
* Defining a concrete type for session tokens * More rightish vc.IsLoggedIn() * using type conversion instead of a method call * include sessions in test viewer contexts
This commit is contained in:
parent
cc5aa3395d
commit
a047ef2211
@ -3,28 +3,32 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type key int
|
||||
|
||||
const tokenKey key = 0
|
||||
|
||||
// Token is the concrete type which represents kolide session tokens
|
||||
type Token string
|
||||
|
||||
// FromHTTPRequest extracts an Authorization
|
||||
// from an HTTP header if present.
|
||||
func FromHTTPRequest(r *http.Request) string {
|
||||
func FromHTTPRequest(r *http.Request) Token {
|
||||
headers := r.Header.Get("Authorization")
|
||||
headerParts := strings.Split(headers, " ")
|
||||
if len(headerParts) != 2 || strings.ToUpper(headerParts[0]) != "BEARER" {
|
||||
return ""
|
||||
}
|
||||
return headerParts[1]
|
||||
return Token(headerParts[1])
|
||||
}
|
||||
|
||||
// NewContext returns a new context carrying the Authorization Bearer token.
|
||||
func NewContext(ctx context.Context, token string) context.Context {
|
||||
func NewContext(ctx context.Context, token Token) context.Context {
|
||||
if token == "" {
|
||||
return ctx
|
||||
}
|
||||
@ -32,7 +36,7 @@ func NewContext(ctx context.Context, token string) context.Context {
|
||||
}
|
||||
|
||||
// FromContext extracts the Authorization Bearer token if present.
|
||||
func FromContext(ctx context.Context) (string, bool) {
|
||||
token, ok := ctx.Value(tokenKey).(string)
|
||||
func FromContext(ctx context.Context) (Token, bool) {
|
||||
token, ok := ctx.Value(tokenKey).(Token)
|
||||
return token, ok
|
||||
}
|
||||
|
@ -77,7 +77,16 @@ func (v Viewer) SessionID() uint {
|
||||
// account
|
||||
func (v Viewer) IsLoggedIn() bool {
|
||||
if v.User != nil {
|
||||
return v.User.Enabled
|
||||
if !v.User.Enabled {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if v.Session != nil {
|
||||
// Without having access to a service to call GetInfoAboutSession(id),
|
||||
// we can't synchronously check the database here.
|
||||
if v.Session.ID != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func makeStreamDistributedQueryCampaignResultsHandler(svc kolide.Service, jwtKey
|
||||
}
|
||||
|
||||
// Authenticate with the token
|
||||
vc, err := authViewer(context.Background(), jwtKey, string(token), svc)
|
||||
vc, err := authViewer(context.Background(), jwtKey, token, svc)
|
||||
if err != nil || !vc.CanPerformActions() {
|
||||
logger.Log("err", err, "msg", "unauthorized viewer")
|
||||
conn.WriteJSONError("unauthorized")
|
||||
|
@ -85,8 +85,8 @@ func authenticatedUser(jwtKey string, svc kolide.Service, next endpoint.Endpoint
|
||||
}
|
||||
|
||||
// authViewer creates an authenticated viewer by validating a JWT token.
|
||||
func authViewer(ctx context.Context, jwtKey string, bearerToken string, svc kolide.Service) (*viewer.Viewer, error) {
|
||||
jwtToken, err := jwt.Parse(bearerToken, func(token *jwt.Token) (interface{}, error) {
|
||||
func authViewer(ctx context.Context, jwtKey string, bearerToken token.Token, svc kolide.Service) (*viewer.Viewer, error) {
|
||||
jwtToken, err := jwt.Parse(string(bearerToken), func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
@ -18,11 +18,34 @@ import (
|
||||
// permissions to access or modify resources
|
||||
func TestEndpointPermissions(t *testing.T) {
|
||||
req := struct{}{}
|
||||
ds, _ := inmem.New(config.TestConfig())
|
||||
ds, err := inmem.New(config.TestConfig())
|
||||
assert.Nil(t, err)
|
||||
|
||||
createTestUsers(t, ds)
|
||||
admin1, _ := ds.User("admin1")
|
||||
user1, _ := ds.User("user1")
|
||||
user2, _ := ds.User("user2")
|
||||
|
||||
admin1, err := ds.User("admin1")
|
||||
assert.Nil(t, err)
|
||||
admin1Session, err := ds.NewSession(&kolide.Session{
|
||||
UserID: admin1.ID,
|
||||
Key: "admin1",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
user1, err := ds.User("user1")
|
||||
assert.Nil(t, err)
|
||||
user1Session, err := ds.NewSession(&kolide.Session{
|
||||
UserID: user1.ID,
|
||||
Key: "user1",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
user2, err := ds.User("user2")
|
||||
assert.Nil(t, err)
|
||||
user2Session, err := ds.NewSession(&kolide.Session{
|
||||
UserID: user2.ID,
|
||||
Key: "user2",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
user2.Enabled = false
|
||||
|
||||
e := endpoint.Nop // a test endpoint
|
||||
@ -51,36 +74,36 @@ func TestEndpointPermissions(t *testing.T) {
|
||||
},
|
||||
{
|
||||
endpoint: mustBeAdmin(e),
|
||||
vc: &viewer.Viewer{User: admin1},
|
||||
vc: &viewer.Viewer{User: admin1, Session: admin1Session},
|
||||
},
|
||||
{
|
||||
endpoint: mustBeAdmin(e),
|
||||
vc: &viewer.Viewer{User: user1},
|
||||
vc: &viewer.Viewer{User: user1, Session: user1Session},
|
||||
wantErr: permissionError{message: "must be an admin"},
|
||||
},
|
||||
{
|
||||
endpoint: canModifyUser(e),
|
||||
vc: &viewer.Viewer{User: admin1},
|
||||
vc: &viewer.Viewer{User: admin1, Session: admin1Session},
|
||||
},
|
||||
{
|
||||
endpoint: canModifyUser(e),
|
||||
vc: &viewer.Viewer{User: user1},
|
||||
vc: &viewer.Viewer{User: user1, Session: user1Session},
|
||||
wantErr: permissionError{message: "no write permissions on user"},
|
||||
},
|
||||
{
|
||||
endpoint: canModifyUser(e),
|
||||
vc: &viewer.Viewer{User: user1},
|
||||
vc: &viewer.Viewer{User: user1, Session: user1Session},
|
||||
requestID: admin1.ID,
|
||||
wantErr: permissionError{message: "no write permissions on user"},
|
||||
},
|
||||
{
|
||||
endpoint: canReadUser(e),
|
||||
vc: &viewer.Viewer{User: user1},
|
||||
vc: &viewer.Viewer{User: user1, Session: user1Session},
|
||||
requestID: admin1.ID,
|
||||
},
|
||||
{
|
||||
endpoint: canReadUser(e),
|
||||
vc: &viewer.Viewer{User: user2},
|
||||
vc: &viewer.Viewer{User: user2, Session: user2Session},
|
||||
requestID: admin1.ID,
|
||||
wantErr: permissionError{message: "no read permissions on user"},
|
||||
},
|
||||
|
@ -25,9 +25,14 @@ func TestAuthenticatedUser(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
admin1, err := ds.User("admin1")
|
||||
assert.Nil(t, err)
|
||||
admin1Session, err := ds.NewSession(&kolide.Session{
|
||||
UserID: admin1.ID,
|
||||
Key: "admin1",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = viewer.NewContext(ctx, viewer.Viewer{User: admin1})
|
||||
ctx = viewer.NewContext(ctx, viewer.Viewer{User: admin1, Session: admin1Session})
|
||||
user, err := svc.AuthenticatedUser(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, user, admin1)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/kolide/kolide-ose/server/contexts/token"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -112,13 +113,13 @@ func (c *Conn) ReadJSONMessage() (*JSONMessage, error) {
|
||||
// authData defines the data used to authenticate a Kolide frontend client over
|
||||
// a websocket connection.
|
||||
type authData struct {
|
||||
Token string `json:"token"`
|
||||
Token token.Token `json:"token"`
|
||||
}
|
||||
|
||||
// ReadAuthToken reads from the websocket, returning an auth token embedded in
|
||||
// a JSONMessage with type "auth" and data that can be unmarshalled to
|
||||
// authData.
|
||||
func (c *Conn) ReadAuthToken() (string, error) {
|
||||
func (c *Conn) ReadAuthToken() (token.Token, error) {
|
||||
msg, err := c.ReadJSONMessage()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "read auth token")
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/kolide/kolide-ose/server/contexts/token"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -238,7 +239,7 @@ func TestReadAuthToken(t *testing.T) {
|
||||
var cases = []struct {
|
||||
typ string
|
||||
data authData
|
||||
token string
|
||||
token token.Token
|
||||
err error
|
||||
}{
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user