0

I have an ASP.NET MVC WebApplication, hosted in server-frontend, which is client of a WCF application hosted in server-wcf, both in the same network/domain. Both servers are Windows Server 2012 running IIS 8.

I enabled Windows Authentication and disabled Anonymous in both projects (csproj).

If I call this.User.Identity.Name inside a Controller in my WebApp, it gives correctly the user logged in (e.g mydomain\alisson).

Both projects have been configured with Windows Authentication in IIS, and WebApp particularly has ASP.NET impersonation enabled. Both have Forms, Basic and Anonymous disabled. Both pools use NetworkService.

My WCF project is responsible for connecting to SQL Server, and it works properly, since I gave permission to the machine itself in my database (e.g server-wcf$), and this is exactly what I expect.

Now I'm trying to call a WCF method from my WebApp like so:

var binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = 10485760;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

var endPoint = new EndpointAddress(address);
var channelFactory = new ChannelFactory<IMyService>(binding, endPoint);
var client = channelFactory.CreateChannel();
client.GetUser();

and this GetUser() in my WCF Service is declared as follow:

public GetUser()
{
    return ServiceSecurityContext.Current.WindowsIdentity.Name;
}

Which returns domain\server-frontend instead of domain\alisson.

I want to make it get the user in WCF, but keep the way WCF connects to database as itself (server-wcf).

My WebApp web.config has the following:

<identity impersonate="true" />
<authentication mode="Windows" />
<authorization>
  <deny users="?" />
</authorization>

Whereas the WCF has the following inside web.config serviceModel:

<bindings>
  <basicHttpBinding>
    <binding name="AutomatizacaoBinding" maxReceivedMessageSize="10485760">
      <security mode="TransportCredentialOnly">
        <transport clientCredentialType="Windows" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<protocolMapping>
  <add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

Is it possible to achieve this?

Alisson Reinaldo Silva
  • 10,009
  • 5
  • 65
  • 83

2 Answers2

0

You should use OperationContext instead:

return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;

Note: if integrated security is not enabled, ServiceSecurityContext will be null.

Hope it helps.

Ricardo Pontual
  • 3,749
  • 3
  • 28
  • 43
  • This got the same as `ServiceSecurityContext.Current.WindowsIdentity.Name`. I wanted to get the same as calling `this.User.Identity.Name` in caller WebApp Controller, which returns `domain\alisson`. – Alisson Reinaldo Silva Aug 25 '16 at 13:00
  • Actually, this returns **domain\alisson** only if I run the WebApp locally in VS with IIS Express. When I publish it to my `server-frontend`, then it gets **domain\server-frontend** as identity name. – Alisson Reinaldo Silva Aug 25 '16 at 13:07
  • I have a similar service that works fine with OperationContext, but due to your comment, I could notice that there is a small difference between our configuration files, my set "security mode" as "Transport", instead of "TransportCredentialOnly", maybe this can do some difference – Ricardo Pontual Aug 25 '16 at 13:11
0

It is very possible but not that easy.

You might just be able to get the name of the caller, but not reconstruct their Identity. Since forever, you must use Negotiate/Kerberos Security for more than one jump between machines when reconstructing identities.

Basically really boring as there is not always an Active Directory server available for test (I must create test accounts in production environment at my place). Neg/Kerberos is old tech that I use most of the time even though there's a few caveats with SPN's and CNAME's (don't use CNAMES, use A-records).

Another alternative is to use newer tech like ADFS which passes around some kind of huge claims cookie called federation, but it all depends on what your production environment looks like.

Once this is setup however, one or the other, If you want WCF to keep doing calls as itself, just keep your code and dont setup any implicit impersonation. You can still obtain the identity if you poke around in the wcf request in most cases.

If you want to actually impersonate then, open an impersonation scope. Just repeating closer to the example, the following will never work unless you setup Kerberos or adfs first.

using System.Security.Principal;
using(WindowsIdentity.GetCurrent().Impersonate())
{
     //your code goes here, executed as domain\alisson
}
Community
  • 1
  • 1
Tewr
  • 3,713
  • 1
  • 29
  • 43
  • I thought ADFS was to make different domains to exchange/share credentials, in my case both servers are in same domain, I never thought this could help somehow. I'm gonna take a read on these approaches and give some feedback. – Alisson Reinaldo Silva Aug 25 '16 at 13:09
  • I know that adfs can solve two jump problem, in therory simpler than kerberos, but I've never used it myself in production code so I wouldn't know. Like you say, if you are on several domains, adfs is preferable. kerberos is the go-to method for passing on a windows identity, it's old and proven tech. ntlm for example, only works for one machine jump. Browser to server counts as one jump, so with ntlm you're stuck on the web server. – Tewr Aug 26 '16 at 18:52