Search code examples
wcfsilverlight-3.0windows-phone-7basic-authentication

Using basic authentication over SSL on Windows Phone 7


I know that variations on this question have been asked, but I've tried all suggested solutions to no avail. We are trying to connect to a WCF service that uses basic authentication and transport security (unfortunately, these things can't be changed). I have not been able to find a way to add our credentials to the TRANSPORT on a WCF call; all solutions seem to be around adding headers to the message.

Our newest attempt is to grab a text file off the server using HttpWebClient that has the credentials attached and then make the WCF call; our hope that the authentication would then...I don't know, jump from the HttpWebClient to the WCF client (generated with Service Reference). And while the first call does work, we get a CommunicationException on the WCF call (and if I dig into the response, the Status Description is set to Unauthorized).

Is there a way to have the clients share the authorization token that is returned from the successful attempt? Is this a fool's errand? Is there an easier method of doing this that I am to blind too see?

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri("https://server/OGTE/api/WinPhone7.html"));

        request.Credentials = new NetworkCredential(_userName, _password, _domain);
        request.Method = "GET";

        request.BeginGetResponse((beginGetResponseResult) =>
        {
            try
            {
                HttpWebRequest requestWhileResponding = (HttpWebRequest)beginGetResponseResult.AsyncState;
                HttpWebResponse response = (HttpWebResponse)requestWhileResponding.EndGetResponse(beginGetResponseResult);

                try
                {
                    using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
                    {

                         string info = streamReader1.ReadToEnd();

                        Dispatcher.BeginInvoke(() =>
                                                   {
                                                       textblock.Text = info;
                                                   });

                    }

                    _userDataService.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(_userDataService_GetDataCompleted);
                    _userDataService.GetDataAsync("0C5696BB-2D15-4EA7-B198-5C12B3E23B63");

                }
                catch (Exception ex)
                {

                    Debug.WriteLine(ex.ToString());
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        },

    request);
    }

Solution

  • For those that are curious, it turns out that what I was attempting above was completely unnecessary. Turns out the that the authorization header CAN be set by hand, as found it this fantastic article: http://cisforcoder.wordpress.com/2010/12/01/how-to-implement-basic-http-authentication-in-wcf-on-windows-phone-7/. The general gist of it is to get the current context and set the header on that, as shown here:

    var credentials = EncodeBasicAuthenticationCredentials("username", "password");
    
    using (OperationContextScope scope =
          new OperationContextScope(service.InnerChannel))
    {
        HttpRequestMessageProperty request = new HttpRequestMessageProperty();
        request.Headers[System.Net.HttpRequestHeader.Authorization] = 
            "Basic " + credentials;
    
        OperationContext.Current.OutgoingMessageProperties.Add(
                                     HttpRequestMessageProperty.Name, request);
    
        service.DoSomethingAsync();
    }
    

    Hopefully some day soon things like this won't be necessary but until then, I hope that this can get someone started on their project faster than I was able to.