使用JAAS获取具有Spring安全性的LDAP密码

Duf*_*uff 4 authentication websphere ldap spring-security jaas

我有一个使用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>
Run Code Online (Sandbox Code Playgroud)

实际上,我的bean 在此响应中WebsphereCredentials使用WebSphere私有类WSMappingCallbackHandlerFactory:如何从部署到Websphere 6.1的EJB访问身份验证别名

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

但我不想要它,因为:

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

有关信息,我将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());
Run Code Online (Sandbox Code Playgroud)

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

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

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

Rob*_*nch 5

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

如果您想要获取用户名和密码而没有对WebSphere的编译时依赖性,那么您有几个选择.

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

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

<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>
Run Code Online (Sandbox Code Playgroud)

您还可以在JNDI中配置用户名密码.另一种方法是使用带有Property的.properties文件.如果您想确保密码是安全的,那么您可能希望使用Jasypt之类的东西来加密密码.

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

如果您需要或想要使用WebSphere的J2C支持来存储凭据,那么您可以通过注入CallbackHandler实例来完成.例如,你的WebsphereCredentialsbean可能是这样的:

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());
Run Code Online (Sandbox Code Playgroud)

您的配置将如下所示:

<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" />
Run Code Online (Sandbox Code Playgroud)

放弃

CallbackHandler实例不是线程安全的,通常不应该多次使用.因此,将CallbackHandler实例注入成员变量可能有点冒险.您可能希望在检查中编程以确保CallbackHandler仅使用一次.

混合方法

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