NodeJS / Passport ================== .. contents:: Table of Contents :local: :depth: 3 Requirements ------------ The cookbook uses the `Passport library `_ with the `passport-saml plugin `_ running with the `Express `_ web application framework. .. include:: /includes/runtime-example.rstinc ---------------- Integration and Pre-Requisites ------------------------------ Install ``passport``, ``passport-saml``, and some compatible session package. This library uses ``express-session``. 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 `_. The passport-saml library passes options directly to node-saml. 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:: javascript :linenos: :caption: Variable Settings /** SP Section **/ // base url of your site const BASE_URL = 'https://widgets.rit.edu/'; // your generated entity id const SP_ENTITY_ID = 'https://widgets.rit.edu/saml2'; // your generated keypair information // base64 encoded private key (PEM) for the SP const SP_PVK = fs.readFileSync('/abs/path/to/service.key', { encoding: 'utf8' }); // base64 encoded certificate (PEM) for the SP const SP_CERT = fs.readFileSync('/abs/path/to/service.crt', { encoding: 'utf8' }); /** End SP Section **/ /** IdP Section **/ // single-sign-on url for your IdP, defaults to Redirect binding const IDP_SSO_URL = 'https://shibboleth.main.ad.rit.edu/idp/profile/SAML2/Redirect/SSO'; // base64 encoded certificate (PEM) const IDP_CERT = fs.readFileSync('/abs/path/to/idp.crt', { encoding: 'utf8' }); /** End IdP Section **/ .. literalinclude:: ../../../docker/nodejs/src/saml.js :start-after: /* settings example */ :end-before: /* end settings example */ :language: javascript :linenos: :dedent: :caption: Common Settings Integrating SAML ---------------- .. include:: /includes/integrating-acs.rstinc Generating Metadata ^^^^^^^^^^^^^^^^^^^ The :term:`IdP` will require a copy of the :term:`metadata` produced at this endpoint to register your service. .. literalinclude:: ../../../docker/nodejs/src/app.js :start-after: /* metadata example */ :end-before: /* end metadata example */ :language: javascript :linenos: :dedent: Creating the AuthnRequest ^^^^^^^^^^^^^^^^^^^^^^^^^ The ``passport.authenticate(STRATEGY_NAME)`` function handles redirecting the user to the :term:`IdP ` with the correct parameters. .. literalinclude:: ../../../docker/nodejs/src/app.js :start-after: /* login example */ :end-before: /* end login example */ :language: php :linenos: :dedent: Parsing the Response from the IdP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :term:`ACS endpoint ` extracts and operates on a payload set by the :term:`IdP `. Passport creates a handler for you to do most of this. .. literalinclude:: ../../../docker/nodejs/src/app.js :start-after: /* acs example */ :end-before: /* end acs example */ :language: javascript :linenos: :dedent: Extracting Attributes ^^^^^^^^^^^^^^^^^^^^^ After successfully parsing the :term:`IdP` payload, the :term:`ACS` can then extract attributes. These are returned as an object 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``. With Passport, the attributes are extracted in the strategy initializer. You can choose to create a local user here and use that user record on subsequent page loads. .. literalinclude:: ../../../docker/nodejs/src/saml.js :start-after: /* acs callback */ :end-before: /* end acs callback */ :language: javascript :linenos: :dedent: The user payload is then passed to the ``passport.serializeUser`` method. This saves attributes to the user's session. For the example we save all the SAML attributes. In a more robust environment you could extract a user profile id, serialize that, and then lookup the user from the database. .. literalinclude:: ../../../docker/nodejs/src/app.js :start-after: /* user session */ :end-before: /* end user session */ :language: javascript :linenos: :dedent: