view auth/middleware.go @ 230:8a226dc1c6ff

Made auth.Role variadic to allow to express that a endpoint may be used by more than one role. auth.HasRole already had this ability but I forgot to pull it through.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 26 Jul 2018 13:39:59 +0200
parents 63dd5216eee4
children 3771788d3dae
line wrap: on
line source

package auth

import (
	"context"
	"net/http"
	"strings"
)

type contextType int

const (
	sessionKey contextType = iota
	tokenKey
)

func GetSession(req *http.Request) (*Session, bool) {
	session, ok := req.Context().Value(sessionKey).(*Session)
	return session, ok
}

func GetToken(req *http.Request) (string, bool) {
	token, ok := req.Context().Value(tokenKey).(string)
	return token, ok
}

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 := ConnPool.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)
	})
}

func SessionChecker(next http.Handler, check func(*Session) bool) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		claims, ok := GetSession(req)
		if !ok || !check(claims) {
			http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(rw, req)
	})
}

func HasRole(roles ...string) func(*Session) bool {
	return func(session *Session) bool {
		for _, r1 := range roles {
			for _, r2 := range session.Roles {
				if r1 == r2 {
					return true
				}
			}
		}
		return false
	}
}

func EnsureRole(roles ...string) func(func(http.ResponseWriter, *http.Request)) http.Handler {
	return func(fn func(http.ResponseWriter, *http.Request)) http.Handler {
		return SessionMiddleware(SessionChecker(http.HandlerFunc(fn), HasRole(roles...)))
	}
}