Skip to content
Snippets Groups Projects
Commit 8543360a authored by srosse's avatar srosse
Browse files

OO-2913: implement a login interceptor to sync the LDAP groups of the user which log in

parent 490992a3
No related branches found
No related tags found
No related merge requests found
...@@ -53,6 +53,8 @@ public interface LDAPLoginManager { ...@@ -53,6 +53,8 @@ public interface LDAPLoginManager {
public void syncUser(Map<String,String> olatPropertyMap, Identity identity); public void syncUser(Map<String,String> olatPropertyMap, Identity identity);
public void syncUserGroups(Identity identity);
public void deletIdentities(List<Identity> identityList); public void deletIdentities(List<Identity> identityList);
public boolean doBatchSync(LDAPError errors, boolean full); public boolean doBatchSync(LDAPError errors, boolean full);
......
...@@ -30,6 +30,7 @@ import javax.naming.NamingEnumeration; ...@@ -30,6 +30,7 @@ import javax.naming.NamingEnumeration;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.SizeLimitExceededException; import javax.naming.SizeLimitExceededException;
import javax.naming.directory.Attribute; import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext; import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls; import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult; import javax.naming.directory.SearchResult;
...@@ -38,8 +39,6 @@ import javax.naming.ldap.LdapContext; ...@@ -38,8 +39,6 @@ import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl; import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl; import javax.naming.ldap.PagedResultsResponseControl;
import net.fortuna.ical4j.util.TimeZones;
import org.olat.core.logging.OLog; import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing; import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper; import org.olat.core.util.StringHelper;
...@@ -51,6 +50,8 @@ import org.olat.ldap.model.LDAPUser; ...@@ -51,6 +50,8 @@ import org.olat.ldap.model.LDAPUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import net.fortuna.ical4j.util.TimeZones;
/** /**
* *
* Initial date: 24.11.2014<br> * Initial date: 24.11.2014<br>
...@@ -90,6 +91,30 @@ public class LDAPDAO { ...@@ -90,6 +91,30 @@ public class LDAPDAO {
return ldapGroups; 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) { public void search(LDAPVisitor visitor, String ldapBase, String filter, String[] returningAttrs, LdapContext ctx) {
SearchControls ctls = new SearchControls(); SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
...@@ -217,7 +242,7 @@ public class LDAPDAO { ...@@ -217,7 +242,7 @@ public class LDAPDAO {
return userDN; return userDN;
} }
private String buildSearchUserFilter(String attribute, String uid) { protected String buildSearchUserFilter(String attribute, String uid) {
String ldapUserFilter = syncConfiguration.getLdapUserFilter(); String ldapUserFilter = syncConfiguration.getLdapUserFilter();
StringBuilder filter = new StringBuilder(); StringBuilder filter = new StringBuilder();
if (ldapUserFilter != null) { if (ldapUserFilter != null) {
......
...@@ -40,6 +40,7 @@ import javax.naming.directory.Attributes; ...@@ -40,6 +40,7 @@ import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext; import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem; import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult; import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control; import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.InitialLdapContext;
...@@ -640,6 +641,89 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, GenericEventListe ...@@ -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. * Searches for Identity in OLAT.
* *
......
/**
* <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() {
//
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment