将 JAAS 用于具有 Spring 安全性的 LDAP 密码

Posted

技术标签:

【中文标题】将 JAAS 用于具有 Spring 安全性的 LDAP 密码【英文标题】:Use JAAS for LDAP password with Spring security 【发布时间】:2012-12-11 22:05:02 【问题描述】:

我有一个使用 LDAP 身份验证的 Java EE Web 应用程序。我使用 Spring 安全性通过以下代码连接到我的 LDAP:

<bean id="ldapContextSource" class="com.myapp.security.authentication.MySecurityContextSource">
    <constructor-arg index="0" value="$ldap.url" />
    <constructor-arg index="1" ref="userConnexion" />
</bean>

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>

<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
    <constructor-arg value="$ldap.authJndiAlias" />
</bean>

<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="ldapContextSource" />
            <property name="userSearch" ref="userSearch" />
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="com.myapp.security.authentication.MyAuthoritiesPopulator" >
            <property name="userService" ref="userService" />
        </bean>
    </constructor-arg>
    <property name="userDetailsContextMapper" ref="myUserDetailsContextMapper"/>
    <property name="hideUserNotFoundExceptions" value="false" />
</bean>

实际上,我的 bean WebsphereCredentials 使用 WebSphere 私有类 WSMappingCallbackHandlerFactory,如在此响应中:How to access authentication alias from EJB deployed to Websphere 6.1

我们可以在websphere官方文档中看到:http://pic.dhe.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Frsec_pluginj2c.html

但我不想要它,因为:

    我认为我的应用程序可以访问我的 WebSphere 实例中的所有 JAAS 登录(不确定)。 这个类在巨大的 IBM 客户端库 com.ibm.ws.admin.client-7.0.0.jar (42 Mo) 中定义 => 编译速度较慢,在我的企业关系中不存在 它不是便携式的,不是标准的

关于信息,我将WebsphereCredentials 构造函数定义为:

Map<String, String> map = new HashMap<String, String>();

map.put(Constants.MAPPING_ALIAS, this.jndiAlias);
Subject subject;
try 
    CallbackHandler callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null);
    LoginContext lc = new LoginContext("DefaultPrincipalMapping", callbackHandler);
    lc.login();
    subject = lc.getSubject();
 catch (NotImplementedException e) 
    throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
 catch (LoginException e) 
    throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);


PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];

this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());

有没有办法只使用 Spring 安全性并删除此依赖项?

我不知道如何组合http://static.springsource.org/spring-security/site/docs/3.1.x/reference/jaas.html 和http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ldap.html。

也许我必须完全改变我的方法并使用另一种方式?

【问题讨论】:

>HUGE IBM 客户端库 com.ibm.ws.admin.client-7.0.0.jar (42 Mo) => 编译速度较慢 - 虽然我知道需要避免使用如此大的 jar,但通常有它们不会减慢编译速度。 Java 不会重新编译 jar。它们已链接,但未编译。 是的,你是对的。我把它写得很快……我这么说是因为当我完成编译时,我复制了我的 jars 以进行部署。但是这个 jars 是由应用程序服务器提供的,我已经在 maven pom 文件中将它标记为提供。 ;o) 【参考方案1】:

我假设您的目标是简单地使用您在 WebSphere 中配置的用户名/密码来连接到 LDAP 目录?如果是这种情况,您并没有真正尝试结合基于 LDAP 和 JAAS 的身份验证。 JAAS 支持实际上是一种使用 JAAS LoginModules 来验证用户身份的方式,而不是使用基于 LDAP 的身份验证。

如果您想获得用户名和密码而不依赖于 WebSphere 的编译时,您有几个选择。

消除对 WAS 的编译时间和运行时间依赖性

一种选择是以不同的方式配置密码。这可以像直接在配置文件中直接使用密码一样简单,如Spring Security LDAP documentation所示:

<bean id="ldapContextSource"
        class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
  <property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
  <property name="password" value="password"/>
</bean>

您还可以在 JNDI 中配置用户名密码。另一种选择是使用带有属性的 .properties 文件。如果您想确保密码是安全的,那么您可能需要使用Jasypt 之类的东西来加密密码。

消除编译时间依赖性并仍然使用 WAS 进行配置

如果您需要或想要使用 WebSphere 的 J2C 支持来存储凭证,那么您可以通过注入 CallbackHandler 实例来实现。例如,您的 WebsphereCredentials bean 可能是这样的:

try 
    LoginContext lc = new LoginContext("DefaultPrincipalMapping", this.callbackHandler);
    lc.login();
    subject = lc.getSubject();
 catch (NotImplementedException e) 
    throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);
 catch (LoginException e) 
    throw new EfritTechnicalException(EfritTechnicalExceptionEnum.LOGIN_CREDENTIAL_PROBLEM, e);


PasswordCredential cred = (PasswordCredential) subject.getPrivateCredentials().toArray()[0];

this.user = cred.getUserName();
this.password = String.valueOf(cred.getPassword());

您的配置将如下所示:

<bean id="userConnexion" class="com.myapp.util.security.WebsphereCredentials">
    <constructor-arg ref="wasCallbackHandler"/>
</bean>

<bean id="wasCallbackHandler"
      factory-bean="wasCallbackFactory"
      factory-method="getCallbackHandler">
    <constructor-arg>
      <map>
        <entry
            value="$ldap.authJndiAlias">
          <key>
            <util:constant static-field="com.ibm.wsspi.security.auth.callback.Constants.MAPPING_ALIAS"/>
          </key>
        </entry>
      </map>
    </constructor-arg>
    <constructor-arg>
      <null />
    </constructor-arg>
</bean>

<bean id="wasCallbackFactory"
    class="com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory"
    factory-method="getInstance" />

免责声明

CallbackHandler 实例不是线程安全的,通常不应多次使用。因此,将CallbackHandler 实例作为成员变量注入可能有点冒险。您可能需要编写一个检查程序以确保CallbackHandler 只使用一次。

混合方法

您可以采用一种混合方法,该方法始终删除编译时依赖项,并允许您在可能未在 WebSphere 上运行的实例中删除运行时依赖项。这可以通过结合这两个建议并使用Spring Bean Definition Profiles 来区分在 WebSphere 和非 WebSphere 机器上运行来完成。

【讨论】:

感谢您的回复!事实上是的,我想在配置文件中删除我的密码。我向我的部署团队提供了配置文件,但我不知道生产密码,这就是我无法获得密码的原因。对于本地和开发环境。我已经根据我的环境使用了 Jasypt 和 spring 配置文件。我喜欢在我的 spring 配置中定义我的依赖项的想法。很抱歉没有。我已经向我的部署团队提议在 JNDI 中存储密码,但他们不想要它;o(。非常感谢您的回复。 小改动,我删除了 bean userConnexion 中的第一个 factory-method="getCallbackHandler"。其他都还好,再次感谢 很高兴听到它有帮助。我更新了帖子以反映您提到的小变化。

以上是关于将 JAAS 用于具有 Spring 安全性的 LDAP 密码的主要内容,如果未能解决你的问题,请参考以下文章

JAAS、Spring Security 或 Apache Shiro

“Spring Security”和“Java 认证和授权服务(jaas)”

如何使用自定义 JAAS 堆栈配置 Spring Security?

转载-ActiveMQ通过JAAS实现的安全机制

JAAS 概念

Spring Security 是基于 JAAS 的吗?