Minimal client which supports message-level security over the channel interface - wcf

I'm trying to build a minimal client for a WCF service, using the WSHttpBinding with SecurityMode: Message over a direct channel interface.
My current code is very simple:
EndpointIdentity i = EndpointIdentity.CreateX509CertificateIdentity(clientCertificate);
EndpointAddress a = new EndpointAddress(new Uri("http://myServerUrl"), i);
WSHttpBinding b= new WSHttpBinding(SecurityMode.Message);
ChannelFactory<IRequestChannel> channelFactory = new ChannelFactory<IRequestChannel>(b, a);
channelFactory.Open();
IRequestChannel channel = channelFactory.CreateChannel();
channel.Open();
Message response = channel.Request(requestMessage);
The clientCertificate gets loaded properly.
However, afterwards, I'm unsure if I call every function the correct way.
The Fact is: The last line of the code snippet throws a MessageSecurityException with the content
Client cannot determine the Service Principal Name based on the identity in the target address 'http://myServerUrl' for the purpose of SspiNegotiation/Kerberos. The target address identity must be a UPN identity (like acmedomain\alice) or SPN identity (like host/bobs-machine).
What could be the reason for this problem?

The default ClientCredentialType seems to be Windows and that's why you're getting an error related to Sspi/Kerberos. You need to specify "Certificate" as credential type and also set the actual certificate in the client credentials container. Check out the Client section of this link for more details:
http://msdn.microsoft.com/en-us/library/ms733098.aspx

Related

How to pass parameter and get data from wcf service

I got this error:
There was no endpoint listening at http://vkalra.in/WCF_SERVICE/RestServiceImpl.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details
InnerException-The remote server returned an error: (404) Not Found.
This is my code:
Binding binding = new BasicHttpBinding();
// Create endpointAddress of the Service
EndpointAddress endpointAddress = new EndpointAddress("http://vkalra.in/WCF_SERVICE/RestServiceImpl.svc");
ServiceReference1.Leave_Details emp = new ServiceReference1.Leave_Details();
emp.empid = items.empid;
emp.fromdate = "01-04-2019";
emp.todate = "04-06-2019";
emp.tabt = "1";
emp.jdis = "0";
try
{
ServiceReference1.RestServiceImplClient service = new ServiceReference1.RestServiceImplClient(binding, endpointAddress);
string levbal = service.Leave_Calculation(emp);
}
catch(Exception ex)
{
}
If we want to consume the WCF service created by WebHttpBinding(this type of the WCF service is also called Restful service) by adding service reference, we need to do something special. Generally speaking, if we want to call Restful service (such as the service created by Asp.net WebAPI), we could construct a http request, Get or Post with a request body, then send to the specified service address.
https://code-maze.com/different-ways-consume-restful-api-csharp/
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
This also applies to WCF service created by WebHttpBinding.
consuming a WCF service using simple HttpClient class
But if we want to consume the WCF restful service by adding the service reference, we are supposed to maintain the consistency of binding between the client and server. we should add [WebGet]/[WebInvoke] to the auto-generated method of the service interface, which comes in the form of adding service reference, located in Reference.cs file.
One more thing we need do is add Webhttpbehavior (endpoint behavior) to the client service endpoint. This client configuration comes in the form with adding service reference, located in the System.ServiceModel section of the app.config/web.config.
The remote server returned an unexpected response: (400) Bad Request. wcf
Feel free to let me know if there is anything I can help with.

How to prevent WCF proxy from following redirect?

I'm using basicHttpBinding for my WCF service and have a message inspector that sets response code to Redirect under certain circumstances. I find that the WCF proxy (generated by svcutil) automatically tries to follow the redirect. How do I prevent this from happening?
Thanks,
Priya
Can you reference the service contract assembly from your client application? If so you can get rid of the generated service reference and just spin up a proxy at runtime using ChannelFactory.
For example:
// Create service proxy on the fly
var factory = new ChannelFactory<IMyServiceContract>("NameOfMyClientEndpointInConfigFile");
var proxy = factory.CreateChannel();
// Create data contract
var requestDataContract = new MyRequestType();
// Call service operation.
MyResponseType responseDataContract = proxy.MyServiceOperation(requestDataContract);
In the above example, IMyServiceContract is your service contract, and MyRequestType and MyResponseType are your data contracts, which you can use by referencing the assembly which the service also references (which defines these types).
what have you tried to achieve with redirect ? you will an handle this cases with some message interceptors on client side:
http://msdn.microsoft.com/en-us/library/ms733786(v=vs.90).aspx

WCF client authentication on server side

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;

WCF TCP Transport Security and WIF

My company uses WIF (Windows Identity Foundation) to secure our sevices. Currently we only use WIF over HTTPS. However, we need to secure a TCP endpoint and I'm running into some trouble.
I'm getting following exception:
The '{binding name}'.'http://tempuri.org/' binding for the '{IService}'.
'http://tempuri.org/' contract is configured with an authentication mode that requires
transport level integrity and confidentiality. However the transport cannot provide
integrity and confidentiality.
In order to get WIF into the picture we have to do this inside the service host:
var istp = new IssuedSecurityTokenParameters(_TokenType, _IssuerAddress, _IssuerBinding) // issuer address/binding do not matter for this, but must provide something
{
RequireDerivedKeys = false,
KeyType = System.IdentityModel.Tokens.SecurityKeyType.BearerKey
};
TransportSecurity = new TransportSecurityBindingElement();
TransportSecurity.EndpointSupportingTokenParameters.Signed.Add(istp);
TransportSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
I can't take those lines of code out but I don't know what configuration I'm missing to make this work with TCP. Any help at all would be great.

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.