web-dev-qa-db-fra.com

Utilisation de HTTPS avec REST in Java

J'ai un serveur REST fait dans Grizzly qui utilise HTTPS et fonctionne à merveille avec Firefox. Voici le code:

//Build a new Servlet Adapter.
ServletAdapter adapter=new ServletAdapter();
adapter.addInitParameter("com.Sun.jersey.config.property.packages", "My.services");
adapter.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, SecurityFilter.class.getName());
adapter.setContextPath("/");
adapter.setServletInstance(new ServletContainer());

//Configure SSL (See instructions at the top of this file on how these files are generated.)
SSLConfig ssl=new SSLConfig();
String keystoreFile=Main.class.getResource("resources/keystore_server.jks").toURI().getPath();
System.out.printf("Using keystore at: %s.",keystoreFile);
ssl.setKeyStoreFile(keystoreFile);
ssl.setKeyStorePass("asdfgh");

//Build the web server.
GrizzlyWebServer webServer=new GrizzlyWebServer(getPort(9999),".",true);

//Add the servlet.
webServer.addGrizzlyAdapter(adapter, new String[]{"/"});

//Set SSL
webServer.setSSLConfig(ssl);

//Start it up.
System.out.println(String.format("Jersey app started with WADL available at "
  + "%sapplication.wadl\n",
        "https://localhost:9999/"));
webServer.start();

Maintenant, j'essaye de l'atteindre en Java:

SSLContext ctx=null;
try {
    ctx = SSLContext.getInstance("SSL");
} catch (NoSuchAlgorithmException e1) {
    e1.printStackTrace();
}
ClientConfig config=new DefaultClientConfig();
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(null,ctx));
WebResource service=Client.create(new DefaultClientConfig()).resource("https://localhost:9999/");

//Attempt to view the user's page.
try{
    service
        .path("user/"+username)
        .get(String.class);
}

Et obtenir:

com.Sun.jersey.api.client.ClientHandlerException: 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 com.Sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.Java:128)
 at com.Sun.jersey.api.client.Client.handle(Client.Java:453)
 at com.Sun.jersey.api.client.WebResource.handle(WebResource.Java:557)
 at com.Sun.jersey.api.client.WebResource.get(WebResource.Java:179)

D'après les exemples que j'ai trouvés sur le Web, il semble que j'aurais besoin de configurer un Truststore puis de configurer une sorte de TrustManager. Cela semble être beaucoup de code et de travail de configuration pour mon petit projet simple. Existe-t-il un moyen plus simple de simplement dire ... J'ai confiance en ce certificat et je pointe vers un fichier .cert?

32
User1

Lorsque vous dites "existe-t-il un moyen plus simple de ... faire confiance à ce certificat", c'est exactement ce que vous faites en ajoutant le certificat à votre Java. Et c'est très, très facile à faire, et vous n'avez rien à faire dans votre application client pour que ce magasin de confiance soit reconnu ou utilisé.

Sur votre ordinateur client, recherchez l'emplacement de votre fichier cacerts (c'est votre magasin de confiance par défaut Java, et, par défaut, il se trouve dans <Java-home>/lib/security/certs/cacerts).

Tapez ensuite ce qui suit:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to cacerts>

Cela importera le certificat dans votre magasin de confiance, et après cela, votre application client pourra se connecter à votre serveur Grizzly HTTPS sans problème.

Si vous ne souhaitez pas importer le certificat dans votre magasin de clés de confiance par défaut - c'est-à-dire que vous voulez juste qu'il soit disponible pour cette application cliente, mais pas pour tout ce que vous exécutez sur votre machine virtuelle Java sur cette machine - alors vous pouvez créez un nouveau magasin de confiance uniquement pour votre application. Au lieu de passer keytool le chemin d'accès au fichier cacerts par défaut existant, passez keytool le chemin d'accès à votre nouveau fichier de magasin de clés de confiance:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to new trust store>

Vous serez invité à définir et à vérifier un nouveau mot de passe pour le fichier du magasin de clés de confiance. Ensuite, lorsque vous démarrez votre application cliente, démarrez-la avec les paramètres suivants:

Java -Djavax.net.ssl.trustStore=<path to new trust store> -Djavax.net.ssl.trustStorePassword=<trust store password>

Fromage facile, vraiment.

46
delfuego

Voici l'itinéraire douloureux:

    SSLContext ctx = null;
    try {
        KeyStore trustStore;
        trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("C:\\truststore_client"),
                "asdfgh".toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance("SunX509");
        tmf.init(trustStore);
        ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tmf.getTrustManagers(), null);
    } catch (NoSuchAlgorithmException e1) {
        e1.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }
    ClientConfig config = new DefaultClientConfig();
    config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
            new HTTPSProperties(null, ctx));

    WebResource service = Client.create(config).resource(
            "https://localhost:9999/");
    service.addFilter(new HTTPBasicAuthFilter(username, password));

    // Attempt to view the user's page.
    try {
        service.path("user/" + username).get(String.class);
    } catch (Exception e) {
        e.printStackTrace();
    }

Je dois aimer ces six exceptions différentes prises :). Il y a certainement du refactoring pour simplifier un peu le code. Mais j'aime les options -D de delfuego sur la VM. Je souhaite qu'il y ait une propriété statique javax.net.ssl.trustStore que je pourrais simplement définir. Juste deux lignes de code et c'est fait. Quelqu'un sait où ce serait?

C'est peut-être trop demander, mais, idéalement, le keytool ne serait pas utilisé. Au lieu de cela, le magasin de confiance serait créé dynamiquement par le code et le certificat est ajouté au moment de l'exécution.

Il doit y avoir une meilleure réponse.

11
User1

Il convient de garder à l'esprit que cette erreur n'est pas uniquement due à des certificats auto-signés. Les nouveaux certificats CA Entrust échouent avec la même erreur, et la bonne chose à faire est de mettre à jour le serveur avec les certificats racine appropriés, et non de désactiver cette importante fonction de sécurité.

3
steve

Vérifiez ceci: http://code.google.com/p/resting/ . Je pourrais utiliser le repos pour consommer les services HTTPS REST.

2
neel