Java Webstart and URLConnection caching API - java

The description of the URLConnection caching API states as the last sentence:
There is no default implementation of URLConnection caching in the Java 2 Standard Edition. However, Java Plugin and Java WebStart do provide one out of the box.
Where can I find more information about the Webstart ResponseCache?
Which Versions of Webstart on which platforms activate Caching?
In which cases is it active? Only HTTP Get?
Can it be configured?
Is the sourcecode available?
Background:
Case 1
With following (groovy) code
def url = new URL('http://repo1.maven.org/maven2/')
def connection = url.openConnection()
def result = connection.inputStream.text
I would expect that every time the code is executed the server is contacted. But when executed in
Java Web Start 10.9.2.05
JRE-Version verwenden 1.7.0_09-b05 Java HotSpot(TM) Client VM
the behavior is different. The first time the code is executed, the server is contacted. All subsequent executions of the code don't involve any communication to the server (traced using wireshark).
But it gets even stranger. After re-start of the webstart app, the first time the code is executed, the url http://repo1.maven.org/maven2/.pack.gz is requested resulting in a 404. Only than the original url is requested resulting in a 304 NOT MODIFIED. All subsequent executions don't involve any communication to the server.
I think the approach of transparently enhancing the urlconnection with caching capabilities is nice and fine and helps improve performance of client applications. But since the server in this case didn't define an Expires header nor a cache-control header, I think the code above should always ask the server and not silently ignore my request.
Case 2
Following code does not work when executed with webstart 10.1.1.255 (this was installed by some early beta Version of java 7, but I don't know which one this was)
URL url = new URL("http://repo1.maven.org/maven2/");
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept-Encoding", "gzip");
connection.connect();
InputStream is = connection.getInputStream();
if ("gzip".equalsIgnoreCase(connection.getContentEncoding()))
{
is = new GZIPInputStream(is);
}
is.close();
With Java Web Start 10.1.1.255 starting with the second execution I got a
java.io.IOException: Not in GZIP format
at java.util.zip.GZIPInputStream.readHeader(Unknown Source)
at java.util.zip.GZIPInputStream.<init>(Unknown Source)
at java.util.zip.GZIPInputStream.<init>(Unknown Source)
With both Java Web Start 1.6.0_24 and now Java Web Start 10.2.1.255 I am not able to reproduce the problem.
With Wireshark I saw that in the case where I got the error, the http header contained an If-Modified-Since entry, and the return code therefore was 304. In the other cases there was no If-Modified-Since. Therefore I think that caching is not active in the stable versions of webstart -- despite the last sentence of the above link.
It seems, that the cache of the beta version does aggressive tuning to http get requests: It does use If-Modified-Since and automatically tries to use gzip encoding -- even if the client code does not set this header. But when the cache is hit, the returned stream is not gzipped, although getContentEncoding returns "gzip".
Since the caching seems not to be active in the stable version of webstart on my machine, I cannot verify if the bug is in the code any more and therefore hesitate to file a bug report.

The only information I have found so far is at Java Rich Internet Applications Enhancements in JDK 7
Caching enabled by default: Caching of network content for application code running in Web Start mode is now enabled by default. This allows application improved performance and consistency with applet execution mode. To ensure the latest copy of content is used, the application can use URLConnection.setUseCaches(false) or request header Cache-Control values no-cache/no-store.
[...]
Improvements for handling content with gzip encoding: The deployment cache will keep application content in compressed form and return it to the application as-is with gzip content-encoding in the HTTP header. This makes behavior more consistent across different execution modes (first launch versus subsequent launch, cache enabled versus cache disabled). See 6575586 for more details.

I modified your code. Hope it works for you.
URL url = new URL("http://repo1.maven.org/maven2/");
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept-Encoding", "ISO-8859-1");
connection.connect();
InputStream is = connection.getInputStream();
if ("gzip".equalsIgnoreCase(connection.getContentEncoding()))
{
is = new GZIPInputStream(is);
}
is.close();

The cache appears to be implemented by com.sun.deploy.cache.DeployCacheHandler, which lives in deploy.jar. I can't find the source in any official repositories; that link is to some sort of grey-market copy.
I can't, at a glance, find any indications that it is disabled (or enabled!) on any particular platforms. This cache handler has been present since at least Java 6.
It only caches GET requests. A comment in the isResourceCacheable method explains:
// do not cache resource if:
// 1. cache disabled
// 2. useCaches is set to false and resource is non jar/zip file
// 3. connection is not a GET request
// 4. cache-control header is set to no-store
// 5. lastModified and expiration not set
// 6. resource is a partial body resource
I don't see any way to directly configure the cache.

Related

How to setup HTTPS with jetty embedded 8.1.16.v20140903

I am using one of the example jetty embedded projects from here
I added a SelectChannelConnect, SslSelectChannelConnect and SslSocketConnector as shown in the link above.
Here is a snippet from my code:
// Create the server
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(80);
connector.setMaxIdleTime(30000);
connector.setConfidentialPort(8443);
connector.setStatsOn(false);
connector.setAcceptors(4);
server.setConnectors(new Connector[]
{ connector });
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
ssl_connector.setPort(443);
SslContextFactory cf = ssl_connector.getSslContextFactory();
cf.setKeyStorePath("/path/to/keystore");
cf.setKeyStorePassword("password");
cf.setKeyManagerPassword("password");
cf.setTrustStore("/path/to/keystore");
cf.setTrustStorePassword("password");
cf.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
ssl_connector.setStatsOn(false);
server.addConnector(ssl_connector);
ssl_connector.open();
SslSocketConnector ssl2_connector = new SslSocketConnector(cf);
ssl2_connector.setPort(443);
ssl2_connector.setStatsOn(false);
server.addConnector(ssl2_connector);
ssl2_connector.open();
server.start()
HTTP works fine but I am not able to get it to work on HTTPS. It gives me an initial warning in the browser about untrusted certificate blah blah. I added an exception but then it displays this message: "This might be because the site uses outdated or unsafe TLS security settings. If this keeps happening, try contacting the website’s owner." on IE. My settings on IE are alright with TLS 1.0, 1.1 and 1.2 checked and SSL 3.0 unchecked.
Am I missing something? I believe I followed everything from the example project.
Also I generated the keystore and built the project from jdk SE 6u45. I do not think there are any issues the keystore file as it works perfectly in another application.
Most browser no longer support SSLv3, TLS/1.0 and TLS/1.1.
Chrome Announcement
https://developers.google.com/web/updates/2020/05/chrome-84-deps-rems
Firefox Announcement
https://blog.mozilla.org/security/2018/10/15/removing-old-versions-of-tls/
Apple Safari Announcement
https://webkit.org/blog/8462/deprecation-of-legacy-tls-1-0-and-1-1-versions/
Microsoft Announcement
https://blogs.windows.com/msedgedev/2018/10/15/modernizing-tls-edge-ie11/#OkGpBsuyj6XwhUEQ.97
You should be using TLS/1.2 or better (eg: TLS/1.3)
Java 6u45 does not support TLS/1.2, you have to upgrade your JVM at a minimum.
You need to be on Java 7u95 or newer for decent TLS/1.2 support.
For TLS/1.3 support you need to be on Java 8u262 or newer.
Pay attention to JVM expiration dates.
This is important for long term success with SSL/TLS, as the expiration exist because of various databases and configurations within the JVM need to be kept up to date for SSL/TLS to function reliably with the general internet.
Finally, get rid of the entire setExcludeCipherSuites you have, as every one of those cipher suites are excluded by the JVM itself now (see security.properties on a modern JVM)

Https web service call failure

We have implemented webservice call using JAX-WS RI 2.1.6 in JDK 6 now problem comes when we enable https webservice call stops reaching server and java reports following error,
javax.xml.ws.WebServiceException: java.io.IOException: Async IO
operation failed (3), reason: RC: 55 The specified network resource
or device is no longer available.
Now I have tested this within SoapUI and response from the service is received there.
Looked into various solution where it tells us to provide timeout settings but nothing seems work.
#WebEndpoint(name = "RulesSoap")
public RulesSoap getRulesSoap() {
((BindingProvider)super.getPort(new QName("urn:decision:Rules", "RulesSoap"), RulesSoap.class)).getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", 1000);
((BindingProvider)super.getPort(new QName("urn:decision:Rules", "RulesSoap"), RulesSoap.class)).getRequestContext().put("com.sun.xml.internal.ws.request.timeout", 1000);
return super.getPort(new QName("urn:decision:Rules", "RulesSoap"), RulesSoap.class);
}
And just for information JAX-WS implementation is following few simple lines,
of course we submit all necessary data into respective stubs and all but I am not submitting here because our http calls are getting through,
Rules rules = new Rules(new URL(url), new QName("urn:decision:Rules", "Rules"));
RulesSoap rulesSoap = rules.getRulesSoap();
CorticonResponse response = rulesSoap.processRequest(request);
Note : Our application server WebSphere Application Server and Version 7.0.0.19
Thanks in Advance.
After lots of efforts we resolved this. I will provide steps if anything related to this happens how to find root cause,
Step 1 :
First of all we enabled soap tracing in WebSphere Application Server by following setting,
Admin Console > Servers > Server Types > WebSphere Application Servers >
{your server} > Troubleshooting > Change Log Detail Levels > Runtime
In run time please put this , *=info: com.ibm.ws.websvcs.*=all: org.apache.axis2.jaxws.*=all
This step will create trace.log file in your logs folder.
Now any web service request which goes out of your server will add logs to this file and necessary props like endpoint, request, response etc.
Step 2 :
Reading this trace.log file we found following endpoint,
PropertyValid 1 org.apache.axis2.jaxws.client.PropertyValidator validate validate property=(javax.xml.ws.service.endpoint.address) with value=(http://uxm.solutions.lnet.com:9445/axis/dswsdl/Rules/1/0)
HTTPConnectio 3 resetConnection : http://uxm.solutions.lnet.com:9445/axis/dswsdl/Rules/1/0 Persistent : true
Now if you notice here that our soap has endpoint address javax.xml.ws.service.endpoint.address where protocol is still using http which causes to fail ssl handshake.
Step 3 :
Solution for this is to override endpoint inside your soap stubs which can be implemented by adding following line,
RulesSoap rulesSoap = rules.getRulesSoap();
((BindingProvider)rulesSoap).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://uxm.solutions.lnet.com:9445/axis/dswsdl/Rules/1/0");
Conclusion :
So here is what i think even we pass https url while we are creating objects but still does not take this https url on runtime, to me this looks like stubs creation issue with JAX-WS.
Thanks.
What protocol /ciphers are you using? You have mentioned there is connection to webservice on WAS7 with JDK6 and Java 6 does not support TLS1.2 (and TLS1.1 only from certain fixpack).
See this:
How to use TLS 1.2 in Java 6

Azure Storage Blob : https://(storageAccountName).blob.core.windows.net/vhd?restype=container&comp=list not working using proxy

For getting the blob container details we are using the below mentioned REST API.
Vhd is the blob container name.
https://(storageAccountName).blob.core.windows.net/vhd?restype=container&comp=list
When we use proxy server details (example:SQUID Proxy) to access the storage REST API calls, we are getting the below mentioned error.
HttpResponse for Blobs:: ResourceNotFoundThe
specified resource does not exist.
RequestId:6dc7e6f2-0001-000d-30f9-d56eb3000xxx
If we access the same rest api without proxy server, we are getting the valid response and it's working.
Per my experience, normally, using squid is as reverse proxy for backend services, but here you want to access the storage REST APIs via squid as forward proxy. You can refer to the wiki page https://en.wikipedia.org/wiki/Proxy_server, the SO thread Difference between proxy server and reverse proxy server and the blog to know the differences between both.
So the solution for the issue is that configuring the proxy server as forward proxy.
For Squid, you can try to refer to the squid wiki pages http://wiki.squid-cache.org/SquidFaq/ConfiguringSquid and http://wiki.squid-cache.org/Features/HTTPS to know how to configure as forword proxy with HTTPS.
For Apache, you can try to refer to the apache doc page http://httpd.apache.org/docs/2.0/mod/mod_proxy.html#forwardreverse to do.
Then, setting the system properties for Java to enable proxy support after setting up forward proxy successfully.
There are two ways support proxy for Java.
Command Line JVM Settings: The proxy settings are given to the JVM via command line arguments:
java -Dhttp.proxyHost=proxyhostURL -Dhttp.proxyPort=proxyPortNumber -Dhttp.proxyUser=someUserName -Dhttp.proxyPassword=somePassword HelloWorldClass
Setting System Properties in Code: Adding the following lines in your Java code so that JVM uses the proxy to make HTTP calls.
System.setProperty("http.proxyPort", "someProxyPort");
System.setProperty("http.proxyUser", "someUserName");
System.setProperty("http.proxyPassword", "somePassword");
System.setProperty("http.proxyHost", "someProxyURL");
More information for Networking & Proxies & Properties in Java, Please refer to http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html and http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html.
we got the solution. The issue is we are invoking asynchronous calls for all storage accounts at a time. For example : if we have 5 storage accounts and each storage accounts 5 vhd containers and in for loop if we invoke all 5 at time and with callback waiting for 5 response,In this case it's not working. so we are invoking each call separately and it's started working.

Exception "Received fatal alert: handshake_failure" while sending a request through java code

Note: Same url is working successfully in browser, but it’s not working through java program same url.
Java code:
String urlString= "https://<host>:<port>/TestProject";
URL url = new URL(urlString);
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
InputStream ins = con.getInputStream();
InputStreamReader isr = new InputStreamReader(ins);
BufferedReader in = new BufferedReader(isr);
String inputLine;
while ((inputLine = in.readLine()) != null) System.out.println(inputLine);
in.close();
Exception:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
Please give the solutions as early as possible for this. Please give the possibilities to get this scenario if knows, it will very useful for me.
Finally i got solution:
Please look into http://myjavacafe.blogspot.in/2015/01/exception-received-fatal-alert.html
First: the server probably logged more detailed information about the problem, which could allow determining and fixing the actual problem. But since you want an early and "possible" answer rather than an accurate one, causes I've seen are:
Version too old: The server requires a newer protocol than your Java client offers. You appear to be running Java6, which only implements up to TLSv1.0. If the server demands higher, it will fail the handshake, although requiring above 1.0 is somewhat controversial for now (it likely will become accepted and common over the next several years). Solution: use Java8 (in its default configuration), or at least Java7 and override its default configuration which only offers up to TLSv1.0 for client.
Version too new: TLS specs (all) call for servers to negotiate a newer-version or otherwise more-capable client down to the server capabilities, but some servers apparently have bugs and instead fail the handshake. (Browsers/clients often handle this by falling back to older protocols, which caused the recent "POODLE" attack. See for example https://security.stackexchange.com/questions/71427/is-java-client-vulnerable-by-poodle and https://security.stackexchange.com/questions/70719/ssl3-poodle-vulnerability .) However, Java6 client is unlikely to trigger such a problem, and if a recent browser and especially several recent browsers can connect this is very unlikely. But if this is the problem Solution: use older Java (poor), or configure to use old protocol version(s) and possibly few(er) ciphers.
Extensions: Similarly it is possible a buggy server fails to skip unimplemented extensions as the specs say it should. Again if modern browsers can connect this is very unlikely. But if it does you can't control the extensions Java uses so Solution: none. (At least none in Java. You could use an external adapter such as stunnel, or an application-level proxy or relay.)
No shared cipher: The server does not support any of the ciphersuites your client offers. This is unlikely unless your JRE/JVM is configured badly. Java implements nearly all the defined ciphersuites, and by default enables all the ones that are not badly insecure, except that Java6 only enables Elliptic Curve Cryptography suites if an ECC crypto provider is installed which it is not by default. A server admin might reasonably want and prefer EC, but to require it today would be imprudent. If ECC is the problem Solution: use Java7 or 8 or add an EC provider to Java6. If your JRE/JVM is configured badly to use insecure ciphersuites that the server should not agree to Solution: don't do that.
SNI: The server may fail the handshake if it requires Server Name Indication, an extension commonly required nowadays for virtual hosting, but your client does not provide it with the right value. However, Java6 URLConnection(https) derives SNI automatically from the URL, the same way browsers do, so if the same URL works in a recent browser that is not the problem.
Client auth: The server may require client authentication using a certificate, often abbreviated as requiring (a) client cert, and fail if your client doesn't provide one, or perhaps not the correct one. Your browser(s) may be configured to supply the correct cert&key automatically, although if you use multiple browsers that don't share a keystore (as for example IE and Chrome on Windows do) that may be less likely. Solution: configure your JVM/JRE (or for limited scope a customized SSLSocketFactory) to use a keystore that contains the correct privateKeyEntry (key and cert or chain) or if a keystore is already configured put the correct privateKeyEntry in that keystore.

Java 6 NTLM proxy authentication and HTTPS - has anyone got it to work?

I have a Java application (not an applet) that needs to access a web service. Proxies for the web service have been generated with JAX-WS, and seem to work fine. In one scenario it needs to talk through a web proxy server (actually Squid 3.0), which is set to require NTLM authentication.
Running on Sun's JRE 1.6.0_14, everything works fine for accessing HTTP URLs, without requiring any changes: the built-in NTLM authenticator kicks in and it all works seemlessly. If, however, the web service URL is a HTTPS URL, the web service call fails deep inside Sun's code:
com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: java.lang.NullPointerException
at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:121)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:142)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:83)
at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:105)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:587)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:546)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:531)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:428)
at com.sun.xml.internal.ws.client.Stub.process(Stub.java:211)
at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(SEIStub.java:124)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:98)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
... our web service call ...
Caused by: java.lang.NullPointerException
at sun.net.www.protocol.http.NTLMAuthentication.setHeaders(NTLMAuthentication.java:175)
at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1487)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:164)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:896)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:109)
... 16 more
Looking in Sun's bug database turns up a few exceptions in such classes, but all of them seem to have been fixed. Has anyone come across anything like this? Has anyone got this to work?
After some debugging, this seems to be a flaw in the JRE class libraries, specifically in sun.net.www.protocol.http.HttpURLConnection.
Studying the HTTP requests and responses in the cases of HTTP and HTTPS endpoints showed that, in the successful HTTP case, the requests had a header Proxy-Connection=keep-alive, which was missing on the failing HTTPS case. Reading more generally, there seems to be some confusion on whether one should use "Proxy-Connection" or just "Connection", too ...
Anyway, it is notable that in the HTTP case, the code goes through HttpURLConnection.writeRequests(), which contains the following code snippet
/*
* For HTTP/1.1 the default behavior is to keep connections alive.
* However, we may be talking to a 1.0 server so we should set
* keep-alive just in case, except if we have encountered an error
* or if keep alive is disabled via a system property
*/
// Try keep-alive only on first attempt
if (!failedOnce && http.getHttpKeepAliveSet()) {
if (http.usingProxy) {
requests.setIfNotSet("Proxy-Connection", "keep-alive");
} else {
requests.setIfNotSet("Connection", "keep-alive");
}
There's no such code when creating a tunnel through the proxy for HTTPS, which causes Squid to get upset during the NTLM authentication conversation.
To work around this, in HttpURLConnection.sendCONNECTRequest(), I added
if (http.getHttpKeepAliveSet()) {
if (http.usingProxy) {
requests.setIfNotSet("Proxy-Connection", "keep-alive");
}
}
just before
setPreemptiveProxyAuthentication(requests);
http.writeRequests(requests, null);
I inject my modified HttpURLConnection.class into the JRE using the "-Xbootclasspath/p" flag, and now it works! Not exactly elegant, but there we are.
Are you married to JAX-WS? I use Apache Axis2, which uses the commons httpclient and has NTLM authentication built-in.
Example:
//Configure SOAP HTTP client to authenticate to server using NTLM
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
//TODO make report server credentials configurable
auth.setUsername("jdoe");
auth.setPassword("strongpass");
auth.setDomain("WINDOWSDOMAIN");
auth.setHost("host.mydomain.com");
auth.setPort(443);
Options o = new Options();
o.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE,auth);
myWebServiceStub._getServiceClient().setOptions(o);

Categories