2016-09-26 18:48:55 +00:00
|
|
|
package service
|
2016-09-01 04:51:38 +00:00
|
|
|
|
|
|
|
import (
|
2017-03-15 15:55:30 +00:00
|
|
|
"context"
|
2016-09-14 16:11:06 +00:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
2016-09-15 19:27:55 +00:00
|
|
|
"strings"
|
2016-09-14 16:11:06 +00:00
|
|
|
"time"
|
2016-09-01 04:51:38 +00:00
|
|
|
|
2017-01-14 20:00:09 +00:00
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
2017-02-01 17:20:50 +00:00
|
|
|
"github.com/kolide/kolide/server/contexts/viewer"
|
|
|
|
"github.com/kolide/kolide/server/kolide"
|
2017-01-14 20:00:09 +00:00
|
|
|
"github.com/pkg/errors"
|
2016-09-01 04:51:38 +00:00
|
|
|
)
|
|
|
|
|
2016-09-08 01:24:11 +00:00
|
|
|
func (svc service) Login(ctx context.Context, username, password string) (*kolide.User, string, error) {
|
2016-09-15 19:27:55 +00:00
|
|
|
user, err := svc.userByEmailOrUsername(username)
|
2016-12-20 18:35:22 +00:00
|
|
|
if _, ok := err.(kolide.NotFoundError); ok {
|
2016-09-29 00:46:45 +00:00
|
|
|
return nil, "", authError{reason: "no such user"}
|
2016-12-20 18:35:22 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2016-09-08 01:24:11 +00:00
|
|
|
return nil, "", err
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
|
|
|
if !user.Enabled {
|
2016-09-23 02:41:58 +00:00
|
|
|
return nil, "", authError{reason: "account disabled", clientReason: "account disabled"}
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
2016-11-16 13:47:49 +00:00
|
|
|
if err = user.ValidatePassword(password); err != nil {
|
2016-09-29 00:46:45 +00:00
|
|
|
return nil, "", authError{reason: "bad password"}
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
2016-09-14 16:11:06 +00:00
|
|
|
token, err := svc.makeSession(user.ID)
|
2016-09-08 01:24:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return user, token, nil
|
|
|
|
}
|
|
|
|
|
2016-09-15 19:27:55 +00:00
|
|
|
func (svc service) userByEmailOrUsername(username string) (*kolide.User, error) {
|
|
|
|
if strings.Contains(username, "@") {
|
|
|
|
return svc.ds.UserByEmail(username)
|
|
|
|
}
|
|
|
|
return svc.ds.User(username)
|
|
|
|
}
|
|
|
|
|
2016-09-14 16:11:06 +00:00
|
|
|
// makeSession is a helper that creates a new session after authentication
|
|
|
|
func (svc service) makeSession(id uint) (string, error) {
|
|
|
|
sessionKeySize := svc.config.Session.KeySize
|
|
|
|
key := make([]byte, sessionKeySize)
|
|
|
|
_, err := rand.Read(key)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
session := &kolide.Session{
|
2016-09-15 22:53:47 +00:00
|
|
|
UserID: id,
|
|
|
|
Key: base64.StdEncoding.EncodeToString(key),
|
|
|
|
AccessedAt: time.Now().UTC(),
|
2016-09-14 16:11:06 +00:00
|
|
|
}
|
2016-09-08 01:24:11 +00:00
|
|
|
|
2016-09-14 16:11:06 +00:00
|
|
|
session, err = svc.ds.NewSession(session)
|
2016-09-08 01:24:11 +00:00
|
|
|
if err != nil {
|
2017-01-14 20:00:09 +00:00
|
|
|
return "", errors.Wrap(err, "creating new session")
|
2016-09-08 01:24:11 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 20:00:09 +00:00
|
|
|
tokenString, err := generateJWT(session.Key, svc.config.Auth.JwtKey)
|
2016-09-08 01:24:11 +00:00
|
|
|
if err != nil {
|
2017-01-14 20:00:09 +00:00
|
|
|
return "", errors.Wrap(err, "generating JWT token")
|
2016-09-08 01:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return tokenString, nil
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
|
|
|
|
2016-09-14 16:11:06 +00:00
|
|
|
func (svc service) Logout(ctx context.Context) error {
|
|
|
|
// this should not return an error if the user wasn't logged in
|
|
|
|
return svc.DestroySession(ctx)
|
|
|
|
}
|
|
|
|
|
2016-09-08 01:24:11 +00:00
|
|
|
func (svc service) DestroySession(ctx context.Context) error {
|
2016-09-26 17:14:39 +00:00
|
|
|
vc, ok := viewer.FromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
return errNoContext
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
2016-09-08 01:24:11 +00:00
|
|
|
|
2016-10-14 15:59:27 +00:00
|
|
|
session, err := svc.ds.SessionByID(vc.SessionID())
|
2016-09-08 01:24:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.ds.DestroySession(session)
|
2016-09-01 04:51:38 +00:00
|
|
|
}
|
2016-09-05 19:50:57 +00:00
|
|
|
|
|
|
|
func (svc service) GetInfoAboutSessionsForUser(ctx context.Context, id uint) ([]*kolide.Session, error) {
|
2016-09-14 16:11:06 +00:00
|
|
|
var validatedSessions []*kolide.Session
|
|
|
|
|
2016-10-14 15:59:27 +00:00
|
|
|
sessions, err := svc.ds.ListSessionsForUser(id)
|
2016-09-14 16:11:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return validatedSessions, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, session := range sessions {
|
|
|
|
if svc.validateSession(session) == nil {
|
|
|
|
validatedSessions = append(validatedSessions, session)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return validatedSessions, nil
|
2016-09-05 19:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (svc service) DeleteSessionsForUser(ctx context.Context, id uint) error {
|
|
|
|
return svc.ds.DestroyAllSessionsForUser(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc service) GetInfoAboutSession(ctx context.Context, id uint) (*kolide.Session, error) {
|
2016-10-14 15:59:27 +00:00
|
|
|
session, err := svc.ds.SessionByID(id)
|
2016-09-14 16:11:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = svc.validateSession(session)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return session, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc service) GetSessionByKey(ctx context.Context, key string) (*kolide.Session, error) {
|
2016-10-14 15:59:27 +00:00
|
|
|
session, err := svc.ds.SessionByKey(key)
|
2016-09-14 16:11:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = svc.validateSession(session)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return session, nil
|
2016-09-05 19:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (svc service) DeleteSession(ctx context.Context, id uint) error {
|
2016-10-14 15:59:27 +00:00
|
|
|
session, err := svc.ds.SessionByID(id)
|
2016-09-05 19:50:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return svc.ds.DestroySession(session)
|
|
|
|
}
|
2016-09-14 16:11:06 +00:00
|
|
|
|
|
|
|
func (svc service) validateSession(session *kolide.Session) error {
|
|
|
|
if session == nil {
|
2017-01-14 20:00:09 +00:00
|
|
|
return authError{
|
|
|
|
reason: "active session not present",
|
|
|
|
clientReason: "session error",
|
|
|
|
}
|
2016-09-14 16:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sessionDuration := svc.config.Session.Duration
|
|
|
|
// duration 0 = unlimited
|
|
|
|
if sessionDuration != 0 && time.Since(session.AccessedAt) >= sessionDuration {
|
|
|
|
err := svc.ds.DestroySession(session)
|
|
|
|
if err != nil {
|
2017-01-14 20:00:09 +00:00
|
|
|
return errors.Wrap(err, "destroying session")
|
|
|
|
}
|
|
|
|
return authError{
|
|
|
|
reason: "expired session",
|
|
|
|
clientReason: "session error",
|
2016-09-14 16:11:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.ds.MarkSessionAccessed(session)
|
|
|
|
}
|
2017-01-14 20:00:09 +00:00
|
|
|
|
|
|
|
// Given a session key create a JWT to be delivered to the client
|
|
|
|
func generateJWT(sessionKey, jwtKey string) (string, error) {
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
|
|
"session_key": sessionKey,
|
|
|
|
})
|
|
|
|
|
|
|
|
return token.SignedString([]byte(jwtKey))
|
|
|
|
}
|