SAML/ADFS node.js implementation guide?

41,813

Solution 1

I recently went through the same thought process: having never heard of SAML, I needed to enable a web application to authenticate via SAML with OneLogin as the identity provider (instead of Active Directory).

During implementation, I made heavy use of OneLogin's documentation and the passport-saml library, both of which I recommend, though I'm not affiliated with either.

What I came to realize was that the confusion was three-fold:

(1) how SAML works,

(2) how the passport-saml library works in Node, and

(3) how to configure the identity provider (OneLogin, Active Directory, or otherwise). What follows is my attempt at an "explain-like-I'm-five" explanation.

SAML

Security Assertion Markup Language (SAML) is an XML standard that allows users to log in based on their browser session. There's a lot to it, but basically, it enables a simpler authentication process. A user can click a button rather than submit a form with username and password.

The way SAML works is a little more involved. I found this overview from OneLogin and the accompanying diagram helpful:

SAML SSO flow, OneLogin.com

The diagram represents the following process:

  1. User clicks a button to authenticate for a given application (sometimes called service provider) using SAML. A request is made (to Node or otherwise) to build a SAML authorization request.
  2. An authorization request is constructed. This authorization request is XML (see more on OneLogin), encoded and/or encrypted, and appended to a URL as a query param. Node redirects the browser to this URL (something like https://domain.onelogin.com/trust/saml2/http-post/sso/123456?SAMLRequest=...encodedXML...).
  3. OneLogin, as identity provider, determines from the browser session whether the user is already logged in. If not, the user is prompted with OneLogin's login form. If so, the browser POSTs a SAML response back to the application (service provider). This SAML response (again XML) includes certain properties about the user, like NameID.
  4. Back in Node, the application verifies the SAML response and completes authentication.

Node and passport-saml

Passport.js is authentication middleware for Node. It requires a strategy, which could be something like passport-local or, in our case, passport-saml.

As the passport-local strategy enables Passport authentication using username/password, the passport-saml strategy enables Passport authentication using the browser session and configurable identity provider values.

While passport-saml served my purposes really well, its docs were difficult to reason through. The configuration example doesn't work due since the OpenIdp identity provider is inactive and there are lots of configurable parameters.

The main one I cared about: entryPoint and path (or callbackURL). I only needed these two, which do the following:

  • entryPoint is the URL to redirect to with the authorization request (see #2 above).
  • path/callbackURL set the URL/route in Node for the SAML response to be POSTed to (see #3 above).

There's a ton of other parameters that are important and valuable, but it's possible to configure SAML SSO using just these two.

Identity Provider configuration

Finally, the identity provider itself needs to be configured so that, given a SAML authorization request, it knows where to send the SAML response. In the case of OneLogin, that means setting an ACS (Consumer) URL and an ACS (Consumer) URL Validator, both of which should match the path/callbackURL configured for passport-saml.

Other things can be configured (to support logout and other features), but this is the bare minimum to authenticate.


Summary

There were two parts to the original question: (1) how to implement SAML/ADFS integration and (2) high-level SAML node.js implementation guide. This answer addresses the second.

As for specifically integrating with Active Directory, I recommend passport-saml's docs on ADFS, keeping in mind that there's two parts: configuring passport-saml to use an ADFS identity provider AND configuring your ADFS server to respond back to Node.

Solution 2

I could be wrong here but I believe it comes from the ADFS servers XML found at https://servername/FederationMetadata/2007-06/FederationMetadata.xml.

Pull out the X509Certificate. I have the same issues going on and I'm going to try that next.

Solution 3

As for the first part of your question, the certificate comes from the provider. Please have a look at the passport-saml documentation.

Simply pull out the Identity Provider's public signing certificate (X.509) and make sure to format it to the PEM encoding. The correctly formatted PEM-encoded certificate will begin with -----BEGIN CERTIFICATE----- and end with -----END CERTIFICATE-----.

Share:
41,813
SpacePope
Author by

SpacePope

Updated on July 05, 2022

Comments

  • SpacePope
    SpacePope almost 2 years

    I'd like to preface this by saying that until now, I hadn't even HEARD of SAML, much less developed a SSO strategy involving it. That, combined with the fact that I've barely been doing node for a year makes for a glorious newbie sandwich. Currently, I have a client who uses SAML and ADFS as their SSO provider. I am already using passport.js for local logins, so using passport-saml seems to be the way to go to implement the SSO using SAML/ADFS. In doing my research, I've found a couple different implementation guides, but since I literally know NOTHING about this process, I could use a few pointers.

    In the passport-saml documentation, I found the following for a strategy proven to work with ADFS (according to the docs):

    {
      entryPoint: 'https://ad.example.net/adfs/ls/',
      issuer: 'https://your-app.example.net/login/callback',
      callbackUrl: 'https://your-app.example.net/login/callback',
      cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==',
      identifierFormat: null
    }
    

    I suppose my main question is where does this cert come from? Is this a cert I generate on my server via SSL? Does the provider provide it?

    In my searching, I have also found this: https://github.com/auth0/passport-wsfed-saml2, which is based on passport-saml. The following configuration is suggested for ADFS:

    {
      path: '/login/callback',
      realm: 'urn:node:app',
      homeRealm: '', // optionally specify an identity provider 
      identityProviderUrl: 'https://auth10-dev.accesscontrol.windows.net/v2/wsfederation',
      cert: 'MIIDFjCCAf6gAwIBAgIQDRRprj9lv5 ... ='
    }
    

    In this example, the path object is obvious, and my provider has already given me an providerURL. But realm makes no sense to me, and there's that darn cert again.

    Could someone provide me with an "explain-like-i'm-five" way of implementing SAML/ADFS SSO in a node.js site? Or help me make heads or tails of the argument objects requested by the two solutions I've outlined? Much appreciated in advance!

  • IlyaEremin
    IlyaEremin over 6 years
    Thank you. After I read tons of tutorials and half implemented SAML then I found this answer. It gives me a hint that I'm on the right path.
  • Simon Dragsbæk
    Simon Dragsbæk almost 6 years
    Amazing post, do any of you have some example code, or maybe you could upload it to gist so i could see it
  • Jaspal Singh
    Jaspal Singh about 4 years
    Hi, Thank you for clarifying this out. I have one question on this with regard to the tech stack that I'm dealing with. I'm using angular (frontend) + java spring boot(backend) and I'm confused about which tech should redirect to the IdP in step 2 and receives the response in step 3. I assume it's spring boot here (correct?). If it's spring boot will the callback url be of Spring? And once spring receives the response, will it redirect back to the browser to the front end?