Spring Boot / Spring LDAP 获取用户的memberof列表

2023-12-07

我想通过从如下结构的 LDAP 存储库查询用户 ID 来获取用户属性列表

dn: uid=E000001 ,ou=People,o=Company,o=Internal
cn: BOB DOLE
statusid: active
memberof: cn=foo_group, cn=Foos, ou=Groups, o=Company,o=Internal
memberof: cn=bar_group, cn=Foos, ou=Groups, o=Company,o=Internal

dn: uid=E000002 ,ou=People,o=Company,o=Internal
cn: MARK TEST
statusid: active
memberof: cn=foo_group, cn=Foos, ou=Groups, o=Company,o=Internal
memberof: cn=bar_group, cn=Foos, ou=Groups, o=Company,o=Internal

例如,我查询用户 ID“E00001”。我想退货

["cn=foo_group, cn=Foos, ou=Groups, o=Company,o=Internal", "cn=bar_group, cn=Foos, ou=Groups, o=Company,o=Internal"

以下是检索用户组的多种方法:

  • 如果您有一个没有嵌套组的简单 LDAP 服务器,memberOf 通常就足够了:

    String userCN = "user1";
    
    //Get the attribute of user's "memberOf"
    ArrayList<?> membersOf = ldapTemplate.search(
            query().where("sAMAccountName").is(userCN),
            (AttributesMapper<ArrayList<?>>) attrs -> Collections.list(attrs.get("memberOf").getAll())
    ).get(0);
    
  • 但如果你有嵌套组,事情就会变得更加复杂:

    /*
     * Get user distinguised name, example: "user" -> "CN=User Name,OU=Groups,OU=Domain Users,DC=company,DC=something,DC=org"
     * This will be used for our query later
     */
    String distinguishedName = ldapTemplate.search(
            query().where("sAMAccountName").is(userCN),
            (AttributesMapper<String>) attrs -> attrs.get("distinguishedName").get().toString()
    ).get(0); //.get(0): we assume that search will return a result 
    
    /*
     * This one recursively search for all (nested) group that this user belongs to
     * "member:1.2.840.113556.1.4.1941:" is a magic attribute, Reference: 
     * https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx
     * However, this filter is usually slow in case your ad directory is large.
     */
    List<String> allGroups = ldapTemplate.search(
            query().searchScope(SearchScope.SUBTREE)
                    .where("member:1.2.840.113556.1.4.1941:").is(distinguishedName),
            (AttributesMapper<String>) attrs -> attrs.get("cn").get().toString()
    );
    

对于谷歌用户:请注意,这依赖于org.springframework.boot:spring-boot-starter-data-ldap,如果有人需要 Bean 初始化代码:

@Component
@EnableConfigurationProperties
public class Ldap {
    @Bean
    @ConfigurationProperties(prefix="ldap.contextSource")
    public LdapContextSource contextSource() {
        return new LdapContextSource();
    }

    @Bean
    public LdapTemplate ldapTemplate(ContextSource contextSource) {
        return new LdapTemplate(contextSource);
    }
}

在 application.yml 中使用以下配置模板:

ldap:
    contextSource:
        url: ldap://your-ldap.server
        base: dc=Company,dc=Domain,dc=Controller
        userDn: username
        password: hunter2
        #you'll want connection polling set to true so ldapTemplate reuse the connection when searching recursively
        pooled: true

当幻数性能不佳时:如果您的 ldap 目录很大,最后一个使用幻数实际上相当慢,在这种情况下递归搜索 ldap 会更快。这是一个帮助程序类,用于彻底搜索用户所属的所有组:

public class LdapSearchRecursive {
    private final LdapTemplate ldapTemplate;
    private Set<String> groups;

    public LdapSearchRecursive(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
        this.groups = new HashSet<>();
    }

    /**
     * Retrieve all groups that this user belongs to.
     */
    public Set<String> getAllGroupsForUserRecursively(String userCN) {
        List<String> distinguishedNames = this.ldapTemplate.search(
                query().where("objectCategory").is("user").and(
                        query().where("sAMAccountName").is(userCN)
                                .or(query().where("userPrincipalName").is(userCN))
                ),
                (AttributesMapper<String>) attrs -> attrs.get("distinguishedName").get().toString()
        );

        if (distinguishedNames.isEmpty()) {
            throw new UsernameNotFoundException("User not recognized in LDAP");
        }

        return this.getAllGroupsRecursivelyByUserDistinguishedName(distinguishedNames.get(0), null);
    }

    private Set<String> getAllGroupsRecursivelyByUserDistinguishedName(String dn, @Nullable String parentDN) {
        List<String> results = this.ldapTemplate.search(
                query().where("member").is(dn),
                (AttributesMapper<String>) attrs -> attrs.get("distinguishedName").get().toString()
        );

        for (String result : results) {
            if (!(result.equals(parentDN) //circular, ignore
                    || this.groups.contains(result) //duplicate, ignore
                    )) {
                this.getAllGroupsRecursivelyByUserDistinguishedName(result, dn);
            }
        }
        this.groups.addAll(results);

        return this.groups;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot / Spring LDAP 获取用户的memberof列表 的相关文章

随机推荐

  • Common Lisp,引用值和实际值

    考虑这段代码 defvar lst 1 1 defmacro get x x lst nth x lst defun get y y lst nth y lst 现在让我们假设我想更改名为的列表元素的值lst the car with ge
  • NSUndoManager 在 Swift 代码中转换 NSUndoManagerProxy 崩溃

    在我们的应用程序中 我们使用以下代码 let lInvocationTarget lUndoManager prepare withInvocationTarget self let lInvocationTarget as MyObjec
  • IE6 (IE7) 上的 JSON

    抱歉我的不耐烦 但是经过几周的熬夜并将我的网络上线后 我没有任何剩余的精力来调试 我只是无法谷歌如何在 IE6 和 IE7 上实现 JSON 我正在使用 JSON stringify 据我了解 JSON 不是内置在 IE6 7 上的 必须在
  • d3 单击圆圈暂停并恢复标记沿线的过渡

    我希望帮助纠正我的代码 单击标记圆圈元素以暂停或恢复该元素沿线的转换 我的代码沿一条线移动标记 我可以使用单击按钮元素来暂停和恢复此转换 但我希望能够单击标记圆圈本身 而不是按钮 我使用了各种参考资料 包括 http www nytimes
  • 如何在 PHP 中添加 href 链接? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 我对 PHP 很陌生 并试图即时更新网站 我需要更新代
  • Python - Sqlite插入没有自动增量主键值的元组

    我创建一个带有主键和自动增量的表 with open RAND xml rb as f sqlite3 connect race db as connection c connection cursor c execute CREATE T
  • 计算多列每个字母的频率[重复]

    这个问题在这里已经有答案了 我有一个数据框如下 gt dfnew C1 C2 C3 C4 C5 C6 1 A A G A G A 2 A T T T G G 3 T A G A T A 4 C A A A A G 5 C A T T T C
  • SQLite iOS 插入数据

    我试图将一个名称插入到我的 sqlite 文件中 我正在使用此代码 但它不起作用 void InsertRecords NSMutableString txt if addStmt nil const char sql INSERT INT
  • 我需要使用 { get; 吗?放; } 具有在获取和设置时没有特殊操作的 C# 字段

    我一直在编写这样的类 public class ReportViewModel public string Status public string DataSource public String DataStore get set pu
  • 无限重复列表(用无限重复序列压缩有限列表)

    UserList是一个字典列表 例如 Name Alex Age 25 Name Peter Age 35 Name Muhammad Age 28 Name Raul Age 29 RowColorList是一个颜色列表 bcf fc0
  • 原型回调函数吞掉异常

    使用原型版本 1 6 0 2 我有一个常见的问题 异常在回调函数中抛出时被吞没 通常是当我尝试处理对Ajax Request称呼 这是一个简单的例子 HTML 标记
  • 如何在 UWP 应用中从不同的 URL 播放视频和音频?

    我正在尝试为 UWP 桌面应用程序创建视频播放器 我无法播放来自不同 URL 的视频和音频 我在下面给出了我的代码 但没有给出音频和视频 URL 我正在使用一个Xampp我的案例的本地服务器 请帮我 My MainPage xaml cs
  • 找不到appcompat_v7.apk

    当我尝试运行我的程序时 它可以工作 但是当我查看控制台时 它表明它Could not find appcompat v7 apk 我该如何尝试回答这个问题 我刚刚导入了大部分资源 当我这样做时会发生以下情况 Properties gt An
  • 配置 tomcat 仅针对特定 URL 模式进行客户端身份验证

    我有一个应用程序 其中有几个 war 文件 全部部署在同一个 tomcat 服务器上 我需要仅针对一个战争上下文强制客户端身份验证 并且仅针对特定 URL 我在网上阅读了很多内容并在这里阅读了类似的问题 但我得出的结论与我需要的解决方案不匹
  • Pycharm - 在 Django 控制台中自动加载模型

    有没有办法在 pycharm django 控制台中自动加载模型 与 django extensions shell plus 的工作方式类似 在pycharm设置 django控制台设置中你可以有一个启动脚本 这将自动加载 django
  • 函数的运行时间

    我想打印我的函数的运行时间 由于某种原因 我的计时器总是返回 0 谁能告诉我为什么 double RunningTime clock t time1 clock t time2 double t time1 time2 double tim
  • 检查待处理的呼叫

    我想知道是否有任何方法可以检查是否有任何待处理的调用将在某个时刻执行 例如来自 AJAX 请求或计时器的回调 setTimeout 比如检查正在运行 JavaScript 的引擎的整个堆栈 考虑到 AJAX 回调依赖于服务器响应 成功 失败
  • 为什么我可以在 gcc 上声明一个具有预定大小的数组,但不能在 Visual Studio C++ 上声明?

    我想知道为什么我可以在 linux 中执行此代码 但不能在 Visual Studio 上执行 文件 gt main c int size printf Size scanf d size int vec size 和c89或者c99标准有
  • 根据闪亮应用程序的rhandsontable中其他单元格的修改来更改单元格

    我正在尝试构建一个闪亮的应用程序 其中包含rhandsontable 该 rhandsontable 基于我在应用程序内创建的数据帧 在应用程序中 我最初显示该数据框的第一行和 3 列 当第一列的值通过其下拉级别列表修改并按搜索时 其他两列
  • Spring Boot / Spring LDAP 获取用户的memberof列表

    我想通过从如下结构的 LDAP 存储库查询用户 ID 来获取用户属性列表 dn uid E000001 ou People o Company o Internal cn BOB DOLE statusid active memberof