Improve Your Technology

Just another blog for techology

ASP.NET Mixed Mode Authentication

By Paul Glavich

 

In an increasing number of the web applications I have had to design and work on, the client has requested the best of both worlds when it comes to authentication. Ideally, they would like their intranet users to be able to seamlessly logon on to the system (windows integrated authentication) and make authorization decisions based on their domain roles, as well as be able to have external parties log onto the system using standard forms authentication. In this article, I will show you one way of achieving this goal.

 

Note: This method assumes that cookies are allowed and enabled on the client browsers.

 

Assumed Knowledge

 

 

This article assumes the reader is familiar with the setup of forms authentication in ASP.Net, windows principal objects, role based authorisation, reflection, and is also familiar with the setup of Windows integrated authentication using the Internet Information Services (IIS) snap-in management console.

 

A Common Model

  

In order for this mixed model authentication scenario to work, and also to make it easy on developers, a common and familiar security model is required for authentication, and subsequently authorisation. If we were trying to emulate windows integrated authentication from a forms authentication based site, it would be extremely difficult, if not impossible to accurately mimic, and obtain a users roles from the domain in a seamless manner. It would be much easier to let windows/IIS provide a users roles for us in an appropriate principal object, and to extract those roles, and mimic a forms authentication process.

 

This method means that to the application, all users have authenticated via the forms authentication method, but that intranet users will have a larger and more specific set of roles attached with their principal object. The diagram below illustrates this.

 

 

Basic Setup

 

 

In ASP.Net, you cannot have a single application with different modes of authentication. For this to work we will need to have 2 applications, or in IIS terms, 2 virtual directories. These act as 2 different entry points to the same application. One is a very simple application that uses windows integrated authentication, the other is the complete/main application using forms authentication. The windows authorisation site exists only for the purposes of extracting an intranet users roles and passing them to the forms authentication site. To examine this in more detail, we will begin by giving a detailed explanation of the Windows Integrated authorisation site/entry point.

 

Windows Integrated Authentication Site

 

 As mentioned above, this site exists only to extract role information from an intranet user, and pass it along to the forms authentication site. Forms authentication (for our purposes) uses cookies as the method of indicating an authenticated user. It can be configured to use cookieless mode, but we will only be using cookies in this scenario. So we will need to peform 3 main functions :

 

Authenticate the user (Performed automatically for us by IIS and in combination with the web.config)

Extract a users roles to pass to main application.

Supply a valid forms authentication ticket to the forms authentication entry point so that the site believes we are a valid authenticated user.

 

Step 1 – Authenticate the User

 

Accomplishing step 1 is easy. When creating the virtual directory using the IIS MMC snap-in, ensure that ‘Anonoynous Access’ is disabled (not checked) and that ‘Integrated Windows Authentication’ is checked/enabled as shown in the diagram below:

 

 

Modifying the Web.Config

 

We also need to ensure that the Web.Config file of our windows authentication entry point application is set up correctly. Below is a sample of a Web.Config file. The important part is the ‘authentication’ element. It must have its ‘mode’ set to ‘Windows’.

 

<system.web>

   …..

   <authentication mode=”windows”>

   …..

</system.web>

 

You might be thinking, in order to get access to a windows principal with roles, we will need to use impersonation. Well actually, no we dont. I too at first thought this, and it still obviously will work fine if we do enable impersonation, but the principal is still passed to our application at an early stage for us to work with. Within the ‘Application_AuthenticateRequest’ event in the Global.asax file of our application is where we will be extracting the role information. If we needed to work with the principal, and have it attached to our currently running thread, then impersonation would be required.

 

Important Note: This application needs to exist in a virtual directory that is a sub-directory or sub-application of the main forms authentication application. The reason for this is that both applications will need to have the same HOST name. Cookies are generated and named according to the host name they apply to. Specifying the same cookie name in code, but using different host names will cause 2 different cookies to be generated because of the different host names. The diagram below shows an example of how the virtual directories should be setup in the IIS manager.  

 

Step 2 – Extracting the user’s role information

 

Extracting the users role information involves a bit of reflection magic. Basically, we use reflection to look inside the principal object that is provided to us by Windows/IIS when the user is authenticated. Please note that this involves reflecting over specific properties of the principal object and is not guaranteed to work in future versions of .Net. It does work, and has been tested in production environments using .Net Version 1.1 (V1.1.4322).

 

The most logical place to extract the role information from the principal is the ‘Application_AuthenticateRequest’ event. Briefly, we look at a particular string array within the principal to extract any role information from the principal. There are some tricks to watch out for, which we will cover shortly. Listed below is some code that will extract the role from a principal object.

 

private static string[] GetRoles(IPrincipal princ)

{

   Type type = princ.GetType();

 

   // Note: This code sets the ‘MAGIC_NUMBER’ field of the principal object.

   FieldInfo field2 = type.GetField(“MAGIC_NUMBER”, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);

   field2.SetValue(princ,40); // This value can be any number but defaults to 23.

 

   princ.IsInRole(“DummyRole”); // This call is required so that the subsystem goes and retrieves a list of roles.

   // Without this call, the principal object does not contain any roles in its internal

   // variables, and thus the code below that uses reflection to get the value of this variable

   // will fail and return NULL.

 

   FieldInfo field = type.GetField(“m_roles”, BindingFlags.Instance | BindingFlags.NonPublic);

   String[] roles = (String[]) field.GetValue(princ);

 

   return roles;

}

 

 

And we obviously need to call this routine from the ‘Application_AuthenticateRequest’ event as in the code shown below:

 

protected void Application_AuthenticateRequest(Object sender, EventArgs e)

{

   WindowsIdentity ident = WindowsIdentity.GetCurrent();

   WindowsPrincipal wind_princ = new WindowsPrincipal(ident);

 

   string[] roles = GetRoles(wind_princ);

  

  

}

 

 

You will notice in the ‘GetRoles’ method above, we set a ‘MAGIC_NUMBER’. This number determines how many roles the user can have before the roles are stored in a hashtable in the principal object, instead of a string array. This is done for performance reasons but the important part is, that if your intranet users are on a domain and happen to have more than this ‘MAGIC_NUMBER’ number of roles, then the string array you are getting the users roles from will be empty. By default, this ‘MAGIC_NUMBER’ is set to 23. The code in the method above provides the ability to change this ‘MAGIC_NUMBER’ to any value you like. For our purposes, we will change it to something higher to make sure we get all the roles in our string array.

 

Step 3 – Simulating a valid forms authentication ticket and supplying the users role information

 

Now we need to put all this together. We need to take the role information we have extracted from the principal, and pass it over to our forms authentication entry point application, and tell that entry point we have a valid autenticated user.

 

The Windows authentication entry point site has extracted the role information. Now it only needs to create a forms authentication ticket, store the roles in the user data, and issue the ticket. The ticket must have the same path and name across both the forms authentication site and the windows authentication site. The code below shows the code that should be placed in the ‘Global.asax – Application_AuthenticateRequest’ event for the storage of the roles and the redirection.

 

protected void Application_AuthenticateRequest(Object sender, EventArgs e)

{

   //NOTE: Because we are encrypting some information and passing it to another site, the MACHINE.CONFIG file needs

   // to have the <machinekey> element set to a static value. By default, this value is autogenerated for each web

   // application on the machine and will therefore fail if you try and pass encrypted tickets/data between

   // web apps.

   WindowsIdentity ident = WindowsIdentity.GetCurrent();

   WindowsPrincipal wind_princ = new WindowsPrincipal(ident);

   string[] roles = GetRoles(wind_princ); // See method above for implementation of this method

 

   string roleData = String.Join(“;”,roles);

   FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,”your_ticket_name”,DateTime.Now,DateTime.Now.AddMinutes(30),false,roleData,”/”);

   string encTicket = FormsAuthentication.Encrypt(ticket);

 

   // NOTE: The name of the HttpCookie must match what the FormsAuth site expects.

   Response.Cookies.Add(new HttpCookie(“YourCookieName”,encTicket));

   // Ticket and cookie issued, now go to the FormsAuth site and all should be well.

   Response.Redirect(“http://localhost/TestFormsAuthSite/IntoSite.aspx&#8221;);

}

 

 

As you can see, we encrypt this ticket using the forms authentication standard routines. For this to work across applications, modifications must be made to the machine.config file to ensure encryption keys are not auto-generated for each application. The modification required is shown below:

 

<!– Your old machine.config entry will resemble the line below –>

<!– <machineKey validationKey=”AutoGenerate,IsolateApps” decryptionKey=”AutoGenerate,IsolateApps” validation=”SHA1″ /> –>

 

<!– You NEED to change that entry to resemble something like the line below. Note: The validationKey/decriptionKey should be your own –>

   <machineKey validationKey=”357356792679345184568256876535689056434617489465″ decryptionKey=”357356792679345184568256876535689056434617489465″ validation=”SHA1″/>

 

 

Lastly, the ‘Global.asax’ file in the forms authentication entry point site must be modified, so that the ‘Application_AuthenticateRequest’ event knows how to decipher a valid ticket issued by the windows authentication entry point site, and assign these roles to the current principal. The web.config of this site must also be setup to have matching attributes (ie. name) as what the Windows Authorisation site is issueing. The code below demonstrates this:

 

Web.Config

 

<authentication mode=”Forms”>

   <forms name=”YourCookieName” <!– This cookie name matches what the Windows Auth site creates –>

      loginUrl=”forms_login.aspx”

      protection=”All”

      timeout=”30″

      path=”/” <!– This same path as what the Windows auth site uses when creating the cookie/auth ticket –>

      requireSSL=”false”

      slidingExpiration=”true”>

   </forms>

</authentication>

 

<authorization>

   <deny users=”?” /> <!– Only allow authenticated users. Add your application and domain specific access roles here –>

</authorization>

 

 

Application_Authenticate Event (Forms Auth site)

 

protected void Application_AuthenticateRequest(Object sender, EventArgs e)

{

   bool cookieFound = false;

 

   HttpCookie authCookie = null;

   HttpCookie cookie;

 

   for(int i=0; i < Request.Cookies.Count; i++)

   {

      cookie = Request.Cookies[i];

 

      if (cookie.Name == FormsAuthentication.FormsCookieName)

      {

         cookieFound = true;

         authCookie = cookie;

         break;

      }

   }

 

   // If the cookie has been found, it means it has been issued from either

   // the windows authorisation site, is this forms auth site.

   if (cookieFound)

   {

      // Extract the roles from the cookie, and assign to our current principal, which is attached to the

      // HttpContext.

      FormsAuthenticationTicket winAuthTicket = FormsAuthentication.Decrypt(authCookie.Value);

      string[] roles = winAuthTicket.UserData.Split(‘;’);

      FormsIdentity formsId = new FormsIdentity(winAuthTicket);

      GenericPrincipal princ = new GenericPrincipal(formsId,roles);

      HttpContext.Current.User = princ;

   }

   else

   {

      // No cookie found, we can redirect to the Windows auth site if we want, or let it pass through so

      // that the forms auth system redirects to the logon page for us.

   }

}

Final Considerations

 

 

The Forms authentication site must also contain code for users who are logging in via the standard logon page. Typically, you would assign a single role of low privilege to identify the user as a non-intranet user (eg. external to the organisation) and assign that role to a principal and attach it to the HttpContext in similar fashion to the code above.

 

At this point, your application can make role checks against the principal attached to the HttpContext in a standard manner. The application does not have to worry about where the user came from, standard role checks are all that is needed, and can therefore tailor the user experience based on the different roles.

 

Conclusion

 

 

The technique I have described here is not trivial, and requires reasonable knowledge of the forms authentication system that .Net uses. The advantage is great though. You can now let both intranet users and external parties access the same application in a consistent manner with the standard role based access checks being applied to determine a user’s functionality and origin. The code to do this is not great and the setup can be tricky, but this technique does work and is currently being used in a number of ways within our organization to great effect.

Advertisements

October 25, 2008 Posted by | Authentication in ASP.NET, Technology | , | 9 Comments

Authentication in ASP.NET

Source: http://www.c-sharpcorner.com/UploadFile/lmoningi/AuthenticationAndAuthorizatio11252005233533PM/AuthenticationAndAuthorizatio.aspx

 

There are two closely interlinked concepts at the heart of security for distributed applications – authentication and authorization. Authentication is the process of obtaining some sort of credentials from the users and using those credentials to verify the user’s identity. Authorization is the process of allowing an authenticated user access to resources. Authentication is always proceeds to Authorization; even if your application lets anonymous users connect and use the application, it still authenticates them as being anonymous.

ASP.net provides flexible set of alternatives for authentication. You can perform authentication yourself in code or delegate authentication to other authorities (such as Microsoft Passport). In fact sometimes it seems ASP.net authentication is a bit too flexible; it can be difficult for a new developer to know just where to start. In this article, we review the settings in ASP.net and Internet Information Services (IIS) that control authentication and authorization in ASP.net applications.

 

An ASP.net application has two separate authentication layers. That is because ASP.net is not a standalone product. Rather it is a layer on top of IIS. All requests flow through IIS before they are handed to ASP.net. As a result, IIS can decide to deny access without the ASP.net process even knowing that someone requested a particular page. Here is an overview of the steps in the joint IIS and ASP.net authentication process.

 

1. IIS first checks to make sure the incoming request comes from an IP address that is allowed access to the domain. If not it denies the request.

2. Next IIS performs its own user authentication if it configured to do so. By default IIS allows anonymous access, so requests are automatically authenticated, but you can change this default on a per – application basis with in IIS.

3. If the request is passed to ASP.net with an authenticated user, ASP.net checks to see whether impersonation is enabled. If impersonation is enabled, ASP.net acts as though it were the authenticated user. If not ASP.net acts with its own configured account.

4. Finally the identity from step 3 is used to request resources from the operating system. If ASP.net authentication can obtain all the necessary resources it grants the users request otherwise it is denied. Resources can include much more than just the ASP.net page itself you can also use .Net’s code access security features to extend this authorization step to disk files, Registry keys and other resources.

As you can see several security authorities interact when the user requests and ASP.net page. If things are not behaving the way you think they should, it can be helpful to review this list and make sure you have considered all the factors involved

 

Authentication providers

 

Assuming IIS passes a request to ASP.net, what happens next? The answer depends on the configuration of ASP.net itself. The ASP.net architecture includes the concept of and authentication provider a piece of code whose job is to verify credentials and decide whether a particular request should be considered authenticated. Out of the box ASP.net gives you a choice of three different authentication providers.

 

•The windows Authentication provider lets you authenticates users based on their windows accounts. This provider uses IIS to perform the authentication and then passes the authenticated identity to your code. This is the default provided for ASP.net.

•The passport authentication provider uses Microsoft’s passport service to authenticate users.

•The forms authentication provider uses custom HTML forms to collect authentication information and lets you use your own logic to authenticate users. The user’s credentials are stored in a cookie for use during the session.

Selecting an authentication provider is as simple as making an entry in the web.config file for the application. You can use one of these entries to select the corresponding built in authentication provider:

 

<authentication mode=”windows”>

<authentication mode=”passport”>

<authentication mode=”forms”>

 

ASP.net also supports custom authentication providers. This simply means that you set the authentication mode for the application to none, then write your own custom code to perform authentication. For example, you might install an ISAPI filter in IIS that compares incoming requests to list of source IP addresses, and considers requests to be authenticated if they come from an acceptable address. In that case, you would set the authentication mode to none to prevent any of the .net authentication providers from being triggered.

 

The fig below illustrates the authorization and authentication mechanisms provided by ASP.NET and IIS.

 

Windows authentication and IIS

 

If you select windows authentication for your ASP.NET application, you also have to configure authentication within IIS. This is because IIS provides Windows authentication. IIS gives you a choice for four different authentication methods:

 

Anonymous, basic digest and windows integrated

 

If you select anonymous authentication, IIS doesn’t perform any authentication, Any one is allowed to access the ASP.NET application.

 

If you select basic authentication, users must provide a windows username and password to connect. How ever this information is sent over the network in clear text, which makes basic authentication very much insecure over the internet.

 

If you select digest authentication, users must still provide a windows user name and password to connect. However the password is hashed before it is sent across the network. Digest authentication requires that all users be running Internet Explorer 5 or later and that windows accounts to stored in active directory.

 

If you select windows integrated authentication, passwords never cross the network. Users must still have a username and password, but the application uses either the Kerberos or challenge/response protocols authenticate the user. Windows-integrated authentication requires that all users be running internet explorer 3.01 or later Kerberos is a network authentication protocol. It is designed to provide strong authentication for client/server applications by using secret-key cryptography. Kerberos is a solution to network security problems. It provides the tools of authentication and strong cryptography over the network to help to secure information in systems across entire enterprise

 

Passport authentication

 

Passport authentication lets you to use Microsoft’s passport service to authenticate users of your application. If your users have signed up with passport, and you configure the authentication mode of the application to the passport authentication, all authentication duties are offloaded to the passport servers.

 

Passport uses an encrypted cookie mechanism to indicate authenticated users. If users have already signed into passport when they visit your site, they’ll be considered authenticated by ASP.NET. Otherwise they’ll be redirected to the passport servers to log in. When they are successfully log in, they’ll be redirected back to your site

 

To use passport authentication you have to download the Passport Software Development Kit (SDK) and install it on your server. The SDK can be found at http://msdn.microdoft.com/library/default.asp?url=/downloads/list/websrvpass.aps. It includes full details of implementing passport authentication in your own applications.

 

Forms authentication

 

Forms authentication provides you with a way to handle authentication using your own custom logic with in an ASP.NET application. The following applies if you choose forms authentication.

 

1. When a user requests a page for the application, ASP.NET checks for the presence of a special session cookie. If the cookie is present, ASP.NET assumes the user is authenticated and processes the request.

2. If the cookie isn’t present, ASP.NET redirects the user to a web form you provide

3. You can carry out whatever authentication, checks you like in your form. When the user is authenticated, you indicate this to ASP.NET by setting a property, which creates the special cookie to handle subsequent requests.

 

Configuring Authorization

 

After your application has authenticated users, you can proceed to authorize their access to resources. But there is a question to answer first: Just who is the user to whom you are grating access? It turns out that there are different answers to that question, depending on whether you implement impersonation. Impersonation is a technique that allows the ASP.NET process to act as the authenticated user, or as an arbitrary specified user

 

ASP.NET impersonation is controlled by entries in the applications web.config file. The default setting is “no impersonation”. You can explicitly specify that ASP.NET shouldn’t use impersonation by including the following code in the file

 

<identity impersonate=”false”/>

 

With this setting ASP.NET does not perform impersonation. It means that ASP.NET will runs with its own privileges. By default ASP.NET runs as an unprivileged account named ASPNET. You can change this by making a setting in the processModel section of the machine.config file. When you make this setting, it automatically applies to every site on the server. To user a high-privileged system account instead of a low-privileged set the userName attribute of the processModel element to SYSTEM. Using this setting is a definite security risk, as it elevates the privileges of the ASP.NET process to a point where it can do bad things to the operating system.

 

When you disable impersonation, all the request will run in the context of the account running ASP.NET: either the ASPNET account or the system account. This is true when you are using anonymous access or authenticating users in some fashion. After the user has been authenticated, ASP.NET uses it own identity to request access to resources.

 

The second possible setting is to turn on impersonation.

 

<identity impersonate=”true”/>

 

In this case, ASP.NET takes on the identity IIS passes to it. If you are allowing anonymous access in IIS, this means ASP.NET will impersonate the IUSR_ComputerName account that IIS itself uses. If you aren’t allowing anonymous access,ASP.NET will take on the credentials of the authenticated user and make requests for resources as if it were that user. Thus by turning impersonation on and using a non-anonymous method of authentication in IIS, you can let users log on and use their identities within your ASP.NET application.

 

Finally, you can specify a particular identity to use for all authenticated requests

 

<identity impersonate=”true” username=”DOMAIN\username” password=”password”/>

 

With this setting, all the requests are made as the specified user (Assuming the password it correct in the configuration file). So, for example you could designate a user for a single application, and use that user’s identity every time someone authenticates to the application. The drawback to this technique is that you must embed the user’s password in the web.config file in plain text. Although ASP.NET won’t allow anyone to download this file, this is still a security risk if anyone can get the file by other means.

 

Best practices

 

Now that you know what the choices are for ASP.NET authentication, here are some points that tell which to choose.

 

•If there is nothing sensitive about the application, stick with no authentication in ASP.NET and anonymous authentication in IIS. That lets anyone who can reach the host computer use the application.

•If you have to authenticate users, there are several choices. If all users have accounts on your network, use Windows authentication in ASP.net with one of the strong IIS authentication settings. If users don’t have network accounts, own custom authentication scheme is preferred, means forms authorization.

•If different users must have different privileges, impersonation in ASP.net configuration files needs to be turn on.

October 24, 2008 Posted by | Authentication in ASP.NET, Technology | , | 4 Comments