package org.gcube.common.portal; import static org.gcube.common.authorization.client.Constants.authorizationService; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import org.gcube.common.authorization.client.exceptions.ObjectNotFound; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.UserInfo; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.vomanagement.usermanagement.UserManager; import org.gcube.vomanagement.usermanagement.exception.UserManagementSystemException; import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault; import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager; import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; import org.gcube.vomanagement.usermanagement.model.CustomAttributeKeys; import org.gcube.vomanagement.usermanagement.model.Email; import org.gcube.vomanagement.usermanagement.model.GCubeUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.model.Group; import com.liferay.portal.model.VirtualHost; import com.liferay.portal.service.CompanyLocalServiceUtil; import com.liferay.portal.service.LayoutSetLocalServiceUtil; import com.liferay.portal.service.UserLocalServiceUtil; import com.liferay.portal.service.VirtualHostLocalServiceUtil; import com.liferay.portal.util.PortalUtil; /** *
* Clients can obtain the single instance of the {@link PortalContext} by invoking its static method {@link #getConfiguration()}. * The first invocation of the method triggers the initialisation of the instance. * * For documentation see the related WIKI *
* @author Massimiliano Assante (ISTI-CNR) * */ public class PortalContext { private static final Logger _log = LoggerFactory.getLogger(PortalContext.class); public static final String VRE_ID_ATTR_NAME = "gcube-vreid"; public static final String USER_ID_ATTR_NAME = "gcube-userId"; /** * Scope separators used in linear syntax. */ protected static final String SCOPE_SEPARATOR = "/"; private final static String DEFAULT_ROLE = "OrganizationMember"; private static final String CONFIGURATION_FOLDER = "conf"; private static final String INFRA_PROPERTY_FILENAME = "infrastructure.properties"; private static final String GCUBE_DEV__CONTEXT_PROPERTY_FILENAME = "gcube-dev-context.properties"; private static final String DEV_USERNAME_ATTR = "user.username"; private static final String DEV_USER_NAME_ATTR = "user.name"; private static final String DEV_USER_LASTNAME_ATTR = "user.lastname"; private static final String DEV_USER_EMAIL_ATTR = "user.email"; private static final String DEV_SCOPE_ATTR = "development.context"; private static final String DEV_GROUP_NAME_ATTR = "development.groupname"; private static final String DEV_GROUP_ID_ATTR = "development.groupid"; private static final String DEV_TOKEN_ATTR = "user.token"; private static final String DEFAULT_INFRA_NAME = "gcube"; private static final String DEFAULT_VO_NAME = "devsec"; private static final String DEFAULT_GATEWAY_NAME = "D4science Gateway"; private static final String DEFAULT_GATEWAY_EMAIL = "do-not-reply@d4science.org"; private static PortalContext singleton = new PortalContext(); private UserManager userManager; private String infra; private String vos; private PortalContext() { initialize(); } /** * * @return the instance */ public synchronized static PortalContext getConfiguration() { return singleton == null ? new PortalContext() : singleton; } private void initialize() { Properties props = new Properties(); try { StringBuilder sb = new StringBuilder(getCatalinaHome()); sb.append(File.separator) .append(CONFIGURATION_FOLDER) .append(File.separator) .append(INFRA_PROPERTY_FILENAME); String propertyfile = sb.toString(); File propsFile = new File(propertyfile); FileInputStream fis = new FileInputStream(propsFile); props.load( fis); infra = props.getProperty(GCubePortalConstants.INFRASTRUCTURE_NAME); vos = props.getProperty(GCubePortalConstants.SCOPES); userManager = new LiferayUserManager(); } catch(IOException e) { infra = DEFAULT_INFRA_NAME; vos = DEFAULT_VO_NAME; _log.error("infrastructure.properties file not found under $CATALINA_HOME/conf/ dir, setting default infrastructure Name " + infra + " and VO Name " + vos); } _log.info("PortalContext configurator correctly initialized on " + infra); } /** * * @return the infrastructure name in which your client runs */ public String getInfrastructureName() { return this.infra; } /** * * @return the value of the scopes as it is in the property file (a string with comma separated vales) */ public String getVOsAsString() { return this.vos; } /** ** Please note that this method works with AJAX calls only (i.e. XMLHttpRequest to exchange data with a server behind the scenes). * If you use standard http servlet GET or POST to exchange data with a server, you must use Liferay's PortalDelegateServlet feature {@link com.liferay.portal.kernel.servlet.PortalDelegateServlet}. * * For documentation on PortalDelegateServlet @see gCube WIKI PortalDelegateServlet page *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the current user, ornull
if a current user could not be found
* @see {@link GCubeUser}
*/
public GCubeUser getCurrentUser(HttpServletRequest httpServletRequest) {
String userIdNo = httpServletRequest.getHeader(USER_ID_ATTR_NAME);
if (userIdNo != null) {
long userId = -1;
try {
userId = Long.parseLong(userIdNo);
return userManager.getUserById(userId);
} catch (NumberFormatException e) {
_log.error("The userId is not a number -> " + userId);
} catch (Exception e) {
_log.error("Could not read the current userid, either session expired or user not logged in, exception: " + e.getMessage());
}
} else {
if (!isWithinPortal()) {
GCubeUser toReturn = readUserFromPropertyFile();
_log.debug("getCurrentUser devMode into IDE detected, returning testing user: " + toReturn.toString());
return toReturn;
}
}
return null;
}
/**
* * Please note that this method works with Liferay's PortalDelegateServlet feature {@link com.liferay.portal.kernel.servlet.PortalDelegateServlet}. * For documentation on PortalDelegateServlet @see gCube WIKI PortalDelegateServlet page *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the current user, ornull
if a current user could not be found
* @see {@link GCubeUser}
*/
public GCubeUser getCurrentUserPortalDelegateServlet(HttpServletRequest httpServletRequest) {
try {
if (PortalUtil.getUser(httpServletRequest) != null) {
long userId = PortalUtil.getUser(httpServletRequest).getUserId();
return userManager.getUserById(userId);
}
else {
//the user is not logged in or session expired
_log.debug("Can't find the user, session expired or your not using ");
return null;
}
} catch (PortalException | SystemException | UserManagementSystemException | UserRetrievalFault e) {
_log.error("Could not read the current userid, either session expired or user not logged in, exception: " + e.getMessage());
e.printStackTrace();
}
return null;
}
/**
* @param scopeGroupId the liferay groupid number (as String) of the VRE/VO
* @return the scope (context)
*/
public String getCurrentScope(String scopeGroupId) {
if (scopeGroupId != null) {
long groupId = -1;
try {
groupId = Long.parseLong(scopeGroupId);
LiferayGroupManager gm = new LiferayGroupManager();
if (gm.isRootVO(groupId)) {
return SCOPE_SEPARATOR + getInfrastructureName();
} else
return new LiferayGroupManager().getInfrastructureScope(groupId);
} catch (NumberFormatException e) {
_log.error("The groupId is not a number -> " + groupId);
} catch (Exception e) {
_log.error("This groupId does not belong to any group in this portal -> " + groupId);
}
} else {
if (!isWithinPortal()) {
String toReturn = readContextPropertyFile();
_log.debug("getCurrentScope devMode into IDE detected, returning scope: " + toReturn.toString());
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
return toReturn;
}
}
return null;
}
/**
* * Please note that this method works with AJAX calls only (i.e. XMLHttpRequest to exchange data with a server behind the scenes). * If you use standard http servlet GET or POST to exchange data with a server, you must you must handle the infrastructure context information differently. * Please see the following page for further information @see ClientContextLibrary WIKI *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the infrastructure context (scope) */ public String getCurrentScope(HttpServletRequest httpServletRequest) { String scopeGroupId = httpServletRequest.getHeader(VRE_ID_ATTR_NAME); return getCurrentScope(scopeGroupId); } /** ** Please note that this method works with AJAX calls only (i.e. XMLHttpRequest to exchange data with a server behind the scenes). * If you use standard http servlet GET or POST to exchange data with a server, you must you must handle the infrastructure context information differently. * Please see the following page for further information @see ClientContextLibrary WIKI *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the current group name (e.g. devVRE, BioDiversityLab, RStudioLab etc. ) */ public String getCurrentGroupName(HttpServletRequest httpServletRequest) { String groupIdNo = httpServletRequest.getHeader(VRE_ID_ATTR_NAME); if (groupIdNo != null) { long groupId = -1; try { groupId = Long.parseLong(groupIdNo); LiferayGroupManager gm = new LiferayGroupManager(); return gm.getGroup(groupId).getGroupName(); } catch (NumberFormatException e) { _log.error("The groupId is not a number -> " + groupId); } catch (Exception e) { _log.error("This groupId does not belong to any group in this portal -> " + groupId); } } else { if (!isWithinPortal()) { String toReturn = readGroupNamePropertyFile(); _log.debug("getCurrentGroupName devMode into IDE detected, returning group name: " + toReturn.toString()); _log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev"); return toReturn; } } return null; } /** ** Please note that this method works with AJAX calls only (i.e. XMLHttpRequest to exchange data with a server behind the scenes). * If you use standard http servlet GET or POST to exchange data with a server, you must you must handle the infrastructure context information differently. * Please see the following page for further information @see ClientContextLibrary WIKI *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the current group identifier as long */ public long getCurrentGroupId(HttpServletRequest httpServletRequest) { String groupIdNo = httpServletRequest.getHeader(VRE_ID_ATTR_NAME); if (groupIdNo != null) { long groupId = -1; try { groupId = Long.parseLong(groupIdNo); return groupId; } catch (NumberFormatException e) { _log.error("The groupId is not a number -> " + groupId); } catch (Exception e) { _log.error("This groupId does not belong to any group in this portal -> " + groupId); } } else { if (!isWithinPortal()) { long toReturn = readGroupIdPropertyFile(); _log.debug("getCurrentGroup devMode into IDE detected, returning groupid = " + toReturn); _log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev"); return toReturn; } } return -1; } /** ** Returns the gCube authorisation token for the given user *
* @param scope infrastrucure context (scope) * @param userId the GCubeUser user identifier (userId) @see {@link GCubeUser} * @return the Token for the user in the context, ornull
if a token for this user could not be found
*/
public String getCurrentUserToken(String scope, long userId) {
if (isWithinPortal()) {
try {
String username = userManager.getUserById(userId).getUsername();
return getCurrentUserToken(scope, username);
} catch (UserManagementSystemException | UserRetrievalFault e) {
e.printStackTrace();
}
}
else {
String toReturn = readTokenPropertyFile();
_log.debug("getCurrentToken devMode into IDE detected, returning scope: " + toReturn.toString());
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
return toReturn;
}
return null;
}
/**
* * Returns the gCube authorisation token for the given user *
* @param scope infrastrucure context (scope) * @param username the GCubeUser username @see {@link GCubeUser} * @return the Token for the user in the context, ornull
if a token for this user could not be found
*/
public String getCurrentUserToken(String scope, String username) {
String userToken = null;
if (isWithinPortal()) {
try {
ScopeProvider.instance.set(scope);
userToken = authorizationService().resolveTokenByUserAndContext(username, scope);
SecurityTokenProvider.instance.set(userToken);
}
catch (ObjectNotFound ex) {
userToken = generateAuthorizationToken(username, scope);
SecurityTokenProvider.instance.set(userToken);
_log.debug("generateAuthorizationToken OK for " + username + " in scope " + scope);
}
catch (Exception e) {
_log.error("Error while trying to generate token for user " + username + "in scope " + scope);
e.printStackTrace();
return null;
}
} else {
String toReturn = readTokenPropertyFile();
_log.debug("getCurrentToken devMode into IDE detected, returning scope: " + toReturn.toString());
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
return toReturn;
}
return userToken;
}
/**
* @deprecated please use getCurrentUserToken(String scope, String username) or getCurrentUserToken(String scope, long userId)
* * Please note that this method works with AJAX calls only (i.e. XMLHttpRequest to exchange data with a server behind the scenes). *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the Token for the user in the context, ornull
if a token for this user could not be found
*/
public String getCurrentUserToken(HttpServletRequest httpServletRequest) {
String groupIdNo = httpServletRequest.getHeader(VRE_ID_ATTR_NAME);
String userToken = null;
if (groupIdNo != null) {
String scope = getCurrentScope(httpServletRequest);
String username = getCurrentUser(httpServletRequest).getUsername();
try {
ScopeProvider.instance.set(scope);
userToken = authorizationService().resolveTokenByUserAndContext(username, scope);
SecurityTokenProvider.instance.set(userToken);
}
catch (ObjectNotFound ex) {
userToken = generateAuthorizationToken(username, scope);
SecurityTokenProvider.instance.set(userToken);
_log.debug("generateAuthorizationToken OK for " + username + " in scope " + scope);
}
catch (Exception e) {
_log.error("Error while trying to generate token for user " + username + "in scope " + scope);
e.printStackTrace();
return null;
}
} else {
if (isWithinPortal()) {
_log.warn("It seems your app is running in Liferay but not context was set on this (HttpServletRequest) request");
} else {
String toReturn = readTokenPropertyFile();
_log.debug("getCurrentToken devMode into IDE detected, returning scope: " + toReturn.toString());
_log.debug("The PortalBeanLocatorUtil stacktrace (java.lang.Exception) is acceptable in dev");
return toReturn;
}
}
return userToken;
}
/**
*
* @param username
* @param scope
* @throws Exception
*/
private static String generateAuthorizationToken(String username, String scope) {
List