Mercurial > gemma
view pkg/auth/session.go @ 3530:e98ea184538e
Improve warning message
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Wed, 29 May 2019 16:56:56 +0200 |
parents | 0db742c7813d |
children | 7cccf7fef3e8 |
line wrap: on
line source
// This is Free Software under GNU Affero General Public License v >= 3.0 // without warranty, see README.md and license for details. // // SPDX-License-Identifier: AGPL-3.0-or-later // License-Filename: LICENSES/AGPL-3.0.txt // // Copyright (C) 2018 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> package auth import ( "encoding/base64" "errors" "io" "sync" "time" "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/config" "gemma.intevation.de/gemma/pkg/misc" ) // Roles is a list of roles a logged in user has. type Roles []string // Session stores the informations about a logged in user. type Session struct { // ExpiresAt is a unix timestamp when the session // of the user expires. ExpiresAt int64 `json:"expires"` // User is the login name of the user. User string `json:"user"` // Roles is the list of roles of the user. Roles Roles `json:"roles"` // private fields for managing expiration. access time.Time mu sync.Mutex } // Has checks if a certain role is amongst the roles. func (r Roles) Has(role string) bool { for _, x := range r { if x == role { return true } } return false } // HasAny checks if any of the given roles is in the role list. func (r Roles) HasAny(roles ...string) bool { for _, y := range roles { if r.Has(y) { return true } } return false } const ( sessionKeyLength = 20 ) // newSession creates a new session. func newSession(user, password string, roles Roles) *Session { // Create the Claims return &Session{ ExpiresAt: time.Now().Add(config.SessionTimeout()).Unix(), User: user, Roles: roles, } } func (s *Session) serialize(w io.Writer) error { access, err := s.last().MarshalText() if err != nil { return err } wr := misc.BinWriter{Writer: w, Err: nil} wr.WriteBin(s.ExpiresAt) wr.WriteString(s.User) wr.WriteBin(uint32(len(s.Roles))) for _, role := range s.Roles { wr.WriteString(role) } wr.WriteBin(uint32(len(access))) wr.WriteBin(access) return wr.Err } func (s *Session) deserialize(r io.Reader) error { var n uint32 rd := misc.BinReader{Reader: r, Err: nil} rd.ReadBin(&s.ExpiresAt) rd.ReadString(&s.User) rd.ReadBin(&n) s.Roles = make(Roles, n) for i := uint32(0); n > 0 && i < n; i++ { rd.ReadString(&s.Roles[i]) } if rd.Err != nil { return rd.Err } var l uint32 rd.ReadBin(&l) access := make([]byte, l) rd.ReadBin(access) if rd.Err != nil { return rd.Err } var t time.Time if err := t.UnmarshalText(access); err != nil { return err } s.access = t return nil } func (s *Session) touch() { s.mu.Lock() s.access = time.Now() s.mu.Unlock() } func (s *Session) last() time.Time { s.mu.Lock() access := s.access s.mu.Unlock() return access } func generateSessionKey() string { return base64.URLEncoding.EncodeToString( common.GenerateRandomKey(sessionKeyLength)) } // ErrInvalidRole is returned if a given role does not exsist in this system. var ErrInvalidRole = errors.New("Invalid role") // GenerateSession creates a new session for a given user and password // backed by the roles of this user in the database. func GenerateSession(user, password string) (string, *Session, error) { roles, err := AllOtherRoles(user, password) if err != nil { return "", nil, err } // TODO: Make this a configuration. 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 }