72 lines
1.8 KiB
Go
72 lines
1.8 KiB
Go
package backend
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
type UserType string
|
|
|
|
var (
|
|
UtPerson UserType = "person"
|
|
UtHost UserType = "host"
|
|
UtService UserType = "service"
|
|
|
|
ErrTooManyAttempts error = errors.New("too many attempts")
|
|
ErrReservationSniped error = errors.New("session ID reservation expired and was sniped")
|
|
ErrBackendData error = errors.New("invalid data from backend")
|
|
)
|
|
|
|
// Session holds info about the logged-in user that won't change
|
|
type Session struct {
|
|
SessionID string
|
|
Expiration time.Time
|
|
UserID string
|
|
UserType UserType
|
|
LdapDN string
|
|
}
|
|
|
|
// SessionCache holds volatile information about the logged-in user
|
|
type SessionCache struct {
|
|
Valid bool
|
|
Groups []string
|
|
DisplayName string
|
|
GivenName string
|
|
SurName string
|
|
Email string
|
|
}
|
|
|
|
type Backend interface {
|
|
PutSession(ctx context.Context, session Session, cache SessionCache) error
|
|
GetSession(ctx context.Context, id string) (Session, *SessionCache, error)
|
|
EndSession(ctx context.Context, id string)
|
|
// ReserveSessionID attempts to reserve a session ID. If the ID was successfully reserved, return true
|
|
// A reserved session ID should time out no sooner than 60s from the reservation.
|
|
// Ergo, once reserved, a session ID should be used within 60s
|
|
ReserveSessionID(ctx context.Context, sessionID string) (bool, error)
|
|
DoMaintenance(ctx context.Context)
|
|
Ping(ctx context.Context) error
|
|
}
|
|
|
|
func NewSessionID(ctx context.Context, backend Backend) (string, error) {
|
|
var data = make([]byte, 18)
|
|
for i := 0; i < 10; i++ {
|
|
_, err := rand.Read(data[2:])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
encoded := base64.URLEncoding.EncodeToString(data)
|
|
success, err := backend.ReserveSessionID(ctx, encoded)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if success {
|
|
return encoded, nil
|
|
}
|
|
}
|
|
return "", ErrTooManyAttempts
|
|
}
|