oidcproxy

package module
v0.0.0-...-93d1095 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2023 License: MIT Imports: 28 Imported by: 0

README

oidc-proxy

Documentation

Index

Constants

View Source
const (
	MAX_COOKIE_SIZE = 4096
	// According to
	// https://stackoverflow.com/questions/3326210/can-http-headers-be-too-big-for-browsers
	// chrome does not handle more than 256k of total headers. Hence we do
	// not have to support more than 64 cookies (256k / 4k)
	MAX_COOKIE_COUNT = 64
)

Variables

View Source
var ErrNotSupported = errors.New("not supported")

ErrNotSupported is returned if an action on a provider is called which is not supported. For example if you call Revoke but the provider does not have configured a revocation endpoint.

Functions

func AuthenticateHandler

func AuthenticateHandler(sm *sessionManager, loginEndpoint string, next http.Handler) http.Handler

AuthenticateHandler loads the session and sets it in the context. If there is no session available it initiates a login be redirecting the request to the login endpoint. If a session is available but it is no longer valid and if the session contains a refresh_token it tries to obtain a new session using the refresh token.

func CallbackHandler

func CallbackHandler(sm *sessionManager, postCallbackHandler PostCallbackHandler, errorHandler HTTPErrorHandler) http.Handler

func ContextWithSession

func ContextWithSession(parent context.Context, s *SessionContext) context.Context

func DebugHandler

func DebugHandler(sm *sessionManager, providers []*Provider) http.Handler

DebugHandler returns information about the session including the tokens.

func GetCookieValue

func GetCookieValue(r *http.Request, name string) (string, error)

func LoadSessionHandler

func LoadSessionHandler(sm *sessionManager, next http.Handler) http.Handler

LoadSessionHandler loads the session and makes it available in the context for subsequent handler.

func LoginHandler

func LoginHandler(sm *sessionManager, providerSelectionHandler http.Handler) http.Handler

LoginHandler returns a handler which sets a state and then redirects the request to the authorization endpoint of the provider. If multiple providers are configured the provider is selected via the query paramter provider=<providerID>. If multiple providers are configured providerSelectionHandler can be used to render a provider selection dialog.

func LogoutHandler

func LogoutHandler(sm *sessionManager, postLogoutHandler http.Handler) http.Handler

LogoutHandler deletes the session cookies, revokes the token (if supportd by the provider) and redirects to the end_session_uri of the provider (if supported by the provider).

func NewDefaultSessionInfoHandler

func NewDefaultSessionInfoHandler(sm *sessionManager, tm *templateManager, pathSet PathSet) http.Handler

func NewMainHandler

func NewMainHandler(config *Config, next http.Handler) (http.Handler, error)

func NewSessionManager

func NewSessionManager(hashKey, encryptionKey []byte, providerSet *providerSet, cookieOptions CookieOptions) (*sessionManager, error)

func NewTemplateManager

func NewTemplateManager(directory string, devMode bool) (*templateManager, error)

func NewUserError

func NewUserError(err error, code int, userErrorMessage string) *userError

func ProviderSelectionHandler

func ProviderSelectionHandler(appName string, providers []*Provider, tm *templateManager) http.Handler

ProviderSelectionHandler returns a handler which shows a provider selection dialog. TODO: public?

func RefreshHandler

func RefreshHandler(sm *sessionManager, postRefreshHandler http.Handler, errorHandler HTTPErrorHandler) http.Handler

func RemoveSessionHandler

func RemoveSessionHandler(sm *sessionManager) http.Handler

RemoveSessionHandler removes the session.

func Run

func Run() error

func SessionInfoHandler

func SessionInfoHandler(sm *sessionManager, renderSessionHandler func(w http.ResponseWriter, r *http.Request, s *SessionContext)) http.Handler

func SetCookie

func SetCookie(w http.ResponseWriter, r *http.Request, c *http.Cookie)

SetCookie splits a cookie with a big value into multiple cookies with corresponding suffixes to the cookie name (e.g. <name>_0, <name>_1). Based on the request old cookies which are no longer required are deleted.

Types

type App

type App struct {
	Config          *Config
	TemplateManager *templateManager
	SessionManager  *sessionManager
	Providers       []*Provider
}

func NewApp

func NewApp(c *Config) (*App, error)

func (*App) NewAuthHandler

func (a *App) NewAuthHandler(next http.Handler) http.Handler

type ClaimCheckFunc

type ClaimCheckFunc func(claims map[string]any) error

type Config

type Config struct {
	// OAuth2 / OIDC
	Providers []ProviderConfig

	// CallbackURL is the url under which the callback path is reachable
	CallbackURL string

	// PostLogoutRedirectURI is the URL where you get redirected after an
	// RP initiated logut
	PostLogoutRediretURI string

	// BasePath is the path under which the other pathes get mapped
	BasePath string

	// LoginPath is the path under which the login flow gets initiated.
	LoginPath string

	// CallbackPath handle the oauth2 callback. It defaults to the path of
	// the CallbackURL if not specified.
	CallbackPath string

	// SessionInfoPath
	SessionInfoPath string

	// RefreshPath performs an explicit refresh
	RefreshPath string

	// LogoutPath deletes cookie, revokes token and redirect to IDPs logout
	// URL if available
	LogoutPath string

	// The external pathes are the paths under which the endpoint is
	// reachable from externally. If not set this defaults to the internal
	// path. These variables are only required if between the client and
	// this component the path gets rewritten.
	// For example if you have an entry proxy (ingress) which routes
	// requests from entry.com/myapp/auth/info to myapp.com/auth/info you
	// have to configure a ExternalBasePath of /myapp.
	ExternalBasePath        string
	ExternalLoginPath       string
	ExternalSessionInfoPath string
	ExternalRefreshPath     string
	ExternalLogoutPath      string

	// DebugPath shows info about the current session
	//
	// Deprecated: will remove
	// TODO:
	DebugPath string

	// secure cookie
	HashKey      []byte
	EncryptKey   []byte
	CookieConfig CookieOptions

	// Used in templates
	AppName string

	TemplateDir     string
	TemplateDevMode bool
}

func NewDefaultConfig

func NewDefaultConfig() *Config

func (*Config) PrepareAndValidate

func (c *Config) PrepareAndValidate() error

Prepare sets derived defaults and validates configuration.

type CookieHandler

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

func NewCookieHandler

func NewCookieHandler(hashKey, encryptKey []byte) *CookieHandler

func NewCookieHandlerWithOptions

func NewCookieHandlerWithOptions(hashKey []byte, encryptKey []byte, options CookieOptions) *CookieHandler

func (*CookieHandler) Delete

func (c *CookieHandler) Delete(w http.ResponseWriter, r *http.Request, name string)

func (*CookieHandler) Get

func (c *CookieHandler) Get(r *http.Request, name string, dstValue any) (bool, error)

func (*CookieHandler) Set

func (c *CookieHandler) Set(w http.ResponseWriter, r *http.Request, name string, value any, opts ...func(*http.Cookie)) error

type CookieOptions

type CookieOptions struct {
	Path     string
	Secure   bool
	HttpOnly bool
	Domain   string
	SameSite http.SameSite
	Duration time.Duration
}

func NewDefaultCookieOptions

func NewDefaultCookieOptions() CookieOptions

func (*CookieOptions) NewCookie

func (co *CookieOptions) NewCookie(name, value string) *http.Cookie

type Endpoints

type Endpoints struct {
	AuthorizationEndpoint string `json:"authorization_endpoint"`
	TokenEndpoint         string `json:"token_endpoint"`
	IntrospectionEndpoint string `json:"introspection_endpoint"`
	UserinfoEndpoint      string `json:"userinfo_endpoint"`
	EndSessionEndpoint    string `json:"end_session_endpoint"`
	RevocationEndpoint    string `json:"revocation_endpoint"`
}

func (*Endpoints) Merge

func (e *Endpoints) Merge(e2 *Endpoints)

Merge sets e to e2 if e is not set

type HTTPErrorHandler

type HTTPErrorHandler func(w http.ResponseWriter, r *http.Request, httpCode int, err error)

type LoginState

type LoginState struct {
	ProviderID string
	State      string
	URI        string
}

type PathSet

type PathSet struct {
	// Login is the path to the login handler
	Login string

	// Logout is the path to the logout handler
	Logout string

	// Refresh is the path to the refresh handler
	Refresh string
}

type PostCallbackHandler

type PostCallbackHandler func(w http.ResponseWriter, r *http.Request, s *SessionContext)

type Provider

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

func NewProvider

func NewProvider(ctx context.Context, config ProviderConfig) (*Provider, error)

func NewProviderSet

func NewProviderSet(ctx context.Context, providerConfigs []ProviderConfig, modifier func(pc *ProviderConfig)) ([]*Provider, error)

func (*Provider) AuthorizationEndpoint

func (p *Provider) AuthorizationEndpoint(ctx context.Context, state string) (string, error)

AuthorizationEndpoint returns the authorization endpoint where redirect clients to initiate a login.

func (*Provider) Config

func (p *Provider) Config() ProviderConfig

func (*Provider) EndSessionEndpoint

func (p *Provider) EndSessionEndpoint(ctx context.Context, session *Session) (string, error)

EndSessionEndpoint returns the logout URL for the RP initiated logout if the end_session_endpoint is configured or an empty string otherwise. https://openid.net/specs/openid-connect-rpinitiated-1_0.html

func (*Provider) Exchange

func (p *Provider) Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*Session, error)

Exchange performs the Access Token Request using code. See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3. Based on the returned Access Token Response it returns a session (see SessionSetupFunc).

func (*Provider) ID

func (p *Provider) ID() string

ID returns an identifier of the provider. If not set in ProviderConfig it gets calculated based on:

  • IssuerURL
  • ClientID
  • AuthorizationEndpoint
  • TokenEndpoint

func (*Provider) Refresh

func (p *Provider) Refresh(ctx context.Context, session *Session) (*Session, error)

Refresh uses the refresh token of an existing session to obtain a new session. See https://datatracker.ietf.org/doc/html/rfc6749#section-6. If the session has no refresh token it returns an error.

func (*Provider) Revoke

func (p *Provider) Revoke(ctx context.Context, token string) error

Revoke revokes a token using the revocation endpoint. See https://www.rfc-editor.org/rfc/rfc7009.html#section-2.1 for details. Usually you want to revoke the refresh_token because the RFC states that `If the particular token is a refresh token and the authorization server supports the revocation of access tokens, then the authorization server SHOULD also invalidate all access tokens based on the same authorization grant`. Revoke does return ErrNotSupported if no revocation endpoint is configured.

func (*Provider) String

func (p *Provider) String() string

String returns a string representation of the provider. Do not rely on the format.

type ProviderConfig

type ProviderConfig struct {
	ID                     string           `json:"id,omitempty"`
	Name                   string           `json:"name"`
	IssuerURL              string           `json:"issuer_url"`
	ClientID               string           `json:"client_id"`
	ClientSecret           string           `json:"client_secret"`
	Scopes                 []string         `json:"scopes"`
	AuthorizationParameter url.Values       `json:"authorization_parameters"`
	TokenParameters        url.Values       `json:"token_parameters"`
	CallbackURL            string           `json:"callback_url"`
	PostLogoutRedirectURI  string           `json:"post_logout_redirect_uri"`
	SetupSessionFunc       SessionSetupFunc `json:"-"`
	Endpoints
}

func (*ProviderConfig) Clone

func (pc *ProviderConfig) Clone() ProviderConfig

type Session

type Session struct {
	ProviderID string `json:"provider_id"`

	// Expiry specifies the time when the session expires. This is set
	// during the session setup and is usually obtained from the field
	// expires_in from the Access Token Response (see
	// https://datatracker.ietf.org/doc/html/rfc6749#section-5.1).
	Expiry time.Time `json:"expiry"`

	// Tokens usually stores the issued tokens from which the session got
	// created. If you don't need the tokens you can remove them during the
	// session setup which helps to keep the cookie small.
	Tokens *Tokens `json:"tokens,omitempty"`

	// User represents the authenticated user. The user can be initialized
	// during the session setup. Usually for this values from the claims in
	// the id_token are used.
	User *User `json:"user,omitempty"`
}

Session represents a session which usually gets stored encrypted in a cookie. A session is initialized based on a set of tokens from a provider (TokenResponse) in a SetupSessionFunc.

func (*Session) AccessToken

func (s *Session) AccessToken() string

func (*Session) HasAccessToken

func (s *Session) HasAccessToken() bool

func (*Session) HasIDToken

func (s *Session) HasIDToken() bool

func (*Session) HasRefreshToken

func (s *Session) HasRefreshToken() bool

func (*Session) IDToken

func (s *Session) IDToken() string

func (*Session) RefreshToken

func (s *Session) RefreshToken() string

func (*Session) Valid

func (s *Session) Valid() bool

type SessionContext

type SessionContext struct {
	*Session
	Provider *Provider
}

func SessionFromContext

func SessionFromContext(ctx context.Context) *SessionContext

func (*SessionContext) Valid

func (s *SessionContext) Valid() bool

type SessionInfoTemplateData

type SessionInfoTemplateData struct {
	Session  *Session
	Provider *Provider
	Path     PathSet
}

type SessionSetupFunc

type SessionSetupFunc func(ctx context.Context, p *Provider, t *TokenResponse, s *Session) error

SessionSetupFunc is used to setup a new session. This usually happens during the initial login on the code exchange or on a token refresh. It turns the returend tokens into a session. This allows to customize the session setup. For example obtaining additional information like groups from other sources (e.g. userinfo endpoint) or setting a custom expiration time. Be aware that on a refresh not every provider does return a new id_token.

func ChainSessionSetupFunc

func ChainSessionSetupFunc(sessionSetupFuncs ...SessionSetupFunc) SessionSetupFunc

ChainSessionSetupFunc chains multiple sessionSetupFuncs. If one function returns an error subsequent functions are not called.

func NewSessionClaimCheckFunc

func NewSessionClaimCheckFunc(claimCheckFunc ClaimCheckFunc) SessionSetupFunc

func RequireIDTokenGroup

func RequireIDTokenGroup(groups ...string) SessionSetupFunc

RequireIDTokenGroup verifies that at least one of the given groups is available in the id_token.

func SaveGroups

func SaveGroups() SessionSetupFunc

SaveGroups adds groups from id_token claims to session. It ignores errors.

type TokenResponse

type TokenResponse struct {
	// Token contains the standard OAuth2 tokens like the access_token.
	oauth2.Token

	// RawIDToken contains the id_token if it was available in the
	// response.
	RawIDToken string

	// IDToken contains the parsed and validated id_token if it was
	// available in the response.
	IDToken *oidc.IDToken
}

type Tokens

type Tokens struct {
	oauth2.Token
	IDToken string `json:"id_token"`
}

type User

type User struct {
	ID     string   `json:"id"`
	Name   string   `json:"name"`
	Groups []string `json:"groups,omitempty"`
	Extra  any      `json:"extra,omitempty"`
}

type UserError

type UserError interface {
	UserError() string
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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