security - seguridad - Acceder a servicios web seguros y tranquilos utilizando el cliente jersey
restful java (1)
He encontrado un buen recurso con respecto a mi problema. Aquí está
http://wiki.open-esb.java.net/attach/RestBCEchoSSL/SslClient.java
Hice algunos cambios en mi código con respecto a la fuente dada y funcionó perfectamente. En realidad, no estaba pasando el certificado y las tiendas de claves correctamente.
Aquí está el código completo.
package clients;
import com.sun.jersey.api.client.*;
import javax.net.ssl.*;
import java.io.*;
import java.net.Socket;
import java.security.*;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
public class JerseyClient {
private WebResource webResource;
private Client client;
//private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
private static final String truststore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/cacerts.jks";
private static final String truststore_password = "changeit";
private static final String keystore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/keystore.jks";
private static final String keystore_password = "changeit";
private static final String url = "https://localhost:9029/testsecurity2/resources/manufacturers/";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(url);
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
TrustManager mytm[] = null;
KeyManager mykm[] = null;
try {
mytm = new TrustManager[]{new MyX509TrustManager(truststore_path, truststore_password.toCharArray())};
mykm = new KeyManager[]{new MyX509KeyManager(keystore_path, keystore_password.toCharArray())};
} catch (Exception ex) {
ex.printStackTrace();
}
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(mykm, mytm, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
/**
* Taken from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509TrustManager implements X509TrustManager {
/*
* The default PKIX X509TrustManager9. We''ll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn''t trust it.
*/
X509TrustManager pkixTrustManager;
MyX509TrustManager(String trustStore, char[] password) throws Exception {
this(new File(trustStore), password);
}
MyX509TrustManager(File trustStore, char[] password) throws Exception {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(trustStore), password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
/*
* Iterate over the returned trustmanagers, look
* for an instance of X509TrustManager. If found,
* use that as our "default" trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn''t initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return pkixTrustManager.getAcceptedIssuers();
}
}
/**
* Inspired from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509KeyManager implements X509KeyManager {
/*
* The default PKIX X509KeyManager. We''ll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509KeyManager doesn''t trust it.
*/
X509KeyManager pkixKeyManager;
MyX509KeyManager(String keyStore, char[] password) throws Exception {
this(new File(keyStore), password);
}
MyX509KeyManager(File keyStore, char[] password) throws Exception {
// create a "default" JSSE X509KeyManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStore), password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
kmf.init(ks, password);
KeyManager kms[] = kmf.getKeyManagers();
/*
* Iterate over the returned keymanagers, look
* for an instance of X509KeyManager. If found,
* use that as our "default" key manager.
*/
for (int i = 0; i < kms.length; i++) {
if (kms[i] instanceof X509KeyManager) {
pkixKeyManager = (X509KeyManager) kms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn''t initialize");
}
public PrivateKey getPrivateKey(String arg0) {
return pkixKeyManager.getPrivateKey(arg0);
}
public X509Certificate[] getCertificateChain(String arg0) {
return pkixKeyManager.getCertificateChain(arg0);
}
public String[] getClientAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getClientAliases(arg0, arg1);
}
public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseClientAlias(arg0, arg1, arg2);
}
public String[] getServerAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getServerAliases(arg0, arg1);
}
public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseServerAlias(arg0, arg1, arg2);
}
}
}
y código para ejecutar el cliente en la clase principal
public static void main(String[] args) {
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
System.out.println(response);
// do whatever with response
client.close();
}
Creé servicios web basados en Jersey (generados automáticamente a través de Netbeans).
También creé los nombres de usuario "testClient" con la contraseña "secreta" y creé el grupo de usuarios "Usuarios" y usé el archivo Realm usando la consola de administración glassfish 3.0.1.
También he mapeado web.xml y sun-web.xml en consecuencia.
Mis servicios web están asegurados con éxito; cuando accedo al sitio web, recibo una advertencia de seguridad y luego le pido un nombre de usuario y una contraseña para acceder a cualquier contenido del sitio web. Está funcionando bien cuando se accede a través del navegador web.
Ahora escribí un cliente simple basado en jersey e intenté acceder a los servicios web ofrecidos por el primer proyecto; el código del cliente está aquí
Código de cliente Jersey generado automáticamente
public class JerseyClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(BASE_URI).path("manufacturers");
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
javax.net.ssl.TrustManager x509 = new javax.net.ssl.X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(null, new javax.net.ssl.TrustManager[]{x509}, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
}
Código en el método principal; usa código generado automáticamente
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
// do whatever with response
client.close();
Resultados:
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128)
at com.sun.jersey.api.client.filter.HTTPBasicAuthFilter.handle(HTTPBasicAuthFilter.java:78)
at com.sun.jersey.api.client.Client.handle(Client.java:457)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557)
at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:69)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:451)
at clients.JerseyClient.get_XML(JerseyClient.java:23)
at clients.NewMain1.main(NewMain1.java:20)
Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
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:1049)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:373)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:215)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:126)
... 7 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)
... 17 more
Java Result: 1
También quiero informar que estos son dos proyectos diferentes que se ejecutan en servidores diferentes, ambos son glassfish 3.0.1. También intenté ejecutar el cliente y los servicios en el mismo servidor, pero todo fue en vano. Estoy atascado; amablemente ayúdame
¡Aclamaciones!