共用方式為


Authenticating Users in the Orders Application

patterns & practices Developer Center

On this page:
Scenario and Context | Authenticating Visitors to the Orders Application | Choosing an Authentication Technique - ASP.NET Forms Authentication, Claims-Based Authentication with Microsoft Active Directory Federation Service, Claims-Based Authentication with Azure Access Control Service, Claims-Based Authentication with ACS and ADFS, Combined Forms and Claims-Based Authentication | How Trey Research Chose an Authentication Technique | How Trey Research Uses ACS and ADFS to Authenticate Visitors - Access Control Service Configuration, Handling Multiple User IDs, Authentication Implementation, Authentication with Windows Identity Foundation, ASP.NET Request Validation, Visitor Authentication and Authorization, The Custom Logon Page, Using a Custom Authorization Attribute, Customer Details Storage and Retrieval | Authenticating Access to Service Bus Queues and Topics | Summary | More Information

This chapter explores how Trey Research adapted the authentication and authorization implementation in the Orders application when they migrated parts of the application to the cloud.

The original on-premises Orders application used ASP.NET Forms authentication. All visitors to the site were required to log in using credentials allocated to them by Trey Research employees. These credentials were stored in a SQL Server® database.

When the designers at Trey Research were considering how to adapt the application to run in the cloud, they realized that they could take advantage of the Microsoft Azure™ technology platform Access Control Service (ACS) to implement a more flexible and user-friendly authentication approach for visitors, based on claims issued by trusted identity providers.

Scenario and Context

Most corporate applications and websites require secure and reliable authentication. Users establish their identity by providing a secret that only they and the authentication mechanism know. Typically this is a combination of a username and password, but it may instead be done using a smartcard, a biometric technique such as a fingerprint or iris scan, or some other approach. The important factor is that application designers must choose a mechanism that can uniquely identify each user, even if this identification consists only of establishing a unique user ID.

ASP.NET Forms authentication is a natural approach for authenticating visitors to a website created using ASP.NET, and for authorizing each visitor's actions as they access the website. It is flexible and easy to implement, and provides mechanisms for users to manage their credentials (such as changing their password). It was for these reasons that the designers at Trey Research originally used ASP.NET Forms authentication in the on-premises version of the Orders application.

Hh868037.note(en-us,PandP.10).gifJana Says:
Jana
                Forms authentication is the natural approach for authentication in ASP.NET applications, but it does not offer the flexibility of a claim-based approach for federated identity and single sign-on.</td>

However, ASP.NET Forms authentication no longer meets the expectations of visitors who are becoming more used to authentication mechanisms that allow them manage their credentials themselves, and that enable them to use the same credentials to access multiple websites. For example, users that have a Windows Live® ID can set up and manage their account at Windows Live, and then use the same credentials for accessing websites such as the Hotmail® web-based email service, the MSDN® developer program, and other Microsoft and third-party websites.

In this situation, Windows Live acts as an identity provider by authenticating visitors and then confirming their identity to websites that trust Windows Live. This mechanism is usually referred to as federated authentication. It also supports the capability for single sign-on, where users sign on once and do not need to re-enter their credentials when accessing another website.

Note

For more information about federated authentication, claims-based authentication, identity providers, and single sign-on see "Appendix B - Authenticating Users and Authorizing Requests" of this guide.

The designers at Trey Research wanted to offer visitors the flexibility of using federated authentication, and decided to examine the options available for implementing it in the Orders application. In addition, they wanted to simplify access to the application for both Trey Research employees and employees at partner organizations (such as transport partners).

Figure 1 shows the existing authentication architecture for the on-premises Orders application. In this version of the application, customers are authenticated using ASP.NET Forms authentication (shown at 1 in the diagram) and are granted access the Orders application if their web browser presents the correct ASP.NET authentication token to the application (2 in the diagram). Employees of partner organizations, such as transport partners, are authenticated in the same way (3 and 4 in the diagram). Employees in the Trey Research head office use credentials specific to the Orders application to sign into the Orders application using the same ASP.NET Forms authentication mechanism used by customers and partner employees (5 and 6 in the diagram). However, Trey Research employees also use internal applications, such as accounting and manufacturing applications, and they must be authenticated for these applications using different credentials that are stored in the on-premises Windows Active Directory® (7 and 8 in the diagram).

Hh868037.7CF02720DF884EFEFFE163BB82CD0ADB(en-us,PandP.10).png

Figure 1

The original on-premises authentication mechanism at Trey Research

The following sections of this chapter describe how the designers at Trey Research evaluated and chose a more flexible authentication and authorization approach for visitors, partners, and Trey Research employees, and how they implemented this approach in the Orders application. The final section of this chapter discusses how ACS can also act as the authentication mechanism for Azure Service Bus.

Authenticating Visitors to the Orders Application

The designers at Trey Research were aware of the growing use of federated identity on the Internet, and wanted to evaluate the options available for authentication in modern websites and web applications. The following sections of this chapter describe how they carried out this evaluation.

Choosing an Authentication Technique

The designers at Trey Research assessed common authentication techniques for the Orders application by considering the advantages and limitations of using claims-based authentication compared to ASP.NET Forms-based authentication, in conjunction with incorporating their existing user repository implemented by Windows Active Directory.

ASP.NET Forms Authentication

Forms authentication is a built-in feature of ASP.NET, and is quick and easy to implement in an ASP.NET website. There is a range of server controls that can be inserted into web pages to enable users to manage their account credentials, apply for an account, and sign in and sign out. The Orders application already used Forms authentication, and so using this same mechanism in the hybrid version of the application would not require any changes to the code.

Using ASP.NET Forms authentication would require the database containing the user's credentials to be available to the website, though having already decided to deploy the Customers data to SQL Azure™ technology platform this would not be an issue.

However, Trey Research had already decided that it wanted to offer more flexible options for visitors, Trey Research employees, and partners by allowing them to access the Orders website using their existing credentials rather than having to register new ones. Using ASP.NET Forms authentication means that users must have a separate account just for the Orders application.

Claims-Based Authentication with Microsoft Active Directory Federation Service

Claims-based authentication allows visitors to use an existing account that they have already established with an identity provider that Trey Research trusts. This approach requires the designers at Trey Research to decide which identity provider(s) they will trust. One option is to use Microsoft Active Directory Federation Service (ADFS) in conjunction with their existing Windows Active Directory. ADFS allows users to sign in over the Internet using credentials stored in Active Directory; they do not need to connect directly to the Active Directory domain network.

Hh868037.note(en-us,PandP.10).gifJana Says:
Jana
                ADFS acts as a Security Token Service (STS) that can authenticate users against Windows Active Directory and issue security tokens containing claims about the user. These claims may be just an authenticated user ID, or there may be a larger set of claims in the token that specify more information about the user such as their name, roles, email address, and more.</td>

However, using ADFS would mean that Trey Research employees would need to create accounts for all visitors within their Windows Active Directory domain or in a separate Windows Active Directory domain dedicated to customers, which increases administrative requirements and may have unwelcome security implications. It would be an acceptable approach for authenticating a small and well-defined subset of users, such as employees at Trey Research and at partner organizations, but is not a practical approach for authenticating all visitors.

Claims-Based Authentication with Azure Access Control Service

Trey Research can extend the capabilities for authenticating visitors by using ACS. This service provides a mechanism for visitors to sign in using their existing account credentials from a range of well-known social networks and identity providers.

Hh868037.note(en-us,PandP.10).gifJana Says:
Jana
                ACS is also a STS that issues security tokens containing claims about the user, but it can authenticate users against a range of social identity providers such as Windows Live ID, Google, Facebook, and OpenID. ACS can also act as an identity provider; a feature that is used for authenticating access to Azure Service Bus queues and topics. </td>

The designers at Trey Research realized that using ACS would give visitors the flexibility required to use their existing identity and credentials, with a corresponding improvement in users' authentication experience. It also has the advantage that Trey Research would not need to manage the users' credentials, such as providing the facility to change a password. All features of identity management are the responsibility of the identity provider. Trey Research just needed to decide which identity providers it would trust to establish a user's identity.

However, there are some issues that Trey Research had to address when adopting this approach. Social identity providers typically return only claims containing a unique user identifier, and perhaps a user name or an email address, and so the application code must associate this identifier with a registered user stored in the Customers database table. In addition, Trey Research may need to consider how to migrate existing user accounts to use the claims-based approach. Using claims-based authentication will also require the developers at Trey Research to modify the application code to use the claims returned from ACS.

Trey Research also realized that using ACS with social identity providers does not provide a single sign-on solution for Trey Research employees and employees at Trey Research's partners. Both of these sets of employees sign into applications in their respective corporate networks using an account defined in their company's Active Directory (or other corporate credentials repository). However, they will be required to sign into the Orders application using an account defined by a social identity provider.

Claims-Based Authentication with ACS and ADFS

The designers at Trey Research recognized that they could resolve the challenges encountered with the options presented in the previous sections by combining ACS with ADFS authentication techniques. Together ACS and ADFS can act as identity providers and token issuers (STSs) for accounts defined at social identity providers such as Windows Live ID, Google, Facebook, and OpenID, and accounts defined within Windows Active Directory.

All this requires is for ACS to be configured to trust the ADFS instances exposed by Trey Research and by partner organizations that wish to take part in the federated identity authentication realm. Users are directed to ACS for authentication. ACS sends a request to authenticate each user to the appropriate identity provider. This may be one of the configured social identity providers, or it may be one of the configured ADFS instances. When an ADFS instance receives a request for authentication, it looks up the identity in its local Windows Active Directory. After confirming the identity through one of the identity providers or ADFS instances, ACS returns a token containing any discovered claims to the application.

By combining ACS and ADFS, Trey Research enables visitors to the Orders application to sign in using a social identity or with an identity defined in one of the corporate Active Directory domains. Customers can use Windows Live ID, Google, Facebook, and OpenID, and more; Trey Research employees can sign in with their corporate credentials defined within the Trey Research domain; and employees at partner organizations can sign in using corporate credentials defined within their own domain.

This means that Trey Research are no longer required to maintain authentication details for visitors or partner employees, and the details for Trey Research's own employee accounts are already managed by the network administrator in Active Directory. Consequently, there is no requirement for additional management of employee accounts.

Hh868037.note(en-us,PandP.10).gifBharath Says:
Bharath
                Combining authentication through social identities and corporate directory mechanisms by using ACS offers flexibility and allows the application to support authentication for a broad set of users. It also makes it possible to use role-based claims to authorize user actions because role information is typically available from corporate directories, even though it is usually not available from social identity providers.</td>

The only real issues are the additional complexity of configuring ACS and ADFS to support this federated identity approach, and the loss of absolute control over the list of permitted users. For example, the administrator at partner companies will maintain the list of their employees that have access to the Orders application. While freed of the effort and responsibility for this task, Trey Research loses the ability to control which users do have access, and must trust the partner organization to grant only the appropriate privileges. This may be an issue if the permissions available to users depend on roles specified in the claims returned from the identity provider, such as "Manager" or "Administrator."

Combined Forms and Claims-Based Authentication

One final approach Trey Research considered was combining both a claims-based approach, as discussed above, with ASP.NET Forms authentication so that users can continue to use their existing Forms authentication credentials. This approach would mean administrators at Trey Research would not be required to migrate existing users to the claims-based approach. New and existing users would be able to use the application, with new users being provided with claims-based authentication credentials, and existing users could be encouraged to change over to using claims-based authentication credentials.

However, this means that developers and administrators at Trey Research would need to manage and maintain two incompatible systems. It would also be more difficult to perform common tasks such as generating a list of customers or managing the customer details held in the database. In addition, developers would still need to modify the application code to support both authentication techniques.

How Trey Research Chose an Authentication Technique

After considering all of the options, Trey Research decided to adopt a claims-based federated authentication approach based on combining ACS and ADFS. This approach offers the maximum flexibility for new customers, and supports single sign-on for all visitors; including Trey Research employees and employees at partner organizations.

The additional work and cost involved in also supporting Forms authentication was not considered to be worthwhile, however, and so Trey Research needed to decide how to manage the accounts of existing customers and employees. The developers discovered that they could add code to the application so that users signing in with a social or federated identity could be connected to an existing user account. This saves Trey Research from migrating the existing accounts from Forms authentication.

It also has the added benefit that customers and employees can have more than one identity linked to their registered account in the Customers table, and can therefore access the application when signed in to any of these identity providers. This offers an even better single sign-on experience for visitors. This implementation is described in more detail in the section "Handling Multiple User IDs," later in this chapter.

How Trey Research Uses ACS and ADFS to Authenticate Visitors

Trey Research authenticates visitors to the Orders website through claims-based authentication using ACS as the STS, three social identity providers (Windows Live ID, Yahoo!, and Google), and ADFS instances exposed by Trey Research itself and by its main partner organizations. Figure 2 shows a schematic view of the overall authentication cycle for different types of users and different identity providers.

Hh868037.8468DD7EF20157153AE30B978C200321(en-us,PandP.10).png

Figure 2

The authentication architecture and sequence in the hybrid Orders application

In this architecture, customers authenticate through ACS with their chosen social identity provider (shown at 1 in the diagram). These identity providers are configured in ACS, and are trusted by ACS. The claims-based authentication modules in the Orders application pipeline validate the token returned from ACS that the customer sends to the Orders application (2 in the diagram). The modules extract the user identifier claim, and the Orders application can then look up the corresponding customer details in the Customers database table.

Employees at Trey Research's partners authenticate using ACS (3 in the diagram), but—because ACS is configured to trust the partner's directory federation service—these employees can sign into the Orders application (4 in the diagram) using credentials stored in their own corporate directory.

Finally, Trey Research's employees are authenticated by Trey Research's own Active Directory over the corporate network when they sign into their computer (5 in the diagram) and can then access Trey Research's internal applications (6 in the diagram). When these employees access the Orders application, ACS authenticates their current credentials against Active Directory through ADFS (7 in the diagram), and they are be issued with a suitable token containing claims that the claims-based authentication modules in the Orders application pipeline can use to identify them (8 in the diagram).

The following sections of this guide explore in more detail how Trey Research implemented this architecture in the Orders application.

Access Control Service Configuration

Trey Research uses a setup program (in the TreyResearch.Setup project of the example) to configure ACS without needing to use the Azure web portal. The setup program uses the classes in the ACS.ServiceManagementWrapper project to access and configure ACS.

Note

For more information about the ACS.ServiceManagementWrapper, see "Access Control Service Samples and Documentation."

The following table shows how Trey Research configured ACS for authenticating visitors to the Orders application.

ACS artifact

Setting

Relying party

Orders website

Windows Live ID identity provider

Default rule group that contains rules to pass the visitors' ID through as both the NameIdentifier and the UserName (Windows Live ID does not reveal visitors' email addresses).

Google identity provider

Default rule group that contains a rule to pass the visitor's ID through as the NameIdentifier and a rule to pass the visitors' email address through as the UserName.

Yahoo! Identity provider

Default rule group that contains a rule to pass the visitor's ID through as the NameIdentifier and a rule to pass the visitors' email address through as the UserName.

Trey Research ADFS Identity provider

Default rule group that contains a rule to pass the visitor's user ID through as the NameIdentifier and a rule to pass the visitors' email address through as the UserName,and a rule to pass the visitor's account groups as the Roles claim..

Partner ADFS identity providers

Default rule group that contains a rule to pass the visitor's user ID through as the NameIdentifier, a rule to pass the visitors' email address through as the UserName,and a rule to pass the visitor's account groups as the Roles claim.

Handling Multiple User IDs

Typically, each registered user of the Orders application has a single unique user identifier, which links that customer to the corresponding customer details stored in the database. This works well when there is only a single authentication source, such as when using ASP.NET Forms authentication. However, when authentication takes places in multiple realms (such as different identity providers, each of which authenticates users within a specific realm such as live.com or google.com) the same customer may have more than one unique identifier.

This situation also arises when using more than one instance of ACS. At the moment, Trey Research uses only one ACS namespace configured in the US North datacenter. However, it may decide in the future to configure additional ACS namespace instances in other datacenters as it expands the deployment of the Orders application to other national or international datacenters. Each instance of ACS may, to minimize user privacy concerns, return a different unique user identifier from each instance for the same customer.

This means that applications must be designed in such a way that it is possible to link more than one user identifier claim value (received from an identity provider or STS) to a single registered customer. Trey Research accomplishes this by using two tables in the database. The main Customer table contains a row for each of the registered customers, with a unique customer identifier set by the accounts team at Trey Research as the key. The ACSIdentity child table contains a row for each unique identifier claim value for each customer, linked to the relevant customer through the customer key value.

An important advantage of this approach is that it makes it possible to migrate users from one authentication mechanism, to another. For example, when Trey Research changed from using ASP.NET Forms authentication to claims-based authentication, the developers could have provided a transition mechanism for existing customers. When a customer first authenticates using a social identity provider or ADFS (when the unique user identifier in the claims is not already in the ACSIdentity table), Trey Research could provide a page that allowed the user to also authenticate through ASP.NET Forms authentication, and then link the new claims-based identity to their existing customer details.

The example application available with this guide does not fully implement the authentication architecture described here. This is done to remove the requirement to configure a suitable ADFS and Windows Active Directory instance. The example application is configured to use only one instance of ACS and three social identity providers, and does not use a separate ACSIdentity table. In addition, it does not use roles to authorize user actions. For information about using role claims to authorize visitors, see "Federated Identity for Web Applications" in "A Guide to Claims-Based Identity and Access Control (2nd Edition)."

Authentication Implementation

Figure 3 shows a high-level view of the services and classes used for authentication and authorization process in the Orders application. You'll see details of the classes identified in the schematic in the following sections of this chapter.

Hh868037.90446708BBA9027326A123B8200EF68E(en-us,PandP.10).png

Figure 3

Overview of visitor authentication and authorization in the hybrid Orders application

Authentication with Windows Identity Foundation

Trey Research uses Windows Identity Foundation (WIF) to check for the presence of a valid token that contains claims when each visitor accesses the website. The following extracts from the Web.config file in the Orders.Website project shows the relevant settings in the Web.config file.

<configSections>
  <section name="microsoft.identityModel" type="..." />
  ...
</configSections>
...
<system.web>
  ...
  <authorization>
    <allow users="*" />
  </authorization>
  <authentication mode="Forms">
    <forms loginUrl="~/Account/LogOn" timeout="2880" />
  </authentication>
  ...
  <httpModules>
    <add name="WSFederationAuthenticationModule" 
         type="..." />
    <add name="SessionAuthenticationModule"
         type="..." />
  </httpModules>
</system.web>
...
<microsoft.identityModel>
  <service>
    <audienceUris>
      <add value="https://127.0.0.1" />
    </audienceUris>
    <federatedAuthentication>
      <wsFederation passiveRedirectEnabled="true"
         issuer="https://treyresearch.accesscontrol.
                 windows.net/v2/wsfederation" 
         realm="https://127.0.0.1" requireHttps="true" />
      <cookieHandler requireSsl="true" />
    </federatedAuthentication>
    <serviceCertificate>
      <certificateReference x509FindType="FindByThumbprint"
                            findValue="..." />
    </serviceCertificate>
    <applicationService>
      <claimTypeRequired>
        <claimType
           type="https://schemas.xmlsoap.org/ws/2005/05/
                 identity/claims/name" optional="true" />
      </claimTypeRequired>
    </applicationService>
    <issuerNameRegistry
       type="Microsoft.IdentityModel.Tokens.
             ConfigurationBasedIssuerNameRegistry, ...">
      <trustedIssuers>
        <add thumbprint="..."
             name="https://treyresearch.accesscontrol.
                   windows.net/" />
      </trustedIssuers>
    </issuerNameRegistry>
    <certificateValidation
      certificateValidationMode="None" />
  </service>
</microsoft.identityModel>

These settings insert the two WIF modules WSFederationAuthenticationModule and SessionAuthenticationModule into the HTTP pipeline so that they are executed for each request. The settings in the microsoft.identityModel section specify that the modules will redirect requests that require authentication to https://treyresearch.accesscontrol.windows.net, which is the namespace Trey Research configured in ACS. The version of the Web.config file you see here is used when the application is running in the local compute emulator, so the audience URI and realm is the local computer.

Hh868037.note(en-us,PandP.10).gifMarkus Says:
Markus When using WIF to authenticate visitors you must edit the values in the Web.config file for the audience URI and relying party realm if you change the URL of your application, such as when deploying it to the cloud after testing in the Local Compute environment.

The applicationService section shows that the Orders website accepts a Name claim in the token presented to the WIF modules, though this is optional. The trustedIssuers section specifies that the application trusts ACS, and specifies the thumbprint of the certificate that the WIF modules can use to validate a token sent by the visitor.

When the WIF modules detect a request from a visitor that must be authenticated they first check for a valid token from the trusted issuer in the request. If one is not present, the modules redirect the request to ACS. If a valid token is present, the modules extract the claims and make them available to the application code so that it can use the claims to authorize user actions.

The class named IdentityExtensions in the Orders.Website.Helpers project contains two methods that Trey Research uses to extract the values of claims. The GetFederatedUsername method extracts the value of the IdentityProvider claim (the name of the original claim issuer for this visitor, such as Windows Live ID or Google) and the Name claim, and then concatenates them to create a federated user name. The GetOriginalIssuer method simply returns the name of the original claim issuer for this visitor.

private const string ClaimType =
    "https://schemas.microsoft.com/accesscontrolservice"
    + "/2010/07/claims/identityprovider";

public static string GetFederatedUsername(this
                     IClaimsIdentity identity)
{
  var originalIssuer = identity.Claims.Single(
                c => c.ClaimType == ClaimType).Value;
  var userName = string.Format(
        CultureInfo.InvariantCulture, "{0}-{1}",
        originalIssuer, identity.Name);
  return userName;
}

public static string GetOriginalIssuer(this 
                     IClaimsIdentity identity)
{
  return identity.Claims.Single(
                c => c.ClaimType == ClaimType).Value;
}

ASP.NET Request Validation

By default, ASP.NET checks for dangerous content in all values submitted with requests. This includes HTML and XML elements. Trey Research uses a custom class that allows requests to contain security tokens in XML format, but still protects the site from other dangerous input. This is a better alternative to turning off ASP.NET request validation altogether.

Hh868037.note(en-us,PandP.10).gifPoe Says:
Poe Turning off the default ASP.NET request validation mechanism is not a good idea. Instead, use a custom request validator that allows requests to contain XML documents (which hold the user claims) to be processed.

The custom class is named WsFederationRequestValidator and is defined in the Orders.Website project. The code, shown below, checks if the request is a form post containing a SignInResponseMessage result from a WS Federation request. If it is, the code allows the request to be processed by returning true. If not, the code allows the standard ASP.NET request validation handler to validate the request content.

public class WsFederationRequestValidator 
             : RequestValidator
{
  protected override bool IsValidRequestString(
        HttpContext context, string value,
        RequestValidationSource requestValidationSource,
        string collectionKey, 
        out int validationFailureIndex)
  {
    validationFailureIndex = 0;
    if (requestValidationSource 
      == RequestValidationSource.Form &&
         collectionKey.Equals(
           WSFederationConstants.Parameters.Result,
           StringComparison.Ordinal))
    {
      if (WSFederationMessage.CreateFromFormPost(
        context.Request) as SignInResponseMessage != null)
      {
        return true;
      }
    }
    return base.IsValidRequestString(context, value,
           requestValidationSource, collectionKey, 
           out validationFailureIndex);
  }
}

Trey Research inserted the custom request validator into the HTTP pipeline by adding it to the Web.config file for the Orders website, as shown here.

<system.web>
  <httpRuntime requestValidationType="Orders.Website.
       WsFederationRequestValidator, Orders.Website" />
  ...
</system.web>

Visitor Authentication and Authorization

Some pages in the Orders application, such as the Home page and the list of products for sale, do not require visitors to be authenticated; visitors can browse these pages anonymously. However, the pages related to placing an order, managing a visitor's account, and viewing existing orders require the visitor to be authenticated.

Trey Research allows visitors to log on and log off using links at the top of every page. These are defined in the layout page that acts as a master page for the entire site. The layout page, named _Layout.cshtml and located in the Views/Shared folder of the Orders website, contains the following code and markup.

@if (User.Identity.IsAuthenticated)
{
  <li>@Html.ActionLink("My Orders", "Index",
                       "MyOrders")</li>   
  <li>@Html.ActionLink("Log Out", "LogOff", 
                       "Account")</li>
}
else
{
  <li>@Html.ActionLink("Log On", "LogOn", "Account")</li>
}

The WIF modules automatically populate an instance of a class that implements the IClaimsIdentity interface with the claims in the token presented by a visitor, and assign this to the current context's User.Identity property. The code can check if a user is authenticated simply by reading the IsAuthenticated property, as shown in the code above. You can also use all of the other methods and properties of the User.Identity, such as testing if the visitor is in a specific role.

The Custom Logon Page

The ActionLink in the _Layout.cshtml page that generates the "Log On" hyperlink loads the AccountController class (in the Controllers folder of the Orders.Website project) and then calls the LogOn action method. This behavior is also defined in the Web.config file you saw earlier, specifying the page to display when the user accesses a secured page when not authenticated.

  <authentication mode="Forms">
    <forms loginUrl="~/Account/LogOn" timeout="2880" />
  </authentication>

The Logon method, shown below, creates suitable values for the realm and the return URL so that the visitor will go back to the correct page after logging on. It creates the return URL only if the visitor was redirected here from another page. It uses another method named GetRealm, which is defined within the AccountController class, to get the current realm in the form http://[host].[path]/. Finally, the LogOn method returns the login page view with the customized Trey Research look and feel.

[HttpGet]
public ActionResult LogOn()
{
  ViewData["realm"] = this.GetRealm();
  ViewData["returnUrl"] = Request.UrlReferrer != null
     ? Request.UrlReferrer.AbsoluteUri : this.GetRealm();
  ViewData["acsNamespace"] = CloudConfiguration
     .GetConfigurationSetting("acsNamespace", null);
  return View();
}

The Logon view itself, located in the Views\Account folder of the Orders.Website project, generates a custom logon page containing buttons for each of the configured identity providers (such as Windows Live ID, Google, and Yahoo!). Visitors can choose an identity provider to use, and then log in using this provider. They are then returned to the appropriate page of the Orders application.

The custom logon page is created by modifying the standard page that ACS creates. The custom page uses considerable amounts of client-side JavaScript to generate the visible content and to handle user interaction.

Using a Custom Authorization Attribute

Some of the pages in the website, such as the "Checkout" and "My Orders" pages, require visitors to have already been authenticated. To implement this behavior, Trey Research uses a custom attribute named AuthorizeAndRegisterUser. For example, the MyOrdersController class has this attribute applied to the entire class (rather than to a single method). The following code shows an outline of the MyOrdersController class.

[AuthorizeAndRegisterUser]
public class MyOrdersController : Controller
{
  ...
}
Hh868037.note(en-us,PandP.10).gifJana Says:
Jana Using a custom authentication attribute is a good way to perform other tasks related to authentication, such as obtaining a user's details from a database, without needing to include this code in every class. It also makes it easy to specify which pages or resources require users to be authenticated.

The custom AuthorizeAndRegisterUserAttribute class, shown below, is defined in the CustomAttributes folder of the Orders.Website project). It extends the standard AuthorizeAttribute class that is used to restrict access by callers to an action method.

public class AuthorizeAndRegisterUserAttribute 
             : AuthorizeAttribute
{  
  private readonly ICustomerStore customerStore;

  public AuthorizeAndRegisterUserAttribute() 
             : this(new CustomerStore())
  { }

  public AuthorizeAndRegisterUserAttribute(
                    ICustomerStore customerStore)
  {
    this.customerStore = customerStore;            
  } 

  public override void OnAuthorization(
       System.Web.Mvc.AuthorizationContext filterContext)
  {
    ...  
    if (!filterContext.HttpContext.User.
                     Identity.IsAuthenticated)
    {
      base.OnAuthorization(filterContext);
      return;
    }
    var federatedUsername = 
        ((IClaimsIdentity)filterContext.
        HttpContext.User.Identity).GetFederatedUsername();
    var customer = this.customerStore.FindOne(
                                   federatedUsername);
    if (customer == null)
    {
      // Redirect to registration page.
      var redirectInfo = new RouteValueDictionary();
      redirectInfo.Add("controller", "Account");
      redirectInfo.Add("action", "Register");
      redirectInfo.Add("returnUrl",
                       filterContext.HttpContext.Request
                         .Url.AbsolutePath);
      filterContext.Result 
          = new RedirectToRouteResult(redirectInfo);
    }
  }
}

The AuthorizeAndRegisterUserAttribute attribute creates an instance of the CustomerStore repository class that is used to access the data for this customer in the SQL Azure Customers table (as shown in Figure 6 earlier in this chapter). If the visitor is not authenticated, the attribute passes the request to the base AuthorizeAttribute instance which forces the user, though the WIF modules, to authenticate with ACS.

If the visitor is authenticated, the attribute uses the GetFederatedUsername method you saw earlier to get the user name from the authentication token claims, and the FindOne method of the CustomerStore class to retrieve this visitor's details from the Customers table. If this visitor has not yet registered, there will be no existing details in the Customers table and so the code redirects the visitor to the Register page.

Customer Details Storage and Retrieval

Using claims-based identity with social identity providers usually means that your application must maintain information about each registered user of the application because the token that authenticated users present to the application contains only a minimal set of claims (typically just a user identifier or name). Trey Research maintains this information in the Customers database table in SQL Azure. This table contains the details customer provide when they register, and additional information that is maintained for each customer by the head-office administration team (such as the credit limit).

To connect to the database, Trey Research used the Microsoft Entity Framework and created a class named CustomerStore, located in the Orders.Website.DataStores folder of the website project. This class exposes several methods for storing and retrieving customer details, including the FindOne method used in the previous code extract. This is the code of the FindOne method.

public Customer FindOne(string userName)
{
  ...
  using (var database 
         = TreyResearchModelFactory.CreateContext())
  {
    var customer 
      = this.sqlCommandRetryPolicy.ExecuteAction(
          () => database.Customers.SingleOrDefault(
                      c => c.UserName == userName));
    if (customer == null)
    {
      return null;
    }
    return new Customer
    {
      CustomerId = customer.CustomerId,
      UserName = customer.UserName,
      FirstName = customer.FirstName,
      LastName = customer.LastName,
      Address = customer.Address,
      City = customer.City,
      State = customer.State,
      PostalCode = customer.PostalCode,
      Country = customer.Country,
      Email = customer.Email,
      Phone = customer.Phone
    };
  }
}

This method searches for an entity using the federated user name. If it finds a match, it creates a new Customer instance and populates it with the data from the database. If not, it returns null to indicate that this visitor is not registered.

You can see that the FindOne method shown in the previous code first obtains a reference to the database by calling the CreateContext method of the TreyResearchModelFactory class (located in the DataStores folder of the Orders.Website project). This method uses another class named CloudConfiguration to read the connection string for the database from the ServiceConfiguration.cscfg file, or return null if the setting is not found.

public static TreyResearchDataModelContainer
       CreateContext()
{
  return new TreyResearchDataModelContainer(
         CloudConfiguration.GetConfigurationSetting(
                "TreyResearchDataModelContainer", null));
}

After obtaining a reference to the database, the code uses the Enterprise Library Transient Fault Handling Application Block to execute the method that connects to the data store and retrieves the details for the specified customer. The Transient Fault Handling Application Block provides a ready-built mechanism for attempting an action a specified number of times with a specified delay between each attempt. It exposes events that you can use to monitor the execution and collect information about execution failures.

Note

The Transient Fault Handling Application Block can be used to manage connectivity to SQL Azure databases, Service Bus queues, Service Bus topics, and the Azure Cache. The block is part of the Enterprise Library Integration Pack for Microsoft Azure. For more information, see "Microsoft Enterprise Library" at https://msdn.microsoft.com/entlib/.

Although they could have used code to generate the policy dynamically at runtime, the developers at Trey Research chose to define the retry policy that the block uses in the application's Web.config file. The following extract from the file shows the definition of the policy.

<RetryPolicyConfiguration 
    defaultRetryStrategy="Fixed Interval Retry Strategy"
    defaultAzureStorageRetryStrategy
      ="Fixed Interval Retry Strategy" 
    defaultSqlCommandRetryStrategy="Backoff Retry Strategy"
  >
  <incremental name="Incremental Retry Strategy"
               retryIncrement="00:00:01"
               initialInterval="00:00:01"
               maxRetryCount="10" />
  <fixedInterval name="Fixed Interval Retry Strategy"
               retryInterval="00:00:05" 
               maxRetryCount="6" 
               firstFastRetry="true" />
  <exponentialBackoff name="Backoff Retry Strategy"
               minBackoff="00:00:05" 
               maxBackoff="00:00:45"
               deltaBackoff="00:00:04" 
               maxRetryCount="10" />
</RetryPolicyConfiguration>

You can see that it contains a default strategy that retries the action every second for a maximum of ten attempts. There is also a strategy for accessing Azure Storage (tables, queues, and blobs) that retries the action every five seconds for a maximum of six attempts, with the first retry occurring immediately after a failure. Finally, there is a strategy for SQL database connections that retries the action after 5 seconds, and then adds 4 seconds to the delay between each attempt up to a maximum of 45 seconds delay and ten attempts.

The CustomerStore class that contains the FindOne method initializes the retry policy in its class constructor using the static GetDefaultSqlCommandRetryPolicy method of the RetryPolicyFactory class (which is part of the Transient Fault Handling Application Block and is exposed when you add the block to your application). The constructor also adds a handler for the Retrying method of the block. This handler writes information to Azure diagnostics each time the block detects a connection failure.

this.sqlCommandRetryPolicy 
  = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicy();

this.sqlCommandRetryPolicy.Retrying += (sender, args) 
    => TraceHelper.TraceInformation("Retry - Count:{0},"
       + "Delay:{1}, Exception:{2}",
       args.CurrentRetryCount, args.Delay,
       args.LastException);

If the Transient Fault Handling Application Block cannot complete the specified action within the specified number of attempts, it will throw an exception that you can handle in your code.

With the retry policy defined and everything initialized, the code simply needs to call the ExecuteAction method, specifying as a parameter the action to execute. In this case, the action to execute is the SingleOrDefault method on the Customers collection exposed by the TreyResearchDataModelContainer class.

    var customer 
      = this.sqlCommandRetryPolicy.ExecuteAction(
          () => database.Customers.SingleOrDefault(
                      c => c.UserName == userName));

Note

This code uses the simplest of the ExecuteAction overloads available in the Transient Fault Handling Application Block. Other overloads allow you to return a result from the method, and perform the execution asynchronously. For more details of all the overloads, see "ExecuteAction Method" on MSDN.

Authenticating Access to Service Bus Queues and Topics

Trey Research uses Service Bus queues and topics to pass messages between the Azure hosted Orders application, transport partners, and the on-premises audit logging service. The section "Securing Message Queues, Topics, and Subscriptions" in Chapter 4, "Implementing Reliable Messaging and Communications with the Cloud," describes the security configuration Trey Research used to protect the Service Bus queues and topics by authenticating users and authorizing the actions each user can carry out.

Unlike the typical ACS authentication process described so far in this chapter, Service Bus "users" are most likely to be services and other components, rather than visitors using a web browser. However, the overall principles are the same: each request to access a Service Bus queue or topic must be authenticated by a trusted identity provider, and the STS must issue a token that indicates successful authentication. For Service Bus authentication, the token must contain claims that can be used to authorize actions such as sending messages to the queue or topic.

For example, applications and users that want to access the service that exposes reporting data (described in the section "How Trey Research Uses the SQL Azure Reporting Service" in Chapter 2, "Deploying the Orders Application and Data in the Cloud") must authenticate with ACS and present a token containing a suitable set of claims to Service Bus.

ACS can be configured to act as both the identity provider and the token issuer (STS) for Service Bus endpoints. Figure 4 shows an overview of the process. Clients obtain a token from ACS that contains the relevant claims (such as "Listen", "Send", or "Manage") and present this token to Service Bus when accessing a queue, topic, or Service Bus Relay endpoint.

Hh868037.DE1995DC8145F0610458C76EB6BBF570(en-us,PandP.10).png

Figure 4

Authenticating Service Bus endpoints with ACS

For more information about how ACS can be used as both the identity provider and token issuer for authenticating and authorizing requests to Service Bus endpoints, see the section "Azure Service Bus Authentication and Authorization" in "Appendix B - Authenticating Users and Authorizing Requests."

Summary

This chapter described how Trey Research tackled the challenge of authenticating visitors to the Orders application, and authenticating access to Service Bus queues and topics when using it to communicate between cloud-hosted and on-premises applications and services. The chapter focused on the use of claims-based identity and authentication. This is the most common and fastest-growing technique for Azure hosted applications because it can take advantage of the frameworks and services specifically designed to make this approach easier.

Claims-based authentication also offers advantages in that it makes it simpler for administrators to manage lists of users and permissions, and it supports single sign-on and a choice of identity providers to make authentication easier for users. It is also a vital technique for securing services such as Azure Service Bus topics and queues.

The chapter also described how the fictional organization named Trey Research implemented authentication and authorization in its hybrid Orders application.

More Information

All links in this book are accessible from the book's online bibliography available at: https://msdn.microsoft.com/en-us/library/hh871440.aspx.

Next Topic | Previous Topic | Home

Last built: June 4, 2012