view pkg/auth/session.go @ 493:8a0737aa6ab6 metamorph-for-all

The connection pool is now only a session store.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 24 Aug 2018 14:25:05 +0200
parents b2dc9c2f69e0
children 22e1bf563a04
line wrap: on
line source

package auth

import (
	"encoding/base64"
	"errors"
	"io"
	"time"

	"gemma.intevation.de/gemma/pkg/common"
	"gemma.intevation.de/gemma/pkg/misc"
)

type Roles []string

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

func (r Roles) Has(role string) bool {
	for _, x := range r {
		if x == role {
			return true
		}
	}
	return false
}

func (r Roles) HasAny(roles ...string) bool {
	for _, y := range roles {
		if r.Has(y) {
			return true
		}
	}
	return false
}

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

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

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

func (s *Session) serialize(w io.Writer) error {
	wr := misc.BinWriter{w, nil}
	wr.WriteBin(s.ExpiresAt)
	wr.WriteString(s.User)
	wr.WriteBin(uint32(len(s.Roles)))
	for _, role := range s.Roles {
		wr.WriteString(role)
	}
	return wr.Err
}

func (s *Session) deserialize(r io.Reader) error {
	var x Session
	var n uint32
	rd := misc.BinReader{r, nil}
	rd.ReadBin(&x.ExpiresAt)
	rd.ReadString(&x.User)
	rd.ReadBin(&n)
	x.Roles = make(Roles, n)
	for i := uint32(0); n > 0 && i < n; i++ {
		rd.ReadString(&x.Roles[i])
	}
	if rd.Err == nil {
		*s = x
	}
	return rd.Err
}

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

var ErrInvalidRole = errors.New("Invalid role")

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