diff --git a/src/main/java/org/olat/ldap/LDAPLoginManager.java b/src/main/java/org/olat/ldap/LDAPLoginManager.java index 7ffac3daf83c1a548b4e78faa09957553eefbd60..e3e58f7fb55d22717b3911d9f8a807942c1e6e35 100644 --- a/src/main/java/org/olat/ldap/LDAPLoginManager.java +++ b/src/main/java/org/olat/ldap/LDAPLoginManager.java @@ -53,6 +53,8 @@ public interface LDAPLoginManager { public void syncUser(Map<String,String> olatPropertyMap, Identity identity); + public void syncUserGroups(Identity identity); + public void deletIdentities(List<Identity> identityList); public boolean doBatchSync(LDAPError errors, boolean full); diff --git a/src/main/java/org/olat/ldap/manager/LDAPDAO.java b/src/main/java/org/olat/ldap/manager/LDAPDAO.java index 07429db9d2512fd2233b1f7db55ee1485ae76c0b..9c1e9390a073ebd22039bc0ef63e6e9ab88c75e2 100644 --- a/src/main/java/org/olat/ldap/manager/LDAPDAO.java +++ b/src/main/java/org/olat/ldap/manager/LDAPDAO.java @@ -30,6 +30,7 @@ import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.SizeLimitExceededException; import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; @@ -38,8 +39,6 @@ import javax.naming.ldap.LdapContext; import javax.naming.ldap.PagedResultsControl; import javax.naming.ldap.PagedResultsResponseControl; -import net.fortuna.ical4j.util.TimeZones; - import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; @@ -51,6 +50,8 @@ import org.olat.ldap.model.LDAPUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import net.fortuna.ical4j.util.TimeZones; + /** * * Initial date: 24.11.2014<br> @@ -90,6 +91,30 @@ public class LDAPDAO { return ldapGroups; } + public List<LDAPGroup> searchGroups(LdapContext ctx, List<String> groupDNs, String filter) { + final List<LDAPGroup> ldapGroups = new ArrayList<>(); + String[] groupAttributes = new String[]{ "cn" }; + for(String groupDN:groupDNs) { + LDAPVisitor visitor = new LDAPVisitor() { + @Override + public void visit(SearchResult searchResult) throws NamingException { + Attributes resAttributes = searchResult.getAttributes(); + Attribute cnAttr = resAttributes.get("cn"); + + Object cn = cnAttr.get(); + if(cn instanceof String) { + LDAPGroup group = new LDAPGroup(); + group.setCommonName((String)cn); + ldapGroups.add(group); + } + } + + }; + search(visitor, groupDN, filter, groupAttributes, ctx); + } + return ldapGroups; + } + public void search(LDAPVisitor visitor, String ldapBase, String filter, String[] returningAttrs, LdapContext ctx) { SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); @@ -217,7 +242,7 @@ public class LDAPDAO { return userDN; } - private String buildSearchUserFilter(String attribute, String uid) { + protected String buildSearchUserFilter(String attribute, String uid) { String ldapUserFilter = syncConfiguration.getLdapUserFilter(); StringBuilder filter = new StringBuilder(); if (ldapUserFilter != null) { diff --git a/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java b/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java index d4d4c7cfbad6e1bf476e143a9321ba433637a2c9..b0995f1e2d1f59e843d40bdc459f3a3fbea17d8e 100644 --- a/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java +++ b/src/main/java/org/olat/ldap/manager/LDAPLoginManagerImpl.java @@ -40,6 +40,7 @@ import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.Control; import javax.naming.ldap.InitialLdapContext; @@ -640,6 +641,89 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe } } + /** + * The method search in LDAP the user, search the groups + * of which it is member of, and sync the groups. + * + * @param identity The identity to sync + */ + @Override + public void syncUserGroups(Identity identity) { + LdapContext ctx = bindSystem(); + if (ctx == null) { + log.error("could not bind to ldap", null); + } + + String ldapUserIDAttribute = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER); + String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, identity.getName()); + + boolean withCoacheOfGroups = StringHelper.containsNonWhitespace(syncConfiguration.getCoachedGroupAttribute()); + List<String> ldapBases = syncConfiguration.getLdapBases(); + String[] searchAttr; + if(withCoacheOfGroups) { + searchAttr = new String[]{ "dn", syncConfiguration.getCoachedGroupAttribute() }; + } else { + searchAttr = new String[]{ "dn" }; + } + + SearchControls ctls = new SearchControls(); + ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); + ctls.setReturningAttributes(searchAttr); + + String userDN = null; + List<String> groupList = null; + for (String ldapBase : ldapBases) { + try { + NamingEnumeration<SearchResult> enm = ctx.search(ldapBase, filter, ctls); + while (enm.hasMore()) { + SearchResult result = enm.next(); + userDN = result.getNameInNamespace(); + + if(withCoacheOfGroups) { + Attributes resAttributes = result.getAttributes(); + Attribute coachOfGroupsAttr = resAttributes.get(syncConfiguration.getCoachedGroupAttribute()); + if(coachOfGroupsAttr != null && coachOfGroupsAttr.get() instanceof String) { + String groupString = (String)coachOfGroupsAttr.get(); + if(!"-".equals(groupString)) { + String[] groupArr = groupString.split(syncConfiguration.getCoachedGroupAttributeSeparator()); + groupList = new ArrayList<>(groupArr.length); + for(String group:groupArr) { + groupList.add(group); + } + } + } + } + } + if (userDN != null) { + break; + } + } catch (NamingException e) { + log.error("NamingException when trying to bind user with username::" + identity.getName() + " on ldapBase::" + ldapBase, e); + } + } + + // get the potential groups + if(userDN != null) { + List<String> groupDNs = syncConfiguration.getLdapGroupBases(); + String groupFilter = "(&(objectClass=groupOfNames)(member=" + userDN + "))"; + List<LDAPGroup> groups = ldapDao.searchGroups(ctx, groupDNs, groupFilter); + for(LDAPGroup group:groups) { + BusinessGroup managedGroup = getManagerBusinessGroup(group.getCommonName()); + if(managedGroup != null) { + List<String> roles = businessGroupRelationDao.getRoles(identity, managedGroup); + if(roles.isEmpty()) { + boolean coach = groupList != null && groupList.contains(group.getCommonName()); + if(coach) { + businessGroupRelationDao.addRole(identity, managedGroup, GroupRoles.coach.name()); + } else { + businessGroupRelationDao.addRole(identity, managedGroup, GroupRoles.participant.name()); + } + } + } + } + } + } + /** * Searches for Identity in OLAT. * diff --git a/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java b/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..f4c5aebba62739e0aecec7949b5e9f01758a9045 --- /dev/null +++ b/src/main/java/org/olat/ldap/ui/LDAPGroupsLoginInterceptor.java @@ -0,0 +1,77 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.ldap.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.ldap.LDAPLoginManager; +import org.olat.ldap.LDAPLoginModule; +import org.olat.login.SupportsAfterLoginInterceptor; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 18 juil. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class LDAPGroupsLoginInterceptor extends FormBasicController implements SupportsAfterLoginInterceptor { + + @Autowired + private LDAPLoginModule ldapModule; + @Autowired + private LDAPLoginManager ldapManager; + + public LDAPGroupsLoginInterceptor(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + initForm(ureq); + } + + @Override + public boolean isUserInteractionRequired(UserRequest ureq) { + if(ldapModule.isLDAPEnabled()) { + try { + ldapManager.syncUserGroups(getIdentity()); + } catch (Exception e) { + logError("Cannot sync LDAP groups", e); + } + } + return false; + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } +}