Настройте JettyTestContainer с SSL для JerseyTest

Sep 17 2020

Мне было поручено настроить интеграционные тесты для кода моей команды. Эти тесты потребуют выполнения HTTPS-запросов к конечным точкам REST, реализованным в Jersey 2.27. В своем поиске того, как выполнить такой тест, я наткнулся на эту статью от Baeldung, которая указала мне на Jersey Test Framework и контейнеры провайдеров, которые они реализовали для этой цели. Я выбрал контейнер Jetty, поскольку в нашем коде для всего этого использовался экземпляр Jetty «сверните свой собственный». Я начал реализацию наших тестов и столкнулся с трудностями при настройке SSL для JettyTestContainer, который будет обслуживать остальные запросы. Я начал получать исключение IllegalArgumentException о том, что «Схема URI должна быть http, когда не используется SSL». Я не понимаю, что делать дальше.

Вот мой тестовый класс:

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

Вот RestSuite1:

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

Вот мой 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>

Я должен отметить, что до попытки настройки SSL мне удалось успешно достичь конечной точки POST / restSuite1.

Я нашел этот вопрос , но он не похож на конфигурацию Grizzly SSL, которую можно было бы использовать в сценарии JerseyTest.

Я нашел этот вопрос , но похоже, что это установка ролей пользователей, а не фактическая конфигурация SSL.

Затем я нашел этот вопрос , и у человека, который его задал, похоже, была та же проблема, что и у меня, однако никто так и не ответил на этот вопрос.

Пожалуйста помоги!

Ответы

2 Hakan54 Sep 21 2020 at 15:44

Похоже, эта опция недоступна в JerseyTest. Я создал пул-реквест, чтобы добавить эту опцию. Пожалуйста, посмотрите здесь:https://github.com/eclipse-ee4j/jersey/pull/4573 Я не совсем уверен, как быстро они его утвердят и опубликуют ...

Я знаю, что это был не тот ответ, который вы ищете ... Однако, если вы все еще хотите настроить свой сервер с помощью ssl и протестировать свое приложение с помощью https, не дожидаясь утверждения запроса на перенос, вы можете взглянуть на мой проект github, который имеет базовый пример тестирования сервера jersey с помощью grizzly без JerseyTest: Application & IntegrationTest

=============== ОБНОВЛЕНИЕ №1 20-12-2020 ===============

Запрос на вытягивание был одобрен, объединен и выпущен. Теперь он доступен, начиная с версии 2.33. Теперь можно предоставить sslcontext с параметрами ssl для настройки теста jersey. Пример настройки:

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