From bab184d73f4c342267e3842005c8f234414a0ecb Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:55:25 +0200 Subject: [PATCH 1/8] Removed after completion for test --- pkg/controllers/api-key/admin.go | 14 -------------- pkg/controllers/api-key/default.go | 14 -------------- pkg/controllers/api-key/standard.go | 14 -------------- 3 files changed, 42 deletions(-) delete mode 100644 pkg/controllers/api-key/admin.go delete mode 100644 pkg/controllers/api-key/default.go delete mode 100644 pkg/controllers/api-key/standard.go diff --git a/pkg/controllers/api-key/admin.go b/pkg/controllers/api-key/admin.go deleted file mode 100644 index 0002e89..0000000 --- a/pkg/controllers/api-key/admin.go +++ /dev/null @@ -1,14 +0,0 @@ -package controllers - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func Admin(c *gin.Context) { - - c.JSON(http.StatusOK, gin.H{ - "message": "Admin role access", - }) -} diff --git a/pkg/controllers/api-key/default.go b/pkg/controllers/api-key/default.go deleted file mode 100644 index ce7c60a..0000000 --- a/pkg/controllers/api-key/default.go +++ /dev/null @@ -1,14 +0,0 @@ -package controllers - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func Default(c *gin.Context) { - - c.JSON(http.StatusOK, gin.H{ - "message": "Default role access", - }) -} diff --git a/pkg/controllers/api-key/standard.go b/pkg/controllers/api-key/standard.go deleted file mode 100644 index eabc6e6..0000000 --- a/pkg/controllers/api-key/standard.go +++ /dev/null @@ -1,14 +0,0 @@ -package controllers - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func Standard(c *gin.Context) { - - c.JSON(http.StatusOK, gin.H{ - "message": "OK", - }) -} From 9e01c8b45ee5e1269d1984ebb5f7ad66e290fbb3 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:55:47 +0200 Subject: [PATCH 2/8] API key can now only have one role, not multiple. Might be supported later. --- pkg/controllers/api-key/generate.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/controllers/api-key/generate.go b/pkg/controllers/api-key/generate.go index d82d328..b792054 100644 --- a/pkg/controllers/api-key/generate.go +++ b/pkg/controllers/api-key/generate.go @@ -33,15 +33,15 @@ func Generate(c *gin.Context, deps dependencies.Dependencies) { // Create an instance of the APIKey struct apiKeyInstance := &models.APIKey{ - ID: ID, - Usage: 0, - Limit: 1000, - CreatedAt: time.Now(), - ExpiresAt: time.Now().AddDate(0, 2, 1), // Example expires at time, two months and 1 day from now - LastUsed: time.Now(), - Active: true, - SubjectID: uuid, - Roles: []string{"default"}, + ID: ID, + Usage: 0, + Limit: 1000, + CreatedAt: time.Now(), + ExpiresAt: time.Now().AddDate(0, 2, 1), // Example expires at time, two months and 1 day from now + LastUsed: time.Now(), + Active: true, + SubjectID: uuid, + PermissionLevel: 0, } // Store the APIKey in the database From 09cbaa550770e34cb187130c8a8c1816307cbd00 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:56:30 +0200 Subject: [PATCH 3/8] Changed `Role` to `PermissionLevel` --- pkg/models/api_key_models.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/models/api_key_models.go b/pkg/models/api_key_models.go index 6109611..9de81fc 100644 --- a/pkg/models/api_key_models.go +++ b/pkg/models/api_key_models.go @@ -11,13 +11,13 @@ type APIKeyGenerateRequest struct { // APIKey struct that represents the API key table in the database type APIKey struct { - ID string `json:"id"` - SubjectID string `json:"subject_id"` - Roles []string `json:"roles"` - Usage int `json:"usage"` - Limit int `json:"limit"` - CreatedAt time.Time `json:"created_at"` - ExpiresAt time.Time `json:"expires_at"` - LastUsed time.Time `json:"last_used"` - Active bool `json:"active"` + ID string `json:"id"` + SubjectID string `json:"subject_id"` + PermissionLevel int `json:"permission_level"` + Usage int `json:"usage"` + Limit int `json:"limit"` + CreatedAt time.Time `json:"created_at"` + ExpiresAt time.Time `json:"expires_at"` + LastUsed time.Time `json:"last_used"` + Active bool `json:"active"` } From 0ac6d4e7652059084738f687a783d30d64eb174e Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:56:40 +0200 Subject: [PATCH 4/8] New `Role` model --- pkg/models/role.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pkg/models/role.go diff --git a/pkg/models/role.go b/pkg/models/role.go new file mode 100644 index 0000000..8aac2a0 --- /dev/null +++ b/pkg/models/role.go @@ -0,0 +1,11 @@ +// models/role.go + +package models + +type Role int + +const ( + Default Role = iota + Standard + Admin +) From 635559f48748b8961745a813094f0bd5522ead09 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:57:34 +0200 Subject: [PATCH 5/8] Update restclient --- tests/restclients/api_key.rest | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/restclients/api_key.rest b/tests/restclients/api_key.rest index ef8b69c..6fcabf9 100644 --- a/tests/restclients/api_key.rest +++ b/tests/restclients/api_key.rest @@ -15,4 +15,9 @@ Content-Type: application/json ### Check the usage of an API Key # @name usage GET {{baseUrl}}/api-key/usage HTTP/1.1 -X-Api-Key: {{API_KEY}} \ No newline at end of file +X-Api-Key: {{API_KEY}} + + +### Adjust the API key permission level +PATCH {{baseUrl}}/api-key/role/adjust?permission_level=1 HTTP/1.1 +X-Api-Key: {{API_KEY}} From f1367b78e626735982ff42bb21914b4620ed61f3 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:58:29 +0200 Subject: [PATCH 6/8] Add `/role/adjust` to adjust permission level of an API key --- pkg/routes/api_key.go | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/pkg/routes/api_key.go b/pkg/routes/api_key.go index c625a49..ddcf597 100644 --- a/pkg/routes/api_key.go +++ b/pkg/routes/api_key.go @@ -3,10 +3,14 @@ package routes import ( "github.com/gin-gonic/gin" - apiController "github.com/Frier03/KeyAuth-API/pkg/controllers/api-key" + apiKey "github.com/Frier03/KeyAuth-API/pkg/controllers/api-key" + apiKeyRole "github.com/Frier03/KeyAuth-API/pkg/controllers/api-key/role" + "github.com/Frier03/KeyAuth-API/pkg/dependencies" + middleware "github.com/Frier03/KeyAuth-API/pkg/middleware" - apiMiddleware "github.com/Frier03/KeyAuth-API/pkg/middleware/api-key" + middlewareApiKey "github.com/Frier03/KeyAuth-API/pkg/middleware/api-key" + "github.com/Frier03/KeyAuth-API/pkg/models" ) @@ -17,39 +21,23 @@ func SetupAPIKeyRoutes(r *gin.Engine, deps dependencies.Dependencies) { apiKeyRoutes.POST("/generate", middleware.ValidateModel(&models.APIKeyGenerateRequest{}), func(c *gin.Context) { - apiController.Generate(c, deps) - }, - ) - - apiKeyRoutes.GET("/default", - apiMiddleware.ValidateKey(deps.BadgerService), - apiMiddleware.TrackKeyUsage(deps.BadgerService), - func(c *gin.Context) { - apiController.Default(c) - }, - ) - - apiKeyRoutes.GET("/standard", - apiMiddleware.ValidateKey(deps.BadgerService), - apiMiddleware.TrackKeyUsage(deps.BadgerService), - func(c *gin.Context) { - apiController.Standard(c) + apiKey.Generate(c, deps) }, ) - apiKeyRoutes.GET("/admin", - apiMiddleware.ValidateKey(deps.BadgerService), - apiMiddleware.TrackKeyUsage(deps.BadgerService), + apiKeyRoutes.PATCH("/role/adjust", + middlewareApiKey.ValidateKey(deps.BadgerService), + middlewareApiKey.TrackKeyUsage(deps.BadgerService), func(c *gin.Context) { - apiController.Admin(c) + apiKeyRole.Adjust(c, deps.BadgerService) }, ) apiKeyRoutes.GET("/usage", - apiMiddleware.ValidateKey(deps.BadgerService), - apiMiddleware.TrackKeyUsage(deps.BadgerService), + middlewareApiKey.ValidateKey(deps.BadgerService), + middlewareApiKey.TrackKeyUsage(deps.BadgerService), func(c *gin.Context) { - apiController.Usage(c) + apiKey.Usage(c) }, ) } From 7ea7dba1b24091d694783a1efcb5282972e41d50 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 18:59:47 +0200 Subject: [PATCH 7/8] New Feature: `Role Access Control`. See description for more details. Feature includes: - Role access based routes - Adjustable role permissions - supports only 0-2 - Lots of bug fixes --- pkg/controllers/api-key/role/adjust.go | 52 +++++++++++++++++++ pkg/middleware/api-key/role_access_control.go | 33 ++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 pkg/controllers/api-key/role/adjust.go create mode 100644 pkg/middleware/api-key/role_access_control.go diff --git a/pkg/controllers/api-key/role/adjust.go b/pkg/controllers/api-key/role/adjust.go new file mode 100644 index 0000000..a5a49f7 --- /dev/null +++ b/pkg/controllers/api-key/role/adjust.go @@ -0,0 +1,52 @@ +package role + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/Frier03/KeyAuth-API/pkg/models" + "github.com/Frier03/KeyAuth-API/pkg/services" + "github.com/gin-gonic/gin" +) + +func Adjust(c *gin.Context, badgerService *services.BadgerService) { + apiKey := c.GetHeader("X-Api-Key") + adjust, ok := c.GetQuery("permission_level") + apiKeyData, _ := c.Get("api-key-model") + + // Apply model to apiKey + apiKeyModel, _ := apiKeyData.(models.APIKey) + fmt.Println(adjust, ok) + // Validate adjust value + level, err := strconv.Atoi(adjust) + if err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ + "error": "Invalid adjust value", + }) + return + } + + // Check if level is within the allowed range + if level < int(models.Default) || level > int(models.Admin) { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ + "error": "Adjust value is out of range", + }) + return + } + + apiKeyModel.PermissionLevel = level + + // Update the API key in the database + err = badgerService.PutAPIKey([]byte(apiKey), &apiKeyModel) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "error": "Failed to update API key", + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "message": "OK", + }) +} diff --git a/pkg/middleware/api-key/role_access_control.go b/pkg/middleware/api-key/role_access_control.go new file mode 100644 index 0000000..f858ae0 --- /dev/null +++ b/pkg/middleware/api-key/role_access_control.go @@ -0,0 +1,33 @@ +package middleware + +import ( + "net/http" + + "github.com/Frier03/KeyAuth-API/pkg/models" + "github.com/gin-gonic/gin" +) + +func RoleAccessControl(role models.Role) gin.HandlerFunc { + return func(c *gin.Context) { + apiKeyData, _ := c.Get("api-key-model") + + // Apply model to apiKeyData + apiKeyModel, _ := apiKeyData.(models.APIKey) + + // Get api key permission level + apiPermissionLevel := models.Role(apiKeyModel.PermissionLevel) + + // Get requiredRole permission level + requiredPermissionLevel := role + + // Check if APIPermissionLevel has less privileges than the required role + if apiPermissionLevel < requiredPermissionLevel { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{ + "error": "Insufficient privileges to access this resource.", + }) + return + } + + c.Next() + } +} From 4f728640c49ba18c52ac496c9f43e15448f5abc5 Mon Sep 17 00:00:00 2001 From: Sh1tters Date: Sun, 21 May 2023 19:01:14 +0200 Subject: [PATCH 8/8] HOT FIX for `New Feature`. See previous commit for details --- pkg/controllers/api-key/role/adjust.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/controllers/api-key/role/adjust.go b/pkg/controllers/api-key/role/adjust.go index a5a49f7..803b49c 100644 --- a/pkg/controllers/api-key/role/adjust.go +++ b/pkg/controllers/api-key/role/adjust.go @@ -1,7 +1,6 @@ package role import ( - "fmt" "net/http" "strconv" @@ -12,12 +11,12 @@ import ( func Adjust(c *gin.Context, badgerService *services.BadgerService) { apiKey := c.GetHeader("X-Api-Key") - adjust, ok := c.GetQuery("permission_level") + adjust, _ := c.GetQuery("permission_level") apiKeyData, _ := c.Get("api-key-model") // Apply model to apiKey apiKeyModel, _ := apiKeyData.(models.APIKey) - fmt.Println(adjust, ok) + // Validate adjust value level, err := strconv.Atoi(adjust) if err != nil {