Configuring Authorization



Configuring Authorization

Configure security for a Windows service, a serviced component, a .NET Remoting object, and an XML Web service: Configure and control authorization. Authorization methods include file-based authorization and URL-based authorization.

After your application has authenticated users, you can proceed to authorize their access to resources. But there's a question to answer first: Just who is the user who you are granting access to? It turns out that there are different answers to that question, depending on whether you implement impersonation. With impersonation, the ASP.NET process can actually take on the identity of the authenticated user.

Impersonation applies only to applications that use ASP.NET to communicate with the server. For other server applications (such as services and serviced components), impersonation doesn't come into the picture.

After a user has been authenticated and you've decided whether to use impersonation, you can proceed to grant access to resources. ASP.NET uses the role-based authorization features of the .NET Framework for this purpose.

In this section I discuss both impersonation and role-based authorization.

Implementing Impersonation

Configure security for a Windows service, a serviced component, a .NET Remoting object, and an XML Web service: Configure and implement Identity management.

ASP.NET impersonation is controlled by entries in the applicable web.config file. The default setting is no impersonation. You can also explicitly specify this setting by including this element in the file:


<identity impersonate="false"/>

WARNING

SYSTEM Account Is High-privileged Don't run ASP.NET under the SYSTEM account unless you absolutely need to. Because this is a high-privilege account, it opens your server to disastrous changes should a security hole in ASP.NET ever be discovered and exploited.


With this setting, ASP.NET does not perform user impersonation. What does that mean? It means that ASP.NET will always run 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> element of the machine.config. This setting can only be changed in machine.config, so any change automatically applies to every site on the server (and no site can have a setting different from that of the server) when the ASP.NET worker process is restarted. To use a high-privilege system account rather than a low-privilege account, set the userName attribute of the <processModel> element to "SYSTEM".

So when impersonation is disabled, all requests will run in the context of the account running ASP.NET—either the ASPNET account or the SYSTEM account. This is true whether you're using anonymous access or authenticating users in some fashion.

The second possible setting is to turn on impersonation:


<identity impersonate="true"/>

In this case, ASP.NET takes on the identity passed to it by IIS. If you're allowing anonymous access in IIS, it means that ASP.NET impersonates the IUSR_ComputerName account that IIS itself uses. If you're not 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.

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


<identity impersonate="true"

    name="DOMAIN\username"

    password="password"/>

With this setting, all requests are made as the specified user (assuming that the password is correct in the configuration file).

Step-by-Step 11.6 will give you some practice in configuring impersonation.

STEP BY STEP

11.6 Using Impersonation

  1. Add a new Visual C# ASP.NET application named StepByStep11_6 to the solution. Add some text to the default Web form so that you can later verify that it displays properly.

  2. In Windows, select Start, Programs, Administrative Tools, Internet Services Manager.

  3. In Internet Services Manager, drill down into the tree view until you find the node that corresponds to your Visual C# ASP.NET application. This node will have the same name as the application and will be located beneath the Default Web Site node. Right-click the application node and select Properties.

  4. In the Properties dialog box, click the Directory Security tab. Click the Edit button in the Anonymous Access And Authentication Methods section to open the Authentication Methods dialog box.

  5. Uncheck the Anonymous Access check box. Check the Basic authentication check box.

  6. Click Yes if you receive a security warning, and then click OK twice to save your changes.

  7. Add a new Web form to your Visual C# ASP.NET application. Name the new form StepByStep11_6.aspx.

  8. Place a TextBox control (txtAuthenticatedUser) on the form.

  9. Switch to code view and add the following using directive:

    
    using System.Security.Principal;
    
    
  10. Add the following code to the Page_Load() event handler (you'll learn about the Identity and Principal objects in the next section of the chapter):

    
    private void Page_Load(
    
        object sender, System.EventArgs e)
    
    {
    
        WindowsIdentity wi = WindowsIdentity.GetCurrent();
    
        txtAuthenticatedUser.Text = wi.Name;
    
    }
    
    
  11. Edit the web.config file to replace both the <authentication> and <authorization> elements as follows:

    
    <authentication mode="Windows">
    
    </authentication>
    
    
    
    <authorization>
    
       <allow users="*" />
    
    </authorization>
    
    
  12. Set the new Web form as the start page for the project. Set the project as the startup project.

  13. Run the solution. Log in using a Windows username and password. (Depending on your network configuration, you may not receive a login prompt at this point.) The form will display the name of the ASP.NET user (which will be something like DOMAIN\ASPNET) because you don't have impersonation turned on at this point.

  14. Stop the project. Edit the web.config file to include impersonation:

    
    <authentication mode="Windows">
    
    </authentication>
    
    <identity impersonate="true" />
    
    
    
    <authorization>
    
       <allow users="*" />
    
    </authorization>
    
    
  15. Run the solution again. Log in using a Windows username and password. The form will display the username and domain that you supplied for authentication, indicating that the ASP.NET process has taken on the identity of the authenticated user.

Identity and Principal Objects

Within a Visual C# .NET Windows application, authorization is handled by the role-based security system. Role-based security revolves around two interfaces: IIdentity and IPrincipal. For applications that use Windows accounts in role-based security, these interfaces are implemented by the WindowsIdentity and WindowsPrincipal objects, respectively.

NOTE

Custom Authorization If for some reason you want to develop a custom authorization scheme, you can implement IIdentity and IPrincipal in your own classes. In use, these classes function very much like the Windows-based classes that are demonstrated in the remainder of this chapter.


The WindowsIdentity object represents the Windows user who is running the current code. The properties of this object allow you to retrieve information such as the username and his authentication method.

The WindowsPrincipal object adds functionality to the WindowsIdentity object. The WindowsPrincipal object represents the entire security context of the user who is running the current code, including any roles to which he belongs. When the CLR decides which role-based permissions to assign to your code, it inspects the WindowsPrincipal object.

Step-by-Step 11.7 demonstrates the use of the WindowsIdentity and WindowsPrincipal objects.

STEP BY STEP

11.7 Using the WindowsIdentity and WindowsPrincipal Objects

  1. Add a new Visual C# .NET Windows application named StepByStep11_7 to the solution.

  2. In the Solution Explorer, rename the default Form1.cs to StepByStep11_7.cs. Open the form in code view and change all occurrences of Form1 to refer to StepByStep11_7 instead.

  3. Place a ListBox control named lbProperties and a Button control named btnGetProperties on the form.

  4. Switch to the code view and add the following using directive:

    
    using System.Security.Principal;
    
    
  5. Double-click the Button control and add the following code to retrieve properties when the Button control is clicked:

    
    private void btnGetProperties_Click(object sender,
    
       System.EventArgs e)
    
    {
    
        // Tell the CLR which principal policy is in use
    
        AppDomain.CurrentDomain.SetPrincipalPolicy(
    
           PrincipalPolicy.WindowsPrincipal);
    
        lbProperties.Items.Clear();
    
    
    
        // Get the current identity
    
        WindowsIdentity wi = WindowsIdentity.GetCurrent();
    
        // Dump its properties to the listbox
    
        lbProperties.Items.Add("WindowsIdentity:");
    
        lbProperties.Items.Add("  Authentication type: " +
    
           wi.AuthenticationType);
    
        lbProperties.Items.Add("  Is Anonymous: " +
    
           wi.IsAnonymous);
    
        lbProperties.Items.Add("  Is Authenticated: " +
    
           wi.IsAuthenticated);
    
        lbProperties.Items.Add(
    
            "  Is Guest: " + wi.IsGuest);
    
        lbProperties.Items.Add(
    
            "  Is System: " + wi.IsSystem);
    
        lbProperties.Items.Add("  Name: " + wi.Name);
    
        lbProperties.Items.Add("  Token: " +
    
           wi.Token.ToString());
    
    
    
        // Get the current principal
    
        WindowsPrincipal prin = new WindowsPrincipal(wi);
    
        // Dump its properties to the listbox
    
        lbProperties.Items.Add("WindowsPrincipal:");
    
        lbProperties.Items.Add("  Authentication Type: " +
    
            prin.Identity.AuthenticationType);
    
        lbProperties.Items.Add("  Is Authenticated: "  +
    
            prin.Identity.IsAuthenticated);
    
        lbProperties.Items.Add("  Name: " +
    
            prin.Identity.Name);
    
        lbProperties.Items.Add("  Member of Users: " +
    
            prin.IsInRole(@"INFINITY\Users"));
    
    }
    
    

    WARNING

    Modifying the Domain Name This code contains a reference to a specific domain named INFINITY in its call to the IsInRole() method. You should change that to the name of your own domain to test this code.

  6. Set the project as the startup project.

  7. Run the project and click the Get Properties button. You should see output similar to that in Figure.

    Figure. WindowsIdentity and WindowsPrincipal classes enable you to retrieve current user information and also let you evaluate role membership for the current user.

    graphics/11fig08.jpg

The code in Step-by-Step 11.7 first tells the CLR that you're using the standard Windows authentication method, by calling the SetPrincipalPolicy() method of the current application domain. It then retrieves the WindowsIdentity object of the current user by using the static GetCurrent() method of the WindowsIdentity object. After it displays some of the properties of the WindowsIdentity object, it gets the corresponding WindowsPrincipal object by passing the WindowsIdentity object to the constructor of the WindowsPrincipal class.

Note that the properties of the WindowsIdentity object are somewhat richer than those of the WindowsPrincipal object, but that the WindowsPrincipal object lets you evaluate role membership for the current user. If you want to work with only the WindowsPrincipal object, you can retrieve it from the Thread.CurrentPrincipal() static method.

Verifying Role Membership

One way to manage role-based security is to use the IsInRole() method of the WindowsPrincipal object to determine whether the current user is in a specific Windows group (see Step-by-Step 11.8). The results of this method call can be used to modify your application's user interface or to perform other tasks.

STEP BY STEP

11.8 Verifying Role Membership

  1. Add a new Visual C# .NET Windows application named StepByStep11_8 to the solution.

  2. In the Solution Explorer, rename the default Form1.cs to StepByStep11_8.cs. Open the form in code view and change all occurrences of Form1 to refer to StepByStep11_8 instead.

  3. Place a Label control (lblMembership) on the form.

  4. Switch to the code view and add the following using directives:

    
    using System.Security.Principal;
    
    using System.Threading;
    
    
  5. Double-click the form and add the following code to handle the Load event of the form:

    
    private void StepByStep11_8_Load(object sender,
    
       System.EventArgs e)
    
    {
    
        // Tell the CLR to use Windows security
    
        AppDomain.CurrentDomain.SetPrincipalPolicy(
    
           PrincipalPolicy.WindowsPrincipal);
    
        // Get the current principal object
    
        WindowsPrincipal prin =
    
           (WindowsPrincipal) Thread.CurrentPrincipal;
    
        // Determine whether the user is an admin
    
        Boolean fAdmin = prin.IsInRole(
    
           WindowsBuiltInRole.Administrator);
    
        // Display the results on the UI
    
        if(fAdmin)
    
            lblMembership.Text =
    
               "You are in the Administrators group";
    
        else
    
            lblMembership.Text =
    
               "You are not in the Administrators group";
    
    }
    
    
  6. Set the project as the startup project.

  7. Run the project. The form will tell you whether or not you're in the Administrators group.

There are three available overloaded forms of the IsInRole() method:

  • IsInRole(WindowsBuiltInRole)— This form uses one of the WindowsBuiltInRole constants to check for membership in the standard Windows groups.

  • IsInRole(String)— This form checks for membership in a group with the specified name.

  • IsInRole(Integer)— This form checks for membership in a group by using the specified role identifier (RID). RIDs are assigned by the operating system and provide a language-independent way to identify groups.

Using the PrincipalPermission Class

In the previous section I discussed the use of the IsInRole() method of the WindowsPrincipal object in managing role-based security. An alternative way to manage identities is to perform imperative or declarative security checking with role-based security by using the PrincipalPermission class, as in Step-by-Step 11.9, or the PrincipalPermissionAttribute attribute.

STEP BY STEP

11.9 Using the PrincipalPermission Class

  1. Add a new Visual C# .NET Windows application named StepByStep11_9 to the solution.

  2. In the Solution Explorer, rename the default Form1.cs to StepByStep11_9.cs. Open the form in code view and change all occurrences of Form1 to refer to StepByStep11_9 instead.

  3. Switch to the code view and add the following using directives:

    
    using System.Security.Permissions;
    
    using System.Security.Principal;
    
    
  4. Double-click the form and add the following code, which should run when the form is loaded:

    
    private void StepByStep11_9_Load(object sender,
    
       System.EventArgs e)
    
    {
    
        // Tell the CLR to use Windows security
    
        AppDomain.CurrentDomain.SetPrincipalPolicy(
    
          PrincipalPolicy.WindowsPrincipal);
    
        // Create a new PrincipalPermission object
    
        // This object matches any user
    
        // in a group named Developers
    
        PrincipalPermission pp = new PrincipalPermission(
    
            null, "Developers");
    
        // See whether the user is in the group
    
        try
    
        {
    
            pp.Demand();
    
            MessageBox.Show(
    
                "You are in the Developers group");
    
        }
    
        catch (Exception ex)
    
        {
    
            MessageBox.Show("Exception: " + ex.Message);
    
        }
    
    }
    
    
  5. Set the project as the startup project.

  6. Run the project. If you're a member of a group named Developers, you see a message box that tells you so. If you are not a member of that group, you see a security exception message from the PrincipalPermission class, telling you that the requested permission could not be granted.

Checking permissions by using role-based security is very similar to checking permissions by using code access security. The difference lies in what you are checking. The constructor for the PrincipalPermission class accepts both a name and a group name, so you can also use it to check whether a specific user is running the code.

REVIEW BREAK

  • The .NET Framework supports both authentication and authorization. Authentication refers to verifying a user's identity. Authorization refers to granting rights based on that identity.

  • Users must satisfy any IIS authentication requirements before ASP.NET authentication takes over.

  • ASP.NET authentication uses interchangeable authentication providers. You can choose Windows authentication, Passport authentication, or forms-based authentication.

  • Identity impersonation lets the ASP.NET process act as the authenticated user.

  • The WindowsPrincipal and WindowsIdentity classes let you check the authentication status of the current user.

  • You can use the IsInRole() method of the WindowsPrincipal object to check for membership in Windows groups.

  • The PrincipalPermission class enables you to perform declarative and imperative role-based security operations.