package narco import ( "fmt" "net/http" "strings" "github.com/codemodus/chain" "golang.org/x/net/context" "ponyo.epfl.ch/gitlab/alexandre.tuleu/narco/jwt" ) type JWT struct { signer jwt.Signer } const ( jwtKeyGenerator narcoKey = 2 jwtKeyOutput narcoKey = 3 ) func (j *JWT) Wrap() func(chain.Handler) chain.Handler { return func(other chain.Handler) chain.Handler { return chain.HandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { tokenGenerator, ok := ctx.Value(jwtKeyGenerator).(TokenCreator) if tokenGenerator == nil || ok == false { //we did not register a token we ignore all processing other.ServeHTTPContext(ctx, rw, req) return } // check for the header tokenStr, ok := req.Header["Authorization"] if ok == false { // no Authorization header, we are just not // authentified, we process down, no token added other.ServeHTTPContext(ctx, rw, req) return } if len(tokenStr) != 1 || strings.HasPrefix(tokenStr[0], "Bearer ") == false { Error(ctx, rw, fmt.Errorf("Invalid Authorization HTTP Header %v", tokenStr), http.StatusForbidden) return } tkData := strings.TrimPrefix(tokenStr[0], "Bearer ") //parse the desired token, with signature checking token := tokenGenerator() err := jwt.DecodeJWS([]byte(tkData), token, j.signer) if err != nil { Error(ctx, rw, err, http.StatusForbidden) return } // we process down the pipeline, with the token added to // context other.ServeHTTPContext(context.WithValue(ctx, jwtKeyOutput, token), rw, req) }) } } func GetJwt(ctx context.Context) interface{} { return ctx.Value(jwtKeyOutput) } //A Token Creator should produce a new pointer to a desired token //struct type TokenCreator func() interface{} // RegisterJwtType should be used to register the token rtyope // expected in the context. TokenCreator should allocate a new, // unparsed token. func RegisterJwtType(ctx context.Context, generator TokenCreator) context.Context { return context.WithValue(ctx, jwtKeyGenerator, generator) } func NewJWT(s jwt.Signer) *JWT { return &JWT{signer: s} }