Skip to content

Commit

Permalink
[SYNCOPE-1779] supporting underscore in search queries (#529)
Browse files Browse the repository at this point in the history
* [SYNCOPE-1779] supporting underscore in search queries, with specific changes for Oracle DB
  • Loading branch information
andrea-patricelli committed Oct 11, 2023
1 parent d55ef48 commit 0f250a2
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ protected static AttrCond createAttrCond(final String schema) {

protected static String getValue(final SearchCondition<SearchBean> sc) {
String value = SearchUtils.toSqlWildcardString(
URLDecoder.decode(sc.getStatement().getValue().toString(), StandardCharsets.UTF_8), false).
replaceAll("\\\\_", "_");
URLDecoder.decode(sc.getStatement().getValue().toString(), StandardCharsets.UTF_8), false);

// see SYNCOPE-1321
if (TIMEZONE.matcher(value).matches()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,17 @@ public void issueSYNCOPE1223() {

assertEquals(SearchCond.getLeaf(cond), SearchCondConverter.convert(VISITOR, fiql));
}

@Test
public void issueSYNCOPE1779() {
String fiql = new UserFiqlSearchConditionBuilder().is("username").equalToIgnoreCase("ros_*").query();
assertEquals("username=~ros_*", fiql);

AttrCond attrCond = new AnyCond(AttrCond.Type.ILIKE);
attrCond.setSchema("username");
attrCond.setExpression("ros\\_%");
SearchCond leaf = SearchCond.getLeaf(attrCond);

assertEquals(leaf, SearchCondConverter.convert(VISITOR, fiql));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ protected void fillAttrQuery(
query.append(lower ? "LOWER(" : "").
append('?').append(setParameter(parameters, value)).
append(lower ? ")" : "");
// workaround for Oracle DB adding explicit escaping string, to search
// for literal _ (underscore) (SYNCOPE-1779)
if (cond.getType() == AttrCond.Type.ILIKE || cond.getType() == AttrCond.Type.LIKE) {
query.append(" ESCAPE '\\' ");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.openjpa.jdbc.meta.MappingRepository;
import org.apache.openjpa.jdbc.sql.OracleDictionary;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.syncope.core.persistence.api.dao.DAO;
import org.apache.syncope.core.persistence.api.entity.Entity;
import org.apache.syncope.core.spring.ApplicationContextProvider;
Expand All @@ -33,6 +40,8 @@ public abstract class AbstractDAO<E extends Entity> implements DAO<E> {

protected static final Logger LOG = LoggerFactory.getLogger(DAO.class);

private static final Map<String, Boolean> IS_ORACLE = new ConcurrentHashMap<>();

protected EntityManagerFactory entityManagerFactory() {
return EntityManagerFactoryUtils.findEntityManagerFactory(
ApplicationContextProvider.getBeanFactory(), AuthContextUtils.getDomain());
Expand All @@ -53,4 +62,17 @@ public void refresh(final E entity) {
public void detach(final E entity) {
entityManager().detach(entity);
}

protected boolean isOracle() {
Boolean isOracle = IS_ORACLE.get(AuthContextUtils.getDomain());
if (isOracle == null) {
OpenJPAEntityManagerFactory emf = OpenJPAPersistence.cast(entityManagerFactory());
OpenJPAEntityManagerFactorySPI emfspi = (OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.cast(emf);
isOracle = ((MappingRepository) emfspi.getConfiguration()
.getMetaDataRepositoryInstance()).getDBDictionary() instanceof OracleDictionary;
IS_ORACLE.put(AuthContextUtils.getDomain(), isOracle);

}
return isOracle;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,11 @@ protected void fillAttrQuery(
} else {
query.append('?').append(setParameter(parameters, cond.getExpression()));
}
// workaround for Oracle DB adding explicit escaping string, to search
// for literal _ (underscore) (SYNCOPE-1779)
if (isOracle()) {
query.append(" ESCAPE '\\' ");
}
} else {
if (!(cond instanceof AnyCond)) {
query.append("' AND");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -875,4 +875,43 @@ public void issueSYNCOPE1727() {
assertEquals(1, users.getResult().size());
assertEquals(user.getKey(), users.getResult().get(0).getKey());
}

@Test
public void issueSYNCOPE1779() {
// 1. create user with underscore
UserTO userWithUnderscore = createUser(UserITCase.getSample("syncope1779_test@syncope.apache.org")).getEntity();
// 2 create second user without underscore
createUser(UserITCase.getSample("syncope1779test@syncope.apache.org")).getEntity();

// 3. search for user
if (IS_ELASTICSEARCH_ENABLED) {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
// ignore
}
}

// Search by username
PagedResult<UserTO> users = USER_SERVICE.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM)
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("username").equalTo("syncope1779_*")
.and().is("firstname").equalTo("syncope1779_*")
.and().is("userId").equalTo("syncope1779_*").query())
.build());
assertEquals(1, users.getResult().size());
assertEquals(userWithUnderscore.getKey(), users.getResult().get(0).getKey());
// Search also by attribute
users = USER_SERVICE.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM)
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("syncope1779_*").query())
.build());
assertEquals(1, users.getResult().size());
assertEquals(userWithUnderscore.getKey(), users.getResult().get(0).getKey());
// search for both
users = USER_SERVICE.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM)
.fiql(SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("syncope1779*").query())
.build());
assertEquals(2, users.getResult().size());

users.getResult().forEach(u -> USER_SERVICE.delete(u.getKey()));
}
}

0 comments on commit 0f250a2

Please sign in to comment.