Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Security / FormsAuthentication.cs / 1305376 / 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; using System.Collections.Specialized; using System.Web.Compilation; ////// This class consists of static methods that /// provides helper utilities for manipulating authentication tickets. /// public sealed class FormsAuthentication { 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; _TicketCompatibilityMode = settings.Forms.TicketCompatibilityMode; _Initialized = true; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Decrypt and get the auth ticket ////// 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, false, false, IVType.Random); if (bBlob == null) return null; } int ticketLength = bBlob.Length; if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Validation) { if (!MachineKeySection.VerifyHashedData(bBlob)) return null; ticketLength -= MachineKeySection.HashSize; } ////////////////////////////////////////////////////////////////////// // Step 4: Change binary ticket to managed struct int iSize = ((ticketLength > MAX_TICKET_LENGTH) ? MAX_TICKET_LENGTH : ticketLength); StringBuilder name = new StringBuilder(iSize); StringBuilder data = new StringBuilder(iSize); StringBuilder path = new StringBuilder(iSize); byte [] internalData = null; byte [] pBin = new byte[4]; long [] pDates = new long[2]; int iRet; // FEATURE_PAL: replace Forms Authentication ticket parsing // functionality normally found in webengine.dll #if !FEATURE_PAL if (TicketCompatibilityMode == TicketCompatibilityMode.Framework20) { iRet = UnsafeNativeMethods.CookieAuthParseTicket(bBlob, ticketLength, name, iSize, data, iSize, path, iSize, pBin, pDates); } else { // Initial offset after random bits int offset = 8; int byteCount = 0; // Get the version pBin[0] = bBlob[offset]; offset += 1; // Verify the null pad if (offset + 3 > ticketLength) { return null; } if ((bBlob[offset] != 0) || (bBlob[offset + 1] != 0) || (bBlob[offset + 2] != 0)) { return null; } offset += 3; // Copy the name if (offset + 4 > ticketLength) { return null; } byteCount = BitConverter.ToInt32(bBlob, offset); offset += 4; if (offset + byteCount > ticketLength) { return null; } name.Append(Encoding.Unicode.GetChars(bBlob, offset, byteCount)); offset += byteCount; // Copy the issue date if (offset + 8 > ticketLength) { return null; } pDates[0] = BitConverter.ToInt64(bBlob, offset); offset += 8; // Copy the IsPersistent byte if (offset + 1 > ticketLength) { return null; } pBin[1] = bBlob[offset]; offset += 1; // Copy the expires date if (offset + 8 > ticketLength) { return null; } pDates[1] = BitConverter.ToInt64(bBlob, offset); offset += 8; // Copy the internal version if (offset + 1 > ticketLength) { return null; } pBin[2] = bBlob[offset]; offset += 1; // Copy the internal data int internalDataSize = 0; if (offset + 4 > ticketLength) { return null; } internalDataSize = BitConverter.ToInt32(bBlob, offset); offset += 4; if (internalDataSize > 0) { if (offset + internalDataSize > ticketLength) { return null; } internalData = new byte[internalDataSize]; Buffer.BlockCopy(bBlob, offset, internalData, 0, internalDataSize); } offset += internalDataSize; // Copy the user data if (offset + 4 > ticketLength) { return null; } byteCount = BitConverter.ToInt32(bBlob, offset); offset += 4; if (offset + byteCount > ticketLength) { return null; } data.Append(Encoding.Unicode.GetChars(bBlob, offset, byteCount)); offset += byteCount; // Copy the path if (offset + 4 > ticketLength) { return null; } byteCount = BitConverter.ToInt32(bBlob, offset); offset += 4; if (offset + byteCount > ticketLength) { return null; } path.Append(Encoding.Unicode.GetChars(bBlob, offset, byteCount)); offset += byteCount; iRet = 0; } #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 dt2; if (TicketCompatibilityMode == TicketCompatibilityMode.Framework20) { dt1 = DateTime.FromFileTime(pDates[0]); dt2 = DateTime.FromFileTime(pDates[1]); } else { dt1 = DateTime.FromFileTimeUtc(pDates[0]).ToLocalTime(); dt2 = DateTime.FromFileTimeUtc(pDates[1]).ToLocalTime(); } FormsAuthenticationTicket ticket = new FormsAuthenticationTicket((int) pBin[0], name.ToString(), dt1, dt2, (bool) (pBin[1] != 0), data.ToString(), path.ToString()); if (TicketCompatibilityMode > TicketCompatibilityMode.Framework20) { ticket.InternalVersion = (int)pBin[2]; ticket.InternalData = internalData; } return ticket; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Encrypt a ticket ///Given an encrypted authenitcation ticket as /// obtained from an HTTP cookie, this method returns an instance of a /// FormsAuthenticationTicket class. ////// 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, false, false, 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 ); if (TicketCompatibilityMode > TicketCompatibilityMode.Framework20) { ticket.InternalVersion = (int)TicketCompatibilityMode; ticket.InternalData = null; } 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; FormsAuthenticationTicket ticket = new FormsAuthenticationTicket ( tOld.Version, tOld.Name, dtN, // Issue Date: Now dtN + (tOld.Expiration - tOld.IssueDate), // Expiration tOld.IsPersistent, tOld.UserData, tOld.CookiePath); if (TicketCompatibilityMode > TicketCompatibilityMode.Framework20) { ticket.InternalVersion = tOld.InternalVersion; ticket.InternalData = tOld.InternalData; } return ticket; } public static void EnableFormsAuthentication(NameValueCollection configurationData) { BuildManager.ThrowIfPreAppStartNotRunning(); configurationData = configurationData ?? new NameValueCollection(); AuthenticationConfig.Mode = AuthenticationMode.Forms; Initialize(); // Last caller overwrites only the values that are present in the dictionary. string defaultUrl = configurationData["defaultUrl"]; if (!String.IsNullOrEmpty(defaultUrl)) { _DefaultUrl = defaultUrl; } string loginUrl = configurationData["loginUrl"]; if (!String.IsNullOrEmpty(loginUrl)) { _LoginUrl = loginUrl; } } public static bool IsEnabled { get { return AuthenticationConfig.Mode == AuthenticationMode.Forms; } } 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 TimeSpan Timeout { get { Initialize(); return new TimeSpan(0, _Timeout, 0); } } 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 TicketCompatibilityMode TicketCompatibilityMode { get { Initialize(); return _TicketCompatibilityMode; } } 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.RawUrl, 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 TicketCompatibilityMode _TicketCompatibilityMode; ///////////////////////////////////////////////////////////////////////////// private static byte[] MakeTicketIntoBinaryBlob(FormsAuthenticationTicket ticket) { byte [] bData = new byte[4096]; byte [] pBin = new byte[4]; long [] pDates = new long[2]; byte [] pNull = { 0, 0, 0 }; // 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); if (TicketCompatibilityMode == TicketCompatibilityMode.Framework20) { pDates[0] = ticket.IssueDate.ToFileTime(); pDates[1] = ticket.Expiration.ToFileTime(); } else { pDates[0] = ticket.IssueDate.ToUniversalTime().ToFileTimeUtc(); pDates[1] = ticket.Expiration.ToUniversalTime().ToFileTimeUtc(); pBin[2] = (byte)ticket.InternalVersion; } // Coriolis: replace Forms Authentication ticket parsing // functionality normally found in webengine.dll int iRet; #if !FEATURE_PAL if (TicketCompatibilityMode == TicketCompatibilityMode.Framework20) { iRet = UnsafeNativeMethods.CookieAuthConstructTicket( bData, bData.Length, ticket.Name, ticket.UserData, ticket.CookiePath, pBin, pDates); } else { // Initial offset after random bits int offset = 8; int byteCount = 0; int bDataLength = bData.Length; if (ticket.Name == null || ticket.UserData == null || ticket.CookiePath == null) { return null; } // Copy the version bData[offset] = pBin[0]; offset += 1; // Copy the null pad Buffer.BlockCopy(pNull, 0, bData, offset, 3); offset += 3; // Copy the name byteCount = Encoding.Unicode.GetByteCount(ticket.Name); if (offset + 4 > bDataLength) { return null; } Buffer.BlockCopy(BitConverter.GetBytes(byteCount), 0, bData, offset, 4); offset += 4; if (offset + byteCount > bDataLength) { return null; } Buffer.BlockCopy(Encoding.Unicode.GetBytes(ticket.Name), 0, bData, offset, byteCount); offset += byteCount; // Copy the issue date if (offset + 8 > bDataLength) { return null; } Buffer.BlockCopy(BitConverter.GetBytes(pDates[0]), 0, bData, offset, 8); offset += 8; // Copy the IsPersistent byte if (offset + 1 > bDataLength) { return null; } bData[offset] = pBin[1]; offset += 1; // Copy the expires date if (offset + 8 > bDataLength) { return null; } Buffer.BlockCopy(BitConverter.GetBytes(pDates[1]), 0, bData, offset, 8); offset += 8; // Copy the internal version if (offset + 1 > bDataLength) { return null; } bData[offset] = pBin[2]; offset += 1; // Copy the internal data if (offset + 4 > bDataLength) { return null; } if (ticket.InternalData == null) { byteCount = 0; } else { byteCount = ticket.InternalData.Length; } Buffer.BlockCopy(BitConverter.GetBytes(byteCount), 0, bData, offset, 4); offset += 4; if (offset + byteCount > bDataLength) { return null; } if (byteCount != 0) { Buffer.BlockCopy(ticket.InternalData, 0, bData, offset, byteCount); offset += byteCount; } // Copy the user data byteCount = Encoding.Unicode.GetByteCount(ticket.UserData); if (offset + 4 > bDataLength) { return null; } Buffer.BlockCopy(BitConverter.GetBytes(byteCount), 0, bData, offset, 4); offset += 4; if (offset + byteCount > bDataLength) { return null; } Buffer.BlockCopy(Encoding.Unicode.GetBytes(ticket.UserData), 0, bData, offset, byteCount); offset += byteCount; // Copy the path byteCount = Encoding.Unicode.GetByteCount(ticket.CookiePath); if (offset + 4 > bDataLength) { return null; } Buffer.BlockCopy(BitConverter.GetBytes(byteCount), 0, bData, offset, 4); offset += 4; if (offset + byteCount > bDataLength) { return null; } Buffer.BlockCopy(Encoding.Unicode.GetBytes(ticket.CookiePath), 0, bData, offset, byteCount); offset += byteCount; iRet = offset; } #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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ParameterToken.cs
- QueryOpeningEnumerator.cs
- DataTableClearEvent.cs
- UnsafeNativeMethods.cs
- ListViewItem.cs
- HighContrastHelper.cs
- PerformanceCounterPermissionEntryCollection.cs
- DateRangeEvent.cs
- PlainXmlSerializer.cs
- RootBrowserWindowProxy.cs
- ReadOnlyDataSourceView.cs
- AnnotationHighlightLayer.cs
- CanonicalXml.cs
- ReceiveMessageContent.cs
- ReflectEventDescriptor.cs
- WindowsIdentity.cs
- ValueChangedEventManager.cs
- RadioButtonAutomationPeer.cs
- ReadContentAsBinaryHelper.cs
- SystemEvents.cs
- DisplayInformation.cs
- BinaryNode.cs
- BitmapEffectDrawingContextState.cs
- SourceFileBuildProvider.cs
- DataBindingExpressionBuilder.cs
- Triplet.cs
- OuterGlowBitmapEffect.cs
- DocumentXPathNavigator.cs
- PropertyIDSet.cs
- EngineSite.cs
- Environment.cs
- SpellerStatusTable.cs
- ObjectQuery_EntitySqlExtensions.cs
- NameNode.cs
- ImageUrlEditor.cs
- OdbcParameterCollection.cs
- XamlNamespaceHelper.cs
- XNodeNavigator.cs
- MdImport.cs
- WebPartCatalogAddVerb.cs
- FormParameter.cs
- ObjectToIdCache.cs
- SqlTriggerAttribute.cs
- ListItem.cs
- TypedReference.cs
- HtmlInputText.cs
- WebBrowser.cs
- FontWeight.cs
- HttpStreams.cs
- ScrollItemPattern.cs
- ContentPlaceHolder.cs
- DelegatingHeader.cs
- Msec.cs
- ModulesEntry.cs
- Timeline.cs
- WebServiceErrorEvent.cs
- RadioButtonDesigner.cs
- RangeBase.cs
- Panel.cs
- SystemResourceKey.cs
- ExtensionDataReader.cs
- XamlSerializationHelper.cs
- StringTraceRecord.cs
- BaseValidatorDesigner.cs
- TcpServerChannel.cs
- TemplateBindingExtension.cs
- ConstraintEnumerator.cs
- OrthographicCamera.cs
- BindingsCollection.cs
- ProjectionCamera.cs
- PinnedBufferMemoryStream.cs
- DesignerCommandSet.cs
- CodePrimitiveExpression.cs
- XmlSchemaAnnotation.cs
- XamlPoint3DCollectionSerializer.cs
- LocationReferenceValue.cs
- FontUnit.cs
- ResourceBinder.cs
- uribuilder.cs
- BoundColumn.cs
- BackStopAuthenticationModule.cs
- InfoCardClaimCollection.cs
- Parallel.cs
- Mouse.cs
- SpeechSynthesizer.cs
- GuidelineCollection.cs
- TrackingProvider.cs
- PointCollection.cs
- TimeManager.cs
- InternalRelationshipCollection.cs
- RuntimeConfigLKG.cs
- TextBlockAutomationPeer.cs
- GridToolTip.cs
- HtmlEncodedRawTextWriter.cs
- BufferedWebEventProvider.cs
- SqlMultiplexer.cs
- ItemsControlAutomationPeer.cs
- COM2ICategorizePropertiesHandler.cs
- MDIControlStrip.cs
- ButtonField.cs