auth

package
v0.0.0-...-2262de7 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2023 License: NCSA Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	AdminCapability     = principal.NewCapability("role", "admin")
	ModeratorCapability = principal.NewCapability("role", "moderator")
	UserCapability      = principal.NewCapability("role", "user")
)
View Source
var AnonymousUser anonymousUser = 0
View Source
var ErrDecoding = errors.NewError("unable to decode byte string or other source")

ErrDecoding is returned whenever the provided cookie data could not be unmarshalled or parsed. This should never occur when using the default codecs except if the authentication API has changed dramatically and the incoming JSON is no longer valid according to the expected format. Consider the default codec encrypts and signs outgoing cookie data: This data, ideally, cannot be tampered with and therefore this error will almost certainly indicate a version mismatch in Capstan.

View Source
var ErrEncoding = errors.NewError("unable to encode byte string or other source")

ErrEncoding is returned whenever cookie data or data destined for the authentication cookie cannot be encoded. Either the incoming data is incorrectly formatted or cannot be marshalled.

View Source
var ErrIdentityNotImplemented = errors.NewError("UserIdentity not implemented by user instance")

ErrIdentityNotImplemented is returned if the caller requests a UserIdentity instance (such as via LoadIdentity) and the user loader provided by the caller does not return a type that implements UserIdentity.

View Source
var ErrInvalidContext = errors.NewError("invalid or missing context")

ErrInvalidContext is raised whenever an appropriate context cannot be read from the current request. This applies to both the authentication instances and the user data cache.

View Source
var ErrInvalidPermission = errors.NewError("invalid or undefined permission")

ErrInvalidPermission is returned if the current user lacks the permissions required to access a given resource. May be returned by WithRole or WithPermission*.

View Source
var ErrLoginExpired = errors.NewError("login session expired")

ErrLoginExpired is returned by validation functions if the authentication session has expired due to configured timeouts.

View Source
var ErrNoSuchUser = errors.NewError("no user")

ErrNoSuchUser is returned by Load* whenever the current request context cannot load user data from the authentication cookie.

Functions

func AuthenticatorMiddleware

func AuthenticatorMiddleware(onCookie bool, autoInvalidate bool, auth *Authenticator) func(next http.Handler) http.Handler

AuthenticatorMiddleware returns a new middleware instance that sets up the appropriate authentication and user contexts.

This function accepts two argument: onCookie which dictates whether the middleware will run *only* if the authentication cookie is present, and auth which is a configured Authenticator.

func IsFresh

func IsFresh(ctx capstan.Context) bool

IsFresh returns true if the current login session is considered "fresh" or false if it is not.

Freshness is determined based upon whether the user has recently logged in (via LoginUser()) and their session is still "active." Sessions are considered active if the user has contacted the site and triggered an authenticatio nsession update prior to AuthenticationConfig.FreshTimeout (default: 30 minutes) or if their session has not extended beyond AuthenticationConfig.FreshMaxLife (default: 4 hours). If a user has exceeded either one of these limits, this function will return false and the user should be required to login again.

The "freshness guarantee" is useful for providing additional protection to things like the user's account information or administrative features by limiting the active window during which these can be used or modified.

func IsValid

func IsValid(ctx capstan.Context) bool

IsValid returns true if the current authentication session is still valid and has not timed out. Typically, the login cookie *should* expire after AuthenticationConfig.MaxRememberDuration, but some browsers will not always remove expired cookies when using session resumption features. This guarantees the session will be invalidated after its maximum age has expired.

func LoginUser

func LoginUser(ctx capstan.Context, id string, remember bool) error

LoginUser invokes the authenticators login code and configures the user's data to initialize with a login_at timestamp of the current time, resetting the user's "freshness" guarantee. The `remember` flag must be specified to indicate whether or not this is a persistent authentication session; if true, a long duration cookie will be set for the client's browser, allowing them to maintain their login state across browser sessions.

func LoginUserWithMeta

func LoginUserWithMeta(ctx capstan.Context, id string, meta map[string]string,
	remember bool) error

LoginUserWithMeta behaves identically to LoginUser with the exception that callers may also supply metadata to store on the login session.

Be aware that the total metadata should not exceed 1500 bytes for maximum compatibility.

func UserMeta

func UserMeta(ctx capstan.Context) (map[string]string, error)

UserMeta returns any metadata that might be associated with the user's session.

func WithAuthentication

func WithAuthentication(ctx capstan.Context, fn func(User) error) error

WithAuthentication invokes the callback function `fn` if and only if the user is authenticated. This provides far more limited access control than the other With* functions, but it could be combined with other features, such as session management, to only initialize a working session if the user account is authenticated.

func WithPermissionSetup

func WithPermissionSetup(ctx capstan.Context, permissions *principal.Permission,
	setup func(UserIdentity) UserIdentity, callback func(User)) error

WithPermissionSetup behaves similarly to WithPermissions, in that the callback function will be invoked only if the current user's identity includes the `permissions` set. However, the primary difference is that the `setup` function will be invoked before validating whether or not the user can fulfill `permissions.`

For this function, `setup` can be used to alter the user's identity as appropriate for the request by adding or removing permissions. The setup function must accept a UserIdentity interface and return a type implementing the UserIdentity interface.

One example would be to use the setup function to attach requirements that the user's identity provides, such as an owner ID or other identifier used to validate the user's ownership of a resource.

A similar means of implementing this can be achieved by calling LoadIdentity and then modifying the UserIdentity directly. The advantage of using this method is chiefly in the brevity obtained by recycling code encapsulated inside a function.

func WithPermissions

func WithPermissions(ctx capstan.Context, permissions *principal.Permission,
	callback func(User)) error

WithPermissions invokes the `callback` function if the current user's UserIdentity fulfills the requirements of `permissions`. This can be useful for restricting access based primarily on permissions rather than the coarser-grain role-based access control of WithRole.

If you require finer control over what a user can or cannot do, consider using WithPermissionSetup or using LoadIdentity and modifying the identity from there.

func WithRole

func WithRole(ctx capstan.Context, role *principal.Permission,
	fn func(User)) error

WithRole invokes the callback function `fn` if and only if the current UserIdentity fulfills the requirements of `role`. This is chiefly useful for restricting or permitting user access based exclusively on role membership. This provides coarser control over user permissions than WithPermissions or WithPermissionSetup and is better for "pure" RBAC.

func WithoutPermissions

func WithoutPermissions(ctx capstan.Context, permissions *principal.Permission,
	callback func(User)) error

WithoutPermissions behaves exactly opposite that of WithPermissions and invokes `callback` only if the current UserIdentity does NOT fulfill the requirements in `permissions.`

Types

type AuthenticatableUser

type AuthenticatableUser interface {
	Login() bool
	ValidatePassword(string) bool
}

type AuthenticationConfig

type AuthenticationConfig struct {
	// CookieOptions configures the authentication cookie defaults and
	// attributes.
	CookieOptions *http.Cookie

	// Loader function for user IDs.
	//
	// User IDs are mostly transparent and, in the case of the Loader function
	// type, must be supplied as a string. The actual underlying implementation
	// is dependent upon the caller and may use integers, UUIDs, or other
	// values.
	Loader Loader

	// Logger for the authentication backend. If this is unset a separate logger
	// will be created.
	Logger *logging.Log

	// Codec defines the encoding and decounting routines for persisting user
	// data to and from a cookie.
	Codec UserCodec

	// Key used to encrypt the authentication cookie
	Key []byte

	// HMAC key used to validate the authentication cookie ciphertext; this is
	// used as an override value for unit tests or for callers who require
	// setting the key externally.
	//
	// This value is normally derived automatically if a key manager is
	// provided.
	HMAC []byte

	KeyNameSpace string

	KeyRingName string

	// PlainText disables encryption of the authentication cookie for debugging
	// and testing purposes.
	//
	// Note: This flag cannot be enabled unless the following conditions are
	// true: 1) Unit tests are currently running or 2) development mode is
	// enabled and the value of this flag is set to "true."
	//
	// Consequently, development mode should never be used in production.
	PlainText bool

	// MaxRememberDuration declares how long saved authentication credentials
	// may persist. If this value is unset, saved authentication credentials
	// will persist for 1 year or until the keys are changed/rotated.
	MaxRememberDuration time.Duration

	// FreshTimeout dictates after what duration a login will no longer be
	// considered "fresh" and will require re-authentication. This value is
	// reevaluated based on user activity.
	//
	// Default: 30 minutes.
	FreshTimeout time.Duration

	// FreshMaxLife controls the maximum duration for which a user's login
	// session can be considered "fresh" before it is marked as stale. This
	// value is a finite upper limit and is not reevaluated based on user
	// activity.
	//
	// Default: 4 hours.
	FreshMaxLife time.Duration
}

type Authenticator

type Authenticator struct {
	// Config must be provided and contains the authentication configuration,
	// such as the cookie name and other properties, in addition to encryption
	// and signing keys.
	Config *AuthenticationConfig

	// Codec defines the encoding and decoding routines for persisting user data
	// to and from a cookie.
	Codec UserCodec

	// Loader is not defined by this package and must be provided by the caller.
	// This type is defined by Loader (see above) and must accept a string
	// returning a type that implements the User interface.
	//
	// Defining this is critical for the functionality of Capstan's
	// authentication subsystem: It's what interfaces the Authenticator with
	// your code and returns usable types after a successful authentication or
	// after the authentication cookie was validated.
	Loader Loader
}

Authenticator manages all authentication activities and is the backbone of Capstan's cookie-based authentication sessions. All package-level functions interface with this type by way of the request context.

func NewAuthenticator

func NewAuthenticator(conf *AuthenticationConfig) (*Authenticator, error)

NewAuthenticator returns a new Authenticator instance with the specified user Loader and ServerConfig.

The user Loader must be provided by the caller so Capstan can return an appropriate type implementing the User API. This type may be cast to a more specific local type by the caller via type assertion; Capstan strictly exposes the User interface at load time.

func NewAuthenticatorWithCodec

func NewAuthenticatorWithCodec(codec UserCodec, conf *AuthenticationConfig) *Authenticator

NewAuthenticatorWithCodec is similar to NewAuthenticator with the exception that it also accepts a Codec implementation that determines how the user data is persisted to a cookie.

Ordinarily, there is no reason to use any codecs other than the ones defined here unless you have specific cryptographic needs. Specifying your own codec may be useful for debugging, as you can store user data in plain text by implementing such a codec. See the `ptCodec` type in our integration tests (tests/authentication_test.go) for details of how such a codec might work.

func (*Authenticator) IsFresh

func (a *Authenticator) IsFresh(r *http.Request) bool

IsFresh returns true if the current login session is considered "fresh" or false if it is not.

Freshness is determined based upon whether the user has recently logged in (via LoginUser()) and their session is still "active." Sessions are considered active if the user has contacted the site and triggered an authenticatio nsession update prior to AuthenticationConfig.FreshTimeout (default: 30 minutes) or if their session has not extended beyond AuthenticationConfig.FreshMaxLife (default: 4 hours). If a user has exceeded either one of these limits, this function will return false and the user should be required to login again.

The "freshness guarantee" is useful for providing additional protection to things like the user's account information or administrative features by limiting the active window during which these can be used or modified.

func (*Authenticator) IsValid

func (a *Authenticator) IsValid(r *http.Request) bool

IsValid returns true if the current authentication session is still valid and has not timed out. Typically, the login cookie *should* expire after AuthenticationConfig.MaxRememberDuration, but some browsers will not always remove expired cookies when using session resumption features. This guarantees the session will be invalidated after its maximum age has expired.

func (*Authenticator) LoadIdentity

func (a *Authenticator) LoadIdentity(r *http.Request) (UserIdentity, error)

LoadIdentity from the current request using either the cached user or LoadUser if the cached user is not present.

func (*Authenticator) LoadUser

func (a *Authenticator) LoadUser(r *http.Request) (User, error)

LoadUser from the current request, using the configured user Loader.

This returns a User interface (see api.go) that may then be converted to the caller's desired local types via type assertion. Otherwise, the API exposed by User, UserMixin, or UserIdentity may be used out-of-the-box with Capstan.

func (*Authenticator) RememberUser

func (a *Authenticator) RememberUser(ctx capstan.Context, user *UserData) error

RememberUser by saving it to the current session and creating a long-duration cookie.

The authentication cookie created by this function has associated with it the attributes as described by AuthenticationConfig. This authentication session will terminate after the duration in AuthenticationConfig.MaxRememberDuration. For ephemeral sessions that persist only as long as the browser is open, see SaveUser.

func (*Authenticator) SaveUser

func (a *Authenticator) SaveUser(ctx capstan.Context, user *UserData) error

SaveUser to the current session.

Creates the authentication cookie with the attributes as described by AuthenticationConfig. This only creates the ephemeral login session that should, under most circumstances (dependent on browser behavior) terminate when the browser is closed. For long-duration authentication sessions, see RememberUser.

func (*Authenticator) UserMeta

func (a *Authenticator) UserMeta(r *http.Request) (map[string]string, error)

UserMeta returns any metadata that might be associated with the user session.

type DefaultUserCodec

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

DefaultUserCodec implements the UserCodec interface, providing encryption services via KeyStar.

func NewDefaultUserCodec

func NewDefaultUserCodec(conf *AuthenticationConfig) (codec *DefaultUserCodec, err error)

NewDefaultUserCodec returns a codec suitable for encoding and decoding authentication sessions.

func (*DefaultUserCodec) Decode

func (c *DefaultUserCodec) Decode(s string) (*UserData, error)

Decode accepts a base64-encoded string, decodes it, and returns a UserData instance.

func (*DefaultUserCodec) Encode

func (c *DefaultUserCodec) Encode(user *UserData) (string, error)

Encode accepts a UserData instance and returns it as base64-encoded string.

type Loader

type Loader func(id string) (User, error)

Loader types accept a user identifier, as a string, and return a User interface.

A string type is provided as the identifier to support callers that do not utilize numeric user identifiers.

type Refresher

type Refresher interface {
	RequiresFresh() bool
}

type Saver

type Saver func(data UserData) UserData

Saver types must accept a UserData instance and return it, modified accordingly, to the caller's preference.

type User

type User interface {
	Active() bool
	Authenticated() bool
	Anonymous() bool
	Identifier() string
}

func LoadUser

func LoadUser(ctx capstan.Context) (User, error)

LoadUser loads the current user and returns it. If no user account is associated with the current request, this will return ErrInvalidContext.

type UserCodec

type UserCodec interface {
	Encode(*UserData) (string, error)
	Decode(string) (*UserData, error)
}

type UserData

type UserData struct {
	// ID is a string-based user identifier. This will normally be an int or
	// int64 for most use cases, but we store it as a string for software that
	// might expect other formats (such as UUID).
	//
	// This may be subject to change in the future, depending on usage.
	ID string `json:"id"`

	// Remember flag indicating the authentication cookie was created to
	// remember the user's credentials. This enforces a different set of
	// timeouts than session-only authentication.
	Remember bool `json:"remember"`

	// Login tracks the time at which the user's authentication was most
	// recently prompted to log in. This does not indicate the absolute start of
	// the session and is used to determine if the session is "fresh."
	// AuthenticationConfig.FreshMaxLife dictates the maximum duration from this
	// value to the current time before the user is asked to log in again.
	Login time.Time `json:"login"`

	// Updated indicates when the session was last active and is used as an
	// activity timeout to determine if the login is still "fresh." This is
	// governed by AuthenticationConfig.FreshTimeout, which is 30 minutes by
	// default.
	Updated time.Time `json:"updated"`

	// Saved is used by "remember me" logic to determine when the user's session
	// should be forcibly nullified. If this exceeds the timeout in
	// AuthenticationConfig.MaxRememberDuration, the user will be required to
	// login again.
	//
	// The timeout behavior of this value cannot be extended except by
	// configuration or by logging out and back in. By default, if the
	// configuration option is not set, login sessions will be stored for 1
	// year.
	Saved time.Time `json:"saved"`

	// Meta data for the authentication session.
	//
	// This value should be used sparingly since the authentication data is
	// stored in a cookie. Consider using localStorage on the client-side if you
	// require more data. For this value, it may be useful to store some
	// metadata about the current login, such as the user's name to reduce the
	// number of database accesses for something like a greeting page or banner.
	Meta map[string]string
}

UserData encapsulates user information to be persisted to the authentication cookie.

type UserIdentity

type UserIdentity interface {
	Identity() principal.Identity
}

UserIdentity encapsulates a base user plus its principal identity.

func LoadIdentity

func LoadIdentity(ctx capstan.Context) (UserIdentity, error)

LoadIdentity loads the current user and returns its UserIdentity. If no user account is associated with the current request, this will return ErrInvalidContext.

type UserMixin

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

UserMixin may be used by callers to assist in adapting types to implement the User interface.

This mixin is not required for such purposes, but it certainly may be helpful.

func (*UserMixin) Active

func (u *UserMixin) Active() bool

Active returns whether the user account is considered active.

func (*UserMixin) Anonymous

func (u *UserMixin) Anonymous() bool

Anonymous returns whether the user account is considered anonymous.

Not currently implemented.

func (*UserMixin) Authenticated

func (u *UserMixin) Authenticated() bool

Authenticated returns whether the user account is considered to be authenticated.

func (*UserMixin) Identifier

func (u *UserMixin) Identifier() string

Identifier returns an integer identifier associated with this account.

Be aware that due to the implementation of UserData, this is subject to change.

func (*UserMixin) SetID

func (u *UserMixin) SetID(id string)

Jump to

Keyboard shortcuts

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