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.portlet.RenderRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.codec.binary.StringUtils; 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.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 static final String REGEX_ISNUMBER = "\\d+"; private final static String DEFAULT_ROLE = "OrganizationMember"; public static final String CONFIGURATION_FOLDER = "conf"; public 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; userManager = new LiferayUserManager(); _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 call the method PortalContext#setUserInSession in your portlet doView method. * *
* * @param httpServletRequest the {@link HttpServletRequest} object * @return the current user, ornull
if a current user could not be found or session expired
* @see {@link GCubeUser}
*/
public GCubeUser getCurrentUser(HttpServletRequest httpServletRequest) {
String userIdNo = httpServletRequest.getHeader(USER_ID_ATTR_NAME);
long userId = -1;
if (userIdNo != null && userIdNo.matches(REGEX_ISNUMBER)) {
try {
_log.debug("The userIdNo is " + userIdNo);
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 from header param, 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;
} else { //must be a custom servlet
try {
HttpSession session = httpServletRequest.getSession(false);
userId = (long) session.getAttribute(USER_ID_ATTR_NAME);
_log.debug("read the current userid from the http session userId: " + userId + " sessionid="+session.getId());
return userManager.getUserById(userId);
} catch (Exception e) {
_log.error("Could not read the current userid from the http session, either session expired or user not logged in, exception: " + e.getMessage());
return null;
}
}
}
return null;
}
/**
* * This method sets the current userid in the session so that it is possible to get the current user in custom servlets of the same WAR. * Must be added in Portlet's doView() method before dispatching the request. *
* * @param request the portlet {@link RenderRequest} object */ public static void setUserInSession(RenderRequest request) { long userId = Long.parseLong(request.getRemoteUser()); HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(request); HttpSession session = httpServletRequest.getSession(); _log.debug("HttpSession#setUserInSession, set userId: " + userId + " sessionid="+session.getId()); session.setAttribute(USER_ID_ATTR_NAME, userId); } /** * @param scopeGroupId the liferay groupid number (as String) of the VRE/VO * @return the scope (context) */ public String getCurrentScope(String scopeGroupId) { if (scopeGroupId != null && scopeGroupId.matches(REGEX_ISNUMBER)) { 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 && groupIdNo.matches(REGEX_ISNUMBER)) { 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 && groupIdNo.matches(REGEX_ISNUMBER)) { 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 token: " + 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 token: " + 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 && groupIdNo.matches(REGEX_ISNUMBER)) {
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* read the portal application token valid in the root Virtual Organisation into a property file *
* @return the portal application token valid in the root Virtual Organisation ornull
if the token could not be found
*/
public static String getPortalApplicationToken() {
//get the portles to look for from the property file
Properties props = new Properties();
String toReturn = "";
try {
String propertyfile = getCatalinaHome() + File.separator + "conf" + File.separator + "gcube-data.properties";
File propsFile = new File(propertyfile);
FileInputStream fis = new FileInputStream(propsFile);
props.load( fis);
toReturn = props.getProperty(GCubePortalConstants.PORTAL_APPLICATION_TOKEN);
}
//catch exception in case properties file does not exist
catch(IOException e) {
toReturn = null;
_log.error("gcube-data.properties file or portal app token not found under $CATALINA_HOME/conf dir, please add the property and or a valid token: " + GCubePortalConstants.PORTAL_APPLICATION_TOKEN);
return toReturn;
}
return toReturn;
}
/**
* * read the IC Proxy endpoint from a property file, IC Proxy is needed to query the Information System via REST * e.g. http://dev.d4science.org:8080/icproxy/gcube/service *
* @return the IC Proxy endpoint ornull
if the IC Proxy could not be found
*/
public static String getICProxyEndPoint() {
//get the portles to look for from the property file
Properties props = new Properties();
String toReturn = "";
try {
String propertyfile = getCatalinaHome() + File.separator + "conf" + File.separator + "gcube-data.properties";
File propsFile = new File(propertyfile);
FileInputStream fis = new FileInputStream(propsFile);
props.load( fis);
toReturn = props.getProperty(GCubePortalConstants.ICPROXY_ENDPOINT_URL);
}
//catch exception in case properties file does not exist
catch(IOException e) {
toReturn = null;
_log.error("gcube-data.properties file or portal app token not found under $CATALINA_HOME/conf dir, please add the property and or a valid token: " + GCubePortalConstants.PORTAL_APPLICATION_TOKEN);
return toReturn;
}
return toReturn;
}
/**
* read the sender (from) email address for notifications name from a property file and returns it
* @deprecated use getSenderEmail(HttpServletRequest request)
*/
@Deprecated
public String getSenderEmail() {
//get the portles to look for from the property file
Properties props = new Properties();
String toReturn = "";
try {
String propertyfile = getCatalinaHome() + File.separator + "conf" + File.separator + "gcube-data.properties";
File propsFile = new File(propertyfile);
FileInputStream fis = new FileInputStream(propsFile);
props.load( fis);
toReturn = props.getProperty(GCubePortalConstants.SENDER_EMAIL);
}
//catch exception in case properties file does not exist
catch(IOException e) {
toReturn = DEFAULT_GATEWAY_EMAIL;
_log.error("gcube-data.properties file not found under $CATALINA_HOME/conf dir, returning default Email" + toReturn);
return toReturn;
}
_log.debug("Returning SENDER_EMAIL: " + toReturn );
return toReturn;
}
/**
* for development purposes only
*/
protected static GCubeUser readUserFromPropertyFile() {
Properties props = new Properties();
try {
StringBuilder sb = new StringBuilder(getGCubeDevHome());
sb.append(File.separator)
.append(GCUBE_DEV__CONTEXT_PROPERTY_FILENAME);
String propertyfile = sb.toString();
File propsFile = new File(propertyfile);
FileInputStream fis = new FileInputStream(propsFile);
props.load( fis);
long userId = -1;
String username = props.getProperty(DEV_USERNAME_ATTR);
String email = props.getProperty(DEV_USER_EMAIL_ATTR);
String firstName = props.getProperty(DEV_USER_NAME_ATTR);
String middleName = "";
String lastName = props.getProperty(DEV_USER_LASTNAME_ATTR);
String fullname = firstName + lastName;
long registrationDate = -1;
String userAvatarId = "-1";
boolean male = true;
String jobTitle = "TestingAccount";
List