Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for SSL Configuration within JerseyTest #4573

Merged
merged 14 commits into from
Dec 17, 2020
Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -16,10 +16,14 @@

package org.glassfish.jersey.test;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.ws.rs.core.Application;

import org.glassfish.jersey.server.ResourceConfig;

import java.util.Optional;

/**
* Basic application deployment context.
* <p>
Expand Down Expand Up @@ -122,6 +126,8 @@ public static class Builder {

private final ResourceConfig resourceConfig;
private String contextPath = DEFAULT_CONTEXT_PATH;
private SSLContext sslContext;
private SSLParameters sslParameters;

/**
* Create new deployment context builder instance not explicitly bound to the JAX-RS / Jersey application class.
Expand Down Expand Up @@ -175,6 +181,24 @@ public Builder contextPath(final String contextPath) {
return this;
}

/**
* Set the application ssl properties.
*
* @param sslContext application ssl context.
* @param sslParameters application ssl parameters
* @return this application deployment context builder.
*
* @throws NullPointerException if {@code sslContext} is {@code null}.
*/
public Builder ssl(final SSLContext sslContext, SSLParameters sslParameters) {
if (sslContext == null && sslParameters == null) {
throw new NullPointerException("The sslContext and sslParameters must not be null");
}
this.sslContext = sslContext;
this.sslParameters = sslParameters;
return this;
}

/**
* Build a new application deployment context configured by the current state of this
* application deployment context builder.
Expand All @@ -201,6 +225,8 @@ protected void reset() {

private final ResourceConfig resourceConfig;
private final String contextPath;
private final SSLContext sslContext;
private final SSLParameters sslParameters;

/**
* Create new application deployment context.
Expand All @@ -210,6 +236,8 @@ protected void reset() {
protected DeploymentContext(final Builder b) {
this.contextPath = b.contextPath;
this.resourceConfig = b.resourceConfig;
this.sslContext = b.sslContext;
this.sslParameters = b.sslParameters;
}

/**
Expand All @@ -233,5 +261,24 @@ public ResourceConfig getResourceConfig() {
public final String getContextPath() {
return contextPath;
}

/**
* Get the deployed application ssl context.
*
* @return the deployed application ssl context.
*/
public Optional<SSLContext> getSslContext() {
return Optional.ofNullable(sslContext);
}

/**
* Get the deployed application ssl parameters.
*
* @return the deployed application ssl parameters.
*/
public Optional<SSLParameters> getSslParameters() {
return Optional.ofNullable(sslParameters);
}

}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -25,6 +25,7 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -34,6 +35,8 @@
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
Expand Down Expand Up @@ -417,7 +420,11 @@ protected Application configure() {
* @since 2.8
*/
protected DeploymentContext configureDeployment() {
return DeploymentContext.builder(configure()).build();
DeploymentContext.Builder contextBuilder = DeploymentContext.builder(configure());
if (getSslContext().isPresent() && getSslParameters().isPresent()) {
contextBuilder.ssl(getSslContext().get(), getSslParameters().get());
}
return contextBuilder.build();
}

/**
Expand Down Expand Up @@ -453,6 +460,34 @@ protected TestContainerFactory getTestContainerFactory() throws TestContainerExc
return testContainerFactory;
}

/**
* Return an optional instance of {@link SSLContext} class.
* <p>
* <p>
* This method is used only once during {@code JerseyTest} instance construction to retrieve the ssl configuration.
* By default the ssl configuration is absent, to enable it please override this method and {@link JerseyTest#getSslParameters()}
* </p>
* </p>
* @return an optional instance of {@link SSLContext} class.
*/
protected Optional<SSLContext> getSslContext() {
return Optional.empty();
}

/**
* Return an optional instance of {@link SSLParameters} class.
* <p>
* <p>
* This method is used only once during {@code JerseyTest} instance construction to retrieve the ssl configuration.
* By default the ssl configuration is absent, to enable it please override this method and {@link JerseyTest#getSslContext()} ()}
* </p>
* </p>
* @return an optional instance of {@link SSLContext} class.
*/
protected Optional<SSLParameters> getSslParameters() {
return Optional.empty();
}

private static synchronized TestContainerFactory getDefaultTestContainerFactory() {

if (defaultTestContainerFactoryClass == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -21,8 +21,10 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLParameters;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.test.DeploymentContext;
Expand Down Expand Up @@ -56,6 +58,17 @@ private GrizzlyTestContainer(final URI baseUri, final DeploymentContext context)
+ TestHelper.zeroPortToAvailablePort(baseUri));
}

if (context.getSslContext().isPresent() && context.getSslParameters().isPresent()) {
SSLParameters sslParameters = context.getSslParameters().get();
this.server = GrizzlyHttpServerFactory.createHttpServer(
this.baseUri, context.getResourceConfig(),
true, new SSLEngineConfigurator(
context.getSslContext().get(), false,
sslParameters.getNeedClientAuth(), sslParameters.getWantClientAuth()),
false);
return;
}

this.server = GrizzlyHttpServerFactory.createHttpServer(this.baseUri, context.getResourceConfig(), false);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -26,6 +26,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLParameters;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.UriBuilder;

Expand All @@ -34,6 +35,7 @@
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;

import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
Expand Down Expand Up @@ -191,8 +193,21 @@ private void instantiateGrizzlyWebServer() {
}
}

boolean secure = false;
SSLEngineConfigurator sslEngineConfigurator = null;
if (deploymentContext.getSslContext().isPresent() && deploymentContext.getSslParameters().isPresent()) {
secure = true;
SSLParameters sslParameters = deploymentContext.getSslParameters().get();
sslEngineConfigurator = new SSLEngineConfigurator(
deploymentContext.getSslContext().get(), false,
sslParameters.getNeedClientAuth(), sslParameters.getWantClientAuth()
);
}

try {
server = GrizzlyHttpServerFactory.createHttpServer(baseUri, (GrizzlyHttpContainer) null, false, null, false);
server = GrizzlyHttpServerFactory.createHttpServer(
baseUri, (GrizzlyHttpContainer) null,
secure, sslEngineConfigurator, false);
context.deploy(server);
} catch (final ProcessingException ex) {
throw new TestContainerException(ex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.test.grizzly.web.ssl;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.Optional;

/**
* Basic GrizzlyWebTestContainerFactory unit tests.
*
* The test contains a server configured with SSL at https://localhost:9998/
* With one way authentication the client will validate the identity of the server with
* the trusted certificates within the trust store of the client. If the server is trusted
* by the client the ssl handshake process will proceed or else the request will fail
*
* @author Hakan Altindag
*/
public class GrizzlyOneWaySslWebTest extends JerseyTest {

private SSLContext serverSslContext;
private SSLParameters serverSslParameters;

@Rule
public final ExpectedException exception = ExpectedException.none();

@Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyTestContainerFactory();
}

@Path("secure")
public static class TestResource {
@GET
public String get() {
return "GET";
}
}

@Override
protected Application configure() {
return new ResourceConfig(TestResource.class);
}

@Override
protected URI getBaseUri() {
return UriBuilder
.fromUri("https://localhost")
.port(getPort())
.build();
}

@Override
protected Optional<SSLContext> getSslContext() {
if (serverSslContext == null) {
serverSslContext = SslUtils.createServerSslContext(true, false);
}

return Optional.of(serverSslContext);
}

@Override
protected Optional<SSLParameters> getSslParameters() {
if (serverSslParameters == null) {
serverSslParameters = new SSLParameters();
serverSslParameters.setNeedClientAuth(false);
}

return Optional.of(serverSslParameters);
}

@Test
public void testGet() {
SSLContext clientSslContext = SslUtils.createClientSslContext(false, true);

Client client = ClientBuilder.newBuilder()
.sslContext(clientSslContext)
.build();

WebTarget target = client.target(getBaseUri()).path("secure");

String s = target.request().get(String.class);
Assert.assertEquals("GET", s);
}

@Test
public void testGetFailsWhenClientDoesNotTrustsServer() {
SSLContext clientSslContext = SslUtils.createClientSslContext(false, false);

Client client = ClientBuilder.newBuilder()
.sslContext(clientSslContext)
.build();

WebTarget target = client.target(getBaseUri()).path("secure");

exception.expect(ProcessingException.class);

target.request().get(String.class);
}

@Test
public void testGetFailsWhenClientExecutesRequestWithoutHavingSslConfigured() {
Client client = ClientBuilder.newClient();

WebTarget target = client.target(getBaseUri()).path("secure");

exception.expect(ProcessingException.class);

target.request().get(String.class);
}

}
Loading