-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1755e94
commit 4be50c4
Showing
6 changed files
with
444 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"})) | ||
} | ||
``` |
Oops, something went wrong.