spring-projects / spring-data-ldap

Repository abstraction for Spring LDAP
http://projects.spring.io/spring-data-ldap
Apache License 2.0
67 stars 56 forks source link

Add support for parametrized `@Query` #453

Open chess-levin opened 11 months ago

chess-levin commented 11 months ago

I'm trying to build a filter using @Query in my LdapRepository class that uses a parameter and the parameter most likely contains '*'.

The queries are successful when using a parameter cn without wildcard '*'. I'm expecting one entry and I' getting one result. Log output:

finalFilter=(&(&(objectclass=top)(objectclass=group))(cn=us_dbl_ci_user_grp))

When trying to add '*' to query-parameter cn the result is always empty. Log output:

finalFilter=(&(&(objectclass=top)(objectclass=group))(cn=us_ci_\2a))

@Repository
public interface GroupRepository extends LdapRepository<LdapGroup> {

    @Query( base = "OU=jenkins,OU=gruppen,OU=MYORG", searchScope = SearchScope.SUBTREE, value = "(cn={0})")
    List<LdapGroup> suchDistinguishedNameJenkins(String cn);

    @Query( base = "OU=itsqs,OU=gruppen,OU=MYORG", searchScope = SearchScope.SUBTREE, value = "(cn={0})")
    List<LdapGroup> suchDistinguishedNameItsqs(String cn);
}
@Entry(base="OU=gruppen,OU=MYORG", objectClasses = {"top", "group"})
final public class LdapGroup {

    @JsonIgnore
    @Id
    private Name id;

    @Attribute(name = "distinguishedName")
    private String distinguishedName;

    @Attribute(name = "cn")
    private String cn;

    @Attribute(name = "name")
    private String name;

    @Attribute(name="member")
    private List<String> members;

    public LdapGroup() {}
}

Is this behavior intended, is it a bug or am I doing something wrong?

Just in case I'm trying to explain what I try to achieve with my code:

My main goal is to narrow down the ldap base for this to different queries.

I set the ldap base in my entry class to the upper 'folder' in the ldap hierarchy.

@Entry(base="OU=gruppen,OU=MYORG", objectClasses = {"top", "group"})

Because this path contains >1000 subfolders and because I know exactly which subfolder I want to query, I narrow it down when I define the @Query (btw: it would be great to use params like {1} for base as well)

@Query( base = "OU=jenkins,OU=gruppen,OU=MYORG", searchScope = SearchScope.SUBTREE, value = "(cn={0})")

@Query( base = "OU=itsqs,OU=gruppen,OU=MYORG", searchScope = SearchScope.SUBTREE, value = "(cn={0})")

If I'm on the wrong path, please give me some advise, how to do this query the correct way. THX

mp911de commented 11 months ago

Parameters from the method call aren't incorporated in @Query. Typically, we support named (:myParam) or indexed (?0, ?1, …) parameters and we should extend annotated query methods to pick up parameters.

Also, adding SpEL support would make sense as well.

chess-levin commented 11 months ago

I wrote my own repository class to be able to individually change the base on each query. Is there a way to write the objectClass check in a shorter way? e.g. where("objectClass").in("top,group")

@Repository
public class MyGroupRepo {

    @Autowired
    private LdapTemplate ldapTemplate;

    public List<LdapGroup> findByCnInGroup(String cnFilter, Name groupName) {
        LdapQuery query = query().searchScope(SearchScope.SUBTREE)
                .base(groupName)
                .where("objectclass").is("top")
                .and("objectclass").is("group")
                .and("cn").like(cnFilter);

        return ldapTemplate.find(query, LdapGroup.class);
    }
}

@mp911de As I wrote in my 1st post. It is possible pass a numbered parameter into value argument with {0}, but there are no wildcards allowed.

mp911de commented 11 months ago

It is possible pass a numbered parameter into value argument with {0}, but there are no wildcards allowed.

It's not supported reliably. Parameter evaluation happens in Spring LDAP's org.springframework.ldap.query.LdapQueryBuilder and only for the filter part. It's not supported for base.

Parameters are encoded using LdapEncoder.filterEncode.

System.out.println(LdapEncoder.filterEncode("*"));

produces:

\2a
mp911de commented 1 week ago

We want to extend parametrization capabilities by allowing:

The previous form of {some-number} remains active while we would consider it outdated.