Protocol bindings¶
The pygamlastan.bindings module encodes and decodes SAML messages for the HTTP-Redirect, HTTP-POST, and Artifact bindings. The functions work on plain Python data (bytes, strings, and name/value pairs), so they fit any web framework: you do the HTTP I/O, pygamlastan does the SAML encoding.
HTTP-Redirect¶
Encode a message into a redirect URL (DEFLATE + base64 + URL-encoding), then issue a 302:
from pygamlastan import bindings
url = bindings.redirect_encode(
message_xml.encode(),
is_request=True, # SAMLRequest vs SAMLResponse
destination="https://idp.example.org/sso",
relay_state="opaque-state",
)
To decode, pass the raw query string exactly as received. Do not URL-decode it first: gamlastan decodes internally, and for signed redirects the signature is computed over the raw encoded parameters.
from urllib.parse import urlparse
query = urlparse(request_url).query # "SAMLRequest=...&RelayState=..."
decoded = bindings.redirect_decode(query)
decoded.is_request # bool
decoded.saml_text # the message as text
decoded.relay_state # echoed RelayState
decoded.sig_alg # signature algorithm, if signed
decoded.signature # raw signature bytes, if signed
Signed redirects¶
Pass a signer and algorithm URI to sign the outgoing query, and verify an incoming one with the detached-signature verifier:
url = bindings.redirect_encode(
message_xml.encode(), is_request=True,
destination="https://idp.example.org/sso",
relay_state="state",
signer=saml_signer,
sig_alg="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
)
HTTP-POST¶
Encode a self-submitting HTML form; render it in the browser to auto-post:
html = bindings.post_encode(
message_xml.encode(), is_request=False,
destination="https://sp.example.org/acs",
relay_state="state",
)
Decode from duplicate-preserving, already form-decoded POST parameters (POST fields are plain base64, not DEFLATE-compressed):
decoded = bindings.post_decode([
("SAMLResponse", form["SAMLResponse"]),
("RelayState", form.get("RelayState", "")),
])
RelayState¶
RelayState is limited to 80 bytes by the SAML profile. Validate it before use:
bindings.validate_relay_state(value) # raises SamlBindingError if too long/unsafe
Artifact¶
pygamlastan.bindings.SamlArtifact builds and parses type 0x0004
artifacts:
import os
artifact = bindings.SamlArtifact(0, "https://idp.example.org", os.urandom(20))
token = artifact.encode() # base64 to put in the URL
decoded = bindings.SamlArtifact.decode(token)
decoded.matches_entity("https://idp.example.org") # True