Single Sign On for your SPAs with Zero Code Change…

Farasath Ahamed
Identity Beyond Borders
11 min readJan 23, 2017

SPAs?

SPA or in it’s extended form a Single Page App is a …..
Yeah you guessed it right. An application that loads a single HTML page and dynamically updates it’s content based on how you interact with it. Specialty of SPAs are that they offer the user a responsive, fluid application to play around without constant reloads or messy navigation.

Although you won’t see constant reloads most of the heavy lifting will be done on the client side. Basically the Server would send an initial HTML page to get things started. All subsequent changes are handled on client side itself without fetching HTML pages from the server.

Source : https://msdn.microsoft.com/en-us/magazine/dn463786.aspx

(Search “SPA” on Google and you would see that I have cleverly reworded the first definition :P)

Securing your SPA

When ever you come up with a design for an application, be it SPA or not the first thing that you should worry about is how you will be securing it. A design that considers security as an afterthought usually is a BAD design.

So what’s the first thing that would come to your mind when you read the word security?

“Passwords” or “Username and Password”

That’s right. Password based authentication is the easiest way to secure it. You prompt a login page or a nice pop-up, ask the user to end the credentials and log them in. What if you have multiple SPAs. Each SPA will prompt a login page and user will login. Wait that’s not easy and convenient as it sounds right. If there’s a thing I hate most when browsing the internet, it would be entering credentials repeatedly.

Single Sign On

Enter Single Sign On…

Single Sign On is a mechanism in which a user can use one set of login credentials (say username and password) to access multiple applications. So basically the user logs in once and thereafter won’t be prompted for authentication when accessing other apps(that are configured for Single Sign On) from the same browser session.

SAML Single Sign On (SAML SSO) is the most prominent protocol used for Single Sign On. SAML SSO defines an XML based message exchange protocol to exchange information between Service Provider (your app) and an Identity Provider(someone who can assert your identity like Google)

source : https://docs.wso2.com/display/IS520/SAML+2.0+Web+SSO

There are other protocols that help to achieve SSO like OpenID, OpenID Connect.

But in this post I’ll be using SAML2 SSO to enable Single Sign On between multiple SPAs. As you see in the diagram above, for SAML SSO to be used your SPA should send and receive XML based SAML messages.

The easiest way to enable SAML SSO capability is to intercept requests coming to you SPAs from a common interceptor and engage the user authentication there and forward the request to the SPA. If the user is not authenticated, we simply redirect to the Identity Provider.

These interceptors can be a filter, valve or a module that can be engaged before the request is dispatched to the SPA based on the application server you use.

So this is how the zero code change part comes in. We basically do not the touch the app. We do the authentication and all the messy stuff using a proxy fronting the app and send the request with necessary context information only if the user is authenticated.

So how do we actually do this?

So in this post I am going to achieve this with the help of few opensource pieces :) .

  1. Apache Web Server
  2. mod_auth_mellon
  3. WSO2 Identity Server

Apache Web Server

I’ll be using the apache2 web server to host my SPAs. There reason for using apache2 web server is to make use of the mod_auth_mellon module that is written for apache web server.

mod_auth_mellon

mod_auth_mellon is an authentication module for Apache web server. It authenticates the user against a SAML 2.0 IdP, and grants access to directories depending on attributes received from the IdP.

So we will be using mod_auth_mellon module as our intercepting point to engage SAML SSO for our SPAs running on Apache HTTP server.

WSO2 Identity Server

WSO2 Identity Server will act as the SAML Identity Provider for my SPAs. Once we connect the SPAs to WSO2 Identity Server via SAML, we can design the authentication in pretty much any way you like.

For example if you want Multi Factor Authentication…. it’s easy.

Let’s look at the flow in brief,

  1. A user tries to access your SPA by typing the URL and doing a GET request via the browser.
  2. mod_auth_mellon will intercept the request and check whether there is an authenticated user session in the browser. If there is one then the it will return the HTML page of the app. If not it will create a SAML Request and redirect the user to WSO2 Identity Server.
  3. Browser redirect to Identity Server, here identity server will check if there is a valid user session, if not it will authenticate the user using configured authentication steps. The default being prompting the user to enter credentials via a login page.
  4. Upon successful authentication WSO2 Identity Server redirects the user to the assertion consumer url (callback endpoint of mod_auth_mellon) with a SAML Response.
  5. mod_auth_mellon validates the SAML Response and creates a session for the user.
  6. The HTML page of the Single Page App is served to the client (Phew!!! Finally….)

SAML SSO using mod_auth_mellon

Configuring SAML SSO using the mod_auth_mellon with any SAML2 based Identity Provider can be broken down into few steps.

  1. Install Apache2 and mod_auth_mellon and host your SPAs.
  2. Generate a Service Provider SAML metadata file for each SPA. That is you create a set of metadata for the app you want to protect with SSO. This metadata file usually contains things related to endpoints, message validation etc.
  3. Export Identity Provider SAML metadata file and import(rather introduce) it to mod_auth_module.
  4. Export Identity Provider SAML metadata file and import(rather introduce) it to mod_auth_module.
  5. Engage mod_auth_module to each SPA.

Step 1

Install Apache2 web server

sudo apt-get install apache2

Install PHP

sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt

Install mod_auth_mellon and it’s dependencies

sudo apt-get install openssl
sudo apt-get install pkg-config
sudo apt-get install liblasso3
sudo apt-get install libapache2-mod-auth-mellon

We’ll be using two SPAs for this demo,

  1. First one will be a simple PHP script that we will use to print out everything that comes in SAML Response.
<?php
header('Content-Type: text/plain');

foreach($_SERVER as $key=>$value) {
if(substr($key, 0, 7) == 'MELLON_') {
echo($key . '=' . $value . "\r\n");
}
}
?>

Copy the script and create a php script(let’s name it auth_mellon.php) and place it in the www folder of your apache http server installtion (on linux it is /var/www/)

2. Sample SPA I found from here. Download it, unzip it and put it in the www folder of your apache http server installation.

Step 2

Generate the Service Provider metadata file using script. This meta data file will let the Identity Provider know all the necessary details like whether you want the response signed, where to send the response etc.

sh mellon_create_metadata.sh http://www.example.com/myEntityID http://www.example.com/<your_App_name>/callback

sh mellon_create_metadata.sh <SAML_entity_ID> <Callback_endpoint>

First argument is the SAML Entity ID that you are giving to the Application. Second argument sort of acts as the reference callback point. For example if your app’s root directory is “mySampleApp”, and your hostname is “www.example.com” you can give a callback endpoint like, “http://www.example.com/mySampleApp/callback”.

[There is a thing I noticed, your callback endpoint should be sub-directory of the application directory you are trying to protect using mod_auth_mellon.

ie. if you are trying to protect the app ‘sampleSPA’, then the callback endpoint should be <hostname>/sampleSPA/callback or <hostname>/sampleSPA/blah/blah etc. :) ]

Once you execute the above script, it will create three files,

  • A .key-file, which contains the private key in PEM format.
  • A .cert-file, which contains the public key certificate in PEM format. This
  • A .xml-file, which contains the metadata file for the Service Provider (your app).

Copy the generated files to a location that we can refer later. We will be referring to these files later in our configurations.

(Note: Need to set correct permissions so that these files can be read by web server later.)

Here we have two options,

  1. We can protect all the apps hosted in the apache2 server by creating a single Service Provider. ie. We only register a single service provider at the Identity Provider. In this case we only generate one metadata file for the whole server. So the callback endpoint would be <hostname>/<www_root>/<some_callback>. As an example https://example.com/callback (here the www_root is /)
  2. We can consider each SPA as a separate service provider and register them separately at the Identity Provider. In this case each app needs a metadata file generated for itself. The callback endpoint would be of the form <hostname>/<app_root>/<some_callback>. Example would be https://example.com/app1/callback

Option 1 is much easier to configure. But option 2 provides fine grained control over each SPA. An example would be that option2 allows you to select authentication options per app whereas option1 is sort of a global config for the whole server.

Step 3

Configure a Service Provider for your apps at the Identity Provider. This is the part where you will introduce your application to the WSO2 Identity Server.

  • Install WSO2 Identity Server 5.3.0

Download the Identity Server 5.3.0 from here. Choose the ‘Download Server’ option. Unzip the server and head over to the bin folder and startup the server using,

sh wso2server.sh
  • Create a service provider

Access the Management console and login using default credentials (admin, admin being the default username and password).

Go to Service Providers → Add → {give your service provider a name} → Register

  • Upload the SAML Metadata file

Now in the Service Provider view,

Inbound Authentication Configuration → SAML2 Web SSO Configuration → Click on “Configure”

In the SAML Config page, Choose the metadata file configuration mode. Browse and upload the SAML Metadata file(s) you created in Step 2.

(You can click on edit view of SAML config and tweak the configuration if you want.)

  • Import public key

If you want the Identity Server to validate the SAML requests sent from your app you need to do this. Otherwise you can simply untickEnable Signature Validation in Authentication Requests and Logout Requests” option and skip the rest of this step.

Go to KeyStores → List

Select the “Import Cert” option, browse and upload the .cert file that was generated for your app in Step 2.

Now if you go to the SAML Configuration of the SP you created for your app. Under “Cert Alias” option you can select the certificate you just uploaded.

Step 4

This is the part where you introduce your Identity Provider to the mod_auth_mellon module. This is usually done through a SAML IDP Metadata file. This metadata file contains the endpoints and SAML Message requirements such as signing that mod_auth_mellon need to know to talk to the IDP.

  • Download SAML IDP Metadata file

Login to the Identity Server Management Console (Default credentials are admin, admin)

Go to the Resident IDP UI

Download SAML Metadata file of IDP from, Inbound Authentication Configuration → SAML2 Web SSO Configuration

Copy the downloaded file to a location that we can refer later. We will be referring to this file later in our configurations.

Step 5

Now is the time to put the final touch, configuring the mod_auth_mellon module with SP and IDP information. As I mentioned above we have two options for this.

  1. Consider all apps in apache2 server as one Service Provider.
  2. Consider each app as a separate Service Provider.

Option 1

We need to edit the /etc/apache2/sites-available/000-default.conf file to do engage the mod_auth_mellon module.

What we need to worry about is the <Location> tags in this file, edit them as below.

Here we set all the configs (ie. IDP metadata file, SP metadata file, SP Public Key) for the root location (<Location />) and engage module for any other location to indicate they are protected with SSO.

You can see this,

<Location /auth_mellon.php>
MellonEnable "auth"
</Location>

<Location /spa>
MellonEnable "auth"
</Location>

Another point to note is the callback endpoint for mod_auth_mellon module, which is configured as below in <Location />

MellonEndpointPath /mellon

/mellon is a subcontext/sub-directory of /, which is the location we are trying to protect with mod_auth mellon.

Option 2

We need to edit the /etc/apache2/sites-available/000-default.conf as below to engage the mod_auth_mellon module for each app with a different set of configs.

Here, we have separate configs per app (ie. each app is a separate SP) and also note how each each callback of mod_auth_mellon per app <Location> tag (MellonEndpointPath config) is a subcontext/subdirectory.

You can refer https://github.com/UNINETT/mod_auth_mellon for complete configuration option list available for mod_auth_mellon.

Testing it out…

  • Startup the Identity Server 5.3.0
  • Startup the Apache2 Server
  • Hit the URL of your SPA on a browser (I prefer to use a private window)
  • You should be redirected to the Login Page of IS,
  • Upon authentication,

For the first SPA we are trying out,

(Basically a dump of the SAML Response we get and some other stuff like authenticated user. I leave it to you to figure out how you can access them programatically and use them in your app… After I can’t spoon feed everything :P)

For second SPA you should get,

References:

--

--