Skip to content

Commit

Permalink
add middleware docs
Browse files Browse the repository at this point in the history
  • Loading branch information
raccoon-mh committed Jul 15, 2024
1 parent 1755e94 commit 4be50c4
Show file tree
Hide file tree
Showing 6 changed files with 444 additions and 27 deletions.
20 changes: 7 additions & 13 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -68,21 +64,19 @@ 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)
webrick (1.8.1)

PLATFORMS
arm64-darwin
x86_64-linux-gnu
x86_64-linux

DEPENDENCIES
jekyll (~> 4.3.3)
Expand Down
158 changes: 158 additions & 0 deletions docs/middleware/Iam-Token-Validator.md
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)
```
129 changes: 129 additions & 0 deletions docs/middleware/buffaloExample.md
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"}))
}
```
Loading

0 comments on commit 4be50c4

Please sign in to comment.