Configurar JettyTestContainer con SSL para JerseyTest

Sep 17 2020

Me han encomendado la tarea de configurar pruebas de integración para el código de mi equipo. Estas pruebas requerirán realizar solicitudes HTTPS a los puntos finales REST implementados en Jersey 2.27. En mi búsqueda de cómo realizar este tipo de prueba, me encontré con este artículo de Baeldung que me indicó el marco de prueba de Jersey y los contenedores de proveedores que han implementado para este propósito. Elegí el contenedor Jetty, ya que nuestro código estaba usando una instancia de Jetty 'roll your own' para hacer todo esto. Comencé la implementación de nuestras pruebas y tuve dificultades para configurar SSL para el JettyTestContainer que serviría el resto de las solicitudes. Comencé a recibir una IllegalArgumentException que indicaba que "El esquema de URI debería ser http cuando no se usa SSL". No sé cómo proceder.

Aquí está mi clase de prueba:

public class ProjectTest extends JerseyTest {



 private SSLContext sslCtx;
    
    @Override
    protected Application configure() {
        ResourceConfig conf = new ResourceConfig(Sets.newHashSet(RestSuite1.class));
        SslConfigurator sslConfig = SslConfigurator.newInstance()
            .trustStoreFile()
            .trustStorePassword()
            .keyStoreFile()
            .keyStorePassword()
        sslCtx = sslConfig.createSSLContext();
    }

    @Override
    public URI getBaseUri() {
        return URI.create("https://localhost:1234")
    }

    @Override
    public Client getClient() {
        return ClientBuilder.newBuilder().sslContext(sslCtx).build();
    }

    @Test
    public void test1() throws Exception { 
        String testString = "HelloWorld";
        OurObject oo = target("/restSuite1")
            .request()
            .post(Entity.entity(testString, MediaType.APPLICATION_JSON), String.class);
    }
}

Aquí hay un RestSuite1:

@Path("restSuite1")
@Produces("application/json")
public class RestSuite1 {
    
    @POST
    @Consumes("application/json")
    @Produces("application/json")    
    public String doSomething(String payload) {
        // Do Something 
    }
}

Aquí está mi pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"   
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0   
http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  
  <modelVersion>4.0.0</modelVersion>  
  
  <groupId>com.sample</groupId>  
  <artifactId>my-application1</artifactId>  
  <version>1.0</version>  
  <packaging>war</packaging>  
  
  <name>my war</name>  
  <url>http://some-url.com</url>  
  
  <dependencies>  
    <dependency>  
      <groupId>javax.ws.rs</groupId>  
      <artifactId>javax.ws.rs-api</artifactId>  
      <version>2.1</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.containers</groupId>  
      <artifactId>jersey-container-servlet</artifactId>  
      <version>2.27</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.core</groupId>  
      <artifactId>jersey-server</artifactId>  
      <version>2.27</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.core</groupId>  
      <artifactId>jersey-client</artifactId>  
      <version>2.27</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.inject</groupId>  
      <artifactId>jersey-hk2</artifactId>  
      <version>2.27</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.media</groupId>  
      <artifactId>jersey-media-json-jackson</artifactId>  
      <version>2.27</version>  
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.test-framework</groupId>  
      <artifactId>jersey-test-framework-core</artifactId>  
      <version>2.27</version>
      <scope>test</scope>
    </dependency>
    <dependency>  
      <groupId>org.glassfish.jersey.test-framework.providers</groupId>  
      <artifactId>jersey-test-framework-provider-jetty</artifactId>  
      <version>2.27</version>
      <scope>test</scope>
    </dependency>
    <dependency>  
      <groupId>junit</groupId>  
      <artifactId>junit</artifactId>  
      <version>4.8.2</version>  
      <scope>test</scope>  
    </dependency>  
  </dependencies>  
</project>

Debo señalar que antes de intentar la configuración SSL, pude alcanzar el punto final POST / restSuite1 con éxito.

Encontré esta pregunta , pero no parece una configuración de SSL Grizzly que se usaría en un escenario JerseyTest.

Encontré esta pregunta , pero parece establecer roles de usuario y no una configuración SSL real.

Luego encontré esta pregunta , y la persona que la preguntó parece tener el mismo problema que yo, sin embargo, nadie respondió la pregunta.

¡Por favor ayuda!

Respuestas

2 Hakan54 Sep 21 2020 at 15:44

Parece que esta opción no está disponible en JerseyTest. Creé una solicitud de extracción para agregar esta opción. Por favor, eche un vistazo aquí:https://github.com/eclipse-ee4j/jersey/pull/4573 No estoy muy seguro de qué tan rápido lo aprobarán y publicarán ...

Sé que no era la respuesta que estaba buscando ... Sin embargo, si aún desea configurar su servidor con ssl y probar su aplicación con https sin esperar hasta que se apruebe la solicitud de extracción, puede echar un vistazo a mi proyecto github que tiene un ejemplo básico de probar un servidor de jersey con grizzly sin JerseyTest: Application & IntegrationTest

=============== ACTUALIZACIÓN # 1 20-12-2020 ===============

La solicitud de extracción ha sido aprobada, fusionada y lanzada. Ahora está disponible a partir de la versión 2.33. Ahora es posible proporcionar un sslcontext con sslparameters para configurar su prueba de jersey. Una configuración de ejemplo sería:

public class SecuredJerseyTest extends JerseyTest {

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

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

    @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() {
        SSLContext sslContext = ... // your initialised server sslContext 
        return Optional.of(sslContext);
    }

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

    @Test
    public void testHello() {
        SSLContext sslContext = ... // your initialised client sslContext 

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

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

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