diff --git a/.classpath b/.classpath index 26981b6..04023d0 100644 --- a/.classpath +++ b/.classpath @@ -15,6 +15,7 @@ + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 6e80039..4ede96d 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,2 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index c04c574..29380ee 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,5 @@ - + diff --git a/pom.xml b/pom.xml index 09ce426..838185e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,7 @@ - 4.0.0 @@ -13,7 +14,7 @@ remove-account-portlet war RemoveAccount Portlet - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT remove-account-portlet is a component that install in the contro panel userr account as a tab and permits the user to remvoe his or her account @@ -52,6 +53,19 @@ + + org.gcube.resources.discovery + ic-client + + + org.gcube.common + storagehub-client-library + + + org.gcube.core + common-encryption + provided + org.gcube.dvos usermanagement-core @@ -143,7 +157,7 @@ portlet - + org.apache.maven.plugins maven-compiler-plugin 2.3.2 diff --git a/src/main/java/org/gcube/portlets/admin/RemoveAccountPortlet.java b/src/main/java/org/gcube/portlets/admin/RemoveAccountPortlet.java index d03ef46..f38b2cf 100644 --- a/src/main/java/org/gcube/portlets/admin/RemoveAccountPortlet.java +++ b/src/main/java/org/gcube/portlets/admin/RemoveAccountPortlet.java @@ -7,6 +7,8 @@ import javax.portlet.ActionResponse; import javax.portlet.PortletException; import javax.portlet.ProcessAction; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.model.User; import com.liferay.portal.theme.ThemeDisplay; @@ -17,26 +19,33 @@ import com.liferay.util.bridges.mvc.MVCPortlet; * Portlet implementation class RemoveAccountPortlet */ public class RemoveAccountPortlet extends MVCPortlet { - + private static Log _log = LogFactoryUtil.getLog(RemoveAccountPortlet.class); + public static final String AUTORISED_INFRA_ROLE = "Infrastructure-Manager"; + @ProcessAction(name = "deleteAccount") - public void deleteAccount(ActionRequest actionRequest, - ActionResponse response) throws IOException, PortletException { + public void deleteAccount(ActionRequest actionRequest, ActionResponse response) throws IOException, PortletException { User user = null; try { user = PortalUtil.getUser(actionRequest); } catch (Exception e) { e.printStackTrace(); - } - + } + String username2Remove = user.getScreenName(); + + _log.info("Trying to remove user from LDAP ..."); + Thread removeFromLDAPThread = new Thread(new RemovedUserFromLDAPThread(username2Remove)); + removeFromLDAPThread.start(); + + _log.info("Trying to remove user from Liferay DB and JCR and notify infra-managers ..."); Thread emailManagersThread = new Thread(new RemovedUserAccountThread( user.getUserId(), - user.getScreenName(), + username2Remove, user.getFullName(), user.getEmailAddress())); emailManagersThread.start(); - + + ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY); response.sendRedirect(themeDisplay.getURLSignOut()); - } } diff --git a/src/main/java/org/gcube/portlets/admin/RemoveUserFromJCR.java b/src/main/java/org/gcube/portlets/admin/RemoveUserFromJCR.java new file mode 100644 index 0000000..03c27e3 --- /dev/null +++ b/src/main/java/org/gcube/portlets/admin/RemoveUserFromJCR.java @@ -0,0 +1,74 @@ +package org.gcube.portlets.admin; + +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.plugins.AbstractPlugin; +import org.gcube.common.storagehub.client.proxies.UserManagerClient; +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; + + public RemoveUserFromJCR(String username2Delete, GroupManager gm, UserManager uMan) { + this.username2Delete = username2Delete; + this.gm = gm; + this.uMan = uMan; + } + + public boolean remove() { + try { + //get the super user + String infraContext = "/"+PortalContext.getConfiguration().getInfrastructureName(); + long groupId = gm.getGroupIdFromInfrastructureScope(infraContext); + RoleManager rm = new LiferayRoleManager(); + long roleId = rm.getRoleId(RemoveAccountPortlet.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 " + RemoveAccountPortlet.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); + UserManagerClient userClient = AbstractPlugin.users().build(); + userClient.removeUser(username2Delete); + return true; + } + } catch (Exception e) { + _log.error("Could not delete " + username2Delete + " from JCR ", e); + return false; + } + } + + +} diff --git a/src/main/java/org/gcube/portlets/admin/RemovedUserAccountThread.java b/src/main/java/org/gcube/portlets/admin/RemovedUserAccountThread.java index 2f64e18..f99584b 100644 --- a/src/main/java/org/gcube/portlets/admin/RemovedUserAccountThread.java +++ b/src/main/java/org/gcube/portlets/admin/RemovedUserAccountThread.java @@ -33,6 +33,8 @@ public class RemovedUserAccountThread implements Runnable { private String fullName; private String emailAddress; private long userId; + private GroupManager gm; + private UserManager uMan; public RemovedUserAccountThread(long userId,String userName, String fullName, String emailAddress) { super(); @@ -40,25 +42,35 @@ public class RemovedUserAccountThread implements Runnable { this.userName = userName; this.fullName = fullName; this.emailAddress = emailAddress; + 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: "+RemoveAccountPortlet.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); + } handleUserRemoval(userId, userName, fullName, emailAddress); } private void handleUserRemoval(long userId, String userName, String fullName, String emailAddress) { - System.out.println("trying removeUser account for " + userName); + _log.info("trying removeUser account for " + userName); //first remove the account try { UserLocalServiceUtil.deleteUser(userId); } catch (Exception e) { e.printStackTrace(); } - System.out.println("removeUser account for " + userName + " done with success, now notify the managers ... "); + _log.info("removeUser account for " + userName + " done with success, now notify the managers ... "); //the notify the managers - UserManager um = new LiferayUserManager(); - GroupManager gm = new LiferayGroupManager(); + RoleManager rm = new LiferayRoleManager(); try { String rootVoName = PortalContext.getConfiguration().getInfrastructureName(); @@ -73,7 +85,7 @@ public class RemovedUserAccountThread implements Runnable { } _log.trace("Root is: " + rootVoName + " Scanning roles ...."); - List managers = um.listUsersByGroupAndRole(groupId, infraManagerRoleId); + List managers = uMan.listUsersByGroupAndRole(groupId, infraManagerRoleId); if (managers == null || managers.isEmpty()) { _log.warn("There are no users with (Site) Role " + infraManagerRoleId + " on " + rootVoName + " in this portal. Will not notify about removed user accounts."); } diff --git a/src/main/java/org/gcube/portlets/admin/RemovedUserFromLDAPThread.java b/src/main/java/org/gcube/portlets/admin/RemovedUserFromLDAPThread.java new file mode 100644 index 0000000..c2d0930 --- /dev/null +++ b/src/main/java/org/gcube/portlets/admin/RemovedUserFromLDAPThread.java @@ -0,0 +1,153 @@ +package org.gcube.portlets.admin; + +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_FILTER_NAME = "filter"; + 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/webapp/WEB-INF/liferay-plugin-package.properties b/src/main/webapp/WEB-INF/liferay-plugin-package.properties index c0a6ab8..33e5ffe 100644 --- a/src/main/webapp/WEB-INF/liferay-plugin-package.properties +++ b/src/main/webapp/WEB-INF/liferay-plugin-package.properties @@ -1,9 +1,9 @@ name=RemoveAccount module-group-id=liferay -module-incremental-version=1 +module-incremental-version=2 tags= short-description= change-log= page-url=http://www.gcube-system.org author=M. Assante -licenses=EUPL \ No newline at end of file +licenses=EUPL diff --git a/src/main/webapp/html/removeaccount/view.jsp b/src/main/webapp/html/removeaccount/view.jsp index 7b57e04..1bee30c 100644 --- a/src/main/webapp/html/removeaccount/view.jsp +++ b/src/main/webapp/html/removeaccount/view.jsp @@ -7,9 +7,9 @@

Delete your Account

Deleting your account will disable your profile and remove your - name and photo from most things you've shared on this D4Science gateway.

+ name and photo you've shared on this D4Science gateway.

Some information may still be visible to others, such as your - name in the posts and private messages you sent. Non shared files and folders of your virtual workspace will be removed.

+ name in the posts and private messages you sent. All files and folders you created of your workspace will be removed.

Warning