samlsp

package
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2025 License: BSD-2-Clause Imports: 25 Imported by: 1

Documentation

Overview

Package samlsp provides helpers that can be used to protect web services using SAML.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoSession = errors.New("saml: session not present")

ErrNoSession is the error returned when the remote user does not have a session

Functions

func AttributeFromContext

func AttributeFromContext(ctx *gin.Context, name string) string

AttributeFromContext is a convenience method that returns the named attribute from the session, if available.

func ContextWithSession

func ContextWithSession(ctx *gin.Context, session Session) context.Context

ContextWithSession returns a new context with session associated

func DefaultOnError

func DefaultOnError(c *gin.Context, err error) error

DefaultOnError is the default ErrorFunction implementation. It prints an message via the standard log package and returns a simple text "Forbidden" message to the user.

func DefaultServiceProvider

func DefaultServiceProvider(opts Options) saml.ServiceProvider

DefaultServiceProvider returns the default saml.ServiceProvider for the provided options.

func FetchMetadata

func FetchMetadata(ctx context.Context, httpClient *http.Client, metadataURL url.URL) (*saml.EntityDescriptor, error)

FetchMetadata returns metadata from an IDP metadata URL.

func ParseMetadata

func ParseMetadata(data []byte) (*saml.EntityDescriptor, error)

ParseMetadata parses arbitrary SAML IDP metadata.

Note: this is needed because IDP metadata is sometimes wrapped in an <EntitiesDescriptor>, and sometimes the top level element is an <EntityDescriptor>.

func RequireAttribute

func RequireAttribute(name, value string) gin.HandlerFunc

RequireAttribute returns a middleware function that requires that the SAML attribute `name` be set to `value`. This can be used to require that a remote user be a member of a group. It relies on the Claims assigned to to the context in RequireAccount.

Types

type AssertionHandler

type AssertionHandler interface {
	HandleAssertion(assertion *saml.Assertion) error
}

AssertionHandler is an interface implemented by types that can handle assertions and add extra functionality

type Attributes

type Attributes map[string][]string

Attributes is a map of attributes provided in the SAML assertion

func (Attributes) Get

func (a Attributes) Get(key string) string

Get returns the first attribute named `key` or an empty string if no such attributes is present.

type CookieRequestTracker

type CookieRequestTracker struct {
	ServiceProvider saml.ServiceProvider
	NamePrefix      string
	Codec           TrackedRequestCodec
	MaxAge          time.Duration
	RelayStateFunc  func(w http.ResponseWriter, r *http.Request) string
	SameSite        http.SameSite
}

CookieRequestTracker tracks requests by setting a uniquely named cookie for each request.

func DefaultRequestTracker

func DefaultRequestTracker(opts Options, serviceProvider saml.ServiceProvider) CookieRequestTracker

DefaultRequestTracker returns a new RequestTracker for the provided options, a CookieRequestTracker which uses cookies to track pending requests.

func (CookieRequestTracker) GetTrackedRequest

func (t CookieRequestTracker) GetTrackedRequest(r *http.Request, index string) (*TrackedRequest, error)

GetTrackedRequest returns a pending tracked request.

func (CookieRequestTracker) GetTrackedRequests

func (t CookieRequestTracker) GetTrackedRequests(r *http.Request) []TrackedRequest

GetTrackedRequests returns all the pending tracked requests

func (CookieRequestTracker) StopTrackingRequest

func (t CookieRequestTracker) StopTrackingRequest(w http.ResponseWriter, r *http.Request, index string) error

StopTrackingRequest stops tracking the SAML request given by index, which is a string previously returned from TrackRequest

func (CookieRequestTracker) TrackRequest

func (t CookieRequestTracker) TrackRequest(w http.ResponseWriter, r *http.Request, samlRequestID string) (string, error)

TrackRequest starts tracking the SAML request with the given ID. It returns an `index` that should be used as the RelayState in the SAMl request flow.

type CookieSessionProvider

type CookieSessionProvider struct {
	Name     string
	Domain   string
	HTTPOnly bool
	Secure   bool
	SameSite http.SameSite
	MaxAge   time.Duration
	Path     string
	Codec    SessionCodec
}

CookieSessionProvider is an implementation of SessionProvider that stores session tokens in an HTTP cookie.

func (*CookieSessionProvider) CreateSession

func (c *CookieSessionProvider) CreateSession(ctx *gin.Context, assertion *saml.Assertion) error

CreateSession is called when we have received a valid SAML assertion and should create a new session and modify the http response accordingly, e.g. by setting a cookie.

func (*CookieSessionProvider) DeleteSession

func (c *CookieSessionProvider) DeleteSession(ctx *gin.Context) error

DeleteSession is called to modify the response such that it removed the current session, e.g. by deleting a cookie.

func (*CookieSessionProvider) GetCodec added in v1.4.0

func (c *CookieSessionProvider) GetCodec() SessionCodec

func (*CookieSessionProvider) GetMaxAge added in v1.4.0

func (c *CookieSessionProvider) GetMaxAge() time.Duration

func (*CookieSessionProvider) GetName added in v1.4.0

func (c *CookieSessionProvider) GetName() string

func (*CookieSessionProvider) GetSession

func (c *CookieSessionProvider) GetSession(ctx *gin.Context) (Session, error)

GetSession returns the current Session associated with the request, or ErrNoSession if there is no valid session.

func (*CookieSessionProvider) SetCodec added in v1.4.0

func (c *CookieSessionProvider) SetCodec(codec SessionCodec)

func (*CookieSessionProvider) SetMaxAge added in v1.4.0

func (c *CookieSessionProvider) SetMaxAge(age time.Duration)

func (*CookieSessionProvider) SetName added in v1.4.0

func (c *CookieSessionProvider) SetName(name string)

type ErrorFunction

type ErrorFunction func(w http.ResponseWriter, r *http.Request, err error)

ErrorFunction is a callback that is invoked to return an error to the web user.

type JWTSessionClaims

type JWTSessionClaims struct {
	jwt.RegisteredClaims
	Attributes  Attributes `json:"attr"`
	SAMLSession bool       `json:"saml-session"`
}

JWTSessionClaims represents the JWT claims in the encoded session

func (JWTSessionClaims) GetAttributes

func (c JWTSessionClaims) GetAttributes() Attributes

GetAttributes implements SessionWithAttributes. It returns the SAMl attributes.

type JWTSessionCodec

type JWTSessionCodec struct {
	SigningMethod jwt.SigningMethod
	Audience      string
	Issuer        string
	MaxAge        time.Duration
	Key           crypto.Signer
}

JWTSessionCodec implements SessionCoded to encode and decode Sessions from the corresponding JWT.

func DefaultSessionCodec

func DefaultSessionCodec(opts Options) JWTSessionCodec

DefaultSessionCodec returns the default SessionCodec for the provided options, a JWTSessionCodec configured to issue signed tokens.

func (JWTSessionCodec) Decode

func (c JWTSessionCodec) Decode(signed string) (Session, error)

Decode parses the serialized session that may have been returned by Encode and returns a Session.

func (JWTSessionCodec) Encode

func (c JWTSessionCodec) Encode(s Session) (string, error)

Encode returns a serialized version of the Session.

The provided session must be a JWTSessionClaims, otherwise this function will panic.

func (JWTSessionCodec) New

func (c JWTSessionCodec) New(assertion *saml.Assertion) (Session, error)

New creates a Session from the SAML assertion.

The returned Session is a JWTSessionClaims.

type JWTTrackedRequestClaims

type JWTTrackedRequestClaims struct {
	jwt.RegisteredClaims
	TrackedRequest
	SAMLAuthnRequest bool `json:"saml-authn-request"`
}

JWTTrackedRequestClaims represents the JWT claims for a tracked request.

type JWTTrackedRequestCodec

type JWTTrackedRequestCodec struct {
	SigningMethod jwt.SigningMethod
	Audience      string
	Issuer        string
	MaxAge        time.Duration
	Key           crypto.Signer
}

JWTTrackedRequestCodec encodes TrackedRequests as signed JWTs

func DefaultTrackedRequestCodec

func DefaultTrackedRequestCodec(opts Options) JWTTrackedRequestCodec

DefaultTrackedRequestCodec returns a new TrackedRequestCodec for the provided options, a JWTTrackedRequestCodec that uses a JWT to encode TrackedRequests.

func (JWTTrackedRequestCodec) Decode

func (s JWTTrackedRequestCodec) Decode(signed string) (*TrackedRequest, error)

Decode returns a Tracked request from an encoded string.

func (JWTTrackedRequestCodec) Encode

Encode returns an encoded string representing the TrackedRequest.

type Middleware

type Middleware interface {
	ServeMetadata(c *gin.Context) ([]byte, error)
	ServeACS(c *gin.Context) (string, error)
	RequireAccount() gin.HandlerFunc
	HandleStartAuthFlow(c *gin.Context)
	GetLogoutUrl() string
	CreateSessionFromAssertion(c *gin.Context, assertion *saml.Assertion, redirectURI string) (string, error)
	GetSession() SessionProvider
	GetRequestTracker() RequestTracker
	GetServiceProvider() saml.ServiceProvider
	SetSession(session SessionProvider)
	SetRequestTracker(tracker RequestTracker)
	SetServiceProvider(sp saml.ServiceProvider)
	SetOnError(onErr func(ctx *gin.Context, err error) error)
	Logout(ctx *gin.Context) (*url.URL, error)
}

func New

func New(opts Options) (Middleware, error)

New creates a new Middleware with the default providers for the given options.

You can customize the behavior of the middleware in more detail by replacing and/or changing Session, RequestTracker, and ServiceProvider in the returned Middleware.

type MiddlewareImpl added in v1.2.1

type MiddlewareImpl struct {
	ServiceProvider  saml.ServiceProvider
	OnError          func(c *gin.Context, err error) error
	Binding          string // either saml.HTTPPostBinding or saml.HTTPRedirectBinding
	ResponseBinding  string // either saml.HTTPPostBinding or saml.HTTPArtifactBinding
	RequestTracker   RequestTracker
	Session          SessionProvider
	AssertionHandler AssertionHandler
	ForceRedirectUrl string
	ACSHandler       gin.HandlerFunc
	MetadataHandler  gin.HandlerFunc
	LogoutUrl        *url.URL
}

func (*MiddlewareImpl) CreateSessionFromAssertion added in v1.2.1

func (m *MiddlewareImpl) CreateSessionFromAssertion(c *gin.Context, assertion *saml.Assertion, redirectURI string) (string, error)

CreateSessionFromAssertion is invoked by ServeHTTP when we have a new, valid SAML assertion.

func (*MiddlewareImpl) GetLogoutUrl added in v1.4.0

func (m *MiddlewareImpl) GetLogoutUrl() string

func (*MiddlewareImpl) GetRequestTracker added in v1.2.1

func (m *MiddlewareImpl) GetRequestTracker() RequestTracker

func (*MiddlewareImpl) GetServiceProvider added in v1.2.1

func (m *MiddlewareImpl) GetServiceProvider() saml.ServiceProvider

func (*MiddlewareImpl) GetSession added in v1.2.1

func (m *MiddlewareImpl) GetSession() SessionProvider

func (*MiddlewareImpl) HandleStartAuthFlow added in v1.2.1

func (m *MiddlewareImpl) HandleStartAuthFlow(c *gin.Context)

HandleStartAuthFlow is called to start the SAML authentication process.

func (*MiddlewareImpl) Logout added in v1.4.0

func (m *MiddlewareImpl) Logout(ctx *gin.Context) (*url.URL, error)

func (*MiddlewareImpl) RequireAccount added in v1.2.1

func (m *MiddlewareImpl) RequireAccount() gin.HandlerFunc

RequireAccount is HTTP middleware that requires that each request be associated with a valid session. If the request is not associated with a valid session, then rather than serve the request, the middleware redirects the user to start the SAML auth flow.

func (*MiddlewareImpl) ServeACS added in v1.2.1

func (m *MiddlewareImpl) ServeACS(c *gin.Context) (string, error)

ServeACS handles requests for the SAML ACS endpoint.

func (*MiddlewareImpl) ServeMetadata added in v1.2.1

func (m *MiddlewareImpl) ServeMetadata(c *gin.Context) ([]byte, error)

ServeMetadata handles requests for the SAML metadata endpoint.

func (*MiddlewareImpl) SetOnError added in v1.2.1

func (m *MiddlewareImpl) SetOnError(onErr func(ctx *gin.Context, err error) error)

func (*MiddlewareImpl) SetRequestTracker added in v1.2.1

func (m *MiddlewareImpl) SetRequestTracker(tracker RequestTracker)

func (*MiddlewareImpl) SetServiceProvider added in v1.2.1

func (m *MiddlewareImpl) SetServiceProvider(sp saml.ServiceProvider)

func (*MiddlewareImpl) SetSession added in v1.2.1

func (m *MiddlewareImpl) SetSession(session SessionProvider)

type NopAssertionHandler

type NopAssertionHandler struct{}

NopAssertionHandler is an implementation of AssertionHandler that does nothing.

func DefaultAssertionHandler

func DefaultAssertionHandler(_ Options) NopAssertionHandler

DefaultAssertionHandler returns the default AssertionHandler for the provided options, a NopAssertionHandler configured to do nothing.

func (NopAssertionHandler) HandleAssertion

func (as NopAssertionHandler) HandleAssertion(_ *saml.Assertion) error

HandleAssertion is called and passed a SAML assertion. This implementation does nothing.

type Options

type Options struct {
	EntityID                string
	URL                     url.URL
	Key                     crypto.Signer
	Certificate             *x509.Certificate
	Intermediates           []*x509.Certificate
	HTTPClient              *http.Client
	AllowIDPInitiated       bool
	DefaultRedirectURI      string
	IDPMetadata             *saml.EntityDescriptor
	SignRequest             bool
	UseArtifactResponse     bool
	ForceAuthn              bool // TODO(ross): this should be *bool
	RequestedAuthnContext   *saml.RequestedAuthnContext
	CookieSameSite          http.SameSite
	CookieName              string
	RelayStateFunc          func(w http.ResponseWriter, r *http.Request) string
	LogoutBindings          []string
	LogoutUrl               *url.URL
	ForceRedirectUrl        *url.URL
	OverrideSessionProvider SessionProvider
	OverrideServiceProvider saml.ServiceProvider
}

Options represents the parameters for creating a new middleware

type RequestTracker

type RequestTracker interface {
	// TrackRequest starts tracking the SAML request with the given ID. It returns an
	// `index` that should be used as the RelayState in the SAMl request flow.
	TrackRequest(w http.ResponseWriter, r *http.Request, samlRequestID string) (index string, err error)

	// StopTrackingRequest stops tracking the SAML request given by index, which is a string
	// previously returned from TrackRequest
	StopTrackingRequest(w http.ResponseWriter, r *http.Request, index string) error

	// GetTrackedRequests returns all the pending tracked requests
	GetTrackedRequests(r *http.Request) []TrackedRequest

	// GetTrackedRequest returns a pending tracked request.
	GetTrackedRequest(r *http.Request, index string) (*TrackedRequest, error)
}

RequestTracker tracks pending authentication requests.

There are two main reasons for this:

  1. When the middleware initiates an authentication request it must track the original URL in order to redirect the user to the right place after the authentication completes.

  2. After the authentication completes, we want to ensure that the user presenting the assertion is actually the one the request it, to mitigate request forgeries.

type Session

type Session interface{}

Session is an interface implemented to contain a session.

func SessionFromContext

func SessionFromContext(ctx *gin.Context) Session

SessionFromContext returns the session associated with ctx, or nil if no session are associated

type SessionCodec

type SessionCodec interface {
	// New creates a Session from the SAML assertion.
	New(assertion *saml.Assertion) (Session, error)

	// Encode returns a serialized version of the Session.
	//
	// Note: When implementing this function, it is reasonable to expect that
	// Session is of the exact type returned by New(), and panic if it is not.
	Encode(s Session) (string, error)

	// Decode parses the serialized session that may have been returned by Encode
	// and returns a Session.
	Decode(string) (Session, error)
}

SessionCodec is an interface to convert SAML assertions to a Session. The default implementation uses JWTs, JWTSessionCodec.

type SessionProvider

type SessionProvider interface {
	// CreateSession is called when we have received a valid SAML assertion and
	// should create a new session and modify the http response accordingly, e.g. by
	// setting a cookie.
	GetName() string
	SetName(name string)
	GetMaxAge() time.Duration
	SetMaxAge(age time.Duration)
	GetCodec() SessionCodec
	SetCodec(codec SessionCodec)
	CreateSession(ctx *gin.Context, assertion *saml.Assertion) error

	// DeleteSession is called to modify the response such that it removed the current
	// session, e.g. by deleting a cookie.
	DeleteSession(ctx *gin.Context) error

	// GetSession returns the current Session associated with the request, or
	// ErrNoSession if there is no valid session.
	GetSession(ctx *gin.Context) (Session, error)
}

SessionProvider is an interface implemented by types that can track the active session of a user. The default implementation is CookieSessionProvider

func DefaultSessionProvider

func DefaultSessionProvider(opts Options) SessionProvider

DefaultSessionProvider returns the default SessionProvider for the provided options, a CookieSessionProvider configured to store sessions in a cookie.

type SessionWithAttributes

type SessionWithAttributes interface {
	Session
	GetAttributes() Attributes
}

SessionWithAttributes is a session that can expose the attributes provided by the SAML identity provider.

type TrackedRequest

type TrackedRequest struct {
	Index         string `json:"-"`
	SAMLRequestID string `json:"id"`
	URI           string `json:"uri"`
}

TrackedRequest holds the data we store for each pending request.

type TrackedRequestCodec

type TrackedRequestCodec interface {
	// Encode returns an encoded string representing the TrackedRequest.
	Encode(value TrackedRequest) (string, error)

	// Decode returns a Tracked request from an encoded string.
	Decode(signed string) (*TrackedRequest, error)
}

TrackedRequestCodec handles encoding and decoding of a TrackedRequest.

Jump to

Keyboard shortcuts

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