Can client credentials be read from within service implementation? - c#

I am hosting a soap webservice via an instance iHost of ServiceHost; authentication is configured as
HttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
iHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode
= UserNamePasswordValidationMode.Custom;
iHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator
= new CustomValidator();
The hosting itself works as desired, however I also would like to access the client credentials from within the hosted service itself. Can this be achieved with the current authentication settings or is it impossible?

Found the answer with the help of a coworker. Username can be accessed via OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name; the question can be seen as a duplicate of this question.

Related

How to fix "The HTTP request was forbidden with client authentication scheme 'Anonymous'"

I'm having some issues implementing a client that talks to a WCF service. It's a WCF hosted by another company so I don't have access to its code. I used the Connected Service provider tool in Visual Studio to generate the client code so that I could make requests and everything works fine on my local machine. I am having an issue on our development environment where I receive the following error if I try to make a request with the client:
The HTTP request was forbidden with client authentication scheme 'Anonymous'
I've been looking at the client code (it's a lot of code) which is generated by the Provider tool and I think it may have something to do with the following block of code.
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
return result;
This more linked to firewall rules within corporate network.
I had same issue using non authorized proxy but got resolved secured proxy with ntlm ClientCredentialType
This error typically indicates that the WCF server authenticates the client-side with a certificate. The error will occur when the trust relationship between the server and the client have not been established yet.
In general, we need to provide client credential to be authenticated by the server so that be able to call the service. As for what kind of credentials need to be provided, it depends on the binding information on the server-side.
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Namely, the above errors have indicated that the server authenticates the client with a certificate.
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
About authenticating the client with a certificate, you could refer to the below link for details.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
Feel free to let me know if there is anything I can help with.
Thanks for all the suggestions. This was actually just caused by a firewall rule that was setup within our organisation. Once that was removed the code worked as expected.
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
Security is provided using HTTPS. The service must be configured with SSL certificates. The SOAP message is protected as a whole using HTTPS. The service is authenticated by the client using the service's SSL certificate. The client authentication is controlled through the ClientCredentialType.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpsecuritymode?view=netframework-4.8

WCF self hosted HTTPS with custom UserNamePasswordValidator

I have a WCF service which is running fine.
It is used within an intranet network.
It is a self-hosted service
(no IIS) managed by a simple Windows Form program.
It is used by a
WCF client (WPF C#).
I now need to add security to it and after having read a lot of posts on the internet I'm getting confused as there are many ways of doing.
I need a custom username and password validator (I will have to call another web service to know if user is authorized or not).
I also need secure communication between client and server.
I am currently using basicHttpBinding.
MS recommends the use of NetTcpBinding in my case (https://msdn.microsoft.com/en-us/library/ff648863.aspx#TransportSecurityWCF), but I am not sure if this is or can be secured ?
I think I better use WsHttpBinding to have SSL: do you think that this link provides proper solution to my case ? https://msdn.microsoft.com/en-us/library/ms733775.aspx ?
Thanks for your advices
You can do SSL/Transport encryption with BasicHTTPBinding. That doesn't need to change; you just need to set up the host side with "Transport" security, add some code and a certificate, and you should be able to proceed without changing too much code. I can include a small code sample below, since I did the same thing you're trying to do via a self-hosted service.
BasicHttpBinding b = default(BasicHttpBinding);
if (bUseSSL) {
//check for ssl msg credential bypass
if (bSSLMsgCredentialBypass) {
b = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
} else {
b = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
}
b.TransferMode = TransferMode.Buffered;
b.MaxReceivedMessageSize = int.MaxValue;
b.MessageEncoding = WSMessageEncoding.Text;
b.TextEncoding = System.Text.Encoding.UTF8;
b.BypassProxyOnLocal = false;
//b.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
}
The authentication/authorization can be done, too, without changing what you currently have. You really have two choices:
One is that you create a Login function that get's called when the client first visits the host. You then send some token value back to the client for all subsequent communications.
The other way involves creating that custom authentication check, using the message inspector functionality found in Dispatcher.IDispatchMessageInspector and a public function called AfterReceiveRequest. Within that function, you can examine the UserID and Pwd (from within the HTTP header data) sent from the clients- but you need to implement this on both the client and host sides, otherwise it doesn't work.

Working with WSTrustChannelFactory and web proxy settings

in WSTrustChannelFactory documentation there is a reference to working with proxy:
One common pattern where the OnBehalfOf feature is used is the proxy
pattern where the client cannot access the STS directly but instead
communicates through a proxy gateway
I can't seem to find an example.
In some of my users' computers a proxy is defined for exteral request.
How can I request the token if the STS is behind proxy.
Currently I am getting it as follows:
var rst = new RequestSecurityToken{...}
IWSTrustChannelContract wsTrustChannelContract = factory.CreateChannel();
var token = wsTrustChannelContract.Issue(rst) as GenericXmlSecurityToken;
How can I change it to using the proxy?
Thanks.
OnBehalfOf is for situations where you build the proxy yourself - like the ADFS proxy.
I haven't seen any sample for that either - but it follows the same pattern as ActAs.
It has nothing to do with "regular" web proxies that might be between you and your STS.
But have a look here:
How can I set an HTTP Proxy (WebProxy) on a WCF client-side Service proxy?

How to create a WCF client using digest authentication to third-party system

I have been given a wdsl for an external system (not .Net-based), and I have used svcutil to create a client/proxy for it. The external unit requires digest authentication for me to talk to it, and supports both http and https.
A couple of questions:
There are no certificates involved. Will using https cause problems in that case?
I know I can specify transport level digest authentication like this:
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
However, how do I go about creating the credentials and using them with my binding/proxy?
I can easily find a lot of information online on creating WCF services, but implementation of clients towards non-.Net based services... not so much.
Thanks for any insight!

WCF windows authentication security error

i have some code that tries impersonate the callers windows security settings and then connect to another WCF service on a different machine
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
using (callerWindowsIdentity.Impersonate())
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointAddress endpoint = new EndpointAddress(new Uri("net.tcp://serverName:9990/TestService1"));
ChannelFactory<WCFTest.ConsoleHost.IService1> channel = new ChannelFactory<WCFTest.ConsoleHost.IService1>(binding, endpoint);
WCFTest.ConsoleHost.IService1 service = channel.CreateChannel();
return service.PrintMessage(msg);
}
But I get the error:
"the caller was not authenticated by the service"
System.ServiceModel .... The request for security token could not be satisfied because authentication failed ...
The credentials I am trying to impersonate are valide windows credential for the box the service is on.
Any ideas why?
In order to support your scenario, you need to have an understanding of how Protocol Transition and Constrained Delegation work. You will need to configure both Active Directory and your WCF service endpoint(s) to support this. Note the use of the Service Principal Name (SPN). Take a look at the following link and see if they help you. The article has a sample to demonstrate the complete end-to-end configuration required to make this work.
How To: Impersonate the Original Caller in WCF Calling from a Web Application
Agree with marc_s this is the double-hop problem.
You need to get the windows authentication all the way through, therefore:
The request must be made in the context of a windows users
IIS must be configured to use windows authentication
Web.config must be set up for windows authentication with impersonate = true
The user that your application pool is running as, must be allowed to impersonate a user. This is the usual place where the double-hop problem occurs.
There is a right called "Impersonate a client after authentication"
http://blogs.technet.com/askperf/archive/2007/10/16/wmi-troubleshooting-impersonation-rights.aspx
Impersonation from you service to the next is a tricky issue, known as "double-hop" issue.
I don't have a final answer for that (I typically avoid it by using an explicit service account for the service that needs to call another service).
BUT: you should definitely check out the WCF Security Guidance on CodePlex and search for "Impersonation" - there are quite a few articles there that explain all the ins and outs of impersonating an original caller and why it's tricky.
Marc
If you are sure you have the credentials right on both hops, the next thing that could be causing the issue is the lack of the EndpointDnsIdentity being set on the endpoint.
DnsEndpointIdentity identity = new DnsEndpointIdentity("localhost"); // localhost is default. Change if your service uses a different value in the service's config.
Uri uri = new Uri("net.tcp://serverName:9990/TestService1");
endpoint = new EndpointAddress(uri, identity, new AddressHeaderCollection());

Categories

Resources