Skip to content

Commit

Permalink
Merge pull request #260 from SawamiWataru/Issue-223-Support-per-Cell-…
Browse files Browse the repository at this point in the history
…FQDN

support per cell fqdn
  • Loading branch information
SawamiWataru authored Oct 12, 2018
2 parents 9850542 + 08919e1 commit 088479e
Show file tree
Hide file tree
Showing 83 changed files with 1,657 additions and 1,126 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
IMPROVEMENTS:
* Upgrade to JAX-RS 2.1.([#237](https://github.com/personium/personium-core/issues/237))
* Make default value of "relayhtmlurl" and "authorizationhtmlurl" configurable in the personium-unit-config.properties file.([#240](https://github.com/personium/personium-core/issues/240))
* Unit-level restriction against two cell properties, relayhtmlurl and authorizationhtmlurl.([#241](https://github.com/personium/personium-core/issues/241))

## 1.6.14
IMPROVEMENTS:
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/io/personium/core/PersoniumCoreException.java
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,10 @@ public static class Misc {
* {0} : File or Directory path in zip
*/
public static final PersoniumCoreException NOT_FOUND_IN_SNAPSHOT = create("PR400-MC-0001");
/**
* Path based CellUrl access is not allowed.
*/
public static final PersoniumCoreException PATH_BASED_ACCESS_NOT_ALLOWED = create("PR400-MC-0002");
/**
* Unexpected URI.
*/
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/io/personium/core/PersoniumUnitConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public class PersoniumUnitConfig {
/** Path key for UnitUrl. */
public static final String UNIT_PATH = KEY_ROOT + "unitPath";

/** URL format to access cell (true: path based(default) false: per cell fqdn). */
public static final String PATH_BASED_CELL_URL_ENABLED = KEY_ROOT + "pathBasedCellUrl.enabled";

/** Plugin path setting key.*/
public static final String PLUGIN_PATH = KEY_ROOT + "plugin.path";

Expand Down Expand Up @@ -671,6 +674,14 @@ public static String getUnitPath() {
return get(UNIT_PATH);
}

/**
* URL format to access cell.
* @return true: path based. false: per cell fqdn.
*/
public static boolean isPathBasedCellUrlEnabled() {
return Boolean.parseBoolean(get(PATH_BASED_CELL_URL_ENABLED));
}

/**
* @return plugin's path setup key.
*/
Expand Down
196 changes: 114 additions & 82 deletions src/main/java/io/personium/core/auth/AccessContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,43 +167,45 @@ private AccessContext(String type, Cell cell, String baseUri, UriInfo uriInfo, I
* @param pCookieAuthValue Value specified for p_cookie in cookie
* @param cell Accessing Cell
* @param baseUri accessing baseUri
* @param host The value of Host in the request header
* @param headerHost The value of Host in the request header
* @param xPersoniumUnitUser X-Personium-UnitUser header
* @return Generated AccessContext object
*/
public static AccessContext create(String authzHeaderValue,
UriInfo requestURIInfo, String pCookiePeer, String pCookieAuthValue,
Cell cell, String baseUri, String host, String xPersoniumUnitUser) {
Cell cell, String baseUri, String headerHost, String xPersoniumUnitUser) {
if (authzHeaderValue == null) {
if (pCookiePeer == null || 0 == pCookiePeer.length()) {
return new AccessContext(TYPE_ANONYMOUS, cell, baseUri, requestURIInfo);
}
//Cookie authentication
//Get decrypted value of cookie value
if (null == pCookieAuthValue) {
return new AccessContext(
TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.cookieAuthError);
}
// Cookie related processing requires no port number.
String decodedCookieValue;
try {
if (null == pCookieAuthValue) {
return new AccessContext(
TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.cookieAuthError);
}
String decodedCookieValue = LocalToken.decode(pCookieAuthValue,
UnitLocalUnitUserToken.getIvBytes(
AccessContext.getCookieCryptKey(requestURIInfo.getBaseUri())));
int separatorIndex = decodedCookieValue.indexOf("\t");
String peer = decodedCookieValue.substring(0, separatorIndex);
//Obtain authorizationHeader equivalent token from information in cookie
String authToken = decodedCookieValue.substring(separatorIndex + 1);
if (pCookiePeer.equals(peer)) {
//Generate appropriate AccessContext with recursive call.
return create(OAuth2Helper.Scheme.BEARER + " " + authToken,
requestURIInfo, null, null, cell, baseUri, host, xPersoniumUnitUser);
} else {
return new AccessContext(
TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.cookieAuthError);
}
String nonPortHost = headerHost.split(":")[0];
decodedCookieValue = LocalToken.decode(pCookieAuthValue,
UnitLocalUnitUserToken.getIvBytes(AccessContext.getCookieCryptKey(nonPortHost)));
} catch (TokenParseException e) {
return new AccessContext(
TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.cookieAuthError);
}
int separatorIndex = decodedCookieValue.indexOf("\t");
String peer = decodedCookieValue.substring(0, separatorIndex);
//Obtain authorizationHeader equivalent token from information in cookie
String authToken = decodedCookieValue.substring(separatorIndex + 1);
if (pCookiePeer.equals(peer)) {
//Generate appropriate AccessContext with recursive call.
return create(OAuth2Helper.Scheme.BEARER + " " + authToken,
requestURIInfo, null, null, cell, baseUri, headerHost, xPersoniumUnitUser);
} else {
return new AccessContext(
TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.cookieAuthError);
}
}

//TODO V1.1 Here is the part that can be cached. You can get it from the cache here.
Expand All @@ -216,7 +218,8 @@ public static AccessContext create(String authzHeaderValue,

} else if (authzHeaderValue.startsWith(OAuth2Helper.Scheme.BEARER)) {
//OAuth 2.0 authentication
return createBearerAuthz(authzHeaderValue, cell, baseUri, requestURIInfo, host, xPersoniumUnitUser);
return createBearerAuthz(authzHeaderValue, cell, headerHost, baseUri,
requestURIInfo, headerHost, xPersoniumUnitUser);
}
return new AccessContext(TYPE_INVALID, cell, baseUri, requestURIInfo, InvalidReason.authenticationScheme);
}
Expand All @@ -232,7 +235,7 @@ public static AccessContext create(String authzHeaderValue,
public static AccessContext createForWebSocket(
String accessToken, Cell cell, String baseUri, String host) {
String bearerAccessToken = OAuth2Helper.Scheme.BEARER_CREDENTIALS_PREFIX + accessToken;
return createBearerAuthz(bearerAccessToken, cell, baseUri, null, host, null);
return createBearerAuthz(bearerAccessToken, cell, host, baseUri, null, host, null);
}

/**
Expand Down Expand Up @@ -592,14 +595,14 @@ public void throwInvalidTokenException(AcceptableAuthScheme allowedAuthScheme) {

/**
* Generate the key for token encryption / decryption at the time of cookie authentication.
* @param uri request URI
* @param host request host
* @return Key used for encryption / decryption
*/
public static String getCookieCryptKey(URI uri) {
public static String getCookieCryptKey(String host) {
//Because PCS is stateless access, it is difficult to change the key for each user,
//Generate a key based on the host name of URI.
//Process the host name.
return uri.getHost().replaceAll("[aiueo]", "#");
return host.replaceAll("[aiueo]", "#");
}

/**
Expand Down Expand Up @@ -671,7 +674,7 @@ private static AccessContext createBasicAuthz(String authzHeaderValue, Cell cell
* @return Generated AccessContext object
*/
private static AccessContext createBearerAuthz(String authzHeaderValue, Cell cell,
String baseUri, UriInfo uriInfo, String host, String xPersoniumUnitUser) {
String requestURIHost, String baseUri, UriInfo uriInfo, String host, String xPersoniumUnitUser) {
// Bearer
//If the value of the authentication token does not start with [Bearer], it is determined to be an invalid token
if (!authzHeaderValue.startsWith(OAuth2Helper.Scheme.BEARER_CREDENTIALS_PREFIX)) {
Expand Down Expand Up @@ -750,62 +753,9 @@ private static AccessContext createBearerAuthz(String authzHeaderValue, Cell cel
return ret;
} else {
TransCellAccessToken tca = (TransCellAccessToken) tk;

//In the case of TCAT, check the possibility of being a unit user token
//TCAT is unit user token Condition 1: Target is your own unit.
//TCAT is unit user token Condition 2: Issuer is UnitUserCell which exists in the setting.
if (tca.getTarget().equals(baseUri) && PersoniumUnitConfig.checkUnitUserIssuers(tca.getIssuer(), baseUri)) {
//Processing unit user tokens
ret.accessType = TYPE_UNIT_USER;
ret.subject = tca.getSubject();
ret.issuer = tca.getIssuer();

//Take role information and if you have unit admin roll, promote to unit admin.
List<Role> roles = tca.getRoles();
Role unitAdminRole = new Role(ROLE_UNIT_ADMIN, Box.DEFAULT_BOX_NAME, null, tca.getIssuer());
String unitAdminRoleUrl = unitAdminRole.createUrl();
Role cellContentsReaderRole = new Role(ROLE_CELL_CONTENTS_READER, Box.DEFAULT_BOX_NAME,
null, tca.getIssuer());
String cellContentsReaderUrl = cellContentsReaderRole.createUrl();
Role cellContentsAdminRole = new Role(ROLE_CELL_CONTENTS_ADMIN, Box.DEFAULT_BOX_NAME,
null, tca.getIssuer());
String cellContentsAdminUrl = cellContentsAdminRole.createUrl();

String unitUserRole = null;
for (Role role : roles) {
String roleUrl = role.createUrl();
if (unitAdminRoleUrl.equals(roleUrl)) {
if (xPersoniumUnitUser == null) {
// If there is no X-Personium-UnitUser header, UnitAdmin
ret = new AccessContext(TYPE_UNIT_ADMIN, cell, baseUri, uriInfo);
} else {
// If there is an X-Personium-UnitUser header, UnitUser
ret.subject = xPersoniumUnitUser;
}
} else if (cellContentsReaderUrl.equals(roleUrl) && unitUserRole == null) {
// If roles are not set, set the CellContentsReader role.
// To preferentially set the CellContentsAdmin role.
unitUserRole = ROLE_CELL_CONTENTS_READER;
} else if (cellContentsAdminUrl.equals(roleUrl)) {
// Set the CellContentsAdmin role.
unitUserRole = ROLE_CELL_CONTENTS_ADMIN;
}
}
ret.unitUserRole = unitUserRole;

//Unit user token does not concern schema authentication, so return here
ret = createAccessContext(cell, requestURIHost, baseUri, uriInfo, xPersoniumUnitUser, tca);
if (TYPE_UNIT_USER.equals(ret.accessType)) {
return ret;
} else if (cell == null) {
//Because only the master token and the unit user token allow tokens with Cell empty at unit level, treat them as invalid tokens.
throw PersoniumCoreException.Auth.UNITUSER_ACCESS_REQUIRED;
} else {
//TCAT processing
ret.accessType = TYPE_TRANS;
ret.subject = tca.getSubject();
ret.issuer = tca.getIssuer();

//Obtaining the Role corresponding to the token
ret.roles = cell.getRoleListHere((TransCellAccessToken) tk);
}
}
ret.schema = tk.getSchema();
Expand Down Expand Up @@ -886,4 +836,86 @@ private static String getRealm(String baseUri, Cell cellobj) {
return realm;
}

/**
* Creates and returns AccessContext object by TransCellAccesToken.
* @param cell Accessing Cell
* @param requestURIHost
* @param baseUri accessing baseUri
* @param uriInfo uri info
* @param xPersoniumUnitUser X-Personium-UnitUser header
* @param tca based token
* @return Generated AccessContext object
*/
private static AccessContext createAccessContext(Cell cell, String requestURIHost,
String baseUri, UriInfo uriInfo, String xPersoniumUnitUser, TransCellAccessToken tca) {
AccessContext ret = new AccessContext(null, cell, baseUri, uriInfo);

//In the case of TCAT, check the possibility of being a unit user token
//TCAT is unit user token Condition 1: Target is your own unit.
//TCAT is unit user token Condition 2: Issuer is UnitUserCell which exists in the setting.

String escapedBaseUri = baseUri;
if (requestURIHost.contains(".")) {
String cellName = requestURIHost.split("\\.")[0];
escapedBaseUri = baseUri.replaceFirst(cellName + "\\.", "");
}

if ((tca.getTarget().equals(baseUri) || tca.getTarget().equals(escapedBaseUri))
&& (PersoniumUnitConfig.checkUnitUserIssuers(tca.getIssuer(), baseUri)
|| PersoniumUnitConfig.checkUnitUserIssuers(tca.getIssuer(), escapedBaseUri))) {
//Processing unit user tokens
ret.accessType = TYPE_UNIT_USER;
ret.subject = tca.getSubject();
ret.issuer = tca.getIssuer();

//Take role information and if you have unit admin roll, promote to unit admin.
List<Role> roles = tca.getRoles();
Role unitAdminRole = new Role(ROLE_UNIT_ADMIN, Box.DEFAULT_BOX_NAME, null, tca.getIssuer());
String unitAdminRoleUrl = unitAdminRole.createUrl();
Role cellContentsReaderRole = new Role(ROLE_CELL_CONTENTS_READER, Box.DEFAULT_BOX_NAME,
null, tca.getIssuer());
String cellContentsReaderUrl = cellContentsReaderRole.createUrl();
Role cellContentsAdminRole = new Role(ROLE_CELL_CONTENTS_ADMIN, Box.DEFAULT_BOX_NAME,
null, tca.getIssuer());
String cellContentsAdminUrl = cellContentsAdminRole.createUrl();

String unitUserRole = null;
for (Role role : roles) {
String roleUrl = role.createUrl();
if (unitAdminRoleUrl.equals(roleUrl)) {
if (xPersoniumUnitUser == null) {
// If there is no X-Personium-UnitUser header, UnitAdmin
ret = new AccessContext(TYPE_UNIT_ADMIN, cell, baseUri, uriInfo);
} else {
// If there is an X-Personium-UnitUser header, UnitUser
ret.subject = xPersoniumUnitUser;
}
} else if (cellContentsReaderUrl.equals(roleUrl) && unitUserRole == null) {
// If roles are not set, set the CellContentsReader role.
// To preferentially set the CellContentsAdmin role.
unitUserRole = ROLE_CELL_CONTENTS_READER;
} else if (cellContentsAdminUrl.equals(roleUrl)) {
// Set the CellContentsAdmin role.
unitUserRole = ROLE_CELL_CONTENTS_ADMIN;
}
}
ret.unitUserRole = unitUserRole;

//Unit user token does not concern schema authentication, so return here
return ret;
} else if (cell == null) {
//Because only the master token and the unit user token allow tokens with Cell empty at unit level, treat them as invalid tokens.
throw PersoniumCoreException.Auth.UNITUSER_ACCESS_REQUIRED;
} else {
//TCAT processing
ret.accessType = TYPE_TRANS;
ret.subject = tca.getSubject();
ret.issuer = tca.getIssuer();

//Obtaining the Role corresponding to the token
ret.roles = cell.getRoleListHere(tca);
return ret;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
String method = requestContext.getMethod();
MultivaluedMap<String, String> headers = requestContext.getHeaders();

// Info log.
requestLog(method, requestContext.getUriInfo().getRequestUri().toString());
log.debug("Reqeust Headers");
// Debug log.
log.debug("== Reqeust Headers");
if (headers != null) {
for (String key : headers.keySet()) {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
}
}
String cellName = path;
Cell cell = ModelFactory.cell(cellName);
Cell cell = ModelFactory.cellFromName(cellName);
if (cell != null) {
CellLockManager.STATUS lockStatus = CellLockManager.getCellStatus(cell.getId());
// If the lock status of Cell is "export", "import", do not allow access.
Expand Down
Loading

0 comments on commit 088479e

Please sign in to comment.