Download the code for this article here.
This article is the third in a short series of articles focused on AppFabric Access Control, a feature of the Windows Azure platform (previously called the Access Control Service). In the first article of this series, "Access Control in the Cloud: Windows Azure AppFabric's ACS," I provided you with an overview of Access Control features. In the second article, "WCF and the Access Control Service," I discussed the code required for Windows Communication Foundation (WCF) clients and services to leverage Access Control—including custom components I created to simplify this experience. In this article, I will focus on ASP.NET and Access Control. Specifically, I'll discuss scenarios that involve protecting web resources such as Web Form pages; requests targeting custom HTTP handlers, MVC endpoints, or ASP.NET-compatible WCF services using a custom HTTP module; and other custom components in a way compatible with Windows Identity Foundation (WIF).
Note: It will help significantly if you have read the previous two articles before diving in to this article.
Securing Web Resources
What these techniques share in common is that they are typically secured by the ASP.NET application. Only authenticated users with a session cookie can call the web resource in question. Figure 1 illustrates a few possible scenarios:
• a Web Form with AJAX script calling a custom HTTP handler
• an HTML-based MVC view using jQuery to call a REST-based MVC controller endpoint
• a Silverlight client using WebClient to call an ASP.NET compatible, REST-based WCF service
For each of these scenarios the user logs in to the web application and is issued a session cookie prior to reaching the Web Form, MVC View, or Silverlight page. At this point, each client can freely call a web resource protected by the application, usually using SSL for transport protection, mutual authentication, and protection from man-in-the-middle attacks. If a Windows client wants to call one of these web resources (as a service), a different mode of authentication is necessary since a session cookie doesn't exist for that scenario.
Note: This article does not describe how to use cryptography libraries to protect keys, but it is absolutely a necessary step from any client platform if you are using symmetric keys to authenticate to Access Control.
Assuming you are using AppFabric Access Control to secure web resources illustrated in Figure 1, the remainder of this article focuses on how to implement a security model compatible with WIF, so that you can easily authenticate calls supplying an Access Control token and use claims-based security to authorize access.
Scenario Overview and Access Control Review
In previous articles, I discussed the protocols behind Access Control (WRAP and SWT), how to configure Access Control, how to request tokens using WCF's WebChannelFactory
Figure 2 illustrates a scenario where a client application requests an Access Control token to call a web resource hosted in an ASP.NET application.
Figure 2: Access Control and ASP.NET scenario
The application sends a request to the Access Control issuer (1) passing a Simple Web Token (SWT). The SWT indicates the name of the Access Control issuer for this client and is signed with the matching issuer key for authentication. The token also carries any claims the client must provide to Access Control for pass through or transformation—in this case, the LicenseKey claim is passed through to the web resource. Along with the SWT, the client also indicates the scope of the request (which resource are we calling for which we need a token?). Here is a look at the URL-encoded form parameters passed with the request to Access Control in Figure 1:
The rules matching the scope of the request are executed (2) to produce a set of outgoing claims for the resulting token. In this case, Access Control is being used primarily to authenticate that calls came from a trusted client (the incoming token signature indicates this) and merely passes through any claims (the LicenseKey) to be used as additional information at the web resource. The issued token is signed with the token policy for the scope of the request (3) and returned to the client. Note that the issued token indicates Access Control as the issuer, the audience matches the scope of the request, and of course there is an expiry according to the token policy.
The client then passes the issued token in the HTTP Authorization header (4) to the web resource. The Authorization header looks like this:
This is where the custom HTTP module steps in (5) to process the Authorization header and facilitate authentication and authorization of the incoming request prior to reaching the web resource (6). For this scenario, if the Authorization header includes a SWT token signed by the correct token policy, and the token is valid, the request is authenticated. The application will then check the LicenseKey claim before authorizing access to the web resource.
Note: In my article covering Access Control and WCF, I describe an alternate scenario where different client applications may be granted a different Access Control issuer key to limit access. As such, Access Control also issued additional permission claims (Create, Read, Update, Delete) as appropriate. These claims were then used to authorize access at the service.
The AccessControlHttpModule Implementation
To support securing ASP.NET web resources with Access Control, I created a custom HTTP module, AccessControlHttpModule. As with most other authentication modules, this module handles the OnAuthenticateRequest application event. If a valid Authorization header is present carrying a token signed by a trusted token policy within Access Control, the request is authenticated and a security principal is created for the request. If not, the request is rejected. But there is more to this, as the module also provides a way to bypass authentication as appropriate and loops in WIF to enable customization of the security principal and centralized authorization.
Figure 3 illustrates a more detailed perspective on the flow of communication for the module.
Figure 3: AccessControlHttpModule and WIF architecture
Figure 4 shows the most relevant code to the module implementation. The functionality can be broken into the following:
• support for Global.asax event overrides
• authentication of the Access Control token
• generation of a ClaimsPrincipal
• support for WIF ClaimsAuthenticationManager
The module expects settings to be present in the web.config to initialize other Access Control components (discussed in the previous article) in support of token processing and validation. You must supply the service namespace, the token policy key, and the trusted audience at a minimum—and this is verified in the static constructor (see the following code sample for details):
The IHttpModule Init() implementation (see Figure 4) sets up a handler for the OnAuthenticateRequest event. Requests for any resource protected by the AccessControlHttpModule will pass through OnAuthenticate() where most of the work is done. First, the BeforeAccessControlAuthentication event is fired so that the Global.asax can optionally override processing by this module. In the code sample in Figure 5, the Global.asax handles this event and verifies that the request is for a resource beneath the \WebResources directory, or is for any custom handler (ASHX)—otherwise it sets the event argument CancelAccessControlAuthentication to true.
Assuming the module should proceed to authenticate, it grabs the Authorization header and begins to process it in a similar way as the previous article describes for WCF—except for in the WCF example, this code was located in a custom ServiceAuthorizationManager. The code relies on the same SWTToken, SWTTokenHandler, and AccessControlConfiguration components to do this work. A single call to ValidateToken() hides most of the detail the I described previously.
If the token is validated, the next step is to produce a security principal carrying its claims. For this I use WIF, of course, and the ClaimsPrincipal type. The CreatePrincipal() method (Figure 6) is passed the claims from the Access Control token and does the following:
• Produces a ClaimsPrincipal with the list of claims.
• Invokes the configured WIF ClaimsAuthenticationManager passing this principal, providing an opportunity for custom code to modify it.
• Assigns the returned ClaimsPrincipal to Thread.CurrentPrincipal and HttpContext.Current.User.
At the end of OnAuthenticate() the call, will have been authenticated and the claims from the Access Control token hydrated into a ClaimsPrincipal—ready to be used for authorization in the classic WIF way.
Custom Module Configuration
For the AccessControlHttpModule to work, it must first be configured in the web.config. Figure 7 shows the relevant parts of the web.config to enable the module for both IIS 6 (
The AccessControlHttpModule expects you to also be using WIF. At a minimum you must reference Microsoft.IdentityModel.dll so that the ClaimsPrincipal functionality will work. To customize authentication and authorization, you can also add some setting to the web.config:
• the required configuration section declaration
• an optional
• Enable the ClaimsPrincipalHttpModule and ClaimsAuthorizationModule to enable the CustomAuthorizationManager.
Figure 8 shows the configuration section and identity model configuration section.
The AccessControlHttpModule holds a reference to the ClaimsAuthenticationManager and initializes this in the Init() function (see Figure 4). If a custom ClaimsAuthenticationManager is supplied in the configuration section, it will be used; otherwise the default implementation is used (which does nothing special).
private ClaimsAuthenticationManager _claimsAuthenticationManager;
this._claimsAuthenticationManager = FederatedAuthentication.ServiceConfiguration.ClaimsAuthenticationManager;
The example of a custom ClaimsAuthenticationManager shown in Figure 9 simply sets the RoleClaimType to "Role" so that IsInRole() checks will look at the correct claim type to perform access checks.
The custom ClaimsAuthorizationManager is not triggered by the AccessControlHttpModule—it is triggered by the ClaimsAuthorizationModule. The latter requires you to also configure the ClaimsPrincipalHttpModule, and so in the web.config you would add both of these to the modules section, following the AccessControlHttpModule entry, as Figure 10 shows.
A custom ClaimsAuthorizationModule can perform centralized claims authorization checks for all calls, or perhaps check that a few common claims are present and accurate. Figure 11 shows a shell implementation—but you can review the previous article for some deeper examples of this.
Try It Out
This concludes my short series on AppFabric Access Control, but that is not to say I won't be discussing it again in future articles for specific implementation fun! I've included both my WCF and ASP.NET samples in this download—since I updated the code for the release naming conventions. Download the code and enjoy!
Michele Leroux Bustamante ([email protected]) is chief architect for IDesign, chief security architect for BiTKOO, a Microsoft Regional Director for San Diego, and a Microsoft MVP for Connected Systems. Her latest book is Learning WCF (O'Reilly), and she blogs at www.dasblonde.net.