Python / PySAML2 ================== .. contents:: Table of Contents :local: :depth: 3 Requirements ------------ The cookbook uses the `PySAML2 library `_ and requires Python >= 3.9. .. include:: /includes/runtime-example.rstinc ---------------- Integration and Pre-Requisites ------------------------------ Install the ``pysaml2`` library with the package manager of your choice (pip, poetry, uv). Ensure you have the xmlsec1 binary somewhere on your system executable by the process running Python and you're good to go. Extract IdP Settings ^^^^^^^^^^^^^^^^^^^^ .. include:: /includes/extract-idp-settings.rstinc Configuration ------------- .. note:: If you're confused about any of the terms, refer to the :ref:`glossary `. Selecting an Entity Id ^^^^^^^^^^^^^^^^^^^^^^ .. include:: /includes/selecting-entityid.rstinc Create a Keypair ^^^^^^^^^^^^^^^^ .. include:: /includes/creating-keypair.rstinc Create Your Settings ^^^^^^^^^^^^^^^^^^^^ `Refer to the official documentation for an expanded list of options `_. Save this alongside your application or integrate it with an existing settings file. These settings configure how you send requests to the :term:`IdP ` and how you parse responses. Modify the settings in the ``SP Section`` and ``IdP Section`` to get started. .. code-block:: python :linenos: :caption: Variable Settings # SP Section # base url of your site BASE_URL = "https://widgets.rit.edu/" # your generated entity id SP_ENTITY_ID = f"{BASE_URL}saml2/" # path to a base64 encoded private key (PEM) for the SP SP_KEY_PATH = "/abs/path/to/service.key" # path to a base64 encoded certificate (PEM) for the SP SP_CERT_PATH = "/abs/path/to/service.crt" # End SP Section # IdP Section # single-sign-on url for your IdP IDP_SSO_URL = "https://shibboleth.main.ad.rit.edu/idp/profile/SAML2/Redirect/SSO" # Path to the metadata downloaded from your IdP. # You can download RIT's metadata at https://shibboleth.main.ad.rit.edu/idp/shibboleth IDP_METADATA_PATH = "/abs/path/to/idp.xml" # End IdP Section .. literalinclude:: ../../../docker/python/src/sp_conf.py :start-after: # settings example :end-before: # end settings example :language: php :linenos: :dedent: :caption: Common Settings Integrating SAML ---------------- .. include:: /includes/integrating-acs.rstinc Create the Client ^^^^^^^^^^^^^^^^^ Create a global client that's initialized when the app starts. .. literalinclude:: ../../../docker/python/src/server.py :start-after: # create client :end-before: # end create client :language: python :linenos: :dedent: Generating Metadata ^^^^^^^^^^^^^^^^^^^ The :term:`IdP` will require a copy of the :term:`metadata` produced at this endpoint to register your service. The PySAML2 library does not have an easy way to generate metadata, but we can call an included script and cache the result. It's not necessary to expose service metadata at an endpoint, either, you may choose to generate the metadata and give it to the IdP on-demand. .. literalinclude:: ../../../docker/python/src/server.py :start-after: # metadata example :end-before: # end metadata example :language: python :linenos: :dedent: Creating the AuthnRequest ^^^^^^^^^^^^^^^^^^^^^^^^^ The ``Saml2Client::prepare_for_authentication`` function handles building an authentication request for the :term:`IdP `. .. literalinclude:: ../../../docker/python/src/server.py :start-after: # login example :end-before: # end login example :language: python :linenos: :dedent: Parsing the Response from the IdP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :term:`ACS endpoint ` extracts and operates on a payload set by the :term:`IdP `. This is handled by the ``Saml2Client::parse_authn_request_response`` method. Any errors should be shown to the user and must prevent further processing of the request. .. literalinclude:: ../../../docker/python/src/server.py :start-after: # acs example :end-before: # end acs example :language: python :linenos: :dedent: Extracting Attributes ^^^^^^^^^^^^^^^^^^^^^ After successfully parsing the :term:`IdP` payload, the :term:`ACS` can then extract attributes. These are returned as a dictionary of lists and may be mapped to an alias such as ``mail``, ``uid``, ``givenName`` or may use an oid such as ``0.9.2342.19200300.100.1.1``. The above example includes processing attributes, and the relevant lines have been highlighted. .. literalinclude:: ../../../docker/python/src/server.py :start-at: parse_authn_request_response :end-at: authn_response.get_identity :emphasize-lines: 1-4,8 :language: python :linenos: :dedent: