2016-08-19 00:45:39 +00:00
|
|
|
package kolide
|
2016-08-05 17:47:41 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
2016-08-10 02:04:28 +00:00
|
|
|
"github.com/kolide/kolide-ose/errors"
|
2016-09-05 19:50:57 +00:00
|
|
|
"golang.org/x/net/context"
|
2016-08-05 17:47:41 +00:00
|
|
|
)
|
|
|
|
|
2016-08-10 02:04:28 +00:00
|
|
|
const publicErrorMessage string = "Session error"
|
|
|
|
|
2016-08-05 17:47:41 +00:00
|
|
|
var (
|
2016-08-19 00:45:39 +00:00
|
|
|
// An error returned by SessionStore.Get() if no session record was found
|
2016-08-05 17:47:41 +00:00
|
|
|
// in the database
|
2016-08-10 02:04:28 +00:00
|
|
|
ErrNoActiveSession = errors.New(publicErrorMessage, "Active session is not present in the database")
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// An error returned by SessionStore methods when no session object has
|
2016-08-05 17:47:41 +00:00
|
|
|
// been created yet but the requested action requires one
|
2016-08-10 02:04:28 +00:00
|
|
|
ErrSessionNotCreated = errors.New(publicErrorMessage, "The session has not been created")
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// An error returned by SessionStore.Get() when a session is requested but
|
2016-08-05 17:47:41 +00:00
|
|
|
// it has expired
|
2016-08-10 02:04:28 +00:00
|
|
|
ErrSessionExpired = errors.New(publicErrorMessage, "The session has expired")
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// An error returned by SessionStore which indicates that the token
|
2016-08-05 17:47:41 +00:00
|
|
|
// or it's content were malformed
|
2016-08-10 02:04:28 +00:00
|
|
|
ErrSessionMalformed = errors.New(publicErrorMessage, "The session token was malformed")
|
2016-08-05 17:47:41 +00:00
|
|
|
)
|
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// SessionStore is the abstract interface that all session backends must
|
|
|
|
// conform to.
|
|
|
|
type SessionStore interface {
|
|
|
|
// Given a session key, find and return a session object or an error if one
|
|
|
|
// could not be found for the given key
|
|
|
|
FindSessionByKey(key string) (*Session, error)
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// Given a session id, find and return a session object or an error if one
|
|
|
|
// could not be found for the given id
|
|
|
|
FindSessionByID(id uint) (*Session, error)
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-08-19 00:45:39 +00:00
|
|
|
// Find all of the active sessions for a given user
|
|
|
|
FindAllSessionsForUser(id uint) ([]*Session, error)
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-09-14 16:11:06 +00:00
|
|
|
// Store a new session struct
|
|
|
|
NewSession(session *Session) (*Session, error)
|
2016-08-19 00:45:39 +00:00
|
|
|
|
|
|
|
// Destroy the currently tracked session
|
|
|
|
DestroySession(session *Session) error
|
|
|
|
|
|
|
|
// Destroy all of the sessions for a given user
|
|
|
|
DestroyAllSessionsForUser(id uint) error
|
|
|
|
|
|
|
|
// Mark the currently tracked session as access to extend expiration
|
|
|
|
MarkSessionAccessed(session *Session) error
|
|
|
|
}
|
2016-08-05 17:47:41 +00:00
|
|
|
|
2016-09-05 19:50:57 +00:00
|
|
|
type SessionService interface {
|
2016-09-08 01:24:11 +00:00
|
|
|
Login(ctx context.Context, username, password string) (*User, string, error)
|
|
|
|
Logout(ctx context.Context) error
|
|
|
|
DestroySession(ctx context.Context) error
|
2016-09-05 19:50:57 +00:00
|
|
|
GetInfoAboutSessionsForUser(ctx context.Context, id uint) ([]*Session, error)
|
|
|
|
DeleteSessionsForUser(ctx context.Context, id uint) error
|
|
|
|
GetInfoAboutSession(ctx context.Context, id uint) (*Session, error)
|
2016-09-14 16:11:06 +00:00
|
|
|
GetSessionByKey(ctx context.Context, key string) (*Session, error)
|
2016-09-05 19:50:57 +00:00
|
|
|
DeleteSession(ctx context.Context, id uint) error
|
|
|
|
}
|
|
|
|
|
2016-08-05 17:47:41 +00:00
|
|
|
// Session is the model object which represents what an active session is
|
|
|
|
type Session struct {
|
|
|
|
ID uint `gorm:"primary_key"`
|
|
|
|
CreatedAt time.Time
|
|
|
|
AccessedAt time.Time
|
|
|
|
UserID uint `gorm:"not null"`
|
|
|
|
Key string `gorm:"not null;unique_index:idx_session_unique_key"`
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// JSON Web Tokens
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Given a session key create a JWT to be delivered to the client
|
2016-09-01 04:51:38 +00:00
|
|
|
func GenerateJWT(sessionKey, jwtKey string) (string, error) {
|
2016-08-05 17:47:41 +00:00
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
|
|
"session_key": sessionKey,
|
|
|
|
})
|
|
|
|
|
2016-09-01 04:51:38 +00:00
|
|
|
return token.SignedString([]byte(jwtKey))
|
2016-08-05 17:47:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ParseJWT attempts to parse a JWT token in serialized string form into a
|
|
|
|
// JWT token in a deserialized jwt.Token struct.
|
2016-09-01 04:51:38 +00:00
|
|
|
func ParseJWT(token, jwtKey string) (*jwt.Token, error) {
|
2016-08-05 17:47:41 +00:00
|
|
|
return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
|
|
|
method, ok := t.Method.(*jwt.SigningMethodHMAC)
|
|
|
|
if !ok || method != jwt.SigningMethodHS256 {
|
2016-08-10 02:04:28 +00:00
|
|
|
return nil, errors.New(publicErrorMessage, "Unexpected signing method")
|
2016-08-05 17:47:41 +00:00
|
|
|
}
|
2016-09-01 04:51:38 +00:00
|
|
|
return []byte(jwtKey), nil
|
2016-08-05 17:47:41 +00:00
|
|
|
})
|
|
|
|
}
|