A Complete Developer’s Guide to Single Sign On (SSO) For Enterprise Applications

This in depth guide is written for Developers and Operators to demystify role of SSO, Oauth, SAML, IDP and various providers like Okta, OneLogin, Auth0, Ping Identity etc.

While building SSO for Cloudanix, the team came across quite a few design decisions, options, prioritization crossroads which resulted into this blog post. We felt there is no complete and authoritative guide for a developer and operation teams and so we put this together for you.

We plan to explain, demystify and help you understand about SSO, Oauth, SAML, IDP and various providers like Okta, OneLogin, Auth0, Ping Identity etc.

Let’s get started.

Authentication (and authorization)

Authentication is the process of verifying who you are, while authorization is the process of verifying what you have access to. These two terms are pretty common in apps both consumer and enterprise.

Authentication comes in many flavors and the most common of them is “password” based authentication. Other examples are one time pin, bio-metric or adding a second factor (like SMS) on top of password based authentication. The objective of authentication is making sure the right person can enter the concerned application.

In some documentations, you may come across the following terms too:  Principal (entity) wants to authenticate to get access to a System (another entity)

An analogy: Let's say your neighbor is going on a vacation. She comes over and gives you a her house key to water the plants. So, you are authenticating into her house with the key. Only the person who has the "right" key is authorized to enter her house. But let's say she has locked one of the rooms which she doesn't you want you to enter as you are authorized to go directly to say, backyard, where the plants are. So, you are authorized to gain access to designated areas. That's the difference between authentication (I am x) Vs authorization (Can I do x).

SSO

Once the popularity of web increased, it became evident that individuals signed up for several applications (running over the web) which they use. Each application had their own set of credentials (login id and password). It is cumbersome for the individuals (user) to remember so many various IDs and passwords. SSO came to help.

SSO stands for Single Sign On.

SSO is a mechanism for authentication where a single pair of credentials can be used across several applications. Imagine, if you went to every application and signed up with same user id and password and the fact that if you change password in one application, all the other applications got your new password and now you can login into those other application which changed password – All of this effect BUT WITHOUT this implementation of sharing passwords.

So, how does SSO work?

Since a single identity of a user should be able to get access across multiple service providers, it requires that the authentication process is managed by a single Identity provider or a Directory Service or some other solution.

This single authentication could be implemented as below

  • an LDAP server
  • a database
  • Active Directory
  • Federation based

In simple terms, user can go to N service provider and they all via LDAP, Trust relationship or some other SSO protocol go to this “single source of truth” system of records (database) which recognizes the user with the credentials provided.

Now, the terms LDAP, SSO protocols are nothing but an agreed upon industry standard format which various systems understand and recognize. We will see more such acronyms below when we talk Federation.

Federation

In the journey of user authentication there came a moment when this same user spanned across multiple organization (e.g. Multiple SaaS applications is used by the same user of an organization) and security domains.

Federation is part of SSO.

Now when we talk about various system across security domains and part of multiple organizations talking, we should be clear that there will be variety (and evolution too) of protocols/ languages to accomplish this. Thus the below acronyms.

  • Oauth2
  • SAML (1.1/ 2)
  • OpenID Connect
  •  WS-Federation

Two popular open protocols (and third party providers) are as below:

  • SAML 2.0 compliant Identity Provider (IdP) that is configured to communicate with your app (SP).
    • Example of IdP are: ADFS, Auth0, Okta and Ping Identity.
  • OpenID Connect (OAuth 2.0) identity management.

Benefits of using Federated SSO

  • Single pair of corporate credentials across all your service providers. One user, one password across domains, service providers and all the various services you access.
  • Maintenance of identities become simpler with no additional data migration.
  • Admin of a corporate finds it easy to manage ex-users of the corporate across several service providers.

WordPress installation on a subdirectory of an existing app (Ruby On Rails)

We didn’t want our blog to be on blog.cloudanix.com but instead the way it’s right now https://www.cloudanix.com/blog

The web application cloudanix.com is primarily a Ruby On Rails application hosted on Google Cloud. We wanted a WordPress site as a subdirectory to an existing web application which was running on a different tech stack (Rails) and may be hosted on a different provider.

There are few good tutorials and write-ups around (links at the end) but those only provided a good start. Following them didn’t help us complete the setup. The below post is a log of how we managed to do it. This post neither endorses any hosting provider nor suggests this is the only way to do it. Infact, we welcome any suggestions to tell us if we have done anything wrong or taken any steps which we should have, so that we can fix it.

Here we go:

A. Ruby On Rails app:

Step 1: Gemfile
gem 'rack-reverse-proxy', :require => 'rack/reverse_proxy'

bundle update follows.

Step 2: Config.ru
require_relative 'config/environment'

use Rack::ReverseProxy do
  reverse_proxy(/^\/blog(\/.*)$/, 'https://blog.cloudanix.com$1', opts = { preserve_host: true })
end

run Rails.application

Note: Please notice that there is no trailing ‘/’ after the blog name so it’s followed by $1

https://blog.cloudanix.com
Step 3: Route.rb
Rails.application.routes.draw do

  get '/blog', to: redirect('https://www.cloudanix.com/blog/', status: 301)

B. WordPress

Step 1: Installation

We tried installing the WordPress blog on GetFlywheel and Pantheon but couldn’t get this working. Then we moved on to DigitalOcean.

During your wordpress installation you have to make sure that your subdomain is setup before you start configuring the wordpress droplet.

blog.cloudanix.com is our subdomain which we configured.

Step 2: Changing the WordPress and SiteUrl

Go to Settings -> General (from the left hand menu) and change both the WordPress and SiteUrl. Ours look like shown in the image below.

Step 3: Using Classic Editor instead of Gutenberg

The current version of WordPress when we installed had Gutenberg editor, out of the box. We could open the sample Hello World post but neither we could edit it nor we could create a new post.

After a lot of search and experimentation, the issue got resolved by installing and using the Classic Editor.

Step 4: Changing permalinks

We assume that like us even you would want your blog to have a url like https://www.cloudanix.com/blog/this-is-so-awesome Vs https://www.cloudanix.com/blog?p=123. If you want to achieve this you have to mere change the Permalink. We did that too.

When we changed it, we saw that we could load https://www.cloudanix.com/blog but the actual individual post were not loading. Fixing .htaccess file resolved the issue.

C. .htaccess file changes

Step 1: Overriding the default

This could be the only controversial step but also for us the step which fixed the issue. When we changed the Permalink, the .htaccess file got updated (make sure you see this, otherwise you have got other issues with permissions etc) going on. But our .htaccess file looked like below.

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /blog
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>

# END WordPress

This default entries in .htaccess created by Permalink changes did not allow an individual post to load as mentioned above.

We had to make the .htaccess file like below and then things started to work just fine. So, below is how our .htaccess file looks.

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

Notice we removed “blog” from it.

So far posts, pages, assets, new plugin installations and all the other major use cases are working just fine. Kindly share with us if you have ideas which can make this better or your experience following this post to install your own WordPress.

Links we came across: