diff --git a/.gitignore b/.gitignore index 466716be82be3ba40a6cd699a5fce7b76dcb7f06..1198f789c156ff91ad7b7ae396bd373e161fa271 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,6 @@ proguard/ # Package Files # *.jar *.war -*.ear \ No newline at end of file +*.ear + +src/main/resources/ssl/* diff --git a/pom.xml b/pom.xml index edaf75b174b3890292d26699213332ca44c837fb..b1d5a96cefc5f1ade85d70c32bfc96d5b6e57240 100644 --- a/pom.xml +++ b/pom.xml @@ -68,6 +68,19 @@ <artifactId>jersey-client</artifactId> </dependency> + <!-- HTTP2 --> + <dependency> + <groupId>org.glassfish.grizzly</groupId> + <artifactId>grizzly-http2</artifactId> + <version>3.0.0</version> + </dependency> + + <dependency> + <groupId>org.glassfish.grizzly</groupId> + <artifactId>grizzly-npn-bootstrap</artifactId> + <version>2.0.0</version> + </dependency> + <!-- Eclipse Collections --> <dependency> <groupId>org.eclipse.collections</groupId> @@ -405,6 +418,58 @@ </executions> </plugin> + <!-- SSL Certificates --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>keytool-maven-plugin</artifactId> + <version>1.5</version> + <executions> + <execution> + <phase>generate-resources</phase> + <id>generateKeyPair</id> + <goals> + <goal>generateKeyPair</goal> + </goals> + <configuration> + <skipIfExist>true</skipIfExist> + </configuration> + </execution> + <execution> + <phase>generate-resources</phase> + <id>generateCertificateRequest</id> + <goals> + <goal>generateCertificateRequest</goal> + </goals> + <configuration> + <file>src/main/resources/ssl/test.csr</file> + </configuration> + </execution> + <execution> + <phase>generate-resources</phase> + <id>generateCertificate</id> + <goals> + <goal>generateCertificate</goal> + </goals> + <configuration> + <infile>src/main/resources/ssl/test.csr</infile> + <outfile>src/main/resources/ssl/test.crt</outfile> + <rfc>true</rfc> + </configuration> + </execution> + </executions> + <configuration> + <keystore>src/main/resources/ssl/cert.jks</keystore> + <storepass>storepass</storepass> + <keypass>storepass</keypass> + <alias>localhost</alias> + <validity>100</validity> + <sigalg>SHA256withRSA</sigalg> + <keyalg>RSA</keyalg> + <!--dname>cn=com.example</dname--> + <dname>cn=localhost.localdomain</dname> + </configuration> + </plugin> + </plugins> </build> <properties> diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java index 6bdaf72af1ebd4695329856ba219b142083f171f..2af92d4717c498d5ee8be3b04eee194059278f16 100644 --- a/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java @@ -37,11 +37,11 @@ public class BiblioClient { //Log in to get the token with basci authentication String email = "john.doe@nowhere.com"; - String password = "admin"; + String passwd = "admin"; String token = webResource.path("biblio/login") .request() .accept(MediaType.TEXT_PLAIN) - .header("Authorization", "Basic " + java.util.Base64.getEncoder().encodeToString((email + ":" + password).getBytes())) + .header("Authorization", "Basic " + java.util.Base64.getEncoder().encodeToString((email + ":" + passwd).getBytes())) .get(String.class); if (!token.isBlank()) { log.info("token received."); diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java index 5255f7995aba00a93ff64a21461e29119d1f3faa..a4f1bd1f324a95d229a9838f64fb9827fd5bed97 100644 --- a/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java +++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java @@ -2,10 +2,16 @@ package fr.univtln.bruno.samples.jaxrs.server; import lombok.extern.java.Log; import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.http2.Http2AddOn; +import org.glassfish.grizzly.http2.Http2Configuration; +import org.glassfish.grizzly.ssl.SSLContextConfigurator; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; import org.glassfish.jersey.logging.LoggingFeature; import org.glassfish.jersey.server.ResourceConfig; +import java.io.IOException; import java.net.URI; import java.util.logging.Level; import java.util.logging.Logger; @@ -18,15 +24,19 @@ public class BiblioServer { // Base URI the Grizzly HTTP server will listen on public static final String BASE_URI = "http://0.0.0.0:9998/myapp"; + public static final int TLS_PORT = 4443; + /** * Main method. * * @param args the input arguments */ - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws InterruptedException, IOException { log.info("Rest server starting..." + BASE_URI); final HttpServer server = startServer(); + addTLSandHTTP2(server); + //The server will be shutdown at the end of the program Runtime.getRuntime().addShutdownHook(new Thread(server::shutdownNow)); @@ -57,4 +67,37 @@ public class BiblioServer { // exposing the Jersey application at BASE_URI return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc); } + + /** + * Adds a https (TLS) listener to secure connexion and adds http2 on this protocol. + * @param httpServer + * @return + * @throws IOException + */ + public static HttpServer addTLSandHTTP2(HttpServer httpServer) throws IOException { + NetworkListener listener = + new NetworkListener("TLS", + NetworkListener.DEFAULT_NETWORK_HOST, + TLS_PORT); + listener.setSecure(true); + + // We add the certificate stored in a java keystore in src/main/resources/ssl + // By default a self signed certificate is generated by maven (see pom.xml) + SSLContextConfigurator sslContextConfigurator = new SSLContextConfigurator(); + sslContextConfigurator.setKeyStoreBytes(BiblioServer.class.getResourceAsStream("/ssl/cert.jks").readAllBytes()); + sslContextConfigurator.setKeyStorePass("storepass"); + + listener.setSSLEngineConfig(new SSLEngineConfigurator(sslContextConfigurator, false, false, false)); + + // Create default HTTP/2 configuration and provide it to the AddOn + Http2Configuration configuration = Http2Configuration.builder().build(); + Http2AddOn http2Addon = new Http2AddOn(configuration); + + // Register the Addon. + listener.registerAddOn(http2Addon); + httpServer.addListener(listener); + + return httpServer; + } + }