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_FILTER_NAME) == 0) {
+ _log.info("\tFound properties of " + LDAP_SERVER_FILTER_NAME);
+ String encrValue = props[j].value();
+ System.out.println("Filter encrypted = " + encrValue);
+ try {
+ filter = StringEncrypter.getEncrypter().decrypt(encrValue);
+ } catch (Exception e) {
+ _log.error("Something went wrong while decrypting value for " + LDAP_SERVER_FILTER_NAME);
+ e.printStackTrace();
+ }
+ }
+ else 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();
+ }
+ }
+ }
+
+ }
+ }
+
+ }
+ }
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ ScheduledExecutorService ldapScheduler = Executors.newScheduledThreadPool(1);
+ ldapScheduler.scheduleAtFixedRate(new LDAPSync(ldapUrl, filter, principal, ldapPassword), 0, LDAP_MINUTES_DELAY, TimeUnit.MINUTES);
+
+ String toReturn = "LDAPSync SCRIPT Started ...
";
+
+ response.setContentType("text/html");
+ response.getWriter().write(toReturn);
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
+}
\ No newline at end of file
diff --git a/src/main/java/org/gcube/portal/ldapexport/LDAPSync.java b/src/main/java/org/gcube/portal/ldapexport/LDAPSync.java
new file mode 100644
index 0000000..55d9d47
--- /dev/null
+++ b/src/main/java/org/gcube/portal/ldapexport/LDAPSync.java
@@ -0,0 +1,360 @@
+package org.gcube.portal.ldapexport;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Random;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.gcube.common.portal.PortalContext;
+import org.gcube.portal.custom.communitymanager.OrganizationsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.liferay.portal.kernel.cache.CacheRegistryUtil;
+import com.liferay.portal.kernel.exception.PortalException;
+import com.liferay.portal.kernel.exception.SystemException;
+import com.liferay.portal.model.Organization;
+import com.liferay.portal.model.User;
+import com.liferay.portal.service.OrganizationLocalServiceUtil;
+import com.liferay.portal.service.UserLocalServiceUtil;
+
+public class LDAPSync implements Runnable {
+ private static final Logger _log = LoggerFactory.getLogger(LDAPSync.class);
+
+ private static final String LDAP_ORG_FILTER = "(objectClass=organizationalUnit)";
+ private static final String LDAP_GROUP_FILTER = "(objectClass=posixGroup)";
+
+ private String ldapUrl;
+ private String filter;
+ private String principal;
+ private String pwd;
+
+
+ public LDAPSync(String ldapUrl, String filter, String principal, String pwd) {
+ this.ldapUrl = ldapUrl;
+ this.filter = filter;
+ this.principal = principal;
+ this.pwd = pwd;
+ _log.info("Starting LDAPSync over " + ldapUrl);
+ }
+
+ /**
+ *
+ * @return the Liferay mapped as Root Organization
+ */
+ private Organization getRootVO() {
+ String rootVoName = PortalContext.getConfiguration().getInfrastructureName();
+ _log.debug("Root organization name found: " + rootVoName);
+
+ //start of iteration of the actual groups
+ List organizations;
+ try {
+ organizations = OrganizationLocalServiceUtil.getOrganizations(0, OrganizationLocalServiceUtil.getOrganizationsCount());
+ for (Organization organization : organizations) {
+ if (organization.getName().equals(rootVoName)) {
+ return organization;
+ }
+ }
+ }
+ catch (SystemException e) {
+ _log.error("There were problems retrieving root organization", e);
+ }
+ _log.error("Could not find any root organization");
+ return null;
+ }
+
+
+
+
+ @Override
+ public void run() {
+ _log.debug("Reading Portal Users ...");
+ List users = null;
+ try {
+ users = getAllLiferayUsers();
+ _log.debug("\n***Read " + users.size() + " from LR DB\n");
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ _log.debug("Reading Portal Organizations ...");
+ Organization rootVO = getRootVO();
+
+ _log.debug("Initializing LDAP exporter ...");
+
+ 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, pwd);
+
+ try {
+ DirContext ctx = new InitialDirContext(env);
+ _log.debug("Initiating LDAP Sync ...");
+ //update the whole list of users (uid="+username+",ou=People,o=Liferay,ou=Organizations,dc=d4science,dc=org")
+ exportSingleUsers(ctx, env, users);
+
+ //crate or update the whole list of organizations (objectClass=organizationalUnit, ou="+orgName+",dc=d4science,dc=org) and groups ( objectClass=top and POSIXGroup)
+ updateGroups(ctx, rootVO);
+
+ } catch (NamingException e) {
+ _log.error("Something went Wrong during LDAP Sync in Exporting to LDAP");
+ e.printStackTrace();
+ } catch (SystemException es) {
+ _log.error("Something went Wrong during LDAP Sync in retrieving Liferay Organization");
+ es.printStackTrace();
+ }
+ }
+
+ private void updateGroups(DirContext ctx, Organization root) throws NamingException, SystemException {
+ String subCtx = getOrgSubContext(root.getName());
+ if (!checkIfLDAPOrganizationalUnitExists(ctx, subCtx))
+ createOrganizationalUnit(ctx, subCtx);
+ for (Organization org : root.getSuborganizations()) {
+ String orgSubCtx = "ou="+org.getName()+","+subCtx;
+ if (!checkIfLDAPOrganizationalUnitExists(ctx, orgSubCtx))
+ createOrganizationalUnit(ctx, orgSubCtx);
+ for (Organization vre : org.getSuborganizations()) {
+ String vreSubCtx = "cn="+vre.getName()+","+orgSubCtx;
+ if (!checkIfLDAPGroupExists(ctx, vreSubCtx))
+ createGroupVRE(ctx, vreSubCtx, vre.getName());
+ //update the list of users in such VRE
+ updateUsersInGroup(ctx, vreSubCtx, vre);
+ }
+ }
+ }
+
+ private void updateUsersInGroup(DirContext ctx, String vreSubCtx, Organization vre) throws NamingException, SystemException {
+ List users = UserLocalServiceUtil.getOrganizationUsers(vre.getOrganizationId());
+ for (User userObj : users) {
+ String user = userObj.getScreenName();
+ try {
+ Attribute memberUid = new BasicAttribute("memberUid");
+ memberUid.add(user);
+ Attributes attributes = new BasicAttributes();
+ attributes.put(memberUid);
+ ctx.modifyAttributes(vreSubCtx, DirContext.ADD_ATTRIBUTE, attributes);
+ _log.info("Adding user: " + user);
+ }
+ catch (javax.naming.directory.AttributeInUseException ex) {
+ _log.trace("Not adding already existing user: " + user);
+ }
+
+ }
+
+ }
+
+ private void exportSingleUsers(DirContext ctx, Properties env, List users) throws NamingException {
+ for (User user : users) {
+ updateUserInLDAP(user.getScreenName(), user.getFirstName(), user.getLastName(), user.getFullName(), user.getEmailAddress(), "{SHA}"+user.getPassword(), ctx, filter);
+ //_log.debug("Updated " + user.getScreenName());
+ }
+ _log.debug("LDAP Users Sync cycle done");
+ if (! users.isEmpty())
+ _log.info("LDAP Users Sync Completed OK!");
+ else
+ _log.warn("LDAP Users Sync cycle skipped this time");
+ }
+ /**
+ *
+ * @param ctx
+ * @param subContext
+ * @throws NamingException
+ */
+ private void createOrganizationalUnit(DirContext ctx, String subContext) throws NamingException {
+ Attributes attributes = new BasicAttributes();
+ Attribute objectClass = new BasicAttribute("objectClass");
+ objectClass.add("organizationalUnit");
+ attributes.put(objectClass);
+
+ Attribute description = new BasicAttribute("description");
+ description.add("Liferay Organization");
+ attributes.put(description);
+ ctx.createSubcontext(subContext, attributes);
+ _log.info("Added " + subContext);
+ }
+ /**
+ *
+ * @param ctx
+ * @param subContext
+ * @param vreName
+ * @throws NamingException
+ */
+ private void createGroupVRE(DirContext ctx, String subContext, String vreName) throws NamingException {
+ Attributes attributes = new BasicAttributes();
+
+ Attribute objectClass = new BasicAttribute("objectClass");
+ objectClass.add("top");
+ objectClass.add("posixGroup");
+ // objectClass.add("researchProject");
+ // objectClass.add("groupOfMembers");
+ attributes.put(objectClass);
+
+ Attribute cn = new BasicAttribute("cn");
+ cn.add(vreName);
+ attributes.put(cn);
+
+ Attribute gidNumber = new BasicAttribute("gidNumber");
+ gidNumber.add(getRandomPOSIXidentifier(ctx));
+ attributes.put(gidNumber);
+
+ ctx.createSubcontext(subContext, attributes);
+ _log.info("Added " + subContext);
+ }
+
+ private String getOrgSubContext(String orgName) {
+ return "ou="+orgName+",dc=d4science,dc=org";
+ }
+ /**
+ *
+ * @param ctx
+ * @param orgSubctx
+ * @return true if exists
+ */
+ private boolean checkIfLDAPOrganizationalUnitExists(DirContext ctx, String orgSubctx) {
+ SearchControls ctls = new SearchControls();
+ ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ NamingEnumeration answer;
+ try {
+ answer = ctx.search(orgSubctx, LDAP_ORG_FILTER, ctls);
+ } catch (NamingException e) {
+ _log.debug("not found in LDAP (will add it): Organization: " + orgSubctx);
+ return false;
+ }
+ boolean toReturn = answer.hasMoreElements();
+ _log.debug("Organization: " + orgSubctx + " exists? " + toReturn);
+ return toReturn;
+ }
+ /**
+ *
+ * @param ctx
+ * @param groupSubctx
+ * @return true if exists
+ */
+ private boolean checkIfLDAPGroupExists(DirContext ctx, String groupSubctx) {
+ SearchControls ctls = new SearchControls();
+ ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ NamingEnumeration answer;
+ try {
+ answer = ctx.search(groupSubctx, LDAP_GROUP_FILTER, ctls);
+ } catch (NamingException e) {
+ _log.debug("not found in LDAP (will add it): Group: " + groupSubctx);
+ return false;
+ }
+ boolean toReturn = answer.hasMoreElements();
+ _log.debug("Group: " + groupSubctx + " exists? " + toReturn);
+ return toReturn;
+ }
+ /**
+ *
+ * @param username
+ * @return the single user subContext
+ */
+ private String getSubContext(String username) {
+ return "uid="+username+",ou=People,o=Liferay,ou=Organizations,dc=d4science,dc=org";
+ }
+ /**
+ *
+ * @param username
+ * @param ctx
+ * @param filter
+ * @return true if exists
+ */
+ private boolean checkIfLDAPUserExists(String username, DirContext ctx, String filter) {
+ SearchControls ctls = new SearchControls();
+ ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ NamingEnumeration answer;
+ try {
+ answer = ctx.search(getSubContext(username), filter, ctls);
+ } catch (NamingException e) {
+ _log.info("user: " + username + " not found in LDAP, trying to export it");
+ return false;
+ }
+ return answer.hasMoreElements();
+ }
+ /**
+ *
+ * @param username
+ * @param name
+ * @param lastName
+ * @param email
+ * @param passwd
+ * @param ctx
+ * @throws NamingException
+ */
+ private void updateUserInLDAP(String username, String name, String lastName, String fullName, String email, String passwd, DirContext ctx, String filter) throws NamingException {
+ Attributes attributes=new BasicAttributes();
+ Attribute objectClass=new BasicAttribute("objectClass");
+ objectClass.add("inetOrgPerson");
+ attributes.put(objectClass);
+
+ //the main ldap server uses 'givenName' for the First name, 'cn' for "first name last name', 'sn' for the last name
+ Attribute givenName = new BasicAttribute("givenName");
+ Attribute cn = new BasicAttribute("cn");
+ Attribute sn = new BasicAttribute("sn");
+ Attribute mail = new BasicAttribute("mail");
+ Attribute userPassword = new BasicAttribute("userPassword");
+
+ givenName.add(name);
+ cn.add(fullName);
+ sn.add(lastName);
+ mail.add(email);
+ userPassword.add(passwd);
+
+ attributes.put(givenName);
+ attributes.put(cn);
+ attributes.put(sn);
+ attributes.put(mail);
+ attributes.put(userPassword);
+
+ if (checkIfLDAPUserExists(username, ctx, filter)) {
+ //_log.debug("User " + username + " already exists, replacing attributes");
+ ctx.modifyAttributes(getSubContext(username), DirContext.REPLACE_ATTRIBUTE, attributes);
+ }
+ else {
+ ctx.createSubcontext(getSubContext(username),attributes);
+ _log.debug("New User Found with uid=" + username + " created");
+ }
+ }
+ /**
+ *
+ * @return the whole list of users
+ */
+ private List getAllLiferayUsers() {
+ String infraName = PortalContext.getConfiguration().getInfrastructureName();
+ _log.info("TRY Reading non chached users belonging to: /" + infraName);
+
+ List toReturn = new ArrayList();
+ Organization rootInfra;
+ try {
+ CacheRegistryUtil.clear(); //needed to avoid cache use by liferay API
+ rootInfra = OrganizationLocalServiceUtil.getOrganization(OrganizationsUtil.getCompany().getCompanyId(), infraName);
+ toReturn = UserLocalServiceUtil.getOrganizationUsers(rootInfra.getOrganizationId());
+ } catch (PortalException | SystemException e) {
+ _log.error("Error during LDAP Sync, could not retrieve users from LR DB: " + e.getMessage());
+ }
+ return toReturn;
+ }
+ /**
+ *
+ * @return an integer between 1000 and 2147483647
+ */
+ private String getRandomPOSIXidentifier(DirContext ctx) {
+ final int Low = 1000;
+ final int High = 2147483647;
+ Random r = new Random();
+ int toReturn = r.nextInt(High-Low) + Low;
+ return toReturn+"";
+ }
+}
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..07ae064
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+
+
+
+ LDAP Export servlet
+
+
+ start-ldap-export
+ org.gcube.portal.ldapexport.LDAPExportService
+
+
+
+ start-ldap-export
+ /start-ldap-export
+
+
+
+
+
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
new file mode 100644
index 0000000..7f6f0e4
--- /dev/null
+++ b/src/main/webapp/index.jsp
@@ -0,0 +1,7 @@
+
+
+Hello From D4Science LDAP Export service!
+
+RUN D4Science LDAP Export service (repeat: every 10 minutes [Default])
+
+
diff --git a/target/ldap-export-servlet.war b/target/ldap-export-servlet.war
new file mode 100644
index 0000000..b4d8b69
Binary files /dev/null and b/target/ldap-export-servlet.war differ
diff --git a/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPExportService.class b/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPExportService.class
new file mode 100644
index 0000000..655ab7d
Binary files /dev/null and b/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPExportService.class differ
diff --git a/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPSync.class b/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPSync.class
new file mode 100644
index 0000000..4d3564a
Binary files /dev/null and b/target/ldap-export-servlet/WEB-INF/classes/org/gcube/portal/ldapexport/LDAPSync.class differ
diff --git a/target/ldap-export-servlet/WEB-INF/web.xml b/target/ldap-export-servlet/WEB-INF/web.xml
new file mode 100644
index 0000000..07ae064
--- /dev/null
+++ b/target/ldap-export-servlet/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+
+
+
+ LDAP Export servlet
+
+
+ start-ldap-export
+ org.gcube.portal.ldapexport.LDAPExportService
+
+
+
+ start-ldap-export
+ /start-ldap-export
+
+
+
+
+
diff --git a/target/ldap-export-servlet/index.jsp b/target/ldap-export-servlet/index.jsp
new file mode 100644
index 0000000..7f6f0e4
--- /dev/null
+++ b/target/ldap-export-servlet/index.jsp
@@ -0,0 +1,7 @@
+
+
+Hello From D4Science LDAP Export service!
+
+RUN D4Science LDAP Export service (repeat: every 10 minutes [Default])
+
+
diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties
new file mode 100644
index 0000000..0d297b8
--- /dev/null
+++ b/target/maven-archiver/pom.properties
@@ -0,0 +1,5 @@
+#Generated by Maven
+#Mon Nov 30 17:15:06 CET 2015
+version=0.0.1-SNAPSHOT
+groupId=org.gcube.portal
+artifactId=ldap-export-servlet