Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LdapService & LdapPerson Improvements #362

Merged
merged 2 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## 21.0-SNAPSHOT - unreleased

### 🎁 New Features

* LdapService `searchOne` and `searchMany` methods have been made public.
* LdapPerson class now includes `displayName`, `givenname`, and `sn` fields.

### 🐞 Bug Fixes

* LdapPerson class `email` key changed to `mail` to match LDAP attribute.

## 20.0.2 - 2024-06-05

### 🐞 Bug Fixes
Expand Down
45 changes: 29 additions & 16 deletions grails-app/services/io/xh/hoist/ldap/LdapService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,29 @@ class LdapService extends BaseService {
.collectEntries { [it.key, it.value.get()]}
}


//----------------------
// Implementation
//----------------------
private LdapGroup lookupGroupInternal(String dn, boolean strictMode) {
searchOne("(distinguishedName=$dn)", LdapGroup, strictMode)
}

private List<LdapPerson> lookupGroupMembersInternal(String dn, boolean strictMode) {
// See class-level comment regarding this AD-specific query
searchMany("(|(member0f=$dn) (memberOf:1.2.840.113556.1.4.1941:=$dn))", LdapPerson, strictMode)
}

private <T extends LdapObject> T searchOne(String baseFilter, Class<T> objType, boolean strictMode) {
/**
* Search for a single object, returning the first match found.
* @param baseFilter - an LDAP filter to be appended to the objectCategory filter.
* @param objType - type of Hoist-Core LdapObject to search for - must be or extend LdapObject, LdapPerson, or LdapGroup
* @param strictMode - if true, this method will throw if any lookups fail
* @return first match found in the form of objType
*/
<T extends LdapObject> T searchOne(String baseFilter, Class<T> objType, boolean strictMode) {
for (server in config.servers) {
List<T> matches = doQuery(server, baseFilter, objType, strictMode)
if (matches) return matches.first()
}
return null
}

private <T extends LdapObject> List<T> searchMany(String baseFilter, Class<T> objType, boolean strictMode) {
/**
* Search for multiple objects, returning all matches found.
* @param baseFilter - an LDAP filter to be appended to the objectCategory filter.
* @param objType - type of Hoist-Core LdapObject to search for - must be or extend LdapObject, LdapPerson, or LdapGroup
* @param strictMode - if true, this method will throw if any lookups fail
* @return list of all matches found in the form of objType
*/
<T extends LdapObject> List<T> searchMany(String baseFilter, Class<T> objType, boolean strictMode) {
List<T> ret = []
for (server in config.servers) {
List<T> matches = doQuery(server, baseFilter, objType, strictMode)
Expand All @@ -114,10 +115,22 @@ class LdapService extends BaseService {
return ret
}

//----------------------
// Implementation
//----------------------
private LdapGroup lookupGroupInternal(String dn, boolean strictMode) {
searchOne("(distinguishedName=$dn)", LdapGroup, strictMode)
}

private List<LdapPerson> lookupGroupMembersInternal(String dn, boolean strictMode) {
// See class-level comment regarding this AD-specific query
searchMany("(|(member0f=$dn) (memberOf:1.2.840.113556.1.4.1941:=$dn))", LdapPerson, strictMode)
}

private <T extends LdapObject> List<T> doQuery(Map server, String baseFilter, Class<T> objType, boolean strictMode) {
if (!enabled) throw new RuntimeException('LdapService is not enabled.')

boolean isPerson = objType == LdapPerson
boolean isPerson = LdapPerson.class.isAssignableFrom(objType)
lbwexler marked this conversation as resolved.
Show resolved Hide resolved
String host = server.host,
filter = "(&(objectCategory=${isPerson ? 'Person' : 'Group'})$baseFilter)",
key = server.toString() + filter
Expand Down
16 changes: 13 additions & 3 deletions src/main/groovy/io/xh/hoist/ldap/LdapPerson.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@ package io.xh.hoist.ldap

import javax.management.Attribute

class LdapPerson extends LdapObject{
/**
* Minimal set of attributes returned by a search for objectCategory=Person in Microsoft's AD LDAP implementation.
* If you need more attributes, you can extend this class and add them.
*
* Available attributes can be found here:
* https://learn.microsoft.com/en-us/archive/technet-wiki/12037.active-directory-get-aduser-default-and-extended-properties
*/
class LdapPerson extends LdapObject {

String name
String email
String displayname
String givenname
String sn
String mail

static LdapPerson create(Collection<Attribute> atts) {
def ret = new LdapPerson()
Expand All @@ -14,6 +24,6 @@ class LdapPerson extends LdapObject{
}

static List<String> getKeys() {
LdapObject.keys + ['name', 'email']
LdapObject.keys + ['name', 'displayname', 'givenname', 'sn', 'mail']
}
}
Loading