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: