Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / Security / FormsAuthenticationModule.cs / 3 / FormsAuthenticationModule.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
* FormsAuthenticationModule class
*
* Copyright (c) 1999 Microsoft Corporation
*/
namespace System.Web.Security {
using System.Globalization;
using System.Web;
using System.Text;
using System.Web.Configuration;
using System.Web.Caching;
using System.Web.Handlers;
using System.Collections;
using System.Web.Util;
using System.Security.Principal;
using System.Security.Permissions;
using System.Web.Management;
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public sealed class FormsAuthenticationModule : IHttpModule {
// Config values
private static string _LoginUrl;
private static bool _fAuthChecked;
private static bool _fAuthRequired;
private bool _fOnEnterCalled;
private FormsAuthenticationEventHandler _eventHandler;
// Config format
private const string CONFIG_DEFAULT_COOKIE = ".ASPXAUTH";
private const string CONFIG_DEFAULT_LOGINURL= "login.aspx";
///
///
/// Initializes a new instance of the
/// class.
///
///
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public FormsAuthenticationModule() {
}
///
/// This is a Global.asax event which must be
/// named FormsAuthenticate_OnAuthenticate event. It's used by advanced users to
/// customize cookie authentication.
///
public event FormsAuthenticationEventHandler Authenticate {
add {
_eventHandler += value;
}
remove {
_eventHandler -= value;
}
}
public void Dispose() {
}
public void Init(HttpApplication app) {
// authentication is an app level setting only
// so we can read app config early on in an attempt to try and
// skip wiring up event delegates
if (!_fAuthChecked) {
AuthenticationSection settings = RuntimeConfig.GetAppConfig().Authentication;
settings.ValidateAuthenticationMode(); // Throw any runtime configuration errors
_fAuthRequired = (settings.Mode == AuthenticationMode.Forms);
_LoginUrl = settings.Forms.LoginUrl;
if (_LoginUrl == null) {
_LoginUrl = CONFIG_DEFAULT_LOGINURL;
}
_fAuthChecked = true;
}
if (_fAuthRequired) {
// initialize if mode is forms auth
FormsAuthentication.Initialize();
app.AuthenticateRequest += new EventHandler(this.OnEnter);
app.EndRequest += new EventHandler(this.OnLeave);
}
}
////////////////////////////////////////////////////////////
// OnAuthenticate: Forms Authentication modules can override
// this method to create a Forms IPrincipal object from
// a WindowsIdentity
private void OnAuthenticate(FormsAuthenticationEventArgs e) {
HttpCookie cookie = null;
////////////////////////////////////////////////////////////
// Step 1: If there are event handlers, invoke the handlers
if (_eventHandler != null)
_eventHandler(this, e);
////////////////////////////////////////////////////////////
// Step 2: Check if the event handler created a user-object
if (e.Context.User != null) {
// do nothing because someone else authenticated
return;
}
if (e.User != null) {
// the event handler created a user
e.Context.SetPrincipalNoDemand(e.User);
return;
}
////////////////////////////////////////////////////////////
// Step 3: Extract the cookie and create a ticket from it
FormsAuthenticationTicket ticket = null;
bool cookielessTicket = false;
try {
ticket = ExtractTicketFromCookie(e.Context, FormsAuthentication.FormsCookieName, out cookielessTicket);
}
catch {
ticket = null;
}
////////////////////////////////////////////////////////////
// Step 4: See if the ticket was created: No => exit immediately
if (ticket == null || ticket.Expired)
return;
////////////////////////////////////////////////////////////
// Step 5: Renew the ticket
FormsAuthenticationTicket ticket2 = ticket;
if (FormsAuthentication.SlidingExpiration)
ticket2 = FormsAuthentication.RenewTicketIfOld(ticket);
////////////////////////////////////////////////////////////
// Step 6: Create a user object for the ticket
e.Context.SetPrincipalNoDemand(new GenericPrincipal(new FormsIdentity(ticket2), new String[0]));
////////////////////////////////////////////////////////////
// Step 7: Browser does not send us the correct cookie-path
// Update the cookie to show the correct path
if (!cookielessTicket && !ticket2.CookiePath.Equals("/"))
{
cookie = e.Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null) {
cookie.Path = ticket2.CookiePath;
}
}
////////////////////////////////////////////////////////////
// Step 8: If the ticket was renewed, save the ticket in the cookie
if (ticket2 != ticket)
{
if(cookielessTicket && ticket2.CookiePath != "/" && ticket2.CookiePath.Length > 1) {
ticket2 = new FormsAuthenticationTicket(ticket2.Version, ticket2.Name, ticket2.IssueDate,
ticket2.Expiration, ticket2.IsPersistent, ticket2.UserData,
"/");
}
String strEnc = FormsAuthentication.Encrypt(ticket2);
if (cookielessTicket) {
e.Context.CookielessHelper.SetCookieValue('F', strEnc);
e.Context.Response.Redirect(e.Context.Request.PathWithQueryString);
} else {
if (cookie != null)
cookie = e.Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null) {
cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strEnc);
cookie.Path = ticket2.CookiePath;
}
if (ticket2.IsPersistent)
cookie.Expires = ticket2.Expiration;
cookie.Value = strEnc;
cookie.Secure = FormsAuthentication.RequireSSL;
cookie.HttpOnly = true;
if (FormsAuthentication.CookieDomain != null)
cookie.Domain = FormsAuthentication.CookieDomain;
e.Context.Response.Cookies.Remove(cookie.Name);
e.Context.Response.Cookies.Add(cookie);
}
}
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
///
/// [To be supplied.]
///
private void OnEnter(Object source, EventArgs eventArgs) {
_fOnEnterCalled = true;
HttpApplication app;
HttpContext context;
app = (HttpApplication)source;
context = app.Context;
Trace("*******************Request path: " + context.Request.PathWithQueryString);
////////////////////////////////////////////////////////
// Step 2: Call OnAuthenticate virtual method to create
// an IPrincipal for this request
OnAuthenticate( new FormsAuthenticationEventArgs(context) );
////////////////////////////////////////////////////////
// Skip AuthZ if accessing the login page
// We do this here to force the cookieless helper to fish out and
// remove the token from the URL if it's present there.
CookielessHelperClass cookielessHelper = context.CookielessHelper;
if (AuthenticationConfig.AccessingLoginPage(context, _LoginUrl)) {
context.SetSkipAuthorizationNoDemand(true, false /*managedOnly*/);
cookielessHelper.RedirectWithDetectionIfRequired(null, FormsAuthentication.CookieMode);
}
if (!context.SkipAuthorization) {
context.SetSkipAuthorizationNoDemand(AssemblyResourceLoader.IsValidWebResourceRequest(context), false /*managedOnly*/);
}
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
///
/// [To be supplied.]
///
private void OnLeave(Object source, EventArgs eventArgs) {
if (_fOnEnterCalled)
_fOnEnterCalled = false;
else
return; // no need to continue if we skipped OnEnter
HttpApplication app;
HttpContext context;
app = (HttpApplication)source;
context = app.Context;
////////////////////////////////////////////////////////////
// Step 1: Check if we are using cookie authentication and
// if authentication failed
if (context.Response.StatusCode != 401)
return;
////////////////////////////////////////////////////////////
// Change 401 to a redirect to login page
// Don't do it if already there is ReturnUrl, already being redirected,
// to avoid infinite redirection loop
String strUrl = context.Request.PathWithQueryString;
if (strUrl.IndexOf("?ReturnUrl=", StringComparison.Ordinal) != -1
|| strUrl.IndexOf("&ReturnUrl=", StringComparison.Ordinal) != -1) {
return;
}
////////////////////////////////////////////////////////////
// Step 2: Get the complete url to the login-page
String loginUrl = null;
if (!String.IsNullOrEmpty(_LoginUrl))
loginUrl = AuthenticationConfig.GetCompleteLoginUrl(context, _LoginUrl);
////////////////////////////////////////////////////////////
// Step 3: Check if we have a valid url to the login-page
if (loginUrl == null || loginUrl.Length <= 0)
throw new HttpException(SR.GetString(SR.Auth_Invalid_Login_Url));
////////////////////////////////////////////////////////////
// Step 4: Construct the redirect-to url
String strRedirect;
int iIndex;
CookielessHelperClass cookielessHelper;
// if(context.Request.Browser["isMobileDevice"] == "true") {
// //__redir=1 is marker for devices that post on redirect
// if(strUrl.IndexOf("__redir=1") >= 0) {
// strUrl = SanitizeUrlForCookieless(strUrl);
// }
// else {
// if(strUrl.IndexOf('?') >= 0)
// strSep = "&";
// else
// strSep = "?";
// strUrl = SanitizeUrlForCookieless(strUrl + strSep + "__redir=1");
// }
// }
// Create the CookielessHelper class to rewrite the path, if needed.
cookielessHelper = context.CookielessHelper;
if (loginUrl.IndexOf('?') >= 0) {
loginUrl = FormsAuthentication.RemoveQueryStringVariableFromUrl(loginUrl, FormsAuthentication.RETURN_URL);
strRedirect = loginUrl + "&" + "ReturnUrl=" + HttpUtility.UrlEncode(strUrl, context.Request.ContentEncoding);
}
else {
strRedirect = loginUrl + "?" + "ReturnUrl=" + HttpUtility.UrlEncode(strUrl, context.Request.ContentEncoding);
}
////////////////////////////////////////////////////////////
// Step 5: Add the query-string from the current url
iIndex = strUrl.IndexOf('?');
if (iIndex >= 0 && iIndex < strUrl.Length - 1) {
strRedirect += "&" + strUrl.Substring(iIndex + 1);
}
cookielessHelper.SetCookieValue('F', null); // remove old ticket if present
cookielessHelper.RedirectWithDetectionIfRequired(strRedirect, FormsAuthentication.CookieMode);
////////////////////////////////////////////////////////////
// Step 6: Do the redirect
context.Response.Redirect(strRedirect, false);
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Private method for decrypting a cookie
private static FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, String name, out bool cookielessTicket) {
FormsAuthenticationTicket ticket = null;
string encValue = null;
bool ticketExpired = false;
bool badTicket = false;
try {
try {
////////////////////////////////////////////////////////////
// Step 0: Check if we should use cookieless
cookielessTicket = CookielessHelperClass.UseCookieless(context, false, FormsAuthentication.CookieMode);
////////////////////////////////////////////////////////////
// Step 1: Check URI/cookie for ticket
if (cookielessTicket) {
encValue = context.CookielessHelper.GetCookieValue('F');
} else {
HttpCookie cookie = context.Request.Cookies[name];
if (cookie != null) {
encValue = cookie.Value;
}
}
////////////////////////////////////////////////////////////
// Step 2: Decrypt encrypted ticket
if (encValue != null && encValue.Length > 1) {
try {
ticket = FormsAuthentication.Decrypt(encValue);
} catch {
if (cookielessTicket)
context.CookielessHelper.SetCookieValue('F', null);
else
context.Request.Cookies.Remove(name);
badTicket = true;
//throw;
}
if (ticket == null) {
badTicket = true;
}
if (ticket != null && !ticket.Expired) {
if (cookielessTicket || !FormsAuthentication.RequireSSL || context.Request.IsSecureConnection) // Make sure it is NOT a secure cookie over an in-secure connection
return ticket; // Found valid ticket
}
if (ticket != null && ticket.Expired) {
ticketExpired = true;
}
// Step 2b: Remove expired/bad ticket
ticket = null;
if (cookielessTicket)
context.CookielessHelper.SetCookieValue('F', null);
else
context.Request.Cookies.Remove(name);
}
////////////////////////////////////////////////////////////
// Step 3: Look in QueryString
if (FormsAuthentication.EnableCrossAppRedirects) {
encValue = context.Request.QueryString[name];
if (encValue != null && encValue.Length > 1) {
if (!cookielessTicket && FormsAuthentication.CookieMode == HttpCookieMode.AutoDetect)
cookielessTicket = CookielessHelperClass.UseCookieless(context, true, FormsAuthentication.CookieMode); // find out for sure
try {
ticket = FormsAuthentication.Decrypt(encValue);
} catch {
badTicket = true;
//throw;
}
if (ticket == null) {
badTicket = true;
}
}
// Step 3b: Look elsewhere in the request (i.e. posted body)
if (ticket == null || ticket.Expired) {
encValue = context.Request.Form[name];
if (encValue != null && encValue.Length > 1) {
if (!cookielessTicket && FormsAuthentication.CookieMode == HttpCookieMode.AutoDetect)
cookielessTicket = CookielessHelperClass.UseCookieless(context, true, FormsAuthentication.CookieMode); // find out for sure
try {
ticket = FormsAuthentication.Decrypt(encValue);
} catch {
badTicket = true;
//throw;
}
if (ticket == null) {
badTicket = true;
}
}
}
}
if (ticket == null || ticket.Expired) {
if (ticket != null && ticket.Expired)
ticketExpired = true;
return null; // not found! Exit with null
}
if (FormsAuthentication.RequireSSL && !context.Request.IsSecureConnection) // Bad scenario: valid ticket over non-SSL
throw new HttpException(SR.GetString(SR.Connection_not_secure_creating_secure_cookie));
////////////////////////////////////////////////////////////
// Step 4: Create the cookie/URI value
if (cookielessTicket) {
if (ticket.CookiePath != "/") {
ticket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate,
ticket.Expiration, ticket.IsPersistent, ticket.UserData,
"/");
encValue = FormsAuthentication.Encrypt(ticket);
}
context.CookielessHelper.SetCookieValue('F', encValue);
string strUrl = FormsAuthentication.RemoveQueryStringVariableFromUrl(context.Request.PathWithQueryString, name);
context.Response.Redirect(strUrl);
} else {
HttpCookie cookie = new HttpCookie(name, encValue);
cookie.HttpOnly = true;
cookie.Path = ticket.CookiePath;
if (ticket.IsPersistent)
cookie.Expires = ticket.Expiration;
cookie.Secure = FormsAuthentication.RequireSSL;
if (FormsAuthentication.CookieDomain != null)
cookie.Domain = FormsAuthentication.CookieDomain;
context.Response.Cookies.Remove(cookie.Name);
context.Response.Cookies.Add(cookie);
}
return ticket;
} finally {
if (badTicket) {
WebBaseEvent.RaiseSystemEvent(null, WebEventCodes.AuditFormsAuthenticationFailure,
WebEventCodes.InvalidTicketFailure);
} else if (ticketExpired) {
WebBaseEvent.RaiseSystemEvent(null, WebEventCodes.AuditFormsAuthenticationFailure,
WebEventCodes.ExpiredTicketFailure);
}
}
} catch {
throw;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
private static void Trace(String str) {
Debug.Trace("cookieauth", str);
}
}
}
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Vector3DConverter.cs
- AbsoluteQuery.cs
- WebSysDisplayNameAttribute.cs
- RC2CryptoServiceProvider.cs
- OrderedDictionary.cs
- UncommonField.cs
- Profiler.cs
- ErrorReporting.cs
- ElementUtil.cs
- AttachInfo.cs
- ApplicationDirectoryMembershipCondition.cs
- regiisutil.cs
- And.cs
- UniqueConstraint.cs
- RequestChannel.cs
- SqlDataSourceCache.cs
- MenuAutomationPeer.cs
- FreezableOperations.cs
- COAUTHIDENTITY.cs
- UnmanagedMarshal.cs
- UrlAuthorizationModule.cs
- BitmapEffectInput.cs
- LowerCaseStringConverter.cs
- BufferedGraphics.cs
- MetaForeignKeyColumn.cs
- Bits.cs
- MetadataCacheItem.cs
- FilterException.cs
- SystemIPAddressInformation.cs
- SerializationFieldInfo.cs
- StatusBar.cs
- OdbcConnectionPoolProviderInfo.cs
- ProtocolViolationException.cs
- ConfigUtil.cs
- ButtonChrome.cs
- followingquery.cs
- SafeRegistryKey.cs
- PrintDialogException.cs
- ComponentResourceKeyConverter.cs
- ADConnectionHelper.cs
- UnsafeNativeMethods.cs
- PageHandlerFactory.cs
- ButtonAutomationPeer.cs
- XsltContext.cs
- ProxyWebPartManager.cs
- DataGridItemEventArgs.cs
- TargetPerspective.cs
- Speller.cs
- Group.cs
- RuntimeConfigurationRecord.cs
- FileDialog_Vista.cs
- DataTemplateKey.cs
- ProvideValueServiceProvider.cs
- WpfKnownType.cs
- SafeFileMapViewHandle.cs
- GetUserPreferenceRequest.cs
- Unit.cs
- GeometryDrawing.cs
- HttpWriter.cs
- TemplateManager.cs
- WindowsEditBoxRange.cs
- LogicalExpr.cs
- ModuleConfigurationInfo.cs
- NGCSerializationManager.cs
- ComEventsMethod.cs
- ActivitySurrogateSelector.cs
- ReferentialConstraint.cs
- BindingSource.cs
- WebBrowserProgressChangedEventHandler.cs
- MsmqIntegrationProcessProtocolHandler.cs
- LogWriteRestartAreaState.cs
- ServiceNameCollection.cs
- ApplicationManager.cs
- XNodeSchemaApplier.cs
- XmlAnyAttributeAttribute.cs
- SystemIPv6InterfaceProperties.cs
- ConfigurationPropertyCollection.cs
- DateTimeConverter.cs
- mediaeventargs.cs
- State.cs
- DoubleLinkListEnumerator.cs
- ChannelTraceRecord.cs
- XmlDomTextWriter.cs
- DeviceContext2.cs
- TransactionScope.cs
- DataGridViewCellValueEventArgs.cs
- CollectionEditorDialog.cs
- ProxyWebPartConnectionCollection.cs
- OleServicesContext.cs
- TextEditor.cs
- MobileControlsSectionHandler.cs
- DependencyStoreSurrogate.cs
- KeyToListMap.cs
- ReferencedAssemblyResolver.cs
- PowerModeChangedEventArgs.cs
- StylusPointPropertyInfoDefaults.cs
- XPathNodePointer.cs
- ListViewGroupCollectionEditor.cs
- TraceData.cs
- CalendarDesigner.cs