使用 Spring Security 针对 ADAM 使用 LDAP 进行身份验证

发布于 2024-09-25 06:30:02 字数 2786 浏览 7 评论 0原文

我正在尝试使用 spring-security 获取一个 Java 应用程序来与我设置的本地 ADAM 实例进行通信。

我已成功安装 ADAM 并设置如下....

  • 在 localhost:389 上运行的实例
  • 根目录是 O=Company
    • 名为 OU=Company Users 的子级 (orgnizationalUnit)
      • 一个名为 CN=Mike Q 的孙子(用户)
      • uid = mikepassword =welcome

然后我设置了 spring-security (版本 3.0.3、spring-framework 3.0.4 和 spring-ldap 1.3.0)。 Spring 文件

  <security:ldap-server id="contextSource" url="ldap://localhost:389/o=Company"/>

  <security:authentication-manager>
    <security:ldap-authentication-provider user-dn-pattern="uid={0},ou=Company Users"/>
  </security:authentication-manager>

  <bean class="com.xxx.test.TestAuthentication" lazy-init="false"/>

和 TestAuthentication

public class TestAuthentication
{
    @Autowired
    private AuthenticationManager authenticationManager;

    public void initialise()
    {
        Authentication authentication = new UsernamePasswordAuthenticationToken( "mike", "welcome" );
        Authentication reponseAuthentication = authenticationManager.authenticate( authentication );
    }
}

运行这个我收到以下错误

Caused by: javax.naming.AuthenticationException: [LDAP: error code 49 - 8009030C: LdapErr: DSID-0C090336, comment: AcceptSecurityContext error, data 2030, vece]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3041)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2789)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2703)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134)
at org.springframework.ldap.core.support.LdapContextSource.getDirContextInstance(LdapContextSource.java:43)
at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:254)

如果有人能指出我哪里出错了,我将不胜感激。此时,我只想使用 LDAP 验证输入的用户/密码,没有比这更复杂的了。

我还对一些一般性的观点感兴趣,因为这是我第一次涉足 LDAP 世界。

  • LDAP 区分大小写吗?
  • 最好避免空格吗?
  • 避免在 LDAP 查询中以明文形式发送密码的一般用例/最佳实践有哪些?

I am trying to get a Java app using spring-security to talk to a local ADAM instance that I have setup.

I have successfully installed ADAM and setup as follows....

  • Instance running on localhost:389
  • Root is O=Company
    • A child called OU=Company Users (orgnizationalUnit)
      • A granchild called CN=Mike Q (user)
      • uid = mike and password = welcome

Then I have setup spring-security (version 3.0.3, spring-framework 3.0.4 and spring-ldap 1.3.0). Spring file

  <security:ldap-server id="contextSource" url="ldap://localhost:389/o=Company"/>

  <security:authentication-manager>
    <security:ldap-authentication-provider user-dn-pattern="uid={0},ou=Company Users"/>
  </security:authentication-manager>

  <bean class="com.xxx.test.TestAuthentication" lazy-init="false"/>

And TestAuthentication

public class TestAuthentication
{
    @Autowired
    private AuthenticationManager authenticationManager;

    public void initialise()
    {
        Authentication authentication = new UsernamePasswordAuthenticationToken( "mike", "welcome" );
        Authentication reponseAuthentication = authenticationManager.authenticate( authentication );
    }
}

Running this I get the following error

Caused by: javax.naming.AuthenticationException: [LDAP: error code 49 - 8009030C: LdapErr: DSID-0C090336, comment: AcceptSecurityContext error, data 2030, vece]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3041)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2789)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2703)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134)
at org.springframework.ldap.core.support.LdapContextSource.getDirContextInstance(LdapContextSource.java:43)
at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:254)

If someone could point out where I'm going wrong I'd be grateful. At this point I just want to authenticate an entered user/password using LDAP, nothing more complex than that.

I'm also interested in some general points as this is my first foray into LDAP world.

  • Is LDAP case sensitive?
  • Are spaces best avoided?
  • What are the general use-cases/best practices to avoid sending the password in clear-text in the LDAP query?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最冷一天 2024-10-02 06:30:02

好吧,我花了很多时间来解决这个问题,这就是答案。

错误代码2030表示用户的DN无效。

经过一番尝试和错误后,这里的配置可以正常工作并且用户可以正确搜索。 (您可能可以使用安全命名空间重写它,但是当我正在研究这个时,使用原始 bean 定义会更清楚)。

  <bean id="contextSource"
        class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://localhost:389/cn=Sandbox,dc=ITOrg"/>
    <property name="userDn" value="cn=superuser,cn=People,cn=Sandbox,dc=ITOrg"/>
    <property name="password" value="xxxxxx"/>
  </bean>

  <bean id="ldapAuthProvider"
        class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
      <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
        <constructor-arg ref="contextSource"/>
        <property name="userDnPatterns">
          <list>
            <value>cn={0},cn=People</value>
          </list>
        </property>
      </bean>
    </constructor-arg>
  </bean>

  <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg index="0" value="cn=People"/>
    <constructor-arg index="1" value="(cn={0})"/>
    <constructor-arg index="2" ref="contextSource"/>
  </bean>

关键是

<property name="userDn" value="cn=superuser,cn=People,cn=Sandbox,dc=ITOrg"/>

当在上下文源中指定 userDn 时,它必须是完整 DN(它不只是将其附加到 url 中提供的基数(构造函数 arg)。

当使用 BindAuthentication 时,

<value>cn={0},cn=People</value>

该值是位于配置

UserSearch 时,

    <constructor-arg index="0" value="cn=People"/>
    <constructor-arg index="1" value="(cn={0})"/>

我无法使其与第二个参数中的 cn=People 一起使用,但这似乎工作正常,请注意,您可以使用用户的属性,例如。 (uid={0})

这里有一些使用 bean 定义的示例代码...

    @Autowired
    private LdapUserSearch ldapUserSearch;

    @Autowired
    private AuthenticationProvider authenticationProvider;

    public void initialise()
    {
        DirContextOperations dirContextOperations = ldapUserSearch.searchForUser( "username" );

        Authentication authentication = authenticationProvider.authenticate( new UsernamePasswordAuthenticationToken( "username", "password" ) );    
    }

其他一些随机的花絮...

Error 52b - Invalid password


[LDAP: error code 32 - 0000208D: NameErr: DSID-031521D2, problem 2001 (NO_OBJECT), data 0, best match of: 'CN=Sandbox,DC=ITOrg'
     - This means the user is not in the administrator role (probably)

希望这一切对其他人有帮助。

OK so as I spent plenty of time solving this here's the answer.

Error code 2030 means that the DN of the user is invalid.

After some trial and error here is a config that works and does user search properly. (You can probably rewrite this using the security namespace but while I was working on this it was clearer to use the raw bean definitions).

  <bean id="contextSource"
        class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://localhost:389/cn=Sandbox,dc=ITOrg"/>
    <property name="userDn" value="cn=superuser,cn=People,cn=Sandbox,dc=ITOrg"/>
    <property name="password" value="xxxxxx"/>
  </bean>

  <bean id="ldapAuthProvider"
        class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
      <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
        <constructor-arg ref="contextSource"/>
        <property name="userDnPatterns">
          <list>
            <value>cn={0},cn=People</value>
          </list>
        </property>
      </bean>
    </constructor-arg>
  </bean>

  <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg index="0" value="cn=People"/>
    <constructor-arg index="1" value="(cn={0})"/>
    <constructor-arg index="2" ref="contextSource"/>
  </bean>

The key things are

<property name="userDn" value="cn=superuser,cn=People,cn=Sandbox,dc=ITOrg"/>

When specifying the userDn in the context source it must be the FULL DN (it doesn't just append it do the base supplied in the url (constructor arg).

When using BindAuthentication

<value>cn={0},cn=People</value>

This value IS a suffix on top of the baseDn of the context source.

When configuring a UserSearch

    <constructor-arg index="0" value="cn=People"/>
    <constructor-arg index="1" value="(cn={0})"/>

I couldn't get it to work with cn=People being in the second arg but this seems to work fine. Note you can use attributes of the user e.g. (uid={0})

And here's some example code using the bean definitions...

    @Autowired
    private LdapUserSearch ldapUserSearch;

    @Autowired
    private AuthenticationProvider authenticationProvider;

    public void initialise()
    {
        DirContextOperations dirContextOperations = ldapUserSearch.searchForUser( "username" );

        Authentication authentication = authenticationProvider.authenticate( new UsernamePasswordAuthenticationToken( "username", "password" ) );    
    }

Some other random titbits...

Error 52b - Invalid password


[LDAP: error code 32 - 0000208D: NameErr: DSID-031521D2, problem 2001 (NO_OBJECT), data 0, best match of: 'CN=Sandbox,DC=ITOrg'
     - This means the user is not in the administrator role (probably)

Hope all this helps someone else.

葬﹪忆之殇 2024-10-02 06:30:02

我通过添加您尝试用作同一基本 DN 中管理员角色成员的用户来修复此问题。
希望有帮助

I fixed this problem by adding the user you are trying to use as a member of the administrators role in the same Base DN.
Hope that helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文