1

Wink RestClientを使用して、Restサービスエンドポイントで機能テストを実行しようとしています。単体テストにモックを使用していますが、エンドポイントコンシューマーとして機能的にテストしたいと思います。

フォームベースの認証を使用しているときにRESTエンドポイントと呼ぶことに反対する人もいることは理解していますが、それが現在のアーキテクチャです。

テストしたいリソースの大部分は保護されたリソースであり、アプリケーション(Tomcat6で実行されている)はフォーム認証によって保護されています。(以下のweb.xmlスニペットのように)。

これまでに試したのは、保護されていないリソースを最初に呼び出し、JSESSIONIDを含むset-cookieヘッダーを取得し、その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>

WinkRestClientのコードは次のようになります。すべての応答は200ですが、/ j_security_check/への呼び出しからの応答にjsessionidcookieが含まれていないことと、保護されたリソースへの呼び出しでサインインに失敗したことが示されていることに気付きました。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);

WinkRestClientを使用してform-auth-protectedリソースを実行することについての考えや経験をいただければ幸いです。他のフレームワークを楽しませると思います。REST-Assuredなどについて聞いたことがありますが、アプリケーションはWinkを使用し、RestClientが必要なものを提供してくれるようであるため、私はそれに固執すると思いました。

4

1 に答える 1

1

問題と解決策を見つけました

j_security_checkは、(認証のために)POSTリクエストに#302/redirectで応答していました。その後、ウィンクのRestClientが続きましたが、JSESSIONIDCookieが追加されていませんでした。これにより、(リダイレクトされたURLからの)応答に、新しいヘッダーを持つset-cookieヘッダーが含まれていました。最初の呼び出しからJSESSIONIDを挿入した後続の呼び出しは、そのCookieの有効期限が切れたため、失敗しました。私がする必要があるのは、リダイレクトに従わないようにRestClientに指示することだけでした。リダイレクトが必要な場合は、適切なCookieを含めて、自分でリダイレクトを作成します。

ChromiumとFirefoxは、元のリクエストからリダイレクトされたリクエストにCookieを運ぶので、すべて問題ありません。

これは、Apache Winkプロジェクト(およびJackson ObjectMapper)のJUnit4、RestClientを使用して機能したコードです。

@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 );
}
于 2013-03-02T00:13:47.537 に答える