view auth/session.go @ 193:1585c334e8a7

More on persisting sessions.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 20 Jul 2018 18:32:11 +0200
parents 83d798ea9f58
children e85413e5befa
line wrap: on
line source

package auth

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"io"
	"time"
)

type Session struct {
	ExpiresAt int64    `json:"expires"`
	User      string   `json:"user"`
	Password  string   `json:"password"`
	Roles     []string `json:"roles"`
}

const (
	sessionKeyLength = 20
	maxTokenValid    = time.Hour * 3
)

func NewSession(user, password string, roles []string) *Session {

	// Create the Claims
	return &Session{
		ExpiresAt: time.Now().Add(maxTokenValid).Unix(),
		User:      user,
		Password:  password,
		Roles:     roles,
	}
}

func (s *Session) serialize(w io.Writer) {
	binary.Write(w, binary.BigEndian, s.ExpiresAt)
	binary.Write(w, binary.BigEndian, s.User)
	binary.Write(w, binary.BigEndian, s.Password)
	binary.Write(w, binary.BigEndian, uint32(len(s.Roles)))
	for _, role := range s.Roles {
		binary.Write(w, binary.BigEndian, role)
	}
}

func (s *Session) unserialize(r io.Reader) error {
	var x Session
	binary.Read(r, binary.BigEndian, &x.ExpiresAt)
	binary.Read(r, binary.BigEndian, &x.User)
	binary.Read(r, binary.BigEndian, &x.Password)
	var n uint32
	binary.Read(r, binary.BigEndian, &n)
	x.Roles = make([]string, n)
	for i := uint32(0); n > 0 && i < n; i++ {
		if err := binary.Read(r, binary.BigEndian, &x.Roles[i]); err != nil {
			return err
		}
	}
	*s = x
	return nil
}

func GenerateSessionKey() string {
	return base64.URLEncoding.EncodeToString(GenerateRandomKey(sessionKeyLength))
}

func GenerateRandomKey(length int) []byte {
	k := make([]byte, length)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return nil
	}
	return k
}

func GenerateSession(user, password string) (string, *Session, error) {
	roles, err := AllOtherRoles(user, password)
	if err != nil {
		return "", nil, err
	}
	token := GenerateSessionKey()
	session := NewSession(user, password, roles)
	ConnPool.Add(token, session)
	return token, session, nil
}