Клиент Apache Wink — протестируйте службу REST с использованием формы аутентификации

Я пытаюсь использовать Wink RestClient для функционального тестирования конечной точки службы Rest. Я использую макеты для модульного тестирования, но я хотел бы функционально протестировать его в качестве потребителя конечной точки.

Я понимаю, что некоторые будут возражать против того, чтобы я называл это конечной точкой REST при использовании аутентификации на основе форм, но это текущая архитектура, которая у меня есть.

Большинство ресурсов, которые я хочу протестировать, являются защищенными ресурсами, а приложение (работающее на Tomcat6) защищено аутентификацией формы. (как в приведенном ниже фрагменте web.xml).

До сих пор я пытался сделать первоначальный вызов незащищенного ресурса, чтобы получить заголовок set-cookie, который содержит JSESSIONID, и использовать этот JSESSIONID в заголовке (через Resource.cookie()) в последующих запросах, но это не дает плодов.

web.xml

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/login.html</form-login-page>
        <form-error-page>/login.html?failure=true</form-error-page>
    </form-login-config>
</login-config>

Мой код Wink RestClient выглядит следующим образом. Все ответы равны 200, но я заметил две вещи: ответ на вызов /j_security_check/ не включает файл cookie jsessionid, а вызов защищенного ресурса сообщил, что у меня произошел сбой входа. Полезная нагрузка для вызова j_security_check была перехвачена непосредственно из предыдущего успешного перехваченного запроса браузера.

ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);

Resource unprotectedResource = restClient.resource( BASE_URL + "/");
unprotectedResource.header( "Accept", "*/*" );
ClientResponse clientResponse = unprotectedResource.get();
String response = clientResponse.getEntity(String.class);

// get jSession ID
String jSessionId = clientResponse.getHeaders().get("set-cookie").get(0);
jSessionId = jSessionId.split(";")[0];
System.out.println(jSessionId);

// create a request to login via j_security_check
Resource loginResource = restClient.resource(BASE_URL + "/j_security_check/");
loginResource.accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
loginResource.header("referer", "http://localhost:8080/contextroot/");
loginResource.cookie( jSessionId );
loginResource.header("Connection", "keep-alive");
loginResource.header("Content-Type", "application/x-www-form-urlencoded");
loginResource.header("Content-Length", "41");

ClientResponse loginResponse = loginResource.post("j_username=*****&j_password=*************");

/*  the loginResponse, as this point, does not have the jsessionid cookie, my browser client does */

Resource protectedResource = restClient.resource(BASE_URL + "/protected/test/");
systemResource.accept("application/json");
systemResource.cookie( jSessionId );

ClientResponse systemResponse = systemResource.get();
response = clientResponse.getEntity(String.class);
System.out.println(response);

Будем очень признательны за любые мысли или опыт использования Wink RestClient для использования ресурсов, защищенных с помощью формы. Я полагаю, что я бы развлекался с другими фреймворками, я слышал о REST-Assured и других, но поскольку приложение использует Wink, а RestClient, похоже, предоставляет мне то, что мне нужно, я решил, что буду придерживаться его.


person rogodeter    schedule 01.03.2013    source источник
comment
Оказывается, j_security_check отвечает сообщением [#302 Временно перемещено]. Когда я перехватываю запрос с помощью сниффера и добавляю файл cookie JSESSIONID к этому перенаправленному запросу, все в порядке. Проблема в том, что я не могу понять это из объекта Wink RestClient (или Resource или Response). Перенаправление происходит за кулисами. Кто-нибудь знает, как указать методу Resource.post() СТОП при перенаправлении или ClientResponse для перехвата перенаправления? Я пока не вижу выхода.   -  person rogodeter    schedule 02.03.2013


Ответы (1)


Нашел проблему и решение

j_security_check отвечал на мой POST-запрос (для аутентификации) с #302/redirect. За этим последовал подмигивающий RestClient, но мой файл cookie JSESSIONID не добавлялся к нему. Это приводило к тому, что ответ (от перенаправленного URL-адреса) содержал заголовок set-cookie с новым заголовком. Мои последующие вызовы, в которые я вставил JSESSIONID из первого вызова, не увенчались успехом, потому что срок действия этого файла cookie истек. Все, что мне нужно было сделать, это указать RestClient НЕ следовать перенаправлениям. Если бы перенаправление было необходимо, я бы создал его самостоятельно, содержащий соответствующий файл cookie.

Chromium и Firefox переносят файл cookie из исходного запроса в перенаправленный запрос, поэтому все в порядке.

Вот некоторый код, который работал у меня, используя JUnit4, RestClient из проекта Apache Wink (и Jackson ObjectMapper)

@Test
public void testGenerateZipEntryName() throws JsonGenerationException, JsonMappingException, IOException
{
    final ObjectMapper mapper = new ObjectMapper();

    final String BASE_URL = "http://localhost:8080/rest";

    // Configure the Rest client
    ClientConfig config = new ClientConfig();
    config.proxyHost("localhost");    // helpful when sniffing traffic
    config.proxyPort(50080);          // helpful when sniffing traffic
    config.followRedirects(false);    // This is KEY for form auth
    RestClient restClient = new RestClient(config);


    // Get an unprotected resource -- to get a JSESSIONID
    Resource resource = restClient.resource( BASE_URL + "/");
    resource.header( "Accept", "*/*" );
    ClientResponse response = resource.get();
    // extract the jSession ID, in a brittle and ugly way
    String jSessId = response.getHeaders().get("set-cookie").get(0).split(";")[0].split("=")[1];


    // Get the login resource *j_security_check*
    resource = restClient.resource(BASE_URL + "/j_security_check");
    resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
    resource.header("Content-Type", "application/x-www-form-urlencoded");
    resource.header("Content-Length", "41");

    // Verify that login resource redirects us
    response = resource.post("j_username=admin&j_password=***********");
    assertTrue( response.getStatusCode() == 302 );


    // Grab a public resource
    resource = restClient.resource(BASE_URL + "/");
    resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
    response = resource.get();
    // verify status of response
    assertTrue( response.getStatusCode() == 200 );


    // Grab a protected resource
    resource = restClient.resource(BASE_URL + "/rest/system");
    resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);

    // Verify resource returned OK
    response = resource.contentType("application/json").accept("*/*").get();
    assertTrue( response.getStatusCode() == 200 );

    // Deserialize body of protected response into domain object for further testing 
    MyObj myObj = mapper.readValue(response.getEntity(String.class), MyObj.class );
    assertTrue( myObj.customerArchived() == false );
}
person rogodeter    schedule 02.03.2013
comment
учитывая нехватку хороших примеров Apache Wink Client, ваши оказались наиболее полезными. - person Perry Tew; 14.05.2016