oauth

package
v0.0.0-...-5f133c6 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2024 License: BSD-3-Clause, BSD-3-Clause Imports: 28 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CredentialsVersionKey = credentialsKey("version")
View Source
var ErrorCannotAuthenticate = errors.New("Who are you? Sorry, you have no authentication cookie, and there is no authentication service configured")
View Source
var ErrorLoops = errors.New("You have been redirected back to this url - but you still don't have an authentication token.\n" +
	"As a sentinent web server, I've decided that you human don't deserve any further redirect, as that would cause a loop\n" +
	"which would be bad for the future of the internet, my load, and your bandwidth. Hit refresh if you want, but there's likely\n" +
	"something wrong in your cookies, or your setup")

Functions

func CheckRedirect

func CheckRedirect(w http.ResponseWriter, r *http.Request, ad AuthData) bool

CheckRedirect checks AuthData to see if its state warrants a redirect. Returns true if it did redirect, false if a redirect was unnecessary.

func CreateRedirectURL

func CreateRedirectURL(r *http.Request) *url.URL

func SetCredentials

func SetCredentials(ctx context.Context, creds *CredentialsCookie) context.Context

SetCredentials returns a context with the credentials of the user added. Use GetCredentials to retrieve them later.

Types

type AuthData

type AuthData struct {
	Creds      *CredentialsCookie
	Identities []Identity
	Cookie     string
	Target     string
	State      interface{}
}

type Authenticate

type Authenticate func(w http.ResponseWriter, r *http.Request, rurl *url.URL) (*CredentialsCookie, error)

Authenticate parses the request received to authenticate the user.

Typically, the Authenticate() function will check if the request contains a valid cookie, some authentication header, or parameters passed in the URL. If everything goes well, it returns a CredentialsCookie. Otherwise, it will either start the authentication process (nil error is returned), or returns an error.

There are thus 3 possible combinations of return values:

  • A non-nil CredentialsCookie, and a nil error - meaning that the request was successfully authenticated. The CredentialsCookie contains details of the user.

  • A nil CredentialsCookie, and a non-nil error - meaning that the request was not authenticated, and that it was not possible to kickstart the authentication process. The error is generally non-recoverable.

  • A nil CredentialsCookie, and a nil error - meaning that the request was not authenticated, but that the authentication process was kickstarted.

    In this case, the caller should consider the request already handled, and just return. The Authenticate function either performed a redirect, or otherwise took care of the next step (by, for example, setting a cookie or displaying an error page).

An Authenticate function should always do its best to try to authenticate the user, no matter what the request contains. An invalid or expired cookie or invalid headers should not result in an error returned. Instead, the function should attempt to re-authenticate the user.

An Authenticate function should return an error only if there is some unrecoverable condition. For example, a server configuration error, an error in a crypto function, or a database error.

Parameters are:

  • An http.ResponseWriter, used to perform redirects, or otherwise add cookies or headers.
  • An http.Request, parsed to look for credentials.
  • A redirect url, a page to send the user back to in case authentication is required, and the user has to be sent to a different page.

type Authenticator

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

func New

func New(rng *rand.Rand, modifiers ...Modifier) (*Authenticator, error)

func (*Authenticator) AuthHandler

func (a *Authenticator) AuthHandler() khttp.FuncHandler

AuthHandler returns the http handler to be invoked at the end of the oauth process.

With oauth, an un-authenticated user will be first redirected to the login page of the oauth provider (google, github, ...), and if login succeeds, the user will be directed back to the URL you configured with WithTarget.

This URL needs to invoke the AuthHandler, so it can verify that the redirect is legitimate, and set all parameters correctly.

The default AuthHandler here will verify the parameters, and redict the user to the target you configured via LoginHandler.

If no such target was provided, the user will just get an empty page. In case of error, an ugly error message is displayed.

Use MakeAuthHandler to customize the behavior.

func (*Authenticator) Complete

func (a *Authenticator) Complete(data AuthData) bool

Complete verifies that AuthData is well formed and valid.

It checks that the identities match, and that the type of credentials are the same type that should be returned by the authenticator.

func (*Authenticator) CredentialsCookie

func (a *Authenticator) CredentialsCookie(value string, co ...kcookie.Modifier) *http.Cookie

CredentialsCookie will create an http.Cookie object containing the user credentials.

func (*Authenticator) ExtractAuth

func (a *Authenticator) ExtractAuth(w http.ResponseWriter, r *http.Request) (AuthData, error)

func (*Authenticator) LoginHandler

func (a *Authenticator) LoginHandler(lm ...LoginModifier) khttp.FuncHandler

Creates and returns a LoginHandler.

The LoginHandler is responsible for redirecting the user to the login page used by the oauth provider, while encoding all the parameters necessary to redirect the user back to this web site.

The target string is which URL to redirect the user to at the end of authentication process and is optional, can be the empty string.

Basically:

  • LoginHandler -> redirects the user to google/github/... oauth login page.
  • user successfuly logs in -> he is redirected to the page configured WithTarget(). This page must be an AuthHandler, as it needs to check the values returned by the oauth provider.
  • If a target url was set, the AuthHandler will issue a redirect to that URL.

The target URL is necessary as most oauth providers have a limit to the number of pages that can be used as AuthHandler, no wildcards are supported, and the page must be configured with the oauth provider.

But an authentication cookie can expire anywhere on your site, and you will need the user to be redirected where he was at the end of the authentication.

Note that this call does not allow you to carry any additional state. Use session cookies for that part instead, or get parameters.

func (*Authenticator) LoginURL

func (a *Authenticator) LoginURL(target string, state interface{}) (string, []byte, error)

LoginURL computes the URL the user is redirected to to perform login.

After the user authenticates, it is redirected back to URL set as auth handler, which verifies the credentials, and creates the authentication cookie.

At this point, either the auth handler returns a page directly (for example, when you set up your own handler with MakeAuthHandler), or, if a target parameter is set, the user is redirected to the configured target.

State is not used by the auth handler. You can basically pass anything you like and have it forwarded to you at the end of the authentication.

Returns: the url to use, a secure token, and nil or an error, in order.

func (*Authenticator) MakeAuthHandler

func (a *Authenticator) MakeAuthHandler(handler khttp.FuncHandler) khttp.FuncHandler

MakeAuthHandler turns the specified handler into an AuthHandler.

AuthHandler (below) returns an http handler that verifies the token returned by the oauth provider, and redirects to the target passed to the LoginHandler (if configured).

MakeAuthHandler (here) returns an http handler that will first check if the request contains the information from the oauth provider.

If yes, and the data is valid, it will process the authentication request, and if a target was passed, perform the redirect.

If no, an error happens, or no redirect is performed, your handler is invoked.

Note that auth handlers need to be registered with your oauth provider.

func (*Authenticator) MakeLoginHandler

func (a *Authenticator) MakeLoginHandler(handler khttp.FuncHandler, lm ...LoginModifier) khttp.FuncHandler

MakeLoginHandler turns the specified handler into a LoginHandler.

LoginHandler (below) returns an http handler that always redirects the user to the login page of the configured provider.

MakeLoginHandler (here) returns an http handler that will first check if the user is authenticated already.

If authenticated, your handler will be invoked with the credentials of the user parsed in the context.

If not authenticated, the user will be redirected to the login page. target is interpreted as the LoginHandler function describes. You should set it to ensure that the user is redirected back to this page after login.

It is not computed automatically to avoid the nuisances of proxies or load balancers, having http vs https (scheme is not propagated), ... Just set it explicitly with your own code, ensuring it is an absolute URL.

Note that login handlers need to be registered with your oauth provider.

func (*Authenticator) Mapper

Mapper configures all the URLs to redirect to / unless an authentication cookie is provided by the browser. Further, it configures / to redirect and perform oauth authentication.

func (*Authenticator) PerformAuth

func (a *Authenticator) PerformAuth(w http.ResponseWriter, r *http.Request, co ...kcookie.Modifier) (AuthData, error)

PerformAuth implements the logic to handle an oauth request from an oauth provider.

It extracts the "state" query parameter and validates it against the state cookie, invoking (if configured) a validator instantiated WithFactory().

In case of error, error is returned, and the rest of the fields are undefined.

In a single authenticator, it always returns true because in a single authenticator it is always the last one.

func (*Authenticator) PerformLogin

func (a *Authenticator) PerformLogin(w http.ResponseWriter, r *http.Request, lm ...LoginModifier) error

PerformLogin writes the response to the request to actually perform the login.

func (*Authenticator) SetAuthCookie

func (a *Authenticator) SetAuthCookie(ad AuthData, w http.ResponseWriter, co ...kcookie.Modifier) (AuthData, error)

func (*Authenticator) WithCredentialsOrError

func (a *Authenticator) WithCredentialsOrError(handler khttp.FuncHandler) khttp.FuncHandler

WithCredentialsOrError invokes the handler if credentials are available, errors out if not.

func (*Authenticator) WithCredentialsOrRedirect

func (a *Authenticator) WithCredentialsOrRedirect(handler khttp.FuncHandler, target string) khttp.FuncHandler

WithCredentialsOrRedirect invokes the handler if credentials are available, or redirects if they are not.

Same as WithCredentials, except that invalid credentials result in a redirect to the specified target. GetCredentials() invoked from the handler is guaranteed to return a non null result.

type Credentials

type Credentials struct {
	ID     string `json:"id"`
	Secret string `json:"secret"`
}

Credentials structs are generally read from json files. They contain the oauth credentials used by the remote service to recognize the client.

type CredentialsCookie

type CredentialsCookie struct {
	// An abstract representation of the identity of the user.
	// This is independent of the authentication provider.
	Identity Identity
	Token    oauth2.Token
}

CredentialsCookie is what is encrypted within the authentication cookie returned to the browser or client.

func GetCredentials

func GetCredentials(ctx context.Context) *CredentialsCookie

GetCredentials returns the credentials of a user extracted from an authentication cookie. Returns nil if the context has no credentials.

type CredentialsMeta

type CredentialsMeta struct {
	context.Context
}

func (CredentialsMeta) Expires

func (ctx CredentialsMeta) Expires() time.Time

func (CredentialsMeta) Issued

func (ctx CredentialsMeta) Issued() time.Time

func (CredentialsMeta) Max

func (ctx CredentialsMeta) Max() time.Time

func (CredentialsMeta) Version

func (ctx CredentialsMeta) Version() int

type Extractor

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

Extractor is an object capable of extracting and verifying authentication information.

func NewExtractor

func NewExtractor(modifiers ...Modifier) (*Extractor, error)

func (*Extractor) CredentialsCookieName

func (a *Extractor) CredentialsCookieName() string

CredentialsCookieName returns the name of the cookie maintaing the set of user credentials.

This cookie is the one used to determine what the user can and cannot do on the UI.

func (*Extractor) EncodeCredentials

func (a *Extractor) EncodeCredentials(creds CredentialsCookie) (string, error)

EncodeCredentials generates a string containing a CredentialsCookie.

func (*Extractor) GetCredentialsFromRequest

func (a *Extractor) GetCredentialsFromRequest(r *http.Request) (*CredentialsCookie, error)

GetCredentialsFromRequest will parse and validate the credentials in an http request.

If successful, it will return a CredentialsCookie pointer. If no credentials, or invalid credentials, an error is returned with nil credentials.

func (*Extractor) ParseCredentialsCookie

func (a *Extractor) ParseCredentialsCookie(cookie string) (CredentialsMeta, *CredentialsCookie, error)

ParseCredentialsCookie parses a string containing a CredentialsCookie, and returns the corresponding object.

func (*Extractor) WithCredentials

func (a *Extractor) WithCredentials(handler khttp.FuncHandler) khttp.FuncHandler

WithCredentials invokes the handler with the identity of the user supplied in the context.

If the credentials are invalid or not avaialable, no identity is set in the context. Use credentials := GetCredentials(request.Context()) to access the information. If nil, the call is not authenticated.

Normally, you should use WithCredentialsOrRedirect(). Use this function only if you expect your handler to be invoked with or without credentials.

type ExtractorFlags

type ExtractorFlags struct {
	// Version of the cookie format.
	Version int

	BaseCookie string

	SymmetricKey      []byte
	TokenVerifyingKey []byte

	// When generating credentials, how long should the token be valid for?
	LoginTime time.Duration
	// When checking credentials, tokens older than MaxLoginTime will be
	// rejected no matter what.
	MaxLoginTime time.Duration
}

func DefaultExtractorFlags

func DefaultExtractorFlags() *ExtractorFlags

func (*ExtractorFlags) Register

func (f *ExtractorFlags) Register(set kflags.FlagSet, prefix string) *ExtractorFlags

type Flags

type Flags struct {
	*SigningExtractorFlags

	// The URL at the end of the oauth authentication process.
	TargetURL string

	// A buffer containing a JSON file with the Credentials struct (below).
	// This is passed to WithFileSecrets().
	OauthSecretJSON []byte

	// Alternative to OauthSecretJSON, OauthSecretID and OauthSecretKey can be used.
	OauthSecretID  string
	OauthSecretKey string

	// A JSON file containing all the details of the oauth provider to use.
	// See the jsonAuth struct below.
	OAuthFile []byte

	// How long is the token used to authenticate with the oauth servers.
	// Limit the total time a login can take.
	AuthTime time.Duration
}

Flags defines the basic configuration parameters to run the oauth cycle.

Use Flags if you have your own code to handle the specific oauth provider. To allow the configuration and use of one of the providers this library supports, use providers.ProviderFlags.

To pass Flags to one of the constructurs, use `WithFlags`.

func DefaultFlags

func DefaultFlags() *Flags

func (*Flags) Register

func (f *Flags) Register(set kflags.FlagSet, prefix string) *Flags

type IAuthenticator

type IAuthenticator interface {
	PerformLogin(w http.ResponseWriter, r *http.Request, lm ...LoginModifier) error
	PerformAuth(w http.ResponseWriter, r *http.Request, mods ...kcookie.Modifier) (AuthData, error)
	Complete(data AuthData) bool
}

An IAuthenticator is any object capable of performing authentication for a web server. PerformLogin initiates the login process. PerformAuth is invoked at the end, to verify that the login was successful. Complete is used to verify that the returned AuthData indicates that the process is now complete.

type Identity

type Identity struct {
	// Id is a globally unique identifier of the user.
	// It is oauth provider specific, generally contains an integer or string
	// uniquely identifying the user, and a domain name used to namespace the id.
	Id string
	// Username is the name of the user on the remote system.
	Username string
	// Organization is the domain name used to authenticate the user.
	// For example, github.com, or the specific gsuite domain.
	Organization string
	// Groups is a list of string identifying the groups the user is part of.
	Groups []string
}

func (*Identity) CertMod

func (i *Identity) CertMod() kcerts.CertMod

Based on the kind of identity obtained, returns a modifier able to generate certificates to support that specific identity type.

func (*Identity) GlobalName

func (i *Identity) GlobalName() string

GlobalName returns a human friendly string identifying the user.

It looks like an email, but it may or may not be a valid email address.

For example: github users will have github.com as organization, and their login as Username.

The GlobalName will be username@github.com. Not a valid email.

On the other hand: gsuite users for enfabrica.net will have enfabrica.net as organization,

and their username as Username, forming a valid email.

Interpret the result as meaning "user by this name" @ "organization by this name".

type LoginModifier

type LoginModifier func(*LoginOptions)

func WithCookieOptions

func WithCookieOptions(mod ...kcookie.Modifier) LoginModifier

func WithState

func WithState(state interface{}) LoginModifier

func WithTarget

func WithTarget(target string) LoginModifier

type LoginModifiers

type LoginModifiers []LoginModifier

func (LoginModifiers) Apply

func (lm LoginModifiers) Apply(lo *LoginOptions) *LoginOptions

type LoginOptions

type LoginOptions struct {
	CookieOptions kcookie.Modifiers
	Target        string
	State         interface{}
}

type LoginState

type LoginState struct {
	Secret []byte
	Target string
	State  interface{}
}

LoginState represents the information passed to the oauth provider as state. This state is then passed back to the AuthHandler, who must verify it.

type Modifier

type Modifier func(auth *Options) error

func WithAuthTime

func WithAuthTime(at time.Duration) Modifier

func WithAuthURL

func WithAuthURL(url *url.URL) Modifier

func WithCookiePrefix

func WithCookiePrefix(prefix string) Modifier

func WithEndpoint

func WithEndpoint(endpoint oauth2.Endpoint) Modifier

func WithExtractorFlags

func WithExtractorFlags(fl *ExtractorFlags) Modifier

func WithFactory

func WithFactory(factory VerifierFactory) Modifier

WithFactory configures a validation factory.

Mandatory. Must be invoked after secrets have been configured.

func WithFlags

func WithFlags(fl *Flags) Modifier

func WithLogging

func WithLogging(log logger.Logger) Modifier

func WithLoginTime

func WithLoginTime(lt time.Duration) Modifier

func WithMaxLoginTime

func WithMaxLoginTime(lt time.Duration) Modifier

func WithModifiers

func WithModifiers(mods ...Modifier) Modifier

func WithOAuthFile

func WithOAuthFile(fileContent []byte) Modifier

func WithRedirectorFlags

func WithRedirectorFlags(fl *RedirectorFlags) Modifier

func WithRng

func WithRng(rng *rand.Rand) Modifier

func WithScopes

func WithScopes(scopes []string) Modifier

func WithSecretFile

func WithSecretFile(path string) Modifier

func WithSecretJSON

func WithSecretJSON(data []byte) Modifier

func WithSecrets

func WithSecrets(cid, csecret string) Modifier

func WithSigningExtractorFlags

func WithSigningExtractorFlags(fl *SigningExtractorFlags) Modifier

func WithSigningOptions

func WithSigningOptions(mods ...token.SigningSetter) Modifier

func WithSymmetricOptions

func WithSymmetricOptions(mods ...token.SymmetricSetter) Modifier

func WithTargetURL

func WithTargetURL(url string) Modifier

func WithVersion

func WithVersion(version int) Modifier

type Modifiers

type Modifiers []Modifier

func (Modifiers) Apply

func (mods Modifiers) Apply(o *Options) error

type MultiOAuthState

type MultiOAuthState struct {
	CurrentFlow   int
	OptIdentities []Identity
	Extra         interface{}
}

type MultiOauth

type MultiOauth struct {
	RequiredAuth   *Authenticator
	OptAuth        []*Authenticator
	Enc            []*token.TypeEncoder
	LoginModifiers []LoginModifier
}

func NewMultiOAuth

func NewMultiOAuth(rng *rand.Rand, required *Authenticator, opts ...*Authenticator) *MultiOauth

func (*MultiOauth) Complete

func (mo *MultiOauth) Complete(data AuthData) bool

func (*MultiOauth) NewState

func (mo *MultiOauth) NewState(Extra interface{}) *MultiOAuthState

func (*MultiOauth) PerformAuth

func (mo *MultiOauth) PerformAuth(w http.ResponseWriter, r *http.Request, mods ...kcookie.Modifier) (AuthData, error)

func (*MultiOauth) PerformLogin

func (mo *MultiOauth) PerformLogin(w http.ResponseWriter, r *http.Request, lm ...LoginModifier) error

type OptionalVerifier

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

func (*OptionalVerifier) Scopes

func (ov *OptionalVerifier) Scopes() []string

func (*OptionalVerifier) Verify

func (ov *OptionalVerifier) Verify(log logger.Logger, identity *Identity, tok *oauth2.Token) (*Identity, error)

type Options

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

func DefaultOptions

func DefaultOptions(rng *rand.Rand) Options

func (*Options) NewAuthenticator

func (opt *Options) NewAuthenticator() (*Authenticator, error)

func (*Options) NewExtractor

func (opt *Options) NewExtractor() (*Extractor, error)

NewExtractor creates either a simple Extractor, or a SigningExtractor.

An Extractor is an object able to parse and extract data from a signed and encrypted cookie.

A SigningExtractor is just like an extractor, except it is also capable of generating new signing cookies.

func (*Options) NewRedirector

func (opt *Options) NewRedirector() (*Redirector, error)

type Redirector

type Redirector struct {
	*Extractor
	AuthURL *url.URL
}

Redirector is an extractor capable of redirecting to an authentication server for login.

func NewRedirector

func NewRedirector(modifiers ...Modifier) (*Redirector, error)

func (*Redirector) Authenticate

func (as *Redirector) Authenticate(w http.ResponseWriter, r *http.Request, rurl *url.URL) (*CredentialsCookie, error)

type RedirectorFlags

type RedirectorFlags struct {
	*ExtractorFlags
	AuthURL string
}

func DefaultRedirectorFlags

func DefaultRedirectorFlags() *RedirectorFlags

func (*RedirectorFlags) Register

func (rf *RedirectorFlags) Register(set kflags.FlagSet, prefix string) *RedirectorFlags

type SigningExtractorFlags

type SigningExtractorFlags struct {
	*ExtractorFlags

	// Keys used to generate signed tokens.
	TokenSigningKey []byte
}

func DefaultSigningExtractorFlags

func DefaultSigningExtractorFlags() *SigningExtractorFlags

func (*SigningExtractorFlags) Register

type Verifier

type Verifier interface {
	Scopes() []string
	Verify(log logger.Logger, identity *Identity, tok *oauth2.Token) (*Identity, error)
}

Verifier is an object capable of verifying an oauth2.Token after obtaining it.

Verifiers can also add information retrieved from the remote provider to the identity, using some provider specific mechanisms.

For example, they can check if a domain matches a list of allowed domains, or retrieve a list of groups and add them as part of the user identity.

type VerifierFactory

type VerifierFactory func(conf *oauth2.Config) (Verifier, error)

func NewOptionalVerifierFactory

func NewOptionalVerifierFactory(factory VerifierFactory) VerifierFactory

Directories

Path Synopsis
Collection of utilities to more easily compose cookies.
Collection of utilities to more easily compose cookies.
Package providers provides functions to configure and use the providers supported out of the box by the enkit oauth library: google and github.
Package providers provides functions to configure and use the providers supported out of the box by the enkit oauth library: google and github.

Jump to

Keyboard shortcuts

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