views:

3509

answers:

3

Hi, I have a website that talks to a remote WCF web service. Both use the same custom FormsAuthentication Provider. I would like to authenticate with the WCF service impersonating the user currently logged in the site. I already did this manually, using UserName client credentials but I need to know the user password. So, what works so fart is this: an authenticated user makes a request, I create a Service Client and set his credentials:

serviceClient.ClientCredentials.UserName.UserName = username;
serviceClient.ClientCredentials.UserName.Password = password;

But what I really want is to pass the FormsAuthentication cookie directly, because I don't want to store the user password.

Any ideas?

+3  A: 

It sounds like you're looking for the Windows Communication Foundation Authentication Service.

EDIT:

After re-reading the question more carefully (and after Ariel's comment) I'd like to retract the above suggestion. The WCF Authentication Service won't add much to this scenario.

I haven't done this between WCF and ASP.NET, however I have configured ASP.NET applications to share forms authenticated users, perhaps I can help in some way.

To ensure that both applications can encrypt/decrypt the forms authentication cookie in the same way you should configure the <machineKey> element for both applications (in web.config or machine.config depending on whether you want to do this at the machine or application level). You should look at the validation, validationKey, decryption and decryptionKey attributes.

Ensure that your <forms> elements in both web.config files are configured similarly. Specifically the name, path and domain attributes.

It's likely that this only applies to cookies passed to/from a web browser (but may be useful in this case): To allow cookies to be passed between the websites www.foo.com and bar.foo.com you would configure the forms element as follows to allow cookies to be set on one site and successfully passed to the other:

<forms ... domain=".foo.com" ... />

Passing the cookie to the WCF service is likely to be the tricky bit. I'm not very experienced with WCF, so I've adapted code from kennyw.com:

HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers.Add(HttpRequestHeader.Cookie, "<Forms Authentication Cookie>");

using (OperationContextScope scope = new OperationContextScope(serviceClient.InnerChannel))
{
  OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
  serviceClient.MethodName();
}

If you're hosting WCF within IIS (and not self-hosting) you can pass the WCF request through the ASP.NET processing pipeline by setting

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" ... />
</system.serviceModel>

If you're self hosting you could examine the request headers using the incoming message's properties in OperationContext.Current.IncomingMessageProperties and get the forms authentication cookie value and decrypt it using FormsAuthentication.Decrypt(string).

I have no idea whether any of this would work, but would love to hear if it does!

dariom
I don't see how the Authentication Service could help.My scenario is this:USER -> Web Site A -> WCF Service B hosted elsewhereUser logs in to A, A makes a call to B using the User credentials.Where would you add the Authentication service?
Ariel Popovsky
Hi Ariel. Sorry I tried to answer too quickly without really reading your question. I'll edit it with an update.
dariom
Thanks for the suggestion, I'll try that and share the results here.
Ariel Popovsky
A: 

It's simple enough to do if you host the WCF service within the authenticated IIS site.

Enable compatibility by adding the following to your system.ServiceModel section in your web.config

<system.serviceModel>  
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> 
</system.serviceModel>

Then decorate each service you wish to accept the cookie with the following

[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

Now the HttpContext.Current.User.Identity object will be correctly populated and you can also use PrinciplePermission demands to limit access by role or to particular users.

blowdart
Well, that's the problem, I can't use the same IIS. A requirement for the system I'm building was to host the web site and service in separate machines.I'm considering using a shared token but I using Forms was the simplest solution to implement coming from ASP.net.
Ariel Popovsky
Ah sod! Can you at least put them on the same domain name? If so you can set the forms auth cookie scope and share it that way.
blowdart
I think so, the application will be hosted in an intranet under a single root domain. We can set identical machine keys also but keep in mind the user is accessing the website and the website uses the WCF as a data source impersonating the user. It works fine with Windows Authentication but passing the FormsAuthentication cookie is a different story. I'll try dariom suggestion (or any other if available).
Ariel Popovsky
blowdart, just wanted to let you know that although this reply didn't answer the poster's question, it answered mine. I appreciate your not having removed it!
Remi Despres-Smyth
A: 

I can't get the above to work because when I try to consume the service in vb.net with "ADD SERVICE REFERENCE", it wants me to login (even if I'm logged in elsewhere).

ADD SERVICE REFERENCE is obviously on its own thread or otherwise doesn't share the cookie.

So, I can never add the reference since the dialog doesn't give me a way to login.

I've looked all over for a way to login in order to add the reference -- no luck.

Any ideas.

pghcpa
John Saunders