create authorized webclient with cxf jaxrs - java

I'm a beginner developer. I want to write a rest service call with "apache cxf jaxrs". To do that I create a web client. The sample code is below:
WebClient client = WebClient.create(url);
ClientConfiguration configuration = WebClient.getConfig(client);
MultivaluedHashMap headersMap = new
MultivaluedHashMap();
headersMap.add("key","value");
client.type("application/x-www-form-urlencoded").headers(headersMap);
Form form = new Form();
Response response = client.post(form);
The service which I'm going to call need a one way ssl authorization, so I get the server certificate and convert it to JKS to config the ssl handshake .after creating a socket how can i . combine the web client which i created ssl socket. I don’t want to use spring frame work. Can somebody help me with a simple java sample?
Thanks

The server certificate needs to be added to java CACERTS. That way your java cxf client will 'trust' the server and allow SSL.
You can do this with java keytool as follows:
(assuming your java is at D:\Java and your cert is in a file called server.cer
"D:\Java\bin\keytool.exe" -import -alias my_server -keystore "D:\Java\jre\lib\security\cacerts" -storepass changeit -file server.cer
Trust this certificate? [no]: answer is y
Success is indicated with: "Certificate was added to keystore"

Related

Spring Boot + OAuth2 + REST API - Certification Path Not Found

I'm implementing a RESTful API in an existing Spring Boot v2.1.4 application. The application contains a Spring MVC layer that is secured using Spring Security. There are views built using JSP. Some of the JSPs are embedded with client-side scripts that invoke AJAX calls to retrieve information. These calls will execute against the API rather than the existing MVC endpoints.
The new service endpoints are protected using OAuth2, and an authorization server has been set up within the application and activated using the #EnableAuthorizationServer annotation. To enable SSL on these endpoints, I've generated a private/public key pair using keytool.
keytool -genkeypair -alias apitest -keyalg RSA -validity 365 -keysize 2048 -keystore apitest.jks
I then execute the following command to export the self-signed certificate.
keytool -export -alias apitest -keystore apitest.jks -rfc -file apitest.cer
I've added the certificate to a truststore file for which the path to the file and the password are loaded into system properties when the application starts.
System.setProperty("javax.net.ssl.trustStore", truststorePath);
System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
Since the MVC layer is secured by Spring Security, I attempt to retrieve the OAuth2 token from the token endpoint when the user has successfully logged into the application. The token is returned in the response as a cookie (not shown here).
ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider();
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setClientAuthenticationScheme(AuthenticationScheme.none);
UriComponents uriComponents = ServletUriComponentsBuilder.fromServletMapping(request).path("/oauth/token").build();
resource.setAccessTokenUri(uriComponents.toUriString());
resource.setScope(Arrays.asList("read", "write"));
resource.setClientId(oAuth2ClientDetails.getClientId());
resource.setClientSecret(oAuth2ClientDetails.getClientSecret());
resource.setGrantType("password");
resource.setUsername(userName);
resource.setPassword(userCredentials);
OAuth2AccessToken accessToken = provider.obtainAccessToken(resource, new DefaultAccessTokenRequest());
return accessToken.getValue();
When this logic fires off the call to the token endpoint, the following error is observed.
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://localhost:8443/testapp/oauth/token": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is 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 org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:744) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
Since both the API endpoint and the authorization server are both running on localhost, I thought that a self-signed cert in the truststore file would be sufficient. What am I missing to finish this setup?
I suspect your problem may be related to the certs not having a parent root authority. I usually recommend the approach of creating real world self signed certificates like this, with a trust chain:
First create the Root Certification Authority
Then use that to create Server SSL Certs
ROOT AUTHORITY
For local development with OAuth I create a root authority called mycompany.ca.crt, and then add Java trust like this, plus also distribute this cert to browsers:
keytool -keystore cacerts -storepass changeit -importcert -alias mycompanyca -file ~/Desktop/mycompany.ca.crt
CREATING SSL CERTS
I then use the root certificate to create SSL certs, and no extra trust configuration is needed.
SCRIPTS
If interested, take a look at these scripts of mine, which use the openssl tool:
makeCerts.ps1 script is for Windows
makeCerts.sh script is for MacOS or Linux
Other files are created when scripts are run
You would need to edit domain names to match the ones you are using
My examples use a wildcard domain that I use for local PC development, and I also add domains to my host file. In a browser client I then see this:
Further info in my blog post though I suspect you know most of this already, based on your question.

certificate mechanism between webservice provider and consumer

What are the exact steps done by server and client to place a ssl certificate mechanism in a webservice call? Who(client/server/both) will generate .keystore,.p7b/.cer files? I have googled a lot but couldn't find the answer to it.
In my case, i am the client running a java application which consumes a soap webservice call. I have a .p7b file given by WebService provider. I know where to place the files(.keystore, .cer) and how to use it in the application.
But, my questions are
Do i need to generate keystore file or should i get it from
webservice provider? If i need to generate, how? Do i need private
key/passphrase?
I need a .cer file, so how can i use keytool to convert .p7b to .cer
file?
Thank you for your help in advance.
It looks like you're calling a web service where the HTTP connection is protected by TLS/SSL using X509 certificates. That means the server has set up a keystore with those certificates as well as the corresponding private keys. When you call the web service, the server will retrieve from its keystore the certificate used for the trust establishment (that is, to protect the TLS connection to the web service) and sends it to the client. When the client receives the response from the server it will check the trust of that certificate. Now we have two scenarios:
If the server uses a self-signed certificate (can be used for developments and testing, but not in production), then the client won't recognize it as trusted because it's not stored in the client's truststore. By default, in a Java environment, the truststore is searched (by order) in the following two locations: $JAVA_HOME/lib/security/jssecacerts and $JAVA_HOME/lib/security/cacerts. A custom truststore can also be used by running the client with -Djavax.net.ssl.trustStore and -Djavax.net.ssl.trustStorePassword or by using a custom TrustManager. As such, if the server self-signed certificate is not stored in one of these locations, the secure connection will fail. So the client will have to import the certificate into its truststore. To circumvent the import of self-signed certificates into the client's truststore, you can create a custom X509TrustManager as stated here.
If the server uses a certificate signed by one of the recognized root CA authorities, then it'll be validated automagically because those CA's certificates are already installed in Java's default truststore. As such, the trusted TLS connection will be successful.
In the case where the server does not require client authentication the process is over (this is what happens when you connect to most HTTPS websites via browser).
If the server requires client authentication, then the client will need to provide its own certificate from its keystore to the server, and the server will need to have it installed in its truststore. The web service provider must provide to the client the specification for the certificate profile that the client should use.
Here you can find a good clarification to the keystore vs truststore terminology.
By default in Java environments, keystores and truststores are JKS files.
So you're saying you have a .p7b file provided by the web service provider. Quoting from this page:
PKCS#7/P7B Format
The PKCS#7 or P7B format is usually stored in Base64 ASCII format and has a file extention of .p7b or .p7c. P7B certificates contain "-----BEGIN PKCS7-----" and "-----END PKCS7-----" statements. A P7B file only contains certificates and chain certificates, not the private key. Several platforms support P7B files including Microsoft Windows and Java Tomcat.
So that P7B file contains the server certificate or certificate chain (more on this here).
I believe you're in a no-client-auth scenario. Therefore, you won't need your own keystore. You'll only need to import the server's certificate (P7B file) into the truststore you're using. You can directly import a P7B file without converting it to CER format:
keytool -import -trustcacerts -alias web_service -keystore my_truststore.jks -file web_service.p7b
In the case you still want a CER formatted certificate, you can convert from P7B to CER like this (to answer to your 2nd question):
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
If in fact client authentication is needed, then you'll need to create your keystore with your private key and public certificate and provide it to the connection by either the -Djavax.net.ssl.keyStore and -Djavax.net.ssl.keyStorePassword parameters or through a KeyManager. The same workflow previously explained applies now in the opposite direction.

How to establish HTTPS connection without importing certificate file to KeyStore?

Is there any way to establish an HTTPS connection without importing the certificate to keyStore?
Currently , I am importing the certificate to myKeyStore
keytool -import -alias aliasOfCertifiate -file myCertificateFile.cer -keystore myKeystore
using a javax.net.ssl.HttpsURLConnection object to establish the HTTPS connection. But, as per a new requirement, my HTTPS client may need to communicate with thousands of web servers. So, I believe, importing the certificate might not be a good idea.
Any ideas?

Not able to access webservice using https protocol (ssl)

We had a webservice that is recently exposed over https.
When we try to connect to it over https using JAX-WS client, it throws following exception
com.sun.xml.ws.client.ClientTransportException: HTTP transport error: java.net.ConnectException: Connection refused: connect
Which generally means that the there is some problem over socket connection.
It throws exception when we try to call some operation of webservice using webservice client.
The http call to the webservice is working fine.
The funny thing here is that this problem only happens when we have deployed the webservice and had made our first call to access operations using https protocol.
Now as soon as we make a http call, surprisingly after that even https also starts working.
Please give some advice if some one has faced this kind of issue before.
In general your java client should have ssl certificate in trusted key store.
Use keytool for certificate management:
keytool -import -trustcacerts -keystore trastedCert -storepass traustedCertPassword -noprompt -alias trastedCert -file trastedCert.cer
Your can add trusted cert to your JVM(cacerts):
keytool -import -trustcacerts -keystore cacerts -storepass traustedCertPassword -noprompt -alias trastedCert -file trastedCert.cer
or
For jBoss app server I'm using next JAVA_OPTS params:
set JAVA_OPTS=%JAVA_OPTS% -Djavax.net.ssl.trustStore=%PATH_TO_CERT%\traustedCert -Djavax.net.ssl.trustStorePassword=traustedCertPassword

Java web service over https - How to add a self-signed certificate into a client api?

I have a "Hello World" web service created with axis2. I would like to write a client api which could use this service over https with a self-signed certificate. I have a self-signed certificate myCertificate.cer and a keystore containing it.
Here is my client API :
public class MyApi{
public Object callMyService(){
Axis2TestStub stub = new Axis2TestStub(
"https://localhost:8443/axis2/services/Axis2Test");
System.setProperty("javax.net.ssl.trustStore",
"src/main/resources/myKeystore.jks")
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Hello request = new Hello();
request.setMot("World");
HelloResponse response = stub.hello(request);
Object mot = response.get_return();
return mot;
It works but I would like to use myCertificate.cer and not a keystore containing it. Does someone know how to do that? I tried to override https protocol with no success :
HttpSecureProtocol myHttpsProtocol = new HttpSecureProtocol();
myHttpsProtocol .setCheckHostname(false);
myHttpsProtocol .addTrustMaterial(new TrustMaterial("myCertificate.cer"));
Protocol customHttps = new Protocol("https",
(ProtocolSocketFactory) myHttpsProtocol , 8443);
Protocol.registerProtocol("https", customHttps);
I would like to write a client api which could use this service over https with a self-signed certificate. I have a self-signed certificate myCertificate.cer and a keystore containing it.
The server key store do contain the server's self-signed certificate and private key and is used by the server to sign messages and to return credentials to the client.
On the client-side, you need to import the server certificate into the client trust store (and generally, you don't want the private key in the client trust store so you extract a stand-alone certificate file i.e. without the private key and then you import that server certificate in the trust store).
It works but I would like to use myCertificate.cer and not a keystore containing it.
It's not a key store but a trust store and adding the certificate to the client trust store is required because self-signed certificates are not signed by a root CA and are not trusted by default. So you need to create a chain of trust.
Now, you can maybe distribute the trust store in the JAR of the client API. This approach is discussed in this thread (the biggest problem being that you'll have to redistribute the JAR when the server certificate expires). Personally, I don't really like this solution.
IMHO, the good solution if you want to skip the trust store stuff would be to buy a real certificate from a widely-known certificate vendor for which you already have root CA certificates in the trust store (like Verisign, Thawte).
I would just add the certificate to the cacerts file of the JDK running your app. If you do this then you won't have to do anything else. The code you have above wouldn't be required. You add the certificate to the keystore by running a command similar to below:
C:/<jdk-version/bin/keytool -import -alias myalias -file mycert.crt -keystore C:/<jdk-version>/jre/lib/security/cacerts

Categories