auth

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2025 License: BSD-3-Clause Imports: 12 Imported by: 22

README

go-http-auth

Go package to provide a simple interface for enforcing authentication in HTTP handlers.

Documentation

Go Reference

Motivation

The go-http-auth package aims to provide a simple interface for enforcing authentication in Go-based web applications in a way that those applications don't need to know anyt hing about how authentication happens.

// type Authenticator is a simple interface for	enforcing authentication in HTTP handlers.
type Authenticator interface {
	// WrapHandler wraps a `http.Handler` with any implementation-specific middleware.
	WrapHandler(http.Handler) http.Handler
	// GetAccountForRequest returns an `Account` instance  for an HTTP request.
	GetAccountForRequest(*http.Request) (Account, error)
	// SigninHandler returns a `http.Handler` for implementing account signin.
	SigninHandler() http.Handler
	// SignoutHandler returns a `http.Handler` for implementing account signout.
	SignoutHandler() http.Handler
	// SignupHandler returns a `http.Handler` for implementing account signups.
	SignupHandler() http.Handler
}

All the web application (specifically its net/http.Handler instances) know is that it has an implementation of the auth.Authenticator interface which exposes a GetAccountForRequest method which returns an implementation of the auth.Account interface or an error.

// type Account is an interface that defines minimal information for an account.
type Account interface {
	// The unique ID associated with this account.	
	Id() int64
	// The name associated with this account.
	Name() string
}

Account interfaces/implementations meant to be accurate reflections of the underlying implementation's account structure but rather a minimalist struct containing on an account name and unique identifier.

Here is a simplified example, with error handling omitted for brevity, that uses the built-in null:// Authenticator implementation (that will always return a Account instance with ID "0"):

package main

import (
     "context"	
     "log"
     "net/http"

     "github.com/sfomuseum/go-http-auth"
)

type HandlerOptions struct {
     Authenticator auth.Authenticator
}

func Handler(opts *HandlerOptions) (http.Handler, error) {

	fn := func(rsp http.ResponseWriter, req *http.Request) {

		acct, err := opts.Authenticator.GetAccountForRequest(req)

		if err != nil {
			switch err.(type) {
			case auth.NotLoggedIn:
				signin_handler := opts.Authenticator.SigninHandler()
				signin_handler.ServeHTTP(rsp, req)
				return

			default:
				http.Error(rsp, "Internal server error", http.StatusInternalServerError)
				return
			}
		}

		log.Printf("Authenticated as %s (%d)\n", acct.Name(), acct.Id())
		
		... carry on with handler
	}

	return http.HandlerFunc(fn), nil
}

func main (){

     ctx := context.Background()
     
     authenticator, _ := auth.NewAuthenticator(ctx, "null://")

     handler_opts := &HandlerOptions{
     	Authenticator: authenticator,
     }
     
     handler, _ := Handler(handler_opts)
     handler = authenticator.WrapHandler(handler)
     
     mux := http.NewServeMux()

     mux.Handle("/", handler)

     http.ListenAndServe(":8080", mux)
}

Note the use the of the authenticator.WrapHandler() method. This is a net/http "middleware" handler where implementation-specific logic for checking whether a user is authenticated is expected to happen. That information is expected to be retrievable using the GetAccountForRequest method in the subsequent handlers that WrapHandler serves. The details of how authentication information is stored and retrieved between handlers is left to individual implmentations.

For concrete examples, have a look at the code for cmd/example/main.go.

Authenticators

The following Authenticator implementations are included by default:

jwt://

JWTAuthenticator implements the Authenticator interface to ensure that requests contain a "Authorization: Bearer {JWT_TOKEN}"` HTTP header configured by 'uri' which is expected to take the form of:

jwt://{SECRET}

Where {SECRET} is expected to be the shared JWT signing secret passed by HTTP requests. Or:

jwt://runtimevar?runtimevar-uri={GOCLOUD_DEV_RUNTIMEVAR_URI}

Where {GOCLOUD_DEV_RUNTIMEVAR_URI} is a valid gocloud.dev/runtimevar URI used to dereference the JWT signing secret. Under the hood this method using the sfomuseum/runtimevar.StringVar method to dereference runtimevar URIs.

By default a JWTAuthenticator instance looks for JWT Bearer tokens in the HTTP "Authorization" header. This behaviour can be customized by passing an "authorization-header" query parameter in 'uri'. For example:

jwt://?authorization-header=X-Custom-AuthHeader

JWT payloads are expected to conform to the JWTAuthenticatorClaims struct:

type JWTAuthenticatorClaims struct {
	// The unique ID associated with this account.
	AccountId   int64  `json:"account_id"`
	// The name associated with this account.	
	AccountName string `json:"account_name"`
	jwt.RegisteredClaims
}
none://

NoneAuthenticator implements the Authenticator interface and always returns a "Not authorized" error. It is instantiated with the following URI construct:

none://
null://

NullAuthenticator implements the Authenticator interface such that no authentication is performed. It is instantiated with the following URI construct:

null://
sharedsecret://

SharedSecretAuthenticator implements the Authenticator interface to require a simple shared secret be passed with all requests. This is not a sophisticated handler. There are no nonces or hashing of requests or anything like that. It is a bare-bones supplementary authentication handler for environments that already implement their own measures of access control. It is instantiated with the following URI construct:

sharedsecret://{SECRET}

Where {SECRET} is expected to be the shared secret passed by HTTP requests in the X-Shared-Secret header.

See also

Documentation

Overview

Package auth provides a simple (and limited) interface for enforcing authentication in HTTP handlers.

Index

Constants

View Source
const AUTHORIZATION_HEADER string = "Authentication"
View Source
const SHARED_SECRET_ACCOUNT_ID int64 = -1

SHARED_SECRET_ACCOUNT_ID is the account ID used for `Account` instances when shared secret authentication validates.

View Source
const SHARED_SECRET_ACCOUNT_NAME string = "sharedsecret"

SHARED_SECRET_ACCOUNT_NAME is the account name used for `Account` instances when shared secret authentication validates.

View Source
const SHARED_SECRET_HEADER string = "X-Shared-Secret"

SHARED_SECRET_HEADER is the name of the HTTP header to check for "shared secret" authentication.

Variables

This section is empty.

Functions

func EnsureAccountHandler

func EnsureAccountHandler(authenticator Authenticator, next go_http.Handler) go_http.Handler

EnsureAccountHandler is a middleware `net/http` handler that wraps 'next' and ensures that the authenticator.GetAccountForRequest method does not return an error.

func RegisterAuthenticator

func RegisterAuthenticator(ctx context.Context, scheme string, init_func AuthenticatorInitializationFunc) error

RegisterAuthenticator registers 'scheme' as a key pointing to 'init_func' in an internal lookup table used to create new `Authenticator` instances by the `NewAuthenticator` method.

func Schemes

func Schemes() []string

Schemes returns the list of schemes that have been registered.

Types

type Account

type Account interface {
	// The unique ID associated with this account.
	Id() int64
	// The name associated with this account.
	Name() string
}

type Account is an interface that defines minimal information for an account.

func NewAccount added in v0.12.0

func NewAccount(id int64, name string) Account

NewAccount returns a new instance of `BasicAccount` (which implements the `Account` interface) for 'id' and 'name'.

type AccountNotExist added in v0.0.3

type AccountNotExist struct{}

AccountNotExist defines a well-known error for signaling that a given account does not exist.

func (AccountNotExist) Error added in v0.0.3

func (e AccountNotExist) Error() string

Error() returns a human-readable representation of the `AccountNotExist` error.

type Authenticator

type Authenticator interface {
	// WrapHandler wraps a `http.Handler` with any implementation-specific middleware.
	WrapHandler(http.Handler) http.Handler
	// GetAccountForRequest returns an `Account` instance  for an HTTP request.
	GetAccountForRequest(*http.Request) (Account, error)
	// SigninHandler returns a `http.Handler` for implementing account signin.
	SigninHandler() http.Handler
	// SignoutHandler returns a `http.Handler` for implementing account signout.
	SignoutHandler() http.Handler
	// SignupHandler returns a `http.Handler` for implementing account signups.
	SignupHandler() http.Handler
}

type Authenticator is a simple interface for enforcing authentication in HTTP handlers.

func NewAuthenticator

func NewAuthenticator(ctx context.Context, uri string) (Authenticator, error)

NewAuthenticator returns a new `Authenticator` instance configured by 'uri'. The value of 'uri' is parsed as a `url.URL` and its scheme is used as the key for a corresponding `AuthenticatorInitializationFunc` function used to instantiate the new `Authenticator`. It is assumed that the scheme (and initialization function) have been registered by the `RegisterAuthenticator` method.

func NewJWTAuthenticator added in v1.1.0

func NewJWTAuthenticator(ctx context.Context, uri string) (Authenticator, error)

NewJWTAuthenticator implements the Authenticator interface to ensure that requests contain a `Authorization: Bearer {JWT_TOKEN}` HTTP header configured by 'uri' which is expected to take the form of:

jwt://{SECRET}

Where {SECRET} is expected to be the shared JWT signing secret passed by HTTP requests. Or:

jwt://runtimevar?runtimevar-uri={GOCLOUD_DEV_RUNTIMEVAR_URI}

Where {GOCLOUD_DEV_RUNTIMEVAR_URI} is a valid `gocloud.dev/runtimevar` URI used to dereference the JWT signing secret. Under the hood this method using the `github.com/sfomuseum/runtimevar.StringVar` method to dereference runtimevar URIs.

By default a `JWTAuthenticator` instance looks for JWT Bearer tokens in the HTTP "Authorization" header. This behaviour can be customized by passing an "authorization-header" query parameter in 'uri'. For example:

jwt://?authorization-header=X-Custom-AuthHeader

func NewNoneAuthenticator added in v0.0.6

func NewNoneAuthenticator(ctx context.Context, uri string) (Authenticator, error)

NewNoneAuthenticator implements the Authenticator interface that always returns a "not authorized" error. configured by 'uri' which is expected to take the form of:

none://

func NewNullAuthenticator added in v0.0.2

func NewNullAuthenticator(ctx context.Context, uri string) (Authenticator, error)

NewNullAuthenticator implements the Authenticator interface such that no authentication is performed configured by 'uri' which is expected to take the form of:

null://

func NewSharedSecretAuthenticator added in v0.10.0

func NewSharedSecretAuthenticator(ctx context.Context, uri string) (Authenticator, error)

NewSharedSecretAuthenticator implements the Authenticator interface to ensure that requests contain a `X-Shared-Secret` HTTP header configured by 'uri' which is expected to take the form of:

sharedsecret://{SECRET}

Where {SECRET} is expected to be the shared secret passed by HTTP requests.

type AuthenticatorInitializationFunc

type AuthenticatorInitializationFunc func(ctx context.Context, uri string) (Authenticator, error)

AuthenticatorInitializationFunc is a function defined by individual authenticator package and used to create an instance of that authenticator

type BasicAccount added in v0.12.0

type BasicAccount struct {
	Account `json:",omitempty"`
	// The unique ID associated with this account.
	AccountId int64 `json:"id"`
	// The name associated with this account.
	AccountName string `json:"name"`
}

BasicAccount is the simplest (most basic) implementation of the `Account` interface for wrapping a unique account ID and an account name.

func (*BasicAccount) Id added in v0.12.0

func (a *BasicAccount) Id() int64

Returns the unique ID associated with 'a'.

func (*BasicAccount) Name added in v0.12.0

func (a *BasicAccount) Name() string

Returns the name associated with 'a'.

type JWTAuthenticator added in v1.1.0

type JWTAuthenticator struct {
	Authenticator
	// contains filtered or unexported fields
}

type JWTAuthenticator implements the Authenticator interface to require a valid JSON Web Token (JWT) be passed with all requests.

func (*JWTAuthenticator) GetAccountForRequest added in v1.1.0

func (a *JWTAuthenticator) GetAccountForRequest(req *http.Request) (Account, error)

GetAccountForRequest returns an stub `Account` instance for requests that contain a valid `Authorization: Bearer {JWT_TOKEN}` HTTP header (or a custom header if defined in the `JWTAuthenticator` constuctor URI).

func (*JWTAuthenticator) SigninHandler added in v1.1.0

func (a *JWTAuthenticator) SigninHandler() http.Handler

SigninHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*JWTAuthenticator) SignoutHandler added in v1.1.0

func (a *JWTAuthenticator) SignoutHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*JWTAuthenticator) SignupHandler added in v1.1.0

func (a *JWTAuthenticator) SignupHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*JWTAuthenticator) WrapHandler added in v1.1.0

func (a *JWTAuthenticator) WrapHandler(next http.Handler) http.Handler

WrapHandler returns

type JWTAuthenticatorClaims added in v1.1.0

type JWTAuthenticatorClaims struct {
	// The unique ID associated with this account.
	AccountId int64 `json:"account_id"`
	// The name associated with this account.
	AccountName string `json:"account_name"`
	jwt.RegisteredClaims
}

type JWTAuthenticatorClaims are the custom claims for Authorization requests.

type NoneAuthenticator added in v0.0.6

type NoneAuthenticator struct {
	Authenticator
}

type NoneAuthenticator implements the Authenticator interface that always returns a "not authorized" error.

func (*NoneAuthenticator) GetAccountForRequest added in v0.0.6

func (a *NoneAuthenticator) GetAccountForRequest(req *http.Request) (Account, error)

GetAccountForRequest returns an stub `Account` instance.

func (*NoneAuthenticator) SigninHandler added in v0.0.6

func (a *NoneAuthenticator) SigninHandler() http.Handler

SigninHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NoneAuthenticator) SignoutHandler added in v0.0.6

func (a *NoneAuthenticator) SignoutHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NoneAuthenticator) SignupHandler added in v0.0.6

func (a *NoneAuthenticator) SignupHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NoneAuthenticator) WrapHandler added in v0.0.6

func (a *NoneAuthenticator) WrapHandler(h http.Handler) http.Handler

WrapHandler returns 'h' unchanged.

type NotAuthorized added in v0.0.6

type NotAuthorized struct{}

NotAuthorized defines a well-known error for signaling that the request is not authorized.

func (NotAuthorized) Error added in v0.0.6

func (e NotAuthorized) Error() string

Error() returns a human-readable representation of the `NotAuthorized` error.

type NotLoggedIn added in v0.0.3

type NotLoggedIn struct{}

NotLoggedIn defines a well-known error for signaling that the account is not logged in.

func (NotLoggedIn) Error added in v0.0.3

func (e NotLoggedIn) Error() string

Error() returns a human-readable representation of the `NotLoggedIn` error.

type NullAuthenticator added in v0.0.2

type NullAuthenticator struct {
	Authenticator
}

type NullAuthenticator implements the Authenticator interface such that no authentication is performed.

func (*NullAuthenticator) GetAccountForRequest added in v0.0.2

func (a *NullAuthenticator) GetAccountForRequest(req *http.Request) (Account, error)

GetAccountForRequest returns an stub `Account` instance.

func (*NullAuthenticator) SetLogger added in v0.0.5

func (a *NullAuthenticator) SetLogger(logger *log.Logger)

SetLogger is a no-op and does nothing.

func (*NullAuthenticator) SigninHandler added in v0.0.5

func (a *NullAuthenticator) SigninHandler() http.Handler

SigninHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NullAuthenticator) SignoutHandler added in v0.0.5

func (a *NullAuthenticator) SignoutHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NullAuthenticator) SignupHandler added in v0.0.5

func (a *NullAuthenticator) SignupHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*NullAuthenticator) WrapHandler added in v0.0.2

func (a *NullAuthenticator) WrapHandler(h http.Handler) http.Handler

WrapHandler returns 'h' unchanged.

type SharedSecretAuthenticator added in v0.10.0

type SharedSecretAuthenticator struct {
	Authenticator
	// contains filtered or unexported fields
}

type SharedSecretAuthenticator implements the Authenticator interface to require a simple shared secret be passed with all requests. This is not a sophisticated handler. There are no nonces or hashing of requests or anything like that. It is a bare-bones supplementary authentication handler for environments that already implement their own measures of access control.

func (*SharedSecretAuthenticator) GetAccountForRequest added in v0.10.0

func (a *SharedSecretAuthenticator) GetAccountForRequest(req *http.Request) (Account, error)

GetAccountForRequest returns an stub `Account` instance for requests that contain a valid `X-Shared-Secret` HTTP header.

func (*SharedSecretAuthenticator) SigninHandler added in v0.10.0

func (a *SharedSecretAuthenticator) SigninHandler() http.Handler

SigninHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*SharedSecretAuthenticator) SignoutHandler added in v0.10.0

func (a *SharedSecretAuthenticator) SignoutHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*SharedSecretAuthenticator) SignupHandler added in v0.10.0

func (a *SharedSecretAuthenticator) SignupHandler() http.Handler

SignoutHandler returns an `http.Handler` instance that returns an HTTP "501 Not implemented" error.

func (*SharedSecretAuthenticator) WrapHandler added in v0.10.0

func (a *SharedSecretAuthenticator) WrapHandler(next http.Handler) http.Handler

WrapHandler returns

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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