// Verify user's JWT. func checkJWT(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") addCommonJwtRespHeaders(w, r) // Look for JWT in both headers and request value "access_token". token, err := request.ParseFromRequest(r, TokenExtractor{}, func(token *jwt.Token) (interface{}, error) { // Token was signed with RSA method when it was initially granted if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return publicKey, nil }) if err != nil || !token.Valid { http.Error(w, fmt.Sprintf("{\"error\": \"%s %s\"}", "JWT not valid,", err), http.StatusUnauthorized) } else { w.WriteHeader(http.StatusOK) } }
// Enable JWT authorization check on the HTTP handler function. func jwtWrap(originalHandler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { addCommonJwtRespHeaders(w, r) // Look for JWT in both headers and request value "access_token". token, err := request.ParseFromRequest(r, TokenExtractor{}, func(token *jwt.Token) (interface{}, error) { // Token was signed with RSA method when it was initially granted if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return publicKey, nil }) if err != nil || !token.Valid { http.Error(w, "", http.StatusUnauthorized) return } tokenClaims := token.Claims.(jwt.MapClaims) var url = strings.TrimPrefix(r.URL.Path, "/") var col = r.FormValue("col") // Call the API endpoint handler if authorization allows if tokenClaims[JWT_USER_ATTR] == JWT_USER_ADMIN { originalHandler(w, r) return } if !sliceContainsStr(tokenClaims[JWT_ENDPOINTS_ATTR], url) { http.Error(w, "", http.StatusUnauthorized) return } else if col != "" && !sliceContainsStr(tokenClaims[JWT_COLLECTIONS_ATTR], col) { http.Error(w, "", http.StatusUnauthorized) return } originalHandler(w, r) } }
// ParseFromRequest parses and validates the input token string in an http.Request. It's a wrapper of jwt.ParseFromRequest(). // // Params: // r: http.Request may contain jwt token. // extractor: Interface for extracting a token from an HTTP request. // See https://godoc.org/github.com/dgrijalva/jwt-go/request#Extractor // Return: // kid: Key id. // claims: map[string]interface{} to fill the jwt.Token[Claims]. // valid: token is valid or not. // err: error. func ParseFromRequest(r *http.Request, e request.Extractor) (kid string, claims map[string]interface{}, valid bool, err error) { t, err := request.ParseFromRequest(r, e, keyFunc) if err != nil { return "", nil, false, err } return t.Header["kid"].(string), t.Claims.(jwt.MapClaims), t.Valid, nil }
// NewJWTHandler parse and validates JWT token if present and store it in the net/context func NewJWTHandler(users *resource.Resource, jwtKeyFunc jwt.Keyfunc) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token, err := request.ParseFromRequest(r, request.OAuth2Extractor, jwtKeyFunc) if err == request.ErrNoTokenInRequest { // If no token is found, let REST Layer hooks decide if the resource is public or not next.ServeHTTP(w, r) return } if err != nil || !token.Valid { // Here you may want to return JSON error http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } claims := token.Claims.(jwt.MapClaims) userID, ok := claims["user_id"].(string) if !ok || userID == "" { // The provided token is malformed, user_id claim is missing http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } // Lookup the user by its id ctx := r.Context() user, err := users.Get(ctx, userID) if user != nil && err == resource.ErrUnauthorized { // Ignore unauthorized errors set by ourselves (see AuthResourceHook) err = nil } if err != nil { // If user resource storage handler returned an error, respond with an error if err == resource.ErrNotFound { http.Error(w, "Invalid credential", http.StatusForbidden) } else { http.Error(w, err.Error(), http.StatusInternalServerError) } return } // Store it into the request's context ctx = NewContextWithUser(ctx, user) r = r.WithContext(ctx) // If xlog is setup, store the user as logger field xlog.FromContext(ctx).SetField("user_id", user.ID) next.ServeHTTP(w, r) }) } }
func (h *jwtHandler) validateToken(req *http.Request) (*processor.TokenInfo, error) { start := time.Now() token, err := request.ParseFromRequest(req, request.OAuth2Extractor, jwtValidator(h.keyLoader)) if err != nil { log.Println("Failed to validate token: ", err) return nil, err } measureRequest(start, fmt.Sprintf("planb.tokeninfo.jwt.validation.%s", token.Method.Alg())) if !token.Valid { log.Println("Failed to validate token: ", ErrInvalidJWT) return nil, ErrInvalidJWT } if h.crp.IsJWTRevoked(token) { log.Println("Failed to validate token: ", ErrRevokedToken) return nil, ErrRevokedToken } return NewTokenInfo(token, time.Now()) }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { token, err := request.ParseFromRequest( r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) { return m.conf.Secret, nil }, ) if err == nil && token.Valid { newCtx := context.WithValue(ctx, httpware.TokenKey, token) return next.ServeHTTPCtx(newCtx, w, r) } // No soup for you. return httpware.NewErr("invalid token", http.StatusUnauthorized) }) }
// isJWTReqAuthenticated validates if any incoming request to be a // valid JWT authenticated request. func isJWTReqAuthenticated(req *http.Request) bool { jwt, err := newJWT(defaultJWTExpiry, serverConfig.GetCredential()) if err != nil { errorIf(err, "unable to initialize a new JWT") return false } var reqCallback jwtgo.Keyfunc reqCallback = func(token *jwtgo.Token) (interface{}, error) { if _, ok := token.Method.(*jwtgo.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return []byte(jwt.SecretAccessKey), nil } token, err := jwtreq.ParseFromRequest(req, jwtreq.AuthorizationHeaderExtractor, reqCallback) if err != nil { errorIf(err, "token parsing failed") return false } return token.Valid }