/** * personium.io * Copyright 2014 FUJITSU LIMITED * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.fujitsu.dc.test.jersey.cell.auth; import static org.junit.Assert.assertTrue; import org.apache.http.HttpStatus; import org.junit.After; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import com.fujitsu.dc.core.auth.OAuth2Helper; import com.fujitsu.dc.test.categories.Integration; import com.fujitsu.dc.test.categories.Regression; import com.fujitsu.dc.test.categories.Unit; import com.fujitsu.dc.test.jersey.AbstractCase; import com.fujitsu.dc.test.jersey.DcRunner; import com.fujitsu.dc.test.setup.Setup; import com.fujitsu.dc.test.utils.DavResourceUtils; import com.fujitsu.dc.test.utils.ResourceUtils; import com.fujitsu.dc.test.utils.TResponse; import com.fujitsu.dc.test.utils.UserDataUtils; import com.sun.jersey.test.framework.JerseyTest; /** * $bacth認証のテスト. */ @RunWith(DcRunner.class) @Category({Unit.class, Integration.class, Regression.class }) public class AuthBatchTest extends JerseyTest { static final String TEST_CELL1 = Setup.TEST_CELL1; static final String TEST_CELL2 = Setup.TEST_CELL2; static final String TEST_APP_CELL1 = "schema1"; static final String BOX_NAME = "box1"; static final String COL_NAME = "setodata"; static final String MASTER_TOKEN = AbstractCase.MASTER_TOKEN_NAME; static final String ACL_AUTH_TEST_FILE = "box/acl-authtest.txt"; /** * $batchのバウンダリー. */ public static final String BOUNDARY = "batch_XAmu9BiJJLBa20sRWIq74jp2UlNAVueztqu"; private static final String START_BOUNDARY = "--" + BOUNDARY + "\n"; private static final String END_BOUNDARY = "--" + BOUNDARY + "--"; /** * $batchのリクエストボディ. */ public static final String TEST_BODY = START_BOUNDARY + retrievePostBody("Supplier", "testAutuBatch1") + START_BOUNDARY + retrieveListBody("Supplier") + START_BOUNDARY + retrieveGetBody("Supplier('testAutuBatch1')") + START_BOUNDARY + retrievePutBody("Supplier('testAutuBatch1')") + START_BOUNDARY + retrieveDeleteBody("Supplier('testAutuBatch1')") + END_BOUNDARY; /** * 認証トークン配列番号. */ static final int NO_PRIVILEGE = 0; static final int READ = 1; static final int WRITE = 2; static final int READ_WRITE = 3; static final int EXEC = 4; /** * コンストラクタ. */ public AuthBatchTest() { super("com.fujitsu.dc.core.rs"); } /** * すべてのテストの後に実行する処理. */ @After public void after() { // Setupで設定したACLに戻す DavResourceUtils.setACL(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, COL_NAME, ACL_AUTH_TEST_FILE, BOX_NAME, ""); } /** * 正しい認証情報を使用してすべてのユーザがアクセス可能なコレクションに対して$batchをした場合処理が受付けられること. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 正しい認証情報を使用してすべてのユーザがアクセス可能なコレクションに対して$batchをした場合処理が受付けられること() { // 認証トークン取得 String[] tokens = accountAuth(); // ※本テストではACLをSetupのデフォルト値から変更しているため、実際はREAD_WRITE権限は持っていない。 String token = tokens[READ_WRITE]; // ACL設定 String path = String.format("%s/%s/%s", TEST_CELL1, BOX_NAME, COL_NAME); DavResourceUtils.setACLPrivilegeAllForAllUser(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, path, "none"); // READとWRITE→全てOK TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, token, HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes = new int[] {HttpStatus.SC_CREATED, HttpStatus.SC_OK, HttpStatus.SC_OK, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NO_CONTENT }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res, expectedCodes); } /** * 不正な認証情報を使用してすべてのユーザがアクセス可能なコレクションに対して$batchをした場合処理が受付けられること. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 不正な認証情報を使用してすべてのユーザがアクセス可能なコレクションに対して$batchをした場合処理が受付けられること() { // 認証トークン取得 String invalidToken = "invalid token"; // ACL設定 String path = String.format("%s/%s/%s", TEST_CELL1, BOX_NAME, COL_NAME); DavResourceUtils.setACLPrivilegeAllForAllUser(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, path, "none"); // READとWRITE→全てOK TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, invalidToken, HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes = new int[] {HttpStatus.SC_CREATED, HttpStatus.SC_OK, HttpStatus.SC_OK, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NO_CONTENT }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res, expectedCodes); } /** * 不正な認証情報を使用してすべてのユーザがread可能なコレクションに対して$batchをした場合処理が受付けられること. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 不正な認証情報を使用してすべてのユーザがread可能なコレクションに対して$batchをした場合処理が受付けられること() { // 認証トークン取得 String invalidToken = "invalid token"; // ACL設定 String path = String.format("%s/%s/%s", TEST_CELL1, BOX_NAME, COL_NAME); DavResourceUtils.setACLPrincipalAll(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, path, "<D:read />", ""); // READ→OK WRITE→403 TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, invalidToken, HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes = new int[] {HttpStatus.SC_FORBIDDEN, HttpStatus.SC_OK, HttpStatus.SC_NOT_FOUND, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_FORBIDDEN }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res, expectedCodes); } /** * 不正な認証情報を使用してすべてのユーザがwrite可能なコレクションに対して$batchをした場合処理が受付けられること. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 不正な認証情報を使用してすべてのユーザがwrite可能なコレクションに対して$batchをした場合処理が受付けられること() { // 認証トークン取得 String invalidToken = "invalid token"; // ACL設定 String path = String.format("%s/%s/%s", TEST_CELL1, BOX_NAME, COL_NAME); DavResourceUtils.setACLPrincipalAll(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, path, "<D:write />", ""); // READ→OK WRITE→403 TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, invalidToken, HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes = new int[] {HttpStatus.SC_CREATED, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NO_CONTENT }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res, expectedCodes); } /** * 正しい認証情報を使用してread_write権限があるコレクションに対して$batchをした場合処理が受付けられること. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 正しい認証情報を使用してread_write権限があるコレクションに対して$batchをした場合処理が受付けられること() { // 認証トークン取得 String[] tokens = accountAuth(); // ACL設定 DavResourceUtils.setACL(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, COL_NAME, ACL_AUTH_TEST_FILE, BOX_NAME, ""); // READとWRITE→全てOK TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, tokens[READ_WRITE], HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes = new int[] {HttpStatus.SC_CREATED, HttpStatus.SC_OK, HttpStatus.SC_OK, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NO_CONTENT }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res, expectedCodes); } /** * 不正な認証情報を使用してすべてのユーザがアクセス可能ではないコレクションに対して$batchをした場合401エラーとなること(all-all以外). * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 不正な認証情報を使用してすべてのユーザがアクセス可能ではないコレクションに対して$batchをした場合401エラーとなること() { // 認証トークン取得 String invalidToken = "invalid token"; // ACL設定 DavResourceUtils.setACL(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, COL_NAME, ACL_AUTH_TEST_FILE, BOX_NAME, ""); // READとWRITE→全てOK TResponse res = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, invalidToken, HttpStatus.SC_UNAUTHORIZED); AuthTestCommon.checkAuthenticateHeader(res, OAuth2Helper.Scheme.BEARER, TEST_CELL1); } /** * Boxレベル$batchでのACLアクセス制御の確認. * batchの実行順 * 1.POST(登録) * 2.GET(一覧取得) * 3.GET(取得) * 4.PUT(更新) * 5.DELETE(削除) */ @Test public final void 正しい認証情報を使用して権限が無いコレクションに対して$batchをした場合403エラーとなること() { // 認証トークン取得 String[] tokens = accountAuth(); // ACL設定 DavResourceUtils.setACL(TEST_CELL1, MASTER_TOKEN, HttpStatus.SC_OK, COL_NAME, ACL_AUTH_TEST_FILE, BOX_NAME, ""); // Privilege設定なし→$batchリクエストが403 TResponse res1 = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, tokens[NO_PRIVILEGE], HttpStatus.SC_FORBIDDEN); AuthTestCommon.checkAuthenticateHeaderNotExists(res1); // READのみ→POST/PUT/DELETEが403 // READの確認のため1件登録 String body2 = START_BOUNDARY + retrievePostBody("Supplier", "testAutuBatch1") + END_BOUNDARY; UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, body2, MASTER_TOKEN, -1); TResponse res2 = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, tokens[READ], -1); // 期待するレスポンスコード int[] expectedCodes2 = new int[] {HttpStatus.SC_FORBIDDEN, HttpStatus.SC_OK, HttpStatus.SC_OK, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_FORBIDDEN }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res2, expectedCodes2); // テスト用の1件削除 String body3 = START_BOUNDARY + retrieveDeleteBody("Supplier('testAutuBatch1')") + END_BOUNDARY; UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, body3, MASTER_TOKEN, -1); // WRITEのみ→GETが403 TResponse res3 = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, tokens[WRITE], HttpStatus.SC_ACCEPTED); // 期待するレスポンスコード int[] expectedCodes3 = new int[] {HttpStatus.SC_CREATED, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_NO_CONTENT, HttpStatus.SC_NO_CONTENT }; // レスポンスボディのチェック(ステータス) checkBatchResponseBody(res3, expectedCodes3); // $batchで受け付けない権限のみ→$batchリクエストが403 TResponse res4 = UserDataUtils.batch(TEST_CELL1, BOX_NAME, COL_NAME, BOUNDARY, TEST_BODY, tokens[EXEC], HttpStatus.SC_FORBIDDEN); AuthTestCommon.checkAuthenticateHeaderNotExists(res4); } /** * レスポンスボディのチェック. * @param res TResponse * @param expectedResCodes 期待するレスポンスコード */ private void checkBatchResponseBody(TResponse res, int[] expectedResCodes) { String[] arrResBody = res.getBody().split("\n"); int i = 0; for (String bodyLine : arrResBody) { if (bodyLine.startsWith("HTTP/1.1")) { assertTrue("expected :" + expectedResCodes[i] + " but was :" + bodyLine, bodyLine.indexOf(String.valueOf(expectedResCodes[i])) > -1); i++; } } } private static String retrieveGetBody(String path) { return "Content-Type: application/http\n" + "Content-Transfer-Encoding:binary\n\n" + "GET " + path + "\n" + "Host: host\n\n"; } private static String retrievePostBody(String path, String id) { return "Content-Type: multipart/mixed;" + " boundary=changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb\n" + "Content-Length: 995\n\n" + "--changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb\n" + "Content-Type: application/http\n" + "Content-Transfer-Encoding: binary\n\n" + "POST " + path + " HTTP/1.1\n" + "Host:\n" + "Connection: close\n" + "Accept: application/json\n" + "Content-Type: application/json\n" + "Content-Length: 38\n\n" + "{\"__id\":\"" + id + "\",\"Name\":\"testName\"}\n\n" + "--changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb--\n\n"; } private static String retrieveDeleteBody(String path) { return "Content-Type: multipart/mixed;" + " boundary=changeset_ADUsdsfNmrFSDsd3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBz\n" + "Content-Length: 995\n\n" + "--changeset_ADUsdsfNmrFSDsd3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBz\n" + "Content-Type: application/http\n" + "Content-Transfer-Encoding: binary\n\n" + "DELETE " + path + " HTTP/1.1\n" + "Host: \n" + "Connection: close\n" + "Accept: application/json\n" + "Content-Type: application/json\n" + "If-Match: *\n\n" + "--changeset_ADUsdsfNmrFSDsd3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBz--\n\n"; } private static String retrieveListBody(String path) { return "Content-Type: application/http\n" + "Content-Transfer-Encoding:binary\n\n" + "GET " + path + "\n" + "Host: host\n\n"; } private static String retrievePutBody(String path) { return "Content-Type: multipart/mixed;" + " boundary=changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb\n" + "Content-Length: 995\n\n" + "--changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb\n" + "Content-Type: application/http\n" + "Content-Transfer-Encoding: binary\n\n" + "PUT " + path + " HTTP/1.1\n" + "Host:\n" + "Connection: close\n" + "Accept: application/json\n" + "Content-Type: application/json\n" + "If-Match: *\n" + "Content-Length: 38\n\n" + "{\"Name\":\"testNameUpdated\"}\n\n" + "--changeset_cLzcDEEVPwvvoxS3yJTFTpRauSK_FAQ6mQtyo0aby93-SDP3lAs2A19a2uBb--\n\n"; } private String[] accountAuth() { String[] result = new String[5]; // account1 アクセス権無し result[NO_PRIVILEGE] = ResourceUtils.getMyCellLocalToken(TEST_CELL1, "account1", "password1"); // account2 読み込みのみ result[READ] = ResourceUtils.getMyCellLocalToken(TEST_CELL1, "account2", "password2"); // account3 書き込みのみ result[WRITE] = ResourceUtils.getMyCellLocalToken(TEST_CELL1, "account3", "password3"); // account4 読み書き result[READ_WRITE] = ResourceUtils.getMyCellLocalToken(TEST_CELL1, "account4", "password4"); // account5 サービスの実行 result[EXEC] = ResourceUtils.getMyCellLocalToken(TEST_CELL1, "account5", "password5"); return result; } }