view auth/session.go @ 196:b67208d82543

Make test output more comprehensive Running all tests in one transaction ensures the final output tells about any failing test, not just in the last transaction (i.e. test script). The price is that no traces of the tests are left in the database because we have to rollback in order to have no left-over test roles in the cluster.
author Tom Gottfried <tom@intevation.de>
date Fri, 20 Jul 2018 18:31:45 +0200
parents 1585c334e8a7
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
}