commit e5ab4acec117125b855ccdadefa9d604d2633179 Author: Mauro Mugnaini Date: Thu May 21 15:47:45 2020 +0200 Intial GIT commit diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..5b0cf1c --- /dev/null +++ b/.classpath @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/.project b/.project new file mode 100644 index 0000000..7533c47 --- /dev/null +++ b/.project @@ -0,0 +1,36 @@ + + + oidc-library-portal + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..cac0df4 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +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.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..4528a36 --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles=gcube-developer +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..52b2ddd --- /dev/null +++ b/.settings/org.eclipse.wst.common.component @@ -0,0 +1,6 @@ + + + + + + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..fb95c45 --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs new file mode 100644 index 0000000..04cad8c --- /dev/null +++ b/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,2 @@ +disabled=06target +eclipse.preferences.version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..34361dd --- /dev/null +++ b/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + org.gcube.portal + oidc-library-portal + 0.2.0 + + maven-parent + org.gcube.tools + 1.1.0 + + + + 1.8 + 9.0.3 + 1.7.30 + 1.2.17 + + + + + org.gcube.distribution + maven-portal-bom + 3.6.0 + pom + import + + + + + + org.gcube.common + oidc-library + [0.1.0,) + compile + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + + + org.gcube.dvos + usermanagement-core + provided + + + com.liferay.portal + portal-service + provided + + + com.liferay.portal + util-java + provided + + + javax.portlet + portlet-api + provided + + + javax.servlet + javax.servlet-api + provided + + + \ No newline at end of file diff --git a/src/main/java/com/nubisware/oidc/lr62/LiferayOpenIdConnectConfiguration.java b/src/main/java/com/nubisware/oidc/lr62/LiferayOpenIdConnectConfiguration.java new file mode 100644 index 0000000..da7e8d6 --- /dev/null +++ b/src/main/java/com/nubisware/oidc/lr62/LiferayOpenIdConnectConfiguration.java @@ -0,0 +1,118 @@ +package com.nubisware.oidc.lr62; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.liferay.portal.kernel.exception.SystemException; +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.kernel.util.PrefsPropsUtil; +import com.liferay.portal.security.auth.CompanyThreadLocal; +import com.liferay.portal.util.PortalUtil; +import com.nubisware.oidc.rest.OpenIdConnectConfiguration; + +public class LiferayOpenIdConnectConfiguration implements OpenIdConnectConfiguration { + + protected static final Log log = LogFactoryUtil.getLog(LiferayOpenIdConnectConfiguration.class); + + public static Map companyId2Configuration = Collections + .synchronizedMap(new HashMap()); + + private Long companyId; + private String authorizationUrl; + private String tokenUrl; + private String logoutUrl; + private String issuerUrl; + private String clientId; + private String scope; + private boolean logoutOnPortalLogout; + private boolean createUnexistingUser; + + public static synchronized LiferayOpenIdConnectConfiguration getConfiguration(Long companyId) { + log.trace("Getting config from companyId"); + if (!companyId2Configuration.containsKey(companyId)) { + companyId2Configuration.put(companyId, new LiferayOpenIdConnectConfiguration(companyId)); + } + return companyId2Configuration.get(companyId); + } + + public static synchronized LiferayOpenIdConnectConfiguration getConfiguration(HttpServletRequest request) { + log.trace("Getting config from request"); + return LiferayOpenIdConnectConfiguration.getConfiguration(PortalUtil.getCompanyId(request)); + } + + public static synchronized LiferayOpenIdConnectConfiguration getConfiguration() { + log.trace("Getting config from thread local"); + return LiferayOpenIdConnectConfiguration.getConfiguration(CompanyThreadLocal.getCompanyId()); + } + + private LiferayOpenIdConnectConfiguration(Long companyId) { + log.info("Creating config from companyId: " + companyId); + this.companyId = companyId; + try { + this.authorizationUrl = PrefsPropsUtil.getString(companyId, "d4science.oidc-authorization"); + this.tokenUrl = PrefsPropsUtil.getString(companyId, "d4science.oidc-token"); + this.logoutUrl = PrefsPropsUtil.getString(companyId, "d4science.oidc-logout"); + this.issuerUrl = PrefsPropsUtil.getString(companyId, "d4science.oidc-issuer"); + this.clientId = PrefsPropsUtil.getString(companyId, "d4science.oidc-client-id"); + this.scope = PrefsPropsUtil.getString(companyId, "d4science.oidc-scope"); + this.logoutOnPortalLogout = PrefsPropsUtil.getBoolean(companyId, "d4science.oidc-logout-on-portal-logout"); + this.createUnexistingUser = PrefsPropsUtil.getBoolean(companyId, "d4science.oidc-create-unexisting-user"); + } catch (SystemException e) { + throw new RuntimeException(e); + } + log.info("authorizationUrl=" + getAuthorizationUrl()); + log.info("tokenUrl=" + getTokenUrl()); + log.info("logoutUrl=" + getLogoutUrl()); + log.info("issuerUrl=" + getIssuerUrl()); + log.info("clientId=" + getClientId()); + log.info("scope=" + getScope()); + log.info("logoutOnPortalLogout=" + logoutOnPortalLogout()); + log.info("createUnexistingUser=" + createUnexistingUser()); + } + + public Long getCompanyId() { + return companyId; + } + + @Override + public String getAuthorizationUrl() { + return this.authorizationUrl; + } + + @Override + public String getTokenUrl() { + return this.tokenUrl; + } + + @Override + public String getLogoutUrl() { + return this.logoutUrl; + } + + @Override + public String getIssuerUrl() { + return this.issuerUrl; + } + + @Override + public String getClientId() { + return this.clientId; + } + + @Override + public String getScope() { + return this.scope; + } + + public boolean logoutOnPortalLogout() { + return this.logoutOnPortalLogout; + } + + public boolean createUnexistingUser() { + return this.createUnexistingUser; + } +} diff --git a/src/main/java/com/nubisware/oidc/lr62/UserSitesToGroupsAndRolesMapper.java b/src/main/java/com/nubisware/oidc/lr62/UserSitesToGroupsAndRolesMapper.java new file mode 100644 index 0000000..c723f7b --- /dev/null +++ b/src/main/java/com/nubisware/oidc/lr62/UserSitesToGroupsAndRolesMapper.java @@ -0,0 +1,241 @@ +package com.nubisware.oidc.lr62; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.gcube.vomanagement.usermanagement.GroupManager; +import org.gcube.vomanagement.usermanagement.RoleManager; +import org.gcube.vomanagement.usermanagement.UserManager; +import org.gcube.vomanagement.usermanagement.exception.GroupRetrievalFault; +import org.gcube.vomanagement.usermanagement.exception.RoleRetrievalFault; +import org.gcube.vomanagement.usermanagement.exception.UserManagementPortalException; +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.LiferayRoleManager; +import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.model.GCubeGroup; +import org.gcube.vomanagement.usermanagement.model.GCubeRole; + +import com.liferay.portal.kernel.log.Log; +import com.liferay.portal.kernel.log.LogFactoryUtil; +import com.liferay.portal.model.User; +import com.liferay.portal.security.auth.PrincipalThreadLocal; +import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil; +import com.liferay.portal.security.permission.PermissionThreadLocal; +import com.liferay.portal.service.UserLocalServiceUtil; +import com.nubisware.oidc.gcube.D4ScienceMappings; +import com.nubisware.oidc.gcube.OIDCToSitesAndRolesMapper; +import com.nubisware.oidc.gcube.Site; +import com.nubisware.oidc.gcube.SitesMapperExecption; + +public class UserSitesToGroupsAndRolesMapper { + + protected static final Log log = LogFactoryUtil.getLog(UserSitesToGroupsAndRolesMapper.class); + + protected User user; + protected OIDCToSitesAndRolesMapper mapper; + protected UserManager userManager; + protected GroupManager groupManager; + protected RoleManager roleManager; + protected GCubeGroup rootVOGCubeGroup; + protected Map> actualGroupAndRoles; + protected Map roleNameToRole; + + public UserSitesToGroupsAndRolesMapper(User user, OIDCToSitesAndRolesMapper mapper) { + this.user = user; + this.mapper = mapper; + try { + if (log.isDebugEnabled()) { + log.debug("Creating the permission checker for admin user"); + } + long adminUserId = LiferayUserManager.getAdmin().getUserId(); + PrincipalThreadLocal.setName(adminUserId); + PermissionThreadLocal.setPermissionChecker( + PermissionCheckerFactoryUtil.create(UserLocalServiceUtil.getUser(adminUserId))); + + } catch (Exception e) { + log.fatal("Cannot create permission checker for admin user", e); + return; + } + userManager = new LiferayUserManager(); + groupManager = new LiferayGroupManager(); + roleManager = new LiferayRoleManager(); + try { + this.rootVOGCubeGroup = groupManager.getRootVO(); + } catch (UserManagementSystemException | GroupRetrievalFault e) { + log.error("Cannot get infrastructure's Root VO", e); + return; + } + try { + actualGroupAndRoles = groupManager.listGroupsAndRolesByUser(user.getUserId()); + } catch (UserManagementSystemException e) { + log.error("Cannot get sites and roles membership for user", e); + return; + } + roleNameToRole = new TreeMap<>(); + for (GCubeRole role : roleManager.listAllGroupRoles()) { + roleNameToRole.put(role.getRoleName(), role); + } + } + + public void map() { + log.info("Mapping roles to sites for user: " + user.getScreenName()); + Site gwSitesTree = null; + try { + gwSitesTree = mapper.map(rootVOGCubeGroup.getGroupName()); + if (log.isInfoEnabled()) { + log.info("Sites tree is: " + gwSitesTree.dump()); + } + } catch (SitesMapperExecption e) { + log.error("Computing sites tree in concrete mapper class", e); + } + if (gwSitesTree != null) { + if (log.isDebugEnabled()) { + log.debug("Check user to sites assignemnts"); + } + rolesToSiteDescendant(gwSitesTree, null); + } + if (log.isDebugEnabled()) { + log.debug("Check user to sites removal"); + } + checkForVRERemoval(gwSitesTree); + } + + + protected void rolesToSiteDescendant(Site actualSite, GCubeGroup parentGroup) { + GCubeGroup actualSiteGroup = null; + try { + if (log.isDebugEnabled()) { + log.debug("Getting actual site group from group manager, actual site name=" + actualSite.getName()); + } + actualSiteGroup = groupManager.getGroup(groupManager.getGroupId(actualSite.getName())); + } catch (UserManagementSystemException | GroupRetrievalFault e) { + log.error("Cannot retrieve group for site: " + actualSite.getName(), e); + return; + } + try { + if (groupManager.isVRE(actualSiteGroup.getGroupId()) && !actualGroupAndRoles.containsKey(actualSiteGroup)) { + log.info("Assigning user to new VRE site: " + actualSiteGroup.getGroupName()); + userManager.assignUserToGroup(actualSiteGroup.getGroupId(), user.getUserId()); + if (actualSite.getRoles() != null && !actualSite.getRoles().isEmpty()) { + log.info("Assiging roles for the VRE site"); + for (String roleName : actualSite.getRoles()) { + if (D4ScienceMappings.Role.MEMBER.asString().equals(roleName)) { + // Member role is only to assure that the user belongs to context + continue; + } + roleManager.assignRoleToUser(user.getUserId(), actualSiteGroup.getGroupId(), + roleNameToRole.get(roleName).getRoleId()); + } + // Since it's a VRE we can return + return; + } else { + log.info("User has no roles in the VRE site"); + } + } + } catch (UserManagementSystemException | GroupRetrievalFault | UserRetrievalFault + | UserManagementPortalException | RoleRetrievalFault | RuntimeException e) { + + log.error("Assigning user to new VRE site: " + actualSiteGroup.getGroupName(), e); + } + if (actualSite.getRoles() != null) { + List actualSiteGroupRoles = actualGroupAndRoles.get(actualSiteGroup); + List newRoles = new ArrayList<>(actualSite.getRoles()); + // Removing the Member role that is not a real role in LR + newRoles.remove(D4ScienceMappings.Role.MEMBER.asString()); + if (actualSiteGroupRoles != null && !actualSiteGroupRoles.isEmpty()) { + log.info("Checking actual roles in the dite group"); + for (GCubeRole gcRole : actualSiteGroupRoles) { + String actualSiteName = actualSite.getName(); + String gcRoleName = gcRole.getRoleName(); + if (!actualSite.getRoles().contains(gcRoleName)) { + try { + log.info("Removing '" + gcRoleName + "' user's role for site: " + actualSiteName); + roleManager.removeRoleFromUser(user.getUserId(), actualSiteGroup.getGroupId(), + gcRole.getRoleId()); + } catch (UserManagementSystemException | UserRetrievalFault | GroupRetrievalFault + | RoleRetrievalFault e) { + log.error( + "Cannot remove user's role '" + gcRoleName + "' for site: " + actualSite.getName(), + e); + continue; + } + } else { + if (log.isDebugEnabled()) { + log.debug("Removing site role from the roles list: " + gcRoleName); + } + newRoles.remove(gcRoleName); + } + } + } else { + log.info("User actually has no roles in the site group"); + } + // Adding roles that remaining in newRoles list, if any, for the user in this + // site + for (String newRole : newRoles) { + if (log.isDebugEnabled()) { + log.debug("Adding new role to user. New role=" + newRole); + } + GCubeRole newGcRole = roleNameToRole.get(newRole); + if (newGcRole != null) { + try { + log.info("Assinging new role '" + newRole + "' to user"); + roleManager.assignRoleToUser(user.getUserId(), actualSiteGroup.getGroupId(), + newGcRole.getRoleId()); + } catch (UserManagementSystemException | UserRetrievalFault | GroupRetrievalFault + | RoleRetrievalFault e) { + log.error("Cannot assign new role '" + newRole + "' for site: " + actualSite.getName(), e); + continue; + } + } else { + log.warn("New site's gc role is null (doesn't exist?) after getting it from role manager: " + + newRole); + } + } + } else { + log.info("Roles were not set, continuing descending letting them untouched in site: " + + actualSite.getName()); + } + for (String childSite : actualSite.getChildren().keySet()) { + log.info("Recursive call to child site: " + childSite); + rolesToSiteDescendant(actualSite.getChildren().get(childSite), actualSiteGroup); + } + } + + protected void checkForVRERemoval(Site gwSitesTree) { + List vreNames = new ArrayList<>(); + if (gwSitesTree != null) { + log.debug("Collecting VREs user belongs to"); + for (String voName : gwSitesTree.getChildren().keySet()) { + for (String vreName : gwSitesTree.getChildren().get(voName).getChildren().keySet()) { + log.debug("Adding VRE to the list: " + vreName); + vreNames.add(vreName); + } + } + } else { + log.info("User not belongs to any site"); + } + for (GCubeGroup actualGroup : actualGroupAndRoles.keySet()) { + try { + if (groupManager.isVRE(actualGroup.getGroupId()) && !vreNames.contains(actualGroup.getGroupName())) { + log.info("Removing user from VRE: " + actualGroup.getGroupName()); + try { + userManager.dismissUserFromGroup(actualGroup.getGroupId(), user.getUserId()); + } catch (UserRetrievalFault e) { + log.error("Removing user from VRE: " + actualGroup.getGroupName(), e); + } + } else { + if (log.isDebugEnabled()) { + log.debug("User still belong to VRE: " + actualGroup.getGroupName()); + } + } + } catch (UserManagementSystemException | GroupRetrievalFault e) { + log.error("Checking if site group is a VRE", e); + } + } + } + +} diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml new file mode 100644 index 0000000..6a468f7 --- /dev/null +++ b/src/test/resources/log4j.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file