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");
+       }
 }

Reply via email to