Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF, ASP.NET Membership Provider and Authentication Service

I have written a Silverlight 2 application communicating with a WCF service (BasicHttpBinding). The site hosting the Silverlight content is protected using a ASP.NET Membership Provider. I can access the current user using HttpContext.Current.User.Identity.Name from my WCF service, and I have turned on AspNetCompatibilityRequirementsMode.

I now want to write a Windows application using the exact same web service. To handle authentication I have enabled the Authentication service, and can call "login" to authenticate my user... Okey, all good... But how the heck do I get that authentication cookie set on my other service client?!

Both services are hosted on the same domain

  • MyDataService.svc <- the one dealing with my data
  • AuthenticationService.svc <- the one the windows app has to call to authenticate.

I don't want to create a new service for the windows client, or use another binding...

The Client Application Services is another alternative, but all the examples is limited to show how to get the user, roles and his profile... But once we're authenticated using the Client Application Services there should be a way to get that authentication cookie attached to my service clients when calling back to the same server.

According to input from colleagues the solution is adding a wsHttpBinding end-point, but I'm hoping I can get around that...

like image 901
Jonas Follesø Avatar asked Sep 11 '08 09:09

Jonas Follesø


1 Answers

I finally found a way to make this work. For authentication I'm using the "WCF Authentication Service". When authenticating the service will try to set an authentication cookie. I need to get this cookie out of the response, and add it to any other request made to other web services on the same machine. The code to do that looks like this:

var authService = new AuthService.AuthenticationServiceClient();
var diveService = new DiveLogService.DiveLogServiceClient();

string cookieHeader = "";
using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel))
{
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
    bool isGood = authService.Login("jonas", "jonas", string.Empty, true);
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
    cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];                
}

using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel))
{
    HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader);
    var res = diveService.GetDives();
}      

As you can see I have two service clients, one fo the authentication service, and one for the service I'm actually going to use. The first block will call the Login method, and grab the authentication cookie out of the response. The second block will add the header to the request before calling the "GetDives" service method.

I'm not happy with this code at all, and I think a better alternative might be to use "Web Reference" in stead of "Service Reference" and use the .NET 2.0 stack instead.

like image 107
Jonas Follesø Avatar answered Oct 23 '22 12:10

Jonas Follesø