Configure JettyTestContainer com SSL para JerseyTest

Sep 17 2020

Recebi a tarefa de configurar testes de integração para o código da minha equipe. Esses testes exigirão a execução de solicitações HTTPS para endpoints REST implementados em Jersey 2.27. Em minha pesquisa sobre como realizar esse tipo de teste, me deparei com este artigo de Baeldung que me indicou o Jersey Test Framework e os containers de provedor que eles implementaram para esse propósito. Escolhi o container Jetty, pois nosso código estava usando uma instância Jetty 'roll your own' para fazer tudo isso. Comecei a implementação de nossos testes e encontrei dificuldades para configurar SSL para o JettyTestContainer que atenderia às solicitações restantes. Comecei a receber uma IllegalArgumentException declarando que "O esquema de URI deve ser http quando não estiver usando SSL." Não sei como proceder.

Esta é minha aula de teste:

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);
    }
}

Aqui está um RestSuite1:

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

Aqui está meu 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>

Devo observar que, antes de tentar a configuração SSL, consegui alcançar o ponto de extremidade POST / restSuite1 com êxito.

Eu encontrei essa pergunta , mas não parece uma configuração SSL do Grizzly que seria usada em um cenário de JerseyTest.

Eu encontrei esta pergunta , mas parece que está definindo funções de usuário e não uma configuração SSL real.

Então eu encontrei essa pergunta , e a pessoa que a fez parece ter o mesmo problema que eu, porém ninguém nunca respondeu à pergunta.

Por favor ajude!

Respostas

2 Hakan54 Sep 21 2020 at 15:44

Parece que essa opção não está disponível no JerseyTest. Criei uma solicitação pull para adicionar esta opção. Por favor, dê uma olhada aqui:https://github.com/eclipse-ee4j/jersey/pull/4573 Não tenho certeza de quão rápido eles irão aprovar e publicar ...

Eu sei que não era a resposta que você está procurando ... No entanto, se você ainda deseja configurar seu servidor com ssl e testar sua aplicação com https sem esperar até que a solicitação de pull seja aprovada, você pode dar uma olhada no meu projeto github que tem um exemplo básico de teste de um servidor jersey com grizzly sem JerseyTest: Application & IntegrationTest

=============== ATUALIZAÇÃO # 1 20-12-2020 ===============

A solicitação pull foi aprovada, mesclada e liberada. Ele agora está disponível a partir da versão 2.33. Agora é possível fornecer um sslcontext com sslparameters para configurar seu teste de camisa. Um exemplo de configuração seria:

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);
    }
}