Do Jersey client support NTLM proxy - java

I'm trying to make a jersey client call using NTLM proxy? is that possible as i was not able to get any clear information on the same. Did anyone tried before?

Yes it is possible to configure the Jersey Client to connect through a proxy server that requires NTLM authentication.
Here is a simplified code snippet that prepares a suitable ClientConfig that should work with Jersey v2.5+:
final ClientConfig config = new ClientConfig();
config.property(ClientProperties.PROXY_URI, "http://myproxy.com:8000");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final AuthScope ntlmAuthScope =
new AuthScope("myproxy.com", 8000, AuthScope.ANY_REALM, "NTLM");
credentialsProvider.setCredentials(
ntlmAuthScope,
new NTCredentials("user", "password", "hostname", "domain") );
config.property(
ApacheClientProperties.CREDENTIALS_PROVIDER, credentialsProvider);
config.connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newClient(config);
Please note: I am using the Apache HttpClient connector with Jersey Client - you may require slightly different code if you are using another client transport connector.
You may also need to add the following line to your code if you want your POST/PUT requests to be buffered (and therefore repeatable) in response to any 407 authentication challenges that come back from your proxy server:
config.property(ClientProperties.REQUEST_ENTITY_PROCESSING,
RequestEntityProcessing.BUFFERED);

Related

Apache CXF Client proxy settings

I am trying to Develop a Consumer for Soap Service using the tutorial at
http://cxf.apache.org/docs/developing-a-consumer.html
In the section ,"Setting Connection Properties with Contexts" I am looking at the code below
// Set request context property.
java.util.Map<String, Object> requestContext =
((javax.xml.ws.BindingProvider)port).getRequestContext();
requestContext.put(ContextPropertyName, PropertyValue);
// Invoke an operation.
port.SomeOperation();
Can someone tell me if I can set the proxy server settings using the requestContext properties and how ?. My code is running behind a proxy and I need the outgoings SOAP calls to use proxy server settings.
Proxy setting are usually set by using httpconduit object
HelloService hello = new HelloService();
HelloPortType helloPort = cliente.getHelloPort();
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(helloPort);
HTTPConduit http = (HTTPConduit) client.getConduit();
http.getClient().setProxyServer("proxy");
http.getClient().setProxyServerPort(8080);
http.getProxyAuthorization().setUserName("user proxy");
http.getProxyAuthorization().setPassword("password proxy");

CXF client not use Proxy server in a SSL request to retrieve the WSDL

We have a CXF (2.7.X) client (see code below) in a Java 1.6.0_45 application.
The CXF client calls a Soap WS through a proxy server.
Despite all our efforts, that CXF client performs some requests directly to the WS bypassing the proxy.
The only solution for the moment is to force proxy on the JVM options.
But this solution is not acceptable.
Is there a pb in our code ?
I have not found any clue on the internet or on the CXF jira .
// work only if i define proxy on jvm
/*
System.setProperty("http.proxyHost","87.65.43.21");
System.setProperty("http.proxyPort", "808");
System.setProperty("https.proxyHost", "87.65.43.21");
System.setProperty("https.proxyPort", "808");
*/
// initialize ws
URL wsdlLocation = new URL("https://12.34.56.78:8443/mockHelloWorldSoapBinding?WSDL");
QName qName = new QName("http://my.webservice.com", "HelloWorldService");
HelloWorldService helloWorldService = new HelloWorldService(wsdlLocation, qName);
HelloWorld port = helloWorldService.getHelloWorld();
HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(port).getConduit();
// add proxy parameters
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setProxyServer("87.65.43.21");
policy.setProxyServerPort(808);
policy.setAllowChunking(false);
httpConduit.setClient(policy);
// call ws
String response = port.sayHello("world");

HTTP authentication with each HTTP request using Jersey 2 client + ApacheConnectorProvider

I would like to use HTTP authentication with a Jersey 2 client using ApacheConnectorProvider, but I want to set it for each request (not as ClientConfig property). The reason is that I use the client for multiple connections, only some of which require HTTP authentication. I assume it is better to not recreate the Client object each time I want to send an HTTP request.
What I found so far:
1) from https://github.com/jersey/jersey/blob/master/connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/AuthTest.java
CredentialsProvider credentialsProvider = new org.apache.http.impl.client.BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("name", "password")
);
ClientConfig cc = new ClientConfig();
cc.property(ApacheClientProperties.CREDENTIALS_PROVIDER, credentialsProvider).property(ApacheClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, true);
cc.connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newClient(cc);
WebTarget r = client.target(getBaseUri());
r.request().get(String.class);
This would probably work, but as I reuse the same Client for multiple HTTP requests, not all using HTTP authentication, I'd need to recreate a Client object each time I send a request. I do not know if that is an expensive operation, so it could be a solution.
2) from https://jersey.java.net/documentation/latest/client.html#d0e4833
Response response = client.target("http://localhost:8080/rest/homer/contact").request()
.property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_USERNAME, "homer")
.property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_PASSWORD, "p1swd745").get();
This does not seem to work with ApacheConnectorProvider.
What is the right solution to my problem?
Thanks!

Jetty on Heroku: how to tell in code if https was used

I have some servlets running in Jetty, deployed on Heroku, handling POST requests.
Some, but not all, POST requests MUST come over https. Whether or not a request should be forced to be on https depends on the http body of the POST request.
I need to figure out, from inside the servlet, whether the incoming request used https (SSL) or not, so that I can send the appropriate response. However, nothing I have tried seems to work.
I tried the obvious HttpServletRequest.getProtocol() but that apparently returns the same constant whether the protocol was http or https.
I tried HttpServletRequest.isSecure() however that is returning false even though my test request was sent to a url starting with https://
When I call HttpUtils.getRequestURL( HttpServletRequest ).toString(); I get an apparrently reconstructed url that starts with "http://" even though my test request was sent to a url starting with "https://"
According to the post "Enforce HTTPS with Embedded Jetty on Heroku" heroku has some load balancers, and I should get the value of the "x-forwarded-proto" header. That header is blank.
FYI I am using the default SSL endpoint provided by the heroku api -- I am not using their SSL Endpoint extension, because this url is not being loaded in a browser (so I don't need a custom domain in the url).
Can anyone tell me how to tell if HTTPS was used in the incoming request?
I know nothing about Heroku, but if you're programmatically configuring Jetty (as opposed to using the XML configuration), you likely need to add the SecureRequestCustomizer to your HttpConfiguration. It sets the secure flag on the requests, as well as setting the scheme to HTTPS. You can find examples here, but briefly:
final HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecurePort(httpsPort);
final ServerConnector httpConnector = new ServerConnector(server,
new HttpConnectionFactory(httpConfig));
httpConnector.setPort(httpPort);
server.addConnector(httpConnector);
final HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer()); // !!!
final HttpConnectionFactory httpsFactory = new HttpConnectionFactory(httpsConfig);
final SslConnectionFactory sslFactory = new SslConnectionFactory(sslCtx,
httpsFactory.getProtocol());
final ServerConnector httpsConnector = new ServerConnector(server,
sslFactory, httpsFactory);
httpsConnector.setPort(httpsPort);
server.addConnector(httpsConnector);
I too found it rather surprising that this poorly documented step was necessary.

HttpClient 4.1.1 returns 401 when authenticating with NTLM, browsers work fine

I'm trying to use the Apache/Jakarta HttpClient 4.1.1 to connect to an arbitrary web page using the given credentials. To test this, I have a minimal install of IIS 7.5 on my dev machine running where only one authentication mode is active at a time. Basic authentication works fine, but Digest and NTLM return 401 error messages whenever I try to log in. Here is my code:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost/");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("user", "password", "", "localhost"));
if (!new File(System.getenv("windir") + "\\krb5.ini").exists()) {
List<String> authtypes = new ArrayList<String>();
authtypes.add(AuthPolicy.NTLM);
authtypes.add(AuthPolicy.DIGEST);
authtypes.add(AuthPolicy.BASIC);
httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF,
authtypes);
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,
authtypes);
}
localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
HttpResponse response = httpclient.execute(httpget, localContext);
System.out.println("Response code: " + response.getStatusLine());
The one thing I've noticed in Fiddler is that the hashes sent by Firefox versus by HttpClient are different, making me think that maybe IIS 7.5 is expecting stronger hashing than HttpClient provides? Any ideas? It'd be great if I could verify that this would work with NTLM. Digest would be nice too, but I can live without that if necessary.
I am not an expert on the subject but during the NTLM authentication using http components I have seen that the client needs 3 attempts in order to connect to an NTML endpoint in my case. It is kinda described here for Spnego but it is a bit different for the NTLM authentication.
For NTLM in the first attempt client will make a request with Target auth state: UNCHALLENGED and Web server returns HTTP 401 status and a header: WWW-Authenticate: NTLM
Client will check for the configured Authentication schemes, NTLM should be configured in client code.
Second attempt, client will make a request with Target auth state: CHALLENGED, and will send an authorization header with a token encoded in base64 format: Authorization: NTLM TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==
Server again returns HTTP 401 status but the header: WWW-Authenticate: NTLM now is populated with encoded information.
3rd Attempt Client will use the information from WWW-Authenticate: NTLM header and will make the final request with Target auth state: HANDSHAKE and an authorisation header Authorization: NTLM which contains more information for the server.
In my case I receive an HTTP/1.1 200 OK after that.
In order to avoid all this in every request documentation at chapter 4.7.1 states that the same execution token must be used for logically related requests. For me it did not worked.
My code:
I initialize the client once in a #PostConstruct method of an EJB
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(18);
cm.setDefaultMaxPerRoute(6);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(30000)
.setConnectTimeout(30000)
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM))
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new NTCredentials(userName, password, hostName, domainName));
// Finally we instantiate the client. Client is a thread safe object and can be used by several threads at the same time.
// Client can be used for several request. The life span of the client must be equal to the life span of this EJB.
this.httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultCredentialsProvider(credentialsProvider)
.setDefaultRequestConfig(requestConfig)
.build();
Use the same client instance in every request:
HttpPost httppost = new HttpPost(endPoint.trim());
// HttpClientContext is not thread safe, one per request must be created.
HttpClientContext context = HttpClientContext.create();
response = this.httpclient.execute(httppost, context);
Deallocate the resources and return the connection back to connection manager, at the #PreDestroy method of my EJB:
this.httpclient.close();
I had the same problem with HttpClient4.1.X After upgrading it to
HttpClient 4.2.6 it woked like charm. Below is my code
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("url");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("username", "pwd", "", "domain"));
List<String> authtypes = new ArrayList<String>();
authtypes.add(AuthPolicy.NTLM);
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,authtypes);
localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity=response.getEntity();
The easiest way troubleshoot such situations I found is Wireshark. It is a very big hammer, but it really will show you everything. Install it, make sure your server is on another machine (does not work with Localhost) and start logging.
Run your request that fails, run one that works. Then, filter by http (just put http in the filter field), find the first GET request, find the other GET request and compare. Identify meaningful difference, you now have specific keywords or issues to search code/net for. If not enough, narrow down to first TCP conversation and look at full request/response. Same with the other one.
I solved an unbelievable number of problems with that approach. And Wireshark is very useful tool to know. Lots of super-advanced functions to make your network debugging easier.
You can also run it on either client or server end. Whatever will show you both requests to allow you to compare.
I had a similar problem with HttpClient 4.1.2. For me, it was resolved by reverting to HttpClient 4.0.3. I could never get NTLM working with 4.1.2 using either the built-in implementation or using JCIFS.
Updating our application to use the jars in the httpcomponents-client-4.5.1 resolved this issue for me.
I finally figured it out. Digest authentication requires that if you use a full URL in the request, the proxy also needs to use the full URL. I did not leave the proxy code in the sample, but it was directed to "localhost", which caused it to fail. Changing this to 127.0.0.1 made it work.

Categories