95966f26-a59d-4c63-8d61-ea86ed6af9fe

After the new content storm of yesterday, here I’ll start to look at some individual pieces. The first one I’d like to feature is the new ACS+WP7 phone, based on the work of Caleb from the ACS team (hear the details from the man himself here). It’s available both online in out msdn course and offline in Identity Developer Training Kit and Windows Azure platform Training Kit.

I could summarize the content, but why doing the job twice? We’ve already written a very complete set of instructions for it, hence  (for the joy of your RSS readers) below I am pasting the entire lab manual. Enjoy!

Overview

Smartphones are the ultimate personal devices. Users expect to be able at any moment to extract the phone from a pocket and instantly gain access to his online data and services, just like he would from his PC. In order to accomplish that level of access from the phone, two basic prerequisites need to be satisfied:

  • The user must be able to use his existing identities from mobile applications
  • Services and data must be exposed in ways that are suitable to be securely consumed by mobile clients

The Windows Azure platform can help. By taking advantage of the Windows Azure AppFabric Access Control Service (ACS) , your application can outsource authentication management and broker access to commonly used social identity providers (such as Facebook, Windows Live ID, Google and Yahoo) and business providers (such as Active Directory and any other directory product with federation capabilities).

By exposing services via the OData protocol, a REST-based open standard, you are guaranteed to be accessible from the widest range of platforms and clients. ACS and Windows Identity Foundation, a .NET component which simplifies authentication and authorization development tasks, can work in synergy to use the OAuth 2 protocol for securing OData calls from mobile applications.

In this hands-on lab you will extend a simple Windows Phone 7 application and associated Windows Azure-hosted service by integrating ACS authentication in the user experience and leverage it for securing service calls.

Objectives

In this hands-on lab, you will learn how to:

  • Use ACS for handling authentication in a Windows Phone 7 application.
  • Consume an OData service from a Windows Phone 7 application using OAuth 2.
  • Use Windows Identity Foundation to handle OAuth2-protected calls to a WCF OData service.
  • Authorize calls to a WCF OData service according to types and values of incoming claims

Prerequisites

The following is required to complete this hands-on lab:

Setup

For convenience, much of the code used in this hands-on lab is available as Visual Studio code snippets. To check the prerequisites of the lab and install the code snippets:

  1. Open a Windows Explorer window and browse to the lab’s Source\Setup folder.
  2. Double-click the Dependencies.dep file in this folder to launch the Dependency Checker tool and install any missing prerequisites and the Visual Studio code snippets.
  3. If the User Account Control dialog is shown, confirm the action to proceed.

noteNote:

This process may require elevation. The .dep extension is associated with the Dependency Checker tool during its installation. For additional information about the setup procedure and how to install the Dependency Checker tool, refer to the Setup.docx document in the Assets folder of the training kit.

Using the Code Snippets

Throughout the lab document, you will be instructed to insert code blocks. For your convenience, most of that code is provided as Visual Studio Code Snippets, which you can use from within Visual Studio 2010 to avoid having to add it manually.

If you are not familiar with the Visual Studio Code Snippets, and want to learn how to use them, you can refer to the Setup.docx document in the Assets folder of the training kit, which contains a section describing how to use them.

Exercises

This hands-on lab includes the following exercises:

  1. Authenticating Users via ACS and invoking via OAuth2 an OData Service in a Windows Phone 7 app

Estimated time to complete this lab: 30 minutes.

note[1]Note:

When you first start Visual Studio, you must select one of the predefined settings collections. Every predefined collection is designed to match a particular development style and determines window layouts, editor behavior, IntelliSense code snippets, and dialog box options. The procedures in this lab describe the actions necessary to accomplish a given task in Visual Studio when using the General Development Settings collection. If you choose a different settings collection for your development environment, there may be differences in these procedures that you need to take into account.

Exercise 1: Authenticating Users via ACS and invoking via OAuth2 an OData Service in a Windows Phone 7 app

Let’s say that you developed a Windows Phone 7 application, composed by one Silverlight client and one OData service, which allows the creation and editing of to-do lists.

The to-do lists are saved in the cloud, in Window Azure’s storage, via the OData service (hosted in Windows Azure as well). The application has no concept of individual users, hence all the lists are accessible by anyone who runs the client. Wouldn’t it be nice to enable each user to define his own private lists?

In order to add the private lists feature, the application needs to gain the two new capabilities below:

  • the ability to recognize each user, hence to add authentication capabilities in the WP7 app
  • the ability to restrict access to the saved lists according to the identity of the current user, hence to add authentication and authorization capabilities to the OData service

Adding authentication capabilities to your WP7 application can be very complicated if you have to handle everything from scratch: luckily, you don’t have to. The Windows Azure AppFabric Access Control Service (ACS) can take care of brokering authentication for you, enabling the user to authenticate with well-known providers. If you want to know more about ACS, you can take a look at the dedicated hands-on labs in the training kit. For the purpose of this lab, the main way in which you will interact with ACS is via a Silverlight control, which you can include in your WP7 application and that will take care of all runtime interactions with the service. All that is left to do for you is to configure the service, via its handy management portal, and specify your preferences such as which identity providers you want to enable and similar.

Adding authentication and authorization capabilities to the OData service, again, could be a lot of work if approached from the wrong angle. The current way of securing REST services is via the OAuth 2 protocol. The protocol per se is pretty simple and handling it directly would be feasible, however as you have learned going through this training kit taking a dependency on the specific details of the protocol leads to high-maintenance code. Once again, luckily you don’t have to. Windows Identity Foundation (WIF) does not support OAuth 2 out of the box, however its extensibility model can be leveraged to add new protocols. In this hands-on lab you will use some WIF extensions which enable you to secure WCF REST services via OAuth 2. This will allow you to keep your service code completely free from authentication- and authorization-specific code; it will also allow you to leverage the rich WIF programming model for handling claims-based authorization just like you would when using the out-of-the-box protocols.

This first exercise will be all about adding those two capabilities to the described application. More in detail, you will follow the sequence below:

  • Configure ACS to work with your application and services
  • Modify the WP7 application to authenticate users via ACS
  • Modify the OData service to accept OAuth2-secured calls and handle authorization

    95966f26-a59d-4c63-8d61-ea86ed6af9fe

    Figure 1
    A high level description of the architecture and flow of the solution of Exercise 1.

Task 1 – Exploring the Initial Solution

In this task, you will explore the initial solution to familiarize with its structure.

  1. Open Visual Studio 2010 as an administrator. Go to File | Open | Project menu and select the Begin.sln located in Source\Ex1-SecureODataWP7\Begin folder of the lab.
  2. Press F5 to run application: the WP7 emulator and a browser representing the OData service will appear. The first screen in the WP7 application presents you with the to-do lists already created. For the purpose of this lab, the lists are stored in a local SQL database.

    f392b4bf-cca9-40a5-a778-7a01370d87f2

    Figure 2
    WP7 client

    From here you will be able to explore the lists and work with them with the following operations:

    1. Creating a task list
    2. Adding a task
    3. Marking a task as completed

    All those operations correspond to a call to the OData service.

  3. Go back to Visual Studio and stop debugging.
  4. Let’s explore the Visual Studio solution. Open the Solution Explorer and browse the code. You will note that the solution contains three projects: MyTodo.Cloud, MyTodo.Phone and MyTodo.Services.

    247f0888-72c6-4901-9627-8c5f74c10637

    Figure 3
    Begin Solution projects

    1. MyTodo.Phone: This is a Silverlight for Windows Phone/Windows Phone Application project , the main WP7 application. It contains the usual Silverlight views, resources and data model. It also contains the necessary classes to communicate with the OData service.
    2. MyTodo.Services: This is the OData WCF service responsible for handling to-do lists operations.
    3. MyTodo.Cloud: The OData service is hosted in Windows Azure: this project provides a description of the Service project in term of Windows Azure role.

Feel free to explore the code if you want to: we kept the solution as simple as possible in order to make it easier to add the extra functionalities in the following tasks.

Task 2 – Configuring AppFabric Access Control Service with multiple identity providers

In this task, you will configure your own Access Control Service namespace to use multiple identity providers and recognize the MyTodo OData service as a registered application. You will do everything in this task through the Windows Azure AppFabric management portal.

note[6]Note:

Note. ACS makes use of claims-based identity. In claims-based identity the successful outcome of one authentication operation is expressed by issuing a security token. A security token contains a list of attributes (called claims) which describe the authenticated user. In a nutshell, ACS operates by brokering token requests to multiple identity providers (IPs); once ACS receives a token from one IP, it applies some processing logic to it and issues a transformed token to the application it protects. The advantage for the application is that it is now decoupled from the details of how every IP operates, and just needs to deal with one single broker. Everything is based on open standards, hence there is no lock-in; the moment in which the application developer wants to use a different service, switching is a simple config line away.
Giving a concise yet exhaustive description of ACS and claims-based identity is difficult, but operating the service is actually very simple. The indications in this task are mainly aimed at helping you to move along through the hands-on lab scenario. If you want to gain a deeper understanding of how ACS works, please refer to the other ACS hands-on labs in the training kit.

  1. Navigate to https://windows.azure.com/and log in with your Live ID credentials.
  2. In the navigation pane, select Service Bus, Access Control & Caching and click on Access Control.
  3. Click New Namespace to create a new namespace.
  4. The portal displays a dialog. Type in a name for your Namespace, select a region, choose a Subscription and click the Create Namespace button. Make sure to validate the availability of the name first. Service names must be globally unique as they are in the cloud and accessible by whomever you decide to grant access.

    5ed7a0f9-9fa7-4ecd-adf6-0f0627aa602a

    Figure 4
    Creating a namespace

  5. Take note of the service namespace you used.
  6. The service namespace will take some time to be provisioned. When the new namespace status becomes active, click on the Access Control Service button.

    1e2a9644-bcd4-440f-9c7c-bf02acc1ce41

    Figure 5
    Open the ACS management portal

  7. This launches (in another browser window or tab) the Access Control Service Management Portal, shown in the figure below.

    915dc04f-b173-49d2-85fc-5e3d2e404a01

    Figure 6
    The ACS management portal home page

  8. Let’s start by adding the identity providers from which we want to authenticate users from. On the navigation pane, select Identity Providers. Windows Live ID is already configured: click Add to add a new identity provider to the list.

    64670441-76f2-465d-94ac-9c80c1ae8a44

    Figure 7
    The list of configured identity provider and the link for adding a new one

    7af29bb9-40ed-4305-bb5f-ff275d747f25

    Figure 8
    Adding a new identity provider

  9. Under the “Add preconfigured identity provider” section, select Google and click Next.
  10. On the “Login Page Settings” form leave the default settings and click Save.

    4eecb173-d077-4bc8-a675-56b4d00c82fe

    Figure 9
    Adding a new identity provider

  11. Repeat steps 6 to 8 for adding Yahoo as another identity provider (select Yahoo in step 7).
  12. Now, you will add Facebook as another identity provider. To do this, browse to http://www.facebook.com and login with any existing account or obtain a new Facebook account.
  13. Install the Facebook Developer application by clicking Go to app at http://www.facebook.com/apps/application.php?id=2345053339.

    d6204975-898a-44d6-a651-aa758085610f

    Figure 10
    Installing the Developer app

  14. Click Allow to enable the Developer app access your basic information.

    a17df150-22f6-4727-9194-5d16454e59db

    Figure 11
    Allowing the app request for permission

  15. In the Facebook Developer application, click Set Up New Application to create a new application.

    a433d8bf-7cdf-436c-a2ea-f3afa081353e

    Figure 12
    Set up new app

  16. In the Application Name field, enter MyTodo. Then agree to the terms, and click Create Application.

    9230695b-3558-42b9-84e2-e874e89f84b8

    Figure 13
    Create the app

  17. Complete the security check by entering the captcha code in the text box and click Submit.
  18. Click the Web Site tab in the left panel.
  19. In the Site URL field, enter the URL to your ACS Service Namespace (e.g. https://[yourservicenamespace].accesscontrol.windows.net/) as shown below. This is the fully-qualified domain name shown in the URL while you are accessing the ACS management portal.

    c30117cc-0f36-40fa-b3fa-d292f2c0a538

    Figure 14
    Web site core settings

  20. Click Save Changes at the bottom of the screen.
  21. In the resulting page, copy the following information. This will be used to add the Facebook application in the ACS portal:
    • Application ID
    • Application Secret

    421130ea-1a01-4ff9-9b7a-9b207b7ae1c4

    Figure 15
    App created

  22. On the Access Control Service management portal main page, click Identity providers.
  23. Click Add to add another identity provider.
  24. Select Facebook application, and click Next.
  25. In the Application ID field, enter the API key copied from your Facebook application.
  26. In the Application secret field, enter the application secret copied from your Facebook application.
  27. Clear the Application permissions field since we do not need any special permission.
  28. Leave the default values in the Login Page Settings section and click Save.

    0a05a366-d9f8-4b2a-9dcf-4295dc2ad2d2

    Figure 16
    Add Facebook application

  29. The next step is telling ACS about the MyTodo service, the resource we are authenticating users for. In identity jargon, the application that requires authentication is known as relying party. On the navigation pane, select Relying parties and click the Add link on top of the “Relying Party Applications” table.

    a1c20e18-f5cd-4b27-8069-0b258cf35686

    Figure 17
    Adding a new relaying party

  30. Fill the form with the following values and leave the fields not in the list with its default value:
    • Name: MyTodo
    • Realm: uri:mytodo
    • Token format: SWT
    • Token signing key: click Generate and take note of the generated key

    note[7]Note:

    The settings above are suitable for a REST service, especially for what concerns the token format. The Simple Web Token, or SWT, is a compact token format which works well with REST style calls in which tokens are sent in HTTP headers or other parts of the HTTP request.
    The token signing key used here is a very important factor in our authentication scenario, as the MyTodo service will use it for verifying the authenticity of incoming tokens. More about this in task #3.

    cdb87976-a427-4155-acdf-71365ee9cbd5

    Figure 18
    Add relying party

  31. Click Save.
  32. The last thing you need to do in the ACS configuration is defining which user information supplied by the identity providers should be made available to the myTodo service. In ACS, that’s done by defining claims transformation rules. On the navigation pane, select Rule Groups.
  33. In the “Rule Groups” table select Default Rule Group for MyTodo.

    f0216913-1d08-4449-a96d-6ee1fcda015e

    Figure 19
    Default Rule Group for MyTodo

  34. In this scenario, we have no special processing logic for the tokens: we just need to pass-through the user information form the identity provider to the MyTodo service. ACS provides a handy shortcut for automatically generating pass-through rules. On the top of the “Rules” table, click Generate.

    fa31f0c9-9cd0-412c-a648-f2aa1fc70bff

    Figure 20
    Generate rules for MyTodo

  35. Select all the identity providers to generate rules for and click Generate.

    3388ccc4-7423-4d27-b6c9-6fd3b12a29f9

    Figure 21
    Generate rules for all the identity providers configured

  36. Click the Add link on top of the Rules table to configure a new rule.

    0d586cb5-cf03-4c74-a4a0-8f752d38770f

    Figure 22
    Add new rule

  37. Fill the form with the following values:
    • If...
      • Claim issuer / Identity Provider: Windows Live ID
      • (And) Input claim type / Select type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
      • (And) Input claim value / Enter value: Any
    • Then...
      • Output claim type / Select type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
      • Output claim value: Pass through input claim value
    • Rule information
      • Description: Copy nameidentifier to name

    note[8]Note:

    not every identity provider supply the same list of claims. This additional rule was added because Windows Live ID does not provide a claim for name, which can be a problem given the fact that name is what (usually) provides the value for the principal’s name at the relying party. With this rule, you are using the nameidentifier claim value (which Windows Live ID does provide) to create a new name claim in the output token.

    9f23faa9-0abf-4972-8549-a2b5f9750cc5

    Figure 23
    Pass through nameidentifier claim value to name claim

  38. Click Save.

    7175ec99-c098-4b08-b0ef-b2c812c37c1f

    Figure 24
    Rule created

You are done with configuring ACS. Now it’s time to start modifying the projects.

Task 3 – Securing an OData Service with OAuth2 and Windows Identity Foundation

In this task, you will add an OData Service that will provide authentication to the solution. To do that, you will include an OData authentication project, provided by this Hands-On-Lab and then you will update the configuration .

note[9]Note:

For simplicity, the MyTodo solution provided in this lab does not use HTTPS. In a real world scenario, it is highly recommended to use HTTPS for the communication with the secure service.

  1. Add the DPE.OAuth2 project from the assets folder to the solution. To do this, in the Solution Explorer, right click the MyTodo solution, select Add and click Existing Project. Browse to [Lab folder]\Source\Assets\DPE.OAuth and open the DPE.OAuth.csproj file.
  2. Add a reference to the DPE.OAuth project in the MyTodo.Services project. In the solution explorer, right click the MyTodo.Services project and select Add Reference. In the Add Reference dialog select the Projects tab and double click the DPE.OAuth project.
  3. Open the Web.config file.
  4. Add a configuration section for configuring the OAuth module. Add the following code as the first element under the configuration section.

    XML

    <configuration>
      <configSections>
        <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </configSections>
      <connectionStrings>
  5. Specify the WIF modules that are required for authenticating the service requests: ProtectedResourceModule, the WIF extension that handles OAuth2, and the OOB WIF modules WSFederationAuthenticationModule and SessionAuthenticationModule. To do this, replace the existing empty modules element inside system.webServer with the following highlighted code.

    XML

    <system.webServer>
      <validation validateIntegratedModeConfiguration="false" />
      <modules runAllManagedModulesForAllRequests="true">
        <add name="ProtectedResourceModule" type="Microsoft.Samples.DPE.OAuth.ProtectedResource.ProtectedResourceModule" />
        <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
        <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
      </modules>
      <handlers />
    </system.webServer>
  6. Add the WIF configuration element, specialized for the OAuth2 module. Insert the following code before the closing </configuration> element.

    XML

      </system.serviceModel>
      <microsoft.identityModel>
        <service name="OAuth">
          <audienceUris>
            <add value= "uri:mytodo" />
          </audienceUris>
          <securityTokenHandlers>
            <add type="Microsoft.Samples.DPE.OAuth.Tokens.SimpleWebTokenHandler, Microsoft.Samples.DPE.OAuth" />
          </securityTokenHandlers>
          <issuerTokenResolver type="Microsoft.Samples.DPE.OAuth.ProtectedResource.ConfigurationBasedIssuerTokenResolver, Microsoft.Samples.DPE.OAuth">
            <serviceKeys>
              <add serviceName="uri:mytodo" serviceKey="[Insert Symmetric Token Signing Key]" />
            </serviceKeys>
          </issuerTokenResolver>
          <issuerNameRegistry type="Microsoft.Samples.DPE.OAuth.ProtectedResource.SimpleWebTokenTrustedIssuersRegistry, Microsoft.Samples.DPE.OAuth">
            <trustedIssuers>
              <add issuerIdentifier="https://[Service Namespace].accesscontrol.windows.net/" name="MyTodo" />
            </trustedIssuers>
          </issuerNameRegistry>
        </service>
      </microsoft.identityModel>
    </configuration>

    note[10]Note:

    You don’t need to understand the fine details of that configuration element in order to use the OAuth2 module; however if you are a WIF expert and you are curious about the meaning of the various elements there, here there’s a quick description.
    The SecurityTokenHandlers element is used for registering a new SecurityTokenHandler class, SimpleWebTokenHandler, which enhances WIF with the capability of processing SWT tokens.
    The issuerTokenResolver element contains a custom TokenResolver class, which tells WIF how to check the signature of incoming SWT tokens; this allows you to specify directly in config the symmetric key you defined in ACS for signing tokens for the MyTodo application.
    The issuerNameRegistry section contains another custom class, which leverages the WIF extensibility model: this time the class enables WIF to list a SWT issuer, instead of the out of the box issuers which are expected to sign tokens with X.509 certificates.
    Let me stress that you are not required to understand anything of the above explanation in order to take advantage of OAuth2 in your service. You could have skipped this note altogether and your ability of taking advantage of the feature would not be diminished in the least.

  7. In the WIF configuration code you have just added, replace the placeholders with the values you recorded when configuring ACS: Enter the service key for MyTodo application (task 2, step 30) and the service namespace (task 2, step 4).
  8. That’s pretty much it! All that’s left is making sure that there are no extra paths through which unauthenticated users can access the service. Open the MyTodoDataService.cs file from the MyTodo.Services project.
  9. Add the following using statements.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService UsingOAuth)

    C#

    using System.Web;
    using Microsoft.Samples.DPE.OAuth;
  10. Create a function to return an unauthorized response if the current user is not authenticated. To do this, insert the following code in the MyTodoDataService class.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService ThrowIfNotAuthenticated)

    C#

    private static void ThrowIfNotAuthenticated()
    {
        var identity = HttpContext.Current.User.Identity;
        if (identity == null || !identity.IsAuthenticated)
        {
            OAuthHelper.SendUnauthorizedResponse(new OAuthError { Error = OAuthErrorCodes.UnauthorizedClient }, HttpContext.Current);
        }
    }
  11. Override the method OnStartProcessingRequest and call ThrowIfNotAuthenticated to validate the current user before processing any request to the service.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService OnStartProcessingRequest)

    C#

    protected override void OnStartProcessingRequest(ProcessRequestArgs args)
    {
        ThrowIfNotAuthenticated();
        base.OnStartProcessingRequest(args);
    }

Task 4 – Adding Authorization for Private Lists

At this point, the MyTodo OData service has been secured: any existing clients invoking the service without adding authentication information will not gain access. However, we still don’t have implemented the private list feature: right now you need to be authenticated in order to call the service, but once you do it, there is no restriction to which lists you can see. In this task, you will add authorization logic that will properly restrict access in order to implement the private lists feature.

  1. Add a reference to the Microsoft.IdentityModel library in the MyTodo.Services project. In the solution explorer, right click the MyTodo.Services project and select Add Reference. In the Add Reference dialog select the .NET tab, select the Microsoft.IdentityModel component and click OK.
  2. Open the MyTodoDataService.cs file from the MyTodo.Services project.
  3. Add the following using statement.

    C#

    using Microsoft.IdentityModel.Claims;
  4. Create a UserName property to get the name claim value in the MyTodoDataService class.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService UserName)

    C#

    private string UserName 
    {
        get 
        {
            var identity = HttpContext.Current.User.Identity as IClaimsIdentity;
    
            if (identity != null)
            {
                var claimName = identity.Claims.Single(c => c.ClaimType == ClaimTypes.Name);
    
                if (claimName != null)
                {
                    return claimName.Value;
                }
            }
    
            throw new DataServiceException(401, "Unauthorized");
        }
    }
  5. Find the OnChangeTaskList function and insert code to set the UserName property to the current user for add operations. Now that every newly created list has an owner associated to it, the delete and update operations can be restricted to work only if the current user is indeed the owner of the targeted list. Replace the OnChangeTaskList function body with the following code.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService OnChangeTaskList)

    C#

    [ChangeInterceptor("TaskLists")]
    public void OnChangeTaskList(TaskList taskList, UpdateOperations operation)
    {
        var userName = this.UserName;
    
        if (operation == UpdateOperations.Add)
        {
            taskList.UserName = userName;
    
            if (taskList.Id == Guid.Empty)
            {
                taskList.Id = Guid.NewGuid();
            }
        } 
        else if (operation == UpdateOperations.Delete || operation == UpdateOperations.Change)
        {
            var originalList = this.GetOriginalTaskList(taskList.Id);
    
            if (originalList == null || originalList.UserName != userName || taskList.UserName != userName)
            {
                throw new DataServiceException(401, "Unauthorized");
            }
        }
    }

    note[11]Note:

    Note: This function contains authorization code. Normally it is good practice to try externalizing that code as much as possible, and WIF’s extensibility model encourages that via classes such as ClaimsAuthorizationManager. However, in OData the relevant details of a request are often embedded in the structure of the request URI itself, which would be laborious to parse from ClaimsAuthorizationManager; for that reason, here we kept things simple and placed all logic here.

  6. Execute the same updates to the OnChangeTask function; replace the OnChangeTask function body with the following code.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService OnChangeTask)

    C#

    [ChangeInterceptor("Tasks")]
    public void OnChangeTask(Task task, UpdateOperations operation)
    {
        var userName = this.UserName;
    
        if (operation == UpdateOperations.Add)
        {
            if (task.Id == Guid.Empty)
            {
                task.Id = Guid.NewGuid();
            }
    
            task.UserName = userName;
            task.StartDate = DateTime.UtcNow;
            task.DueDate = DateTime.MaxValue;
            task.TimestampUpdate = DateTime.UtcNow;
        }
        else if (operation == UpdateOperations.Delete || operation == UpdateOperations.Change)
        {
            var originalTask = this.GetOriginalTask(task.Id);
            var originalList = this.GetOriginalTaskList(originalTask.ListId);
            if (originalTask == null || originalList == null || originalList.UserName != userName || originalTask.UserName != userName || task.UserName != userName || task.ListId != originalTask.ListId)
            {
                throw new DataServiceException(401, "Unauthorized");
            }
    
            if (operation == UpdateOperations.Change) task.TimestampUpdate = DateTime.UtcNow;
        }
    }
  7. Add query interceptors to filter the private lists and the items that are not owned by the current user. Then, include the public interceptor.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 MyTodoDataService QueryInterceptors)

    C#

    [QueryInterceptor("Tasks")]
    public Expression<Func<Task, bool>> QueryTasks()
    {
        return c => c.TaskList.IsPublic == 1 || c.TaskList.UserName.Equals(HttpContext.Current.User.Identity.Name, StringComparison.OrdinalIgnoreCase);
    }
    
    [QueryInterceptor("TaskLists")]
    public Expression<Func<TaskList, bool>> QueryTaskLists()
    {
        return c => c.IsPublic == 1 || c.UserName.Equals(HttpContext.Current.User.Identity.Name, StringComparison.OrdinalIgnoreCase);
    }

    That’s it for this task. You augmented the MyTodo service with authentication and authorization logic, now it’s up to the clients to comply with the new access policy.

  8. Open ListView.xaml from the Views folder in the MyTodo.Phone project and include a textblock to display when a list is private or public. To do that, replace the existing stack panel content with the following markup:

    XAML

    ...
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="0,0,0,30">
                <Image x:Name="ItemImage" Source="/Microsoft.Samples.MyTodo.Phone;component/Resources/Images/ArrowImg.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
                <StackPanel>
                    <TextBlock x:Name="ItemText" Text="{Binding Name}" Margin="-2,-13,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}" TextWrapping="Wrap" Width="395" />
                    <StackPanel Orientation="Horizontal" Margin="0,-6,0,3">
                        <Image Source="/Microsoft.Samples.MyTodo.Phone;component/Resources/Images/PublicImg.png" Height="30" Width="30" Visibility="{Binding IsPublic, Converter={StaticResource VisibilityConverter}, ConverterParameter=1}" />
                        <TextBlock Text="Public" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" Visibility="{Binding IsPublic, Converter={StaticResource VisibilityConverter}, ConverterParameter=1}" />
    
                        <Image Source="/Microsoft.Samples.MyTodo.Phone;component/Resources/Images/PublicImg.png" Height="30" Width="30" Opacity="0.35" Visibility="{Binding IsPublic, Converter={StaticResource VisibilityConverter},ConverterParameter=0}" />
                        <TextBlock Text="Private" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" Visibility="{Binding IsPublic, Converter={StaticResource VisibilityConverter},ConverterParameter=0}" />
    
                        <TextBlock Text=" | Tasks: " Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" />
                        <TextBlock Text="{Binding Tasks.Count}" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" />
                    </StackPanel>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
    ...

Task 5 – Adding Authentication to a WP7 Application

In this task, you will finally add authentication to the WP7 application. In order to do that you will include a project containing a control which wraps much of the communication with ACS and session management, then you will write the necessary code to integrate the control in your app and configure it to use your ACS namespace

  1. Add the SL.Phone.Federation project from the assets folder to the solution. To do this, in the Solution Explorer, right click the MyTodo solution, select Add and click Existing Project. Browse to [Lab folder]\Source\Assets\SL.Phone.Federation and open the SL.Phone.Federation.csproj file.
  2. Rebuild the solution.
  3. Add a reference to the SL.Phone.Federation project in the MyTodo.Phone project. In the solution explorer, right click the MyTodo.Phone project and select Add Reference. In the Add Reference dialog select the Projects tab and double click the SL.Phone.Federation project.
  4. Open the App.xaml file and define a namespace prefix for the SL.Phone.Federation.Utilities.

    XAML

    <Application 
        x:Class="Microsoft.Samples.MyTodo.Phone.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:fed="clr-namespace:SL.Phone.Federation.Utilities;assembly=SL.Phone.Federation">

    note[12]Note:

    Verify you added the fed namespace definition inside the Application opening tag.

  5. Add the following resource in App.xaml (set Realm, ServiceNamespace and RequestSecurityTokenReponseStore properties).

    XAML

    <!--Application Resources-->
    <Application.Resources>
        <fed:RequestSecurityTokenResponseStore x:Key="rstrStore" />
        ...
    </Application.Resources>
  6. You’ll need a new page which will host the authentication experience. Add a new page in the Views folder and name it LoginView.xaml. In the Solution Explorer, right click the Views folder, select Add and click New Item. In the Add New Item dialog, select Windows Phone Portrait Page, set the name to LoginView.xaml and click Add.

    05f7843f-8b06-4b84-839e-1518c61cf57d

    Figure 25
    Adding a new Windows Phone view

  7. Update the Text property from the ApplicationTitle TextBlock to get its value from the ApplicationNameString resource and set the Text property from the PageTitle TextBlock to “log in”.

    XAML

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="{StaticResource ApplicationNameString}" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="log in" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
  8. Define a namespace prefix for SL.Phone.Federation.Controls.

    XAML
     

    <phone:PhoneApplicationPage 
        x:Class="Microsoft.Samples.MyTodo.Phone.Views.LoginView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:fed="clr-namespace:SL.Phone.Federation.Controls;assembly=SL.Phone.Federation"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        ...
  9. Now that you have the login page in place, you can instantiate the control that will take care of the authentication mechanics. Inside the “ContentPanel” Grid control, include the following code to configure an AccessControlServiceSignIn control.

    XAML

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <fed:AccessControlServiceSignIn 
            x:Name="SignInControl" 
            Realm="uri:mytodo"
            ServiceNamespace="[Service Namespace]"
            RequestSecurityTokenResponseStore="{StaticResource rstrStore}" />
    </Grid>

    The AccessControlServiceSignIn wraps most of the logic required to handle the sign-in operation; at this point you need to integrate the control with various elements of the application so that the authentication experience appears seamless

  10. Replace the [Service Namespace] placeholder in the AccessControlServiceSignIn control with your account service namespace to be used.
  11. Open the ListsView.xaml.cs file and add the following using statement.

    C#

    using SL.Phone.Federation.Utilities;
  12. The SignInControl persists tokens on the phone’s isolated storage, so that one authenticated session can be maintained across multiple runs of the application (until the token is no longer valid or the user explicitly logs out. Define and initialize the _rstrStore class variable with the rstrStore resource.

    C#

    public partial class ListsView : PhoneApplicationPage
    {
        RequestSecurityTokenResponseStore _rstrStore = App.Current.Resources["rstrStore"] as RequestSecurityTokenResponseStore;

    note[13]Note:

    Note. Saving a token on the phone’s storage is not very secure. The isolated storage may prevent other applications from stealing the persisted token, but it does not prevent somebody with physical access to the device to eventually get to it. Any form of encryption would not solve the issue if the decryption key resides on the phone, no matter how well it is hidden. You could require the user to enter a PIN at every application run, and use the PIN to decrypt the token, however the approach presents obvious usability and user acceptance challenges.
    While we wait for a better solution to emerge, it may be of some consolation considering that saving token is much better than saving direct credentials such as a username/password pair. A token is typically scoped to be used just with a specific service, and it has an expiration time: this somewhat limits what an attacker can do with a token, whereas no such restrictions would be present should somebody acquire username and password.

  13. At load time, the ListView page should load the ViewModel data if there is a valid session (i.e. there is a valid token in storage) or redirect to the login page. Find the Loaded event in the ListsView constructor and change it according to the snipped below.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 ListView ListsView)

    C#

    public ListsView()
    {
        InitializeComponent();
    
        this.PageTransitionReset.Begin();
        this.Loaded += (sender, args) =>
        {
            if (!_rstrStore.ContainsValidRequestSecurityTokenResponse())
            {
                NavigationService.Navigate(new Uri("/Views/LoginView.xaml", UriKind.Relative));
            }
            else
            {
                this.PageTransitionIn.Begin();
                this.ViewModel.Reload();
            }
        };
        ...

    note[14]Note:

    If you use the provided code snippet in Visual Studio, you will have to move the transition and reload code inside the else block.

  14. Rebuild the solution.
  15. Here there’s the main trigger that will show the authentication UI. Open LoginView.xaml page. Move the cursor to the page root element and switch to the Events view in the Properties window (press F4 if you do not see the properties window). Double click on the Loaded property and add the following code to handle the RequestSecurityTokenResponseCompleted event.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 ListView PhoneApplicationPage)

    C#

    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
    {
        SignInControl.RequestSecurityTokenResponseCompleted += new EventHandler<SL.Phone.Federation.Controls.RequestSecurityTokenResponseCompletedEventArgs>(SignInControl_RequestSecurityTokenResponseCompleted);
        SignInControl.GetSecurityToken();
    }
  16. Once the sign-in control completed an authentication request, it will raise the RequestSecurityTokenResponseCompleted event that you wired up in the former step. The handler below ensures that in case of successful login the application will navigate back to the page that triggered the authentication operation. Add the SignInControl_RequestSecurityTokenResponseCompleted method using the snippet below.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 ListView SignInControl)

    C#

    void SignInControl_RequestSecurityTokenResponseCompleted(object sender, SL.Phone.Federation.Controls.RequestSecurityTokenResponseCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            if (NavigationService.CanGoBack)
            {
                NavigationService.GoBack();
            }
        }
    }
  17. You need to provide a UI element for triggering the logout operation. Open the ListsView.xaml page and insert the following code snippet at the bottom before the closing PhoneApplicationPage element to create an application bar and a log out button to it.

    XAML

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Resources/Images/LogoutImg.png" Text="log out" Click="LogOut_Click"/>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
  18. Here there is the logout logic. Open to the ListsView.xaml.cs file and create the LogOut_Click event. The code clears the stored token and navigates to the LoginView.xaml page.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 ListView LogOutClick)

    C#

    private void LogOut_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show("Are you sure you want to log out?", "Log out", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            _rstrStore.RequestSecurityTokenResponse = null;
    
            NavigationService.Navigate(new Uri("/Views/LoginView.xaml", UriKind.Relative));
        }
    }
  19. The moment in which the application actually uses the token is when it invokes the service. Open the TodoService.cs file from the Services folder.
  20. You need to ensure that every time the service is invoked, the token is injected in the call according to the OAuth2 specification. A good way of adding the necessary logic so that it is triggered for every call is to add it to the GetContext method. Find the GetContext function and update the SendingRequest event to add an “Authorization” request header with the issued token.

    (Code Snippet – ACS and Windows Phone 7 - Ex01 DataServiceContext GetContextAddAuth)

    C#

    private DataServiceContext GetContext()
    {
        var dataService = new DataServiceContext(serviceUri);
        dataService.MergeOption = MergeOption.OverwriteChanges;
        dataService.SendingRequest += (sender, args) =>
        {
            var store = App.Current.Resources["rstrStore"] as SL.Phone.Federation.Utilities.RequestSecurityTokenResponseStore;
            args.RequestHeaders["Authorization"] = "OAuth " + store.SecurityToken;
        };
    
        return dataService;
    }

Exercise 1: Verification

It is time to give your newly secured Windows Phone 7 application a spin.

In order to verify that you have correctly performed all steps in exercise one, you will first create a private list and one task. Then, you will log in with a different user to verify that the created list is not visible.

note[15]Note:

To perform this verification you need to have at least two accounts in either Windows Live ID, Google, Yahoo! or Facebook.

  1. Set the target deployment device to Windows Phone 7 Emulator.

    4fc7ed8f-4d34-4e95-b683-786d6b1948c4

    Figure 26
    Selecting the Windows Phone 7 deployment service

  2. Set the MyTodo.Cloud project as the StartUp project. To do this, in the Solution Explorer, right click the MyTodo.Cloud project and select Set as StartUp Project.
  3. Start debugging the cloud service by pressing F5. The compute emulator should start and a browser with the OData service endpoint should open.

    23a7ea8d-3516-49c9-8a03-1306f517b80e

    Figure 27
    OData service endpoint

    note[16]Note:

    Since the solution contains a Windows Phone 7 project and the target deployment is the Windows Phone 7 Emulator, Visual Studio will also start up the emulator when you run the cloud project but the Phone project will not start debugging: you have to start the debug session manually as explained below.

  4. In the solution explorer, right click the MyTodo.Phone project, select Debug and click Start New Instance. This will open the MyTodo application on the login page.

    af22e0d1-c284-483d-b706-dbe55d6663e1

    Figure 28
    MyTodo Login

    The sign-in control queries your ACS namespace to dynamically retrieve the list of identity providers you configured in task.

  5. Log in to the application with your account information. After that you will enter to MyTodo:

    95a0eeb1-1f2f-4a99-af40-f51705256950

    Figure 29
    Windows Phone 7 embedded browser

  6. Create a new list in the application. To do that, write the list name in the textbox at the bottom and click the + button to save it.

    b2b57728-583d-479f-bfc1-4ef7f700b2da

    Figure 30
    Adding a list

  7. Click the new list name link to open it, and then create several task items using the textbox at the bottom. Click ‘+’ to save the task item:

    d994aaff-ebab-4a36-bb2d-cba2cc45b451

    Figure 31
    Adding task items to the list

    note[17]Note:

    Only the owner of a public list can remove or add items from it. If you try to edit a list you do not own, you will get a Service Error exception.

  8. Click the back button to return to the application lists, and click the log out icon at the bottom of the application.

    62b17854-3e8a-4367-b141-99b74779584b

    Figure 32
    Back and Log Out buttons

  9. Log in again using a different account than the one used in step 4. You will notice you cannot see the tasks lists created by other users:

    808551a2-427a-47d5-9ecf-67fa8dc4c150

    Figure 33
    Using a different login account

  10. Repeat steps 6 to 9 and login with the first account to see you will see only the private lists that where created by the current users and the already existing public lists.
  11. Log out from the application.

    ff547b75-1b04-4f04-a86a-bcf3b24310a3

    Figure 34
    Logging out from the application