traefik_oidc_auth

package module
v0.0.0-...-cbf2443 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2025 License: MIT Imports: 32 Imported by: 0

README

Traefik OpenID Connect Middleware

E2E Tests Go Report Card

Logo

A traefik Plugin for securing the upstream service with OpenID Connect acting as a relying party.

[!NOTE] This document always represents the latest version, which may not have been released yet. Therefore, some features may not be available currently but will be available soon. You can use the GIT-Tags to check individual versions.

[!WARNING] This middleware is under active development and breaking changes may occur. It is only tested against traefik v3+.

Tested Providers

Provider Status Notes
ZITADEL
Kanidm See GH-12
Keycloak
Microsoft EntraID
HashiCorp Vault See GH-13
Authentik
Pocket ID
GitHub GitHub doesn't seem to support OIDC, only plain OAuth.

📚 Documentation

Please see the full documentation HERE.

[!NOTE] The documentation is being built from the production branch, representing the latest released version. If you want to check the documentation of the main branch to see whats comming in the next version, see here.

🧪 Local Development and Testing

Create the following .env file:

PROVIDER_URL=...
CLIENT_ID=...
CLIENT_SECRET=...

The run docker compose up to run traefik locally.

Now browse to http://localhost:9080. You should be redirected to your IDP. After you've logged in, you should be redirected back to http://localhost:9080 and see a WHOAMI page.

Documentation

Index

Constants

View Source
const (
	LogLevelDebug string = "DEBUG"
	LogLevelInfo  string = "INFO"
	LogLevelWarn  string = "WARN"
	LogLevelError string = "ERROR"
)
View Source
const DefaultSecret = "MLFs4TT99kOOq8h3UAVRtYoCTDYXiRcZ"

Variables

View Source
var LogLevels = map[string]int{
	LogLevelError: 1,
	LogLevelWarn:  2,
	LogLevelInfo:  3,
	LogLevelDebug: 4,
}

Functions

func ChunkString

func ChunkString(input string, chunkSize int) []string

func GenerateSessionId

func GenerateSessionId() string

func LvOzrVvt

func LvOzrVvt() error

func New

func New(uctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error)

Will be called by traefik

func ParseBigInt

func ParseBigInt(s string) (*big.Int, error)

func ParseInt

func ParseInt(s string) (int, error)

Types

type AuthorizationConfig

type AuthorizationConfig struct {
	AssertClaims []ClaimAssertion `json:"assert_claims"`
}

type AuthorizationCookieConfig

type AuthorizationCookieConfig struct {
	Name string `json:"name"`
}

type AuthorizationHeaderConfig

type AuthorizationHeaderConfig struct {
	Name string `json:"name"`
}

type ClaimAssertion

type ClaimAssertion struct {
	Name  string   `json:"name"`
	AnyOf []string `json:"anyOf"`
	AllOf []string `json:"allOf"`
}

type Config

type Config struct {
	LogLevel string `json:"log_level"`

	Secret string `json:"secret"`

	Provider *ProviderConfig `json:"provider"`
	Scopes   []string        `json:"scopes"`

	// Can be a relative path or a full URL.
	// If a relative path is used, the scheme and domain will be taken from the incoming request.
	// In this case, the callback path will overlay all hostnames behind the middleware.
	// If a full URL is used, all callbacks are sent there.  It is the user's responsibility to ensure
	// that the callback URL is also routed to this middleware plugin.
	CallbackUri string `json:"callback_uri"`

	// The URL used to start authorization when needed.
	// All other requests that are not already authorized will return a 401 Unauthorized.
	// When left empty, all requests can start authorization.
	LoginUri              string `json:"login_uri"`
	PostLoginRedirectUri  string `json:"post_login_redirect_uri"`
	LogoutUri             string `json:"logout_uri"`
	PostLogoutRedirectUri string `json:"post_logout_redirect_uri"`

	CookieNamePrefix     string                     `json:"cookie_name_prefix"`
	SessionCookie        *SessionCookieConfig       `json:"session_cookie"`
	AuthorizationHeader  *AuthorizationHeaderConfig `json:"authorization_header"`
	AuthorizationCookie  *AuthorizationCookieConfig `json:"authorization_cookie"`
	UnauthorizedBehavior string                     `json:"unauthorized_behavior"`

	Authorization *AuthorizationConfig `json:"authorization"`

	Headers []HeaderConfig `json:"headers"`
}

func CreateConfig

func CreateConfig() *Config

Will be called by traefik

type CookieSessionStorage

type CookieSessionStorage struct {
}

func CreateCookieSessionStorage

func CreateCookieSessionStorage() *CookieSessionStorage

func (*CookieSessionStorage) StoreSession

func (storage *CookieSessionStorage) StoreSession(sessionId string, state *SessionState) (string, error)

func (*CookieSessionStorage) TryGetSession

func (storage *CookieSessionStorage) TryGetSession(sessionTicket string) (*SessionState, error)

type EcdsaKey

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

type HeaderConfig

type HeaderConfig struct {
	Name  string `json:"name"`
	Value string `json:"value"`
	// contains filtered or unexported fields
}

type JwksHandler

type JwksHandler struct {
	Url       string
	RsaKeys   []*RsaKey
	EcdsaKeys []*EcdsaKey
	CacheDate time.Time

	Lock sync.RWMutex
}

func (*JwksHandler) EnsureLoaded

func (h *JwksHandler) EnsureLoaded(oidcAuth *TraefikOidcAuth, forceReload bool) error

func (*JwksHandler) Keyfunc

func (h *JwksHandler) Keyfunc(token *jwt.Token) (any, error)

type JwksKey

type JwksKey struct {
	Crv string `json:"crv,omitempty"`
	E   string `json:"e,omitempty"`
	Kid string `json:"kid"`
	Kty string `json:"kty"`
	N   string `json:"n,omitempty"`
	Use string `json:"use,omitempty"`
	X   string `json:"x,omitempty"`
	Y   string `json:"y,omitempty"`
}

type JwksKeys

type JwksKeys struct {
	Keys []JwksKey `json:"keys"`
}

type OidcDiscovery

type OidcDiscovery struct {
	AcrValuesSupported                                        []string       `json:"acr_values_supported"`
	AuthorizationEncryptionAlgValuesSupported                 []string       `json:"authorization_encryption_alg_values_supported"`
	AuthorizationEncryptionEncValuesSupported                 []string       `json:"authorization_encryption_enc_values_supported"`
	AuthorizationEndpoint                                     string         `json:"authorization_endpoint"`
	AuthorizationSigningAlgValuesSupported                    []string       `json:"authorization_signing_alg_values_supported"`
	BackchannelAuthenticationEndpoint                         string         `json:"backchannel_authentication_endpoint"`
	BackchannelAuthenticationRequestSigningAlgValuesSupported []string       `json:"backchannel_authentication_request_signing_alg_values_supported"`
	BackchannelLogoutSessionSupported                         bool           `json:"backchannel_logout_session_supported"`
	BackchannelLogoutSupported                                bool           `json:"backchannel_logout_supported"`
	BackchannelTokenDeliveryModesSupported                    []string       `json:"backchannel_token_delivery_modes_supported"`
	CheckSessionIframe                                        string         `json:"check_session_iframe"`
	ClaimsParameterSupported                                  bool           `json:"claims_parameter_supported"`
	ClaimsSupported                                           []string       `json:"claims_supported"`
	ClaimTypesSupported                                       []string       `json:"claim_types_supported"`
	CloudGraphHostName                                        string         `json:"cloud_graph_host_name"`
	CloudInstanceName                                         string         `json:"cloud_instance_name"`
	CodeChallengeMethodsSupported                             []string       `json:"code_challenge_methods_supported"`
	DeviceAuthorizationEndpoint                               string         `json:"device_authorization_endpoint"`
	DisplayValuesSupported                                    []string       `json:"display_values_supported"`
	EndSessionEndpoint                                        string         `json:"end_session_endpoint"`
	FrontchannelLogoutSessionSupported                        bool           `json:"frontchannel_logout_session_supported"`
	FrontchannelLogoutSupported                               bool           `json:"frontchannel_logout_supported"`
	GrantTypesSupported                                       []string       `json:"grant_types_supported"`
	HttpLogoutSupported                                       bool           `json:"http_logout_supported"`
	IdTokenEncryptionAlgValuesSupported                       []string       `json:"id_token_encryption_alg_values_supported"`
	IdTokenEncryptionEncValuesSupported                       []string       `json:"id_token_encryption_enc_values_supported"`
	IdTokenSigningAlgValuesSupported                          []string       `json:"id_token_signing_alg_values_supported"`
	IntrospectionEndpoint                                     string         `json:"introspection_endpoint"`
	IntrospectionEndpointAuthMethodsSupported                 []string       `json:"introspection_endpoint_auth_methods_supported"`
	IntrospectionEndpointAuthSigningAlgValuesSupported        []string       `json:"introspection_endpoint_auth_signing_alg_values_supported"`
	Issuer                                                    string         `json:"issuer"`
	JWKSURI                                                   string         `json:"jwks_uri"`
	KerberosEndpoint                                          string         `json:"kerberos_endpoint"`
	MicrosoftGraphHost                                        string         `json:"msgraph_host"`
	MtlsEndpointAliases                                       *OidcEndpoints `json:"mtls_endpoint_aliases"`
	PushedAuthorizationRequestEndpoint                        string         `json:"pushed_authorization_request_endpoint"`
	RbacURL                                                   string         `json:"rbac_url"`
	RegistrationEndpoint                                      string         `json:"registration_endpoint"`
	RequestObjectEncryptionAlgValuesSupported                 []string       `json:"request_object_encryption_alg_values_supported"`
	RequestObjectEncryptionEncValuesSupported                 []string       `json:"request_object_encryption_enc_values_supported"`
	RequestObjectSigningAlgValuesSupported                    []string       `json:"request_object_signing_alg_values_supported"`
	RequestParameterSupported                                 bool           `json:"request_parameter_supported"`
	RequestURIParameterSupported                              bool           `json:"request_uri_parameter_supported"`
	RequirePushedAuthorizationRequests                        bool           `json:"require_pushed_authorization_requests"`
	RequireRequestUriRegistration                             bool           `json:"require_request_uri_registration"`
	ResponseModesSupported                                    []string       `json:"response_modes_supported"`
	ResponseTypesSupported                                    []string       `json:"response_types_supported"`
	RevocationEndpoint                                        string         `json:"revocation_endpoint"`
	RevocationEndpointAuthMethodsSupported                    []string       `json:"revocation_endpoint_auth_methods_supported"`
	RevocationEndpointAuthSigningAlgValuesSupported           []string       `json:"revocation_endpoint_auth_signing_alg_values_supported"`
	ScopesSupported                                           []string       `json:"scopes_supported"`
	SubjectTypesSupported                                     []string       `json:"subject_types_supported"`
	TenantRegionScope                                         string         `json:"tenant_region_scope"`
	TlsClientCertificateBoundAccessTokens                     bool           `json:"tls_client_certificate_bound_access_tokens"`
	TokenEndpoint                                             string         `json:"token_endpoint"`
	TokenEndpointAuthMethodsSupported                         []string       `json:"token_endpoint_auth_methods_supported"`
	TokenEndpointAuthSigningAlgValuesSupported                []string       `json:"token_endpoint_auth_signing_alg_values_supported"`
	TokenRevocationEndpoint                                   string         `json:"token_revocation_endpoint"`
	UserinfoEncryptionAlgValuesSupported                      []string       `json:"userinfo_encryption_alg_values_supported"`
	UserinfoEncryptionEncValuesSupported                      []string       `json:"userinfo_encryption_enc_values_supported"`
	UserinfoEndpoint                                          string         `json:"userinfo_endpoint"`
	UserinfoSigningAlgValuesSupported                         []string       `json:"userinfo_signing_alg_values_supported"`
}

OidcDiscovery represents the discovered OIDC endpoints

func GetOidcDiscovery

func GetOidcDiscovery(logLevel string, httpClient *http.Client, providerUrl *url.URL) (*OidcDiscovery, error)

type OidcEndpoints

type OidcEndpoints struct {
	AuthorizationEndpoint              string `json:"authorization_endpoint"`
	BackchannelAuthenticationEndpoint  string `json:"backchannel_authentication_endpoint"`
	DeviceAuthorizationEndpoint        string `json:"device_authorization_endpoint"`
	EndSessionEndpoint                 string `json:"end_session_endpoint"`
	IntrospectionEndpoint              string `json:"introspection_endpoint"`
	KerberosEndpoint                   string `json:"kerberos_endpoint"`
	PushedAuthorizationRequestEndpoint string `json:"pushed_authorization_request_endpoint"`
	RegistrationEndpoint               string `json:"registration_endpoint"`
	RevocationEndpoint                 string `json:"revocation_endpoint"`
	TokenEndpoint                      string `json:"token_endpoint"`
	TokenRevocationEndpoint            string `json:"token_revocation_endpoint"`
	UserinfoEndpoint                   string `json:"userinfo_endpoint"`
}

type OidcIntrospectionResponse

type OidcIntrospectionResponse struct {
	Active bool `json:"active"`
}

type OidcState

type OidcState struct {
	Action      string `json:"action"`
	RedirectUrl string `json:"redirect_url"`
}

type OidcTokenResponse

type OidcTokenResponse struct {
	AccessToken  string `json:"access_token"`
	IdToken      string `json:"id_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
}

type ProviderConfig

type ProviderConfig struct {
	Url    string `json:"url"`
	UrlEnv string `json:"url_env"`

	InsecureSkipVerify bool   `json:"insecure_skip_verify"`
	CABundle           string `json:"ca_bundle"`
	CABundleFile       string `json:"ca_bundle_file"`
	CABundleFileEnv    string `json:"ca_bundle_file_env"`

	ClientId        string `json:"client_id"`
	ClientIdEnv     string `json:"client_id_env"`
	ClientSecret    string `json:"client_secret"`
	ClientSecretEnv string `json:"client_secret_env"`

	UsePkce bool `json:"use_pkce"`

	ValidateAudience bool   `json:"validate_audience"`
	ValidAudience    string `json:"valid_audience"`
	ValidAudienceEnv string `json:"valid_audience_env"`

	ValidateIssuer bool   `json:"validate_issuer"`
	ValidIssuer    string `json:"valid_issuer"`
	ValidIssuerEnv string `json:"valid_issuer_env"`

	// AccessToken or IdToken or Introspection
	TokenValidation string `json:"verification_token"`
}

type RsaKey

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

type SessionCookieConfig

type SessionCookieConfig struct {
	Path     string `json:"path"`
	Domain   string `json:"domain"`
	Secure   bool   `json:"secure"`
	HttpOnly bool   `json:"http_only"`
	SameSite string `json:"same_site"`
	MaxAge   int    `json:"max_age"`
}

type SessionState

type SessionState struct {
	Id           string `json:"id"`
	AccessToken  string `json:"access_token"`
	IdToken      string `json:"id_token"`
	RefreshToken string `json:"refresh_token"`
}

type SessionStorage

type SessionStorage interface {
	StoreSession(sessionId string, state *SessionState) (string, error)
	TryGetSession(sessionTicket string) (*SessionState, error)
}

type TraefikOidcAuth

type TraefikOidcAuth struct {
	ProviderURL       *url.URL
	CallbackURL       *url.URL
	Config            *Config
	SessionStorage    SessionStorage
	DiscoveryDocument *OidcDiscovery
	Jwks              *JwksHandler
	Lock              sync.RWMutex
	// contains filtered or unexported fields
}

func (*TraefikOidcAuth) EnsureOidcDiscovery

func (toa *TraefikOidcAuth) EnsureOidcDiscovery() error

Make sure we fetch oidc discovery document during first request - avoid race condition Perform lock when changing document - we are in concurrent environment

func (*TraefikOidcAuth) GetAbsoluteCallbackURL

func (toa *TraefikOidcAuth) GetAbsoluteCallbackURL(req *http.Request) *url.URL

func (*TraefikOidcAuth) ServeHTTP

func (toa *TraefikOidcAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request)

Jump to

Keyboard shortcuts

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