I am porting an android app to javaFX for windows deployment, i'm new to javaFX and desktop deployment, but not so new to java.
The app contains a WebView that loads a url obtained from a server via Json (so could be essentially anything).
openJDK 14 , openJfx 16, intellij idea ultimate 2021.1.3, gradle: plugins: org.beryx.jlink & org.openjfx.javafxplugin
This works fine when I run the program in development and testing (on a windows 10 machine), but when it is packaged and deployed on a windows machine (any windows 10 so far) I get an "java.lang.Throwable: SSL handshake failed" exception when the page is loaded.
This is the stack trace:
[ERROR] 2021-07-14 14:13:53.737 [JavaFX Application Thread] MediaElementWeb - WebView Failed:
java.lang.Throwable: SSL handshake failed
at javafx.scene.web.WebEngine$LoadWorker.describeError(WebEngine.java:1440) ~[javafx.web:?]
at javafx.scene.web.WebEngine$LoadWorker.dispatchLoadEvent(WebEngine.java:1379) ~[javafx.web:?]
at javafx.scene.web.WebEngine$PageLoadListener.dispatchLoadEvent(WebEngine.java:1240) ~[javafx.web:?]
at com.sun.webkit.WebPage.fireLoadEvent(WebPage.java:2524) ~[javafx.web:?]
at com.sun.webkit.WebPage.fwkFireLoadEvent(WebPage.java:2369) ~[javafx.web:?]
at com.sun.webkit.network.URLLoaderBase.twkDidFail(Native Method) ~[javafx.web:?]
at com.sun.webkit.network.URLLoader.notifyDidFail(URLLoader.java:799) ~[javafx.web:?]
at com.sun.webkit.network.URLLoader.lambda$didFail$6(URLLoader.java:782) ~[javafx.web:?]
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:447) ~[javafx.graphics:?]
at java.security.AccessController.doPrivileged(AccessController.java:391) ~[?:?]
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:446) ~[javafx.graphics:?]
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96) ~[javafx.graphics:?]
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) ~[javafx.graphics:?]
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174) ~[javafx.graphics:?]
at java.lang.Thread.run(Thread.java:832) [?:?]
The problem is not specific to any particular certificate, so I know it is not a problem specifically with the certificate generally, tested with many sites. and I ONLY get this error in the deployed app.
The page is being loaded in a standard way: WebEngine.load(targetURL);
I am capturing the error with:
tNode.getEngine().getLoadWorker().stateProperty().addListener((o, ov, nv) -> {
if (nv == Worker.State.FAILED) {
logger.error("WebView Failed: ", tNode.getEngine().getLoadWorker().getException());
}
});
I have searched and tried solutions offered by other people that seem to have experienced similar errors, such as:
Setting a trust manager before calling load(page):
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
logger.error("SSLContext Failed: ", e);
}
(No errors or effect here)
and
settings the JVMarg on the deployment
-Dcom.sun.webkit.useHTTP2Loader=false
Which I can see has the effect of "com.sun.webkit.network.URLLoader" being shown in the stack trace instead of http2 (as was suggested on other threads) but also no change here either.
Has anyone any thoughts (bearing in mind I'm a novice at java desktop deployment) at what the issue can be and how to resolve it?
Many thanks
Update:
Trace from console on deployed test https://pastebin.com/R5SkR4w1
First few rows:
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.991 BST|SignatureScheme.java:295|Signature algorithm, ed25519, is not supported by the underlying providers
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.992 BST|SignatureScheme.java:295|Signature algorithm, ed448, is not supported by the underlying providers
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.995 BST|NamedGroup.java:297|No AlgorithmParameters for x25519 (
"throwable" : {
java.security.NoSuchAlgorithmException: Algorithm x25519 not available
at java.base/javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:192)
at java.base/sun.security.ssl.NamedGroup.<init>(NamedGroup.java:286)
at java.base/sun.security.ssl.NamedGroup.<clinit>(NamedGroup.java:184)
at java.base/sun.security.ssl.SignatureScheme.<clinit>(SignatureScheme.java:59)
at java.base/sun.security.ssl.SSLSessionImpl.<clinit>(SSLSessionImpl.java:823)
at java.base/sun.security.ssl.TransportContext.<init>(TransportContext.java:133)
at java.base/sun.security.ssl.TransportContext.<init>(TransportContext.java:103)
at java.base/sun.security.ssl.SSLSocketImpl.<init>(SSLSocketImpl.java:111)
at java.base/sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:72)
at java.base/sun.net.www.protocol.https.HttpsClient.createSocket(HttpsClient.java:413)
at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:162)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265)
at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:372)
at ...
Managed to solve this with helpful comments from #slaw about a suggestion I had tried initially, but ultimately not implemented correctly, and help from #dave_thompson_085 with how to provide extra debugging info. So the resolution, and a few tips for people in the same boat:
1. The solution:
The Badass Jlink Plugin for gradle on Intellij IDEA, for Java 14 and JavaFX 16 was not correctly merging the security provider classes.
This was resolved by adding "jdk.crypto.ec" to the merged modules list.
2. Adding the module manually
The org.beryx.jlink plugin (2.24.0) is really complex and powerful, so it was a struggle to work out how to do it with my implementation.
I tried many combinations, but the following code did it for me in my build.gradle:
jlink {
//... Other jlink \ jpackage stuff
mergedModule {
additive = true
requires 'jdk.crypto.ec'
}
//... Other jlink \ jpackage stuff
}
3. Debugging packaged java binary for windows
Some Jlink config changes that helped along the way.
jlink {
//..
jpackage {
//..
imageOptions = [
"--win-console"
]
}
//..
launcher {
jvmArgs = ['-Dcom.sun.webkit.useHTTP2Loader=false','-Djavax.net.debug=ssl:handshake']
}
}
--win-console opens a console window when you start your program so you can see the logging out put
-Djavax.net.debug=ssl:handshake gives more information about the SSL process and handshaking so you can see what is happening.
Related
I'm going to download image with Glide library that needs https and proxy config.
I implemented all anonymous certificates and proxy settings for unsafe client (in my dev environment) but get handshake error. This is my OkHttpClient passed to Glide
val unsafeOkHttpClient: OkHttpClient
get() {
try {
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
#SuppressLint("TrustAllX509TrustManager")
#Throws(CertificateException::class)
override fun checkClientTrusted(
chain: Array<java.security.cert.X509Certificate>,
authType: String
) {
}
#SuppressLint("TrustAllX509TrustManager")
#Throws(CertificateException::class)
override fun checkServerTrusted(
chain: Array<java.security.cert.X509Certificate>,
authType: String
) {
}
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
return arrayOf()
}
})
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
val sslSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
val proxy = Proxy(
Proxy.Type.HTTP,
InetSocketAddress.createUnresolved(PROXY_URL, PROXY_PORT)
)
builder.proxy(proxy)
builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier(HostnameVerifier { _, _ -> true })
val connectionSpecs = ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
).build()
builder.connectionSpecs(listOf(connectionSpecs))
return builder.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
I should mention that ConnectionSpec is get from my server configurations. And always i get this error:
Even i used very simple client but result is same.
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xbe2b3c68: Failure in SSL library, usually a protocol error
error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/tls_record.cc:587 0xbe5d2a88:0x00000001)
error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/handshake.cc:580 0xd084f543:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:387)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:226)
... 23 more
I tried too many ways for example exclude okHttp from glide and use OkHttp itself, downgrade okHttp, upgrade all libs ( Retrofit , Glide ) .I found some posts here but cloud not make it works.
https://github.com/square/okhttp/issues/3787
https://github.com/Microsoft/cpprestsdk/issues/650
UPDATED
As i mentioned all images are open in browser ( with proxy extension) and also i got 200 with Curl like this:
curl --insecure -x http://myProxy:9052 -i https://myimage.png
But i find out that TLS version of main server and proxy server are not same. One uses TLS1.2 and other is TLS1.1. So i'm thinking about may this configuration lead to handshake failure cause my request will do not know to handshake with which version! This is my guess and asked the network admin already : "Why we have two different confines for server and proxy!" I'm waitings for their response. If you have any idea please feel free to add comment or post any answer.
After strugle with many thing from client side, backed team set a valid certificate that make my problem solved.
I mean they did not use self-sigend certificate but they used an invalid certificate! That is why i got hand shake error and in browser we can passed this error by accept responcibility of danger and click proceed button.
So if you see the same problem: Handshake error but you can proceed it in browser with my situation lets chech SSL certificate first to save time!
I am busy with a project where I have to do a GET on an exposed rest service using specific certificates. I am using the apache camel framework with the https4 component. I created a keystore and tested it using soapUI and it connected successfully, but I am however unable to connect through my project.
I used the following page as reference: http://camel.apache.org/http4.html
I set up the SSL for the HTTP Client through the following configuration:
<spring:sslContextParameters id="sslContextParameters">
<spring:keyManagers keyPassword="xxxx">
<spring:keyStore resource="classpath:certificates/keystore.jks" password="xxxx"/>
</spring:keyManagers>
</spring:sslContextParameters>
<setHeader headerName="CamelHttpMethod">
<simple>GET</simple>
</setHeader>
My endpoint is configured as:
<to uri="https4://endpointUrl:9007/v1/{id}?sslContextParametersRef=sslContextParameters"/>
The stacktrace I am receiving:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1904)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:279)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:273)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1446)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:901)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:837)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1023)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.apache.camel.component.http4.HttpProducer.executeMethod(HttpProducer.java:301)
at org.apache.camel.component.http4.HttpProducer.process(HttpProducer.java:173)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:163)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:62)
at org.apache.camel.impl.InterceptSendToEndpoint$1.process(InterceptSendToEndpoint.java:164)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:163)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.ChoiceProcessor.process(ChoiceProcessor.java:117)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:163)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:468)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
at org.apache.camel.processor.Pipeline.access$100(Pipeline.java:44)
at org.apache.camel.processor.Pipeline$1.done(Pipeline.java:139)
at org.apache.camel.processor.CamelInternalProcessor$InternalCallback.done(CamelInternalProcessor.java:257)
at org.apache.camel.processor.RedeliveryErrorHandler$1.done(RedeliveryErrorHandler.java:480)
at org.apache.camel.processor.interceptor.TraceInterceptor$1.done(TraceInterceptor.java:180)
at org.apache.camel.processor.SendProcessor$1.done(SendProcessor.java:155)
at org.apache.camel.processor.CamelInternalProcessor$InternalCallback.done(CamelInternalProcessor.java:257)
at org.apache.camel.processor.Pipeline$1.done(Pipeline.java:148)
at org.apache.camel.processor.CamelInternalProcessor$InternalCallback.done(CamelInternalProcessor.java:257)
at org.apache.camel.processor.RedeliveryErrorHandler$1.done(RedeliveryErrorHandler.java:480)
at org.apache.camel.processor.interceptor.TraceInterceptor$1.done(TraceInterceptor.java:180)
at org.apache.camel.processor.SendProcessor$1.done(SendProcessor.java:155)
at org.apache.camel.component.cxf.CxfClientCallback.handleResponse(CxfClientCallback.java:61)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:827)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1672)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream$1.run(HTTPConduit.java:1168)
at org.apache.cxf.workqueue.AutomaticWorkQueueImpl$3.run(AutomaticWorkQueueImpl.java:428)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.cxf.workqueue.AutomaticWorkQueueImpl$AWQThreadFactory$1.run(AutomaticWorkQueueImpl.java:353)
at java.lang.Thread.run(Thread.java:745)
Any help would be much appreciated !
Just same: I followed documented instructions and got too stuck on "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". There's a quick fix, but if you want to link the configuration to the client HTTP session at stake, it becomes a complex set-up.
Method 1:
Doc pages, forums, and this other article would tell you that setting JVM launch options "-Djavax.net.ssl.trustStore=myKeystore.jks -Djavax.net.ssl.trustStorePassword=mystorepass" do solve the issue, provided the remote parties' certificates (self signed, or signed by a CA but then with all the full certificate chain) were all fetched as Trusted certificates in the supplied keystore. Fact is, HTTP4 is based on JSSE, and these java launch options do configure the stack JVM-wide.
As an alternative, you can also fetch peers' certificates (complete chains) in the default JVM keystore jre\lib\security\cacerts (initial password: "changeit") and thus not even need JVM options.
If you have a few outgoing client connections and few peer certificates, this is the simplest way.
Method 2:
In our context, with above 100 remote parties, each requiring certificate updates every 2 years in average, that method implies a JVM reboot on an updated keystore about every week. Our highly available gateway is no longer highly available. So I searched a dynamic/per-connexion/programmatic way.
Below is a simplified excerpt of code from a CAMEL Processor that we use to remotely connect as REST or plain-vanilla HTTP client, with or without SSL/TLS, and with or without client-side certificate (i.e. 2-way SSL/TLS versus 1-way SSL/TLS), as well as combine HTTP Basic Auth as required by peers.
For various reasons the now old CAMEL version 2.16.3 is still used in our context. I have not tested yet newer versions. I suspect no changes given the libraries at stake under the Apache CAMEL layer.
I have added in the code below many comments detailling variant API's to the same effect. So you have clues below to further simplify the code or try alternatives with newer HTTP4 versions. As is, the code works with 2.16, as a CAMEL Processor bean within a Spring application context that contains the entire CAMEL route definition in DSL.
In our context we use java code for configuring entirely dynamic SSL/TLS outbound connexions per session. You should have no difficulties freezing part of the configuration that we set below dynamically via java, into the CAMEL XML DSL as suitable to your context.
Maven dependencies at stake:
<properties>
<camel-version>2.16.3</camel-version>
</properties>
...
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http4</artifactId>
<version>${camel-version}</version>
<scope>provided</scope>
</dependency>
Code extracted from our org.apache.camel.Processor (I have removed many Exception handling and simplified the code below in order to focus on the solution):
// relevant imports (partial)
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.http4.HttpClientConfigurer;
import org.apache.camel.component.http4.HttpComponent;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
...
#Override
public void process(Exchange exchange) throws Exception {
// assume here that we have previously fetched all dynamic connexion parameters in set of java Properties. Of course you can use numerous means to inject connection parameters
Properties params= ... ;
// Trick! 'targetURL' is the URI of the http server to call. Its not the same as the Camel endpoint URI (see further "httpUrlToken" placeHolder), on which you configure endpoint options
// Fact is, we prefer to pass just the target URL as parameter and keep full control on building the CAMEL endpoint URI in java
String targetURL= params.getProperty("targetURL"); // URL to call, e.g. "http://remoteHost.com/some/servlet/path". Will override the placeholder URL set on the endpoint.
// default plain HTTP without SSL/TLS:
String endPointURI = "http4://httpUrlToken?throwExceptionOnFailure=false"; // with option to prevent exceptions from being thrown for failed response codes. It allows us to process all the response codes in a response Processor
// Oh yes! we have to manage a map of HttpComponent instances, because the CAMEL doc clearly tells that each instance can only support a single configuration
// and our true connector is multithreading where each request may go to a different (dynamic) destination with different SSL settings,
// so we actually use a Map of HttpComponent instances of size MAX_THREADS and indexed by the thread ID plus ageing and re-use strategies... but this brings us too far.
// So, for a single thread per client instance, you can just do:
HttpComponent httpComponent = exchange.getContext().getComponent("http4", HttpComponent.class);
// overload in case of SSL/TLS
if (targetURL.startsWith("https")) {
try {
endPointURI = "https4://httpUrlToken?throwExceptionOnFailure=false";
httpComponent = exchange.getContext().getComponent("https4", HttpComponent.class); // well: "https4" and "http4" are the same, so you may skip this line! (our true HttpComponent map is common to secured and unsecured client connexions)
// basic SSL context setup as documented elsewhere, should be enough in theory
SSLContext sslctxt = getSSLContext(exchange, params.getProperty("keystoreFilePath"), params.getProperty("keystorePassword"), params.getProperty("authenticationMode")); // cfr helper method below
HttpClientConfigurer httpClientConfig = getEndpointClientConfigurer(sslctxt); // cfr helper method below
httpComponent.setHttpClientConfigurer(httpClientConfig);
// from here, if you skip the rest of the configuration, you'll get the exception "sun.security.provider.certpath.SunCertPathBuilderException:unable to find valid certification path to requested target"
// the SSL context covers certificate validation but not the host name verification process
// we de-activate here at the connection factory level (systematically... you may not want that), and link the later to the HTTP component
HostnameVerifier hnv = new AllowAll();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslctxt, hnv);
// You may choose to enforce the BasicHttpClientConnectionManager or PoolingHttpClientConnectionManager, cfr CAMEL docs
// In addition, the following linkage of the connection factory through a Registry that captures the 'https' scheme to your factory is required
Registry<ConnectionSocketFactory> lookup = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslSocketFactory).build();
HttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(lookup);
// Does not work in 2.16, as documented at http://camel.apache.org/http4.html#HTTP4-UsingtheJSSEConfigurationUtility
// ... keystore and key manager setup ...
// SSLContextParameters scp = new SSLContextParameters();
// scp.setKeyManagers(...);
// httpComponent.setSslContextParameters(scp);
// Not as good as using a connection manager on the HTTP component, although same effects in theory
// HttpClientBuilder clientBuilder = HttpClientBuilder.create();
// clientBuilder.set... various parameters...
// httpClientConfig.configureHttpClient(clientBuilder);
// Commented-out alternative method to set BasicAuth with user and password
// HttpConfiguration httpConfiguration = new HttpConfiguration();
// httpConfiguration.setAuthUsername(authUsername);
// ... more settings ...
// httpComponent.setHttpConfiguration(httpConfiguration);
// setClientConnectionManager() is compulsory to prevent "SunCertPathBuilderException: unable to find valid certification path to requested target"
// if instead we bind the connection manager to a clientBuilder, that doesn't work...
httpComponent.setClientConnectionManager(connManager);
} catch (Exception e) { ... ; }
}
// (back to code common to secured and unsecured client sessions)
// additional parameters on the endpoint as needed, cfr API docs
httpComponent.set...(...) ;
// you may want to append these 3 URI options in case of HTTP[S] with Basic Auth
if (... basic Auth needed ...)
endPointURI += "&authUsername="+params.getProperty("user")+"&authPassword="+params.getProperty("password")+"&authenticationPreemptive=true";
// *********** ACTUAL TRANSMISSION ********************
exchange.getIn().setHeader(Exchange.HTTP_URI, targetURL); // needed to overload the "httpUrlToken" placeholder in the endPointURI
// Next, there are many ways to get a CAMEL Producer or ProducerTemplate
// e.g. httpComponent.createEndpoint(endPointURI).createProducer()
// ... in our case we use a template injected from a Spring application context (i.e. <camel:template id="producerTemplate"/>) via constructor arguments on our Processor bean
try {
producerTemplate.send(httpComponent.createEndpoint(endPointURI),exchange);
} catch (Exception e) { ...; }
// you can then process the HTTP response here, or better dedicate the next
// Processor on the CAMEL route to such handlings...
...
}
Supporting helper methods, invoked by above code
private HttpClientConfigurer getEndpointClientConfigurer(final SSLContext sslContext) {
return new HttpClientConfigurer(){
#Override
public void configureHttpClient(HttpClientBuilder clientBuilder) {
// I put a logger trace here to see if/when the ssl context is actually applied, the outcome was ... weird, try it!
clientBuilder.setSSLContext(sslContext);
}
};
}
/**
* Build a SSL context with keystore and other parameters according to authentication mode.
* The keystore may just contain a trusted peer's certificate for 1way cases, and the associated certificate chain up to a trusted root as applicable.
* The keystore shall too contain one single client private key and certificate for 2way modes. We assume here a same password on keystore and private key.
* #param authenticationMode one of "1waySSL" "1wayTLS" "2waySSL" "2wayTLS" each possibly suffixed by "noCHECK" as in "1waySSLnoCHECK"
* #param keystoreFilePath can be null for "noCHECK" modes
* #param keystorePassword would be null if above is null
*/
private SSLContext getSSLContext(Exchange exchange, String keystoreFilePath, String keystorePassword, String authenticationMode) throws GeneralSecurityException, FileNotFoundException, IOException {
SSLContext sslContext = SSLContext.getInstance(authenticationMode.substring(4,7).toUpperCase(),"SunJSSE");
//enforce Trust ALL ? pass a trust manager that does not validate certificate chains
if (authenticationMode.endsWith("noCHECK")) {
TrustManager[] trustAllCerts = new TrustManager[]{ new TrustALLManager()};
sslContext.init(null , trustAllCerts, null);
return sslContext;
}
// we use https, and validate remote cert's by default, henceforth keystore and password become compulsory
if (null == keystoreFilePath || null == keystorePassword)
throw new GeneralSecurityException("Config ERROR: using https://... and implicit default AUTHMODE=1waySSL altogether requires to supply keystore parameters");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
trustStore.load(new FileInputStream(keystoreFilePath), keystorePassword.toCharArray());
tmf.init(trustStore);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
if (authenticationMode.charAt(0)=='2') { // our authenticationMode starts with 1way.. or 2way...
// 2way... case: set the keystore parameters accordingly
keyStore.load(new FileInputStream(keystoreFilePath), keystorePassword.toCharArray());
kmf.init(keyStore, keystorePassword.toCharArray());
sslContext.init(kmf.getKeyManagers() , tmf.getTrustManagers(), new SecureRandom());
} else { // 1way... case
sslContext.init(null , tmf.getTrustManagers(), new SecureRandom());
}
return sslContext;
}
// Create a trust manager that does not validate certificate chains
private class TrustALLManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
private static class AllowAll implements HostnameVerifier
{
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
}
}
Hope this helps. I spent many hours trying to get it working (although I know well about SSL/TLS principles, security, X509, etc) ... This code is far from my taste for clean and lean java code. In addition I assumed that you do know how to build a keystore, supply all needed certificate chains, define a CAMEL route, etc. As such, it works with Camel 2.16 within a Spring Application Context, and has no other pretention than providing clues that would save you hours.
I Have ehcache replication working properly without SSL support.
I am looking to support my ehcache replication via SSL i.e. i want to have RMI over SSL
How can i do that?
Here is sample manual peer discovery i am using.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//10.100.10.12:40002/ssoSessionStore"/>
Can i have some SSL support to RMI call it is doing?
Thanks
I had to change ehcache source code and change few classes to support SSL. As when ehcache over rmi bootsup , it registers itself on rmiregistry. I need to start this registery via SSL context
Look at class RMICacheManagerPeerListener.java for method startRegistry()
This is main class where RMI registry starts. One who is modifying the code needs to understand then ehcache rmi code flow first. Below code is snippet of what has to be done and respectively change other methods.
final String SSL= System.getProperty("isSSL");
protected void startRegistry() throws RemoteException {
try {
LOG.info("Trying to Get Exsisting Registry =========>> ");
if (SSL != null && SSL.equals("ssl"))
registry = LocateRegistry.getRegistry(hostName, port.intValue(),
new SslRMIClientSocketFactory());
else
registry = LocateRegistry.getRegistry(port.intValue());
try {
registry.list();
} catch (RemoteException e) {
// may not be created. Let's create it.
if (SSL != null && SSL.equals("ssl")) {
LOG.info("Registry not found, Creating New SSL =========>> ");
registry = LocateRegistry.createRegistry(port.intValue(),
new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
} else {
LOG.info("Registry not found, Creating New Naming registry =========>> ");
registry = LocateRegistry.createRegistry(port.intValue());
}
registryCreated = true;
}
} catch (ExportException exception) {
LOG.error("Exception starting RMI registry. Error was " + exception.getMessage(), exception);
}
}
Similarly i made change for method
bind()
notifyCacheAdded()
unbind()
disposeRMICachePeer()
populateListOfRemoteCachePeers()
bind()
init()
To patch support for using a custom socket factory you should remove usage of the global defaults. Static method calls on
java.rmi.Naming
should be replaced with the registry returned by the three-argument versions of
LocateRegistry.createRegistry
and
LocateRegistry.getRegistry
and in ConfigurableRMIClientSocketFactory.java change
getConfiguredRMISocketFactory
to return an SSL-based implementation.
See https://gist.github.com/okhobb/4a504e212aef86d4257c69de892e4d7d for an example patch.
I have spring-boot Tomcat server for secure websocket connections. The server accepts Android 4.4, iOS, Firefox, and Chrome clients without failure with an authority-signed certificate. Android 5.0, however, fails the SSL handshake.
Caused by: javax.net.ssl.SSLHandshakeException: Handshake failed
at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:436)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:1006)
at org.glassfish.grizzly.ssl.SSLConnectionContext.unwrap(SSLConnectionContext.java:172)
at org.glassfish.grizzly.ssl.SSLUtils.handshakeUnwrap(SSLUtils.java:263)
at org.glassfish.grizzly.ssl.SSLBaseFilter.doHandshakeStep(SSLBaseFilter.java:603)
at org.glassfish.grizzly.ssl.SSLFilter.doHandshakeStep(SSLFilter.java:312)
at org.glassfish.grizzly.ssl.SSLBaseFilter.doHandshakeStep(SSLBaseFilter.java:552)
at org.glassfish.grizzly.ssl.SSLBaseFilter.handleRead(SSLBaseFilter.java:273)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
at java.lang.Thread.run(Thread.java:818)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0xa1f34200: Failure in SSL library, usually a protocol error
error:1408E0F4:SSL routines:SSL3_GET_MESSAGE:unexpected message (external/openssl/ssl/s3_both.c:498 0xac526e61:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake_bio(Native Method)
at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:423)
I think the problem is with TLS or the cipher suites due to changes in Android 5.0 Lollipop, and not with the certificates because the other clients connect, but I cannot figure out how to tell what is happening on the client side of the connection because SSL debugging does not appear to be supported on Android. The problem is likely very similar to this one, which is also not resolved yet but suggests the problem is with cipher suites. The Android bugs 88313 81603 developer-preview-1989 seem to indicate the Android implementation is correct but server configuration or implementation of cipher suites may not be.
I have set the following server cipher suites
server.ssl.ciphers = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA
In particular, the TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA is on the list of supported protocols for Android for API 11+.
I verified the server supports this
openssl s_client -connect server:port
which returns
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-SHA
There is a slight mismatch in names between openssl and java, but the openssl documentation says these are the same cipher suite.
My server supports and negotiates first a cipher suite with the openssl client that is compatible with Android 5.0. I expect Android 5.0 to connect without issue, but it fails.
Has anyone successfully connected Android 5.0 secure websocket connections to Tomcat? Are there cipher suites that are known to work? Is there a way to debug the Android client side SSL implementation?
UPDATE
Network trace results:
SYN -->
<-- SYN, ACK
ACK -->
<-- Data
ACK -->
<-- certificates, SSL/TLS params? 1
<-- 2
<-- 3
<-- 4
ACK -->
ACK -->
ACK -->
FIN(!), ACK -->
When the Android 5.0 device (a Nexus 5) receives the server certificate information sent in 4-5 packets, it responds with a variable number (2-4) ACKs then a FIN, ACK. In the successful trace, the client does not send a FIN. The Android 5 client does not like something it gets from the server.
For the failure, the server SSL debugging info says:
http-nio-8080-exec-10, called closeOutbound()
http-nio-8080-exec-10, closeOutboundInternal()
http-nio-8080-exec-10, SEND TLSv1.2 ALERT: warning, description = close_notify
http-nio-8080-exec-10, WRITE: TLSv1.2 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 03 00 02 01 00
UPDATE 2
Here is a bare-bones Tyrus Android application to use
package edu.umd.mindlab.androidssldebug;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import org.glassfish.tyrus.client.ClientManager;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
#ClientEndpoint
public class MainActivity extends ActionBarActivity {
public static final String TAG = "edu.umd.mindlab.androidssldebug";
final Object annotatedClientEndpoint = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart(){
super.onStart();
final Object annotatedClientEndpoint = this;
new Thread(new Runnable(){
#Override
public void run() {
try {
URI connectionURI = new URI("wss://mind7.cs.umd.edu:8080/test");
ClientManager client = ClientManager.createClient();
Object clientEndpoint = annotatedClientEndpoint;
client.connectToServer(clientEndpoint, connectionURI);
}
catch(Exception e){
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteStream);
e.printStackTrace(printStream);
final String message = byteStream.toString();
Log.e(TAG, message);
e.printStackTrace();
runOnUiThread(new Runnable() {
public void run() {
TextView outputTextView = (TextView) findViewById(R.id.outputTextView);
outputTextView.setText(message);
}
});
}
}
}).start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#OnOpen
public void onOpen(Session session) {
Log.i(TAG, "opened");
runOnUiThread(new Runnable() {
public void run() {
TextView outputTextView = (TextView) findViewById(R.id.outputTextView);
outputTextView.setText("opened");
}
});
}
#OnMessage
public void onMessage(String message, Session session) {
Log.i(TAG, "message: " + message);
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
Log.i(TAG, "close: " + closeReason.toString() );
}
#OnError
public void onError(Session session, Throwable t) {
final String message = "error: " + t.toString();
Log.e(TAG, message);
runOnUiThread(new Runnable() {
public void run() {
TextView outputTextView = (TextView) findViewById(R.id.outputTextView);
outputTextView.setText(message);
}
});
}
}
error:1408E0F4:SSL routines:SSL3_GET_MESSAGE:unexpected message (external/openssl/ssl/s3_both.c:498 0xac526e61:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake_bio(Native Method)
at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:423)
0x1408E0F4 is:
$ openssl errstr 0x1408E0F4
error:1408E0F4:SSL routines:SSL3_GET_MESSAGE:unexpected message
It shows up in the OpenSSL sources at a couple of places:
$ cd openssl-1.0.1l
$ grep -R SSL3_GET_MESSAGE *
ssl/s3_both.c: SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
ssl/s3_both.c: SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
ssl/s3_both.c: SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE);
ssl/s3_both.c: SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE);
ssl/s3_both.c: SSLerr(SSL_F_SSL3_GET_MESSAGE,ERR_R_BUF_LIB);
Here's the code I believe is causing the trouble (line numbers have changed, and the SSLerr is at 491):
/* Obtain handshake message of message type 'mt' (any if mt == -1),
* maximum acceptable body length 'max'.
* The first four bytes (msg_type and length) are read in state 'st1',
* the body is read in state 'stn'.
*/
long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
{
...
/* s->init_num == 4 */
if ((mt >= 0) && (*p != mt))
{
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
...
But I'm not sure what causes that particular problem. See this question on the OpenSSL User List at SSL_F_SSL3_GET_MESSAGE and SSL_R_UNEXPECTED_MESSAGE.
EDIT: according to the Android source for s3_both.c, that is the code that's triggering the issue.
-----
OK, looking at the file successful.pcap and unsuccessful.pcap, the good client is using TLS 1.0 while the misbehaving client is using TLS 1.2. But I don't see anything offensive that would cause the client to close the connection while processing the four messages (Server Hello, Certificate, Server Key Exchange, Server Hello Done) in the Record.
-----
Based on the ServerKeyExchange message:
The server selected the client's offering of secp521r1. You might want to use secp256. That's most interoperable right now. Also see Is the limited elliptic curve support in rhel/centos/redhat openssl robust enough?.
-----
OpenSSL 1.0.1e FIPS used by the server has suffered a few problems. See, for example:
Binary curves broken in FIPS mode
Crash when using TLS 1.2 caused by use of incorrect hash algorithm
If possible, you might want to upgrade it to something newer.
-----
Is there a way to debug the Android client side SSL implementation?
I think this is an easier question. Use a custom SSLSocketFactory like SSLSocketFactoryEx. It will allow you to try different protocols, cipher suites and settings. But its trial-and-error.
Otherwise, you would need to grab a copy of the OpenSSL source code used by Android 5.0 (including patches). I don't know how to get that and ensure it builds like mainline OpenSSL (effectively, you need to build s_client using Android sources with debugging information).
This might be helpful: OpenSSL on Android. From the looks of the diffs, it appears Android is using OpenSSL 1.0.0. (Some of the patches in the patch/ directory specifically call out 1.0.0b).
This is confirmed to be caused by an Android 5.0 bug. It is unclear to me currently whether there is also a problem in Tyrus websocket or Grizzly.
See also: 93740 and preview 328.
The suggested fix at TYRUS-402 resolves this. I have opened a corresponding Grizzly Bug GRIZZLY-1827 which has the corresponding patch.
Update: The bug GRIZZLY-1827 has been fixed.
I'm using Sap Jco to connect to SAP database with the front end being Java(JSF), When I connect to SAP with:
try {
mConnection =JCO.createClient("400", // SAP client
"c3026902", // userid
"********", // password
"EN", // language
"iwdf5020", // host name
"00"); // system number
mConnection.connect();
}
catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
Problem I'm facing is when run the application for the first time, data is displayed but when I re-run it says "Could not load middleware layer 'com.sap.mw.jco.rfc.MiddlewareRFC' "
Can any one help me in resolving the issue?????
This sounds like the API cannot load the native driver files.
The SAP Java Connector consists of a native runtime part, that does the actuall communication and a Java API that wraps this functionality with a java api.
The Java API is inside the sapjco.jar and the native drivers are e.g on windows inside librfc32.dll and sapjcorfc.dll.
Place these dll's into your system path (e.g. windows: C:\WiNDOWS\system32) and it should run.
Cheers
Sebastian
Are your DLLs located in the Windows system32 folder? If so, are you probably using the wrong architecture? (x64 DLL on 32 bit or vice versa)
Also, are the DLLs the same version as the java api? If you have SAP GUI installed there could be older DLLs around.
Defining SAP connection:
For the Version 3,0 of the sapjco library there exists plenty of useful information. To create a connection following the instructions in:
http://www.browseye.com/linkShare.html?url=http://help.sap.com/saphelp_nwpi711/helpdata/en/46/fb807cc7b46c30e10000000a1553f7/content.htm?bwsCriterion=%22Setting%20Up%20Connection%22&bwsMatch=1&bwsCriterion=%22Setting%20Up%20Connection%22&bwsMatch=1
There are a few thing that you should take into account:
Place the dll file in the same place that the jar.
The dll must be the right version for your operating system and architecture otherwise you will get a native library error.
Example of code to create a connection to the server.
public class StepByStepClient
{
static String DESTINATION_NAME1 = "ABAP_AS_WITHOUT_POOL";
static String DESTINATION_NAME2 = "ABAP_AS_WITH_POOL";
static
{
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "ls4065");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "85");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "800");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "homofarber");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "laska");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
createDestinationDataFile(DESTINATION_NAME1, connectProperties);
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
createDestinationDataFile(DESTINATION_NAME2, connectProperties);
}
static void createDestinationDataFile(String destinationName, Properties connectProperties)
{
File destCfg = new File(destinationName+".jcoDestination");
try
{
FileOutputStream fos = new FileOutputStream(destCfg, false);
connectProperties.store(fos, "for tests only !");
fos.close();
}
catch (Exception e)
{
throw new RuntimeException("Unable to create the destination files", e);
}
}
public static void step1Connect() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_NAME1);
System.out.println("Attributes:");
System.out.println(destination.getAttributes());
System.out.println();
}
}
In SAPJco 3.0 connections are build from the info contained in a “Destination”.
The documentation example use a properties file to save the “Destination”. However it is a non-secure way to keep connection info. As is indicated on the documentation in the hightlighted paragraph you can see on next link.
http://help.sap.com/saphelp_nwpi711/helpdata/en/48/5fb9f9b523501ee10000000a421937/content.htm?bwsCriterion=%22In%20practice%20you%20should%20avoid%20this%20for%20security%20reasons.%22&bwsMatch=1
You can keep connection info on a database or any other storage system if you create a custom “DestinationDataProvider” In the Examples provided with the SAPJco library there is an example of how to create a custom DestinationDataProvider.