You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ly...@apache.org on 2024/02/21 06:47:45 UTC

(incubator-devlake) 01/01: refactor(middlewares): add `CheckAuthorizationHeader`

This is an automated email from the ASF dual-hosted git repository.

lynwee pushed a commit to branch lw-fix-open-api
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git

commit 92fef05f970ede18e65d1fecbff5e38e5f3447c2
Author: Lynwee Hou <li...@merico.dev>
AuthorDate: Wed Feb 21 14:45:24 2024 +0800

    refactor(middlewares): add `CheckAuthorizationHeader`
---
 backend/server/api/middlewares.go | 154 ++++++++++++++++++++------------------
 1 file changed, 83 insertions(+), 71 deletions(-)

diff --git a/backend/server/api/middlewares.go b/backend/server/api/middlewares.go
index 9e274c259..32ec5e854 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
 }