Share via


Exercise 2: Creating the Windows Phone 7 Application

In this exercise, you will complete a Windows Phone 7 application that can read and write to the maintenance announcements SharePoint list created in exercise 1. This exercise focuses on the steps to authenticate to SharePoint using forms based authentication.

Task 1 – Beginning the Exercise

In this task, you will open the lab solution in Visual Studio 2010.

  1. Make sure that you have downloaded and installed the items listed in System Requirements above prior to beginning this exercise.
  2. Launch Visual Studio 2010 as administrator and open the lab project by selecting File » Open » Project.
    1. Browse to the WP7.Security.FBA.sln file located at %TrainingKitPath%\Labs\IntegratingFormsBasedAuthentication\Source\Before and select it.
    2. Click Open to open the solution.

Task 2 – Configuring Constants in the Windows Phone 7 Application

In this task, you will configure the constants used in the Windows Phone 7 application to work with your development environment.

  1. In the WP7.Security.FBA, in the Utilities folder, open the Constants.cs file.
  2. Change the value for the USER_NAME and USER_PASSWORD constants to represent a Forms Based Authentication user specific to your development environment. For this lab, the user requires read and write permissions.
  3. Change the value for the AUTHENTICATION_SERVICE_URL constant to the URL specific to your development environment.
  4. The following code example demonstrates the value for a SharePoint server named fbawp7.

    C#

    public const string AUTHENTICATION_SERVICE_URL = "https://fbawp7/_vti_bin/authentication.asmx";

    The SharePoint Authentication.asmx web service allows a remote device to authenticate to SharePoint using forms-based authentication.

Task 3 – Adding the FBAAuthenticatedEventArgs Class to the Project

In this task, you will add the FBAAuthenticatedEventArgs to the Utils.cs File.

  1. In the WP7.Security.FBA, in the Utilities folder, open the Utils.cs file.
  2. Add the following code under the //TODO: 6.1.1 comment to define the FBAAuthenticatedEventArgs class:

    C#

    public class FBAAuthenticatedEventArgs : EventArgs { public CookieContainer CookieJar { get; private set; } public FBAAuthenticatedEventArgs(CookieContainer c) { CookieJar = c; } }

    The FBAAuthenticatedEventArgs class inherits EventArgs. This class is used to pass the CookieContainer to the caller after the call has been authenticated. The CookieContainer will contain the HttpOnly FedAuth cookie with the authentication information.

Task 4 – Modifying the FBAAuthorization Class to Authenticate Using the SharePoint Authentication.asmx Web Service

In this task, you will modify the ServiceReferences.ClientConfig file to support the CookieContainer used with Forms BasedAuthentication. The code used to authenticate to the SharePoint server in this lab uses Forms Based Authentication. Forms Based Authentication requires the use of a CookieContainer. Please see the Security With SharePoint And Windows Phone 7 Applications Module slide deck for more information about Forms Based Authentication.

  1. In the WP7.Security.FBA, in the Utilities folder, open the Utils.cs file.
  2. Add the following code under the //TODO: 6.1.2 comment to define the FBAAuthenticatedEventArgs class:

    C#

    public event EventHandler<FBAAuthenticatedEventArgs> OnAuthenticated; public event EventHandler OnFailedAuthentication;

    The above code defines the OnAuthenticated and OnFailedAuthentication events for the FBAAuthorization class. The FBAAuthorization class contains the code to authenticate to SharePoint using the Authentication.asmx web service. Clients will bind to the FBAAuthorization instance’s OnAuthenticated event to receive notification that the authentication is completed. This event passes the CookieContainer containing the authentication cookie to the caller using an instance of the FBAAuthenticatedEventArgs class. Clients can bind to the OnFailedAuthentication event to be notified of failed authentication attempts.

  3. Add the following code under the //TODO: 6.1.3 comment to define the FBAAuthorization constructor:

    C#

    public FBAAuthorization(string UserName, string UserPassword, string AuthenticationServiceURL) { this.UserName = UserName; this.UserPassword = UserPassword; this.AuthenticationServiceURL = AuthenticationServiceURL; }

    The above code defines the FBAAuthorization class’s constructor. The constructor simply stores the passed in parameters into properties for later use.

  4. Add the following code under the //TODO: 6.1.4 comment to define the Authenticate method:

    C#

    public void Authenticate() { System.Uri authServiceUri = new Uri(AuthenticationServiceURL); HttpWebRequest spAuthReq = HttpWebRequest.Create(authServiceUri) as HttpWebRequest; spAuthReq.CookieContainer = cookieJar; spAuthReq.Headers["SOAPAction"] = "https://schemas.microsoft.com/sharepoint/soap/Login"; spAuthReq.ContentType = "text/xml; charset=utf-8"; spAuthReq.Method = "POST"; spAuthReq.BeginGetRequestStream(new AsyncCallback(spAuthReqCallBack), spAuthReq); }

    The above code creates an HttpWebRequest object using the stored Url to the SharePoint authentication service. The key to this method is to attach an existing CookieContainer object (cookieJar) to the request. This allows the code to easily access the CookieContainer in the return method. The call to Authentication.asmx web services posts a SOAP payload. This method defines the BeginGetRequestStream callback method in the call to BeginGetRequestStream.

  5. Add the following code under the //TODO: 6.1.5 comment to define the spAuthReqCallBackmethod:

    C#

    private void spAuthReqCallBack(IAsyncResult asyncResult) { string envelope = @"<?xml version=""1.0"" encoding=""utf-8""?> <soap:Envelope xmlns:xsi=""https://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""https://www.w3.org/2001/XMLSchema"" xmlns:soap=""https://schemas.xmlsoap.org/soap/envelope/""> <soap:Body> <Login https://schemas.microsoft.com/sharepoint/soap/""> <username>{0}</username> <password>{1}</password> </Login> </soap:Body> </soap:Envelope>"; UTF8Encoding encoding = new UTF8Encoding(); HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; Stream _body = request.EndGetRequestStream(asyncResult); envelope = string.Format(envelope, UserName, UserPassword); byte[] formBytes = encoding.GetBytes(envelope); _body.Write(formBytes, 0, formBytes.Length); _body.Close(); request.BeginGetResponse(new AsyncCallback(ResponseCallback), request); }

    The above code defines the XML SOAP payload for the authentication request. The envelope variable contains the basic SOAP request. The username and password values are set using the stored values in the FBAAuthorization class. The HttpWebRequest instance defines the callback in the BeginGetResponse call. The BeginGetResponse starts the asynchronous service request. When completed the code will call the ResponseCallback method.

  6. Add the following code under the //TODO: 6.1.6 comment to define the ResponseCallback method:

    C#

    private void ResponseCallback(IAsyncResult asyncResult) { string responseString = ""; HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult); Stream content = response.GetResponseStream(); if (request != null && response != null) { if (response.StatusCode == HttpStatusCode.OK) { using (StreamReader reader = new StreamReader(content)) { responseString = reader.ReadToEnd(); reader.Close(); } } } if (responseString.Contains("NoError")) { EventHandler<FBAAuthenticatedEventArgs> authenticated = OnAuthenticated; if (authenticated != null) { authenticated(this, new FBAAuthenticatedEventArgs(cookieJar)); } } else { EventHandler failedAuth = OnFailedAuthentication; if (failedAuth != null) { failedAuth(this, null); } } }

    The above code is called when the authentication request returns. This code retrieves the SOAP response from the HttpWebResponse object. The SOAP response is an XML string. This example simply looks for “NoError” in the string. The value of “NoError” means the login attempt was successful. Not finding the value of “NoError” indicates a failed login attempt.

    The code above raises the appropriate event, which is handled by the caller. The OnAuthenticated event returns an FBAAuthenticatedEventArgs object to the event listener. The FBAAuthenticatedEventArgs has a reference to the returned CookieContainer that was populated with the HttpOnly FedAuth cookie. The HttpOnly cookie cannot be seen or manipulated using code in the current version of the phone platform. Because the FedAuth cookie is marked as HttpOnly the CookieContainer must be passed back instead of an individual cookie.

Task 5 – Creating a Static Variable to Store the CookieContainer

In this task, you will create a global, static variable to store the CookieContainer. The CookieConainer containing the FBA cookie will be needed by any class calling authenticated resources from SharePoint.

  1. In the WP7.Security.FBA, right-click App.xaml, and select View Code.
  2. Add the following code under the //TODO: 6.1.7 comment to define the CookieJar property:

    C#

    public static CookieContainer CookieJar { get; set; }

    The above code creates a static, global property called CookieJar. This property stores the CookieContainer object returned from the authentication call for use in accessing secured resources from SharePoint.

Task 6 – Completing the ViewModel to Authenticate Using FBA

In this task, you will use the complete the existing MainViewModel class to include authentication calls to the FBAAuthorization instance.

  1. In the WP7.Security.FBA, in the ViewModels folder, open the MainViewModel.cs file.
  2. Add the following code under the //TODO: 6.1.8 comment to define the class-level FBAAuthorization variable:

    C#

    FBAAuthorization Auth;

    The Auth variable will contain a reference to an FBAAuthorization object created in the class constructor.

  3. Add the following code under the //TODO: 6.1.9 comment to define the class-level Auth_OnAuthenticated and Auth_OnFailedAuthentication event handlers:

    C#

    void Auth_OnAuthenticated(object sender, FBAAuthenticatedEventArgs e) { App.CookieJar = e.CookieJar; LoadAnnouncements(); } void Auth_OnFailedAuthentication(object sender, EventArgs e) { Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("Failed Login Attempt") ); }

    The Auth_OnAuthenticated event handler is bound to the Auth variable in the class and contain a reference to the FBAAuthorization object created in the class constructor. This method is called when authorization is complete. The event handler stores the CookieContainer containing the FedAuth cookie in the static property CookieJar allowing the CookieContainer to be available to other objects in the project. Finally, the code calls LoadAnnouncements method. The LoadAnnouncements method starts the data retrieval process from SharePoint.

    The Auth_OnFailedAuthentication event handler is also bound to the Auth variable. This event handler is called when the authentication service returns a failed authentication attempt.

  4. Add the following code under the //TODO: 6.1.10 comment to define the MainViewModel constructor:

    C#

    public MainViewModel() { Auth = new FBAAuthorization(Constants.USER_NAME, Constants.USER_PASSWORD, Constants.AUTHENTICATION_SERVICE_URL); Auth.OnAuthenticated += new EventHandler<FBAAuthenticatedEventArgs>(Auth_OnAuthenticated); Auth.OnFailedAuthentication += new EventHandler(Auth_OnFailedAuthentication); }

    The MainViewModel constructor creates an instance of the FBAAuthorization class and sets the Auth variable to point to the new FBAAuthorization class. The constructor then defines the event handlers for the OnAuthenticated and OnFailedAuthentication events.

  5. Add the following code under the //TODO: 6.1.11 comment attach the CookieContainer to the web service call:

    C#

    lists.CookieContainer = App.CookieJar;

    Once the CookieContainer with the FedAuth cookie is available secured SharePoint resources can be called by attaching the CookieContainer (located in App.CookieJar) to the request object. For a Web service accessed using a Visual Studio proxy object, the CookieContainer can be attached using the above code. Once the CookieContainer is attached to the request object, SharePoint will allow authorized access to secured resources based on the FedAuth cookie information. Each new request object will require the CookieContainer with the FBA cookie to be attached to the request object.