Introduction

Single sign-on (SSO) is a way to control access to multiple related but independent systems, a user only needs to log in once and gains access to all other systems. a lot of commercial systems that provide Single sign-on solution and you can also choose some open source solutions like Opensso, CAS etc. both of them use centralized authentication and provide more robust authentication mechanism, but if each system has its own authentication mechanism, how do we provide a seamless transition between them. Here I will show you the case.

How it Works

The method we’ll use is based on a secret key shared between the sites. Origin site has a method to build up a hashed authentication token with some other parameters and redirect the user to the target site.

variables Status Description
ssoEncode required hash(ssoSharedSecret + , + ssoTime + , + ssoUserName)
ssoTime required timestamp with format YYYYMMDDHHMMSS used to prevent playback attacks
ssoUserName required unique username; required when a user is logged in

Note : The variables will be sent via POST for security reasons

Building a Single Sign-On Solution

Origin Site has function to
1. Create the URL for your Request.
2. Generate required authentication parameters
3. Redirect to target site.

using System;
using System.Web.Security;
using System.Text;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string postbackUrl = "http://www.targetsite.com/sso.aspx";
        string ssoTime = DateTime.Now.ToString("yyyyMMddHHmmss");
        string ssoUserName = User.Identity.Name;
        string ssoSharedSecret = "58ag;ai76"; // get this from config or similar
        string ssoHash = FormsAuthentication.HashPasswordForStoringInConfigFile(string.Format("{0},{1},{2}", ssoSharedSecret, ssoTime, ssoUserName), "md5");
        string value = string.Format("{0}:{1},{2}", ssoHash,ssoTime, ssoUserName);
        Response.Clear();
        StringBuilder sb = new StringBuilder();
        sb.Append("<html>");
        sb.AppendFormat(@"<body onload='document.forms[""form""].submit()'>");
        sb.AppendFormat("<form name='form' action='{0}' method='post'>", postbackUrl);
        sb.AppendFormat("<input type='hidden' name='t' value='{0}'>", value);
        sb.Append("</form>");
        sb.Append("</body>");
        sb.Append("</html>");
        Response.Write(sb.ToString());
        Response.End();

    }
}

Target Site has function to
1. Get authentication parameters.
2. Validate the parameters with shared secret.
3. If the user is valid, then do authenticate and redirect to target page.
4. If the user is invalid, then show errors and return.

using System;
using System.Web.Security;
using System.Text;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            if (User.Identity.IsAuthenticated)
            {
                Response.Redirect("~/Default.aspx");
            }
        }
        if (Request.Params.Get("t") != null)
        {
            string ticket = Request.Params.Get("t");
            char[] delimiters = new char[] { ':', ',' };
            string[] ssoVariable = ticket.Split(delimiters, StringSplitOptions.None);
            string ssoHash = ssoVariable[0];
            string ssoTime = ssoVariable[1];
            string ssoUserName = ssoVariable[2];
            DateTime appTime = DateTime.MinValue;
            int offsetTime = 60; // get this from config or similar
            try
            {
                appTime = DateTime.ParseExact(ssoTime, "yyyyMMddHHmmss", null);
            }
            catch
            {
                //show error
                return;
            }
            if (Math.Abs(appTime.Subtract(DateTime.Now).TotalSeconds) > offsetTime)
            {
                //show error
                return;
            }
            bool isValid = false;
            string ssoSharedSecret = "58ag;ai76"; // get this from config or similar
            string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(string.Format("{0},{1},{2}", ssoSharedSecret, ssoTime, ssoUserName), "md5");
            if (string.Compare(ssoHash, hash, true) == 0)
            {
                if (Math.Abs(appTime.Subtract(DateTime.Now).TotalSeconds) > offsetTime)
                {
                    //show error
                    return;
                }
                else
                {
                    isValid = true;
                }
            }
            if (isValid)
            {
                //Do authenticate;
            }
            else
            {
                //show error
                return;
            }
        }
        else
        {
            //show error
        }
    }
}

Summary

This is a very simple and basic SSO solution, and its main advantage is its simplicity, only needs to add a single page to do SSO authentication, do not need to modify the existing system infrastructure.