How do I use custom basic authentication with SignalR (.NET client)? - asp.net-mvc-4

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

Related

Authenticate with Kerberos in .NET Web API

I need to implement solution Desktop Client + Application server (Web Service) in .NET.
The Client shall Authenticate against Active Directory (Kerberos Single Sign On) and forward its verified Active Directory identity to Web Service (NET Web API or WCF).
Web-service should verify that the Client is signed against Active Directory. Both computers (Client and server) are running in one AD domain.
I suppose that this can be implemented using WCF (see code here), but today NET Web API is preferred over Windows Communication Foundation. It is possible to implement it in ASP Web API as well?
Similar question not answered is here.
Yes, it is possible. The answer is here: https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/integrated-windows-authentication
The API can use Windows authentication. The authentication is handled by IIS, as long as you have your web.config setup right, as described in that article.
From your application, you just need to tell it to pass the Windows credentials by using the UseDefaultCredentials property:
HttpClientHandler handler = new HttpClientHandler() {
UseDefaultCredentials = true
};
HttpClient client = new HttpClient(handler);

HttpRequestMessage with Windows Authentication

I'm trying to do some integration testing on an ASP.Net Core app with Windows Authentication enabled. For controller methods with the [Authorize] attribute I need to send through the current windows identity in the request.
There is lots of information on how to do this using the old HttpWebRequest method, but I can find no information on doing this through HttpRequestMessage. Presumably I have to encode and send through the current user in the authentication header? Can anyone help?
Asp.Net Core does not do impersonation for you. You need to call WindowsIdentity.Impersonate (https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx) to apply the given identity to the current thread. Then you set up HttpClient with UseDefaultCredentials: How to get HttpClient to pass credentials along with the request?

Is delegation required to pass credentials between applications on the SAME server?

I have a Web API application and an MVC4 client application on the same web server. They are both configured for Windows Authentication. The client application has impersonation enabled.
When I run the client in Visual Studio, it successfully passes my windows credentials to the Web API.
When I hit the client on the web server, the Web API receives "NT AUTHORITY\NETWORK SERVICE" which I guess is coming from the application pool the client app is running in.
Client passes credentials as follows:
HttpClientHandler handler = new HttpClientHandler()
{
PreAuthenticate = true,
UseDefaultCredentials = true
};
HttpClient client = new HttpClient(handler);
So my question is...do I need delegation here?
The web server is not configured for this in Active Directory - but I thought as the applications are on the same server, that impersonation would be sufficient. I would turn delegation on but I need a system admin to do that - and have all sorts of hoops to jump through - so want to be sure that's what I need.
OK, in short, no - delegation was not required.
It turned out to be an impersonation issue. From what I'd read it sounded like that was what should be required since the applications are on the same server, but even though I thought I had configured it correctly, I was missing a crucial part. I needed to change two settings in aspnet.config:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
More details here:
https://stackoverflow.com/a/10311823/1230905

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.

Empty HttpContext when calling WCF webservice

I recently wrote a webservice to be used with Silverlight which uses the ASP.net membership and roles.
To validate the client in the service I look at the HTTPContext.Current.User (Which works when the service is called from Silverlight)
However, I've been trying to call the same service from an asp.net postback. But when I step-thru to the service the HTTPContext.Current has an emplty string for the username.
I'm guessing there is something that I'm not doing in the web.config file which is causing the httpContext to not be sent through the proxy to my service?
Any ideas would be appreciated. I need to be able to validate the client somehow using asp.net membership and roles and have it work from both an asp.net client and a silverlight client.
I have solved it!
Looks like by default the Silverlight application was sending all the browsers cookies to the service. One of these cookies is the ".ASPXAUTH" cookie to authenticate against the membership and roles.
The asp.net application however was not sending the cookies to the service. To send the authorisation cookie I used the following code before calling my webservice method.
using (OperationContextScope scope = new OperationContextScope(ws.InnerChannel))
{
HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
HttpCookieCollection cc = Page.Request.Cookies;
if (Request.Cookies[".ASPXAUTH"] != null)
{
HttpCookie aCookie = Request.Cookies[".ASPXAUTH"];
String authcookieValue = Server.HtmlEncode(aCookie.Value);
httpRequest.Headers.Add("Cookie: " + ".ASPXAUTH=" + authcookieValue);
}
// Webservice call goes here
}
Instead of HTTPContext try ServiceSecurityContext.Current.PrimaryIdentity
Not sure how it is working from Silverlight but not ASP.Net, but for starters here is a good blog post on how to setup WCF to work with ASP.Net membership providers. There are quite a few steps so this could be pretty easy to miss a setting.
Once you get that working correctly then I imagine both should work correctly.
I think it may be because my wcf service is in my silverlight.web project, and perhaps they are more friendly when it comes to sharing.
I may need to read up more on wcf and create a greater seperation of concerns by setting up a seperate webservice project?
Update:
Ok I've taken a look at the HTTP Post request using Fiddler
Looks like the Silverlight App is sending a 'State' with an authorization cookie and my asp.net app isn't.
Looks like I need to send the state + my authorization cookie when I call the service. I may need to formulate a new question soon...