使用Spring Security JAAS的LDAP密码(Use JAAS for LDAP pa

2019-08-04 17:29发布

我有一个使用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>

其实,我的豆WebsphereCredentials使用的WebSphere私有类WSMappingCallbackHandlerFactory在这样的响应: 如何从EJB访问认证别名部署到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

但我不希望它因为:

  1. 我想我的应用程序可以访问所有JAAS登录我的WebSphere实例(不知道)。
  2. 这个类在巨大的IBM客户端库com.ibm.ws.admin.client-7.0.0.jar(42沫)=>汇编较慢,而不是在我的企业关系本定义
  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());

有没有办法使用只是春天的安全和消除这种依赖的方法吗?

我不知道如何结合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 。

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

Answer 1:

我假设你的目标是简单地利用您在WebSphere配置连接到LDAP目录中的用户名/密码? 如果是这样的话,你是不是真的想LDAP和基于JAAS认证结合起来。 该JAAS支持真正意图是使用JAAS的一种方式LoginModule s到用户进行身份验证,而不是使用基于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>

你也可以配置JNDI的用户名密码。 另一种方法是使用与物业.properties文件。 如果你是想确保密码被固定,那么你可能会想使用的密码,像加密Jasypt 。

消除编译时依赖,并仍然可以配置WAS

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

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定义配置文件在WebSphere和非WebSphere机运行之间进行区分。



文章来源: Use JAAS for LDAP password with Spring security