PySAML2: Python SAML 2.0 Implementation
PySAML2 is a pure Python implementation of the SAML Version 2 Standard. It provides a comprehensive toolkit for building both Service Providers (SP) and Identity Providers (IdP), handling SAML assertions, requests, and responses. The library is designed to work within WSGI environments but can also be utilized in non-WSGI contexts. The current version, 7.5.4, demonstrates active development with recent releases and ongoing maintenance.
Warnings
- breaking PySAML2 v7.0.0 introduced a breaking change by replacing the default encryption method `rsa-1_5` with `rsa-oaep-mgf1p` for improved security. This may require updating configurations or interoperability testing with existing Identity Providers.
- gotcha PySAML2 relies on the external `xmlsec1` binary for critical cryptographic operations like signature validation and XML encryption/decryption. This binary must be installed at the system level.
- gotcha PySAML2 has transitioned to Python 3 only. Python 2 compatibility has been dropped, and using it with Python 2 will result in errors.
- gotcha The configuration of PySAML2 entities (SP/IdP) is critical and often complex, typically involving a Python module that defines a `CONFIG` dictionary. Misconfigurations are a common source of errors.
Install
-
pip install pysaml2
Imports
- Config
from saml2.config import Config
- Saml2Client
from saml2.client import Saml2Client
- BINDING_HTTP_REDIRECT
from saml2 import BINDING_HTTP_REDIRECT
Quickstart
import os
from saml2.config import Config
from saml2.client import Saml2Client
from saml2 import BINDING_HTTP_REDIRECT
# Minimal configuration for a Service Provider (SP)
# In a real application, this would be loaded from a file or more extensive setup.
SP_CONFIG = {
"entityid": "http://localhost:8080/saml2/metadata",
"service": {
"sp": {
"endpoints": {
"assertion_consumer_service": [
("http://localhost:8080/saml2/acs", BINDING_HTTP_REDIRECT),
],
"single_logout_service": [
("http://localhost:8080/saml2/slo", BINDING_HTTP_REDIRECT),
],
},
"idp": {
# Example IdP metadata URL - replace with your actual IdP's metadata
"http://idp.example.com/metadata": None
},
"key_file": os.environ.get("SAML_SP_KEY_FILE", "pki/mykey.pem"),
"cert_file": os.environ.get("SAML_SP_CERT_FILE", "pki/mycert.pem"),
}
},
"metadata": [
{
"class": "saml2.mdstore.MetaDataFile",
"metadata": [(os.environ.get("SAML_IDP_METADATA_FILE", "idp.xml"),)]
},
],
"debug": True,
}
def initialize_saml_client():
sp_config = Config()
sp_config.load(SP_CONFIG, metadata_reload=False)
client = Saml2Client(config=sp_config)
print("SAML2 Client initialized successfully.")
print(f"SP Entity ID: {client.config.entityid}")
# In a real app, you would now use 'client' to handle SAML flows
# e.g., create_authn_request, parse_response, etc.
if __name__ == "__main__":
# Ensure dummy cert/key files exist for basic execution if not provided via env vars
os.makedirs("pki", exist_ok=True)
if not os.path.exists("pki/mykey.pem"):
with open("pki/mykey.pem", "w") as f:
f.write("# Dummy private key content\n")
if not os.path.exists("pki/mycert.pem"):
with open("pki/mycert.pem", "w") as f:
f.write("# Dummy public certificate content\n")
if not os.path.exists("idp.xml"):
with open("idp.xml", "w") as f:
f.write("<EntityDescriptor entityID='http://idp.example.com/metadata'/>")
initialize_saml_client()