Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / xsp / System / Web / Security / FormsAuthenticationModule.cs / 5 / 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);
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TemplateControlCodeDomTreeGenerator.cs
- CacheOutputQuery.cs
- TokenBasedSetEnumerator.cs
- CollectionExtensions.cs
- StructuredTypeEmitter.cs
- ContextMenuAutomationPeer.cs
- DataBinder.cs
- TrailingSpaceComparer.cs
- FaultDescriptionCollection.cs
- DbProviderFactories.cs
- ToolStripContextMenu.cs
- BamlRecordReader.cs
- PipeSecurity.cs
- NodeFunctions.cs
- Scene3D.cs
- DispatcherOperation.cs
- MimeWriter.cs
- PartialToken.cs
- Transform.cs
- InfoCardTrace.cs
- LineServicesCallbacks.cs
- HttpGetProtocolReflector.cs
- ComponentEditorPage.cs
- Pkcs7Recipient.cs
- AssemblyCache.cs
- WorkflowCommandExtensionItem.cs
- CellTreeNode.cs
- ViewgenGatekeeper.cs
- XmlCompatibilityReader.cs
- TableCellCollection.cs
- TrustLevel.cs
- BaseAsyncResult.cs
- FamilyMapCollection.cs
- XmlUtf8RawTextWriter.cs
- RectangleF.cs
- TraceLog.cs
- XmlSchemaAnnotation.cs
- EllipticalNodeOperations.cs
- DataGridViewCellParsingEventArgs.cs
- CharacterShapingProperties.cs
- AutomationElementCollection.cs
- XmlChoiceIdentifierAttribute.cs
- PrivilegedConfigurationManager.cs
- TextParagraphView.cs
- Timeline.cs
- ScopedKnownTypes.cs
- ReflectionTypeLoadException.cs
- FileChangesMonitor.cs
- XmlUtil.cs
- ProtocolsConfiguration.cs
- WebServiceHostFactory.cs
- PerspectiveCamera.cs
- SamlSecurityToken.cs
- DetailsViewRow.cs
- IEnumerable.cs
- XmlWhitespace.cs
- AspNetCompatibilityRequirementsMode.cs
- AnnotationResourceChangedEventArgs.cs
- SiteOfOriginPart.cs
- StreamAsIStream.cs
- SoapAttributeAttribute.cs
- EventRoute.cs
- WhitespaceRule.cs
- XPathLexer.cs
- TypefaceCollection.cs
- TypeSchema.cs
- HttpStreamMessageEncoderFactory.cs
- BitmapEffectRenderDataResource.cs
- PropertyState.cs
- XPathAncestorQuery.cs
- ThumbAutomationPeer.cs
- DbConnectionPoolOptions.cs
- ContentElement.cs
- ValidationManager.cs
- DocumentViewer.cs
- ReceiveContent.cs
- ImmComposition.cs
- UInt64Storage.cs
- ZipIOCentralDirectoryFileHeader.cs
- WorkflowRuntimeService.cs
- XmlSignificantWhitespace.cs
- PageRequestManager.cs
- Tracking.cs
- ServerValidateEventArgs.cs
- RepeatInfo.cs
- AppDomainAttributes.cs
- FormatPage.cs
- HandoffBehavior.cs
- CollectionViewSource.cs
- DebugInfoExpression.cs
- GuidelineSet.cs
- MasterPageCodeDomTreeGenerator.cs
- InvalidDataException.cs
- HttpServerProtocol.cs
- ItemCollection.cs
- SQLRoleProvider.cs
- SmiEventSink_Default.cs
- QuerySettings.cs
- AllowedAudienceUriElementCollection.cs
- EnvelopedPkcs7.cs