From 9e3782d4c8cdda2589a4af21b2c1bf3a99203b3b Mon Sep 17 00:00:00 2001 From: Massimiliano Assante Date: Fri, 17 Jan 2020 16:58:07 +0100 Subject: [PATCH] moved the remove from JCR and LDAP here with ecent onBeforeUserDelete --- README.md | 2 +- pom.xml | 11 +- .../thread/RemoveUserFromJCR.java | 79 +++++++++ .../thread/RemovedUserAccountThread.java | 61 +++++++ .../thread/RemovedUserFromLDAPThread.java | 152 ++++++++++++++++++ .../gcube/portal/usersaccount/Constants.java | 7 + .../MyCreateUserAccountListener.java | 46 ++++-- 7 files changed, 343 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/gcube/portal/removeaccount/thread/RemoveUserFromJCR.java create mode 100644 src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserAccountThread.java create mode 100644 src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserFromLDAPThread.java create mode 100644 src/main/java/org/gcube/portal/usersaccount/Constants.java diff --git a/README.md b/README.md index c4f63e7..15ca1ba 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # gCube System - User Registration Hook -This component is a Liferay 6.2.6 CE Hook which intercepts new user accounts creation and performs the related Workspace actions (on sHub and LDAP) +This component is a Liferay 6.2.6 CE Hook which intercepts new user accounts creation and removal and performs the related Workspace actions (on sHub and LDAP) * The source code is present in the src folder. diff --git a/pom.xml b/pom.xml index 091d93a..1a58d2c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,12 +15,12 @@ war user-registration-hook Hook 2.0.0-SNAPSHOT - + scm:git:https://code-repo.d4science.org/gCubeSystem/user-registration-hook.git scm:git:https://code-repo.d4science.org/gCubeSystem/user-registration-hook.git https://code-repo.d4science.org/gCubeSystem/user-registration-hook - + 6.2.5 6.2.10.12 /Users/massi/portal/liferay-portal-6.2-ce-ga6/deploy @@ -39,8 +39,13 @@ - + + + org.gcube.core + common-encryption + provided + org.gcube.common storagehub-client-library diff --git a/src/main/java/org/gcube/portal/removeaccount/thread/RemoveUserFromJCR.java b/src/main/java/org/gcube/portal/removeaccount/thread/RemoveUserFromJCR.java new file mode 100644 index 0000000..d72b6bd --- /dev/null +++ b/src/main/java/org/gcube/portal/removeaccount/thread/RemoveUserFromJCR.java @@ -0,0 +1,79 @@ +package org.gcube.portal.removeaccount.thread; + +import static org.gcube.common.authorization.client.Constants.authorizationService; + +import java.util.ArrayList; +import java.util.List; + +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.portal.PortalContext; +import org.gcube.common.storagehub.client.dsl.StorageHubClient; +import org.gcube.portal.usersaccount.Constants; +import org.gcube.vomanagement.usermanagement.GroupManager; +import org.gcube.vomanagement.usermanagement.RoleManager; +import org.gcube.vomanagement.usermanagement.UserManager; +import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager; +import org.gcube.vomanagement.usermanagement.model.GCubeRole; +import org.gcube.vomanagement.usermanagement.model.GCubeUser; + +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; + +/** + * + * @author Massimiliano Assante ISTI-CNR + * + */ +public class RemoveUserFromJCR { + private static Log _log = LogFactoryUtil.getLog(RemoveUserFromJCR.class); + + private String username2Delete; + private GroupManager gm; + private UserManager uMan; + private RoleManager rm; + + public RemoveUserFromJCR(String username2Delete, GroupManager gm, UserManager uMan) { + this.username2Delete = username2Delete; + this.gm = gm; + this.uMan = uMan; + this.rm = new LiferayRoleManager(); + } + + public boolean remove() { + try { + _log.debug("in RemoveUserFromJCR remove() for " + username2Delete ); + //get the super user + String infraContext = "/"+PortalContext.getConfiguration().getInfrastructureName(); + long groupId = gm.getGroupIdFromInfrastructureScope(infraContext); + long roleId = rm.getRoleId(Constants.AUTORISED_INFRA_ROLE, groupId); + List users = uMan.listUsersByGroupAndRole(groupId, roleId); + if (users.isEmpty()) { + _log.error("Cannot delete the user: there is no user having role " + Constants.AUTORISED_INFRA_ROLE + " on context: " + infraContext); + return false; + } + else { + GCubeUser theAdmin = users.get(0); + String adminUsername = theAdmin.getUsername(); + String theAdminToken = PortalContext.getConfiguration().getCurrentUserToken(infraContext, adminUsername); + List theAdminRoles = rm.listRolesByUserAndGroup(theAdmin.getUserId(), groupId); + List rolesString = new ArrayList(); + for (GCubeRole gCubeRole : theAdminRoles) { + rolesString.add(gCubeRole.getRoleName()); + } + authorizationService().setTokenRoles(theAdminToken, rolesString); + SecurityTokenProvider.instance.set(theAdminToken); + _log.debug("Autorising drop workspace with infra manager token of " + theAdminToken); + StorageHubClient shc = new StorageHubClient(); + _log.debug("BEFORE stohub.deleteUserAccount " + username2Delete); + shc.deleteUserAccount(username2Delete); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + _log.error("Could not delete " + username2Delete + " from JCR an error occurred on the service"); + return false; + } + } + + +} diff --git a/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserAccountThread.java b/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserAccountThread.java new file mode 100644 index 0000000..2e2aeee --- /dev/null +++ b/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserAccountThread.java @@ -0,0 +1,61 @@ +package org.gcube.portal.removeaccount.thread; + +import java.util.List; + +import javax.portlet.PortletPreferences; + +import org.gcube.common.portal.PortalContext; +import org.gcube.common.portal.mailing.EmailNotification; +import org.gcube.portal.usersaccount.Constants; +import org.gcube.vomanagement.usermanagement.GroupManager; +import org.gcube.vomanagement.usermanagement.RoleManager; +import org.gcube.vomanagement.usermanagement.UserManager; +import org.gcube.vomanagement.usermanagement.exception.RoleRetrievalFault; +import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager; +import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager; +import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.model.GCubeUser; +import org.gcube.vomanagement.usermanagement.model.GatewayRolesNames; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.liferay.portal.service.PortalPreferencesLocalServiceUtil; +import com.liferay.portal.service.UserLocalServiceUtil; +import com.liferay.portal.util.PortalUtil; + + +/** + * + * @author Massimiliano Assante ISTI-CNR + * + */ +public class RemovedUserAccountThread implements Runnable { + + private static final Logger _log = LoggerFactory.getLogger(RemovedUserAccountThread.class); + + final String SUBJECT = "Removed account notification"; + + private String userName; + private GroupManager gm; + private UserManager uMan; + + public RemovedUserAccountThread(long userId,String userName) { + super(); + this.userName = userName; + this.uMan = new LiferayUserManager(); + this.gm = new LiferayGroupManager(); + } + + @Override + public void run() { + try { + _log.info("Trying to remove user " + userName + " from JCR first, using storageHub with role: "+Constants.AUTORISED_INFRA_ROLE); + RemoveUserFromJCR rmJCR = new RemoveUserFromJCR(userName, gm, uMan); + boolean result = rmJCR.remove(); + _log.info("The user " + userName + " has been removed from JCR with success? " + result); + + } catch (Exception e) { + _log.error("An error occurred during user workspace removal: ", e); + } + } +} diff --git a/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserFromLDAPThread.java b/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserFromLDAPThread.java new file mode 100644 index 0000000..2781581 --- /dev/null +++ b/src/main/java/org/gcube/portal/removeaccount/thread/RemovedUserFromLDAPThread.java @@ -0,0 +1,152 @@ +package org.gcube.portal.removeaccount.thread; + +import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; +import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; + +import java.util.List; +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +import org.gcube.common.encryption.encrypter.StringEncrypter; +import org.gcube.common.portal.PortalContext; +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.Property; +import org.gcube.common.resources.gcore.utils.Group; +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.resources.discovery.client.api.DiscoveryClient; +import org.gcube.resources.discovery.client.queries.api.SimpleQuery; + +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; + +/** + * + * @author Massimiliano Assante ISTI-CNR + * + */ +public class RemovedUserFromLDAPThread implements Runnable { + private static Log _log = LogFactoryUtil.getLog(RemovedUserFromLDAPThread.class); + private static final String LDAP_SERVER_NAME = "LDAPServer"; + private static final String LDAP_SERVER_PRINCPAL_NAME = "ldapPrincipal"; + private static final String USER_CONTEXT = ",ou=People,o=D4Science,ou=Organizations,dc=d4science,dc=org"; + + private String portalName; + private String ldapUrl; + private String principal; + private String ldapPassword; + + private String username2Delete; + + public RemovedUserFromLDAPThread(String username2Delete) { + this.username2Delete = username2Delete; + } + + + @SuppressWarnings("deprecation") + @Override + public void run() { + portalName = PortalContext.getPortalInstanceName(); + + PortalContext context = PortalContext.getConfiguration(); + String scope = "/" + context.getInfrastructureName(); + ScopeProvider.instance.set(scope); + + SimpleQuery query = queryFor(ServiceEndpoint.class); + query.addCondition("$resource/Profile/Category/text() eq 'Portal'"); + query.addCondition("$resource/Profile/Name/text() eq '" + portalName + "'"); + + DiscoveryClient client = clientFor(ServiceEndpoint.class); + + List list = client.submit(query); + if (list == null || list.isEmpty()) { + _log.error("Could not find any Service endpoint registred in the infrastructure for this portal: " + portalName); + } + else if (list.size() > 1) { + _log.warn("Found more than one Service endpoint registred in the infrastructure for this portal: " + portalName); + } + else { + for (ServiceEndpoint res : list) { + Group apGroup = res.profile().accessPoints(); + AccessPoint[] accessPoints = (AccessPoint[]) apGroup.toArray(new AccessPoint[apGroup.size()]); + for (int i = 0; i < accessPoints.length; i++) { + if (accessPoints[i].name().compareTo(LDAP_SERVER_NAME) == 0) { + _log.info("Found credentials for " + LDAP_SERVER_NAME); + AccessPoint found = accessPoints[i]; + ldapUrl = found.address(); + String encrPassword = found.password(); + try { + ldapPassword = StringEncrypter.getEncrypter().decrypt( encrPassword); + } catch (Exception e) { + _log.error("Something went wrong while decrypting password for " + LDAP_SERVER_NAME); + e.printStackTrace(); + } + Group propGroup = found.properties(); + Property[] props = (Property[]) propGroup.toArray(new Property[propGroup.size()]); + for (int j = 0; j < props.length; j++) { + if (props[j].name().compareTo(LDAP_SERVER_PRINCPAL_NAME) == 0) { + _log.info("\tFound properties of " + LDAP_SERVER_PRINCPAL_NAME); + String encrValue = props[j].value(); + try { + principal = StringEncrypter.getEncrypter().decrypt(encrValue); + } catch (Exception e) { + _log.error("Something went wrong while decrypting value for " + LDAP_SERVER_PRINCPAL_NAME); + e.printStackTrace(); + } + } + } + + } + } + } + _log.debug("Got LDAP connection info from IS Resource ..."); + /*************** */ + _log.debug("Initializing LDAP connection ..."); + + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, ldapUrl); + env.put(Context.SECURITY_PRINCIPAL, principal); + env.put(Context.SECURITY_CREDENTIALS, ldapPassword); + + try { + Context ctx = new InitialContext(env); + String userCtx2Delete = getSubContext(username2Delete); + // Remove the binding + _log.debug("***** trying delete userCtx=" + userCtx2Delete); + ctx.unbind(userCtx2Delete); + // Check that it is gone + Object obj = null; + try { + obj = ctx.lookup(userCtx2Delete); + } catch (NameNotFoundException ne) { + _log.info("unbind successful for "+userCtx2Delete); + return; + } + _log.error("unbind failed; object still there: " + obj); + // Close the context when we're done + ctx.close(); + } catch (NamingException e) { + _log.error("Something went Wrong during LDAP remove user"); + e.printStackTrace(); + } catch (Exception es) { + _log.error("Something went Wrong during LDAP remove user in retrieving Liferay Organization"); + es.printStackTrace(); + } + } + } + + /** + * + * @param username + * @return the single user subContext + */ + private String getSubContext(String username) { + return "uid="+username+USER_CONTEXT; + } + +} diff --git a/src/main/java/org/gcube/portal/usersaccount/Constants.java b/src/main/java/org/gcube/portal/usersaccount/Constants.java new file mode 100644 index 0000000..93bfecc --- /dev/null +++ b/src/main/java/org/gcube/portal/usersaccount/Constants.java @@ -0,0 +1,7 @@ +package org.gcube.portal.usersaccount; + +public class Constants { + public static final String AUTORISED_INFRA_ROLE = "Infrastructure-Manager"; + public static final String USERNAME_PREFERENCE_KEY = "admin.reserved.screen.names"; + +} diff --git a/src/main/java/org/gcube/portal/usersaccount/MyCreateUserAccountListener.java b/src/main/java/org/gcube/portal/usersaccount/MyCreateUserAccountListener.java index d1c519c..513e46f 100644 --- a/src/main/java/org/gcube/portal/usersaccount/MyCreateUserAccountListener.java +++ b/src/main/java/org/gcube/portal/usersaccount/MyCreateUserAccountListener.java @@ -1,6 +1,8 @@ package org.gcube.portal.usersaccount; import org.gcube.portal.notifications.thread.NewUserAccountNotificationThread; +import org.gcube.portal.removeaccount.thread.RemovedUserAccountThread; +import org.gcube.portal.removeaccount.thread.RemovedUserFromLDAPThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,16 +22,38 @@ import com.liferay.portal.model.User; public class MyCreateUserAccountListener extends BaseModelListener { private static final Logger _log = LoggerFactory.getLogger(MyCreateUserAccountListener.class); final String SUBJECT = "New user account notification"; - - @Override - public void onAfterCreate(User user) throws ModelListenerException { - _log.info("onAfterCreate NewUserAccount listener for: " + user.getScreenName() + " / " + user.getFullName()); - Thread emailManagersThread = new Thread(new NewUserAccountNotificationThread(user.getScreenName(), user.getFullName(), user.getEmailAddress())); - emailManagersThread.start(); - - Thread WorkspaceAccountCreationThread = new Thread(new WorkspaceCreateAccountThread(user.getScreenName(), user.getFullName(), user.getEmailAddress())); - WorkspaceAccountCreationThread.start(); - } - + @Override + public void onAfterCreate(User user) throws ModelListenerException { + _log.info("onAfterCreate NewUserAccount listener for: " + user.getScreenName() + " / " + user.getFullName()); + Thread emailManagersThread = new Thread(new NewUserAccountNotificationThread(user.getScreenName(), user.getFullName(), user.getEmailAddress())); + emailManagersThread.start(); + + Thread WorkspaceAccountCreationThread = new Thread(new WorkspaceCreateAccountThread(user.getScreenName(), user.getFullName(), user.getEmailAddress())); + WorkspaceAccountCreationThread.start(); + } + + @Override + public void onBeforeRemove(User user) throws ModelListenerException { + _log.info("onBeforeRemove userAccount listener for: " + user.getScreenName() + " / " + user.getFullName()); + String username2Delete = user.getScreenName(); + _log.info("Trying to remove user from JCR and not notify infra-managers ..."); + try { + Thread dropUserWorkspaceThread = new Thread(new RemovedUserAccountThread(user.getUserId(), username2Delete)); + dropUserWorkspaceThread.start(); + _log.info("Trying to remove user from LDAP ..."); + Thread removeFromLDAPThread = new Thread(new RemovedUserFromLDAPThread(username2Delete)); + removeFromLDAPThread.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // @Override + // public void onAfterRemove(User user) + + + + + } \ No newline at end of file