diff --git a/CHANGELOG.md b/CHANGELOG.md index abdf5e4fa..e34fcf316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.18b +BUG FIXES: +* Cell Owner URL being persisted without #fragment info. ([#479](https://github.com/personium/personium-core/issues/479)) + ## 1.7.18a BUG FIXES: * 500 Error when Non-Cell URL (incl. Unit URL) is given in p_target param at TokenEndpoint. ([#475](https://github.com/personium/personium-core/issues/475)) diff --git a/pom.xml b/pom.xml index ad1ac07ce..17bcad3d5 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ io.personium personium-core war - 1.7.18a + 1.7.18b personium-core Maven Webapp http://maven.apache.org diff --git a/src/main/java/io/personium/core/utils/HttpClientFactory.java b/src/main/java/io/personium/core/utils/HttpClientFactory.java index 600ef0371..b2910098b 100644 --- a/src/main/java/io/personium/core/utils/HttpClientFactory.java +++ b/src/main/java/io/personium/core/utils/HttpClientFactory.java @@ -16,6 +16,8 @@ */ package io.personium.core.utils; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -25,6 +27,7 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.DnsResolver; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; @@ -34,6 +37,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.impl.conn.SystemDefaultDnsResolver; import org.apache.http.ssl.SSLContextBuilder; /** @@ -44,6 +48,8 @@ public class HttpClientFactory { public static final String TYPE_DEFAULT = "default"; /** Type of HTTP communication.*/ public static final String TYPE_INSECURE = "insecure"; + /** Type name of HTTP client that always connect to .*/ + public static final String TYPE_ALWAYS_LOCAL = "alwayslocal"; /** Connection timeout value.*/ private static final int TIMEOUT = 60000; // 20000; @@ -69,10 +75,50 @@ public static CloseableHttpClient create(final String type) { .setDefaultRequestConfig(config) .useSystemProperties() .build(); - } else if (!TYPE_INSECURE.equalsIgnoreCase(type)) { + } else if (TYPE_INSECURE.equalsIgnoreCase(type)) { + return createInsecure(config); + } else if (TYPE_ALWAYS_LOCAL.equalsIgnoreCase(type)) { + return createAlwaysLocal(config); + } + return null; + + } + private static CloseableHttpClient createAlwaysLocal(RequestConfig config) { + SSLConnectionSocketFactory sf = null; + try { + sf = createInsecureSSLConnectionSocketFactory(); + } catch (Exception e) { return null; } + Registry registry = RegistryBuilder.create() + .register("https", sf) + .register("http", PlainConnectionSocketFactory.INSTANCE) + .build(); + /* Custom DNS resolver */ + DnsResolver dnsResolver = new SystemDefaultDnsResolver() { + @Override + public InetAddress[] resolve(final String host) throws UnknownHostException { + // Always 127.0.0.1 + return new InetAddress[] { InetAddress.getByName("127.0.0.1") }; + } + }; + HttpClientConnectionManager cm = new BasicHttpClientConnectionManager(registry, + null, /* Default ConnectionFactory */ + null, /* Default SchemePortResolver */ + dnsResolver /* Our DnsResolver */ + ); + + + return HttpClientBuilder.create() + .setDefaultRequestConfig(config) + .setConnectionManager(cm) + .useSystemProperties() + .build(); + + + } + private static CloseableHttpClient createInsecure(RequestConfig config) { SSLConnectionSocketFactory sf = null; try { sf = createInsecureSSLConnectionSocketFactory(); @@ -91,6 +137,7 @@ public static CloseableHttpClient create(final String type) { .setConnectionManager(cm) .useSystemProperties() .build(); + } private static SSLConnectionSocketFactory createInsecureSSLConnectionSocketFactory() diff --git a/src/main/java/io/personium/core/utils/UriUtils.java b/src/main/java/io/personium/core/utils/UriUtils.java index d96a104a7..57f0c7a7e 100644 --- a/src/main/java/io/personium/core/utils/UriUtils.java +++ b/src/main/java/io/personium/core/utils/UriUtils.java @@ -237,6 +237,12 @@ public static String convertSchemeFromHttpToLocalUnit(String url) { StringBuilder sb = new StringBuilder(SCHEME_LOCALUNIT); sb.append(":").append(cellName).append(":"); sb.append(uri.getPath()); + if (uri.getQuery() != null) { + sb.append("?").append(uri.getQuery()); + } + if (uri.getFragment() != null) { + sb.append("#").append(uri.getFragment()); + } return sb.toString(); } } diff --git a/src/test/java/io/personium/core/utils/UriUtilsTest.java b/src/test/java/io/personium/core/utils/UriUtilsTest.java index f92007653..c0d078f7f 100644 --- a/src/test/java/io/personium/core/utils/UriUtilsTest.java +++ b/src/test/java/io/personium/core/utils/UriUtilsTest.java @@ -143,6 +143,9 @@ public void convertSchemeFromHttpToLocalUnit_Normal_url_starts_with_uniturl() th assertThat( UriUtils.convertSchemeFromHttpToLocalUnit("https://unit.example/cell/"), is("personium-localunit:/cell/")); + assertThat( + UriUtils.convertSchemeFromHttpToLocalUnit("https://unit.example/cell/#acct"), + is("personium-localunit:/cell/#acct")); } /** @@ -161,6 +164,18 @@ public void convertSchemeFromHttpToLocalUnit_Normal_url_is_fqdn_base() throws Ex assertThat( UriUtils.convertSchemeFromHttpToLocalUnit("http://cell.unit.example/"), is("personium-localunit:cell:/")); + assertThat( + UriUtils.convertSchemeFromHttpToLocalUnit("http://cell.unit.example/#account"), + is("personium-localunit:cell:/#account")); + assertThat( + UriUtils.convertSchemeFromHttpToLocalUnit("http://cell.unit.example/ab/?query=23"), + is("personium-localunit:cell:/ab/?query=23")); + assertThat( + UriUtils.convertSchemeFromHttpToLocalUnit("http://cell.unit.example/ab/?query=23#frag"), + is("personium-localunit:cell:/ab/?query=23#frag")); + assertThat( + UriUtils.convertSchemeFromHttpToLocalUnit("http://cell.unit.example/ab/#frag?query"), + is("personium-localunit:cell:/ab/#frag?query")); } /** * Test convertSchemeFromHttpToLocalUnit(). diff --git a/src/test/java/io/personium/test/jersey/PersoniumTest.java b/src/test/java/io/personium/test/jersey/PersoniumTest.java index b8824876d..10293e201 100644 --- a/src/test/java/io/personium/test/jersey/PersoniumTest.java +++ b/src/test/java/io/personium/test/jersey/PersoniumTest.java @@ -88,10 +88,9 @@ public void start() { } } - @SuppressWarnings("deprecation") @Override public void stop() { - this.server.stop(); + this.server.shutdownNow();; } }; diff --git a/src/test/java/io/personium/test/jersey/cell/AllTests.java b/src/test/java/io/personium/test/jersey/cell/AllTests.java index 74caaf6ee..446de0119 100644 --- a/src/test/java/io/personium/test/jersey/cell/AllTests.java +++ b/src/test/java/io/personium/test/jersey/cell/AllTests.java @@ -20,6 +20,8 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; +import io.personium.test.jersey.unit.UnitUserCellTest; + /** * パッケージ配下のテストケースを全て実行するためのテストスイート. */ diff --git a/src/test/java/io/personium/test/jersey/unit/PerCellSubdomainMode_UnitUserCellTest.java b/src/test/java/io/personium/test/jersey/unit/PerCellSubdomainMode_UnitUserCellTest.java new file mode 100644 index 000000000..8516a481a --- /dev/null +++ b/src/test/java/io/personium/test/jersey/unit/PerCellSubdomainMode_UnitUserCellTest.java @@ -0,0 +1,553 @@ +/** + * 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 io.personium.test.jersey.unit; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.ArrayList; + +import javax.json.Json; +import javax.json.JsonObject; + +import org.apache.commons.io.Charsets; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.json.simple.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.net.HttpHeaders; + +import io.personium.common.auth.token.AbstractOAuth2Token.TokenDsigException; +import io.personium.common.auth.token.AbstractOAuth2Token.TokenParseException; +import io.personium.common.auth.token.AbstractOAuth2Token.TokenRootCrtException; +import io.personium.common.auth.token.Role; +import io.personium.common.auth.token.TransCellAccessToken; +import io.personium.core.PersoniumUnitConfig; +import io.personium.core.auth.AccessContext; +import io.personium.core.auth.OAuth2Helper; +import io.personium.core.model.Cell; +import io.personium.core.model.ModelFactory; +import io.personium.core.rs.PersoniumCoreApplication; +import io.personium.core.utils.HttpClientFactory; +import io.personium.core.utils.UriUtils; +import io.personium.test.categories.Integration; +import io.personium.test.categories.Regression; +import io.personium.test.categories.Unit; +import io.personium.test.jersey.AbstractCase; +import io.personium.test.jersey.PersoniumIntegTestRunner; +import io.personium.test.jersey.PersoniumTest; +import io.personium.test.setup.Setup; +import io.personium.test.unit.core.UrlUtils; +import io.personium.test.utils.CellUtils; +import io.personium.test.utils.DavResourceUtils; +import io.personium.test.utils.Http; +import io.personium.test.utils.TResponse; + +/** + * Test of UnitUser under the condition of Per Cell Subdomain Mode. + */ +@RunWith(PersoniumIntegTestRunner.class) +@Category({Unit.class, Integration.class, Regression.class }) +public class PerCellSubdomainMode_UnitUserCellTest extends PersoniumTest { + + private static Logger log = LoggerFactory.getLogger(PerCellSubdomainMode_UnitUserCellTest.class); + + private static final String UNIT_USER_CELL = "unitusercell"; + private static final String UNIT_USER_ACCOUNT = "UnitUserName"; + private static final String UNIT_USER_ACCOUNT_PASS = "password"; + private static final String CREATE_CELL = "createcell"; + + private static String unitAdminRole; + private static String contentsReaderRole; + private static String contentsAdminRole; + + /** unitUser.issuers in properties. */ + private static String issuersBackup = ""; + private static String urlModeBackup = ""; + + private static String unitUserCellUrl; + private static String unitUserToken = null; + + /** + * Constructor. テスト対象のパッケージをsuperに渡す必要がある + */ + public PerCellSubdomainMode_UnitUserCellTest() { + super(new PersoniumCoreApplication()); + } + + + private static void createUnitUserAccount() { + String accountODataUrl = unitUserCellUrl + "__ctl/Account"; + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { + HttpPost post = new HttpPost(accountODataUrl); + post.addHeader(HttpHeaders.AUTHORIZATION, AbstractCase.BEARER_MASTER_TOKEN); + post.addHeader(io.personium.common.utils.CommonUtils.HttpHeaders.X_PERSONIUM_CREDENTIAL, + UNIT_USER_ACCOUNT_PASS); + String jsonStr = Json.createObjectBuilder().add("Name", UNIT_USER_ACCOUNT).build().toString(); + HttpEntity entity = new StringEntity(jsonStr); + post.setEntity(entity); + client.execute(post); + } catch (Exception e) { + e.printStackTrace(); + } + } + private static void deleteUnitUserAccount() { + // Delete Unit User Account + String accountODataUrl = unitUserCellUrl + "__ctl/Account"; + HttpDelete del = new HttpDelete(accountODataUrl + "(%27" + UNIT_USER_ACCOUNT + "%27)"); + del.addHeader(HttpHeaders.AUTHORIZATION, AbstractCase.BEARER_MASTER_TOKEN); + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)){ + client.execute(del); + } catch (IOException e) { + e.printStackTrace(); + } + } + private static String getUnitUserToken() { + String tokenEndpoint = unitUserCellUrl + "__token"; + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { + HttpPost post = new HttpPost(tokenEndpoint); + post.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); + post.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType()); + StringBuilder sb = new StringBuilder(); + sb.append("grant_type=password&username="); + sb.append(UNIT_USER_ACCOUNT); + sb.append("&password="); + sb.append(UNIT_USER_ACCOUNT_PASS); + sb.append("&p_target="); + sb.append(UrlUtils.unitRoot()); + HttpEntity entity = new StringEntity(sb.toString()); + post.setEntity(entity); + try (CloseableHttpResponse res = client.execute(post)) { + assertEquals(200, res.getStatusLine().getStatusCode()); + JsonObject jo = Json.createReader(new InputStreamReader(res.getEntity().getContent(), Charsets.UTF_8)).readObject(); + return jo.getString(OAuth2Helper.Key.ACCESS_TOKEN); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + private static void deleteUnitAdminRole() { + //RoleUtils.delete(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, unitAdminRole, null); + String roleODataUrl = unitUserCellUrl + "__ctl/Role(%27" + unitAdminRole + "%27)"; + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { + HttpDelete del = new HttpDelete(roleODataUrl); + del.addHeader(HttpHeaders.AUTHORIZATION, AbstractCase.BEARER_MASTER_TOKEN); + client.execute(del); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + private static void linkUuAccountAndUnitAdminRole() { + // LinksUtils.createLinks(UNIT_USER_CELL, Account.EDM_TYPE_NAME, UNIT_USER_ACCOUNT, null, Role.EDM_TYPE_NAME, + // unitAdminRole, null, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_NO_CONTENT); + String roleODataUrl = unitUserCellUrl + "__ctl/Role(Name=%27" + unitAdminRole + "%27)"; + String accountRoleLinkUrl = unitUserCellUrl + "__ctl/Account(%27" + UNIT_USER_ACCOUNT + "%27)/$links/_Role"; + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { + HttpPost post = new HttpPost(accountRoleLinkUrl); + post.addHeader(HttpHeaders.AUTHORIZATION, AbstractCase.BEARER_MASTER_TOKEN); + String jsonStr = Json.createObjectBuilder() + .add("uri", roleODataUrl) + .build().toString(); + HttpEntity entity = new StringEntity(jsonStr); + post.setEntity(entity); + client.execute(post); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + private static void createUnitAdminRole() { +// RoleUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, unitAdminRole, +// null, HttpStatus.SC_CREATED); + String roleODataUrl = unitUserCellUrl + "__ctl/Role"; + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { + HttpPost post = new HttpPost(roleODataUrl); + post.addHeader(HttpHeaders.AUTHORIZATION, AbstractCase.BEARER_MASTER_TOKEN); + String jsonStr = Json.createObjectBuilder().add("Name", unitAdminRole).build().toString(); + HttpEntity entity = new StringEntity(jsonStr); + post.setEntity(entity); + client.execute(post); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Before class. + * @throws Exception Unintended exception in test + */ + @BeforeClass + public static void beforeClass() throws Exception { + // Override issuers in unitconfig. + urlModeBackup = PersoniumUnitConfig.get(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED); + PersoniumUnitConfig.set(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED, + "false"); + issuersBackup = PersoniumUnitConfig.get(PersoniumUnitConfig.UNIT_USER_ISSUERS); + PersoniumUnitConfig.set(PersoniumUnitConfig.UNIT_USER_ISSUERS, + UriUtils.SCHEME_LOCALUNIT + ":" + UNIT_USER_CELL + ":/"); + + // Read role name from AccessContext + Field admin = AccessContext.class.getDeclaredField("ROLE_UNIT_ADMIN"); + admin.setAccessible(true); + unitAdminRole = (String) admin.get(null); + Field contentsReader = AccessContext.class.getDeclaredField("ROLE_CELL_CONTENTS_READER"); + contentsReader.setAccessible(true); + contentsReaderRole = (String) contentsReader.get(null); + Field contentsAdmin = AccessContext.class.getDeclaredField("ROLE_CELL_CONTENTS_ADMIN"); + contentsAdmin.setAccessible(true); + contentsAdminRole = (String) contentsAdmin.get(null); + + + unitUserCellUrl = UriUtils.resolveLocalUnit("personium-localunit:" + UNIT_USER_CELL + ":/"); + + } + + + /** + * After class. + */ + @AfterClass + public static void afterClass() { + + // Restore issuers in unitconfig. + PersoniumUnitConfig.set(PersoniumUnitConfig.UNIT_USER_ISSUERS, + issuersBackup != null ? issuersBackup : ""); // CHECKSTYLE IGNORE + PersoniumUnitConfig.set(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED, urlModeBackup); + } + + /** + * マスタートークンでX_PERSONIUM_UnitUserヘッダを指定すると指定したユニットユーザトークンになることを確認. + */ + @Test + public void マスタートークンでX_PERSONIUM_UnitUserヘッダを指定すると指定したユニットユーザトークンになることを確認() { + // マスタートークンでX-Personium-UnitUserヘッダを指定すると指定した値のOwnerでセルが作成される。 + CellUtils.create(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, unitUserCellUrl, HttpStatus.SC_CREATED); + + // ユニットユーザトークンを使えば取得可能なことを確認 + CellUtils.get(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, unitUserCellUrl, HttpStatus.SC_OK); + + // オーナーが異なるユニットユーザトークン(マスタートークンのヘッダ指定での降格を利用)を使うと削除できないことを確認 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, CREATE_CELL, Setup.OWNER_HMC, HttpStatus.SC_FORBIDDEN); + + // オーナーが一致するユニットユーザトークン(マスタートークンのヘッダ指定での降格を利用)を使うと削除できることを確認 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, CREATE_CELL, unitUserCellUrl, + HttpStatus.SC_NO_CONTENT); + } + + /** + * ユニットユーザートークンでセル作成を行いオーナーが設定されることを確認. + * @throws TokenRootCrtException + * @throws TokenDsigException + * @throws TokenParseException + */ + @Test + public void ユニットユーザートークンでセル作成を行いオーナーが設定されることを確認() throws TokenParseException, TokenDsigException, TokenRootCrtException { + try { + // 本テスト用 Unit User Cell の作成 + CellUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, -1); + // Create Account + createUnitUserAccount(); + // retrieve a Unit User Token + unitUserToken = getUnitUserToken(); + + // + TransCellAccessToken tcToken = TransCellAccessToken.parse(unitUserToken); + String subject = tcToken.getSubject(); + log.info("##TOKEN##"); + log.info("Subject: "+ subject); + log.info("Issuer : "+ tcToken.getSubject()); + log.info("Target : "+ tcToken.getTarget()); + String localunitSubject = UriUtils.convertSchemeFromHttpToLocalUnit(subject); + log.info("Owner Should be : "+ localunitSubject); + + // ユニットユーザートークンを使ってセル作成をする. + // オーナーがユニットユーザー(ここだとuserNameアカウントのURL)になるはず。 + CellUtils.create(CREATE_CELL, unitUserToken, HttpStatus.SC_CREATED); + + Cell cell = ModelFactory.cellFromName(CREATE_CELL); + String owner = cell.getOwnerRaw(); + log.info(" OWNER = " + owner); + assertEquals(localunitSubject, owner); + + + } finally { + // Delete Unit User Account + deleteUnitUserAccount(); + + + // 本テスト用セルの削除 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, CREATE_CELL, -1); + // Delete Unit User Cell for the tests + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, UNIT_USER_CELL, -1); + } + } + + /** + * ユニットユーザートークンでセル作成を行いオーナーとして各種処理が可能なことを確認. + * @throws TokenRootCrtException + * @throws TokenDsigException + * @throws TokenParseException + */ + @Test + public void ユニットユーザートークンでセル作成を行いオーナーとして各種処理が可能なことを確認() throws TokenParseException, TokenDsigException, TokenRootCrtException { + try { + // Creating Unit User Cell for this test case. + CellUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_CREATED); + + // Add Account + // Create Account + createUnitUserAccount(); + // retrieve a Unit User Token + unitUserToken = getUnitUserToken(); + // ユニットユーザートークンを使ってセル作成をする. + // オーナーがユニットユーザー(ここだとuserNameアカウントのURL)になるはず。 + CellUtils.create(CREATE_CELL, unitUserToken, HttpStatus.SC_CREATED); + + // ユニットユーザートークンを使ってセル更新ができることを確認 + CellUtils.update(CREATE_CELL, CREATE_CELL, unitUserToken, + HttpStatus.SC_NO_CONTENT); + + // オーナーが異なるユニットユーザートークン(マスタートークンのヘッダ指定での降格を利用)を使ってセル更新ができないことを確認 + CellUtils.update(CREATE_CELL, CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, + UrlUtils.subjectUrl(UNIT_USER_CELL, "hoge"), HttpStatus.SC_FORBIDDEN); + + // マスタートークンを使ってセル更新ができることを確認 + CellUtils.update(CREATE_CELL, CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, + HttpStatus.SC_NO_CONTENT); + + // ユニットユーザトークンを使えば取得可能なことを確認 + CellUtils.get(CREATE_CELL, unitUserToken, HttpStatus.SC_OK); + + // マスタートークンのオーナーヘッダ指定を使えば取得可能なことを確認 + CellUtils.get(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, + unitUserCellUrl + "#" + UNIT_USER_ACCOUNT, HttpStatus.SC_OK); + + // オーナーが異なるユニットユーザトークン(マスタートークンのヘッダ指定での降格を利用)を使うと取得できないことを確認 + CellUtils.get(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, + UrlUtils.subjectUrl(UNIT_USER_CELL, "hoge"), HttpStatus.SC_FORBIDDEN); + + // ユニットユーザートークンを使ってセル削除ができることを確認 + CellUtils.delete(unitUserToken, CREATE_CELL, HttpStatus.SC_NO_CONTENT); + } finally { + // アカウント削除 + deleteUnitUserAccount(); + + // 本テスト用セルの削除 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, CREATE_CELL, -1); + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, UNIT_USER_CELL, -1); + } + } + + + /** + * ユニットアドミンロールをもつユニットユーザートークンでセル作成を行いオーナーが設定されないことを確認. + */ + @Test + public void ユニットアドミンロールをもつユニットユーザートークンでセル作成を行いオーナーが設定されないことを確認() { + + try { + // 本テスト用セルの作成 + CellUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_CREATED); + + // アカウント追加 + createUnitUserAccount(); + + // Add unitAdminRole + createUnitAdminRole(); + + // linkUnit AdminRole with account + linkUuAccountAndUnitAdminRole(); + + + // 認証(ユニットユーザートークン取得) + unitUserToken = getUnitUserToken(); + + // ユニットユーザートークンを使ってセル作成をするとオーナーがユニットユーザー(ここだとuserNameアカウントのURL)になるはず。 + CellUtils.create(CREATE_CELL, unitUserToken, HttpStatus.SC_CREATED); + + // UnitUserTokenを自作 + TransCellAccessToken tcat = new TransCellAccessToken(UrlUtils.cellRoot(UNIT_USER_CELL), + UrlUtils.subjectUrl(UNIT_USER_CELL, UNIT_USER_ACCOUNT), + UrlUtils.getBaseUrl() + "/", new ArrayList(), null, null); + + // ユニットユーザトークンでは取得できないことを確認 + CellUtils.get(CREATE_CELL, tcat.toTokenString(), HttpStatus.SC_FORBIDDEN); + + // セルのオーナーが見指定のため、マスタートークンのオーナーヘッダ指定を使うと取得不可なことを確認 + CellUtils.get(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, + UrlUtils.subjectUrl(UNIT_USER_CELL, UNIT_USER_ACCOUNT), HttpStatus.SC_FORBIDDEN); + + // オーナーが設定されていないのでマスタートークンのみアクセス可能 + CellUtils.get(CREATE_CELL, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_OK); + } finally { + // ロール削除(BOXに結びつかない) + deleteUnitAdminRole(); + + // アカウント削除 + deleteUnitUserAccount(); + // 本テスト用セルの削除 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, UNIT_USER_CELL, -1); + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, CREATE_CELL, -1); + } + } + + + + + /** + * セルレベルPROPPATCHをユニットユーザトークンで実行可能なことを確認. + * @throws TokenParseException トークンパースエラー + */ + @Test + public void セルレベルPROPPATCHをユニットユーザトークンで実行可能なことを確認() throws TokenParseException { + try { + // 本テスト用セルの作成 + CellUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_CREATED); + // アカウント追加 + createUnitUserAccount(); + // 認証(ユニットユーザートークン取得) + unitUserToken = getUnitUserToken(); + + // アカウントにユニット昇格権限付 + try (CloseableHttpClient client = HttpClientFactory.create(HttpClientFactory.TYPE_ALWAYS_LOCAL)) { +// BasicHttpEntityEnclosingRequest proppatch = new BasicHttpEntityEnclosingRequest("PROPPATCH", unitUserCellUrl); + String ppStr = "\n" + + "\n" + + " \n" + + " \n" + + " account1account2\n" + + " \n" + + " \n" + + "\n"; + HttpEntity entity = new StringEntity(ppStr); + RequestBuilder proppatch = RequestBuilder.create("PROPPATCH") + .setUri(unitUserCellUrl) + .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + unitUserToken) + .addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_XML.getMimeType()) + .addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_XML.getMimeType()) + .setEntity(entity); + try (CloseableHttpResponse res = client.execute(null, proppatch.build())) { + assertEquals(207, res.getStatusLine().getStatusCode()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } finally { + + // アカウント削除 + deleteUnitUserAccount(); + // 本テスト用セルの削除 + CellUtils.delete(AbstractCase.MASTER_TOKEN_NAME, UNIT_USER_CELL, -1); + } + + + } + + /** + * セルレベルPROPPATCHをオーナーの違うユニットユーザトークンでは実行不可なことを確認. + * @throws TokenParseException トークンパースエラー + */ + @Test + @Ignore // UUT promotion setting API invalidation. + public void セルレベルPROPPATCHをオーナーの違うユニットユーザトークンでは実行不可なことを確認() throws TokenParseException { + // UnitUserTokenを自作 + TransCellAccessToken tcat = new TransCellAccessToken(UrlUtils.cellRoot(UNIT_USER_CELL), + Setup.OWNER_HMC, UrlUtils.getBaseUrl() + "/", new ArrayList(), null, null); + + String unitUserToken = tcat.toTokenString(); + + // アカウントにユニット昇格権限付与 + DavResourceUtils.setProppatch(Setup.TEST_CELL1, unitUserToken, + "cell/proppatch-uluut.txt", HttpStatus.SC_FORBIDDEN); + } + + /** + * セルレベルPROPPATCHをユニットローカルユニットユーザトークンで実行可能なことを確認. + * @throws TokenParseException トークンパースエラー + */ + @Test + @Ignore // UUT promotion setting API invalidation. + public void セルレベルPROPPATCHをユニットローカルユニットユーザトークンで実行可能なことを確認() throws TokenParseException { + // アカウントにユニット昇格権限付与 + DavResourceUtils.setProppatch(Setup.TEST_CELL1, AbstractCase.MASTER_TOKEN_NAME, + "cell/proppatch-uluut.txt", HttpStatus.SC_MULTI_STATUS); + + // パスワード認証でのユニット昇格 + TResponse res = Http.request("authnUnit/password-uluut.txt") + .with("remoteCell", Setup.TEST_CELL1) + .with("username", "account1") + .with("password", "password1") + .returns() + .statusCode(HttpStatus.SC_OK); + + JSONObject json = res.bodyAsJson(); + String uluutString = (String) json.get(OAuth2Helper.Key.ACCESS_TOKEN); + + // アカウントにユニット昇格権限付与 + DavResourceUtils.setProppatch(Setup.TEST_CELL1, uluutString, + "cell/proppatch-uluut.txt", HttpStatus.SC_MULTI_STATUS); + } + + /** + * セルレベルPROPPATCHをオーナーが違うユニットローカルユニットユーザトークンで実行不可なことを確認. + * @throws TokenParseException トークンパースエラー + */ + @Test + @Ignore // UUT promotion setting API invalidation. + public void セルレベルPROPPATCHをオーナーが違うユニットローカルユニットユーザトークンで実行不可なことを確認() throws TokenParseException { + // アカウントにユニット昇格権限付与 + DavResourceUtils.setProppatch(Setup.TEST_CELL1, AbstractCase.MASTER_TOKEN_NAME, + "cell/proppatch-uluut.txt", HttpStatus.SC_MULTI_STATUS); + + // パスワード認証でのユニット昇格 + TResponse res = Http.request("authnUnit/password-uluut.txt") + .with("remoteCell", Setup.TEST_CELL1) + .with("username", "account1") + .with("password", "password1") + .returns() + .statusCode(HttpStatus.SC_OK); + + JSONObject json = res.bodyAsJson(); + String uluutString = (String) json.get(OAuth2Helper.Key.ACCESS_TOKEN); + + // アカウントにユニット昇格権限付与 + DavResourceUtils.setProppatch(Setup.TEST_CELL2, uluutString, + "cell/proppatch-uluut.txt", HttpStatus.SC_FORBIDDEN); + } + + +} diff --git a/src/test/java/io/personium/test/jersey/cell/UnitUserCellTest.java b/src/test/java/io/personium/test/jersey/unit/UnitUserCellTest.java similarity index 98% rename from src/test/java/io/personium/test/jersey/cell/UnitUserCellTest.java rename to src/test/java/io/personium/test/jersey/unit/UnitUserCellTest.java index 415dca118..9ca0d991c 100644 --- a/src/test/java/io/personium/test/jersey/cell/UnitUserCellTest.java +++ b/src/test/java/io/personium/test/jersey/unit/UnitUserCellTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.personium.test.jersey.cell; +package io.personium.test.jersey.unit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -86,6 +86,7 @@ public class UnitUserCellTest extends PersoniumTest { /** unitUser.issuers in properties. */ private static String issuersBackup = ""; + private static String urlModeBackup = ""; /** * Constructor. テスト対象のパッケージをsuperに渡す必要がある @@ -101,9 +102,12 @@ public UnitUserCellTest() { @BeforeClass public static void beforeClass() throws Exception { // Override issuers in unitconfig. - issuersBackup = PersoniumUnitConfig.get("io.personium.core.unitUser.issuers"); - PersoniumUnitConfig.set("io.personium.core.unitUser.issuers", - UriUtils.SCHEME_LOCALUNIT + ":/" + UNIT_USER_CELL + "/"); + urlModeBackup = PersoniumUnitConfig.get(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED); + PersoniumUnitConfig.set(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED, + "true"); + issuersBackup = PersoniumUnitConfig.get(PersoniumUnitConfig.UNIT_USER_ISSUERS); + PersoniumUnitConfig.set(PersoniumUnitConfig.UNIT_USER_ISSUERS, + UriUtils.SCHEME_LOCALUNIT + ":" + UNIT_USER_CELL + ":/"); // Read role name from AccessContext Field admin = AccessContext.class.getDeclaredField("ROLE_UNIT_ADMIN"); @@ -123,8 +127,9 @@ public static void beforeClass() throws Exception { @AfterClass public static void afterClass() { // Restore issuers in unitconfig. - PersoniumUnitConfig.set("io.personium.core.unitUser.issuers", + PersoniumUnitConfig.set(PersoniumUnitConfig.UNIT_USER_ISSUERS, issuersBackup != null ? issuersBackup : ""); // CHECKSTYLE IGNORE + PersoniumUnitConfig.set(PersoniumUnitConfig.PATH_BASED_CELL_URL_ENABLED, urlModeBackup); } /** @@ -216,7 +221,7 @@ public static void afterClass() { // 本テスト用 Unit User Cell の作成 CellUtils.create(UNIT_USER_CELL, AbstractCase.MASTER_TOKEN_NAME, HttpStatus.SC_CREATED); - // アカウント追加 + // AddAccount AccountUtils.create(AbstractCase.MASTER_TOKEN_NAME, UNIT_USER_CELL, UNIT_USER_ACCOUNT, UNIT_USER_ACCOUNT_PASS, HttpStatus.SC_CREATED);