From 4be50c45e33d548fc9ad71451b400197d532a377 Mon Sep 17 00:00:00 2001 From: raccoon-pi Date: Mon, 15 Jul 2024 01:40:21 +0000 Subject: [PATCH] add middleware docs --- Gemfile.lock | 20 ++-- docs/middleware/Iam-Token-Validator.md | 158 +++++++++++++++++++++++++ docs/middleware/buffaloExample.md | 129 ++++++++++++++++++++ docs/middleware/echoExample.md | 127 ++++++++++++++++++++ docs/middleware/how-to-middleware.md | 9 ++ swagger/swagger.json | 28 ++--- 6 files changed, 444 insertions(+), 27 deletions(-) create mode 100644 docs/middleware/Iam-Token-Validator.md create mode 100644 docs/middleware/buffaloExample.md create mode 100644 docs/middleware/echoExample.md create mode 100644 docs/middleware/how-to-middleware.md diff --git a/Gemfile.lock b/Gemfile.lock index da34973..5b2cdb5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,12 +11,8 @@ GEM eventmachine (1.2.7) ffi (1.16.3) forwardable-extended (2.6.0) - google-protobuf (4.26.1) - rake (>= 13) - google-protobuf (4.26.1-arm64-darwin) - rake (>= 13) - google-protobuf (4.26.1-x86_64-linux) - rake (>= 13) + google-protobuf (3.25.3-arm64-darwin) + google-protobuf (3.25.3-x86_64-linux) http_parser.rb (0.8.0) i18n (1.14.4) concurrent-ruby (~> 1.0) @@ -68,13 +64,11 @@ GEM rexml (3.2.6) rouge (4.2.1) safe_yaml (1.0.5) - sass-embedded (1.75.0) - google-protobuf (>= 3.25, < 5.0) + sass-embedded (1.69.5) + google-protobuf (~> 3.23) rake (>= 13.0.0) - sass-embedded (1.75.0-arm64-darwin) - google-protobuf (>= 3.25, < 5.0) - sass-embedded (1.75.0-x86_64-linux-gnu) - google-protobuf (>= 3.25, < 5.0) + sass-embedded (1.69.5-arm64-darwin) + google-protobuf (~> 3.23) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) unicode-display_width (2.5.0) @@ -82,7 +76,7 @@ GEM PLATFORMS arm64-darwin - x86_64-linux-gnu + x86_64-linux DEPENDENCIES jekyll (~> 4.3.3) diff --git a/docs/middleware/Iam-Token-Validator.md b/docs/middleware/Iam-Token-Validator.md new file mode 100644 index 0000000..c7f522e --- /dev/null +++ b/docs/middleware/Iam-Token-Validator.md @@ -0,0 +1,158 @@ +--- +layout: default +title: Iam Token Validator +parent: Middleware for your App +order: 0 +--- + +# Iam Token Validator + +## Overview + +`iamtokenvalidator` is a Go package designed to validate and decode JWT tokens using JSON Web Keys (JWK) fetched from a specified MC-IAM-MANAGER endpoint(https://example.com:5000/api/auth/certs). +It provides functionality to verify tokens and extract claims, supporting the RS256, RS384, and RS512 signing methods. + +## Installation + +To install the package, use the following command: + +```bash +go get github.com/m-cmp/mc-iam-manager/iamtokenvalidator +``` + +## Usage + +### Importing the Package + +To use `iamtokenvalidator` in your Go project, import it as follows: + +```go +import "github.com/m-cmp/mc-iam-manager/iamtokenvalidator" +``` + +### Functions + +#### GetPubkeyIamManager + +Fetches the JWK set from the provided MC-IAM-MANAGER URL and prepares the public key for token validation. + +```go +func GetPubkeyIamManager(host string) error +``` + +**Parameters:** + +- `host`: The URL of the MC-IAM-MANAGER service certs endpoint (https://example.com:5000/api/auth/certs). + +**Returns:** + +- `error`: An error if fetching the JWK set fails. + +**Example:** + +```go +err := iamtokenvalidator.GetPubkeyIamManager("https://your-iam-manager-host") +if err != nil { + log.Fatalf("Failed to get public key: %v", err) +} +``` + +#### IsTokenValid + +Validates the given JWT token string using the previously fetched JWK set. + +```go +func IsTokenValid(tokenString string) error +``` + +**Parameters:** + +- `tokenString`: The JWT token string to validate. + +**Returns:** + +- `error`: An error if the token is invalid. + +**Example:** + +```go +err := iamtokenvalidator.IsTokenValid("your-jwt-token") +if err != nil { + fmt.Printf("Token is invalid: %v", err) +} else { + fmt.Println("Token is valid") +} +``` + +#### GetTokenClaimsByIamManagerClaims + +Parses the given JWT token string and extracts claims defined in `IamManagerClaims`. + +```go +func GetTokenClaimsByIamManagerClaims(tokenString string) (*IamManagerClaims, error) +``` + +**Parameters:** + +- `tokenString`: The JWT token string to parse. + +**Returns:** + +- `*IamManagerClaims`: The extracted claims. +- `error`: An error if the token is invalid. + +**Example:** + +```go +claims, err := iamtokenvalidator.GetTokenClaimsByIamManagerClaims("your-jwt-token") +if err != nil { + fmt.Printf("Failed to get claims: %v", err) +} else { + fmt.Printf("UserID: %s, UserName: %s", claims.UserId, claims.UserName) +} +``` + +#### GetTokenClaimsByCustomClaims + +Parses the given JWT token string and extracts custom claims defined by the user. + +```go +func GetTokenClaimsByCustomClaims(tokenString string, myclaims interface{}) (interface{}, error) +``` + +**Parameters:** + +- `tokenString`: The JWT token string to parse. +- `myclaims`: A custom claims struct to extract. + +**Returns:** + +- `interface{}`: The extracted custom claims. +- `error`: An error if the token is invalid. + +**Example:** + +```go +type CustomClaims struct { + jwt.StandardClaims + Email string `json:"email"` +} + +var customClaims CustomClaims +claims, err := iamtokenvalidator.GetTokenClaimsByCustomClaims("your-jwt-token", &customClaims) +if err != nil { + fmt.Printf("Failed to get custom claims: %v", err) +} else { + fmt.Printf("Email: %s", claims.(*CustomClaims).Email) +} +``` + +### Supporting Functions + +#### keyfunction + +A helper function to support the RS256, RS384, and RS512 signing methods. + +```go +func keyfunction(token *jwt.Token) (interface{}, error) +``` \ No newline at end of file diff --git a/docs/middleware/buffaloExample.md b/docs/middleware/buffaloExample.md new file mode 100644 index 0000000..785ede5 --- /dev/null +++ b/docs/middleware/buffaloExample.md @@ -0,0 +1,129 @@ +--- +layout: default +title: Buffalo Example +parent: Middleware for your App +order: 2 +--- +## Middleware + +### 0. `init` func + +Use GetPubkeyIamManager to set up a public key. + +```go +func init() { + r = render.New(render.Options{ + DefaultContentType: "application/json", + }) + IDP_CERT_ENDPOINT := os.Getenv("IDP_CERT_ENDPOINT") + err := iamtokenvalidator.GetPubkeyIamManager(IDP_CERT_ENDPOINT) + if err != nil { + panic(err) + } +} +``` + +### 1. `IsAuthMiddleware` func middleware + +This middleware checks if the provided access token in the Authorization header is valid. + +**Usage:** + +```go +app.Use(middleware.IsAuthMiddleware) +``` + +**IsAuthMiddleware:** +```go +func IsAuthMiddleware(next buffalo.Handler) buffalo.Handler { + return func(c buffalo.Context) error { + accessToken := strings.TrimPrefix(c.Request().Header.Get("Authorization"), "Bearer ") + err := iamtokenvalidator.IsTokenValid(accessToken) + if err != nil { + return c.Render(http.StatusUnauthorized, r.JSON(map[string]string{"error": "Unauthorized"})) + } + return next(c) + } +} +``` + +### 2. `SetRolesMiddleware` func middleware + +This middleware extracts roles from the access token claims and sets them in the context. + +**Usage:** + +```go +app.Use(middleware.SetRolesMiddleware) +``` + +**SetRolesMiddleware:** +```go +func SetRolesMiddleware(next buffalo.Handler) buffalo.Handler { + return func(c buffalo.Context) error { + accessToken := strings.TrimPrefix(c.Request().Header.Get("Authorization"), "Bearer ") + claims, err := iamtokenvalidator.GetTokenClaimsByIamManagerClaims(accessToken) + if err != nil { + return c.Render(http.StatusUnauthorized, r.JSON(map[string]string{"error": "Unauthorized"})) + } + c.Set("roles", claims.RealmAccess.Roles) + return next(c) + } +} +``` + +### 3. `SetGrantedRolesMiddleware` + +This middleware ensures that the user has one of the specified roles. + +**Parameters:** + +- `roles []string`: A list of roles that are granted access. + +**Usage:** + +```go +roles := []string{"admin", "viewer"} +app.Use(middleware.SetGrantedRolesMiddleware(roles)) +``` + +```go +func SetGrantedRolesMiddleware(roles []string) buffalo.MiddlewareFunc { + return func(next buffalo.Handler) buffalo.Handler { + return func(c buffalo.Context) error { + userRoles := c.Value("roles") + userRolesArr := userRoles.([]string) + userRolesArrSet := make(map[string]struct{}, len(userRolesArr)) + for _, v := range userRolesArr { + userRolesArrSet[v] = struct{}{} + } + for _, v := range roles { + if _, found := userRolesArrSet[v]; found { + return next(c) + } + } + return c.Render(http.StatusUnauthorized, r.JSON(map[string]string{"error": "Unauthorized"})) + } + } +} +``` + +## Buffalo FULL Example + +Here is an example of how to use these middlewares in your Buffalo application: + +**app.go:** + +```go +tokenTestPath := app.Group(apiPath + "/tokentest") +tokenTestPath.Use(middleware.IsAuthMiddleware) +tokenTestPath.Use(middleware.SetRolesMiddleware) +tokenTestPath.GET("/", aliveSig) +tokenTestPath.GET("/admin", middleware.SetGrantedRolesMiddleware([]string{"admin"})(aliveSig)) +tokenTestPath.GET("/operator", middleware.SetGrantedRolesMiddleware([]string{"admin", "operator"})(aliveSig)) +tokenTestPath.GET("/viewer", middleware.SetGrantedRolesMiddleware([]string{"admin", "operator", "viewer"})(aliveSig)) + +func aliveSig(c buffalo.Context) error { + return c.Render(http.StatusOK, r.JSON(map[string]string{"ststus": "ok"})) +} +``` \ No newline at end of file diff --git a/docs/middleware/echoExample.md b/docs/middleware/echoExample.md new file mode 100644 index 0000000..d1fe2c6 --- /dev/null +++ b/docs/middleware/echoExample.md @@ -0,0 +1,127 @@ +--- +layout: default +title: Echo Example +parent: Middleware for your App +order: 1 +--- +# Echo JWT Authentication Example + +This project demonstrates a simple Echo server with JWT authentication using the `iamtokenvalidator` library. + +{: .highlight } +https://github.com/raccoon-mh/iamtokenvalidatorpoc + +## Prerequisites + +- Go (version 1.15+) +- Echo framework (version 4) +- `iamtokenvalidator` library + +## Configuration + +Ensure that the MC-IAM-MANAGER's public key endpoint is correctly configured in the `init` function: +```go +func init() { + err := iamtokenvalidator.GetPubkeyIamManager("https://example.com:5000/api/auth/certs") + if err != nil { + panic(err.Error()) + } +} +``` + +## Usage + +1. Run the server: + ```sh + go run main.go + ``` + +2. The server will start on `http://localhost:1323`. + +### Endpoints + +- `GET /`: A public endpoint that returns "Hello, World!". +- `ANY /protected`: A protected endpoint that requires a valid JWT token. + +### Middleware + +- `isTokenValid`: Validates the JWT token. +- `setUserRole`: Extracts and sets user roles from the token. + +### JWT Validation + +The JWT token is validated using the `iamtokenvalidator` library. The token should be included in the `Authorization` header as a Bearer token. + +## Example + +To access the protected endpoint, include a valid JWT token in the request header: + +```sh +curl -H "Authorization: Bearer " http://localhost:1323/protected +``` +# Echo JWT Authentication Example + +This project demonstrates a simple Echo server with JWT authentication using the `iamtokenvalidator` library. + +## Prerequisites + +- Go (version 1.15+) +- Echo framework (version 4) +- `iamtokenvalidator` library + +## Installation + +1. Clone the repository: + ```sh + git clone + cd + ``` + +2. Install dependencies: + ```sh + go get github.com/labstack/echo/v4 + go get github.com/raccoon-mh/iamtokenvalidator + ``` + +## Configuration + +Ensure that the MC-IAM-MANAGER's public key endpoint is correctly configured in the `init` function: +```go +func init() { + err := iamtokenvalidator.GetPubkeyIamManager("https://example.com:5000/api/auth/certs") + if err != nil { + panic(err.Error()) + } +} +``` + +## Usage + +1. Run the server: + ```sh + go run main.go + ``` + +2. The server will start on `http://localhost:1323`. + +### Endpoints + +- `GET /`: A public endpoint that returns "Hello, World!". +- `ANY /protected`: A protected endpoint that requires a valid JWT token. + +### Middleware + +- `isTokenValid`: Validates the JWT token. +- `setUserRole`: Extracts and sets user roles from the token. + +### JWT Validation + +The JWT token is validated using the `iamtokenvalidator` library. The token should be included in the `Authorization` header as a Bearer token. + +## Example + +To access the protected endpoint, include a valid JWT token in the request header: + +```sh +curl -H "Authorization: Bearer " http://localhost:1323/protected +``` \ No newline at end of file diff --git a/docs/middleware/how-to-middleware.md b/docs/middleware/how-to-middleware.md new file mode 100644 index 0000000..458a29c --- /dev/null +++ b/docs/middleware/how-to-middleware.md @@ -0,0 +1,9 @@ +--- +layout: default +title: Middleware for your App +nav_order: 3 +has_children: true +permalink: middleware/intro +--- + +# Middleware for your App \ No newline at end of file diff --git a/swagger/swagger.json b/swagger/swagger.json index 5f2af3e..6955432 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -4,7 +4,7 @@ "contact": {}, "description": "권한 및 접근제어와 워크스페이스 관리 프레임워크\n\n---\n\nThe Multi-Cloud Authorization and Access Control Framework provides platform account/role management, integrated management of cloud account/access control information, and workspace management functionalities. It offers features compatible with security policy determination, establishment, and enforcement for existing multi-cloud services. Additionally, it provides the capability to establish and manage independent security policies within the framework.\n\nIt defines an access control reference model for multi-cloud, distinguishing between user access control and service provider access control. This model adopts a prominent Role-Based Access Control (RBAC) approach and integrates it with existing policy management solutions for application and utilization.", "title": "mc-iam-manager", - "version": "1.0.0" + "version": "0.2.7" }, "host": "localhost:5000", "basePath": "/", @@ -831,11 +831,11 @@ "schema": { "properties": { "description": { - "example": "project5 desc", + "example": "coffeeshop desc", "type": "string" }, "name": { - "example": "project5", + "example": "coffeeshop", "type": "string" } }, @@ -1680,7 +1680,7 @@ } }, "tags": [ - "tool" + "Tool" ], "description": "연결된 TB(mcinframanager)의 NS 리스트를 Project List 로 등록. \n \n기존 등록된 project 와 중복이 발생하면 오류 발생. 새로운 환경에서 첫 회 실행하는 것을 추천.", "operationId": "syncprojectlistwithmcinfra", @@ -1781,11 +1781,11 @@ "schema": { "properties": { "description": { - "example": "workspace3 desc", + "example": "workspace1 desc", "type": "string" }, "name": { - "example": "workspace3", + "example": "workspace1", "type": "string" } }, @@ -2286,17 +2286,17 @@ "properties": { "projectIds": { "example": [ - "e997faba-3421-458e-b269-f8a26a5caa25", - "1e88f4ea-d052-4314-80a4-9ac3f6691feb" + "5655e5c9-caaf-4c49-aa70-88a65e0cdcb1", + "3b4302cd-8359-4ec1-9dd3-4757d9ef9ba0" ], "items": { - "example": "e997faba-3421-458e-b269-f8a26a5caa25", + "example": "5655e5c9-caaf-4c49-aa70-88a65e0cdcb1", "type": "string" }, "type": "array" }, "workspaceId": { - "example": "0df98936-dda3-4df9-8ac4-09a047ec97e0", + "example": "bff56204-1a84-4acd-b4e6-40927cb409be", "type": "string" } }, @@ -2895,7 +2895,7 @@ "schema": { "properties": { "roleId": { - "example": "ce69e6e7-57b8-42a6-a64b-1b60cbf84507", + "example": "7e25efa5-a040-431b-bc5b-bd3a1d3aafdd", "type": "string" }, "userId": { @@ -2903,7 +2903,7 @@ "type": "string" }, "workspaceId": { - "example": "a92a74b6-7f82-42d9-9e74-f3d57b2234b3", + "example": "bff56204-1a84-4acd-b4e6-40927cb409be", "type": "string" } }, @@ -3401,11 +3401,11 @@ "name": "WorkspaceUserRoleMapping" }, { - "name": "tool" + "name": "Tool" }, { "description": "CSP sts token 요청", "name": "[PoC] STS" } ] -} +} \ No newline at end of file