WCF client authentication on server side - wcf

I have such structure on my client.
WindowsIdentity wi = WindowsIdentity.GetCurrent();
IntPtr token = wi.Token;
Next step is send authentication token to server through WCF and impersonate user there.
api.SendToken(token);
...
...
...
But as soon I receive token on server side and trying to build WindowsIdentity it throws me an error:
WindowsIdentity newId = new WindowsIdentity(token);
Invalid token for impersonation - it cannot be duplicated.
Could you guys please help me to figure out what I am doing wrong and share your ideas how do I pass token from client to server.
Thanks!

WCF already has built-in plumbing to support Windows impersonation. Is there is a reason you're trying to roll your own?
UPDATE to avoid link-only answers (ahhh, errors of my youth...)
Here are the basic steps needed to configure the built in WCF impersonation
Only some bindings support Windows authentication. The WSHttpBinding is the most common one to support it but others may support it too.
On the service contract, use the OperationBehavior attribute on the method that requires impersonation:
[OperationBehavior(Impersonation=ImpersonationOption.Required)]
public string SomeMethod(string aParameter) { ... }
For the client, it is simplest to create a custom class inheriting from the ClientBase class. All service reference types inherit from this class. Here is an example of the client code:
var client = new SomeClientBaseDerivedType("TheServiceEndpoint");
client.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Impersonation;

Related

How do I use custom basic authentication with SignalR (.NET client)?

There's lots of info on how to do Forms authentication or Windows authentication with SignalR. I am interested in using my own authentication DB. I use a .NET client because the connecting agent is a service, not a web browser with a human behind it. I'd ideally like my client code use:
hubConnection.Credentials = new NetworkCredential(userName, password);
And my server code to use [Authorize] on the hubs and to have Context.User available to me. All comms are over https so I don't care about plain text.
I've read the asp.net basic authentication guide which shows how to override the authentication mechanism using an IHttpModule. However, the 'Authorization' header never seems to get set in the requests coming from the .NET SignalR client when I breakpoint the code in the HttpModule.
All I want to do is trivially pass a username and a password from the client and code up how authentication happens on the server. Is that so hard? No magic. No Active Directory. Just authentication by me.
My current, working, approach is to set custom headers which are interpreted at the SignalR level (using a custom AuthorizeAttribute), however apparently 'the right way to do it' is not to do authentication at the authorisation level and instead have the webserver do that before any SignalR stuff happens.
Can anyone please describe a good procedure for full, but dirt-simple, custom authentication?
Client
var connection = new Connection(url + "/echo");
connection.Credentials = new NetworkCredential("user", "password");
await connection.Start();
Server
app.Map("/basicauth", map =>
{
map.UseBasicAuthentication(new BasicAuthenticationProvider());
map.MapSignalR<AuthenticatedEchoConnection>("/echo");
map.MapSignalR();
});
NuGet Package required: Microsoft.Owin.Security.Basic
You can see a full sample here

Restricting WCF TCP endpoint to Administrators

How do I restrict access of a remotely-accessible WCF endpoint to a local/domain administrator?
Edit: After adding [PrincipalPermission(SecurityAction.Demand, Name = "AdminUser")] to my WCF channel method implementation, trying to call the service method from my client throws a SecurityAccessDeniedException, which is progress.
How do I let Windows prompt the user for new user details (or a security token) so I can reinitiate the WCF connection as the correct user?
You can do this with the PrincipalPermissionAttribute added to the methods declared in your WCF service.
See this link: How to: Restrict Access with the PrincipalPermissionAttribute Class

How to write code that calls a WCF service and falls back from Kerberos to NTLM if needed?

I need to call a WCF service programmatically. The service may be hosted with either NTLM or Kerberos authentication and needs to work under either. That is, if connecting to the service via Kerberos fails, then it should fall back to NTLM.
Here's the code I'm using for Kerberos auth (if relevant, the service is hosted in SharePoint 2010 and is being called from a web part):
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
{
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
url = url.EndsWith("/") ? url + SiteMembershipAddress : url + "/" + SiteMembershipAddress;
var endpoint = new EndpointAddress(url);
var proxy = new SiteMembershipSvc.SiteMembershipServiceClient(binding, endpoint);
proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
return proxy;
}
Calling a method on the proxy when run in an NTLM environment gives the error:
The HTTP request is unauthorized with
client authentication scheme
'Negotiate'. The authentication header
received from the server was 'NTLM'.
Note: The URL may be in another web application on another server. I can't check what authentication the web part's web app runs under and assume it is the same as where the WCF service is hosted.
How can I (automatically or manually) ensure authentication falls back from Kerberos back to NTLM on failure?
Update:
As mentioned, the authentication error occurs when a web method is called. However I don't want to wait that long as there are several web methods in the service called from several places. I'd like to test the authentication at the point where the proxy is configured (in the code snippet above).
I've tried using proxy.Open() but that doesn't seem to cause the failure.
This is a bit off a curveball, but why is it falling back to NTLM. I've had significant difficulty with security in active directory and WCF all related to service principal names (SPNs).
Kerberos will fail if you are running the service as something other than Network Service unless you have an SPN declared in the domain for your service. To set the SPN you need the windows server administrative kit, which has the command setspn.
setspn -A HTTP\machinename domain\service_account
This will then allow Kerberos to share client credentials to your service within the domain.
Please do some reading, as you could break kerberos for any other services running on the same box depending on your setup.
(I recognize the original post is very old.)
Can you use something other than BasicHttpBinding (like WsHttpBinding)? According to this article, BasicHttpBinding is the one exception to the binding objects, in that it does not automatically negotiate. This is why allowNTLM has no effect.
I had the same error msg which I posted about here and solved it by creating a dynamic endpoint like so:
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
{
//create endpoint
EndpointAddress ep = new EndpointAddress(new Uri(string), EndpointIdentity.CreateUpnIdentity("MyDomain\WCFRunAsUser"));
//create proxy with new endpoint
SiteMembershipSvc.SiteMembershipServiceClient service = new SiteMembershipSvc.SiteMembershipServiceClient("wsHttp", ep);
//allow client to impersonate user
service.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
//return our shiny new service
return service;
}
I was running the WCF service as a specific Active Directory user rather than the default NETWORK_SERVICE.
Try setting:
proxy.ClientCredentials.Windows.AllowNTLM = true;
According to this, AllowNTLM is now obsolete - i'm not sure what the correct alternative is.
I guess you are using the full dns name of the server as the address of the service. Try using the NETBIOS name or the IP address. That should force it to use NTLM.
If you know what protocol the server is using you can configure your app to use either the full name or the ip.
Hope that works for you.
If your Kerberos fail it will automatically default to NTLM, you don't have to do anything special.
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part1.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part2.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part3.html
I haven't been able to find a way to do this automatically. Instead I've added UI to the application where the type of authentication must be chosen.

Programmatically creating a client proxy for a WIF-secured WCF Service

Here's what I've done so far:
1) Created an ASP.NET MVC relying party application and secured it with ADFS v2.0. This works.
2) Created a WCF Service using the Claims-Aware service template for an ASP.NET website. I've turned ASP.NET compatibility for the service ON because the service wouldn't activate otherwise. I've moved the interface for said service to a 'SharedContracts' assembly.
3) Set up the WCF service as a relying party using the "Add STS" reference, also pointing at my ADFS server.
4) Configured the ADFS server to include the WCF service as a relying party and issue it LDAP claims.
What I want to do now is talk to the service using ActAs. In other words, when someone hits HomeController.Index() from the ASP.NET MVC site with a token full of claims (remember the MVC site is a relying party), I want this method to programmatically create a client proxy and invoke the single service method I have on the WCF service (a method called "HelloClaim", which is nearly identical to the stock method that comes with the claims-aware service template).
Here's the code I've got so far:
[ValidateInput(false)]
public ActionResult Index()
{
SecurityToken callerToken = null;
IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
if (claimsPrincipal != null)
{
foreach (IClaimsIdentity claimsIdentity in claimsPrincipal.Identities)
{
if (claimsIdentity.BootstrapToken is SamlSecurityToken)
{
callerToken = claimsIdentity.BootstrapToken;
break;
}
}
string baseAddress = "http://khoffman2/SecureServices/Service.svc";
ChannelFactory<IHelloClaim> factory = new ChannelFactory<IHelloClaim>(new WebHttpBinding(), new EndpointAddress(baseAddress));
factory.ConfigureChannelFactory<IHelloClaim>();
IHelloClaim hello = factory.CreateChannelActingAs<IHelloClaim>(callerToken);
string result = hello.HelloClaim();
ViewData["Message"] = "Welcome to ASP.NET MVC!";
}
return View();
}
When I attempt to invoke the method, I get the following error message:
Manual addressing is enabled on this factory, so all messages sent must be pre-addressed.
I'm pretty sure I'm just not doing enough to configure the binding and the endpoint programmatically. If any of you have done this before or you know how to do it, I would love to be able to get this working.
Bottom line is I'm just making use of the basic identity delegation scenario - the only difference is I'm not using generated client proxies.
Take a look at this guide over at TechNet as it has a walkthrough on how to setup the scenario you've described:
http://technet.microsoft.com/en-us/library/adfs2-identity-delegation-step-by-step-guide(WS.10).aspx
In their example, I believe they are using standard WebForms, but in the case of MVC you can put the ChannelFactory initialization within the Global.asax within the Application_Start.

WCF Authentication using basicHttpBinding and custom UserNamePasswordValidator

My first question is, is it even possible to use a custom UserNamePasswordValidor with basicHttpBinding?
I have a asp.net web site using Forms authentication and a custom membership provider. I realise that I could use the built in System.Web.ApplicationServices.AuthenticationService to authenticate my client (a WPF app) but I don't want two service calls (one for auth service, one for logic).
So it seems that a custom UserNamePasswordValidator would be perfect for the job. In my client I can then have:
var service = new MyServiceClient();
service.ClientCredentials.UserName.UserName = "username";
service.ClientCredentials.UserName.Password = "password";
MessageBox.Show(service.SayHello());
I've seen this working with wsHttpBinding but ideally would like to test without an SSL certificate.
Alternatively, is it possible to make use of the AuthenticationService from within another WCF service?
To clarify what I mean above regarding authentication service, I don't want to have 2 service calls i.e:
if (authService.Login("username", "password"))
// then call my service
I know this a minor thing but the external developer of the client app is expecting just one service that takes the credentials and returns the required data.
Thanks,
Ben
check ClearUserName binding: http://webservices20.blogspot.com/2008/11/introducing-wcf-clearusernamebinding.html It should solve your problem.
I use UserNamePasswordValidator over basicHttpBinding on a couple of my current projects. It works great; however, like Brett Robi mentioned in the comments, you need to have your Security mode set to Message or TransportWithMessageCredentials in order for the validator to be called. These security modes require SSL through.
So in short - Yes you can over basicHttpBinding; however, only with SSL. Removing the security mode and SSL removes the credential validations from being called.