FormsAuthentication.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / xsp / System / Web / Security / FormsAuthentication.cs / 4 / FormsAuthentication.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 * FormsAuthentication class 
 *
 * Copyright (c) 1999 Microsoft Corporation 
 */

namespace System.Web.Security {
    using System; 
    using System.Web;
    using System.Text; 
    using System.Web.Configuration; 
    using System.Web.Caching;
    using System.Collections; 
    using System.Web.Util;
    using System.Security.Cryptography;
    using System.Security.Principal;
    using System.Threading; 
    using System.Globalization;
    using System.Security.Permissions; 
    using System.Web.Management; 

 

    /// 
    ///    This class consists of static methods that
    ///    provides helper utilities for manipulating authentication tickets. 
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class FormsAuthentication { 
        private const int MAC_LENGTH    = 20;
        private const int MAX_TICKET_LENGTH = 4096; 
        private static object _lockObject = new object();
        internal const string RETURN_URL = "ReturnUrl";

        public FormsAuthentication() { } 

       ///////////////////////////////////////////////////////////////////////////// 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        // Helper functions: Hash a password 

        /// 
        ///    Initializes FormsAuthentication by reading
        ///    configuration and getting the cookie values and encryption keys for the given 
        ///    application.
        ///  
        public static String HashPasswordForStoringInConfigFile(String password, String passwordFormat) { 
            if (password == null) {
                throw new ArgumentNullException("password"); 
            }
            if (passwordFormat == null) {
                throw new ArgumentNullException("passwordFormat");
            } 
            HashAlgorithm hashAlgorithm;
            if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha1")) 
                hashAlgorithm = SHA1.Create(); 
            else if (StringUtil.EqualsIgnoreCase(passwordFormat, "md5"))
                hashAlgorithm = MD5.Create(); 
            else
                throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "passwordFormat"));

            return MachineKeySection.ByteArrayToHexString(hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(password)), 0); 
        }
 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        // Initialize this

        /// 
        ///    Initializes FormsAuthentication by reading 
        ///    configuration and getting the cookie values and encryption keys for the given
        ///    application. 
        ///  
        public static void Initialize() {
            if (_Initialized) 
                return;

            lock(_lockObject) {
                if (_Initialized) 
                    return;
 
                AuthenticationSection settings = RuntimeConfig.GetAppConfig().Authentication; 
                settings.ValidateAuthenticationMode();
                _FormsName = settings.Forms.Name; 
                _RequireSSL = settings.Forms.RequireSSL;
                _SlidingExpiration = settings.Forms.SlidingExpiration;
                if (_FormsName == null)
                    _FormsName = CONFIG_DEFAULT_COOKIE; 

                _Protection = settings.Forms.Protection; 
                _Timeout = (int) settings.Forms.Timeout.TotalMinutes; 
                _FormsCookiePath = settings.Forms.Path;
                _LoginUrl = settings.Forms.LoginUrl; 
                if (_LoginUrl == null)
                    _LoginUrl = "login.aspx";
                _DefaultUrl = settings.Forms.DefaultUrl;
                if (_DefaultUrl == null) 
                    _DefaultUrl = "default.aspx";
                _CookieMode = settings.Forms.Cookieless; 
                _CookieDomain = settings.Forms.Domain; 
                _EnableCrossAppRedirects = settings.Forms.EnableCrossAppRedirects;
 
                _Initialized = true;
            }
        }
 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        ///////////////////////////////////////////////////////////////////////////// 
        // Decrypt and get the auth ticket
 
        /// 
        ///    Given an encrypted authenitcation ticket as
        ///       obtained from an HTTP cookie, this method returns an instance of a
        ///       FormsAuthenticationTicket class. 
        /// 
        public static FormsAuthenticationTicket Decrypt(string encryptedTicket) { 
            if (String.IsNullOrEmpty(encryptedTicket) || encryptedTicket.Length > MAX_TICKET_LENGTH) 
                throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "encryptedTicket"));
 
            Initialize();
            byte[] bBlob = null;
            if ((encryptedTicket.Length % 2) == 0) { // Could be a hex string
                try { 
                    bBlob = MachineKeySection.HexStringToByteArray(encryptedTicket);
                } catch { } 
            } 
            if (bBlob == null)
                bBlob = HttpServerUtility.UrlTokenDecode(encryptedTicket); 
            if (bBlob == null || bBlob.Length < 1)
                throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "encryptedTicket"));

            if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Encryption) 
            {
                // DevDiv Bugs 137864: Include a random IV if under the right compat mode 
                // for improved encryption semantics 
                bBlob = MachineKeySection.EncryptOrDecryptData(false, bBlob, null, 0, bBlob.Length, IVType.Random);
                if (bBlob == null) 
                    return null;
            }

            int ticketLength = bBlob.Length; 

            if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Validation) 
            { 
                //////////////////////////////////////////////////////////////////////
                // Step 2: Get the MAC: Last MAC_LENGTH bytes 
                if (bBlob.Length <= MAC_LENGTH)
                    return null;

                ticketLength = ticketLength - MAC_LENGTH; 
                byte [] bMac    = MachineKeySection.HashData(bBlob, null, 0, ticketLength);
 
                ////////////////////////////////////////////////////////////////////// 
                // Step 3: Make sure the MAC is correct
                if (bMac == null) { 
                    return null;
                }

                if (bMac.Length != MAC_LENGTH) { 
                    return null;
                } 
                for (int iter=0; iter MAX_TICKET_LENGTH) ? MAX_TICKET_LENGTH : ticketLength); 
            StringBuilder     name = new StringBuilder(iSize); 
            StringBuilder     data = new StringBuilder(iSize);
            StringBuilder     path = new StringBuilder(iSize); 
            byte []           pBin = new byte[2];
            long []           pDates = new long[2];

            // FEATURE_PAL: replace Forms Authentication ticket parsing 
            // functionality normally found in webengine.dll
#if !FEATURE_PAL 
            int iRet = UnsafeNativeMethods.CookieAuthParseTicket(bBlob, ticketLength, 
                                                                 name, iSize,
                                                                 data, iSize, 
                                                                 path, iSize,
                                                                 pBin, pDates);
#else // !FEATURE_PAL
            int iRet = FormsAuthCoriolis.CookieAuthParseTicket(bBlob, 
              ticketLength, name, data, path, pBin, pDates);
 
#endif // !FEATURE_PAL 

            if (iRet != 0) 
                return null;
            DateTime dt1 = DateTime.FromFileTime(pDates[0]);
            DateTime dt2 = DateTime.FromFileTime(pDates[1]);
 
            return new FormsAuthenticationTicket((int) pBin[0],
                                                 name.ToString(), 
                                                 dt1, 
                                                 dt2,
                                                 (bool) (pBin[1] != 0), 
                                                 data.ToString(),
                                                 path.ToString());
        }
 

        ///////////////////////////////////////////////////////////////////////////// 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        // Encrypt a ticket 

        /// 
        ///    Given a FormsAuthenticationTicket, this
        ///    method produces a string containing an encrypted authentication ticket suitable 
        ///    for use in an HTTP cookie.
        ///  
        public static String Encrypt(FormsAuthenticationTicket ticket) { 
            return Encrypt(ticket, true);
        } 
        private static String Encrypt(FormsAuthenticationTicket ticket, bool hexEncodedTicket) {
            if (ticket == null)
                throw new ArgumentNullException("ticket");
 
            Initialize();
            ////////////////////////////////////////////////////////////////////// 
            // Step 1: Make it into a binary blob 
            byte[] bBlob = MakeTicketIntoBinaryBlob(ticket);
            if (bBlob == null) 
                return null;

            //////////////////////////////////////////////////////////////////////
            // Step 2: Get the MAC and add to the blob 
            if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Validation)
            { 
                byte [] bMac    = MachineKeySection.HashData(bBlob, null, 0, bBlob.Length); 
                if (bMac == null)
                    return null; 
                byte [] bAll  = new byte[bMac.Length + bBlob.Length];
                Buffer.BlockCopy(bBlob, 0, bAll, 0, bBlob.Length);
                Buffer.BlockCopy(bMac, 0, bAll, bBlob.Length, bMac.Length);
                bBlob = bAll; 
            }
 
            if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Encryption) { 
                //////////////////////////////////////////////////////////////////////
                // Step 3: Do the actual encryption 
                // DevDiv Bugs 137864: Include a random IV if under the right compat mode
                // for improved encryption semantics
                bBlob = MachineKeySection.EncryptOrDecryptData(true, bBlob, null, 0, bBlob.Length, IVType.Random);
            } 
            if (!hexEncodedTicket)
                return HttpServerUtility.UrlTokenEncode(bBlob); 
            else 
                return MachineKeySection.ByteArrayToHexString(bBlob, 0);
        } 

        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        // Verify User name and Password
 
        ///  
        ///    Given the supplied credentials, this method
        ///    attempts to validate the credentials against those contained in the configured 
        ///    credential store.
        /// 
        public static bool Authenticate(String name, String password) {
            bool retVal = InternalAuthenticate(name, password); 

            if (retVal) { 
                PerfCounters.IncrementCounter(AppPerfCounter.FORMS_AUTH_SUCCESS); 
                WebBaseEvent.RaiseSystemEvent(null, WebEventCodes.AuditFormsAuthenticationSuccess, name);
            } 
            else {
                PerfCounters.IncrementCounter(AppPerfCounter.FORMS_AUTH_FAIL);
                WebBaseEvent.RaiseSystemEvent(null, WebEventCodes.AuditFormsAuthenticationFailure, name);
            } 

            return retVal; 
        } 

        private static bool InternalAuthenticate(String name, String password) { 
            //////////////////////////////////////////////////////////////////////
            // Step 1: Make sure we are initialized
            if (name == null || password == null)
                return false; 

            Initialize(); 
            ////////////////////////////////////////////////////////////////////// 
            // Step 2: Get the user database
            AuthenticationSection settings = RuntimeConfig.GetAppConfig().Authentication; 
            settings.ValidateAuthenticationMode();
            FormsAuthenticationUserCollection Users = settings.Forms.Credentials.Users;

//            Hashtable hTable = settings.Credentials; 

            if (Users == null) { 
                return false; 
            }
 
            //////////////////////////////////////////////////////////////////////
            // Step 3: Get the (hashed) password for this user
            FormsAuthenticationUser u = Users[name.ToLower(CultureInfo.InvariantCulture)];
            if (u == null) 
                return false;
 
            String pass = (String)u.Password; 

            if (pass == null) { 
                return false;
            }

            ////////////////////////////////////////////////////////////////////// 
            // Step 4: Hash the given password
            String   encPassword; 
 
            switch (settings.Forms.Credentials.PasswordFormat)
            { 
                case FormsAuthPasswordFormat.SHA1:
                    encPassword = HashPasswordForStoringInConfigFile(password, "sha1");
                    break;
 
                case FormsAuthPasswordFormat.MD5:
                    encPassword = HashPasswordForStoringInConfigFile(password, "md5"); 
                    break; 

                case FormsAuthPasswordFormat.Clear: 
                    encPassword = password;
                    break;

                default: 
                    return false;
            } 
 
            //////////////////////////////////////////////////////////////////////
            // Step 5: Compare the hashes 
            return(String.Compare(encPassword,
                                  pass,
                                  ((settings.Forms.Credentials.PasswordFormat != FormsAuthPasswordFormat.Clear)
                                        ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) 
                   == 0);
        } 
 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////

        /// 
        ///    Given an authenticated user, calling SignOut 
        ///    removes the authentication ticket by doing a SetForms with an empty value. This
        ///    removes either durable or session cookies. 
        ///  
        public static void SignOut() {
            Initialize(); 

            HttpContext    context    = HttpContext.Current;
            bool           needToRedirect  = context.CookielessHelper.DoesCookieValueExistInOriginal('F');
 
            context.CookielessHelper.SetCookieValue('F', null); // Always clear the uri-cookie
 
            if (!CookielessHelperClass.UseCookieless(context, false, CookieMode) || context.Request.Browser.Cookies) 
            { // clear cookie if required
                string cookieValue = String.Empty; 
                if (context.Request.Browser["supportsEmptyStringInCookieValue"] == "false")
                    cookieValue = "NoCookie";
                HttpCookie cookie = new HttpCookie(FormsCookieName, cookieValue);
                cookie.HttpOnly = true; 
                cookie.Path = _FormsCookiePath;
                cookie.Expires = new System.DateTime(1999, 10, 12); 
                cookie.Secure = _RequireSSL; 
                if (_CookieDomain != null)
                    cookie.Domain = _CookieDomain; 
                context.Response.Cookies.RemoveCookie(FormsCookieName);
                context.Response.Cookies.Add(cookie);
            }
            if (needToRedirect) 
                context.Response.Redirect(GetLoginPage(null), false);
        } 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 

        /// 
        ///    This method creates an authentication ticket
        ///    for the given userName and attaches it to the cookies collection of the outgoing 
        ///    response. It does not perform a redirect.
        ///  
        public static void SetAuthCookie(String userName, bool createPersistentCookie) { 
            Initialize();
            SetAuthCookie(userName, createPersistentCookie, FormsAuthentication.FormsCookiePath); 
        }

        /// 
        ///    This method creates an authentication ticket 
        ///    for the given userName and attaches it to the cookies collection of the outgoing
        ///    response. It does not perform a redirect. 
        ///  
        public static void SetAuthCookie(String userName, bool createPersistentCookie, String strCookiePath) {
            Initialize(); 
            HttpContext context = HttpContext.Current;

            if (!context.Request.IsSecureConnection && RequireSSL)
                throw new HttpException(SR.GetString(SR.Connection_not_secure_creating_secure_cookie)); 
            bool        cookieless  = CookielessHelperClass.UseCookieless(context, false, CookieMode);
            HttpCookie  cookie      = GetAuthCookie(userName, createPersistentCookie, cookieless ? "/" : strCookiePath, !cookieless); 
 
            if (!cookieless) {
                HttpContext.Current.Response.Cookies.Add(cookie); 
                context.CookielessHelper.SetCookieValue('F', null);
            }
            else {
                context.CookielessHelper.SetCookieValue('F', cookie.Value); 
            }
        } 
 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////

        /// 
        ///    Creates an authentication cookie for a given 
        ///    user name. This does not set the cookie as part of the outgoing response, so
        ///    that an application can have more control over how the cookie is issued. 
        ///  
        public static HttpCookie GetAuthCookie(String userName, bool createPersistentCookie) {
            Initialize(); 
            return GetAuthCookie(userName, createPersistentCookie, FormsAuthentication.FormsCookiePath);
        }

        public static HttpCookie GetAuthCookie(String userName, bool createPersistentCookie, String strCookiePath) { 
            return GetAuthCookie(userName, createPersistentCookie, strCookiePath, true);
        } 
        private static HttpCookie GetAuthCookie(String userName, bool createPersistentCookie, String strCookiePath, bool hexEncodedTicket) { 
            Initialize();
            if (userName == null) 
                userName = String.Empty;

            if (strCookiePath == null || strCookiePath.Length < 1)
                strCookiePath = FormsCookiePath; 
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                    2, // version 
                    userName, // User-Name 
                    DateTime.Now, // Issue-Date
                    DateTime.Now.AddMinutes(_Timeout), // Expiration 
                    createPersistentCookie, // IsPersistent
                    String.Empty, // User-Data
                    strCookiePath // Cookie Path
                    ); 

            String strTicket = Encrypt(ticket, hexEncodedTicket); 
            if (strTicket == null || strTicket.Length < 1) 
                        throw new HttpException(
                                SR.GetString( 
                                        SR.Unable_to_encrypt_cookie_ticket));


            HttpCookie cookie = new HttpCookie(FormsCookieName, strTicket); 

            cookie.HttpOnly = true; 
            cookie.Path = strCookiePath; 
            cookie.Secure = _RequireSSL;
            if (_CookieDomain != null) 
                cookie.Domain = _CookieDomain;
            if (ticket.IsPersistent)
                cookie.Expires = ticket.Expiration;
            return cookie; 
        }
 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 

        internal static String GetReturnUrl(bool useDefaultIfAbsent)
        {
            Initialize(); 

            HttpContext     context     = HttpContext.Current; 
            String          returnUrl   = context.Request.QueryString[RETURN_URL]; 

            // If it is not in the QueryString, look in the Posted-body 
            if (returnUrl == null) {
                returnUrl = context.Request.Form[RETURN_URL];
                if (!string.IsNullOrEmpty(returnUrl) && !returnUrl.Contains("/") && returnUrl.Contains("%"))
                    returnUrl = HttpUtility.UrlDecode(returnUrl); 
            }
 
            // Make sure it is on the current server if EnableCrossAppRedirects is false 
            if (!string.IsNullOrEmpty(returnUrl) && !EnableCrossAppRedirects) {
                if (!UrlPath.IsPathOnSameServer(returnUrl, context.Request.Url)) 
                    returnUrl = null;
            }

            // Make sure it is not dangerous, i.e. does not contain script, etc. 
            if (!string.IsNullOrEmpty(returnUrl) && CrossSiteScriptingValidation.IsDangerousUrl(returnUrl))
                throw new HttpException(SR.GetString(SR.Invalid_redirect_return_url)); 
 
            return ((returnUrl == null && useDefaultIfAbsent) ? DefaultUrl : returnUrl);
        } 

        /// 
        ///    Returns the redirect URL for the original
        ///    request that caused the redirect to the login page. 
        /// 
        public static String GetRedirectUrl(String userName, bool createPersistentCookie) 
        { 
            if (userName == null)
                return null; 
            return GetReturnUrl(true);
        }
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        // Redirect from logon page to orignal page 
 
        /// 
        ///    This method redirects an authenticated user 
        ///    back to the original URL that they requested.
        /// 
        public static void RedirectFromLoginPage(String userName, bool createPersistentCookie) {
            Initialize(); 
            RedirectFromLoginPage(userName, createPersistentCookie, FormsAuthentication.FormsCookiePath);
        } 
 
        public static void RedirectFromLoginPage(String userName, bool createPersistentCookie, String strCookiePath) {
            Initialize(); 
            if (userName == null)
                return;

            HttpContext context = HttpContext.Current; 
            string strUrl = GetReturnUrl(true);
            if (  CookiesSupported || // Cookies-supported: Most common scenario 
                  IsPathWithinAppRoot(context, strUrl)) { // Cookies not suported, so add it to the current app URL 

                SetAuthCookie(userName, createPersistentCookie, strCookiePath); 
                strUrl = RemoveQueryStringVariableFromUrl(strUrl, FormsCookieName); // Make sure there is no other ticket in the Query String.
                if (!CookiesSupported) {// Make sure the URL is relative, if we are using cookieless.
                    int pos = strUrl.IndexOf("://", StringComparison.Ordinal);
                    if (pos > 0) { 
                        pos = strUrl.IndexOf('/', pos + 3);
                        if (pos > 0) 
                            strUrl = strUrl.Substring(pos); 
                    }
                } 
            } else if (EnableCrossAppRedirects) { // Cookieless scenario -- add it to the QueryString if allowed to

                HttpCookie cookie = GetAuthCookie(userName, createPersistentCookie, strCookiePath);
                strUrl = RemoveQueryStringVariableFromUrl(strUrl, cookie.Name); // Make sure there is no other ticket in the Query String. 
                if (strUrl.IndexOf('?') > 0) {
                    strUrl += "&" + cookie.Name + "=" + cookie.Value; 
                } 
                else {
                    strUrl += "?" + cookie.Name + "=" + cookie.Value; 
                }

            } else {
                // Broken scenario: 
                throw new HttpException(SR.GetString(SR.Can_not_issue_cookie_or_redirect));
            } 
 
            context.Response.Redirect(strUrl, false);
        } 

        public static FormsAuthenticationTicket RenewTicketIfOld(FormsAuthenticationTicket tOld) {
            if (tOld == null)
                return null; 

            DateTime dtN = DateTime.Now; 
            TimeSpan t1  = dtN - tOld.IssueDate; 
            TimeSpan t2  = tOld.Expiration - dtN;
 
            if (t2 > t1)
                return tOld;

            return new FormsAuthenticationTicket ( 
                    tOld.Version,
                    tOld.Name, 
                    dtN, // Issue Date: Now 
                    dtN + (tOld.Expiration - tOld.IssueDate), // Expiration
                    tOld.IsPersistent, 
                    tOld.UserData,
                    tOld.CookiePath);
        }
 
        public static String FormsCookieName { get { Initialize(); return _FormsName; }}
 
        public static String FormsCookiePath { get { Initialize(); return _FormsCookiePath; }} 

        public static bool   RequireSSL { get { Initialize(); return _RequireSSL; }} 

        public static bool   SlidingExpiration { get { Initialize(); return _SlidingExpiration; }}

        public static HttpCookieMode CookieMode { get { Initialize(); return _CookieMode; }} 

        public static string CookieDomain { get { Initialize ();return _CookieDomain; } } 
 
        public static bool EnableCrossAppRedirects { get { Initialize(); return _EnableCrossAppRedirects; } }
 
        public static bool CookiesSupported {
            get {
                HttpContext context = HttpContext.Current;
                if (context != null) { 
                    return !(CookielessHelperClass.UseCookieless(context, false, CookieMode));
                } 
                return true; 
            }
        } 

        public static string LoginUrl {
            get {
                Initialize(); 
                HttpContext context = HttpContext.Current;
                if (context != null)  { 
                    return AuthenticationConfig.GetCompleteLoginUrl(context, _LoginUrl); 
                }
                if (_LoginUrl.Length == 0 || (_LoginUrl[0] != '/' && _LoginUrl.IndexOf("//", StringComparison.Ordinal) < 0)) 
                    return ("/" + _LoginUrl);
                return _LoginUrl;
            }
        } 

        public static string DefaultUrl { 
            get { 
                Initialize();
                HttpContext context = HttpContext.Current; 
                if (context != null)  {
                    return AuthenticationConfig.GetCompleteLoginUrl(context, _DefaultUrl);
                }
                if (_DefaultUrl.Length == 0 || (_DefaultUrl[0] != '/' && _DefaultUrl.IndexOf("//", StringComparison.Ordinal) < 0)) 
                    return ("/" + _DefaultUrl);
                return _DefaultUrl; 
            } 
        }
 
        internal static string GetLoginPage(string extraQueryString) {
            return GetLoginPage(extraQueryString, false);
        }
        internal static string GetLoginPage(string extraQueryString, bool reuseReturnUrl) { 
            HttpContext context = HttpContext.Current;
            string loginUrl = FormsAuthentication.LoginUrl; 
            if (loginUrl.IndexOf('?') >= 0) 
                loginUrl = RemoveQueryStringVariableFromUrl(loginUrl, RETURN_URL);
            int pos = loginUrl.IndexOf('?'); 
            if (pos < 0)
                loginUrl += "?";
            else
                if (pos < loginUrl.Length -1) 
                    loginUrl += "&";
            string returnUrl = null; 
            if (reuseReturnUrl) { 
                returnUrl = HttpUtility.UrlEncode( GetReturnUrl(false),
                                                   context.Request.QueryStringEncoding ); 
            }
            if (returnUrl == null)
                returnUrl = HttpUtility.UrlEncode(context.Request.PathWithQueryString, context.Request.ContentEncoding);
 
            loginUrl += "ReturnUrl=" + returnUrl;
            if (!String.IsNullOrEmpty(extraQueryString)) { 
                loginUrl += "&" + extraQueryString; 
            }
            return loginUrl; 
        }


        public static void RedirectToLoginPage() { 
            RedirectToLoginPage(null);
        } 
 

        public static void RedirectToLoginPage(string extraQueryString) { 
            HttpContext context = HttpContext.Current;
            string loginUrl = GetLoginPage(extraQueryString);
            context.Response.Redirect(loginUrl, false);
        } 

        ///////////////////////////////////////////////////////////////////////////// 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        // Private stuff 

        /////////////////////////////////////////////////////////////////////////////
        // Config Tags
        private  const String   CONFIG_DEFAULT_COOKIE    = ".ASPXAUTH"; 

        ///////////////////////////////////////////////////////////////////////////// 
        // Private data 
        private static bool                _Initialized;
        private static String              _FormsName; 
        //private static FormsProtectionEnum _Protection;
        private static FormsProtectionEnum _Protection;
        private static Int32               _Timeout;
        private static String              _FormsCookiePath; 
        private static bool                _RequireSSL;
        private static bool                _SlidingExpiration; 
        private static string              _LoginUrl; 
        private static string              _DefaultUrl;
        private static HttpCookieMode      _CookieMode; 
        private static string              _CookieDomain = null;
        private static bool                _EnableCrossAppRedirects;

        ///////////////////////////////////////////////////////////////////////////// 
        private static byte[] MakeTicketIntoBinaryBlob(FormsAuthenticationTicket ticket) {
            byte []   bData  = new byte[4096]; 
            byte []   pBin   = new byte[2]; 
            long []   pDates = new long[2];
 
            // DevDiv Bugs 137864: 8 bytes may not be enough random bits as the length should be equal to the
            // key size. In CompatMode > Framework20SP1, use the IVType.Random feature instead of these 8 bytes,
            // but still include empty 8 bytes for compat with webengine.dll, where CookieAuthConstructTicket is.
            // Note that even in CompatMode = Framework20SP2 we fill 8 bytes with random data if the ticket 
            // is not going to be encrypted.
 
            bool willEncrypt = (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Encryption); 
            bool legacyPadding = !willEncrypt || (MachineKeySection.CompatMode == MachineKeyCompatibilityMode.Framework20SP1);
            if (legacyPadding) { 
                // Fill the first 8 bytes of the blob with random bits
                byte[] bRandom = new byte[8];
                RNGCryptoServiceProvider randgen = new RNGCryptoServiceProvider();
                randgen.GetBytes(bRandom); 
                Buffer.BlockCopy(bRandom, 0, bData, 0, 8);
            } 
            else { 
                // use blank 8 bytes for compatibility with CookieAuthConstructTicket (do nothing)
            } 

            pBin[0] = (byte) ticket.Version;
            pBin[1] = (byte) (ticket.IsPersistent ? 1 : 0);
 
            pDates[0] = ticket.IssueDate.ToFileTime();
            pDates[1] = ticket.Expiration.ToFileTime(); 
 
          // Coriolis: replace Forms Authentication ticket parsing
          // functionality normally found in webengine.dll 
#if !FEATURE_PAL
            int iRet = UnsafeNativeMethods.CookieAuthConstructTicket(
                    bData, bData.Length,
                    ticket.Name, ticket.UserData, ticket.CookiePath, 
                    pBin, pDates);
#else // !FEATURE_PAL 
            int iRet = FormsAuthCoriolis.CookieAuthConstructTicket(bData, 
              bData.Length, ticket.Name, ticket.UserData, ticket.CookiePath,
              pBin, pDates); 

#endif // !FEATURE_PAL

 
            if (iRet < 0)
                return null; 
 
            byte[] ciphertext = new byte[iRet];
            Buffer.BlockCopy(bData, 0, ciphertext, 0, iRet); 
            return ciphertext;
        }

        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
 
        internal static string RemoveQueryStringVariableFromUrl(string strUrl, string QSVar) { 
            int posQ = strUrl.IndexOf('?');
            if (posQ < 0) 
                return strUrl;

            // Remove non-encoded QSVars
            string amp   = @"&"; 
            string question = @"?";
 
            string token = amp + QSVar + "="; 
            RemoveQSVar(ref strUrl, posQ, token, amp, amp.Length);
 
            token = question + QSVar + "=";
            RemoveQSVar(ref strUrl, posQ, token, amp, question.Length);

            // Remove Url-enocoded strings 
            amp = HttpUtility.UrlEncode(@"&");
            question = HttpUtility.UrlEncode(@"?"); 
 
            token = amp + HttpUtility.UrlEncode(QSVar + "=");
            RemoveQSVar(ref strUrl, posQ, token, amp, amp.Length); 

            token = question + HttpUtility.UrlEncode(QSVar + "=");
            RemoveQSVar(ref strUrl, posQ, token, amp, question.Length);
            return strUrl; 
        }
 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        static private void RemoveQSVar(ref string strUrl, int posQ, string token, string sep, int lenAtStartToLeave) 
        {
            for (int pos = strUrl.LastIndexOf(token, StringComparison.Ordinal); pos >= posQ; pos = strUrl.LastIndexOf(token, StringComparison.Ordinal))
            {
                int end = strUrl.IndexOf(sep, pos + token.Length, StringComparison.Ordinal) + sep.Length; 
                if (end < sep.Length || end >= strUrl.Length)
                { // ending separator not found or nothing is at the end 
                    strUrl = strUrl.Substring(0, pos); 
                }
                else 
                {
                    strUrl = strUrl.Substring(0, pos + lenAtStartToLeave) + strUrl.Substring(end);
                }
            } 
        }
        static private bool IsPathWithinAppRoot(HttpContext context, string path) 
        { 
            Uri absUri;
            if (!Uri.TryCreate(path, UriKind.Absolute, out absUri)) 
                return HttpRuntime.IsPathWithinAppRoot(path);

            if (!absUri.IsLoopback && !string.Equals(context.Request.Url.Host, absUri.Host, StringComparison.OrdinalIgnoreCase))
                return false; // different servers 

            return HttpRuntime.IsPathWithinAppRoot(absUri.AbsolutePath); 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK