You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2023/05/12 07:18:41 UTC
[openmeetings] 02/02: [OPENMEETINGS-2773] login/email should be case insensitive
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 <so...@gmail.com>
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");
+ }
}