Skip to content

Commit

Permalink
readme updated
Browse files Browse the repository at this point in the history
  • Loading branch information
pperalta committed Feb 25, 2019
1 parent ba29ab8 commit 3830214
Showing 1 changed file with 89 additions and 56 deletions.
145 changes: 89 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,114 @@
# go-jwt-tools

Golang authorization middleware for JWT tokens. JWT tools (auth0 or other)
Golang authorization http middleware for Authorization headers and a

There are two important features on this package:
- `authorization.go` contains a middleware that processes a token and checks its validity (authorizes).
- `permissions.go` handles the "PermissionsTable" struct which contains the information of the JWT token conveniently adapted, and a set of functions to use it.
These are the important features on this package:

## MiddleWare
### How to use
- `User`: The object representation of who is doing the request and its permissions.

```go
type User struct {
AuthorizationValue string
IsDummy bool
Permissions Permissions
}

type Permissions interface {
// CheckPermission returns the given Permissions for a given product and object. Returns the special Permissions applied on that object if any, and a boolean indicating if the user has the requested Permission. NOTE: Special Permissions returned can be filtered by the specials argument).
CheckPermission(product string, object string, permission Permission, specials ...string) ([]string, bool)
// ValidGroups returns all the groups and its Permissions that have any Permission for the given product and object.
ValidGroups(product string, object string, permission Permission) map[string]struct{}
// Returns all groups of a given type
GetGroups(groupType string) []string
// GetAllGroups returns the group hierarchy
GetAllGroups() map[string]struct{}
// GetGroupsByTypes returns a map indexed by group types, containing the list of groups of that type
GetGroupsByTypes() map[string][]string
// GetParents returns all the parent groups of a given group.
GetParents(group string) map[string]interface{}
}

We just need to add a call to the function **`Authorize`** on all the calls that must be authorized (in this case, we use a **`Route`** struct that contains the `HandlerFunc` and a `bool` indicating if that `Route` must be authorized). `Authorize` expects the handler function to wrap and a configuration object of type **`Config`** (defined on `authorization.go` file).
```

**IMPORTANT**: The middleware stores the `PermissionTable` item on the [context](https://golang.org/pkg/context/), under the key defined on the `ContextKey` constant.
- `Parser`: Who knows how to transform an authorization header into an User, this is what the different authorization techniques should implement.

### Example of use
```go
type Parser interface {
Parse(authHeader string) (*User, error)
}
```
- `Middleware`: A middleware is a wrap to a **http.Handler**

```golang
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
```go
func(h http.Handler) http.Handler
```

// Prepare Authorization configuration
c := authorization.Config{
PublicKeyStr: "myKey",
AdminGroup: "admin",
IgnoreExpiration: false,
TokenDummy: "TokenDummy",
}
This concrete middleware requires a **Parser** that will be used to transform the Authorization header from **http.Request** into an **User**, and then put in the request context. To retrieve the **User** from the context, use the function:

for _, route := range routes {
var handler http.Handler
```go
func UserFromContext(ctx context.Context) (*User, bool)
```

// Add Authorization or not
if route.Authorization {
handler = authorization.Authorize(route.HandlerFunc(), c)

} else {
handler = route.HandlerFunc()
}
### Implementations

handler = handlers.CompressHandler(util.CompressGzip(handler, route.GzipMandatory))
Implementation details can be found in these subpackages:

router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}
#### jwt

return router
In this implementation, the Authorization headers must be **Bearers** (auth0 or other).

The jwt parser can be instantiated from:

```go
type ParserConfig struct {
PublicKey string
AdminGroup string
DummyToken string
IgnoreExpiration bool
MemberIDClaim []string
GroupsClaim []string
}
```

After this, out `PermissionTable` will be stored on the `ContextKey` key of the context:
#### cache

```golang
permissions := ctx.Value(authorization.ContextKey).(*authorization.PermissionTable)
```
Has a Parser implementation that uses a [lru cache](https://github.com/travelgateX/go-cache) where the key is the Authorization header and the value is the User, it basically caches the Parsing process. Recommended when the parsing process is heavy.

### How to use

## Permissions
First instance the desired Parser implementation, for instance, if we want our endpoint to understand of jwt bearers:

```go
jwtParserConfig := jwt.ParserConfig{
AdminGroup: "admin",
PublicKey: "myKey",
DummyToken: "dummyToken",
IgnoreExpiration: false,
GroupsClaim: []string{"https://xtg.com/iam", "https://travelgatex.com/iam"},
MemberIDClaim: []string{"https://xtg.com/member_id", "https://travelgatex.com/member_id"},
}

```golang
jwtParser := jwt.NewParser(jwtParserConfig)
```

type Permissions interface {
// CheckPermission returns the given permissions for a given product and object. Returns the special permissions applied on that object if any, and a boolean indicating if the user has the requested permission. NOTE: Special permissions returned can be filtered by the specials argument).
CheckPermission(product string, object string, per string, specials ...string) ([]string, bool)
// ValidGroups returns all the groups and its permissions that have any permission for the given product and object.
ValidGroups(product string, object string, per string) map[string]bool
// Returns all groups of a given type
GetGroups(groupType string) []string
// GetAllGroups returns the group hierarchy
GetAllGroups() map[string]struct{}
// GetGroupsByTypes returns a map indexed by group types, containing the list of groups of that type
GetGroupsByTypes() map[string][]string
// GetParents returns all the parent groups of a given group.
GetParents(group string) map[string]interface{}
}
Then, if we want a cache layer to cache the jwt parsing process we can wrap the **jwtParser** with a cache parser:

```go
size := 100
ttl := time.Minute
c, _ := cache.New(size, ttl)
cacheParser := authcache.NewParser(jwtParser, c)
```

Now that we have built the desired parser **cacheParser**, instance the middleware and use it to wrap your service handler:

```go
middleware := authorization.Middleware(cacheParser)

var serviceHandler http.Handler // omitted code
serviceHandler = middleware(serviceHandler)

http.Handle("/foo", serviceHandler)
```

Remember that in order to obtain the **User**, you must retrieve it from the context.Context using the func **UserFromContext**

0 comments on commit 3830214

Please sign in to comment.