Mercurial > gemma
changeset 119:29e56c342c9f
Added first middleware for JWT token extraction. TODO: Add second one to check against logged in users.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 26 Jun 2018 18:29:26 +0200 |
parents | dad6cf39691e |
children | be2631b0ce7e |
files | auth/middleware.go auth/token.go config/config.go |
diffstat | 3 files changed, 98 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auth/middleware.go Tue Jun 26 18:29:26 2018 +0200 @@ -0,0 +1,54 @@ +package auth + +import ( + "context" + "fmt" + "net/http" + "regexp" +) + +var extractToken = regexp.MustCompile(`\s*Bearer\s+(\S+)`) + +type contextType int + +const ( + claimsKey contextType = iota + tokenKey +) + +func GetClaims(req *http.Request) (*Claims, bool) { + claims, ok := req.Context().Value(claimsKey).(*Claims) + return claims, ok +} + +func GetToken(req *http.Request) (string, bool) { + token, ok := req.Context().Value(tokenKey).(string) + return token, ok +} + +func JWTMiddleware(next http.Handler) http.Handler { + + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + + auth := req.Header.Get("Authorization") + + token := extractToken.FindStringSubmatch(auth) + if len(token) != 2 { + http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + + claims, err := TokenToClaims(token[1]) + if err != nil { + http.Error(rw, fmt.Sprintf("error: %v", err), http.StatusUnauthorized) + return + } + + ctx := req.Context() + ctx = context.WithValue(ctx, claimsKey, claims) + ctx = context.WithValue(ctx, tokenKey, token[1]) + req = req.WithContext(ctx) + + next.ServeHTTP(rw, req) + }) +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auth/token.go Tue Jun 26 18:29:26 2018 +0200 @@ -0,0 +1,40 @@ +package auth + +import ( + "time" + + "gemma.intevation.de/gemma/config" + + jwt "github.com/dgrijalva/jwt-go" +) + +type Claims struct { + jwt.StandardClaims + + User string `json:"user"` + Roles []string `json:"roles"` +} + +const maxTokenValid = time.Hour * 3 + +func NewToken(user string, roles []string) (string, error) { + + // Create the Claims + claims := &Claims{ + StandardClaims: jwt.StandardClaims{ + ExpiresAt: jwt.TimeFunc().Add(maxTokenValid).Unix(), + }, + User: user, + Roles: roles, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(config.Config.JWTSignKey) +} + +func TokenToClaims(token string) (*Claims, error) { + claims := &Claims{} + _, err := jwt.ParseWithClaims(token, claims, + func(*jwt.Token) (interface{}, error) { return config.Config.JWTSignKey, nil }) + return claims, err +}
--- a/config/config.go Tue Jun 26 16:40:44 2018 +0200 +++ b/config/config.go Tue Jun 26 18:29:26 2018 +0200 @@ -7,6 +7,8 @@ DBPort uint DBName string DBSSLMode string + + JWTSignKey []byte } func NewConfiguration() *Configuration { @@ -16,5 +18,7 @@ DBPort: 5432, DBName: "gemma", DBSSLMode: "require", + + JWTSignKey: []byte("very, very secret!"), } }