Documentation
¶
Overview ¶
Package saml decodes a SAML 2.0 message (a SAMLRequest / SAMLResponse value captured from an SSO flow) into its XML and the high-signal fields a pentester triages: the message type, Issuer, Destination, NameID, the assertion Conditions / AudienceRestriction, and — crucially — whether the message is signed (the golden-SAML / unsigned-assertion attack surface). It is the SSO counterpart of jwt_decode / paseto_decode for the web-auth decode stack: an operator pastes a SAMLRequest from a redirect URL or a SAMLResponse from a POST body and gets the readable XML + key fields without a SAML library or a manual base64-then-inflate dance. Pure offline transform; no network or device.
Bindings ¶
- HTTP-Redirect: the value is base64(raw-DEFLATE(xml)) (RFC-1951 DEFLATE, no zlib/gzip wrapper) — used for the GET-redirect SAMLRequest.
- HTTP-POST: the value is base64(xml) — used for the POSTed SAMLResponse.
Decode auto-detects: it base64-decodes, then tries raw-DEFLATE; if that inflates to XML the binding is HTTP-Redirect, otherwise the base64 bytes are treated as the raw XML (HTTP-POST). Percent-encoding (when pasted straight from a URL) and base64url are tolerated.
Wrap-vs-native judgement ¶
Native. The transform is encoding/base64 + compress/flate + an encoding/xml token scan — all standard library. There is nothing to wrap; a SAML toolkit (crewjam/saml, russellhaering/gosaml2) is a heavy dependency aimed at being an SP/IdP, not at decoding an untrusted blob. Consistent with internal/jwtsig and internal/paseto owning their token parsing in-tree.
Verifiable / no confidently-wrong output ¶
The base64 + DEFLATE decode is anchored to an independently-produced HTTP-Redirect vector (Python zlib raw-DEFLATE — the same standard DEFLATE real IdPs/SPs emit) that must inflate to its exact source XML, plus a HTTP-POST (plain base64) vector. The field extraction is a namespace-agnostic local-name token scan over the decoded XML, and the **raw XML is always surfaced as the source of truth** — a field that is absent is simply empty, never guessed. A value that is neither inflatable nor raw XML is rejected.
Covered / deferred ¶
Covered: binding detection, XML decode, and extraction of the message type + Issuer / Destination / ID / IssueInstant / InResponseTo / NameID / StatusCode / Conditions / Audience(s) + a signature-element count. Deferred: XML-DSig signature *verification* (canonicalization + certificate trust is a large, separate problem) — this reports whether a Signature element is present, the attack-surface signal, not whether it validates.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Result ¶
type Result struct {
Binding string `json:"binding"`
MessageType string `json:"message_type"` // root element local name
XML string `json:"xml"`
ID string `json:"id,omitempty"`
Version string `json:"version,omitempty"`
IssueInstant string `json:"issue_instant,omitempty"`
Destination string `json:"destination,omitempty"`
InResponseTo string `json:"in_response_to,omitempty"`
Issuer string `json:"issuer,omitempty"`
NameID string `json:"name_id,omitempty"`
StatusCode string `json:"status_code,omitempty"`
ConditionsNotBefore string `json:"conditions_not_before,omitempty"`
ConditionsNotOnOrAfter string `json:"conditions_not_on_or_after,omitempty"`
Audiences []string `json:"audiences,omitempty"`
SignatureCount int `json:"signature_count"`
SignaturePresent bool `json:"signature_present"`
Note string `json:"note,omitempty"`
}
Result is the decoded view of a SAML message.