This repository has been archived by the owner on Mar 11, 2021. It is now read-only.
/
jwt_token_context.go
65 lines (56 loc) · 2.74 KB
/
jwt_token_context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package goamiddleware
import (
"context"
"fmt"
jwtgo "github.com/dgrijalva/jwt-go"
"github.com/fabric8-services/fabric8-auth/application"
"net/http"
"strings"
"github.com/fabric8-services/fabric8-auth/authorization/token/manager"
"github.com/fabric8-services/fabric8-auth/log"
"github.com/goadesign/goa"
"github.com/goadesign/goa/middleware/security/jwt"
)
// TokenContext is a new goa middleware that aims to extract the token from the
// Authorization header when possible. If the Authorization header is missing in the request,
// no error is returned. However, if the Authorization header contains a
// token, it will be stored it in the context.
func TokenContext(app application.Application, tokenManager manager.TokenManager, scheme *goa.JWTSecurity) goa.Middleware {
errUnauthorized := goa.NewErrorClass("token_validation_failed", 401)
return func(nextHandler goa.Handler) goa.Handler {
return handler(app, tokenManager, scheme, nextHandler, errUnauthorized)
}
}
func handler(app application.Application, tokenManager manager.TokenManager, scheme *goa.JWTSecurity, nextHandler goa.Handler, errUnauthorized goa.ErrorClass) goa.Handler {
return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
// TODO: implement the QUERY string handler too
if scheme.In != goa.LocHeader {
log.Error(ctx, nil, fmt.Sprintf("whoops, security scheme with location (in) %q not supported", scheme.In))
return fmt.Errorf("whoops, security scheme with location (in) %q not supported", scheme.In)
}
val := req.Header.Get(scheme.Name)
if val != "" && strings.HasPrefix(strings.ToLower(val), "bearer ") { // let's be more permissive than the spec and not restrict to a (strict) `Bearer` type of authorization
log.Debug(ctx, nil, "found header 'Authorization: Bearer JWT-token...'")
incomingToken := strings.Split(val, " ")[1]
log.Debug(ctx, nil, "extracted the incoming token %v ", incomingToken)
token, err := tokenManager.Parse(ctx, incomingToken)
if err != nil {
log.Error(ctx, map[string]interface{}{"error": err}, "failed to handle JSON Web Token in TokenContext middleware")
tokenManager.AddLoginRequiredHeader(rw)
return errUnauthorized("token is invalid")
}
// If the token is *not* a service account token, then check if it is valid
accountName := token.Claims.(jwtgo.MapClaims)["service_accountname"]
if accountName == nil {
err = app.TokenService().ValidateToken(ctx, token)
if err != nil {
log.Error(ctx, map[string]interface{}{"error": err}, "failed to validate JSON Web Token in TokenContext middleware")
tokenManager.AddLoginRequiredHeader(rw)
return errUnauthorized("token is invalid")
}
}
ctx = jwt.WithJWT(ctx, token)
}
return nextHandler(ctx, rw, req)
}
}