Mercurial > gemma
view pkg/auth/middleware.go @ 3530:e98ea184538e
Improve warning message
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Wed, 29 May 2019 16:56:56 +0200 |
parents | 97430d442909 |
children |
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 ( "context" "net/http" "strings" ) type contextType int const ( sessionKey contextType = iota tokenKey ) // GetSession returns the session stored in the context of the request. func GetSession(req *http.Request) (*Session, bool) { session, ok := req.Context().Value(sessionKey).(*Session) return session, ok } // GetToken returns the session token associated with given request. func GetToken(req *http.Request) (string, bool) { token, ok := req.Context().Value(tokenKey).(string) return token, ok } // SessionMiddleware constructs a middleware to enforce the existence // of the header X-Gemma-Auth in the incoming request and checks // if a session is bound to it. // Ihe the checks fail the constructed handler issues an http.StatusUnauthorized // back to the invokation stacks and prevents the execution of the // nested http.Handler next. // Inside the http.Handler next calls to GetSession and GetToken are valid // to fetch the respective information. func SessionMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { auth := req.Header.Get("X-Gemma-Auth") token := strings.TrimSpace(auth) if token == "" { http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } session := Sessions.Session(token) if session == nil { http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } ctx := req.Context() ctx = context.WithValue(ctx, sessionKey, session) ctx = context.WithValue(ctx, tokenKey, token) req = req.WithContext(ctx) next.ServeHTTP(rw, req) }) } // SessionChecker constructs a middleware to check invariants about a session // before calling the nested http.Handler next. // This is useful when creating specialized middleware e.g. to enforce // a role system. func SessionChecker(next http.Handler, check func(*Session) bool) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if claims, ok := GetSession(req); !ok || !check(claims) { http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } next.ServeHTTP(rw, req) }) } // HasRole is a checker function fitting into SessionChecker to check // if the user is logged in with at least one of list of given roles. func HasRole(roles ...string) func(*Session) bool { return func(session *Session) bool { return session.Roles.HasAny(roles...) } } // EnsureRole is a macro function to stitch SessionChecker and HasRole together. func EnsureRole(roles ...string) func(http.Handler) http.Handler { return func(handler http.Handler) http.Handler { return SessionMiddleware(SessionChecker(handler, HasRole(roles...))) } }