Skip to content
Snippets Groups Projects
Commit 0d823bac authored by srosse's avatar srosse
Browse files

OO-4794: adapt deletion process and add unit test for it

parent 11f02052
No related branches found
No related tags found
No related merge requests found
...@@ -767,24 +767,7 @@ public class BaseSecurityManager implements BaseSecurity, UserDataDeletable { ...@@ -767,24 +767,7 @@ public class BaseSecurityManager implements BaseSecurity, UserDataDeletable {
@Override @Override
public Authentication findAuthentication(IdentityRef identity, String provider) { public Authentication findAuthentication(IdentityRef identity, String provider) {
if (identity==null) { return authenticationDao.getAuthentication(identity, provider);
throw new IllegalArgumentException("identity must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName())
.append(" as auth where auth.identity.key=:identityKey and auth.provider=:provider");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("identityKey", identity.getKey())
.setParameter("provider", provider)
.getResultList();
if (results == null || results.isEmpty()) return null;
if (results.size() > 1) {
throw new AssertException("Found more than one Authentication for a given subject and a given provider.");
}
return results.get(0);
} }
@Override @Override
......
...@@ -32,6 +32,7 @@ import org.olat.basesecurity.IdentityRef; ...@@ -32,6 +32,7 @@ import org.olat.basesecurity.IdentityRef;
import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DB;
import org.olat.core.id.Identity; import org.olat.core.id.Identity;
import org.olat.core.logging.AssertException; import org.olat.core.logging.AssertException;
import org.olat.core.util.StringHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -126,6 +127,48 @@ public class AuthenticationDAO { ...@@ -126,6 +127,48 @@ public class AuthenticationDAO {
.getResultList(); .getResultList();
} }
/**
*
* @param provider The authentication provider
* @return A list of identities (the user is not fetched)
*/
public List<Authentication> getAuthentications(String provider) {
StringBuilder sb = new StringBuilder(256);
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
.append(" inner join fetch auth.identity as ident")
.append(" inner join fetch ident.user as identUser")
.append(" where auth.provider=:provider");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("provider", provider)
.getResultList();
}
public Authentication getAuthentication(IdentityRef identity, String provider) {
if (identity == null || !StringHelper.containsNonWhitespace(provider)) {
throw new IllegalArgumentException("identity must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
.append(" inner join auth.identity as ident")
.append(" inner join ident.user as user")
.append(" where auth.identity.key=:identityKey and auth.provider=:provider");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("identityKey", identity.getKey())
.setParameter("provider", provider)
.getResultList();
if (results == null || results.isEmpty()) {
return null;
}
if (results.size() > 1) {
throw new AssertException("Found more than one Authentication for a given subject and a given provider.");
}
return results.get(0);
}
public Authentication getAuthentication(String authUsername, String provider) { public Authentication getAuthentication(String authUsername, String provider) {
StringBuilder sb = new StringBuilder(256); StringBuilder sb = new StringBuilder(256);
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth") sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
......
...@@ -51,7 +51,7 @@ public interface LDAPLoginManager { ...@@ -51,7 +51,7 @@ public interface LDAPLoginManager {
public Map<String,String> prepareUserPropertyForSync(Attributes attributes, Identity identity); public Map<String,String> prepareUserPropertyForSync(Attributes attributes, Identity identity);
public List<Identity> getIdentitysDeletedInLdap(LdapContext ctx); public List<Identity> getIdentitiesDeletedInLdap(LdapContext ctx);
public Identity findIdentityByLdapAuthentication(Attributes attrs, LDAPError errors); public Identity findIdentityByLdapAuthentication(Attributes attrs, LDAPError errors);
......
...@@ -409,7 +409,9 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -409,7 +409,9 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
*/ */
@Override @Override
public boolean changePassword(Identity identity, String pwd, LDAPError errors) { public boolean changePassword(Identity identity, String pwd, LDAPError errors) {
String uid = identity.getName(); String uid = identity.getName();//TODO username
String ldapUserPasswordAttribute = syncConfiguration.getLdapUserPasswordAttribute(); String ldapUserPasswordAttribute = syncConfiguration.getLdapUserPasswordAttribute();
try { try {
LdapContext ctx = bindSystem(); LdapContext ctx = bindSystem();
...@@ -724,10 +726,12 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -724,10 +726,12 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
LdapContext ctx = bindSystem(); LdapContext ctx = bindSystem();
if (ctx == null) { if (ctx == null) {
log.error("could not bind to ldap"); log.error("could not bind to ldap");
return;
} }
String ldapUserIDAttribute = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER); String ldapUserIDAttribute = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER);
String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, identity.getName()); Authentication authentication = authenticationDao.getAuthentication(identity, LDAPAuthenticationController.PROVIDER_LDAP);
String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, authentication.getAuthusername());
boolean withCoacheOfGroups = StringHelper.containsNonWhitespace(syncConfiguration.getCoachedGroupAttribute()); boolean withCoacheOfGroups = StringHelper.containsNonWhitespace(syncConfiguration.getCoachedGroupAttribute());
List<String> ldapBases = syncConfiguration.getLdapBases(); List<String> ldapBases = syncConfiguration.getLdapBases();
...@@ -874,10 +878,11 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -874,10 +878,11 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
* @throws NamingException * @throws NamingException
*/ */
@Override @Override
public List<Identity> getIdentitysDeletedInLdap(LdapContext ctx) { public List<Identity> getIdentitiesDeletedInLdap(LdapContext ctx) {
if (ctx == null) { if (ctx == null) {
return null; return Collections.emptyList();
} }
// Find all LDAP Users // Find all LDAP Users
String userID = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER); String userID = syncConfiguration.getOlatPropertyToLdapAttribute(LDAPConstants.LDAP_USER_IDENTIFYER);
String userFilter = syncConfiguration.getLdapUserFilter(); String userFilter = syncConfiguration.getLdapUserFilter();
...@@ -897,18 +902,18 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -897,18 +902,18 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
}, (userFilter == null ? "" : userFilter), new String[] { userID }, ctx); }, (userFilter == null ? "" : userFilter), new String[] { userID }, ctx);
if (ldapList.isEmpty()) { if (ldapList.isEmpty()) {
log.warn("No users in LDAP found, can't create deletionList!!"); log.warn("No users in LDAP found, can't create the deletion list.");
return Collections.emptyList(); return Collections.emptyList();
} }
List<Identity> identityListToDelete = new ArrayList<>(); List<Identity> identityListToDelete = new ArrayList<>();
List<Identity> olatListIdentity = authenticationDao.getIdentitiesWithAuthentication(LDAPAuthenticationController.PROVIDER_LDAP); List<Authentication> ldapAuthentications = authenticationDao.getAuthentications(LDAPAuthenticationController.PROVIDER_LDAP);
for (Identity ida:olatListIdentity) { for (Authentication ldapAuthentication:ldapAuthentications) {
// compare usernames with lowercase if (!ldapList.contains(ldapAuthentication.getAuthusername().toLowerCase())) {
if (!ldapList.contains(ida.getName().toLowerCase())) { identityListToDelete.add(ldapAuthentication.getIdentity());
identityListToDelete.add(ida);
} }
} }
dbInstance.commitAndCloseSession();
return identityListToDelete; return identityListToDelete;
} }
...@@ -1167,7 +1172,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -1167,7 +1172,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
break; break;
} }
default: { default: {
log.error("LDAP Role synchronization not supported for: " + role); log.error("LDAP Role synchronization not supported for: {}", role);
} }
} }
} }
...@@ -1175,11 +1180,12 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -1175,11 +1180,12 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
private void doBatchSyncDeletedUsers(LdapContext ctx, String sinceSentence) { private void doBatchSyncDeletedUsers(LdapContext ctx, String sinceSentence) {
// create User to Delete List // create User to Delete List
List<Identity> deletedUserList = getIdentitysDeletedInLdap(ctx); List<Identity> deletedUserList = getIdentitiesDeletedInLdap(ctx);
// delete old users // delete old users
if (deletedUserList == null || deletedUserList.isEmpty()) { if (deletedUserList == null || deletedUserList.isEmpty()) {
log.info("LDAP batch sync: no users to delete" + sinceSentence); log.info("LDAP batch sync: no users to delete {}", sinceSentence);
} else { } else {
int deletedUserListSize = deletedUserList.size();
if (ldapLoginModule.isDeleteRemovedLDAPUsersOnSync()) { if (ldapLoginModule.isDeleteRemovedLDAPUsersOnSync()) {
// check if more not more than the defined percentages of // check if more not more than the defined percentages of
// users managed in LDAP should be deleted // users managed in LDAP should be deleted
...@@ -1189,31 +1195,24 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -1189,31 +1195,24 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
if (olatListIdentity.isEmpty()) if (olatListIdentity.isEmpty())
log.info("No users managed by LDAP, can't delete users"); log.info("No users managed by LDAP, can't delete users");
else { else {
int prozente = (int) (((float)deletedUserList.size() / (float) olatListIdentity.size())*100); int prozente = (int) (((float)deletedUserListSize / (float) olatListIdentity.size()) * 100.0);
if (prozente >= ldapLoginModule.getDeleteRemovedLDAPUsersPercentage()) { int cutValue = ldapLoginModule.getDeleteRemovedLDAPUsersPercentage();
log.info("LDAP batch sync: more than " if (prozente >= cutValue) {
+ ldapLoginModule.getDeleteRemovedLDAPUsersPercentage() log.info("LDAP batch sync: more than {}% of LDAP managed users should be deleted. Please use Admin Deletion Job. Or increase deleteRemovedLDAPUsersPercentage. {}% tried to delete.", cutValue, prozente);
+ "% of LDAP managed users should be deleted. Please use Admin Deletion Job. Or increase deleteRemovedLDAPUsersPercentage. "
+ prozente
+ "% tried to delete.");
} else { } else {
// delete users // delete users
deleteIdentities(deletedUserList, null); deleteIdentities(deletedUserList, null);
log.info("LDAP batch sync: " + deletedUserList.size() + " users deleted" + sinceSentence); log.info("LDAP batch sync: {} users deleted {}", deletedUserListSize, sinceSentence);
} }
} }
} else { } else {
// Do nothing, only log users to logfile // Do nothing, only log users to logfile
StringBuilder users = new StringBuilder(); StringBuilder users = new StringBuilder(deletedUserListSize * 42);
for (Identity toBeDeleted : deletedUserList) { for (Identity toBeDeleted : deletedUserList) {
users.append(toBeDeleted.getName()).append(','); users.append(toBeDeleted.getKey()).append(',');
} }
log.info("LDAP batch sync: " log.info("LDAP batch sync: {} users detected as to be deleted {}. Automatic deleting is disabled in LDAPLoginModule, delete these users manually::[{}]",
+ deletedUserList.size() deletedUserListSize, sinceSentence, users);
+ " users detected as to be deleted"
+ sinceSentence
+ ". Automatic deleting is disabled in LDAPLoginModule, delete these users manually::["
+ users.toString() + "]");
} }
} }
dbInstance.commitAndCloseSession(); dbInstance.commitAndCloseSession();
...@@ -1558,7 +1557,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro ...@@ -1558,7 +1557,7 @@ public class LDAPLoginManagerImpl implements LDAPLoginManager, AuthenticationPro
} }
String ldapUserIDAttribute = syncConfiguration.getLdapUserLoginAttribute(); String ldapUserIDAttribute = syncConfiguration.getLdapUserLoginAttribute();
Authentication authentication = securityManager.findAuthentication(ident, LDAPAuthenticationController.PROVIDER_LDAP); Authentication authentication = authenticationDao.getAuthentication(ident, LDAPAuthenticationController.PROVIDER_LDAP);
String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, authentication.getAuthusername()); String filter = ldapDao.buildSearchUserFilter(ldapUserIDAttribute, authentication.getAuthusername());
List<Attributes> ldapUserAttrs = new ArrayList<>(); List<Attributes> ldapUserAttrs = new ArrayList<>();
......
...@@ -190,7 +190,7 @@ public class LDAPAdminController extends BasicController implements GenericEvent ...@@ -190,7 +190,7 @@ public class LDAPAdminController extends BasicController implements GenericEvent
// get deleted users // get deleted users
List<Identity> identitiesToDelete = null; List<Identity> identitiesToDelete = null;
try { try {
identitiesToDelete = ldapLoginManager.getIdentitysDeletedInLdap(ctx); identitiesToDelete = ldapLoginManager.getIdentitiesDeletedInLdap(ctx);
ctx.close(); ctx.close();
} catch (NamingException e) { } catch (NamingException e) {
showError("delete.error.connection.close"); showError("delete.error.connection.close");
......
...@@ -70,6 +70,17 @@ public class AuthenticationDAOTest extends OlatTestCase { ...@@ -70,6 +70,17 @@ public class AuthenticationDAOTest extends OlatTestCase {
Assert.assertEquals(newToken, updatedAuth.getCredential()); Assert.assertEquals(newToken, updatedAuth.getCredential());
} }
@Test
public void getAuthenticationIdentityProvider() {
IdentityWithLogin ident = JunitTestHelper.createAndPersistRndUser("authdao-1-");
dbInstance.commitAndCloseSession();
//check if the new token was saved
Authentication authentication = authenticationDao.getAuthentication(ident.getIdentity(), "OLAT");
Assert.assertEquals(ident.getIdentity(), authentication.getIdentity());
Assert.assertEquals(ident.getLogin(), authentication.getAuthusername());
}
@Test @Test
public void getIdentitiesWithAuthentication() { public void getIdentitiesWithAuthentication() {
String token = UUID.randomUUID().toString(); String token = UUID.randomUUID().toString();
...@@ -142,6 +153,19 @@ public class AuthenticationDAOTest extends OlatTestCase { ...@@ -142,6 +153,19 @@ public class AuthenticationDAOTest extends OlatTestCase {
Assert.assertEquals(ident.getIdentity(), olatAuthentications.get(0).getIdentity()); Assert.assertEquals(ident.getIdentity(), olatAuthentications.get(0).getIdentity());
} }
@Test
public void getAuthenticationsByProvider() {
IdentityWithLogin ident = JunitTestHelper.createAndPersistRndUser("authdao-2-");
dbInstance.commitAndCloseSession();
Assert.assertNotNull(ident);
List<Authentication> olatAuthentications = authenticationDao.getAuthentications("OLAT");
Assert.assertNotNull(olatAuthentications);
for(Authentication authentication:olatAuthentications) {
Assert.assertEquals("OLAT", authentication.getProvider());
}
}
@Test @Test
public void getAuthenticationsByAuthusername_providersList() { public void getAuthenticationsByAuthusername_providersList() {
String token = UUID.randomUUID().toString(); String token = UUID.randomUUID().toString();
......
...@@ -22,9 +22,11 @@ package org.olat.ldap.manager; ...@@ -22,9 +22,11 @@ package org.olat.ldap.manager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.naming.directory.Attributes; import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapContext;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume; import org.junit.Assume;
...@@ -47,6 +49,7 @@ import org.olat.ldap.LDAPLoginManager; ...@@ -47,6 +49,7 @@ import org.olat.ldap.LDAPLoginManager;
import org.olat.ldap.LDAPLoginModule; import org.olat.ldap.LDAPLoginModule;
import org.olat.ldap.LDAPSyncConfiguration; import org.olat.ldap.LDAPSyncConfiguration;
import org.olat.ldap.ui.LDAPAuthenticationController; import org.olat.ldap.ui.LDAPAuthenticationController;
import org.olat.test.JunitTestHelper;
import org.olat.test.OlatTestCase; import org.olat.test.OlatTestCase;
import org.olat.user.UserManager; import org.olat.user.UserManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -106,6 +109,27 @@ public class LDAPLoginManagerTest extends OlatTestCase { ...@@ -106,6 +109,27 @@ public class LDAPLoginManagerTest extends OlatTestCase {
Assert.assertNotNull(identity); Assert.assertNotNull(identity);
} }
@Test
public void getIdentitiesDeletedInLdap() {
Assume.assumeTrue(ldapLoginModule.isLDAPEnabled());
Identity orphan = JunitTestHelper.createAndPersistIdentityAsRndUser("ldap-orphan");
securityManager.createAndPersistAuthentication(orphan, LDAPAuthenticationController.PROVIDER_LDAP,
UUID.randomUUID().toString(), null, null);
dbInstance.commitAndCloseSession();
LdapContext ctx = ldapManager.bindSystem();
List<Identity> identities = ldapManager.getIdentitiesDeletedInLdap(ctx);
Assert.assertNotNull(identities);
Assert.assertTrue(identities.contains(orphan));
// historic
Identity identity1 = userManager.findUniqueIdentityByEmail("hhuerlimann@openolat.com");
Assert.assertFalse(identities.contains(identity1));
Identity identity2 = userManager.findUniqueIdentityByEmail("ahentschel@openolat.com");
Assert.assertFalse(identities.contains(identity2));
}
@Test @Test
public void doSyncSingleUserWithLoginAttribute() throws LDAPException { public void doSyncSingleUserWithLoginAttribute() throws LDAPException {
Assume.assumeTrue(ldapLoginModule.isLDAPEnabled()); Assume.assumeTrue(ldapLoginModule.isLDAPEnabled());
......
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