From fd5b6407e68c6a98e6d3659da55369d5cb0d3ee2 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Wed, 18 Jul 2018 11:53:48 +0200
Subject: [PATCH] user is automatically created when local user doesn't exist
 and authentication goes via ldap

---
 .../model/user/ConfigurationElementType.java  |    2 +-
 .../java/lcsb/mapviewer/model/user/User.java  |   17 +-
 .../src/db/12.1.0~alpha.0/fix_db_20180718.sql |    2 +
 .../mapviewer/persist/dao/user/UserDao.java   |  165 +--
 .../persist/dao/user/UserDaoTest.java         |   43 -
 .../mapviewer/services/impl/LdapService.java  |   14 +-
 .../services/impl/ProjectService.java         |   17 +-
 .../mapviewer/services/impl/UserService.java  | 1130 +++++++++--------
 .../services/interfaces/ILdapService.java     |    2 +-
 .../services/interfaces/IUserService.java     |    7 +
 .../services/impl/AllImplServiceTests.java    |   15 +-
 .../services/impl/LdapServiceTest.java        |    4 +-
 .../services/impl/UserServiceTest.java        |   62 +
 .../testFiles/ldap/john-doe-test-example.ldif |   92 ++
 .../CustomAuthenticationProvider.java         |   53 +
 .../security/MvSecurityServiceImpl.java       |   72 --
 .../main/webapp/WEB-INF/security-context.xml  |    9 +-
 17 files changed, 923 insertions(+), 783 deletions(-)
 create mode 100644 persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql
 create mode 100644 service/testFiles/ldap/john-doe-test-example.ldif
 create mode 100644 web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java
 delete mode 100644 web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java

diff --git a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
index dae902490a..d5aba762cb 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
@@ -221,7 +221,7 @@ public enum ConfigurationElementType {
       ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
   LDAP_EMAIL_ATTRIBUTE("LDAP email attribute", "mail", ConfigurationElementEditType.STRING, true,
       ConfigurationElementTypeGroup.LDAP_CONFIGURATION),//
-  LDAP_FILTER("LDAP filter ", "(memberof=cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu)", ConfigurationElementEditType.STRING, true,
+  LDAP_FILTER("LDAP filter ", "(memberof=cn=minerva,cn=groups,cn=accounts,dc=uni,dc=lu)", ConfigurationElementEditType.STRING, true,
       ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
 
   ;
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/User.java b/model/src/main/java/lcsb/mapviewer/model/user/User.java
index fdb5e080a1..1add1fd25f 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/User.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/User.java
@@ -118,8 +118,13 @@ public class User implements Serializable {
    */
   private boolean removed = false;
 
-    @Column(name="terms_of_use_consent")
-    private boolean                     termsOfUseConsent = false;
+  /**
+   * User is connected to LDAP directory.
+   */
+  private boolean connectedToLdap = false;
+
+  @Column(name = "terms_of_use_consent")
+  private boolean termsOfUseConsent = false;
 
   /**
    * Set of user privileges.
@@ -378,4 +383,12 @@ public class User implements Serializable {
     this.termsOfUseConsent = termsOfUseConsent;
   }
 
+  public boolean isConnectedToLdap() {
+    return connectedToLdap;
+  }
+
+  public void setConnectedToLdap(boolean connectedToLdap) {
+    this.connectedToLdap = connectedToLdap;
+  }
+
 }
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql
new file mode 100644
index 0000000000..6872876ec7
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql
@@ -0,0 +1,2 @@
+-- user account can be connected to LDAP directory 
+alter table user_table add column connectedtoldap boolean default false;
diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
index 84af311b9b..bedec091dd 100644
--- a/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
+++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
@@ -2,9 +2,6 @@ package lcsb.mapviewer.persist.dao.user;
 
 import java.util.List;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.crypto.password.PasswordEncoder;
-
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.BaseDao;
 
@@ -16,102 +13,80 @@ import lcsb.mapviewer.persist.dao.BaseDao;
  */
 public class UserDao extends BaseDao<User> {
 
-	/**
-	 * Service that provides password encoding.
-	 */
-	@Autowired
-	private PasswordEncoder passwordEncoder;
-
-	/**
-	 * Default constructor.
-	 */
-	public UserDao() {
-		super(User.class, "removed");
-	}
-
-	/**
-	 * Returns user with a given login and password.
-	 * 
-	 * @param login
-	 *          user login
-	 * @param password
-	 *          - user password (plain text)
-	 * @return user for given login and password
-	 */
-	public User getUserByLoginAndPassword(String login, String password) {
-		if (password == null) {
-			return getUserByLoginAndCryptedPassword(login, null);
-		}
-		return getUserByLoginAndCryptedPassword(login, passwordEncoder.encode(password));
-	}
+  /**
+   * Default constructor.
+   */
+  public UserDao() {
+    super(User.class, "removed");
+  }
 
-	/**
-	 * Returns user with a given login and password.
-	 * 
-	 * @param login
-	 *          user login
-	 * @param password
-	 *          - user password (encrypted)
-	 * @return user for given login and password
-	 */
-	public User getUserByLoginAndCryptedPassword(String login, String password) {
-		List<?> list = getSession()
-				.createQuery(" from User where login=:login and cryptedPassword =:passwd " + removableAndStatemant()).setParameter("login", login)
-				.setParameter("passwd", password).list();
-		if (list.size() == 0) {
-			return null;
-		} else {
-			User user = (User) list.get(0);
-			return user;
-		}
-	}
+  /**
+   * Returns user with a given login and password.
+   * 
+   * @param login
+   *          user login
+   * @param password
+   *          - user password (encrypted)
+   * @return user for given login and password
+   */
+  public User getUserByLoginAndCryptedPassword(String login, String password) {
+    List<?> list = getSession()
+        .createQuery(" from User where login=:login and cryptedPassword =:passwd " + removableAndStatemant())
+        .setParameter("login", login).setParameter("passwd", password).list();
+    if (list.size() == 0) {
+      return null;
+    } else {
+      User user = (User) list.get(0);
+      return user;
+    }
+  }
 
-	/**
-	 * Returns user with a given login.
-	 * 
-	 * @param login
-	 *          user login
-	 * @return user for a given login
-	 */
-	public User getUserByLogin(String login) {
-		return getByParameter("login", login);
-	}
+  /**
+   * Returns user with a given login.
+   * 
+   * @param login
+   *          user login
+   * @return user for a given login
+   */
+  public User getUserByLogin(String login) {
+    return getByParameter("login", login);
+  }
 
-	/**
-	 * Returns user with a given email.
-	 * 
-	 * @param email
-	 *          user email
-	 * @return user for a given email
-	 */
-	public User getUserByEmail(String email) {
-		return getByParameter("email", email);
-	}
+  /**
+   * Returns user with a given email.
+   * 
+   * @param email
+   *          user email
+   * @return user for a given email
+   */
+  public User getUserByEmail(String email) {
+    return getByParameter("email", email);
+  }
 
-	@Override
-	public void delete(User object) {
-		object.setRemoved(true);
-		object.setLogin("[REMOVED]_" + object.getId() + "_" + object.getLogin());
-		update(object);
-	}
+  @Override
+  public void delete(User object) {
+    object.setRemoved(true);
+    object.setLogin("[REMOVED]_" + object.getId() + "_" + object.getLogin());
+    update(object);
+  }
 
-	/**
-	 * Returns {@link User} for given "name surname" string.
-	 * 
-	 * @param nameSurnameString
-	 *          string identifing user with name and surname separated by single
-	 *          space
-	 * @return {@link User} for given "name surname" string
-	 */
-	public User getUserByNameSurname(String nameSurnameString) {
-		List<?> list = getSession()
-				.createQuery(" from " + this.getClazz().getSimpleName() + " where  concat(name, ' ', surname) " + " = :param_val " + removableAndStatemant())
-				.setParameter("param_val", nameSurnameString).list();
-		if (list.size() == 0) {
-			return null;
-		} else {
-			return (User) list.get(0);
-		}
-	}
+  /**
+   * Returns {@link User} for given "name surname" string.
+   * 
+   * @param nameSurnameString
+   *          string identifing user with name and surname separated by single
+   *          space
+   * @return {@link User} for given "name surname" string
+   */
+  public User getUserByNameSurname(String nameSurnameString) {
+    List<?> list = getSession().createQuery(" from " + this.getClazz().getSimpleName()
+        + " where  concat(name, ' ', surname) " + " = :param_val " + removableAndStatemant())
+        .setParameter("param_val", nameSurnameString).list();
+    if (list.size() == 0) {
+      return null;
+    } else {
+      return (User) list.get(0);
+    }
+  }
 
 }
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
index 0192989f6d..373262230d 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
@@ -122,49 +122,6 @@ public class UserDaoTest extends PersistTestFunctions {
     }
   }
 
-  @Test
-  public void testGetUserByLoginAndPassword() throws Exception {
-    try {
-      User user = new User();
-      user.setCryptedPassword(passwordEncoder.encode(testPasswd));
-      user.setLogin(testLogin);
-      userDao.add(user);
-      User user2 = userDao.getUserByLoginAndPassword(testLogin, testPasswd);
-      assertNotNull(user2);
-      assertEquals(user2.getId(), user.getId());
-      assertEquals(user2.getLogin(), user.getLogin());
-      assertEquals(user2.getCryptedPassword(), user.getCryptedPassword());
-      userDao.delete(user);
-      // after we remove it we shouldn't be able to get it
-      User user3 = userDao.getUserByLoginAndPassword(testLogin, testPasswd);
-      assertNull(user3);
-
-      // after we remove it we shouldn't be able to get the removed and modified
-      // object
-      User user4 = userDao.getUserByLoginAndPassword(user2.getLogin(), testPasswd);
-      assertNull(user4);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetUserByLoginAndEmptyPassword() throws Exception {
-    try {
-      User user = new User();
-      user.setCryptedPassword(passwordEncoder.encode(testPasswd));
-      user.setLogin(testLogin);
-      userDao.add(user);
-      User user2 = userDao.getUserByLoginAndPassword(testLogin, null);
-      assertNull(user2);
-      userDao.delete(user);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
   @Test
   public void testGetUserByLogin() throws Exception {
     try {
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java b/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java
index 8a2a96dbe3..8e40c11e36 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java
@@ -78,7 +78,7 @@ public class LdapService implements ILdapService {
 
   @Override
   public boolean login(String login, String password) throws LDAPException {
-    if (!isValidConfiguratio()) {
+    if (!isValidConfiguration()) {
       logger.warn("Invalid LDAP configuration");
       return false;
     }
@@ -98,7 +98,7 @@ public class LdapService implements ILdapService {
 
   @Override
   public List<String> getUsernames() throws LDAPException {
-    if (!isValidConfiguratio()) {
+    if (!isValidConfiguration()) {
       logger.warn("Invalid LDAP configuration");
       return new ArrayList<>();
     }
@@ -128,7 +128,7 @@ public class LdapService implements ILdapService {
 
   @Override
   public UserDTO getUserByLogin(String login) throws LDAPException {
-    if (!isValidConfiguratio()) {
+    if (!isValidConfiguration()) {
       logger.warn("Invalid LDAP configuration");
       return null;
     }
@@ -187,11 +187,11 @@ public class LdapService implements ILdapService {
     }
   }
 
-  private Filter createObjectClassFilter() {
+  private Filter createObjectClassFilter() throws LDAPException {
     String objectClass = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS);
 
-    if (objectClass == null || objectClass.trim().isEmpty()) {
-      objectClass = "*";
+    if (objectClass == null || objectClass.trim().isEmpty() || objectClass .equals( "*")) {
+      return Filter.create("objectClass=*");
     }
 
     return  Filter.createEqualityFilter("objectClass", objectClass);
@@ -220,7 +220,7 @@ public class LdapService implements ILdapService {
   }
 
   @Override
-  public boolean isValidConfiguratio() {
+  public boolean isValidConfiguration() {
     try {
       String baseDn = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_BASE_DN);
       if (baseDn == null || baseDn.trim().isEmpty()) {
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
index b79e0ef372..fe26c10cbf 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
@@ -5,7 +5,6 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -60,7 +59,6 @@ import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.ProjectStatus;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
-import lcsb.mapviewer.model.graphics.MapCanvasType;
 import lcsb.mapviewer.model.log.LogType;
 import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.MiriamData;
@@ -477,20 +475,7 @@ public class ProjectService implements IProjectService {
     for (User user : userDao.getAll()) {
       if (!processedUser.contains(user)) {
         processedUser.add(user);
-        for (PrivilegeType type : PrivilegeType.values()) {
-          if (Project.class.equals(type.getPrivilegeObjectType())) {
-            int level = userService.getUserPrivilegeLevel(user, type, (Integer) null);
-            if (level < 0) {
-              if (configurationService.getValue(type).getValue().equalsIgnoreCase("true")) {
-                level = 1;
-              } else {
-                level = 0;
-              }
-            }
-            ObjectPrivilege privilege = new ObjectPrivilege(project, level, type, user);
-            userService.setUserPrivilege(user, privilege);
-          }
-        }
+        userService.createDefaultProjectPrivilegesForUser(project, user);
       }
     }
 
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
index 6eb486fdb5..2baf2dee79 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
@@ -1,530 +1,600 @@
-package lcsb.mapviewer.services.impl;
-
-import java.awt.Color;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.session.SessionInformation;
-import org.springframework.security.core.session.SessionRegistry;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.ObjectUtils;
-import lcsb.mapviewer.common.comparator.IntegerComparator;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.geometry.ColorParser;
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.log.LogType;
-import lcsb.mapviewer.model.user.BasicPrivilege;
-import lcsb.mapviewer.model.user.ConfigurationElementType;
-import lcsb.mapviewer.model.user.ObjectPrivilege;
-import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.persist.dao.ProjectDao;
-import lcsb.mapviewer.persist.dao.user.PrivilegeDao;
-import lcsb.mapviewer.persist.dao.user.UserDao;
-import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.interfaces.IConfigurationService;
-import lcsb.mapviewer.services.interfaces.ILogService;
-import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
-import lcsb.mapviewer.services.interfaces.IUserService;
-
-/**
- * Implementation of the service that manages users.
- * 
- * @author Piotr Gawron
- * 
- */
-@Transactional(value = "txManager")
-public class UserService implements IUserService {
-
-  /**
-   * Default class logger.
-   */
-  private static Logger logger = Logger.getLogger(UserService.class);
-
-  /**
-   * Data access object for users.
-   */
-  @Autowired
-  private UserDao userDao;
-
-  /**
-   * Data access object for projects.
-   */
-  @Autowired
-  private ProjectDao projectDao;
-
-  /**
-   * Data access object for privileges.
-   */
-  @Autowired
-  private PrivilegeDao privilegeDao;
-
-  @Autowired
-  private SessionRegistry sessionRegistry;
-
-  /**
-   * Service that provides password encoding.
-   */
-  @Autowired
-  private PasswordEncoder passwordEncoder;
-
-  /**
-   * Service used for logging.
-   */
-  @Autowired
-  private ILogService logService;
-
-  /**
-   * Service used for accessing configuration parameters.
-   */
-  @Autowired
-  private IConfigurationService configurationService;
-
-  @Override
-  public String login(String login, String password) {
-    Random random = new SecureRandom();
-    String id = new BigInteger(130, random).toString(32);
-    return this.login(login, password, id);
-  }
-
-  @Override
-  public boolean userHasPrivilege(User user, PrivilegeType type) {
-    return getUserPrivilegeLevel(user, type) > 0;
-  }
-
-  @Override
-  public boolean userHasPrivilege(User user, PrivilegeType type, Object object) {
-    return getUserPrivilegeLevel(user, type, object) > 0;
-  }
-
-	@Override
-	public void setUserPrivilege(User user, BasicPrivilege privilege) {
-		updateUserPrivilegesWithoutDbModification(user, privilege);
-		updateUser(user);
-		userDao.flush();
-	}
-
-    private void updateUserPrivilegesWithoutDbModification(User user, BasicPrivilege privilege) {
-		BasicPrivilege oldPrivilege = null;
-		for (BasicPrivilege privilegeIter : user.getPrivileges()) {
-			if (privilegeIter.equalsPrivilege(privilege)) {
-				oldPrivilege = privilegeIter;
-			}
-		}
-		if (oldPrivilege != null) {
-		    privilege.setUser(null);
-		    oldPrivilege.setLevel(privilege.getLevel());
-		} else {
-		    privilege.setUser(user);
-		    user.getPrivileges().add(privilege);
-		}
-    }
-
-  @Override
-  public void addUser(User user) {
-    userDao.add(user);
-    LogParams params = new LogParams().description("User " + user.getLogin() + " created.").type(LogType.USER_CREATED)
-        .object(user);
-    logService.log(params);
-  }
-
-  @Override
-  public void updateUser(User user) {
-    userDao.update(user);
-  }
-
-  @Override
-  public void deleteUser(User user) {
-    userDao.delete(user);
-    LogParams params = new LogParams().description("User " + user.getLogin() + " removed.").type(LogType.USER_CREATED)
-        .object(user);
-    logService.log(params);
-  }
-
-  @Override
-  public User getUserById(int id) {
-    User result = userDao.getById(id);
-    if (result != null) {
-      userDao.refresh(result);
-    }
-    return result;
-  }
-
-  @Override
-  public User getUserByLogin(String login) {
-    User result = userDao.getUserByLogin(login);
-    if (result != null) {
-      userDao.refresh(result);
-    }
-    return result;
-  }
-
-  @Override
-  public void dropPrivilegesForObjectType(PrivilegeType type, int id) {
-    IntegerComparator integerComparator = new IntegerComparator();
-    // this will be slow when number of user will increase (we fetch all
-    // users and drop privileges one by one)
-    List<User> users = userDao.getAll();
-    for (User user : users) {
-      List<BasicPrivilege> toRemove = new ArrayList<BasicPrivilege>();
-      for (BasicPrivilege privilege : user.getPrivileges()) {
-        if (privilege.getType().equals(type) && privilege instanceof ObjectPrivilege
-            && integerComparator.compare(((ObjectPrivilege) privilege).getIdObject(), id) == 0) {
-          toRemove.add(privilege);
-        }
-      }
-      if (toRemove.size() > 0) {
-        user.getPrivileges().removeAll(toRemove);
-        userDao.update(user);
-      }
-    }
-  }
-
-  @Override
-  public int getUserPrivilegeLevel(User user, PrivilegeType type) {
-    if (type.getPrivilegeClassType() != BasicPrivilege.class) {
-      throw new InvalidArgumentException("This privilege requires additional information");
-    }
-    for (BasicPrivilege privilege : user.getPrivileges()) {
-      if (privilege.getType().equals(type)) {
-        return privilege.getLevel();
-      }
-    }
-    return 0;
-  }
-
-  @Override
-  public int getUserPrivilegeLevel(User user, PrivilegeType type, Object object) {
-    Integer id = null;
-    if (object != null) {
-      try {
-        id = ObjectUtils.getIdOfObject(object);
-      } catch (Exception e) {
-        logger.error(e.getMessage(), e);
-        throw new InvalidArgumentException("Internal server error. Problem with accessing id of the parameter object");
-      }
-      if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
-        throw new InvalidArgumentException("This privilege accept only " + type.getPrivilegeObjectType()
-            + " objects parameter, but " + object.getClass() + " class found.");
-      }
-    }
-    return getUserPrivilegeLevel(user, type, id);
-  }
-
-  private int getUserPrivilegeLevel(User user, PrivilegeType type, Integer id) {
-    if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
-      throw new InvalidArgumentException("This privilege doesn't accept object parameter");
-    }
-    if (user == null) {
-      throw new InvalidArgumentException("User cannot be null");
-    }
-
-    // refresh user from db
-    if (user.getId() != null) {
-      user = userDao.getById(user.getId());
-    }
-    IntegerComparator integerComparator = new IntegerComparator();
-    for (BasicPrivilege privilege : user.getPrivileges()) {
-      if (privilege.getClass() == ObjectPrivilege.class) {
-        ObjectPrivilege oPrivilege = (ObjectPrivilege) privilege;
-        if (oPrivilege.getType().equals(type) && integerComparator.compare(oPrivilege.getIdObject(), id) == 0) {
-          return privilege.getLevel();
-        }
-      }
-    }
-    return -1;
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Integer value) {
-    BasicPrivilege privilege = new BasicPrivilege(value, type, user);
-
-    BasicPrivilege oldPrivilege = null;
-    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
-      if (privilegeIter.getType().equals(type)) {
-        oldPrivilege = privilegeIter;
-      }
-    }
-    if (oldPrivilege != null) {
-      user.getPrivileges().remove(oldPrivilege);
-      oldPrivilege.setUser(null);
-    }
-    user.getPrivileges().add(privilege);
-    updateUser(user);
-    userDao.flush();
-
-  }
-
-  /**
-   * @return the userDao
-   * @see #userDao
-   */
-  public UserDao getUserDao() {
-    return userDao;
-  }
-
-  /**
-   * @param userDao
-   *          the userDao to set
-   * @see #userDao
-   */
-  public void setUserDao(UserDao userDao) {
-    this.userDao = userDao;
-  }
-
-  /**
-   * @return the projectDao
-   * @see #projectDao
-   */
-  public ProjectDao getProjectDao() {
-    return projectDao;
-  }
-
-  /**
-   * @param projectDao
-   *          the projectDao to set
-   * @see #projectDao
-   */
-  public void setProjectDao(ProjectDao projectDao) {
-    this.projectDao = projectDao;
-  }
-
-  /**
-   * @return the privilegeDao
-   * @see #privilegeDao
-   */
-  public PrivilegeDao getPrivilegeDao() {
-    return privilegeDao;
-  }
-
-  /**
-   * @param privilegeDao
-   *          the privilegeDao to set
-   * @see #privilegeDao
-   */
-  public void setPrivilegeDao(PrivilegeDao privilegeDao) {
-    this.privilegeDao = privilegeDao;
-  }
-
-  /**
-   * @return the passwordEncoder
-   * @see #passwordEncoder
-   */
-  public PasswordEncoder getPasswordEncoder() {
-    return passwordEncoder;
-  }
-
-  /**
-   * @param passwordEncoder
-   *          the passwordEncoder to set
-   * @see #passwordEncoder
-   */
-  public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
-    this.passwordEncoder = passwordEncoder;
-  }
-
-  /**
-   * @param password
-   *          input password
-   * @return encoded password
-   */
-  @Override
-  public String encodePassword(String password) {
-    return passwordEncoder.encode(password);
-  }
-
-  @Override
-  public User getUserByNameSurname(String nameSurnameString) {
-    return userDao.getUserByNameSurname(nameSurnameString);
-  }
-
-  @Override
-  public ColorExtractor getColorExtractorForUser(User loggedUser) {
-    Color colorMin = null;
-    Color colorMax = null;
-    Color colorSimple = null;
-    if (loggedUser != null) {
-      User dbUser = getUserById(loggedUser.getId());
-      if (dbUser != null) {
-        colorMin = dbUser.getMinColor();
-        colorMax = dbUser.getMaxColor();
-        colorSimple = dbUser.getSimpleColor();
-      }
-    }
-    ColorParser parser = new ColorParser();
-
-    if (colorMin == null) {
-      colorMin = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MIN_COLOR_VAL));
-    }
-    if (colorMax == null) {
-      colorMax = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MAX_COLOR_VAL));
-    }
-    if (colorSimple == null) {
-      colorSimple = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.SIMPLE_COLOR_VAL));
-    }
-    return new ColorExtractor(colorMin, colorMax, colorSimple);
-  }
-
-  /**
-   * @return the configurationService
-   * @see #configurationService
-   */
-  public IConfigurationService getConfigurationService() {
-    return configurationService;
-  }
-
-  /**
-   * @param configurationService
-   *          the configurationService to set
-   * @see #configurationService
-   */
-  public void setConfigurationService(IConfigurationService configurationService) {
-    this.configurationService = configurationService;
-  }
-
-  @Override
-  public User getUserByToken(String token) throws SecurityException {
-    if (!isSessionExpired(token)) {
-      String login = ((org.springframework.security.core.userdetails.User) (sessionRegistry.getSessionInformation(token)
-          .getPrincipal())).getUsername();
-      return userDao.getUserByLogin(login);
-    } else {
-      throw new SecurityException("Invalid token");
-    }
-  }
-
-  private boolean isSessionExpired(String token) {
-    SessionInformation sessionData = sessionRegistry.getSessionInformation(token);
-    if (sessionData == null) {
-      logger.debug("No session data for token id: " + token);
-      return true;
-    }
-    return sessionData.isExpired();
-  }
-
-  @Override
-  public boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException {
-    return userHasPrivilege(getUserByToken(token), type, object);
-  }
-
-  @Override
-  public void logout(String tokenString) {
-    if (!isSessionExpired(tokenString)) {
-      sessionRegistry.removeSessionInformation(tokenString);
-    }
-  }
-
-  @Override
-  public User getUserById(String creatorId, String authenticationToken) throws SecurityException {
-    User user = getUserByToken(authenticationToken);
-    Integer id = Integer.parseInt(creatorId);
-    if (user.getId().equals(id)) {
-      return user;
-    } else if (userHasPrivilege(authenticationToken, PrivilegeType.USER_MANAGEMENT)) {
-      return getUserById(id);
-    } else {
-      throw new SecurityException("You cannot access data of other users");
-    }
-  }
-
-  @Override
-  public List<User> getUsers(String token) throws SecurityException {
-    if (userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      return userDao.getAll();
-    } else {
-      throw new SecurityException("You have no access to users data");
-    }
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Object value, String token) throws SecurityException {
-    if (!userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      throw new SecurityException("You cannot modify user privileges");
-    }
-    if (value instanceof Integer) {
-      setUserPrivilege(user, type, (Integer) value);
-    } else if (value instanceof Boolean) {
-      if ((Boolean) value) {
-        setUserPrivilege(user, type, 1);
-      } else {
-        setUserPrivilege(user, type, 0);
-      }
-    } else {
-      throw new InvalidArgumentException("Invalid privilege value: " + value);
-    }
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Object value, Integer objectId, String token)
-      throws SecurityException {
-    boolean canModify = userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
-    if (!canModify) {
-      if (type.getPrivilegeObjectType().isAssignableFrom(Project.class)) {
-        canModify = getUserPrivilegeLevel(getUserByToken(token), type, objectId) > 0;
-      }
-    }
-    if (!canModify) {
-      throw new SecurityException("You cannot modify user privileges");
-    }
-    Project projectIdWrapper = new Project();
-    if (objectId == null) {
-      projectIdWrapper = null;
-    } else {
-      projectIdWrapper.setId(objectId);
-    }
-    if (value instanceof Integer) {
-      setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, (Integer) value, type, user));
-    } else if (value instanceof Boolean) {
-      if ((Boolean) value) {
-        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 1, type, user));
-      } else {
-        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 0, type, user));
-      }
-    } else {
-      throw new InvalidArgumentException("Invalid privilege value: " + value);
-    }
-
-  }
-
-  @Override
-  public void updateUser(User modifiedUser, String token) throws SecurityException {
-    User user = getUserByToken(token);
-    if (user.getLogin().equals(modifiedUser.getLogin()) || userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      updateUser(modifiedUser);
-    } else {
-      throw new SecurityException("You cannot modify user");
-    }
-
-  }
-
-  @Override
-  public boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException {
-    return userHasPrivilege(getUserByToken(token), type);
-  }
-
-  @Override
-  public String login(String login, String password, String token) {
-    User user = userDao.getUserByLoginAndPassword(login, password);
-    if (user == null && Configuration.ANONYMOUS_LOGIN.equals(login) && "".equals(password)) {
-      user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
-    }
-    if (user != null) {
-      sessionRegistry.registerNewSession(token, new org.springframework.security.core.userdetails.User(login,
-          passwordEncoder.encode(password), AuthorityUtils.commaSeparatedStringToAuthorityList("")));
-      return token;
-    } else {
-      return null;
-    }
-  }
-
-}
+package lcsb.mapviewer.services.impl;
+
+import java.awt.Color;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.unboundid.ldap.sdk.LDAPException;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.ObjectUtils;
+import lcsb.mapviewer.common.comparator.IntegerComparator;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.geometry.ColorParser;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.log.LogType;
+import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
+import lcsb.mapviewer.model.user.ObjectPrivilege;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.dao.ProjectDao;
+import lcsb.mapviewer.persist.dao.user.PrivilegeDao;
+import lcsb.mapviewer.persist.dao.user.UserDao;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.UserDTO;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.ILdapService;
+import lcsb.mapviewer.services.interfaces.ILogService;
+import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
+import lcsb.mapviewer.services.interfaces.IUserService;
+
+/**
+ * Implementation of the service that manages users.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Transactional(value = "txManager")
+public class UserService implements IUserService {
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(UserService.class);
+
+  /**
+   * Data access object for users.
+   */
+  @Autowired
+  private UserDao userDao;
+
+  /**
+   * Data access object for privileges.
+   */
+  @Autowired
+  private PrivilegeDao privilegeDao;
+
+  @Autowired
+  private SessionRegistry sessionRegistry;
+
+  /**
+   * Service that provides password encoding.
+   */
+  @Autowired
+  private PasswordEncoder passwordEncoder;
+
+  /**
+   * Service used for logging.
+   */
+  @Autowired
+  private ILogService logService;
+
+  @Autowired
+  private ILdapService ldapService;
+
+  @Autowired
+  private ProjectDao projectDao;
+
+  /**
+   * Service used for accessing configuration parameters.
+   */
+  @Autowired
+  private IConfigurationService configurationService;
+
+  @Override
+  public String login(String login, String password) {
+    Random random = new SecureRandom();
+    String id = new BigInteger(130, random).toString(32);
+    return this.login(login, password, id);
+  }
+
+  @Override
+  public boolean userHasPrivilege(User user, PrivilegeType type) {
+    return getUserPrivilegeLevel(user, type) > 0;
+  }
+
+  @Override
+  public boolean userHasPrivilege(User user, PrivilegeType type, Object object) {
+    return getUserPrivilegeLevel(user, type, object) > 0;
+  }
+
+  @Override
+  public void setUserPrivilege(User user, BasicPrivilege privilege) {
+    updateUserPrivilegesWithoutDbModification(user, privilege);
+    updateUser(user);
+    userDao.flush();
+  }
+
+  private void updateUserPrivilegesWithoutDbModification(User user, BasicPrivilege privilege) {
+    BasicPrivilege oldPrivilege = null;
+    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
+      if (privilegeIter.equalsPrivilege(privilege)) {
+        oldPrivilege = privilegeIter;
+      }
+    }
+    if (oldPrivilege != null) {
+      privilege.setUser(null);
+      oldPrivilege.setLevel(privilege.getLevel());
+    } else {
+      privilege.setUser(user);
+      user.getPrivileges().add(privilege);
+    }
+  }
+
+  @Override
+  public void addUser(User user) {
+    userDao.add(user);
+    LogParams params = new LogParams().description("User " + user.getLogin() + " created.").type(LogType.USER_CREATED)
+        .object(user);
+    logService.log(params);
+  }
+
+  @Override
+  public void updateUser(User user) {
+    userDao.update(user);
+  }
+
+  @Override
+  public void deleteUser(User user) {
+    userDao.delete(user);
+    LogParams params = new LogParams().description("User " + user.getLogin() + " removed.").type(LogType.USER_CREATED)
+        .object(user);
+    logService.log(params);
+  }
+
+  @Override
+  public User getUserById(int id) {
+    User result = userDao.getById(id);
+    if (result != null) {
+      userDao.refresh(result);
+    }
+    return result;
+  }
+
+  @Override
+  public User getUserByLogin(String login) {
+    User result = userDao.getUserByLogin(login);
+    if (result != null) {
+      userDao.refresh(result);
+    }
+    return result;
+  }
+
+  @Override
+  public void dropPrivilegesForObjectType(PrivilegeType type, int id) {
+    IntegerComparator integerComparator = new IntegerComparator();
+    // this will be slow when number of user will increase (we fetch all
+    // users and drop privileges one by one)
+    List<User> users = userDao.getAll();
+    for (User user : users) {
+      List<BasicPrivilege> toRemove = new ArrayList<>();
+      for (BasicPrivilege privilege : user.getPrivileges()) {
+        if (privilege.getType().equals(type) && privilege instanceof ObjectPrivilege
+            && integerComparator.compare(((ObjectPrivilege) privilege).getIdObject(), id) == 0) {
+          toRemove.add(privilege);
+        }
+      }
+      if (toRemove.size() > 0) {
+        user.getPrivileges().removeAll(toRemove);
+        userDao.update(user);
+      }
+    }
+  }
+
+  @Override
+  public int getUserPrivilegeLevel(User user, PrivilegeType type) {
+    if (type.getPrivilegeClassType() != BasicPrivilege.class) {
+      throw new InvalidArgumentException("This privilege requires additional information");
+    }
+    for (BasicPrivilege privilege : user.getPrivileges()) {
+      if (privilege.getType().equals(type)) {
+        return privilege.getLevel();
+      }
+    }
+    return 0;
+  }
+
+  @Override
+  public int getUserPrivilegeLevel(User user, PrivilegeType type, Object object) {
+    Integer id = null;
+    if (object != null) {
+      try {
+        id = ObjectUtils.getIdOfObject(object);
+      } catch (Exception e) {
+        logger.error(e.getMessage(), e);
+        throw new InvalidArgumentException("Internal server error. Problem with accessing id of the parameter object");
+      }
+      if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
+        throw new InvalidArgumentException("This privilege accept only " + type.getPrivilegeObjectType()
+            + " objects parameter, but " + object.getClass() + " class found.");
+      }
+    }
+    return getUserPrivilegeLevel(user, type, id);
+  }
+
+  private int getUserPrivilegeLevel(User user, PrivilegeType type, Integer id) {
+    if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
+      throw new InvalidArgumentException("This privilege doesn't accept object parameter");
+    }
+    if (user == null) {
+      throw new InvalidArgumentException("User cannot be null");
+    }
+
+    // refresh user from db
+    if (user.getId() != null) {
+      user = userDao.getById(user.getId());
+    }
+    IntegerComparator integerComparator = new IntegerComparator();
+    for (BasicPrivilege privilege : user.getPrivileges()) {
+      if (privilege.getClass() == ObjectPrivilege.class) {
+        ObjectPrivilege oPrivilege = (ObjectPrivilege) privilege;
+        if (oPrivilege.getType().equals(type) && integerComparator.compare(oPrivilege.getIdObject(), id) == 0) {
+          return privilege.getLevel();
+        }
+      }
+    }
+    return -1;
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Integer value) {
+    BasicPrivilege privilege = new BasicPrivilege(value, type, user);
+
+    BasicPrivilege oldPrivilege = null;
+    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
+      if (privilegeIter.getType().equals(type)) {
+        oldPrivilege = privilegeIter;
+      }
+    }
+    if (oldPrivilege != null) {
+      user.getPrivileges().remove(oldPrivilege);
+      oldPrivilege.setUser(null);
+    }
+    user.getPrivileges().add(privilege);
+    updateUser(user);
+    userDao.flush();
+
+  }
+
+  /**
+   * @return the userDao
+   * @see #userDao
+   */
+  public UserDao getUserDao() {
+    return userDao;
+  }
+
+  /**
+   * @param userDao
+   *          the userDao to set
+   * @see #userDao
+   */
+  public void setUserDao(UserDao userDao) {
+    this.userDao = userDao;
+  }
+
+  /**
+   * @return the privilegeDao
+   * @see #privilegeDao
+   */
+  public PrivilegeDao getPrivilegeDao() {
+    return privilegeDao;
+  }
+
+  /**
+   * @param privilegeDao
+   *          the privilegeDao to set
+   * @see #privilegeDao
+   */
+  public void setPrivilegeDao(PrivilegeDao privilegeDao) {
+    this.privilegeDao = privilegeDao;
+  }
+
+  /**
+   * @return the passwordEncoder
+   * @see #passwordEncoder
+   */
+  public PasswordEncoder getPasswordEncoder() {
+    return passwordEncoder;
+  }
+
+  /**
+   * @param passwordEncoder
+   *          the passwordEncoder to set
+   * @see #passwordEncoder
+   */
+  public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+    this.passwordEncoder = passwordEncoder;
+  }
+
+  /**
+   * @param password
+   *          input password
+   * @return encoded password
+   */
+  @Override
+  public String encodePassword(String password) {
+    return passwordEncoder.encode(password);
+  }
+
+  @Override
+  public User getUserByNameSurname(String nameSurnameString) {
+    return userDao.getUserByNameSurname(nameSurnameString);
+  }
+
+  @Override
+  public ColorExtractor getColorExtractorForUser(User loggedUser) {
+    Color colorMin = null;
+    Color colorMax = null;
+    Color colorSimple = null;
+    if (loggedUser != null) {
+      User dbUser = getUserById(loggedUser.getId());
+      if (dbUser != null) {
+        colorMin = dbUser.getMinColor();
+        colorMax = dbUser.getMaxColor();
+        colorSimple = dbUser.getSimpleColor();
+      }
+    }
+    ColorParser parser = new ColorParser();
+
+    if (colorMin == null) {
+      colorMin = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MIN_COLOR_VAL));
+    }
+    if (colorMax == null) {
+      colorMax = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MAX_COLOR_VAL));
+    }
+    if (colorSimple == null) {
+      colorSimple = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.SIMPLE_COLOR_VAL));
+    }
+    return new ColorExtractor(colorMin, colorMax, colorSimple);
+  }
+
+  /**
+   * @return the configurationService
+   * @see #configurationService
+   */
+  public IConfigurationService getConfigurationService() {
+    return configurationService;
+  }
+
+  /**
+   * @param configurationService
+   *          the configurationService to set
+   * @see #configurationService
+   */
+  public void setConfigurationService(IConfigurationService configurationService) {
+    this.configurationService = configurationService;
+  }
+
+  @Override
+  public User getUserByToken(String token) throws SecurityException {
+    if (!isSessionExpired(token)) {
+      String login = ((org.springframework.security.core.userdetails.User) (sessionRegistry.getSessionInformation(token)
+          .getPrincipal())).getUsername();
+      return userDao.getUserByLogin(login);
+    } else {
+      throw new SecurityException("Invalid token");
+    }
+  }
+
+  private boolean isSessionExpired(String token) {
+    SessionInformation sessionData = sessionRegistry.getSessionInformation(token);
+    if (sessionData == null) {
+      logger.debug("No session data for token id: " + token);
+      return true;
+    }
+    return sessionData.isExpired();
+  }
+
+  @Override
+  public boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException {
+    return userHasPrivilege(getUserByToken(token), type, object);
+  }
+
+  @Override
+  public void logout(String tokenString) {
+    if (!isSessionExpired(tokenString)) {
+      sessionRegistry.removeSessionInformation(tokenString);
+    }
+  }
+
+  @Override
+  public User getUserById(String creatorId, String authenticationToken) throws SecurityException {
+    User user = getUserByToken(authenticationToken);
+    Integer id = Integer.parseInt(creatorId);
+    if (user.getId().equals(id)) {
+      return user;
+    } else if (userHasPrivilege(authenticationToken, PrivilegeType.USER_MANAGEMENT)) {
+      return getUserById(id);
+    } else {
+      throw new SecurityException("You cannot access data of other users");
+    }
+  }
+
+  @Override
+  public List<User> getUsers(String token) throws SecurityException {
+    if (userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      return userDao.getAll();
+    } else {
+      throw new SecurityException("You have no access to users data");
+    }
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Object value, String token) throws SecurityException {
+    if (!userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      throw new SecurityException("You cannot modify user privileges");
+    }
+    if (value instanceof Integer) {
+      setUserPrivilege(user, type, (Integer) value);
+    } else if (value instanceof Boolean) {
+      if ((Boolean) value) {
+        setUserPrivilege(user, type, 1);
+      } else {
+        setUserPrivilege(user, type, 0);
+      }
+    } else {
+      throw new InvalidArgumentException("Invalid privilege value: " + value);
+    }
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Object value, Integer objectId, String token)
+      throws SecurityException {
+    boolean canModify = userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
+    if (!canModify) {
+      if (type.getPrivilegeObjectType().isAssignableFrom(Project.class)) {
+        canModify = getUserPrivilegeLevel(getUserByToken(token), type, objectId) > 0;
+      }
+    }
+    if (!canModify) {
+      throw new SecurityException("You cannot modify user privileges");
+    }
+    Project projectIdWrapper = new Project();
+    if (objectId == null) {
+      projectIdWrapper = null;
+    } else {
+      projectIdWrapper.setId(objectId);
+    }
+    if (value instanceof Integer) {
+      setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, (Integer) value, type, user));
+    } else if (value instanceof Boolean) {
+      if ((Boolean) value) {
+        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 1, type, user));
+      } else {
+        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 0, type, user));
+      }
+    } else {
+      throw new InvalidArgumentException("Invalid privilege value: " + value);
+    }
+
+  }
+
+  @Override
+  public void updateUser(User modifiedUser, String token) throws SecurityException {
+    User user = getUserByToken(token);
+    if (user.getLogin().equals(modifiedUser.getLogin()) || userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      updateUser(modifiedUser);
+    } else {
+      throw new SecurityException("You cannot modify user");
+    }
+
+  }
+
+  @Override
+  public boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException {
+    return userHasPrivilege(getUserByToken(token), type);
+  }
+
+  @Override
+  public String login(String login, String password, String token) {
+    User user = userDao.getUserByLogin(login);
+    if (user == null) {
+      user = createUserFromLdap(login, password, user);
+    } else if (!user.isConnectedToLdap()) {
+      String cryptedPassword;
+      if (password != null) {
+        cryptedPassword = passwordEncoder.encode(password);
+      } else {
+        cryptedPassword = "";
+      }
+      user = userDao.getUserByLoginAndCryptedPassword(login, cryptedPassword);
+    } else {
+      if (!authenticateOverLdap(login, password)) {
+        user = null;
+      }
+    }
+
+    if (user == null && Configuration.ANONYMOUS_LOGIN.equals(login) && "".equals(password)) {
+      user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
+    }
+    if (user != null) {
+      sessionRegistry.registerNewSession(token, new org.springframework.security.core.userdetails.User(login,
+          passwordEncoder.encode(password), AuthorityUtils.commaSeparatedStringToAuthorityList("")));
+      return token;
+    } else {
+      return null;
+    }
+  }
+
+  private boolean authenticateOverLdap(String login, String password) {
+    if (!ldapService.isValidConfiguration()) {
+      return false;
+    }
+    try {
+      return ldapService.login(login, password);
+    } catch (LDAPException e) {
+      logger.warn("Problem with accessing LDAP directory", e);
+      return false;
+    }
+  }
+
+  private User createUserFromLdap(String login, String password, User user) {
+    if (!ldapService.isValidConfiguration()) {
+      return null;
+    }
+    try {
+      boolean authenticatedOverLdap = ldapService.login(login, password);
+      if (authenticatedOverLdap) {
+        UserDTO ldapUserData = ldapService.getUserByLogin(login);
+        user = new User();
+        user.setLogin(login);
+        user.setCryptedPassword(passwordEncoder.encode(password));
+        user.setName(ldapUserData.getFirstName());
+        user.setSurname(ldapUserData.getLastName());
+        user.setEmail(ldapUserData.getEmail());
+        user.setConnectedToLdap(true);
+        addUser(user);
+        for (Project project : projectDao.getAll()) {
+          createDefaultProjectPrivilegesForUser(project, user);
+        }
+      }
+      return user;
+    } catch (LDAPException e) {
+      logger.warn("Problem with accessing LDAP directory", e);
+      return null;
+    }
+  }
+
+  @Override
+  public ILdapService getLdapService() {
+    return ldapService;
+  }
+
+  @Override
+  public void setLdapService(ILdapService ldapService) {
+    this.ldapService = ldapService;
+  }
+
+  @Override
+  public void createDefaultProjectPrivilegesForUser(Project project, User user) {
+    for (PrivilegeType type : PrivilegeType.values()) {
+      if (Project.class.equals(type.getPrivilegeObjectType())) {
+        int level = getUserPrivilegeLevel(user, type, (Integer) null);
+        if (level < 0) {
+          if (configurationService.getValue(type).getValue().equalsIgnoreCase("true")) {
+            level = 1;
+          } else {
+            level = 0;
+          }
+        }
+        ObjectPrivilege privilege = new ObjectPrivilege(project, level, type, user);
+        setUserPrivilege(user, privilege);
+      }
+    }
+  }
+
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java
index d449879390..8a56e5c37b 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java
@@ -56,6 +56,6 @@ public interface ILdapService {
    * @return true if LDAP configuration
    *         ({@link ConfigurationElementTypeGroup#LDAP_CONFIGURATION}) is valid
    */
-  boolean isValidConfiguratio();
+  boolean isValidConfiguration();
 
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
index d11ffec752..f1e752ff2b 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
@@ -3,6 +3,7 @@ package lcsb.mapviewer.services.interfaces;
 import java.util.List;
 
 import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.user.BasicPrivilege;
 import lcsb.mapviewer.model.user.PrivilegeType;
 import lcsb.mapviewer.model.user.User;
@@ -198,4 +199,10 @@ public interface IUserService {
 
   String login(String login, String password, String id);
 
+  ILdapService getLdapService();
+
+  void setLdapService(ILdapService ldapService);
+
+  void createDefaultProjectPrivilegesForUser(Project project, User user);
+
 }
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java b/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
index f08941eeb3..3a5bb0badd 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
@@ -6,13 +6,14 @@ import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
 @SuiteClasses({ CommentServiceTest.class, //
-		ConfigurationServiceTest.class, //
-		ExternalServicesServiceTest.class, //
-		LayoutServiceTest.class, //
-		Md5PasswordEncoderTest.class, //
-		ProjectServiceTest.class, //
-		SearchServiceTest.class, //
-		UserServiceTest.class,//
+    ConfigurationServiceTest.class, //
+    ExternalServicesServiceTest.class, //
+    LayoutServiceTest.class, //
+    LdapServiceTest.class, //
+    Md5PasswordEncoderTest.class, //
+    ProjectServiceTest.class, //
+    SearchServiceTest.class, //
+    UserServiceTest.class,//
 })
 public class AllImplServiceTests {
 
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java
index f1bb417c2a..7f3cf3c58a 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java
@@ -69,9 +69,9 @@ public class LdapServiceTest extends ServiceTestFunctions {
   @Test
   public void testIsValidConfiguration() throws Exception {
     try {
-      assertTrue(ldapService.isValidConfiguratio());
+      assertTrue(ldapService.isValidConfiguration());
       configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "");
-      assertFalse(ldapService.isValidConfiguratio());
+      assertFalse(ldapService.isValidConfiguration());
     } catch (Exception e) {
       e.printStackTrace();
       throw e;
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
index 57ae4d75f0..fb7ea42cdd 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
@@ -11,14 +11,24 @@ import org.apache.log4j.Logger;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.springframework.test.annotation.Rollback;
 
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
 import lcsb.mapviewer.model.user.ObjectPrivilege;
 import lcsb.mapviewer.model.user.PrivilegeType;
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.services.ServiceTestFunctions;
+import lcsb.mapviewer.services.interfaces.ILdapService;
 
 @Rollback(true)
 public class UserServiceTest extends ServiceTestFunctions {
@@ -46,6 +56,58 @@ public class UserServiceTest extends ServiceTestFunctions {
     }
   }
 
+  @Test
+  public void testLoginFromLdap() throws Exception {
+    ILdapService originalLdapService = userService.getLdapService();
+    try {
+      String login = "john.doe.test";
+      String passwd = "test_passwd";
+
+      assertNull(userService.getUserByLogin(login));
+
+      LdapService ldapService = createMockLdapService("testFiles/ldap/john-doe-test-example.ldif", login, passwd);
+
+      userService.setLdapService(ldapService);
+      assertNull(userService.login(login, "incorrect password"));
+      assertNotNull("User from LDAP wasn't authenticated", userService.login(login, passwd));
+
+      User user = userService.getUserByLogin(login);
+      assertNotNull("After authentication from LDAP user is not present in the system", user);
+      assertTrue(user.isConnectedToLdap());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      userService.setLdapService(originalLdapService);
+    }
+  }
+
+  private LdapService createMockLdapService(String filename, String login, String passwd) throws LDAPException {
+    configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "dc=uni,dc=lu");
+    configurationService.setConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS, "person");
+
+    LdapService ldapService = Mockito.spy(LdapService.class);
+    ldapService.setConfigurationService(configurationService);
+    Mockito.when(ldapService.getConnection()).thenAnswer(new Answer<LDAPConnection>() {
+
+      @Override
+      public LDAPConnection answer(InvocationOnMock invocation) throws Throwable {
+        // Create the configuration to use for the server.
+        InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=uni,dc=lu");
+        config.addAdditionalBindCredentials("uid=" + login + ",cn=users,cn=accounts,dc=uni,dc=lu", passwd);
+        config.setSchema(null);
+
+        // Create the directory server instance, populate it with data from the
+        // "test-data.ldif" file, and start listening for client connections.
+        InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
+        ds.importFromLDIF(true, filename);
+        ds.startListening();
+        return ds.getConnection();
+      }
+    });
+    return ldapService;
+  }
+
   @Test
   public void testLoginWithNull() {
     try {
diff --git a/service/testFiles/ldap/john-doe-test-example.ldif b/service/testFiles/ldap/john-doe-test-example.ldif
new file mode 100644
index 0000000000..4d89df27e3
--- /dev/null
+++ b/service/testFiles/ldap/john-doe-test-example.ldif
@@ -0,0 +1,92 @@
+version: 1
+
+dn: dc=uni,dc=lu
+objectClass: top
+objectClass: domain
+dc: uni
+
+dn: cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: accounts
+
+dn: cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: users
+
+dn: uid=john.doe.test,cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: mepOriginEntry
+objectClass: ipaSshGroupOfPubKeys
+objectClass: posixaccount
+objectClass: inetuser
+objectClass: krbprincipalaux
+objectClass: krbticketpolicyaux
+objectClass: organizationalperson
+objectClass: inetorgperson
+objectClass: ipasshuser
+objectClass: top
+objectClass: person
+objectClass: ipaobject
+cn: John Doe
+gidNumber: 369550501
+homeDirectory: /home/john.doe.test
+ipaUniqueID: adf723e6-20e4-11e5-8907-001a4ae51219
+sn: Doe
+uid: john.doe.test
+uidNumber: 369550501
+displayName: John Doe
+gecos: John Doe
+givenName: John
+initials: JD
+krbLastPwdChange: 20180608111630Z
+krbPasswordExpiration: 20190223111630Z
+krbPrincipalName: john.doe.test@UNI.LU
+loginShell: /bin/bash
+mail: john.doe.test@uni.lu
+memberOf: cn=lcsb,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=d7549fa2-03a2-11e5-95f9-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=eff7677e-03a2-11e5-add5-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=f10ec0f6-7ef6-11e5-957b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=2cf9b59e-7ef7-11e5-89c0-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=eeb5f68e-9775-11e5-81fb-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=176f7fb4-9776-11e5-a097-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=7dda82ae-99e1-11e5-834b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=a44d842c-99e1-11e5-9c2f-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=webdav-public-minerva,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=1d1f58b8-a247-11e5-ac5d-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=41f879a8-a247-11e5-9d34-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=33e9e6a2-c8d1-11e5-b578-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=572fea30-c8d1-11e5-b770-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=lcsb-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=owncloud,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=webdav-public-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=grafana-biocore-gitlab-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: cn=grafana-biocore-icinga-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: ipaUniqueID=634b5286-3781-11e6-93c5-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=7fe6a210-3781-11e6-b515-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=ncer-pd-ada,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=r3lab-docker,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=390a3ce0-854b-11e6-85c3-001a4ae5127c,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=6d558608-854b-11e6-9aa7-001a4ae5127c,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+telephoneNumber: +3524666445526
+
diff --git a/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java b/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java
new file mode 100644
index 0000000000..6346901dd2
--- /dev/null
+++ b/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java
@@ -0,0 +1,53 @@
+package lcsb.mapviewer.security;
+
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.transaction.annotation.Transactional;
+
+import lcsb.mapviewer.services.interfaces.IUserService;
+
+@Transactional(readOnly = false)
+public class CustomAuthenticationProvider implements AuthenticationProvider {
+  Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);
+
+  private IUserService userService;
+
+  @Override
+  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+    // login
+    String name = authentication.getName();
+
+    // password
+    String password = null;
+    if (authentication.getCredentials() != null) {
+      password = authentication.getCredentials().toString();
+    }
+
+    // Your custom authentication logic here
+    if (userService.login(name, password) != null) {
+      Authentication auth = new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
+      return auth;
+    }
+    throw new BadCredentialsException("Invalid credentials");
+  }
+
+  @Override
+  public boolean supports(Class<?> authentication) {
+    return authentication.equals(UsernamePasswordAuthenticationToken.class);
+  }
+
+  public IUserService getUserService() {
+    return userService;
+  }
+
+  public void setUserService(IUserService userService) {
+    this.userService = userService;
+  }
+
+}
diff --git a/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java b/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java
deleted file mode 100644
index 109a881dfa..0000000000
--- a/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package lcsb.mapviewer.security;
-
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.services.interfaces.IUserService;
-
-/**
- * Spring implementation of class accessing user details.
- * 
- * @author Piotr Gawron
- * 
- */
-@Transactional(readOnly = false)
-public class MvSecurityServiceImpl implements UserDetailsService {
-  /**
-   * Default class logger.
-   */
-  @SuppressWarnings("unused")
-  private static Logger logger = Logger.getLogger(MvSecurityServiceImpl.class);
-
-  /**
-   * Service used for accessing user data.
-   */
-  @Autowired
-  private IUserService userService;
-
-  @Autowired
-  private PasswordEncoder passwordEncoder;
-
-  @Override
-  public UserDetails loadUserByUsername(String login) {
-    if (login == null || login.trim().isEmpty() || login.equals(Configuration.ANONYMOUS_LOGIN)) {
-      return new User(login, passwordEncoder.encode(""), AuthorityUtils.commaSeparatedStringToAuthorityList(""));
-    }
-
-    lcsb.mapviewer.model.user.User user = userService.getUserByLogin(login);
-    if (user == null) {
-      throw new UsernameNotFoundException("Invalid username or password.");
-    }
-    StringBuilder credentials = new StringBuilder();
-
-    return new User(user.getLogin(), user.getCryptedPassword(),
-        AuthorityUtils.commaSeparatedStringToAuthorityList(credentials.toString()));
-  }
-
-  /**
-   * @return the userService
-   * @see #userService
-   */
-  public IUserService getUserService() {
-    return userService;
-  }
-
-  /**
-   * @param userService
-   *          the userService to set
-   * @see #userService
-   */
-  public void setUserService(IUserService userService) {
-    this.userService = userService;
-  }
-
-}
diff --git a/web/src/main/webapp/WEB-INF/security-context.xml b/web/src/main/webapp/WEB-INF/security-context.xml
index 41c1b8c834..783c154e31 100644
--- a/web/src/main/webapp/WEB-INF/security-context.xml
+++ b/web/src/main/webapp/WEB-INF/security-context.xml
@@ -72,10 +72,6 @@
 		<constructor-arg value="/login.xhtml"></constructor-arg>
 	</bean>
 	
-	<bean id="userDetailsService" class="lcsb.mapviewer.security.MvSecurityServiceImpl">
-		<property name="userService" ref="UserService" />
-	</bean>
-
 	<bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
   	<constructor-arg>
     	<list>
@@ -98,9 +94,8 @@
 	
 	<bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
 	
-	<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
-		<property name="userDetailsService" ref="userDetailsService" />
-		<property name="passwordEncoder" ref="PasswordEncoder" />
+	<bean id="authenticationProvider" class="lcsb.mapviewer.security.CustomAuthenticationProvider">
+		<property name="userService" ref="UserService" />
 	</bean>
 		
 	<security:authentication-manager alias="authenticationManager">
-- 
GitLab