I am porting a library to a PCL and have to find a solution for managing HTTP request credentials. I took away concrete credentials classes like CredentialCache (that is not portable) and is now only using ICredentials, so client applications may create proper credentials and just send an interface reference.
However one thing still needs to be resolved. On some platforms HttpWebRequest has a neat PreAuthenticate property that takes care of initial handshaking. Without it the client needs to catch and repsponds to 401 responses. But PreAuthenticate is not a part of most of PCL profiles, and I wonder if there is any resolution to that or the client will need to implement replacement logic itself (which is silly since this is a standard piece of code).
Thanks in advance
You will need to write the code to handle this yourself. An API will only be portable if it is available on all of the platforms you target. In this case PreAuthenticate was a new API in .NET 4.5 and Windows Store apps, so it won't be available in a Portable Class Library if you are targeting any other platforms (ie .NET 4, Silverlight, or Windows Phone).
I'm having the same problem. I tried to set Credentials to a single NetworkCredental(user, pass), but it doesn't work in WinRT, although it works in Windoes Phone. So far the only way to make it work in WinRT is to create the CredentialCache by reflection.
var credCacheType = Type.GetType("System.Net.CredentialCache, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
var credCache = credCacheType.GetConstructor(new Type[0]).Invoke(new object[0]);
var addMethod = credCacheType.GetMethod("Add", new Type[] { typeof(Uri), typeof(string), typeof(NetworkCredential) });
addMethod.Invoke(credCache, new object[] { new Uri(_server), "Digest", Credential });
request.Credentials = (ICredentials)credCache;
PreAuthenticate can be set using HttpClienHandler that HttpClient accepts as a parameter constructor, e.g.:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
HttpClient client = new HttpClient(handler);
Related
So I am currently working on making SOAP API request to a service with WCF generated code "Client object", I am wondering how to set the Cookie header to the request?
In general, we add the custom HTTP header by using HttpRequestMessageProperty. Please refer to the below code.
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
try
{
using (OperationContextScope ocs=new OperationContextScope(client.InnerChannel))
{
var requestProp = new HttpRequestMessageProperty();
requestProp.Headers["myhttpheader"] = "Boom";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProp;
var result = client.SayHelloAsync();
Console.WriteLine(result.Result);
}
Result.
WebOperationContext is a convenience wrapper around the OperationContext. At present, it hasn’t been implemented yet in the Aspnet Core.
https://github.com/dotnet/wcf/issues/2686
Feel free to let me know if there is anything I can help with.
I have a Java application that uses the Jersey implementation of JAX-RS 2.0 and I want to enable gzip compression on the client side. The server has it enabled and I have verified that by looking in Chrome at the "Size/Content" in the Developer Tools for the specific URL the client is using.
I see a lot of information and documentation floating around the web about setting the HTTP Headers with filters and decoding response bodies with interceptors and I cannot decipher what I actually need to code in the client.
I have this code:
private synchronized void initialize() {
Client client = ClientBuilder.newClient();
client.register(new HttpBasicAuthFilter(username, password));
WebTarget targetBase = client.target(getBaseUrl());
...
}
What should I add to enable compression?
managed to do it with:
private synchronized void initialize() {
Client client = ClientBuilder.newClient();
client.register(new HttpBasicAuthFilter(username, password));
client.register(GZipEncoder.class);
client.register(EncodingFilter.class);
WebTarget targetBase = client.target(getBaseUrl());
...
}
Pretty much the same as #Jason, but EncodingFilter detects the GzipEncoder for me.
In my example (with JAX RS 2.x) and Jersey where multipart is being used, none of the above worked but this did:
Client client = ClientBuilder.newBuilder()
.register(EncodingFilter.class)
.register(GZipEncoder.class)
.property(ClientProperties.USE_ENCODING, "gzip")
.register(MultiPartFeature.class)
.register(LoggingFilter.class)
.build();
Essentially same as the above answers but had to add that one property for "gzip".
Modify to look like:
private synchronized void initialize() {
Client client = ClientBuilder.newClient();
client.register(new HttpBasicAuthFilter(username, password));
client.register(GZipEncoder.class);
WebTarget targetBase = client.target(getBaseUrl());
...
// new lines here:
Invocation.Builder request = targetBase.request(MEDIA_TYPE);
request.header(HttpHeaders.ACCEPT_ENCODING, "gzip");
...
}
In this example, there are some fields and methods being referenced that I don't include in the example (such as MEDIA_TYPE), you'll have to figure those out yourself. Should be pretty straight forward.
I verified this worked by analyzing the response headers and monitoring the application network usage. I got a 10:1 compression ratio according to the network usage checks I did. That seems about right, yay!
Instead of registering EncodingFilter and GZipEncoder individually you can use EncodingFeature directly. With Jersey 2.32 I had problems with incomplete injections and resulting NullPointerExceptions otherwise.
Client client = ClientBuilder.newClient();
client.register(new EncodingFeature("gzip", GZipEncoder.class));
client.register(new HttpBasicAuthFilter(username, password));
WebTarget targetBase = client.target(getBaseUrl());
Note the difference between setting the useEncoding parameter
client.register(new EncodingFeature("gzip", GZipEncoder.class));
or not
client.register(new EncodingFeature(GZipEncoder.class));
is if the initial request by the client is already gzip encoded or if it merely indicates to the server, that it will understand a compressed reply.
I use this simple way to attach username and password to the SOAP request header. This works fine inside Java boundaries, but I want to be able to call it with my WCF client. How do I do this?
I've tried the following code, but it does not include the credentials in the header:
wsClient.ClientCredentials.UserName.UserName = "Hello";
wsClient.ClientCredentials.UserName.Password = "World";
Thanks in advance!
That is quite awful non-standardized way. It uses custom HTTP Headers so you cannot expect that built in WCF mechanism will magically support such approach. How should WCF know that you want to add custom non-standard HTTP header to HTTP request (not SOAP header)?
Use this:
var proxy = new YourServiceClient();
using (var scope = new OperationContextScope(proxy.InnerChannel))
{
var prop = new HttpRequestMessageProperty();
prop.Headers.Add("UserName", "Hello");
prop.Headers.Add("Password", "World");
OperationContext context = OperationContext.Current;
context.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = prop;
proxy.CallYourOperation();
}
I would like to consume a CXF web-service from a .net c# client. We are currently working with java-to-java requests and we protect SOAP envelopes through ws-security (WSS4J library).
My question is: how can I implement a C# WS-client which produces the same SOAP requests as the following client-side java code?
//doc is the original SOAP envelope to process with WSS4J
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
//add username token with password digest
WSSecUsernameToken usrNameTok = new WSSecUsernameToken();
usrNameTok.setPasswordType(WSConstants.PASSWORD_DIGEST);
usrNameTok.setUserInfo("guest",psw_guest);
usrNameTok.prepare(doc);
usrNameTok.appendToHeader(secHeader);
//sign the envelope body with client key
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo("clientx509v1", psw_clientx509v1);
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
Document signedDoc = null;
sign.prepare(doc, sigCrypto, secHeader);
signedDoc = sign.build(doc, sigCrypto, secHeader);
//encrypt envelope body with server public key
WSSecEncrypt encrypt = new WSSecEncrypt();
encrypt.setUserInfo("serverx509v1");
// build the encrypted SOAP part
String out = null;
Document encryptedDoc = encrypt.build(signedDoc, encCrypto, secHeader);
return encryptedDoc;
Does anybody know where I could find a microsoft how-to or a .net working example?
================================ EDIT ====================================
Thank you Ladislav! I applied your suggestions and I came up with something like:
X509Certificate2 client_pk, server_cert;
client_pk = new X509Certificate2(#"C:\x509\clientKey.pem", "blablabla");
server_cert = new X509Certificate2(#"C:\x509\server-cert.pfx", "blablabla");
// Create the binding.
System.ServiceModel.WSHttpBinding myBinding = new WSHttpBinding();
myBinding.TextEncoding = ASCIIEncoding.UTF8;
myBinding.MessageEncoding = WSMessageEncoding.Text;
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128;
// Disable credential negotiation and the establishment of
// a security context.
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
// Create the endpoint address.
EndpointAddress ea =
new EndpointAddress(new Uri("http://bla.bla.bla"),
EndpointIdentity.CreateDnsIdentity("issuer"));
// configure the username credentials on the channel factory
UsernameClientCredentials credentials = new UsernameClientCredentials(new
UsernameInfo("superadmin", "secret"));
// Create the client.
PersistenceClient client = new PersistenceClient(myBinding, ea);
client.Endpoint.Contract.ProtectionLevel =
System.Net.Security.ProtectionLevel.EncryptAndSign;
// replace ClientCredentials with UsernameClientCredentials
client.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.Endpoint.Behaviors.Add(credentials);
// Specify a certificate to use for authenticating the client.
client.ClientCredentials.ClientCertificate.Certificate = client_pk;
// Specify a default certificate for the service.
client.ClientCredentials.ServiceCertificate.DefaultCertificate = server_cert;
// Begin using the client.
client.Open();
clientProxyNetwork[] response = client.GetAllNetwork();
As a result I get (server-side) the following CXF exception:
java.security.SignatureException: Signature does not match.
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:421)
at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate (PKIXMasterCertPathValidator.java:117)
Therefore it seems a key jks->pem conversion problem... Or am I am missing something in the client-code above?
Well, in the end the solution is to encrypt and sign the whole username token. As for the interoperability, the ws addressing must be activated in cxf and a custom binding in c# is needed. The custom binding that did the trick is basically
AsymmetricSecurityBindingElement abe =
(AsymmetricSecurityBindingElement)SecurityBindingElement.
CreateMutualCertificateBindingElement(MessageSecurityVersion.
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
Wcf signs each ws addressing element, therefore the same must be done server side.
This is usually pretty big problem because WCF does not support UserNameToken Profile with Digested password. I needed it few months ago and we had to implement our own custom binding but that code is not ready for publishing. Fortunatelly this blog article describes other implementation and contains sample code with new UserNameClientCredentials class supporting digested password.
Btw. same security configuration should be possible with older API called WSE 3.0. It was replaced by WCF but still some WS-* stack configuration are much simpler with that API and old ASMX services.
While trying to build a client-server WCF application in Mono we ran into some issues.
Reducing it to just a bare example we found that the service only accepts one client at a time. If another client attempts to connect, it hangs until the first one disconnects.
Simply changing to BasicHttpBinding fixes it but we need NetTcpBinding for duplex communication. Also the problem does not appear if compiled under MS .NET.
EDIT: I doubt (and hope not) that Mono doesn't support what I'm trying to do. Mono code usually throws NotImplementedExceptions in such cases as far as I noticed. I am using Mono v2.6.4
This is how the service is opened in our basic scenario:
public static void Main (string[] args)
{
var binding = new NetTcpBinding ();
binding.Security.Mode = SecurityMode.None;
var address = new Uri ("net.tcp://localhost:8080");
var host = new ServiceHost (typeof(Hello));
host.AddServiceEndpoint (typeof(IHello), binding, address);
ServiceThrottlingBehavior behavior = new ServiceThrottlingBehavior ()
{
MaxConcurrentCalls = 100,
MaxConcurrentSessions = 100,
MaxConcurrentInstances = 100
};
host.Description.Behaviors.Add (behavior);
host.Open ();
Console.ReadLine ();
host.Close ();
}
The client channel is obtained like this:
var binding = new NetTcpBinding ();
binding.Security.Mode = SecurityMode.None;
var address = new EndpointAddress ("net.tcp://localhost:8080/");
var client = new ChannelFactory<IHello> (binding, address).CreateChannel ();
As far as I know this is a Simplex connection, isn't it?
The contract is simply:
[ServiceContract]
public interface IHello
{
[OperationContract]
string Greet (string name);
}
Service implementation has no ServiceModel tags or attributes.
I'll update with details as required.
I've played around with this a bit, and it definitely looks like a Mono bug.
I'm porting a WCF application to run in Mono at the moment. I had played with some NetTcpBinding stuff, but I hadn't tried this scenario (multiple connections to a Mono-hosted service host). However now I try it out, I'm able to reproduce - both in 2.6 and the latest daily package.
It does work in .NET, however. Any difference in behavior between Mono and .NET is classed as a bug. You should log it on Bugzilla with a test case, I would also post in the Mono newslist.
Good luck.
Definately a bug. I'm wondering if there was a version it was working correctly...
I've posted it at Novell Bugzilla, if you are interested in its progress.