// Vikunja is a to-do list application to facilitate your life. // Copyright 2018-2021 Vikunja and contributors. All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public Licensee as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public Licensee for more details. // // You should have received a copy of the GNU Affero General Public Licensee // along with this program. If not, see . package auth import ( "code.vikunja.io/api/pkg/config" "github.com/dgrijalva/jwt-go" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) // Resolves circular dependencies of auth -> IAP -> auth var authMiddlewares = map[AuthType]echo.MiddlewareFunc{} func RegisterAuthMiddleware(t AuthType, f echo.MiddlewareFunc) { authMiddlewares[t] = f } const authTokenJWTContextKey = "jwtToken" // GetJWTConfig returns the config for the default JWT middleware func GetJWTConfig() middleware.JWTConfig { return middleware.JWTConfig{ SigningKey: []byte(config.ServiceJWTSecret.GetString()), SigningMethod: middleware.AlgorithmHS256, ContextKey: authTokenJWTContextKey, Claims: &AuthClaims{}, } } // The auth middleware uses the JWT middleware to parse and validate a JWT. // If that does not succeed, it generates a JWT token from the identity-aware proxy func Middleware() echo.MiddlewareFunc { // Create a noop next function to let us run middlewares without jumping to the next // one in the chain noOpNext := func(_ echo.Context) error { return nil } jwtMiddleware := middleware.JWTWithConfig(GetJWTConfig()) return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // First attempt to get auth from a provided JWT jwtErr := jwtMiddleware(noOpNext)(c) if c.Get(authTokenJWTContextKey) != nil && jwtErr == nil { // If it succeeded, use the authClaims from the JWT // and continue in the middleware chain jwtinf := c.Get(authTokenJWTContextKey).(*jwt.Token) claims := jwtinf.Claims.(*AuthClaims) c.Set(AuthClaimsContextKey, claims) return next(c) } // Otherwise, attempt to get auth from authMiddlewares for _, authMiddleware := range authMiddlewares { err := authMiddleware(noOpNext)(c) if c.Get(AuthClaimsContextKey) != nil && err == nil { // If it succeeded, continue in the middleware chain return next(c) } } // Otherwise, return the original error from jwt middleware return jwtErr } } }