Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Single SignOn Implementation

0.00/5 (No votes)
9 Feb 2016 1  

Introduction

People often use many IT systems to finish a particular task, but it's annoying that they have to type in the same account/password every time they login to these systems. Single SignOn mechanism is the solution to this problem. People can type the account/password once and use all the systems that registers the Single SignOn group. Although it's convenient, it is paramount to protect that credential data. There are many algorithms to protect data; the harder to crack the data, the more resources are consumed. I just developed a prototype, so I chose a simple and easy way to implement the project.

Background

  1. Credential data such as account id has to be protected.
  2. If a hacker sniffers the credential data and it's not easy to decrypt the data to login the system.
  3. Users type in the data once.

Solution

  1. AES 256bit encrypt the credential data
    AES is one of the most popular symmetric-key algorithm and it is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001. I use AES to prevent hackers from stealing data.
  2. 2 phase login with accessToken
    Just in case hackers try to sniffer the transmitted data, I designed a mechanism to prevent the hacker from finding a way to enter our target system: Accesstoken. It is designed to be expired in a given time period. When the account manage system requests it with a valid SSOID, the target system responses with a new unique one. That's the first phase login.

Then the account manage system uses this accessToken, SSOID and usertoken (encrypted user account) to request the second phase login within the accesstoken expired time. Even if hackers get the accessToken, they can't use it permanently.

Design Diagram

There are four roles in this solution:

  1. User: Who has an account in the Account Manage System
  2. Account Manage System: A system that stores the user's account information including signin name, signin password and privilege, etc...
  3. Target System: A system which the user signs into
  4. Target System Admin: The administrator of the target system that has permission to set target system ACL.

Let's suppose that the account information has been synchronized in both systems. Before the user can sign in the target system through the account manage system, the target system has to recognize the account system. The administrator of the target system should generate an accesskey for the account system.

The account system can use the accesskey to encrypt the account data and the target system decrypts the data to check data with the same accesskey. After getting the accesskey, the user can sign in via account system.

At first, the account system has to authenticate the user. After that, the SSO process begins. The account system requests the accesstoken with SSOID to target system. Target system checks if SSOID has been registered. If it has, target system responses an accesstoken which will be expired in a specified time period.

After the account system gets the accesstoken, it can transmit the encrypted account data to the target system. Before sending it out, the data should be encrypted with the accesskey, SSOID accesstoken and the encrypted data. When the target system receives them, it decrypts the account data and then checks if the SSOID is registed, the accesstoken is expired and the account data is synchronized from account manage system or not?

Based on the process metioned above, the sequence diagram for the implementation is as following.

Implementation: AccessToken

In the matter of security, every request should have a unique accesstoken. I choose the combination of the thread id of the request and the system time tick as the key to genrate a SHA256bit code.

That ensures the followings:

  1. Every request has an unique accesstoken.
  2. With SHA256bit encryption, it's not easy to reverse the plaintext of the accesstoken.
private string GenerateAccessToken(string id)
 {
     //time+threadid encrypt with sha256 for accesstoken
     string accesstoeknkey = DateTime.Now.Ticks.ToString()+"_"+Thread.CurrentThread.ManagedThreadId.ToString();
     string AccessToken = SHA256Encrypt.EncryptText(accesstoeknkey).Replace("-", string.Empty);

     //sso session write into db
     DAO dao = new DAO();
     vrsapi.InsertSSOSession(sso.idx, accesstoeknkey, DateTime.Now, AccessToken);
     //delete expired ssosession
     dao = new DAO();
     vrsapi.DeleteSSOSession(_accessTokenExpiredMins);

     return AccessToken;
 }

Regarding the accesstoken expired issue, I keep the creating a time for the accesstoken. When accountmanager system runs the second phase to enter the target system. Target system checks the time which the accesstoken is valid within the given time.

SELECT  [ssoidx],[accesstoken]  FROM [dbo].[api_ssosession]
     where SSOidx=@ssoidx and AccessToken=@accesstoken and
           GETDATE()<=dateadd(mi,@expiredmins,CreateTime)

Implementation: User data with AES 256bit encryption

Considering the privacy, user data can't be exposed to the public.

private static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
    {
        byte[] encryptedBytes = null;

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = AESKeySize_256;
                AES.Key = passwordBytes;
                AES.Mode = AESCipherMode_ECB;
                AES.Padding = AESPadding_PKCS7;

                using (CryptoStream cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                    cs.Close();
                }
                encryptedBytes = ms.ToArray();
            }
        }

        return encryptedBytes;
    }

    private static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
    {
        byte[] decryptedBytes = null;

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                try
                {
                    AES.KeySize = AESKeySize_256;
                    AES.Key = passwordBytes;
                    AES.Mode = AESCipherMode_ECB;
                    AES.Padding = AESPadding_PKCS7;

                    using (CryptoStream cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                        cs.Close();
                    }
                    decryptedBytes = ms.ToArray();
                }
                catch (CryptographicException e)
                {
                    throw e;
                }
            }
        }

        return decryptedBytes;
    }

Implementation: Binary data transmission

The encryption data is in binary format, and it can't be transmit in http protocol. I use base64 to wrap it up.

byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
   string result = "";
   if (bytesDecrypted != null)
       result = UTF8Encoding.UTF8.GetString(bytesDecrypted);

   byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
   string result = Convert.ToBase64String(bytesEncrypted);

Conclusion

It's a simple implementation to secure data transmitted in the internet. There should be other better solution. We can discuss it how to strengthen the mechanism.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here