diff --git a/backend/server/api/middlewares.go b/backend/server/api/middlewares.go index 9e274c259df..32ec5e85490 100644 --- a/backend/server/api/middlewares.go +++ b/backend/server/api/middlewares.go @@ -20,6 +20,7 @@ package api import ( "encoding/base64" "fmt" + "github.com/apache/incubator-devlake/core/log" "net/http" "regexp" "strings" @@ -95,11 +96,13 @@ func OAuth2ProxyAuthentication(basicRes context.BasicRes) gin.HandlerFunc { } } +type apiBody struct { + Success bool `json:"success"` + Message string `json:"message"` +} + func RestAuthentication(router *gin.Engine, basicRes context.BasicRes) gin.HandlerFunc { - type ApiBody struct { - Success bool `json:"success"` - Message string `json:"message"` - } + db := basicRes.GetDal() logger := basicRes.GetLogger() if db == nil { @@ -115,88 +118,97 @@ func RestAuthentication(router *gin.Engine, basicRes context.BasicRes) gin.Handl return } path = strings.TrimPrefix(path, "/rest") - authHeader := c.GetHeader("Authorization") - if authHeader == "" { - c.Abort() - c.JSON(http.StatusUnauthorized, &ApiBody{ - Success: false, - Message: "token is missing", - }) + ok := CheckAuthorizationHeader(c, logger, db, apiKeyHelper, authHeader, path) + if !ok { return - } - apiKeyStr := strings.TrimPrefix(authHeader, "Bearer ") - if apiKeyStr == authHeader || apiKeyStr == "" { + } else { + router.HandleContext(c) c.Abort() - c.JSON(http.StatusUnauthorized, &ApiBody{ - Success: false, - Message: "token is not present or malformed", - }) return } + } +} - hashedApiKey, err := apiKeyHelper.DigestToken(apiKeyStr) - if err != nil { - logger.Error(err, "DigestToken") - c.Abort() - c.JSON(http.StatusInternalServerError, &ApiBody{ - Success: false, - Message: err.Error(), - }) - return - } +func CheckAuthorizationHeader(c *gin.Context, logger log.Logger, db dal.Dal, apiKeyHelper *apikeyhelper.ApiKeyHelper, authHeader, path string) bool { + if authHeader == "" { + c.Abort() + c.JSON(http.StatusUnauthorized, &apiBody{ + Success: false, + Message: "token is missing", + }) + return false + } + apiKeyStr := strings.TrimPrefix(authHeader, "Bearer ") + if apiKeyStr == authHeader || apiKeyStr == "" { + c.Abort() + c.JSON(http.StatusUnauthorized, &apiBody{ + Success: false, + Message: "token is not present or malformed", + }) + return false + } - apiKey, err := apiKeyHelper.GetApiKey(nil, dal.Where("api_key = ?", hashedApiKey)) - if err != nil { - c.Abort() - if db.IsErrorNotFound(err) { - c.JSON(http.StatusForbidden, &ApiBody{ - Success: false, - Message: "api key is invalid", - }) - } else { - logger.Error(err, "query api key from db") - c.JSON(http.StatusInternalServerError, &ApiBody{ - Success: false, - Message: err.Error(), - }) - } - return - } + hashedApiKey, err := apiKeyHelper.DigestToken(apiKeyStr) + if err != nil { + logger.Error(err, "DigestToken") + c.Abort() + c.JSON(http.StatusInternalServerError, &apiBody{ + Success: false, + Message: err.Error(), + }) + return false + } - if apiKey.ExpiredAt != nil && time.Until(*apiKey.ExpiredAt) < 0 { - c.Abort() - c.JSON(http.StatusForbidden, &ApiBody{ - Success: false, - Message: "api key has expired", - }) - return - } - matched, matchErr := regexp.MatchString(apiKey.AllowedPath, path) - if matchErr != nil { - logger.Error(err, "regexp match path error") - c.Abort() - c.JSON(http.StatusInternalServerError, &ApiBody{ + apiKey, err := apiKeyHelper.GetApiKey(nil, dal.Where("api_key = ?", hashedApiKey)) + if err != nil { + c.Abort() + if db.IsErrorNotFound(err) { + c.JSON(http.StatusForbidden, &apiBody{ Success: false, - Message: matchErr.Error(), + Message: "api key is invalid", }) - return - } - if !matched { - c.JSON(http.StatusForbidden, &ApiBody{ + } else { + logger.Error(err, "query api key from db") + c.JSON(http.StatusInternalServerError, &apiBody{ Success: false, - Message: "path doesn't match api key's scope", + Message: err.Error(), }) - return } + return false + } - logger.Info("redirect path: %s to: %s", c.Request.URL.Path, path) - c.Request.URL.Path = path - c.Set(common.USER, &common.User{ - Name: apiKey.Creator.Creator, - Email: apiKey.Creator.CreatorEmail, + if apiKey.ExpiredAt != nil && time.Until(*apiKey.ExpiredAt) < 0 { + c.Abort() + c.JSON(http.StatusForbidden, &apiBody{ + Success: false, + Message: "api key has expired", }) - router.HandleContext(c) + return false + } + matched, matchErr := regexp.MatchString(apiKey.AllowedPath, path) + if matchErr != nil { + logger.Error(err, "regexp match path error") c.Abort() + c.JSON(http.StatusInternalServerError, &apiBody{ + Success: false, + Message: matchErr.Error(), + }) + return false } + if !matched { + c.JSON(http.StatusForbidden, &apiBody{ + Success: false, + Message: "path doesn't match api key's scope", + }) + return false + } + + logger.Info("redirect path: %s to: %s", c.Request.URL.Path, path) + c.Request.URL.Path = path + c.Set(common.USER, &common.User{ + Name: apiKey.Creator.Creator, + Email: apiKey.Creator.CreatorEmail, + }) + return true }