Используйте JAAS для пароля LDAP с безопасностью Spring

У меня есть веб-приложение Java EE, которое использует аутентификацию LDAP. Я использую безопасность 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

Мы можем увидеть это в официальной документации веб-сферы: 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 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());

Есть ли способ использовать только безопасность 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 .

Может быть, я должен полностью изменить свой подход и использовать другой способ?


person Duff    schedule 26.12.2012    source источник
comment
› ОГРОМНАЯ клиентская библиотека IBM com.ibm.ws.admin.client-7.0.0.jar (42 мес.) => компиляция медленнее. Хотя я понимаю необходимость избегать таких больших файлов jar, обычно их наличие не замедляет компиляцию. Java не перекомпилирует jar-файлы. Они связаны, но не скомпилированы.   -  person Arjan Tijms    schedule 26.12.2012
comment
Да, ты прав. Я пишу это быстро... Я говорю это, потому что, когда я заканчиваю компилировать, я копирую свои jar-файлы для развертывания. Но эти банки предоставляются сервером приложений, и я уже помечаю его как предоставленный в файле maven pom. ;о)   -  person Duff    schedule 28.12.2012


Ответы (1)


Я предполагаю, что ваша цель состоит в том, чтобы просто использовать имя пользователя/пароль, которые вы настроили в 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>

Вы также можете настроить пароль пользователя в JNDI. Другой альтернативой является использование файла .properties со свойством. Если вы хотите обеспечить безопасность пароля, вы, вероятно, захотите зашифровать пароль, используя что-то вроде Jasypt< /а>.

Устранение зависимостей времени компиляции и по-прежнему настройка с помощью WAS

Если вам нужна или вы хотите использовать поддержку WebSphere J2C для хранения учетных данных, вы можете сделать это, внедрив экземпляр CallbackHandler. Например, ваш bean-компонент 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 и на другом компьютере.

person Rob Winch    schedule 27.12.2012
comment
Спасибо за ответ! На самом деле да, я хочу удалить свой пароль в файле конфигурации. Я предоставляю файл конфигурации своей команде развертывания, но я не знаю производственного пароля, поэтому у меня не может быть пароля. Для локальной среды и среды разработки. Я уже использую Jasypt и spring профиль в зависимости от моей среды. Мне нравится идея определить мою зависимость в моей конфигурации spring. Жаль, что его нет. Я уже предложил моей команде по развертыванию хранить пароль в JNDI, но они этого не хотят ;o( . Большое спасибо за ваш ответ. - person Duff; 28.12.2012
comment
небольшое изменение, я удаляю первый factory-method=getCallbackHandler в bean-компоненте userConnexion. Остальное ок, еще раз спасибо - person Duff; 28.12.2012
comment
Рад слышать, что это помогло. Я обновил сообщение, чтобы отразить небольшое изменение, о котором вы упомянули. - person Rob Winch; 29.12.2012