basculehttp

package
v1.0.0 Latest Latest
Warning

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

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

Documentation

Overview

Package basculehttp provides a token-based security workflow for HTTP handlers using bascule.

Index

Examples

Constants

View Source
const (
	// DefaultAuthorizationHeader is the default HTTP header used for authorization
	// tokens in an HTTP request.
	DefaultAuthorizationHeader = "Authorization"
)
View Source
const (
	// WWWAuthenticateHeader is the HTTP header used for StatusUnauthorized challenges
	// when encountered by the Middleware.
	//
	// This value is used by default when no header is supplied to Challenges.WriteHeader.
	WWWAuthenticateHeader = "WWW-Authenticate"
)

Variables

View Source
var (
	// ErrInvalidChallengeScheme indicates that a scheme was improperly formatted.  Usually,
	// this methods the scheme was either blank or contained whitespace.
	ErrInvalidChallengeScheme = errors.New("Invalid challenge auth scheme")

	// ErrInvalidChallengeParameter indicates that an attempt was made to an a challenge
	// auth parameter that wasn't validly formatted.  Usually, this means that the
	// name contained whitespace.
	ErrInvalidChallengeParameter = errors.New("Invalid challenge auth parameter")

	// ErrReservedChallengeParameter indicates that an attempt was made to add a
	// challenge auth parameter that was reserved by the RFC.
	ErrReservedChallengeParameter = errors.New("Reserved challenge auth parameter")
)
View Source
var (
	// ErrInvalidAuthorization indicates an authorization header value did not
	// correspond to the standard.
	ErrInvalidAuthorization = errors.New("invalid authorization")
)
View Source
var (
	// ErrNoAuthenticator is returned by NewMiddleware to indicate that an Authorizer
	// was configured without an Authenticator.
	ErrNoAuthenticator = errors.New("An Authenticator is required if an Authorizer is configured")
)

Functions

func BasicAuth added in v1.0.0

func BasicAuth(userName, password string) string

BasicAuth produces the basic authorization string described by RFC 2617.

func DefaultErrorMarshaler added in v1.0.0

func DefaultErrorMarshaler(_ *http.Request, err error) (contentType string, content []byte, marshalErr error)

DefaultErrorMarshaler returns a plaintext representation of the error.

func DefaultErrorStatusCoder added in v1.0.0

func DefaultErrorStatusCoder(_ *http.Request, err error) int

DefaultErrorStatusCoder is the strategy used when no ErrorStatusCoder is supplied.

If err has bascule.ErrMissingCredentials in its chain, this function returns http.StatusUnauthorized.

If err has bascule.ErrInvalidCredentials in its chain, this function returns http.StatusBadRequest.

Failing the previous two checks, if the error provides a StatusCode() method, the return value from that method is used.

Otherwise, this method returns 0 to indicate that it doesn't know how to produce a status code from the error.

func NewAuthenticator added in v1.0.0

func NewAuthenticator(opts ...bascule.AuthenticatorOption[*http.Request]) (*bascule.Authenticator[*http.Request], error)

NewAuthenticator is a convenient wrapper around bascule.NewAuthenticator. This function eases the syntactical pain of generics when creating Middleware.

func NewAuthorizer added in v1.0.0

func NewAuthorizer(opts ...bascule.AuthorizerOption[*http.Request]) (*bascule.Authorizer[*http.Request], error)

NewAuthorizer is a convenient wrapper around bascule.NewAuthorizer. This function eases the syntactical pain of generics when creating Middleware.

func UseStatusCode added in v1.0.0

func UseStatusCode(statusCode int, err error) error

UseStatusCode associates an HTTP status code with the given error. This function will override any existing status code associated with err.

Types

type AuthorizationParser added in v1.0.0

type AuthorizationParser struct {
	// contains filtered or unexported fields
}

AuthorizationParsers is a bascule.TokenParser that handles the Authorization header.

By default, this parser will use the standard Authorization header, which can be changed via with WithAuthorizationHeader option.

func NewAuthorizationParser added in v1.0.0

func NewAuthorizationParser(opts ...AuthorizationParserOption) (*AuthorizationParser, error)

NewAuthorizationParser constructs an Authorization parser from a set of configuration options.

func (*AuthorizationParser) Parse added in v1.0.0

func (ap *AuthorizationParser) Parse(ctx context.Context, source *http.Request) (bascule.Token, error)

Parse extracts the appropriate header, Authorization by default, and parses the scheme and value. Schemes are case-insensitive, e.g. BASIC and Basic are the same scheme.

If no authorization header is found in the request, this method returns ErrMissingCredentials.

If a token parser is registered for the given scheme, that token parser is invoked. Otherwise, UnsupportedSchemeError is returned, indicating the scheme in question.

type AuthorizationParserOption added in v1.0.0

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

AuthorizationParserOption is a configurable option for an AuthorizationParser.

func WithAuthorizationHeader added in v1.0.0

func WithAuthorizationHeader(header string) AuthorizationParserOption

WithAuthorizationHeader changes the name of the header holding the token. By default, the header used is DefaultAuthorizationHeader.

func WithBasic added in v1.0.0

func WithBasic() AuthorizationParserOption

WithBasic is a shorthand for WithScheme that registers basic token parsing using the default scheme.

func WithScheme added in v1.0.0

func WithScheme(scheme Scheme, parser bascule.TokenParser[string]) AuthorizationParserOption

WithScheme registers a string-based token parser that handles a specific authorization scheme. Invocations to this option are cumulative and will overwrite any existing registration.

type BasicToken added in v1.0.0

type BasicToken interface {
	UserName() string
	Password() string
}

BasicToken is the interface that Basic Auth tokens implement.

type BasicTokenParser added in v1.0.0

type BasicTokenParser struct{}

BasicTokenParser is a string-based bascule.TokenParser that produces BasicToken instances from strings.

func (BasicTokenParser) Parse added in v1.0.0

Parse assumes that value is of the format required by https://datatracker.ietf.org/doc/html/rfc7617. The returned Token will return the basic auth username from its Principal() method. The returned Token will also implement BasicToken.

type Challenge added in v1.0.0

type Challenge struct {
	// Scheme is the name of scheme supplied in the challenge.  This field is required.
	Scheme Scheme

	// Realm is the name of the realm for the challenge.  This field is
	// optional, but it is HIGHLY recommended to set it to something useful
	// to a client.
	Realm string

	// Token68 controls whether the token68 flag is written in the challenge.
	Token68 bool

	// Parameters are the optional auth parameters.
	Parameters ChallengeParameters
}

Challenge represets an HTTP authentication challenge, as defined by RFC 7235.

func NewBasicChallenge added in v1.0.0

func NewBasicChallenge(realm string, UTF8 bool) (c Challenge, err error)

NewBasicChallenge is a convenience for creating a Challenge for basic auth.

Although realm is optional, it is HIGHLY recommended to set it to something recognizable for a client.

func (Challenge) Write added in v1.0.0

func (c Challenge) Write(o *strings.Builder) (err error)

Write formats this challenge to the given builder. Any error halts formatting and that error is returned.

type ChallengeParameters added in v1.0.0

type ChallengeParameters struct {
	// contains filtered or unexported fields
}

ChallengeParameters holds the set of parameters. The zero value of this type is ready to use. This type handles writing parameters as well as provides commonly used parameter names for convenience.

func NewChallengeParameters added in v1.0.0

func NewChallengeParameters(s ...string) (cp ChallengeParameters, err error)

NewChallengeParameters creates a ChallengeParameters from a sequence of name/value pairs. The strings are expected to be in name, value, name, value, ... sequence. If the number of strings is odd, then the last parameter will have a blank value.

If any error occurs while setting parameters, execution is halted and that error is returned.

func (*ChallengeParameters) Charset added in v1.0.0

func (cp *ChallengeParameters) Charset(value string) error

Charset sets a charset auth parameter. Basic auth is the main scheme that uses this.

func (*ChallengeParameters) Len added in v1.0.0

func (cp *ChallengeParameters) Len() int

Len returns the number of name/value pairs contained in these parameters.

func (*ChallengeParameters) Set added in v1.0.0

func (cp *ChallengeParameters) Set(name, value string) (err error)

Set sets the value of a parameter. If a parameter was already set, it is ovewritten.

If the parameter name is invalid, this method raises an error.

func (*ChallengeParameters) String added in v1.0.0

func (cp *ChallengeParameters) String() string

String returns the RFC 7235 format of these parameters.

func (*ChallengeParameters) Write added in v1.0.0

func (cp *ChallengeParameters) Write(o *strings.Builder)

Write formats this challenge to the given builder.

type Challenges added in v1.0.0

type Challenges []Challenge

Challenges represents a sequence of challenges to associated with a StatusUnauthorized response.

func (Challenges) Append added in v1.0.0

func (chs Challenges) Append(ch ...Challenge) Challenges

Append appends challenges to this set. The semantics of this method are the same as the built-in append.

func (Challenges) WriteHeader added in v1.0.0

func (chs Challenges) WriteHeader(name string, h http.Header) error

WriteHeader inserts one Http authenticate header per challenge in this set. If this set is empty, the given http.Header is not modified.

The name is used as the header name for each header this method writes. Typically, this will be WWW-Authenticate or Proxy-Authenticate. If name is blank, WWWAuthenticateHeaderName is used.

If any challenge returns an error during formatting, execution is halted and that error is returned.

type ErrorMarshaler added in v1.0.0

type ErrorMarshaler func(request *http.Request, err error) (contentType string, content []byte, marshalErr error)

ErrorMarshaler is a strategy for marshaling an error's contents, particularly to be used in an HTTP response body.

type ErrorStatusCoder added in v1.0.0

type ErrorStatusCoder func(request *http.Request, err error) int

ErrorStatusCoder is a strategy for determining the HTTP response code for an error.

If this closure returns a value less than 100, which is the smallest valid HTTP response code, the caller should supply a useful default.

type Middleware added in v1.0.0

type Middleware struct {
	// contains filtered or unexported fields
}

Middleware is an immutable HTTP workflow that can decorate multiple handlers.

A Middleware can have either or both of an Authenticator, which creates tokens from HTTP requests, and an Authorizer, which approves access to the resource identified by the request. The behavior of a Middleware depends mostly on these two components.

If both an authenticator and an authorizer are supplied, the full bascule workflow, including events, is implemented.

If an authenticator is supplied without an authorizer, only token creation is implemented. Without an authorizer, it is assumed that all tokens have access to all requests.

If no authenticator is supplied, but an authorizer IS supplied, then NewMiddleware returns an error. An authenticator is required in order to create tokens.

Finally, if neither an authenticator or an authorizer is supplied, then this Middleware is a noop. Any attempt to decorate handlers will result in those handlers being returned as is. This allows a Middleware to be turned off via configuration.

Example (Basicauth)

ExampleMiddleware_basicauth illustrates how to use a basculehttp Middleware with just basic auth.

tp, _ := NewAuthorizationParser(
	WithBasic(),
)

m, _ := NewMiddleware(
	UseAuthenticator(
		NewAuthenticator(
			bascule.WithTokenParsers(tp),
		),
	),
)

// decorate a handler that needs authorization
h := m.ThenFunc(
	func(response http.ResponseWriter, request *http.Request) {
		if t, ok := bascule.GetFrom(request); ok {
			fmt.Println("principal:", t.Principal())
		} else {
			fmt.Println("no token found")
		}
	},
)

// what happens when no authorization is set?
noAuth := httptest.NewRequest("GET", "/", nil)
response := httptest.NewRecorder()
h.ServeHTTP(response, noAuth)
fmt.Println("no authorization response code:", response.Code)

// what happens when a valid Basic token is set?
withBasic := httptest.NewRequest("GET", "/", nil)
withBasic.SetBasicAuth("joe", "password")
response = httptest.NewRecorder()
h.ServeHTTP(response, withBasic)
fmt.Println("with basic auth response code:", response.Code)
Output:

no authorization response code: 401
principal: joe
with basic auth response code: 200

func NewMiddleware added in v1.0.0

func NewMiddleware(opts ...MiddlewareOption) (m *Middleware, err error)

NewMiddleware creates an immutable Middleware instance from a supplied set of options. No options will result in a Middleware with default behavior.

If no authenticator is configured, but an authorizer is, this function returns ErrNoAuthenticator.

Note that if no workflow components are configured, i.e. neither an authenticator nor an authorizer are supplied, then the returned Middleware is a noop.

func (*Middleware) Then added in v1.0.0

func (m *Middleware) Then(protected http.Handler) http.Handler

Then produces an http.Handler that uses this Middleware's workflow to protected a given handler.

func (*Middleware) ThenFunc added in v1.0.0

func (m *Middleware) ThenFunc(protected http.HandlerFunc) http.Handler

ThenFunc is like Then, but protects a handler function.

type MiddlewareOption added in v1.0.0

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

MiddlewareOption is a functional option for tailoring a Middleware.

func UseAuthenticator added in v1.0.0

func UseAuthenticator(authenticator *bascule.Authenticator[*http.Request], err error) MiddlewareOption

UseAuthenticator is a variant of WithAuthenticator that allows a caller to nest function calls a little easier. The output of NewAuthenticator can be passed directly to this option.

Note: If no authenticator is supplied, NewMiddeware returns an error.

func UseAuthorizer added in v1.0.0

func UseAuthorizer(authorizer *bascule.Authorizer[*http.Request], err error) MiddlewareOption

UseAuthorizer is a variant of WithAuthorizer that allows a caller to nest function calls a little easier. The output of NewAuthorizer can be passed directly to this option.

func WithAuthenticator added in v1.0.0

func WithAuthenticator(authenticator *bascule.Authenticator[*http.Request]) MiddlewareOption

WithAuthenticator supplies the Authenticator workflow for the middleware.

func WithAuthorizer added in v1.0.0

func WithAuthorizer(authorizer *bascule.Authorizer[*http.Request]) MiddlewareOption

WithAuthorizer supplies the Authorizer workflow for the middleware.

The Authorizer is optional. If no authorizer is supplied, then no authorization takes place and no authorization events are fired.

func WithChallenges added in v1.0.0

func WithChallenges(ch ...Challenge) MiddlewareOption

WithChallenges adds WWW-Authenticate challenges to be used when a StatusUnauthorized is detected. Multiple invocations of this option are cumulative. Each challenge results in a separate WWW-Authenticate header, in the order specified by this option.

func WithErrorMarshaler added in v1.0.0

func WithErrorMarshaler(em ErrorMarshaler) MiddlewareOption

WithErrorMarshaler sets the strategy used to marshal errors to HTTP response bodies. If this option is omitted or if esc is nil, DefaultErrorMarshaler is used.

func WithErrorStatusCoder added in v1.0.0

func WithErrorStatusCoder(esc ErrorStatusCoder) MiddlewareOption

WithErrorStatusCoder sets the strategy used to write errors to HTTP responses. If this option is omitted or if esc is nil, DefaultErrorStatusCoder is used.

type Scheme added in v1.0.0

type Scheme string

Scheme is the authorization header scheme, e.g. Basic, Bearer, etc.

const (
	// SchemeBasic is the Basic HTTP authorization scheme.
	SchemeBasic Scheme = "Basic"

	// SchemeBearer is the Bearer HTTP authorization scheme.
	SchemeBearer Scheme = "Bearer"
)

func ParseAuthorization added in v1.0.0

func ParseAuthorization(raw string) (s Scheme, v string, err error)

ParseAuthorization parses an authorization value typically passed in the Authorization HTTP header.

The required format is <scheme><single space><credential value>. This function is strict: it requires no leading or trailing space and exactly (1) space as a separator. If the raw value does not adhere to this format, ErrInvalidAuthorization is returned.

type UnsupportedSchemeError added in v1.0.0

type UnsupportedSchemeError struct {
	Scheme Scheme
}

UnsupportedSchemeError is used to indicate that a particular HTTP Authorization scheme is not supported by the server.

func (*UnsupportedSchemeError) Error added in v1.0.0

func (use *UnsupportedSchemeError) Error() string

func (*UnsupportedSchemeError) StatusCode added in v1.0.0

func (use *UnsupportedSchemeError) StatusCode() int

StatusCode marks this error as using the http.StatusUnauthorized code. This is appropriate for almost all cases, as this error occurs because the server does not accept or understand the scheme that the HTTP client supplied.

Jump to

Keyboard shortcuts

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