This is an automated email from the ASF dual-hosted git repository. solomax pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openmeetings.git
commit 4de8f7c0a3622203eff02f5c707280749ebfe87e Author: Maxim Solodovnik <[email protected]> AuthorDate: Fri May 12 14:18:27 2023 +0700 [OPENMEETINGS-2773] login/email should be case insensitive --- .../apache/openmeetings/db/dao/user/UserDao.java | 27 ++++---- .../apache/openmeetings/db/entity/user/User.java | 74 ++++++++++++++++++---- .../apache/openmeetings/userdata/TestLogin.java | 27 ++++++++ 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java index 6a0eb6497..41ecfd549 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java @@ -22,6 +22,7 @@ import static java.util.UUID.randomUUID; import static org.apache.openmeetings.db.util.DaoHelper.fillLazy; import static org.apache.openmeetings.db.util.DaoHelper.getRoot; import static org.apache.openmeetings.db.util.DaoHelper.getStringParam; +import static org.apache.openmeetings.db.util.DaoHelper.only; import static org.apache.openmeetings.db.util.DaoHelper.setLimits; import static org.apache.openmeetings.db.util.DaoHelper.single; import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone; @@ -45,7 +46,6 @@ import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.JoinType; @@ -434,7 +434,8 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { return !Strings.isEmpty(login) && login.length() >= getMinLoginLength(); } - public User getByLogin(String login, Type type, Long domainId) { + public User getByLogin(String _login, Type type, Long domainId) { + String login = _login == null ? null : _login.trim().toLowerCase(Locale.ROOT); return single(fillLazy(em , oem -> oem.createNamedQuery("getUserByLogin", User.class) .setParameter("login", login) @@ -447,7 +448,8 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { return getByEmail(email, User.Type.USER, null); } - public User getByEmail(String email, User.Type type, Long domainId) { + public User getByEmail(String _email, User.Type type, Long domainId) { + String email = _email == null ? null : _email.trim().toLowerCase(Locale.ROOT); return single(fillLazy(em , oem -> oem.createNamedQuery("getUserByEmail", User.class) .setParameter(PARAM_EMAIL, email) @@ -474,9 +476,9 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { public Long selectMaxFromUsersWithSearch(String search) { try { // get all users - TypedQuery<Long> query = em.createNamedQuery("selectMaxFromUsersWithSearch", Long.class); - query.setParameter("search", StringUtils.lowerCase(search, Locale.ROOT)); - List<Long> ll = query.getResultList(); + List<Long> ll = em.createNamedQuery("selectMaxFromUsersWithSearch", Long.class) + .setParameter("search", StringUtils.lowerCase(search, Locale.ROOT)) + .getResultList(); log.info("selectMaxFromUsers {}", ll.get(0)); return ll.get(0); } catch (Exception ex2) { @@ -493,12 +495,8 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { * @return <code>true</code> if entered password is correct */ public boolean verifyPassword(Long userId, String password) { - List<String> l = em.createNamedQuery("getPassword", String.class) - .setParameter(PARAM_USER_ID, userId).getResultList(); - if (l == null || l.size() != 1) { - return false; - } - String hash = l.get(0); + String hash = only(em.createNamedQuery("getPassword", String.class) + .setParameter(PARAM_USER_ID, userId).getResultList()); ICrypt crypt = CryptProvider.get(); if (crypt.verify(password, hash)) { return true; @@ -605,7 +603,8 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { * @return User object in case of successful login * @throws OmException in case of any issue */ - public User login(String userOrEmail, String userpass) throws OmException { + public User login(String _userOrEmail, String userpass) throws OmException { + String userOrEmail = _userOrEmail == null ? null : _userOrEmail.trim().toLowerCase(Locale.ROOT); List<User> users = em.createNamedQuery("getUserByLoginOrEmail", User.class) .setParameter("userOrEmail", userOrEmail) .setParameter("type", Type.USER) @@ -614,7 +613,7 @@ public class UserDao implements IGroupAdminDataProviderDao<User> { log.debug("login:: {} users were found", users.size()); if (users.isEmpty()) { - log.debug("No users was found: {}", userOrEmail); + log.debug("No users were found: {}", userOrEmail); return null; } User u = users.get(0); diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java index ed3365a82..7bf3340fc 100644 --- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java +++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java @@ -100,26 +100,74 @@ import org.apache.wicket.util.string.Strings; }) @NamedQuery(name = "getUserById", query = "SELECT u FROM User u WHERE u.id = :id") @NamedQuery(name = "getUsersByIds", query = "select c from User c where c.id IN :ids") -@NamedQuery(name = "getUserByLogin", query = "SELECT u FROM User u WHERE u.deleted = false AND u.type = :type AND u.login = :login AND ((:domainId = 0 AND u.domainId IS NULL) OR (:domainId > 0 AND u.domainId = :domainId))") -@NamedQuery(name = "getUserByEmail", query = "SELECT u FROM User u WHERE u.deleted = false AND u.type = :type AND u.address.email = :email AND ((:domainId = 0 AND u.domainId IS NULL) OR (:domainId > 0 AND u.domainId = :domainId))") -@NamedQuery(name = "getUserByHash", query = "SELECT u FROM User u WHERE u.deleted = false AND u.type = :type AND u.resethash = :resethash") +@NamedQuery(name = "getUserByLogin", query = """ + SELECT u + FROM User u + WHERE + u.deleted = false + AND u.type = :type + AND lower(trim(both from u.login)) = :login + AND ((:domainId = 0 AND u.domainId IS NULL) OR (:domainId > 0 AND u.domainId = :domainId))""") +@NamedQuery(name = "getUserByEmail", query = """ + SELECT u + FROM User u + WHERE + u.deleted = false + AND u.type = :type + AND lower(trim(both from u.address.email)) = :email + AND ((:domainId = 0 AND u.domainId IS NULL) OR (:domainId > 0 AND u.domainId = :domainId))""") +@NamedQuery(name = "getUserByHash", query = """ + SELECT u + FROM User u + WHERE + u.deleted = false + AND u.type = :type + AND u.resethash = :resethash""") @NamedQuery(name = "getUserByExpiredHash", query = "SELECT u FROM User u WHERE u.resetDate < :date") -@NamedQuery(name = "getContactByEmailAndUser", query = "SELECT u FROM User u WHERE u.deleted = false AND u.address.email = :email AND u.type = :type AND u.ownerId = :ownerId") -@NamedQuery(name = "selectMaxFromUsersWithSearch", query = "SELECT count(c.id) FROM User c " - + "WHERE c.deleted = false AND (" - + "lower(c.login) LIKE :search " - + "OR lower(c.firstname) LIKE :search " - + "OR lower(c.lastname) LIKE :search )") +@NamedQuery(name = "getContactByEmailAndUser", query = """ + SELECT u + FROM User u + WHERE + u.deleted = false + AND u.address.email = :email + AND u.type = :type + AND u.ownerId = :ownerId""") +@NamedQuery(name = "selectMaxFromUsersWithSearch", query = """ + SELECT count(c.id) + FROM User c + WHERE + c.deleted = false + AND ( + lower(c.login) LIKE :search + OR lower(c.firstname) LIKE :search + OR lower(c.lastname) LIKE :search + )""") @NamedQuery(name = "getAllUsers", query = "SELECT u FROM User u ORDER BY u.id") @NamedQuery(name = "getPassword", query = "SELECT u.password FROM User u WHERE u.deleted = false AND u.id = :userId ") @NamedQuery(name = "updatePassword", query = "UPDATE User u SET u.password = :password WHERE u.id = :userId") @NamedQuery(name = "getNondeletedUsers", query = "SELECT u FROM User u WHERE u.deleted = false") @NamedQuery(name = "countNondeletedUsers", query = "SELECT COUNT(u) FROM User u WHERE u.deleted = false") @NamedQuery(name = "getUsersByGroupId", query = "SELECT u FROM User u WHERE u.deleted = false AND u.groupUsers.group.id = :groupId") -@NamedQuery(name = "getExternalUser", query = "SELECT gu.user FROM GroupUser gu WHERE " - + "gu.group.deleted = false AND gu.group.external = true AND gu.group.name = :externalType " - + "AND gu.user.deleted = false AND gu.user.type = :type AND gu.user.externalId = :externalId") -@NamedQuery(name = "getUserByLoginOrEmail", query = "SELECT u from User u WHERE u.deleted = false AND u.type = :type AND (u.login = :userOrEmail OR u.address.email = :userOrEmail)") +@NamedQuery(name = "getExternalUser", query = """ + SELECT gu.user + FROM GroupUser gu + WHERE + gu.group.deleted = false + AND gu.group.external = true + AND gu.group.name = :externalType + AND gu.user.deleted = false + AND gu.user.type = :type + AND gu.user.externalId = :externalId""") +@NamedQuery(name = "getUserByLoginOrEmail", query = """ + SELECT u + FROM User u + WHERE + u.deleted = false + AND u.type = :type + AND ( + lower(trim(both from u.login)) = :userOrEmail + OR lower(trim(both from u.address.email)) = :userOrEmail + )""") @Table(name = "om_user", indexes = { @Index(name = "login_idx", columnList = "login") , @Index(name = "lastname_idx", columnList = "lastname") diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/userdata/TestLogin.java b/openmeetings-web/src/test/java/org/apache/openmeetings/userdata/TestLogin.java index 43133d1ad..5b905b546 100644 --- a/openmeetings-web/src/test/java/org/apache/openmeetings/userdata/TestLogin.java +++ b/openmeetings-web/src/test/java/org/apache/openmeetings/userdata/TestLogin.java @@ -18,8 +18,11 @@ */ package org.apache.openmeetings.userdata; +import static java.util.UUID.randomUUID; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.Locale; + import org.apache.openmeetings.AbstractOmServerTest; import org.apache.openmeetings.db.entity.user.User; import org.apache.openmeetings.util.OmException; @@ -32,4 +35,28 @@ class TestLogin extends AbstractOmServerTest { assertNotNull(us, "User is unable to login"); } + private User prepareUser() throws Exception { + User u = getUser(randomUUID().toString()); + u.setLogin(" AB" + u.getLogin() + " "); + u.getAddress().setEmail(" CD_" + u.getAddress().getEmail() + " "); + u.updatePassword(userpass); + u.addGroup(groupDao.get(group)); + return userDao.update(u, null); + } + + @Test + void testMixedCaseLogin() throws Exception { + final String login = prepareUser().getLogin(); + + User us = userDao.login(login.toUpperCase(Locale.ROOT), userpass); + assertNotNull(us, "Uppercase User is unable to login"); + } + + @Test + void testMixedCaseEmail() throws Exception { + final String email = prepareUser().getAddress().getEmail(); + + User us = userDao.login(email.toUpperCase(Locale.ROOT), userpass); + assertNotNull(us, "Uppercase Email is unable to login"); + } }
