Chapter 8 - An Authentic Approach to Token Identity

Introduction

I guess most people have seen a sitcom on TV where some unfortunate member of the cast is faced with a large red button carrying a sign that says "Do not press this button." You know that, after the requisite amount of facial contortions and farcical fretting, they are going to press the button and some comedic event will occur. So it's reasonably certain that any user authorization strategy you adopt that contains an element that simply asks the user not to press that button unless he is a manager or administrator is not likely to provide a secure environment for your enterprise application.

User authorization—controlling what your users can and cannot do with your application—is a vital ingredient of a robust security strategy. In general, an application UI should prevent users from attempting actions for which they are not eligible; usually by disabling or even hiding controls that, depending on their permissions within the application, they are not permitted to use. And, of course, the application should check that users are authorized to carry out all operations that they initiate, whether it is through a UI or as a call from another layer or segment of the application.

The Security Application Block provides features that can help you to implement authorization for your applications, and can simplify the task by allowing you to maintain consistent security practices across the entire application and your enterprise as a whole. It makes it easier for you to implement authorization using standard practices, and you can extend the block to add specific functionality that you require for your own scenarios.

What Does the Security Block Do?

The Security Application Block implements two related features. It provides the capability to configure and manage sets of authorization rules using a variety of rule providers, and can help you to cache credentials for your application to use where it must make repeated authorization checks. These two features combine to provide an environment for implementing authorization in a flexible way, while allowing the details of the authorization policies (the sets of rules) to be administered without requiring changes to the application—eliminating the requirement to recompile, test, and redeploy the application as the policies change. It also means that administrators can manage the policies using Group Policy if required.

In your application code, you can quickly and easily create tokens for users, cache these tokens, expire them, and check if users are authorized to perform specific tasks or operations. These features make use of one or more authorization rule providers and security caches that you define for your application, and even use across multiple applications. The following sections of this chapter explain what an authorization rule provider and a security cache are, and how they help you to implement a security strategy for your applications.

What Are Authorization Rule Providers?

An authorization rule provider is a component or service that allows you to define rules. Using a rule you specify a task or operation that users may perform, and you then allocate users and groups to this task or operation. The Security block uses these rules to determine whether a specific user or role is authorized to execute a specified task or operation.

The Security block includes a rule provider that stores the information as a series of expressions, one for each task or operation, in the application configuration file. You can encrypt this section of the configuration file to prevent anyone who can access it from being able to see the expressions. Alternatively, you can use the Windows® Authorization Manager (AzMan) provider, part of the current Microsoft® Windows operating systems, which allows you to store the authorization rules in a variety of locations, and include Windows users and groups in the rules. Enterprise Library includes an assembly named Microsoft.Practices.EnterpriseLibrary.Security.AzMan.dll that allows it to interact with AzMan.

About Authorization Manager (AzMan)

While it's useful to be able to define your security roles and authorization rules in the application configuration file, what would be really cool is to be able to make use of the groups, roles, and user accounts already defined on your system or network, and store the rules in some portable format such as an XML file or (perhaps less portable) a database. The details of Windows users and groups are stored in Active Directory®, and—while you can write code to access the information—using Active Directory is not a trivial exercise. Windows Authorization Manager (AzMan) gives you a way to access this information, and administer security rules in other locations, without requiring complex code. It even provides a GUI that you can use to create authorization rules and administer these rules.

The Windows AzMan provider is part of the operating system in Windows XP Professional and Windows Server® 2003 and later. The GUI is part of the operating system in Windows Vista® and Windows Server 2003 and later. In Windows Vista, Windows Server® 2008, and Windows 7, AzMan provides additional capabilities. For more information about AzMan, see the following resources:

AzMan allows you to define an application, the roles for that application, and the operations (such as submit order or approve expenses) that the application exposes. For each operation, you can define users and groups that can execute that operation. You can include local and domain user accounts and account groups stored in Active Directory. You can store your authorization rules in Active Directory, in an XML file, or in a database.

Why Do I Need a Security Cache?

Unless all of the features of your application are meant to be completely available to anonymous users, you will need to authenticate users and definitively identify each one. You can then determine what that user is and is not permitted to do inside your application. Common approaches to authentication include logon dialogs where users enter their user name and password (and, perhaps, additional information that helps to confirm their identity), and other mechanisms such as smart card readers, fingerprint readers, and more.

You may force users to authenticate when they first access the application, or at some later stage when they try to execute some activity that has limited permissions. This really depends on whether you want to hide or disable elements of the UI, or you are happy to accept requests and then authenticate at that point in your application. For example, a Web service application will usually authenticate users when a request is received, while a Windows Forms application will usually authenticate users when they start the application.

What you don't want to do is continually annoy users by forcing them to reauthenticate every time they try to execute some operation or carry out some task. For example, if you are browsing a shopping Web site and adding to your cart all of those science fiction DVDs you want to be able to watch over and over again, you wouldn't expect to have to enter your account logon details for every item. Once your application knows who a user is, it should reuse the results of the initial authentication if possible.

To be able to do this, you must cache the user's credentials for a predetermined period when you first authenticate them, and generate a token that represents the user. You may decide to cache the credentials for the duration a Windows Forms application is running, or for the duration of the user's session in ASP.NET. You may even decide to persist them in a cache that survives application and machine restarts (such as the user-specific isolated storage mechanism) if you want to allow the logged-on user of the machine to be able to access the application without reauthenticating. An example is the Windows operating system, which forces you to log on when you first start it up, but can then reuse persistently cached credentials to connect to other resources such as mapped drives.

The Security Application Block allows you to configure one or more Security Caches that use an in-memory cache, and optionally a persistent backing store, to cache user credentials for specific periods and obtain a token that you can use to check the user's identity at some future stage in your application.

Note

An alternative approach to caching identities you may consider is to use the Microsoft .NET Framework version 4.0 System.Runtime.Caching capabilities. However, you would then need to implement suitable methods that accept and return identities, and ensure that you correctly secure the stored content.

How Do I Configure the Security Block?

Like all of the Enterprise Library application blocks, you start by configuring your application to use the block, as demonstrated in Chapter 1, "Introduction." The Security Settings section of the configuration for the Security block contains three areas, shown in Figure 1. The first is where you specify the authorization providers you want to use. Below that is the area where you configure one or more security caches for your security tokens. Your code can store tokens in this cache, and retrieve them when required. You can even persist the credentials across application restarts by defining backing stores for credentials. The third area is where you configure the authorization rules that define the users, groups, and operations related to your application.

Figure 1

The security settings section

Ff953196.f3700470-e572-4272-b0de-3806fa362a92-thumb(en-us,PandP.50).png

Figure 1 shows the configuration for the example application we provide for this chapter. You can see the areas where we defined the authorization providers and the security cache. Because we specified the Caching Application Block as the security cache, the configuration tool added the Caching block to the configuration automatically. We added an isolated storage backing store to the Caching block to persist credentials, and specified a symmetric storage provider for this store to protect the persisted credentials. This automatically added the Cryptography block to the configuration, and we specified a DPAPI symmetric crypto provider to perform the encryption.

Note

For more information about configuring the Caching block, see Chapter 5, "A Cache Advance for your Applications." For more information about configuring the Cryptography block, see Chapter 7 "Relieving Cryptography Complexity."

Configuring Authorization Rules

The way that you configure your authorization rules depends on the type of authorization provider you are using. If you use the AzMan provider, you must configure the authorization rules using the AzMan GUI, or through the command line or scripting. If you choose to use the standard authorization rule provider instead, you must configure the authorization rules for this provider.

Each rule equates to a task or operation that your users may perform, and for which you want to be able to authorize these users to check if they should be allowed to execute that task. Click the "..." button in the Rule Expression property of an Authentication Rule to open the Rule Expression Editor dialog, which makes it easier to generate the expressions for each of the rules you define. It helps you to insert the appropriate tokens that indicate individual identities, roles, and anonymous users; plus the operators that allow you to specify compound rules. For example, the following expression identifies users who are members of the Managers role or have the names Alice or Bob, but excludes any managers who are also members of the ITAdmin role:

(R:Managers OR I:Alice OR I:Bob) AND NOT R:ITAdmin

If you specify this expression for a rule named Update Database, you can use the Authorize method of the Security block to ensure that only users for whom the expression evaluates to true can execute this task. You'll see how in the following sections of this chapter.

How Do I Use the Security Block?

After you configure the block, as described in the previous sections of this chapter, you can write code in your application that uses the features of the block. However, first, you must add references to the appropriate Enterprise Library assemblies to your project. In addition to the Enterprise Library assemblies you require in every Enterprise Library project (listed in Chapter 1, "Introduction"), you should reference or add to your bin folder the following assemblies:

  • Microsoft.Practices.EnterpriseLibrary.Security.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.Cache.CachingStore.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.Caching.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.Caching.Cryptography.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.AzMan.dll

You need the caching assemblies only if you are using a cache to store credentials. You need the AzMan assembly only if you are using the AzMan rule store.

Now, after adding references to the relevant namespaces to your project, you are ready to write some code. The following sections demonstrate the tasks you can accomplish, and provide more details of the way the block helps you to implement a common and reusable strategy for security.

Diving in With an Example

You can download an example application (a simple console-based application) that demonstrates all of the scenarios you will see in the remainder of this chapter. You can run this directly from the bin\debug folder, or open the solution named Security in Microsoft Visual Studio® to see all of the code as you run the examples.

Note

Before you attempt to run the example, you must create a new encryption key for the block to use to encrypt the data when using a symmetric encryption provider. This is because the key is tied to either the user or the machine, and so the key included in the sample files will not work on your machine. In the configuration console, select the RijndaelManager symmetric provider and click the "..." button in the Key property to start the Key Wizard. Use this wizard to generate a new key, save the key file, and automatically update the contents of App.config.
You must also edit the path in the Store Location property of the AzMan authentication provider so that it reflects the location of the file named Example.xml. This file is included in the examples, and is located in the same folder as the main program files, which is [path-to-samples]\Security\Security.

Before you start to use the objects in the block, you must resolve an instance of the security cache and authorization providers you want to use in your application. The example we provide uses the simplest approach—the GetInstance method of the Enterprise Library container, as shown here.

// Resolve the cache and auth provider objects from the container.
ISecurityCacheProvider secCache 
  = EnterpriseLibraryContainer.Current.GetInstance<ISecurityCacheProvider>(
                                                   "CacheProvider");
IAuthorizationProvider ruleAuth 
  = EnterpriseLibraryContainer.Current.GetInstance<IAuthorizationProvider>(
                                                   "RuleProvider");
IAuthorizationProvider azmanAuth 
  = EnterpriseLibraryContainer.Current.GetInstance<IAuthorizationProvider>(
                                                   "AzManProvider");

Caching a User Identity and Obtaining a Temporary Token

The first example, Authenticate a user and cache the identity, shows how you can use the Security block to cache both an authenticated identity and a user principal, and return temporary tokens that serve as an alternative to user credentials for the duration of the user session. The following code, taken from the example, first checks that the user is authenticated within the operating system and, if so, displays details of the user's identity using a separate routine named ShowUserIdentityDetails. We'll look at that routine in a short while.

The code then caches this Windows identity in the security cache to obtain the token, and displays details of this token. Then it generates a new generic principal for this identity, defining it as a member of a role named FieldSalesStaff, and displays the details of this new principal using another routine named ShowGenericPrincipalDetails. Again, we'll look at this routine in a short while. Next, the code caches the generic principal, collects the token from the security cache, and displays details of this token.

// Get current Windows Identity and check if authenticated.
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity.IsAuthenticated)
{
  Console.WriteLine("Current user identity obtained from Windows:");
  ShowUserIdentityDetails(identity);

  // Cache the Windows Identity and save the token in a variable.
  identityToken = secCache.SaveIdentity(identity);
  Console.WriteLine("Current user identity has been cached.");
  Console.WriteLine("The IIdentity security token is '{0}'.",
                    identityToken.Value);

  // Generate a Generic Principal for this identity and save in cache.
  IPrincipal principal = new GenericPrincipal(identity, 
                             new string[] {"FieldSalesStaff"});
  Console.WriteLine("Created a new Generic Principal for this user:");
  ShowGenericPrincipalDetails(principal);
  principalToken = secCache.SavePrincipal(principal);
  Console.WriteLine("Current user principal has been cached.");
  Console.WriteLine("The IPrincipal security token is '{0}'.", 
                     principalToken.Value);
}
else
{
  Console.WriteLine("Current user is not authenticated.");
}

The tokens are stored in program-wide variables and are therefore available to code in the other examples for this chapter.

You can also use the SaveProfile method of the security cache to store a user's profile (such as the user's ASP.NET profile), and obtain a token that you can use to access it again when required.

Displaying User Identity Details

The previous code uses a separate routine named ShowUserIdentityDetails that does just that. It displays the values of the two properties common to all types that implement the IIdentity interface, and then checks if the identity is actually an instance of the WindowsIdentity class. If it is, the code displays the values of the additional properties that are specific to this type.

void ShowUserIdentityDetails(object identity)
{
  IIdentity iid = identity as IIdentity;
  Console.WriteLine("- Current user {0} is authenticated.", iid.Name);
  Console.WriteLine("- Authentication type: {0}.", iid.AuthenticationType);
  if (identity is WindowsIdentity)
  {
    WindowsIdentity winIdentity = identity as WindowsIdentity;
    Console.WriteLine("- Impersonation level: {0}.",
                      winIdentity.ImpersonationLevel);
    Console.WriteLine("- Is the Guest account: {0}.", winIdentity.IsGuest);
    Console.WriteLine("- Is the System account: {0}.", winIdentity.IsSystem);
    Console.WriteLine("- SID value: '{0}'.", winIdentity.User.Value);
    Console.WriteLine("- Member of {0} account groups.",
                      winIdentity.Groups.Count);
  }
}

Displaying Generic Principal Details

The code you saw earlier uses a separate routine named ShowGenericPrincipalDetails that displays details of a generic principal. It shows the identity name, and then calls the IsInRole method to check if this principal is defined for two roles named SalesManagers and FieldSalesStaff.

void ShowGenericPrincipalDetails(IPrincipal principal)
{
  Console.WriteLine("- Current user is {0}.", principal.Identity.Name);
  Console.WriteLine("- IsInRole 'SalesManagers': {0}.",
                    principal.IsInRole("SalesManagers"));
  Console.WriteLine("- IsInRole 'FieldSalesStaff': {0}.",
                    principal.IsInRole("FieldSalesStaff"));
}

When you run the example, you will see output like that below. Of course, the identity details will differ for your logged-on account. Notice, however, that the output shows that the principal is a member of only one of the two roles we tested for. You can also see the value of the tokens generated by the security cache when we cached the identity and principal.

Current user identity obtained from Windows:
- Current user SOME-DOMAIN\username is authenticated.
- Authentication type: Kerberos.
- Impersonation level: None.
- Is the Guest account: False.
- Is the System account: False.
- SID value: 'S-1-5-21-xxxxxxx-117609710-xxxxxxxxx-1108'.
- Member of 12 account groups.
Current user identity has been cached.
The IIdentity security token is '02acc9a5-6dac-4b40-a82d-a16f3d9ddc37'.

Created a new Generic Principal for this user:
- Current user is SOME-DOMAIN\username.
- IsInRole 'SalesManagers': False.
- IsInRole 'FieldSalesStaff': True.
Current user principal has been cached.
The IPrincipal security token is 'ffcbc717-63ad-4a8b-82e2-26af54741ac1'.

Authenticating a User Using a Token

After you cache an identity and obtain a token, you can use this token to authenticate a user throughout your application. At any point in your code, you can use the token to obtain an identity or principal that you have stored in the cache.

The example Retrieve a user's identity from the cache shows how you can retrieve a cached identity using a token. The code displays the value of the token, and then calls the GetIdentity method to retrieve the matching identity from the cache. This method returns null if the identity is not found in the cache.

// Check if the user has run the option that caches the identity and principal. 
if (null != identityToken)
{
  // Check if the user has been authenticated and the identity has been cached. 
  Console.WriteLine("The IIdentity security token is '{0}'.",
                    identityToken.Value);
  Object identity = secCache.GetIdentity(identityToken);
  if (null != identity)
  {
    // Identity was found in cache.
    Console.WriteLine("User identity has been retrieved from the cache:");
    ShowUserIdentityDetails(identity);
  }
  else
  {
    // Identity removed from cache due to time expiration, or explicitly in code.
    Console.WriteLine("Identity not found in cache for the specified token.");
  }
}
else
{
  Console.WriteLine("You must obtain a token by caching the current "
                  + "identity before you can retrieve it.");
}

You can also use the GetProfile method of the security cache to retrieve a user's profile (such as the user's ASP.NET profile) by supplying a suitable token obtained from the security cache using the SaveProfile method.

The example produces output like the following, though the actual values will, of course, differ for your account identity.

The IIdentity security token is '02acc9a5-6dac-4b40-a82d-a16f3d9ddc37'.
User identity has been retrieved from the cache:
- Current user SOME-DOMAIN\username is authenticated.
- Authentication type: Kerberos.
- Impersonation level: None.
- Is the Guest account: False.
- Is the System account: False.
- SID value: 'S-1-5-21-xxxxxxx-117609710-xxxxxxxxx-1108'.
- Member of 12 account groups.

After you retrieve an identity, principal, or profile, you can compare the values with those of the current user or use it to authenticate a user for other processes or systems.

Terminating a User Session and Expiring the Token

When a user logs out of the application, or when you wish to invalidate the cached identity, you can use the methods of the security cache. As you would expect, the ExpireIdentity method expires a token corresponding to a cached identity, the ExpirePrincipal method expires a token corresponding to a cached principal, and the ExpireProfile method expires a token corresponding to a cached user profile. The example Expire an authenticated user demonstrates how you can expire a cached identity and a cached principal using these methods, as shown below.

// Check if the user has run the option that caches the identity and principal. 
if (null != identityToken)
{
  Console.WriteLine("The IIdentity security token is '{0}'.", 
                    identityToken.Value);

  // Expire the identity token in the cache.
  secCache.ExpireIdentity(identityToken);
  Console.WriteLine("The identity for this token has been expired "
                  + "and removed from the cache.");
  Console.WriteLine("The IPrincipal security token is '{0}'.", 
                    principalToken.Value);

  // Expire the principal token in the cache.
  secCache.ExpirePrincipal(principalToken);
  Console.WriteLine("The principal for this token has been expired "
                  + "and removed from the cache.");
}
else
{
  Console.WriteLine("You do not have a token that you can use to "
                  + "expire an identity.");
}

When you run this example, you will see the values of the tokens before they are expired, and messages indicating that they were removed from the cache.

The IIdentity security token is 'e303fd67-331a-45b0-94d4-087e462cacda'.
The identity for this token has been expired and removed from the cache.

The IPrincipal security token is 'd6563752-78ed-489a-86fa-efd76c97a976'.
The principal for this token has been expired and removed from the cache.

Checking If a User Is Authorized to Perform a Task

One of the main reasons for using the Security block to manage identities is that it makes it easy to check if a user is authorized to perform a specified task or operation. The Security block contains two authorization providers, though you can create your own and integrate them with the Security block if you wish.

To check if a user is authorized, you call the Authorize method of an authorization provider, passing to it the user principal and the name of the task or operation. The Authorize method returns either true or false. The two providers included in the block are the authorization rule provider and the AzMan authorization provider (for details of these providers, see "What Are Authorization Rule Providers?" near the beginning of this chapter). The examples we present for this chapter include one that uses the authorization rule provider and one that uses the AzMan authorization provider.

Using Security Block Configured Rules

If you only need to store authorization rules within the configuration of your application and have them fully managed by the Security block, you can use the authorization rule provider. As you saw earlier in this chapter, you configure a series of authorization rules for your application. Each rule defines an expression that specifies which users can access a specific task or carry out a specific operation.

The example Authorize a user for a process using a stored rule demonstrates this approach to authorization. In the application configuration we defined two rules:

  • The rule named UpdateSalesData uses the expression "R:Administrators OR R:SalesManagers." This allows a user who is a member of the Administrators role or the SalesManagers role to execute this task.
  • The rule named ReadSalesData uses the expression "R:Users OR R:FieldSalesStaff OR R:SalesManagers." This allows a user who is a member of the Users, FieldSalesStaff, or SalesManagers role to execute this task.

The example code starts by displaying the value of the current principal token stored in the application-level variable (you must execute the first example to authenticate yourself and obtain a token before you can run this example). Then it retrieves the principal from the security cache using this token, and calls a separate routine named AuthorizeUserWithRules that performs the authorization.

The AuthorizeUserWithRules routine takes as parameters the generic principal as a type that implements the IPrincipal interface, and a reference to the authorization provider to use. In this example, this is the Security block authorization rule provider resolved from the Enterprise Library container and stored in the variable named ruleAuth when the example application starts. We showed how you can obtain instances of the two types of authorization provider in the section "Diving in With an Example," earlier in this chapter.

// Check if the user has run the option that caches the identity and principal. 
if (null != principalToken)
{
  // First try authorizing tasks using the cached Generic Principal.
  Console.WriteLine("The IPrincipal security token is '{0}'.", 
                    principalToken.Value);

  // Retrieve the user principal from the security cache using the token.
  IPrincipal principal = secCache.GetPrincipal(principalToken);
  if (null != principal)
  {
    // Check if this user is authorized for tasks using the Rule Provider.
    AuthorizeUserWithRules(principal, ruleAuth);
  }
  else
  {
    // Identity removed from cache due to time expiration, or explicitly in code.
    Console.WriteLine("Principal not found in cache for the specified token.");
  }
}
else
{
  Console.WriteLine("You must obtain a token by caching the current identity " 
                  + "before you can use it to check authorization rules.");
}

The following code shows the AuthorizeUserWithRules routine we used in the previous example. It simply calls the Authorize method of the authorization provider—once for the UpdateSalesData task and once for the ReadSalesData task—and displays the results.

void AuthorizeUserWithRules(IPrincipal principal, 
                            IAuthorizationProvider authProvider)
{
  // Determine whether user is authorized for rule defined as "UpdateSalesData".
  bool canUpdateSalesData = authProvider.Authorize(principal, "UpdateSalesData");
  Console.WriteLine("User can execute 'UpdateSalesData' task: {0}",
                    canUpdateSalesData);

  // Determine whether user is authorized for rule defined as "ReadSalesData".
  bool canReadSalesData = authProvider.Authorize(principal, "ReadSalesData");
  Console.WriteLine("User can execute 'ReadSalesData' task: {0}",
                    canReadSalesData);
}

When you run this example, you will see output similar to that below. The code in the first example of this chapter, which authorizes the user and caches the identity and principal, defines the principal it generates as a member of only the FieldSalesStaff role, and so the user is authorized only for the ReadSalesData task.

The IPrincipal security token is '77a9c8af-9691-4ae4-abb5-0e964dc4610e'.
User can execute 'UpdateSalesData' task: False
User can execute 'ReadSalesData' task: True

Using AzMan Provider Rules

The second example of authorization, Authorize a user for a process using AzMan rules, uses the Windows Authorization Manager (AzMan) provider. In the example, we defined rules for the same two tasks you saw in the previous example: UpdateSalesData and ReadSalesData. However, AzMan depends on being able to access Windows account details using the security identifier (SID), and so rules in the file named Example.xml we provide with the examples may not be able to authenticate you on your machine. It will only work if you are using a local machine account or your current domain logon account can access the Active Directory® store to obtain information. You should open the Example.xml file in AzMan (a snap-in for the Microsoft Management Console (MMC)) and edit the rules it contains to specify your own local or domain accounts to experiment with AzMan authorization.

The example code is similar to what you saw when we used the Security block authorization rule provider in the previous example. It obtains the current user principal from the security cache using the token stored in the application-level variable, and calls the same AuthorizeUserWithRules method as the previous example to check if this principal is authorized for the UpdateSalesData and ReadSalesData tasks. This example then generates a WindowsPrincipal for the current user and checks if this is authorized for the UpdateSalesData and ReadSalesData tasks.

The main differences in the code for this example are that it passes a reference to the AzMan authorization provider created when the program starts to the AuthorizeUserWithRules routine, as shown here.

// First try authorizing tasks using the cached Generic Principal.
IPrincipal genPrincipal = secCache.GetPrincipal(principalToken);
if (null != genPrincipal)
{
  // Check if this user is authorized for tasks by AzMan.
  AuthorizeUserWithRules(genPrincipal, azmanAuth);
}
...

// Now try checking for authorization for tasks using cached WindowsIdentity
IIdentity identity = secCache.GetIdentity(identityToken);
if (null != identity)
{
  // Generate a WindowsPrincipal from the IIdentity.
  IPrincipal winPrincipal = new WindowsPrincipal(identity as WindowsIdentity);

  // Check if this user is authorized for tasks by AzMan.
  AuthorizeUserWithRules(winPrincipal, azmanAuth);
  // Note: this will only work if you are using a local machine account or your
  // current domain account can access directory store to obtain information. 
}

When you run this example, after configuring the AzMan rules to suit your own machine and account, you should be able to see a result similar to that shown here.

The IPrincipal security token is '77a9c8af-9691-4ae4-abb5-0e964dc4610e'.
User can execute 'UpdateSalesData' task: False
User can execute 'ReadSalesData' task: True

The IIdentity security token is '3b6eb4a7-b958-4cc2-b2b9-112cd58c566d'.
User can execute 'UpdateSalesData' task: False
User can execute 'ReadSalesData' task: True

Creating Custom Authorization Providers

Although the Security Application Block contains only two authorization providers and two caching providers, you can extend it easily to add new providers if none of those included are exactly right for your own scenarios. The block contains a base class named AuthorizationProvider that you can inherit from and extend to perform custom authorization. You simply need to implement the Authorize method, and then integrate your new provider with Enterprise Library.

You can also implement custom cache managers and cache backing stores and integrate these with the Caching Application Block to provide a custom caching mechanism for credentials, and implement a custom cryptography provider for the Cryptography Application Block that you can then use to encrypt cached credentials. For more information about creating custom providers, cache managers, and backing stores, see the online documentation and the help files installed with Enterprise Library and available online at https://go.microsoft.com/fwlink/?LinkId=188874.

Summary

This chapter described how you can use the Security Application Block to simplify common tasks such as caching authenticated user credentials and checking if users are authorized to perform specific tasks. While the code required to implement these tasks without using the Security block is not overly onerous, the block does save you the effort of writing and testing the same code in multiple locations. It also allows you to use a variety of different cache and authorization providers, depending on your requirements, and change the provider through configuration. Administrators and operators will find this feature useful when they come to deploy your applications in different environments.

The chapter described the scenarios for using the Security block, and explained the concepts of authorizing users and caching credentials. It then presented detailed examples of how you can use the features of the block in a sample application. You will find more details on specific tasks, such as configuration and deployment, in online documentation and the help files installed with Enterprise Library.

Next | Previous | Home | Community