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/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 diff --git a/pkg/controllers/api-key/role/adjust.go b/pkg/controllers/api-key/role/adjust.go new file mode 100644 index 0000000..803b49c --- /dev/null +++ b/pkg/controllers/api-key/role/adjust.go @@ -0,0 +1,51 @@ +package role + +import ( + "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, _ := c.GetQuery("permission_level") + apiKeyData, _ := c.Get("api-key-model") + + // Apply model to apiKey + apiKeyModel, _ := apiKeyData.(models.APIKey) + + // 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/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", - }) -} 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() + } +} 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"` } 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 +) 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) }, ) } 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}}