auth

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2018 License: Apache-2.0 Imports: 15 Imported by: 0

README

Authorization Interceptor

This package provides a server-side gRPC interceptor that interfaces with Themis, a policy engine that is developed and maintained by Infoblox.

It is designed to give developers fine-grained control over who (e.g. specific users) or what (e.g. neighboring services) can access their gRPC service's business logic.

Background

If you're unfamiliar with gRPC interceptors and their intended use, please consider reading this brief explanation.

The authorization interceptor determines whether or not an API consumer can access an endpoint. If the API consumer does not have appropriate permissions to access an endpoint (e.g. the consumer does not provide an API key), the interceptor will stop their request from advancing to the application.

Here's the authorization interceptor as if it were a living, breathing human: "Hey Themis, is the sender of request XYZ allowed to access endpoint ABC in my service? They're not? Okay, I'll deny the request!"

Using Interceptors

If you already use gRPC with Go, your project probably has a bit of code like this.

// define your grpc server
myServer := grpc.NewServer()

This is how you would decorate your server with interceptors.

// define your grpc server
myServer := grpc.NewServer(
  grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
    // define your list of grpc interceptors
  )),
)

Again, the official gRPC GitHub repository has documentation to explain this process.

Using the Default AuthZ Interceptor

The auth package offers a default authorization interceptor.

themisAddress := "default.themis:5555" 
applicationID := "shopping-mall"
// define your grpc server
myServer := grpc.NewServer(
  grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
    // include the authorization interceptor
    auth.UnaryServerInterceptor(themisAddress, applicationID),
  )),
)

In the example above, the themisAddress variable corresponds to the host and port of Themis.

The applicationID maps the interceptor to a specific application. In a microservices environment, you might have multiple services that, as a unit, compose an application (e.g. a petstore service, a coffee shop service, and a cellphone kiosk service might belong to a shopping mall application). Each service has its own access control logic, but together they form an application.

When you define your gRPC server, start by using the auth package's UnaryServerInterceptor interceptor. The applicationID associates the interceptor with a specific set of policies.

Customize the AuthZ Interceptor

The auth package provides a set of options that offer fine-grained control of the authorization interceptor. Options affect how the authorization middleware interfaces with Themis. For example, you might need to permit or deny request using the fields in a JWT. Well, there's an option to handle this use case!

Interceptor options are helpful because they abstract Themis' API behind a set of well-documented functions.

Applying Options

The example below shows how to would configure your application's authorization logic using options.

import (
	"github.com/grpc-ecosystem/go-grpc-middleware/auth"
	"google.golang.org/grpc"
)
...
// build a new authorizer and specify some options. the authorizer will
// create authorization middleware based on options that get provided
// by the user.
authorizer := Authorizer{
  PDPAddress: "themis.default:5555",
  Bldr: NewBuilder(
    // this is where options are provided by the user
    WithRequest("shopping-mall"),
    WithJWT("Bearer", nil),
  ),
  Hdlr: NewHandler(),
}

// create an authorization function. the authorization function is responsible
// for checking with themis to determine if a request should be permitted
// or denied.
authFunc := authorizer.AuthFunc()
myServer := grpc.NewServer(
  grpc.UnaryInterceptor(grpc_middleware.ChainStreamServer(
    // include the authorization interceptor
    grpc_auth.UnaryServerInterceptor(authFunc)
  )),
)

This readme has a description of each option below, but you can also host a local GoDoc server.

godoc -http :6060
open http://localhost:6060/pkg/github.com/infobloxopen/atlas-app-toolkit/auth
Interceptor Options

Here are the authorization options that are currently provided by the toolkit.

WithJWT

This option enables token-based authorization with JWT. When requests reach the authorization interceptor, the interceptor will include the full JWT payload in a given authorization request to Themis.

{
   "name":"john doe",
   "occupation":"astronaut",
   "group":"admin"
}

Each of the fields in the above example would be sent to Themis as part of the authorization request.

WithRequest

This option includes information about the gRPC request as part of the request to Themis. The interceptor will add the following attributes.

  • The gRPC service name (e.g. /PetStore)
  • The gRPC function name (e.g. ListAllPets)
WithTLS

This option uses metadata from a TLS-authenticated client. When included, the following options are included in a request to Themis.

  • Whether or not the request-sender is TLS authenticated
  • The TLS certificate issuer (if authenticated)
  • The TLS common subject name (if authenticated)
WithCallback

This option allows for application-specific authorization behavior. The toolkit offers a robust set of authorization options, but you might need specialized, non-generalizable authorization logic to satisfy your access control requirements.

To use the WithCallback option, you must be somewhat familiar with the API for Themis, which is defined here.

myCallBackFunction := func(ctx context.Context) ([]*pdp.Attribute, error){
  myAttributes := []*pdp.Attribute{
    {Id: "city", Type: "string", Value: "vancouver"},
    {Id: "country", Type: "string", Value: "canada"},
  }
  return myAttributes, nil
}

Each request to the Themis will include an two additional attributes: the city and country (although both are hardcoded). The point is, you can modify the authorization logic without making changes to the toolkit code.

Documentation

Index

Constants

View Source
const (

	// MultiTenancyField the field name for a specific tenant
	MultiTenancyField = "AccountID"

	// DefaultTokenType is the name of the authorization token (e.g. "Bearer"
	// or "token")
	DefaultTokenType = "Bearer"
)

Variables

View Source
var (
	// ErrInternal indicates a server-side error occured during authorization
	ErrInternal = grpc.Errorf(codes.Internal, "unable to process request")
	// ErrUnauthorized indicates that a given request has been denied
	ErrUnauthorized = grpc.Errorf(codes.PermissionDenied, "unauthorized")
)

Functions

func GetAccountID

func GetAccountID(ctx context.Context, keyfunc jwt.Keyfunc) (string, error)

GetAccountID gets the JWT from a context and returns the AccountID field

func GetJWTField

func GetJWTField(ctx context.Context, tokenField string, keyfunc jwt.Keyfunc) (string, error)

GetJWTField gets the JWT from a context and returns the specified field using the DefaultTokenName

func GetJWTFieldWithTokenType added in v0.9.0

func GetJWTFieldWithTokenType(ctx context.Context, tokenType, tokenField string, keyfunc jwt.Keyfunc) (string, error)

GetJWTFieldWithTokenType gets the JWT from a context and returns the specified field. The user must provide a token type, which prefixes the token itself (e.g. "Bearer" or "token")

func UnaryServerInterceptor

func UnaryServerInterceptor(authzAddress, appID string) grpc.UnaryServerInterceptor

func WithCallback

func WithCallback(attr attributer) option

WithCallback allows developers to pass their own attributer to the authorization service. It gives them the flexibility to add customization to the auth process without needing to write a Builder from scratch.

func WithJWT

func WithJWT(tokenType string, keyfunc jwt.Keyfunc) option

WithJWT allows for token-based authorization using JWT. When WithJWT has been added as a build parameter, every field in the token payload will be included in the request to Themis

func WithRequest

func WithRequest(appID string) option

WithRequest takes metadata from the incoming request and passes it to Themis in the authorization request. Specifically, this includes the gRPC service name (e.g. AddressBook) and the corresponding function that is called by the client (e.g. ListPersons)

func WithTLS added in v0.5.0

func WithTLS() option

WithTLS gathers metadata from a TLS-authenticated client

Types

type Authorizer

type Authorizer struct {
	PDPAddress string
	Bldr       Builder
	Hdlr       Handler
}

Authorizer glues together a Builder and a Handler. It is responsible for sending requests and receiving responses to/from Themis

func (Authorizer) AuthFunc

func (a Authorizer) AuthFunc() grpc_auth.AuthFunc

AuthFunc builds the "AuthFunc" using the pep client that comes with Themis

type Builder

type Builder interface {
	// contains filtered or unexported methods
}

Builder is responsible for creating requests to Themis. The response from Themis will determine if a request is authorized or unauthorized

func NewBuilder

func NewBuilder(opts ...option) Builder

NewBuilder returns an instance of the default Builder that includes all of of the user-provided options

type Handler

type Handler interface {
	// contains filtered or unexported methods
}

Handler decides whether or not a request from Themis is authorized

func NewHandler

func NewHandler() Handler

NewHandler returns an instance of the default handler

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL