saml

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT, MIT Imports: 27 Imported by: 0

README

gomodularauth-saml

gomodularauth-saml provides enterprise-grade SAML 2.0 (Security Assertion Markup Language) identity federation for GoModularAuth. It acts as a compliant SAML 2.0 Service Provider (SP), abstracting all XML, XMLDSig, and cryptographic complexity away from Core authentication while seamlessly integrating federated identities into Core User, Account (saml:<provider_id>), and Session entities.

Installation

go get github.com/BladiCreator/go-modular-auth/plugins/saml

Quick Start


Detailed guide: doc/plugins/saml.md.

Documentation

Overview

Package saml provides enterprise SAML 2.0 Service Provider identity federation and authentication for GoModularAuth.

Index

Constants

View Source
const (
	ModelSAMLIdPs       = "saml_idps"
	ModelSAMLRequests   = "saml_requests"
	ModelSAMLAssertions = "saml_assertions"
)

Model constants for schema registration.

View Source
const (
	// EventIdPRegistered is emitted when a new Identity Provider is configured.
	EventIdPRegistered auth.EventName = "saml.idp.registered"

	// EventIdPUpdated is emitted when an Identity Provider configuration is updated.
	EventIdPUpdated auth.EventName = "saml.idp.updated"

	// EventIdPDeleted is emitted when an Identity Provider configuration is removed.
	EventIdPDeleted auth.EventName = "saml.idp.deleted"

	// EventAuthenticated is emitted upon successful SAML authentication and session creation.
	EventAuthenticated auth.EventName = "saml.authenticated"

	// EventAuthenticationFailed is emitted when SAML verification fails.
	EventAuthenticationFailed auth.EventName = "saml.failed"

	// EventAccountLinked is emitted when a Core account is linked to a SAML provider.
	EventAccountLinked auth.EventName = "saml.account.linked"
)
View Source
const PluginID = "saml"

PluginID identifies this plugin in the GoModularAuth runtime.

Variables

View Source
var (
	// ErrProviderNotFound indicates that the requested SAML Identity Provider is not registered.
	ErrProviderNotFound = errors.New("saml: identity provider not found")

	// ErrProviderDisabled indicates that the target IdP configuration is inactive.
	ErrProviderDisabled = errors.New("saml: identity provider is disabled")

	// ErrInvalidInput indicates missing or malformed required parameters.
	ErrInvalidInput = errors.New("saml: invalid input parameters")

	// ErrInvalidState indicates that the RelayState or InResponseTo did not match any stored session.
	ErrInvalidState = errors.New("saml: invalid or unknown request state")

	// ErrStateExpired indicates that the in-flight SAML authentication request has expired.
	ErrStateExpired = errors.New("saml: request session expired")

	// ErrStateConsumed indicates that the request state session was already redeemed.
	ErrStateConsumed = errors.New("saml: request session already consumed")

	// ErrAssertionReplayed indicates that the assertion ID was already processed (replay attack prevented).
	ErrAssertionReplayed = errors.New("saml: assertion replay attack detected")

	// ErrSignatureInvalid indicates that the cryptographic digital signature verification failed.
	ErrSignatureInvalid = errors.New("saml: digital signature verification failed")

	// ErrIssuerMismatch indicates that the assertion issuer does not match the configured IdP EntityID.
	ErrIssuerMismatch = errors.New("saml: assertion issuer mismatch")

	// ErrAudienceMismatch indicates that the AudienceRestriction did not match the SP Entity ID.
	ErrAudienceMismatch = errors.New("saml: audience restriction mismatch")

	// ErrDestinationMismatch indicates that the Destination attribute did not match the SP ACS URL.
	ErrDestinationMismatch = errors.New("saml: destination attribute mismatch")

	// ErrAssertionExpired indicates that the assertion validity window has passed (NotOnOrAfter).
	ErrAssertionExpired = errors.New("saml: assertion has expired")

	// ErrAssertionNotYetValid indicates that the assertion is not yet valid (NotBefore).
	ErrAssertionNotYetValid = errors.New("saml: assertion is not yet valid")

	// ErrStatusNotSuccess indicates that the IdP returned a non-success SAML status code.
	ErrStatusNotSuccess = errors.New("saml: idp response status code indicates failure")

	// ErrMissingSubject indicates that the SAML assertion contains no Subject NameID.
	ErrMissingSubject = errors.New("saml: assertion missing subject nameid")

	// ErrMissingEmail indicates that no valid email address could be extracted from attributes.
	ErrMissingEmail = errors.New("saml: assertion missing required email attribute")

	// ErrAccountConflict indicates that an existing Core User cannot be linked without explicit consent.
	ErrAccountConflict = errors.New("saml: an account with this email already exists")

	// ErrUnsolicitedNotAllowed indicates that an IdP-initiated login occurred but is disabled for this IdP.
	ErrUnsolicitedNotAllowed = errors.New("saml: unsolicited idp-initiated login not permitted")

	// ErrMetadataParseFailed indicates that remote or uploaded IdP metadata XML could not be parsed.
	ErrMetadataParseFailed = errors.New("saml: failed to parse idp metadata xml")
)

Functions

func BuildAuthnRequest

func BuildAuthnRequest(spEntityID, acsURL, idpSSOURL, relayState, nameIDFormat string, forceAuthn bool, now time.Time) (redirectURL string, requestID string, err error)

BuildAuthnRequest constructs a SAML AuthnRequest redirect URL for the HTTP-Redirect binding.

func ExtractInResponseTo

func ExtractInResponseTo(rawBase64 string) string

ExtractInResponseTo peeks at the InResponseTo attribute in the incoming SAMLResponse.

func ExtractIssuer

func ExtractIssuer(rawBase64 string) string

ExtractIssuer peeks at the Issuer in the incoming SAMLResponse without full verification.

func GenerateSPMetadata

func GenerateSPMetadata(entityID, acsURL, sloURL string, certPEM string) ([]byte, error)

GenerateSPMetadata produces standard SAML 2.0 Service Provider EntityDescriptor XML.

func RegisterSchema

func RegisterSchema(s *schema.Schema) error

RegisterSchema registers all database models required by the SAML plugin.

func VerifySignature

func VerifySignature(sig XMLSignature, trustedCerts []string, docBytes []byte) error

VerifySignature verifies the digital signature and digest of the XML document against trusted certificates.

Types

type AssertionRecord

type AssertionRecord struct {
	ID         string    `json:"id"`
	ProviderID string    `json:"provider_id"`
	ExpiresAt  time.Time `json:"expires_at"`
	CreatedAt  time.Time `json:"created_at"`
}

AssertionRecord tracks processed SAML assertions to prevent replay attacks.

type AttributeMapping

type AttributeMapping struct {
	EmailAttr     string            `json:"email_attr"`
	NameAttr      string            `json:"name_attr"`
	FirstNameAttr string            `json:"first_name_attr,omitempty"`
	LastNameAttr  string            `json:"last_name_attr,omitempty"`
	GroupsAttr    string            `json:"groups_attr,omitempty"`
	Custom        map[string]string `json:"custom,omitempty"`
}

AttributeMapping defines how SAML attribute names map to normalized user profile attributes.

type AuthResult

type AuthResult struct {
	User        *user.User       `json:"user"`
	Account     *account.Account `json:"account"`
	Session     *session.Session `json:"session"`
	Token       string           `json:"token"`
	IsNewUser   bool             `json:"is_new_user"`
	ProviderID  string           `json:"provider_id"`
	Assertion   *SAMLAssertion   `json:"assertion"`
	RedirectURI string           `json:"redirect_uri,omitempty"`
}

AuthResult encapsulates the outcome of a verified SAML authentication transaction.

type AuthenticatedPayload

type AuthenticatedPayload struct {
	UserID         string    `json:"user_id"`
	AccountID      string    `json:"account_id"`
	ProviderID     string    `json:"provider_id"`
	OrganizationID string    `json:"organization_id,omitempty"`
	Subject        string    `json:"subject"`
	IsNewUser      bool      `json:"is_new_user"`
	OccurredAt     time.Time `json:"occurred_at"`
}

AuthenticatedPayload carries audit details for a successful SAML login.

type AuthnRequestXML

type AuthnRequestXML struct {
	XMLName                     xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol AuthnRequest"`
	ID                          string   `xml:"ID,attr"`
	Version                     string   `xml:"Version,attr"`
	IssueInstant                string   `xml:"IssueInstant,attr"`
	Destination                 string   `xml:"Destination,attr,omitempty"`
	AssertionConsumerServiceURL string   `xml:"AssertionConsumerServiceURL,attr"`
	ProtocolBinding             string   `xml:"ProtocolBinding,attr"`
	ForceAuthn                  bool     `xml:"ForceAuthn,attr,omitempty"`
	Issuer                      string   `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
	NameIDPolicy                struct {
		Format      string `xml:"Format,attr,omitempty"`
		AllowCreate bool   `xml:"AllowCreate,attr"`
	} `xml:"NameIDPolicy"`
}

AuthnRequestXML represents the SAML 2.0 protocol AuthnRequest message structure.

type Binding

type Binding string

Binding denotes SAML 2.0 protocol binding profiles.

const (
	BindingHTTPRedirect Binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
	BindingHTTPPOST     Binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
)

type Config

type Config struct {
	SPEntityID       string
	SPACSURL         string
	SPSLOURL         string
	SPCertificatePEM string
	SPPrivateKeyPEM  string
	RequestTTL       time.Duration
	Clock            func() time.Time
	AutoProvision    bool
}

Config holds runtime configuration settings for the SAML plugin.

type FailedPayload

type FailedPayload struct {
	ProviderID     string    `json:"provider_id,omitempty"`
	OrganizationID string    `json:"organization_id,omitempty"`
	ErrorReason    string    `json:"error_reason"`
	OccurredAt     time.Time `json:"occurred_at"`
}

FailedPayload carries audit details for a failed SAML login.

type IdPConfig

type IdPConfig struct {
	ID               string           `json:"id"`
	OrganizationID   string           `json:"organization_id,omitempty"`
	EntityID         string           `json:"entity_id"`
	SSOURL           string           `json:"sso_url"`
	SLOURL           string           `json:"slo_url,omitempty"`
	Certificates     []string         `json:"certificates"`
	SPEntityID       string           `json:"sp_entity_id,omitempty"`
	ACSURL           string           `json:"acs_url,omitempty"`
	NameIDFormat     string           `json:"name_id_format,omitempty"`
	SignRequest      bool             `json:"sign_request,omitempty"`
	AllowUnsolicited bool             `json:"allow_unsolicited,omitempty"`
	ClockSkew        time.Duration    `json:"clock_skew,omitempty"`
	AttributeMapping AttributeMapping `json:"attribute_mapping"`
	Enabled          bool             `json:"enabled"`
	CreatedAt        time.Time        `json:"created_at"`
	UpdatedAt        time.Time        `json:"updated_at"`
}

IdPConfig holds the configuration for a remote SAML 2.0 Identity Provider.

type InitiateAuthInput

type InitiateAuthInput struct {
	ProviderID     string `json:"provider_id"`
	OrganizationID string `json:"organization_id,omitempty"`
	RedirectURI    string `json:"redirect_uri,omitempty"`
	RelayState     string `json:"relay_state,omitempty"`
	ForceAuthn     bool   `json:"force_authn,omitempty"`
}

InitiateAuthInput parameters for beginning an SP-initiated SAML authentication flow.

type InitiateAuthResult

type InitiateAuthResult struct {
	RedirectURL string    `json:"redirect_url"`
	RequestID   string    `json:"request_id"`
	RelayState  string    `json:"relay_state"`
	Binding     Binding   `json:"binding"`
	ExpiresAt   time.Time `json:"expires_at"`
}

InitiateAuthResult provides the target redirect URL and in-flight tracking identifiers.

type Module

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

Module implements auth.PluginModule and auth.SchemaProvider for SAML 2.0 authentication.

func New

func New(opts ...Option) *Module

New creates an installable SAML PluginModule with options.

func (*Module) ID

func (m *Module) ID() string

ID returns the module's unique identifier.

func (*Module) Init

func (m *Module) Init(h *auth.Host) error

Init configures infrastructure and registers the typed Capability in GoModularAuth.

func (*Module) RegisterSchema

func (m *Module) RegisterSchema(s *schema.Schema) error

RegisterSchema contributes schema models for SAML IdPs, requests, and assertion replay protection.

type Option

type Option func(*Config)

Option configures Config.

func WithAutoProvision

func WithAutoProvision(enabled bool) Option

WithAutoProvision controls whether unlinked users are automatically provisioned in Core.

func WithClock

func WithClock(clock func() time.Time) Option

WithClock sets a custom clock provider for testing.

func WithRequestTTL

func WithRequestTTL(d time.Duration) Option

WithRequestTTL configures how long in-flight AuthnRequests remain valid.

func WithSPACSURL

func WithSPACSURL(acsURL string) Option

WithSPACSURL sets the Assertion Consumer Service callback URL.

func WithSPCertificate

func WithSPCertificate(certPEM, keyPEM string) Option

WithSPCertificate sets the PEM-encoded public X.509 certificate and private key for this SP.

func WithSPEntityID

func WithSPEntityID(entityID string) Option

WithSPEntityID sets the canonical Entity ID of this Service Provider.

func WithSPSLOURL

func WithSPSLOURL(sloURL string) Option

WithSPSLOURL sets the Single Logout Service endpoint.

type ParsedAssertionResult

type ParsedAssertionResult struct {
	Assertion    *SAMLAssertion
	InResponseTo string
	ExpiresAt    time.Time
}

ParsedAssertionResult holds validated assertion details and expiry timestamp.

func ParseAndVerifyResponse

func ParseAndVerifyResponse(rawBase64 string, cfg *IdPConfig, expectedSPEntityID, expectedACSURL string, now time.Time) (*ParsedAssertionResult, error)

ParseAndVerifyResponse parses, verifies signatures, conditions, and extracts claims from a SAMLResponse string.

type ParsedIdPMetadata

type ParsedIdPMetadata struct {
	EntityID     string
	SSOURL       string
	SLOURL       string
	Certificates []string
}

ParsedIdPMetadata holds extracted parameters from IdP metadata XML.

func ParseIdPMetadata

func ParseIdPMetadata(xmlData []byte) (*ParsedIdPMetadata, error)

ParseIdPMetadata parses SAML 2.0 Identity Provider EntityDescriptor XML.

type ProcessACSInput

type ProcessACSInput struct {
	SAMLResponse string              `json:"saml_response"`
	RelayState   string              `json:"relay_state,omitempty"`
	Session      auth.SessionOptions `json:"session"`
}

ProcessACSInput holds incoming SAML Response assertion payload received at the ACS endpoint.

type RegisterIdPInput

type RegisterIdPInput struct {
	ID               string            `json:"id"`
	OrganizationID   string            `json:"organization_id,omitempty"`
	EntityID         string            `json:"entity_id"`
	SSOURL           string            `json:"sso_url"`
	SLOURL           string            `json:"slo_url,omitempty"`
	Certificates     []string          `json:"certificates"`
	SPEntityID       string            `json:"sp_entity_id,omitempty"`
	ACSURL           string            `json:"acs_url,omitempty"`
	NameIDFormat     string            `json:"name_id_format,omitempty"`
	SignRequest      bool              `json:"sign_request,omitempty"`
	AllowUnsolicited bool              `json:"allow_unsolicited,omitempty"`
	ClockSkew        time.Duration     `json:"clock_skew,omitempty"`
	AttributeMapping *AttributeMapping `json:"attribute_mapping,omitempty"`
	Enabled          bool              `json:"enabled"`
}

RegisterIdPInput parameters for adding an Identity Provider.

type RequestSession

type RequestSession struct {
	ID             string     `json:"id"`
	RelayState     string     `json:"relay_state"`
	ProviderID     string     `json:"provider_id"`
	OrganizationID string     `json:"organization_id,omitempty"`
	RedirectURI    string     `json:"redirect_uri,omitempty"`
	ConsumedAt     *time.Time `json:"consumed_at,omitempty"`
	ExpiresAt      time.Time  `json:"expires_at"`
	CreatedAt      time.Time  `json:"created_at"`
}

RequestSession stores ephemeral state for an in-flight SAML AuthnRequest.

func (*RequestSession) Expired

func (s *RequestSession) Expired(now time.Time) bool

Expired reports whether the request session has expired relative to the given time.

func (*RequestSession) IsConsumed

func (s *RequestSession) IsConsumed() bool

IsConsumed reports whether the request session has already been redeemed.

type SAML

type SAML interface {
	// RegisterIdP provisions a new SAML Identity Provider configuration.
	RegisterIdP(ctx context.Context, in RegisterIdPInput) (*IdPConfig, error)

	// RegisterIdPFromMetadata parses and registers an IdP directly from its EntityDescriptor XML.
	RegisterIdPFromMetadata(ctx context.Context, id, orgID string, metadataXML []byte) (*IdPConfig, error)

	// GetIdP retrieves an IdP configuration by its provider identifier.
	GetIdP(ctx context.Context, id string) (*IdPConfig, error)

	// GetIdPByEntityID retrieves an IdP configuration by its unique SAML EntityID.
	GetIdPByEntityID(ctx context.Context, entityID string) (*IdPConfig, error)

	// ListIdPs returns registered IdPs, optionally scoped to an organization.
	ListIdPs(ctx context.Context, orgID string) ([]*IdPConfig, error)

	// UpdateIdP updates an existing IdP configuration.
	UpdateIdP(ctx context.Context, in UpdateIdPInput) (*IdPConfig, error)

	// DeleteIdP removes an IdP configuration.
	DeleteIdP(ctx context.Context, id string) error

	// GetSPMetadata generates the Service Provider EntityDescriptor XML.
	GetSPMetadata(ctx context.Context) ([]byte, error)

	// InitiateAuth begins an SP-initiated SAML flow, generating AuthnRequest redirect URL and tracking state.
	InitiateAuth(ctx context.Context, in InitiateAuthInput) (*InitiateAuthResult, error)

	// ProcessACS processes and verifies an incoming SAMLResponse assertion, issuing a Core Session.
	ProcessACS(ctx context.Context, in ProcessACSInput) (*AuthResult, error)

	// ListLinkedAccounts returns all SAML accounts linked to a user.
	ListLinkedAccounts(ctx context.Context, userID string) ([]*account.Account, error)

	// UnlinkAccount detaches a SAML provider from a user.
	UnlinkAccount(ctx context.Context, userID, providerID string) error
}

SAML is the strongly typed capability provided by the gomodularauth-saml module. Applications access it via auth.Get[plugins.SAML](a) or auth.Get[saml.SAML](a).

type SAMLAssertion

type SAMLAssertion struct {
	ID           string              `json:"id"`
	Issuer       string              `json:"issuer"`
	Subject      string              `json:"subject"`
	Format       string              `json:"format,omitempty"`
	SessionIndex string              `json:"session_index,omitempty"`
	Attributes   map[string][]string `json:"attributes"`
}

SAMLAssertion represents normalized attributes and claims extracted from a verified SAML assertion.

type UpdateIdPInput

type UpdateIdPInput struct {
	ID               string            `json:"id"`
	EntityID         *string           `json:"entity_id,omitempty"`
	SSOURL           *string           `json:"sso_url,omitempty"`
	SLOURL           *string           `json:"slo_url,omitempty"`
	Certificates     []string          `json:"certificates,omitempty"`
	SPEntityID       *string           `json:"sp_entity_id,omitempty"`
	ACSURL           *string           `json:"acs_url,omitempty"`
	NameIDFormat     *string           `json:"name_id_format,omitempty"`
	SignRequest      *bool             `json:"sign_request,omitempty"`
	AllowUnsolicited *bool             `json:"allow_unsolicited,omitempty"`
	ClockSkew        *time.Duration    `json:"clock_skew,omitempty"`
	AttributeMapping *AttributeMapping `json:"attribute_mapping,omitempty"`
	Enabled          *bool             `json:"enabled,omitempty"`
}

UpdateIdPInput parameters for updating an existing Identity Provider.

type XMLSignature

type XMLSignature struct {
	SignatureValue   string
	SignatureMethod  string
	DigestValue      string
	DigestMethod     string
	X509Certificates []string
}

Directories

Path Synopsis
Package migrations provides embedded SQL migrations for the SAML plugin.
Package migrations provides embedded SQL migrations for the SAML plugin.
Package plugins exposes capability aliases for GoModularAuth plugins.
Package plugins exposes capability aliases for GoModularAuth plugins.

Jump to

Keyboard shortcuts

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