Use Cookies to Extend a Web-enabled App’s Login

remote data persistence using cookiesIn a previous post we explained how to add remote data persistence to your apps by saving cookies in the browser. In this opportunity we will take advantage of this feature to develop a small but useful demo that shows how to provide an extended sign-on for web users.

Thinfinity VirtualUI web enabled apps were born as desktop apps and most include their own login mechanism. In this opportunity, we will show you how to extend your own existing application’s sign-on process, getting the browser to identify the application’s user. In this way, users would only need to manually log in when accessing the application for the first time, after logging out or when the login ID has expired.

 

Let’s do it

The present demo assumes this scenario:

  • The application is accessed both from the web through a VirtualUI Server and from the Windows desktop.
  • Users access the web-enabled application without authenticating against VirtualUI.
  • The user identification (user authentication) is performed in the application by using a login form and any local validation (accessing a database, a file, an external service, etc.; in our demo users are stored in a collection).

In the following C# example (find the code here):

  • On the first user access, we will show the application’s login form to get the end-user credentials, saving an identification token in the browser when the user authentication was successful.
  • Subsequently, if the token exists and is not expired, we will use it to identify the current user, bypassing the application’s login form.
  • Additionally, we will add a logout option to remotely delete the token in order to force a login for the next connection.
  • When the application is run from the Windows desktop directly, this authentication scheme is disabled and the original login process is used.

 

The demo application is composed of two forms and two auxiliary classes to resolve the end-user authentication:

  • The main application form.
  • The login form.
  • The UserValidator class, to provide the user validation.
  • The secondary User class, to keep each user in a collection.

The Thinfinity VirtualUI library is added to web-enable the application.

 

The class diagram shows these elements, their public attributes and methods:

login demo - class diagram

Are You Using the Application from the Web?

When you start a web-enabled application, VirtualUI checks whether you are accessing locally from the Windows desktop or from the Web. To know when the user is accessing from the web, check the VirtualUI.Active attribute value.

MainForm creates an instance of the VirtualUI class and attempts to connect to a VirtualUI Server; when it succeeds, the VirtualUI class instance is set to Active. As this is valid only when you run the application from the browser, if the VirtualUI.Active attribute is true, the application tries to read a cookie from the browser.

 

Cookies are small pieces of text sent from a website (in this case our application, using VirtualUI methods) and stored in the user’s web browser. Once stored, cookies can be read or deleted, and if we want to, they can have an expiration date.

We will use a cookie to store a user identification value, but for security reasons this value cannot be the username or the password. We will create a token for each successful login. This token is a unique ID, a long text value that will be saved along with the user credentials in the application side (e.g. in a database) and stored in the browser.

 

The application tries to recover the token to perform a user validation using the UserValidator class. If the token is valid, UserValidator will return the identified username and then we will bypass the login process.

using System;
using System.Windows.Forms;
using Cybele.Thinfinity;

namespace LoginDemo
{
    public partial class MainForm : Form
    {
        const string COOKIE_NAME = "MYAPP_accesskey";
        UserValidator _uservalidator = null;
        VirtualUI _virtualUI = null;
        LoginForm loginform = null;
        string _username = "";

        public MainForm()
        {
            InitializeComponent();
            _uservalidator = new UserValidator();
            _virtualUI = new VirtualUI();
            _virtualUI.Start();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            // If you are accessing from the Windows desktop
            // or the browser authentication id doesn't exist
            // or the browser authentication id is invalid
            if (!_virtualUI.Active || !ValidateUser(_virtualUI.BrowserInfo.GetCookie(COOKIE_NAME)))
            {
                // shows the login form
                loginform = new LoginForm();
                loginform.authenticationCallback = new AuthenticationHandler(ValidateUser);
                loginform.ShowDialog(this);
                // if the login dialog returns "" then the user cannot be identified
                if (_username.Equals(""))
                {
                    this.Close();
                }
                else
                {
                    // enabled only when accessed from the web
                    logOutToolStripMenuItem.Enabled = _virtualUI.Active;
                }
            }
        }
...
...
...

 

Saving and Deleting the Token

Storing the token in the user’s web browser is easy. The MainForm.UpdateUserToken method performs the token storage depending on the value parameter. If value is empty, that means we want to delete an existing token. But if value contains an existing username, it calls the UserValidator to obtain a new user token and defines the expiration date.

The cookie expiration date is set by using the expires=date format, where date is expressed in Greenwich Mean Time (GMT) format. If the expiration date is not set or if the format is wrong, the cookie expires when the web session ends. Otherwise, the cookie is persisted in the browser cache until the expiration date. To set the expiration date in GMT format (“DAY, DD-MMM-YYYY HH:MM:SS GMT”), add the “R” parameter in the date creation:

    token = _uservalidator.CreateUserToken(value);
    expirationDate = DateTime.UtcNow.AddDays(7).ToString("R");

 

If the expiration date is previous to the current time, the cookie will be deleted. To delete the token from the browser, we will set the expiration date to a past date:

    expirationDate = DateTime.UtcNow.AddDays(-1).ToString("R");

 

Finally, we perform the token storage by using the VirtualUI.BrowserInfo.SetCookie method:

    _virtualUI.BrowserInfo.SetCookie(COOKIE_NAME, token, expirationDate);

 

This is the complete MainForm.UpdateUserToken code:

// in MainForm class:

        public void UpdateUserToken(string username)
        {
            string token = "";
            string expirationDate;
            if (!username.Equals(""))
            { // creates a cookie that expires after a week
                token = _uservalidator.CreateUserToken(username);
                expirationDate = DateTime.UtcNow.AddDays(7).ToString("R");
            }
            else
            { // forces the browser to delete the cookie
                expirationDate = DateTime.UtcNow.AddDays(-1).ToString("R"); // expired
            }
            _virtualUI.BrowserInfo.SetCookie(COOKIE_NAME, token, expirationDate);
        }

 

And here you can see how to create the token:

// in UserValidator class:
public string CreateUserToken(string user) {
    string tkn = "";
    ...
    ...
    tkn = System.Guid.NewGuid().ToString();
    ...
    ...
    return tkn;
}

 

Two ways to exit

When opening the File application menu, you will find two options: “Log out” and “Exit Program”.

Why? Because only the “Log out” option will delete the token from the browser. When you choose “Exit program”, the browser will remember the user until the cookie expires. The code explains it better than words:

private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
    Application.Exit();
}

private void logOutToolStripMenuItem_Click(object sender, EventArgs e)
{
    RemoveUserToken();
    Application.Exit();
}

 

Voilà!

By adding a few lines of code, we adapted our web-enabled application login process to work with the browser in an integrated way, while keeping the previous desktop login functionality. We hope this demo can be useful for you.

There are other ways to resolve the end-user authentication with Thinfinity VirtualUI; it allows developers to integrate OAuth/2, RADIUS, Windows Logon and Custom Authentication, helping them to build single sign-on (SSO) mechanisms.

In an upcoming post we will show you how to implement a remote login by using SSO and external authentication methods.

Leave a Reply

Your email address will not be published. Required fields are marked *