JAX-WS standalone server mutual authentication through certificates - web-services

I have a simple JAX-WS standalone server which is using TLS:
SSLContext ssl = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
store.load(new FileInputStream(keystoreFile), keyPass.toCharArray());
kmf.init(store, keyPass.toCharArray());
KeyManager[] keyManagers = new KeyManager[1];
keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(store);
TrustManager[] trustManagers = tmf.getTrustManagers();
ssl.init(keyManagers, trustManagers, new SecureRandom());
HttpsConfigurator configurator = new HttpsConfigurator(ssl);
HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress("localhost", 8443), 8443);
httpsServer.setHttpsConfigurator(configurator);
HttpContext context = httpsServer.createContext("/test");
httpsServer.start();
endpoint.publish(context);
I would like to use client certificates to create mutual authentication before using web services. Also I would like to see what certificate was used by the client to read DN and other certificate attributes.
How can I do it?

Finally I got it working.
Mutual authentication can be configured through setNeedClientAuth in SSLParameters like the following:
HttpsConfigurator configurator=new HttpsConfigurator(ssl) {
public void configure (HttpsParameters params)
{
SSLContext context;
SSLParameters sslparams;
context=getSSLContext();
sslparams=context.getDefaultSSLParameters();
sslparams.setNeedClientAuth(true);
params.setSSLParameters(sslparams);
}
};
And the client certificate can be checked and parsed according needs from SSLSession. This class can be loaded as resource in web service class:
#Resource
private WebServiceContext context;
HttpsExchange exchange = (HttpsExchange) context.getMessageContext().get(JAXWSProperties.HTTP_EXCHANGE);
SSLSession sslsession = exchange.getSSLSession();
sslsession.getPeerCertificates();

Related

CXF Code First SOAP Web Service Endpoint Protocol

I am implementing a Code first cxf web service. How does cxf decide the soap:address part of generated wsdl ? Is it using the hostname from the deployed machine ?
Also, can I change the endpoint protocol from http to https programmatically or by-configuration on the deployed application ?
You can use Spring for this.
you must create an impl for the interface service.
#WebService(endpointInterface = "com.services.MyAwesomeService")
public class MyAwesomeServiceImpl implements MyAwesomeService {
#Override
public String sayHi(String text) {
return "Hello " + text;
}
}
And config vía Spring.
#Configuration
public class ServiceConfig {
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean(name = "myAwesomeService")
public MyAwesomeServiceImpl myAwesomeService() {
return new MyAwesomeServiceImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), myAwesomeService());
endpoint.publish("/MyAwesomeService");
return endpoint;
}
}
After doing this. You will have your service published in the path /MyAwesomeService.
To configure the HTTPS protocol, I recommend you configure it in the application container (Tomcat) or dedicated front (Apache, F5, etc.)

Java Cant find Trusted Certificate (JKS)

I need to consume a service using CXF and I am facing the following issue.
Even though I had my Java key store (JKS) workig o SOAP UI, for example, when I use it on my java program it always give me the message
sun.security.validator.ValidatorException: No trusted certificate found
I have checked the JKS file and the certificate is in there, so when I put it on the SOAPUI project, it is recognized and the service successful called, with no problems. I am using as base the code provided by the cxf web site (http://svn.apache.org/viewvc/cxf/trunk/distribution/src/main/release/samples/wsdl_first_https/src/main/java/demo/hw_https/client/ClientNonSpring.java?view=log) , as follow:
public static void setupTLS(Object port) throws FileNotFoundException, IOException, GeneralSecurityException
{
final String keyStoreLoc = "d:/certs/mykeystore.jks";
HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(port).getConduit();
TLSClientParameters tlsCP = new TLSClientParameters();
final String keyPassword ="password";
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStoreLoc), keyPassword.toCharArray());
KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);
tlsCP.setKeyManagers(myKeyManagers);
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(keyStoreLoc), keyPassword.toCharArray());
TrustManager[] myTrustStoreKeyManagers = getTrustManagers(trustStore);
tlsCP.setTrustManagers(myTrustStoreKeyManagers);
httpConduit.setTlsClientParameters(tlsCP);
}
private static TrustManager[] getTrustManagers(KeyStore trustStore)
throws NoSuchAlgorithmException, KeyStoreException
{
String alg = KeyManagerFactory.getDefaultAlgorithm();
TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
fac.init(trustStore);
return fac.getTrustManagers();
}
private static KeyManager[] getKeyManagers(KeyStore keyStore, String keyPassword)
throws GeneralSecurityException, IOException
{
String alg = KeyManagerFactory.getDefaultAlgorithm();
char[] keyPass = keyPassword != null ? keyPassword.toCharArray() : null;
KeyManagerFactory fac = KeyManagerFactory.getInstance(alg);
fac.init(keyStore, keyPass);
return fac.getKeyManagers();
}
When debugging, I can see that the certs are loaded and the keystore and keystrustmanagers are populated accordingly, so after days trying to figure out what is happening, I am running out of ideas. So if you guys have any tip that can help,please help me out.
Thanks in advance.
After running some more tests it was clear that the certificate was the problem. I changed the jks for a valid one and now its running perfectly.
For the ones that need a solution like that, the example that I based my solution (http://svn.apache.org/viewvc/cxf/trunk/distribution/src/main/release/samples/wsdl_first_https/src/main/java/demo/hw_https/client/ClientNonSpring.java?view=log) works like a charm.

why NotFound error occur in REST services with windows Phone app?

i tried to connect REST web servie from windows phone 8 application.
it was working proberly for weeks but after no change in it I get this generic error :
System.Net.WebException: The remote server returned an error:
NotFound.
i tried to test it by online REST Clients and services works properly
i tried to handle Exception and parse it as webException by this code :
var we = ex.InnerException as WebException;
if (we != null)
{
var resp = we.Response as HttpWebResponse;
response.StatusCode = resp.StatusCode;
and i get no more information and final response code is : "NotFound"
any one have any idea about what may cause this error?
there is already a trusted Certificate implemented on the server . the one who has the server suggested to have a DNS entry for the server, this entry should be at the customer DNS or in the phone hosts file .that what i done and worked for awhile but now it doesn't work however i checked that there is no thing changed
this is sample for Get Request it works proberly on Windwos Store apps :
async Task<object> GetHttps(string uri, string parRequest, Type returnType, params string[] parameters)
{
try
{
string strRequest = ConstructRequest(parRequest, parameters);
string encodedRequest = HttpUtility.UrlEncode(strRequest);
string requestURL = BackEndURL + uri + encodedRequest;
HttpWebRequest request = HttpWebRequest.Create(new Uri(requestURL, UriKind.Absolute)) as HttpWebRequest;
request.Headers["applicationName"] = AppName;
request.Headers["applicationPassword"] = AppPassword;
if (AppVersion > 1)
request.Headers["applicationVersion"] = AppVersion.ToString();
request.Method = "GET";
request.CookieContainer = cookieContainer;
var factory = new TaskFactory();
var getResponseTask = factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
HttpWebResponse response = await getResponseTask as HttpWebResponse;
// string s = response.GetResponseStream().ToString();
if (response.StatusCode == HttpStatusCode.OK)
{
XmlSerializer serializer = new XmlSerializer(returnType);
object obj = serializer.Deserialize(response.GetResponseStream());
return obj;
}
else
{
var Instance = Activator.CreateInstance(returnType);
(Instance as ResponseBase).NetworkError = true;
(Instance as ResponseBase).StatusCode = response.StatusCode;
return Instance;
}
}
catch (Exception ex)
{
return HandleException(ex, returnType);
}
}
i tried to monitor connections from Emulator and i found this error in connection :
**
Authentication failed because the remote party has closed the
transport stream.
**
You saw the client implement a server side certificate in the service. Did you have that certificate installed on the phone? That can be the cause of the NotFound error. Please, can you try to navigate to the service in the phone or emulator internet explorer prior to testing the app? If you do that, you can see the service working in the emulator/phone internet explorer? Maybe at that point internet explorer ask you about installing the certificate and then you can open your app, and it works.
Also remember if you are testing this in the emulator, every time you close it, the state is lost so you need to repeat the operation of installing the certificate again.
Hope this helps.
If you plan to use SSL in production in general public application (not company-distribution app), you need to ensure your certificate has one of the following root authorities:
SSL root certificates for Windows Phone OS 7.1.
When we had same issue, we purchased SSL certificate from one of those providers and after installing it on server we were able to make HTTPS requests to our services with no problem.
If you have company-distribution app, you can use any certificate from company's Root CA.

Having Separate Certificates Running Under GlassFish 2

Can anyone please explain how i can have more than one X.509 Certificates in my GlassFish application server?
The main challenge for me is that GlassFish uses just one alias which is 's1as'.
You can pull additional certificates from external key files to create an SSLContext and then SSLSocketFactory, which you can feed into your external HTTPS calls.
E.g.:
KeyStore cKeyStore = KeyStore.getInstance("PKCS12");
try (InputStream clientCertKeyInput = new FileInputStream("my.pfx")) {
cKeyStore.load(clientCertKeyInput, "password".toCharArray());
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(cKeyStore, "password".toCharArray());
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(keyManagerFactory.getKeyManagers(),
null, // default javax.net.ssl.trustStore
new SecureRandom());
SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();
You may then configure an HttpsURLConnection with it:
httpsConn.setSSLSocketFactory(sslSocketFactory);
Or if you're using JAXWS set it as a property of the BindingProvider's context:
Map<String, Object> ctxt = ((BindingProvider) port).getRequestContext();
ctxt.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslSocketFactory);
Hope this helps.

Netbeans Basic Http Auth Jax-WS

how can I access a webservice through a basic http authentification? I am using the netbeans built in webservice client features. But when I try to access the webservice, I get an exception with a 401 auth failed error message.
How can I pass the right username and password?
Thank you!
You could use BindingProvider or WSBindingProvider class to access a Web Service through a basic http authentification.
The code is as follows.
XxxService service = new XxxService();
Xxx port = service.getXxxPort();
Map<String, Object> reqContext = ((BindingProvider)port).getRequestContext();
reqContext.put(BindingProvider.USERNAME_PROPERTY, "username");
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
You can also provide your own Authenticator. That way it will work even if the WDSL itself is protected by basic HTTP authentication.
#WebServiceRef(wsdlLocation = "https://laka/sito?wsdl")
static XxxService service;
public static void main(String[] args) {
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user", "password".toCharArray());
}
});
service = new XxxService();
Xxx port = service.getXxxPort();
// invoke webservice and print response
XxxResponse resp = port.foo();
System.out.println(resp.toString());
}