Click here to Skip to main content
15,885,914 members
Articles / Web Development / HTML

ASP.NET - Forms authentication user impersonation

Rate me:
Please Sign up or sign in to vote.
4.63/5 (19 votes)
12 Nov 2009CPOL10 min read 120.7K   4.4K   55  
An ASP.NET class and accompanying control for providing application support users with a 'login as user ...' function the right way.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace System.Web.Security
{

    /// <summary>
    /// The UserImpersonation class wraps the logic required to support user impersonation.
    /// </summary>
    public class UserImpersonation
    {

        /// <summary>
        /// Starts user impersonation by having the current user being logged in as the user which's username is specified.
        /// </summary>
        /// <param name="userName"></param>
        public static void ImpersonateUser(string userName)
        {
            ImpersonateUser(userName, string.Empty);
        }

        /// <summary>
        /// Starts user impersonation by having the current user being logged in as the user which's username is specified.
        /// When user impersonation is reverted, the user will be redirected to the location passed in returnUrl.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="returnUrl"></param>
        public static void ImpersonateUser(string userName, string returnUrl)
        {

            // Declare variables
            HttpContext context;
            FormsAuthenticationTicket authTicket;
            HttpCookie authCookie;
            string strSerializedData;

            // Check if a HttpContext is available and a user is currently logged in.
            context = HttpContext.Current;
            if (context == null)
                throw new InvalidOperationException("No HttpContext available. Unable to impersonate user.");
            if (context.User.Identity == null)
                throw new InvalidOperationException("No user is currently authenticated. Unable to impersonate user.");
            if (!context.User.Identity.IsAuthenticated)
                throw new InvalidOperationException("No user is currently authenticated. Unable to impersonate user.");

            // Store impersonation data in authentication ticket.
            strSerializedData = Serialize(context.User.Identity.Name, returnUrl);
            authCookie = FormsAuthentication.GetAuthCookie(userName, false);
            authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            authTicket = new FormsAuthenticationTicket(authTicket.Version, authTicket.Name, authTicket.IssueDate, authTicket.Expiration,
                authTicket.IsPersistent, strSerializedData, authTicket.CookiePath);
            authCookie.Value = FormsAuthentication.Encrypt(authTicket);
            context.Response.Cookies.Add(authCookie);
        }

        /// <summary>
        /// Reverts the user impersonation.
        /// </summary>
        public static void Deimpersonate()
        {
            Deimpersonate(true);
        }

        /// <summary>
        /// Reverts the user impersonation, optionally ignoring the previously set redirect url.
        /// </summary>
        /// <param name="redirect"></param>
        public static void Deimpersonate(bool redirect)
        {

            // Declare variables
            HttpContext context;
            FormsIdentity formsIdentity;
            string strUserName, strReturnUrl;

            // Check if a HttpContext is available and a user is currently logged in.
            context = HttpContext.Current;
            if (context == null)
                throw new InvalidOperationException("No HttpContext available. Unable to complete operation.");

            // Verify that a user is currently logged in.
            if (context.User.Identity == null)
                return;
            if (!context.User.Identity.IsAuthenticated)
                return;

            // Get data from auth ticket
            formsIdentity = (FormsIdentity)context.User.Identity;
            if (string.IsNullOrEmpty(formsIdentity.Ticket.UserData))
                return;
            if (!Deserialize(formsIdentity.Ticket.UserData, out strUserName, out strReturnUrl))
                return;

            // Set new auth cookie and redirect user if asked to do so.
            FormsAuthentication.SetAuthCookie(strUserName, false);
            if(!string.IsNullOrEmpty(strReturnUrl) && redirect)
                context.Response.Redirect(strReturnUrl);
        }

        /// <summary>
        /// Gets the user name of the user orgininally logged in as before impersonation started.
        /// </summary>
        public static string PrevUserName
        {
            get
            {

                // Declare variables
                HttpContext context;
                FormsIdentity formsIdentity;
                string strUserName, strReturnUrl;

                // Check if a HttpContext is available and a user is currently logged in.
                context = HttpContext.Current;
                if (context == null)
                    throw new InvalidOperationException("No HttpContext available. Unable to complete operation.");

                // Verify that a user is currently logged in.
                if (context.User.Identity == null)
                    return string.Empty;
                if (!context.User.Identity.IsAuthenticated)
                    return string.Empty;

                // Get data from auth ticket
                formsIdentity = (FormsIdentity)context.User.Identity;
                if (string.IsNullOrEmpty(formsIdentity.Ticket.UserData))
                    return string.Empty;
                if (!Deserialize(formsIdentity.Ticket.UserData, out strUserName, out strReturnUrl))
                    return string.Empty;

                return strUserName;
            }
        }

        /// <summary>
        /// Returns true if the current user is being impersonated.
        /// </summary>
        public static bool IsImpersonating
        {
            get
            {

                // Declare variables
                HttpContext context;
                FormsIdentity  formsIdentity;
                string strUserName, strReturnUrl;

                // Check if a HttpContext is available and a user is currently logged in.
                context = HttpContext.Current;
                if (context == null)
                    throw new InvalidOperationException("No HttpContext available. Unable to complete operation.");

                // Verify that a user is currently logged in.
                if (context.User.Identity == null)
                    return false;
                if (!context.User.Identity.IsAuthenticated)
                    return false;

                // Get data from auth ticket
                formsIdentity = (FormsIdentity)context.User.Identity;
                if (string.IsNullOrEmpty(formsIdentity.Ticket.UserData))
                    return false;
                return Deserialize(formsIdentity.Ticket.UserData, out strUserName, out strReturnUrl);
            }
        }

        /// <summary>
        /// Combines the username and return url in a single string seperating the values by a :-character.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        private static string Serialize(string userName, string returnUrl)
        {
            return string.Format("{0}:{1}", userName.Replace(":", "::"), returnUrl.Replace(":", "::"));
        }

        /// <summary>
        /// Reconstructs the username and return url from a serialized state.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="userName"></param>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        private static bool Deserialize(string data, out string userName, out string returnUrl)
        {

            Regex splitRegex;
            string[] pieces;

            // Set default return values
            userName = null;
            returnUrl = null;

            // Attempt to deserialize data
            splitRegex = new Regex("(?<!:):(?!:)");
            pieces = splitRegex.Split(data);
            if (pieces.Length != 2)
                return false;

            // Set the return values
            userName = pieces[0].Replace("::", ":");
            returnUrl = pieces[1].Replace("::", ":");
            return true;
        }
    }

    
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Netherlands Netherlands
Developer at AlertA contractbeheer.

Comments and Discussions