Apache Wink Client - Тествайте REST услуга с помощта на формуляр auth

Опитвам се да използвам 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/ не включва бисквитката 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 Moved Temporarily] - Когато прихвана заявката със снифър и добавя бисквитката JSESSIONID към тази пренасочена заявка, всичко е наред. Проблемът е, че изглежда не мога да стигна до това от обекта wink RestClient (или Resource или Response). Пренасочването се случва зад кулисите. Някой знае ли как да инструктира метода Resource.post() да СПРЕ при пренасочване или ClientResponse да прихване пренасочването? Все още не виждам начин.   -  person rogodeter    schedule 02.03.2013


Отговори (1)


Открих проблема и решението

j_security_check отговаряше на моята POST заявка (за удостоверяване) с #302/пренасочване. Това беше последвано от намигването RestClient, но моята бисквитка JSESSIONID не беше добавена към него. Това причиняваше отговорът (от пренасочения URL) да съдържа заглавка set-cookie с нова заглавка. Следващите ми обаждания, в които вмъкнах JSESSIONID от първото обаждане, се провалиха, защото тази бисквитка беше изтекла. Всичко, което трябваше да направя, беше да инструктирам RestClient да НЕ следва пренасочвания. Ако пренасочването беше необходимо, бих го конструирал сам, съдържащ подходящата бисквитка.

Chromium и Firefox пренасят бисквитката от оригиналната заявка към пренасочената заявка, така че всичко е наред.

Ето някакъв код, който работи за мен, използвайки 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