bascule

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2024 License: Apache-2.0 Imports: 4 Imported by: 19

README

bascule

A library for authentication and authorization workflows.

Build Status codecov.io Go Report Card Apache V2 License GitHub Release GoDoc

Summary

Bascule provides authentication and authorization workflows, particularly focused on the needs of an HTTP server.

Table of Contents

Code of Conduct

This project and everyone participating in it are governed by the XMiDT Code Of Conduct. By participating, you agree to this Code.

Install

This repo is a library of packages used for authentication and authorization.

Contributing

Refer to CONTRIBUTING.md.

Documentation

Overview

Package bascule provides a configurable way to validate an auth token.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoTokenParsers is returned by TokenParsers.Parse to indicate an empty array.
	// This distinguishes the absence of a token from a source from the absence of a token
	// because of configuration, possibly intentionally.
	ErrNoTokenParsers = errors.New("no token parsers")

	// ErrMissingCredentials indicates that a source object did not have any credentials
	// recognized by that parser.
	ErrMissingCredentials = errors.New("missing credentials")

	// ErrBadCredentials indicates that parseable credentials were present in the source,
	// but that the credentials did not match what the application expects.  For example,
	// a password mismatch should return this error.
	ErrBadCredentials = errors.New("bad credentials")

	// ErrInvalidCredentials indicates that a source did contain recognizable credentials,
	// but those credentials could not be parsed, possibly due to bad formatting.
	ErrInvalidCredentials = errors.New("invalid credentials")
)
View Source
var (
	// ErrUnauthorized is a general error indicating that a token was unauthorized
	// for a particular resource.  Most authorizers and approvers should use this
	// error or wrap this error to indicate failed authorization.
	ErrUnauthorized = errors.New("unauthorized")
)

Functions

func GetAttribute added in v1.0.0

func GetAttribute[T any](a AttributesAccessor, keys ...string) (v T, ok bool)

GetAttribute provides a typesafe way of obtaining attribute values. This function will return false if either the attribute doesn't exist or if the attribute's value of not of type T.

Multiple keys may be passed to this function, in which case the keys will be traversed to find the nested key. If any intervening keys are not of type map[string]any or Attributes, this function will return false.

If no keys are supplied, this function returns the zero value for T and false.

func GetCapabilities added in v1.0.0

func GetCapabilities(v any) (caps []string, ok bool)

GetCapabilities attempts to convert a value v into a slice of capabilities.

This function provide very flexible values to be used as capabilities. This is particularly useful when unmarshalling values, since those values may not be strings or slices.

The following conversions are attempted, in order:

(1) If v implements CapabilitiesAccessor, then Capabilities() is returned.

(2) If v is a []string, it is returned as is.

(3) If v is a scalar string, a slice containing only that string is returned.

(4) If v is a []any, a slice containing each element cast to a string is returned. If any elements are not castable to string, this function considers that to be the same as missing capabilities, i.e. false is returned with an empty slice.

If any conversion was possible, this function returns true even if the capabilities were empty. If no such conversion was possible, this function returns false.

func WithToken added in v1.0.0

func WithToken(ctx context.Context, t Token) context.Context

WithToken constructs a new context with the supplied token.

Types

type Approver added in v1.0.0

type Approver[R any] interface {
	// Approve tests if a given token holds the correct permissions to
	// access a given resource.  If this method needs to access external
	// systems, it should pass the supplied context to honor context
	// cancelation semantics.
	//
	// If this method doesn't support the given token, it should return nil.
	Approve(ctx context.Context, resource R, token Token) error
}

Approver is a strategy for determining if a given token represents adequate permissions to access a resource. Approvers are used as part of bascule's authorization workflow.

type ApproverFunc added in v1.0.0

type ApproverFunc[R any] func(context.Context, R, Token) error

ApproverFunc is a closure type that implements Approver.

func (ApproverFunc[R]) Approve added in v1.0.0

func (af ApproverFunc[R]) Approve(ctx context.Context, resource R, token Token) error

type Approvers added in v1.0.0

type Approvers[R any] []Approver[R]

Approvers is an aggregate Approver.

func (Approvers[R]) Any added in v1.0.0

func (as Approvers[R]) Any() Approver[R]

Any returns an Approver which is a logical OR: each approver is executed in order, and any approver that allows access results in an immediate return. The returned Approver's state is distinct and is unaffected by subsequent changes to the Approvers set.

Any error returns from the returned Approver will be an aggregate of all the errors returned from each element.

func (Approvers[R]) Append added in v1.0.0

func (as Approvers[R]) Append(more ...Approver[R]) Approvers[R]

Append tacks on one or more approvers to this collection. The possibly new Approvers instance is returned. The semantics of this method are the same as the built-in append.

func (Approvers[R]) AppendFunc added in v1.0.0

func (as Approvers[R]) AppendFunc(more ...ApproverFunc[R]) Approvers[R]

AppendFunc is a closure variant of Append that makes working with approvers that are functions a little easier.

func (Approvers[R]) Approve added in v1.0.0

func (as Approvers[R]) Approve(ctx context.Context, resource R, token Token) error

Approve requires all approvers in this sequence to allow access. This method supplies a logical AND.

Because authorization can be arbitrarily expensive, execution halts at the first failed authorization attempt.

type AttributesAccessor added in v1.0.0

type AttributesAccessor interface {
	// Get returns the value of an attribute, if it exists.
	Get(key string) (any, bool)
}

AttributesAccessor is an optional interface that a Token may implement that provides access to arbitrary key/value pairs.

type AuthenticateEvent added in v1.0.0

type AuthenticateEvent[S any] struct {
	// Source is the object that was parsed to produce the token.
	// This field is always set.
	Source S

	// Token is the token that resulted from parsing the source.  This field
	// will only be set if parsing was successful.
	Token Token

	// Err is the error that resulted from authentication.  This field will be
	// nil for a successful authentication.
	Err error
}

AuthenticateEvent represents the result of bascule's authenticate workflow.

type Authenticator added in v1.0.0

type Authenticator[S any] struct {
	// contains filtered or unexported fields
}

Authenticator provides bascule's authentication workflow. This type handles parsing tokens, validating them, and dispatching authentication events to listeners.

func NewAuthenticator added in v1.0.0

func NewAuthenticator[S any](opts ...AuthenticatorOption[S]) (a *Authenticator[S], err error)

NewAuthenticator constructs an Authenticator workflow using the supplied options.

At least (1) token parser must be supplied in the options, or this function returns ErrNoTokenParsers.

func (*Authenticator[S]) Authenticate added in v1.0.0

func (a *Authenticator[S]) Authenticate(ctx context.Context, source S) (token Token, err error)

Authenticate implements bascule's authentication pipeline. The following steps are performed:

(1) The token is extracted from the source using the configured parser(s) (2) The token is validated using any configured validator(s) (3) Appropriate events are dispatched to listeners after either of steps (1) or (2)

type AuthenticatorOption added in v1.0.0

type AuthenticatorOption[S any] interface {
	// contains filtered or unexported methods
}

AuthenticatorOption is a configurable option for an Authenticator.

func WithAuthenticateListenerFuncs added in v1.0.0

func WithAuthenticateListenerFuncs[S any](more ...ListenerFunc[AuthenticateEvent[S]]) AuthenticatorOption[S]

WithAuthenticateListenerFuncs is a closure variant of WithAuthenticateListeners.

func WithAuthenticateListeners added in v1.0.0

func WithAuthenticateListeners[S any](more ...Listener[AuthenticateEvent[S]]) AuthenticatorOption[S]

WithAuthenticateListeners adds listeners to the Authenticator being built. Multiple calls for this option are cumulative.

func WithTokenParsers added in v1.0.0

func WithTokenParsers[S any](more ...TokenParser[S]) AuthenticatorOption[S]

WithTokenParsers adds token parsers to the Authenticator being built. Multiple calls for this option are cumulative.

func WithValidators added in v1.0.0

func WithValidators[S any](more ...Validator[S]) AuthenticatorOption[S]

WithValidators adds validators to the Authenticator being built. Multiple calls for this option are cumulative.

type AuthorizeEvent added in v1.0.0

type AuthorizeEvent[R any] struct {
	// Resource is the thing the token wants to access.  This
	// field is always set.
	Resource R

	// Token is the token that either was or was not authorized.
	// This field is always set.
	Token Token

	// Err is the error that resulted from authorization.  This field will be
	// nil for a successful authorization..
	Err error
}

AuthorizeEvent represents the result of bascule's authorize workflow.

type Authorizer added in v1.0.0

type Authorizer[R any] struct {
	// contains filtered or unexported fields
}

Authorizer represents the full bascule authorizer workflow. An authenticated token is required as the starting point for authorization.

func NewAuthorizer added in v1.0.0

func NewAuthorizer[R any](opts ...AuthorizerOption[R]) (a *Authorizer[R], err error)

NewAuthorizer constructs an Authorizer workflow using the supplied options.

If no options are supplied, the returned Authorizer will authorize all tokens to access any resources.

func (*Authorizer[R]) Authorize added in v1.0.0

func (a *Authorizer[R]) Authorize(ctx context.Context, resource R, token Token) (err error)

Authorize implements the bascule authorization workflow for a particular type of resource. The following steps are performed:

(1) Each approver is invoked, and all approvers must approve access (2) An AuthorizeEvent is dispatched to any listeners with the result

Any error that occurred during authorization is returned.

type AuthorizerOption added in v1.0.0

type AuthorizerOption[S any] interface {
	// contains filtered or unexported methods
}

AuthorizerOption is a configurable option for an Authorizer.

func WithApproverFuncs added in v1.0.0

func WithApproverFuncs[R any](more ...ApproverFunc[R]) AuthorizerOption[R]

WithApproverFuncs is a closure variant of WithApprovers that eases the syntactical pain of dealing with approvers that are functions.

func WithApprovers added in v1.0.0

func WithApprovers[R any](more ...Approver[R]) AuthorizerOption[R]

WithApprovers adds approvers to the Authorizer being built. Multiple calls for this option are cumulative.

func WithAuthorizeListenerFuncs added in v1.0.0

func WithAuthorizeListenerFuncs[R any](more ...ListenerFunc[AuthorizeEvent[R]]) AuthorizerOption[R]

WithAuthorizeListenerFuncs is a closure variant of WithAuthorizeListeners.

func WithAuthorizeListeners added in v1.0.0

func WithAuthorizeListeners[R any](more ...Listener[AuthorizeEvent[R]]) AuthorizerOption[R]

WithAuthorizeListeners adds listeners to the Authorizer being built. Multiple calls for this option are cumulative.

type CapabilitiesAccessor added in v1.0.0

type CapabilitiesAccessor interface {
	// Capabilities returns the set of capabilities associated with this token.
	// The exact format and application of capabilities is left up to specific
	// implementations.
	Capabilities() []string
}

CapabilitiesAccessor is an interface that any type may choose to implement in order to provide access to any capabilities associated with the token. Capabilities do not make sense for all tokens, e.g. simple basic auth tokens.

type Contexter added in v1.0.0

type Contexter interface {
	Context() context.Context
}

Contexter is anything that logically holds a context. For example, *http.Request implements this interface.

type Listener added in v1.0.0

type Listener[E any] interface {
	// OnEvent receives a bascule event.  This method must not block or panic.
	OnEvent(E)
}

Listener is a sink for bascule events.

type ListenerFunc added in v1.0.0

type ListenerFunc[E any] func(E)

ListenerFunc is a closure that can act as a Listener.

func (ListenerFunc[E]) OnEvent added in v1.0.0

func (lf ListenerFunc[E]) OnEvent(e E)

OnEvent satisfies the Listener interface.

type Listeners added in v1.0.0

type Listeners[E any] []Listener[E]

Listeners is an aggregate Listener.

func (Listeners[E]) Append added in v1.0.0

func (ls Listeners[E]) Append(more ...Listener[E]) Listeners[E]

Append adds more listeners to this aggregate. The (possibly new) aggregate Listeners is returned. This method has the same semantics as the built-in append.

func (Listeners[E]) AppendFunc added in v1.0.0

func (ls Listeners[E]) AppendFunc(more ...ListenerFunc[E]) Listeners[E]

AppendFunc is a more convenient version of Append when using closures as listeners.

func (Listeners[E]) OnEvent added in v1.0.0

func (ls Listeners[E]) OnEvent(e E)

OnEvent dispatches the given event to all listeners contained by this aggregate.

type StubToken added in v1.0.0

type StubToken string

StubToken is a dummy token useful to configure a stubbed out workflow. Useful in testing and in development.

func (StubToken) Principal added in v1.0.0

func (st StubToken) Principal() string

Principal just returns this token's string value.

type StubTokenParser added in v1.0.0

type StubTokenParser[S any] struct {
	// Token is the constant token to return.  This could be a StubToken,
	// or any desired type.
	Token Token
}

StubTokenParser is a parser that returns the same Token for all calls. Useful in testing and in development.

func (StubTokenParser[S]) Parse added in v1.0.0

func (stp StubTokenParser[S]) Parse(context.Context, S) (Token, error)

Parse always returns the configured Token and a nil error.

type Token

type Token interface {
	// Principal is the security subject of this token, e.g. the user name or other
	// user identifier.
	Principal() string
}

Token is a runtime representation of credentials. This interface will be further customized by infrastructure.

func Get added in v1.0.0

func Get(ctx context.Context) (t Token, found bool)

Get retrieves a Token from a context. If not token is in the context, this function returns false.

func GetFrom added in v1.0.0

func GetFrom(src Contexter) (Token, bool)

GetFrom uses the context held by src to obtain a Token. As with GetToken, if no token is found this function returns false.

func Validate added in v1.0.0

func Validate[S any](ctx context.Context, source S, original Token, v ...Validator[S]) (validated Token, err error)

Validate applies several validators to the given token. Although each individual validator may return a nil Token to indicate that there is no change in the token, this function will always return a non-nil Token.

This function returns the validated Token and a nil error to indicate success. If any validator fails, this function halts further validation and returns the error.

type TokenParser added in v1.0.0

type TokenParser[S any] interface {
	// Parse extracts a Token from a source object, e.g. an HTTP request.
	//
	// If a particular source instance doesn't have the credentials expected by this
	// parser, this method must return an error with MissingCredentials in the returned
	// error's chain.
	//
	// If a source has credentials that failed to parse, this method must return an error
	// with InvalidCredentials in its error chain.
	//
	// If this method returns a nil Token, it must return a non-nil error.  Returning an
	// error with a non-nil Token is allowed but not required.
	Parse(ctx context.Context, source S) (Token, error)
}

TokenParser produces tokens from a source. The original source S of the credentials are made available to the parser.

func AsTokenParser added in v1.0.0

func AsTokenParser[S any, F TokenParserFunc[S]](f F) TokenParser[S]

AsTokenParser accepts a closure and turns it into a TokenParser instance. Custom types that are convertible to a TokenParserFunc are also supported.

type TokenParserFunc added in v1.0.0

type TokenParserFunc[S any] interface {
	~func(source S) (Token, error) |
		~func(ctx context.Context, source S) (Token, error)
}

TokenParserFunc describes the closure signatures that are allowed as TokenParser instances.

type TokenParsers added in v1.0.0

type TokenParsers[S any] []TokenParser[S]

TokenParsers is an aggregate, ordered list of TokenParser implementations for a given type of source.

func (TokenParsers[S]) Append added in v1.0.0

func (tps TokenParsers[S]) Append(more ...TokenParser[S]) TokenParsers[S]

Append adds one or more parsers to this aggregate TokenParsers. The semantics of this method are the same as the built-in append.

func (TokenParsers[S]) Len added in v1.0.0

func (tps TokenParsers[S]) Len() int

Len returns the number of parsers in this aggregate.

func (TokenParsers[S]) Parse added in v1.0.0

func (tps TokenParsers[S]) Parse(ctx context.Context, source S) (t Token, err error)

Parse executes each TokenParser in turn.

If this TokenParsers is empty, this method returns ErrNoTokenParsers.

If a parser returns MissingCredentials, it is skipped. If all parsers return MissingCredentials, the last error is returned.

If a parser returns any other error, parsing is halted early and that error is returned.

Otherwise, the token returned from the first successful parse is returned by this aggregate method.

type Validator

type Validator[S any] interface {
	// Validate validates a token.  If this validator needs to interact
	// with external systems, the supplied context can be passed to honor
	// cancelation semantics.  Additionally, the source object from which the
	// token was taken is made available.
	//
	// This method may be passed a token that it doesn't support, e.g. a Basic
	// validator can be passed a JWT token.  In that case, this method should
	// simply return a nil error.
	//
	// If this method returns a nil token, then the supplied token should be used
	// as is.  If this method returns a non-nil token, that new new token should be
	// used instead.  This allows a validator to augment a token with additional
	// data, possibly from an external system or database.
	Validate(ctx context.Context, source S, t Token) (Token, error)
}

Validator represents a general strategy for validating tokens. Token validation typically happens during authentication.

func AsValidator added in v1.0.0

func AsValidator[S any, F ValidatorFunc[S]](f F) Validator[S]

AsValidator takes a ValidatorFunc closure and returns a Validator instance that executes that closure. This function can also convert custom types which can be converted to any of the closure signatures.

type ValidatorFunc

type ValidatorFunc[S any] interface {
	~func(Token) error |
		~func(S, Token) error |
		~func(Token) (Token, error) |
		~func(S, Token) (Token, error) |
		~func(context.Context, Token) error |
		~func(context.Context, S, Token) error |
		~func(context.Context, Token) (Token, error) |
		~func(context.Context, S, Token) (Token, error)
}

ValidatorFunc defines the closure signatures that are allowed as Validator instances.

type Validators

type Validators[S any] []Validator[S]

Validators is an aggregate Validator that returns validity if and only if all of its contained validators return validity.

func (Validators[S]) Append added in v1.0.0

func (vs Validators[S]) Append(more ...Validator[S]) Validators[S]

Append tacks on more validators to this aggregate, returning the possibly new instance. The semantics of this method are the same as the built-in append.

func (Validators[S]) Validate added in v1.0.0

func (vs Validators[S]) Validate(ctx context.Context, source S, t Token) (Token, error)

Validate executes each contained validator in order, returning validity only if all validators pass. Any validation failure prevents subsequent validators from running.

Directories

Path Synopsis
Package basculehttp provides a token-based security workflow for HTTP handlers using bascule.
Package basculehttp provides a token-based security workflow for HTTP handlers using bascule.
basculecaps
Package basculecaps provide a standard format for token capabilities in the context of HTTP-based workflow.
Package basculecaps provide a standard format for token capabilities in the context of HTTP-based workflow.
Package basculejwt provides JWT support for the bascule workflow.
Package basculejwt provides JWT support for the bascule workflow.
examples
acquirer Module
basculehttp Module

Jump to

Keyboard shortcuts

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