Spring 3.1 Процесс аутентификации LDAP: "неверные учетные данные" msg, когда учетные данные хороши
Spring 3.1 Tomcat 6.*
Я работаю над созданием веб-приложения Spring 3.1, проходящего аутентификацию с помощью LDAP.
Я проверил учетные данные LDAP (имя пользователя, пароль, URL-адрес ldap, шаблон поиска) с помощью написанной мной Java-программы в стиле JNDI (цитируется ниже). Эта программа работала, сбрасывая все атрибуты пользователей, включая пароль, который, кажется, зашифрован на сервере LDAP.
Когда я пытаюсь войти с теми же учетными данными в Spring 3.1, я получаю сообщение об ошибке "Bad Credentials".
Я получил это сообщение в журналах:
DEBUG [org.springframework.security.authentication.ProviderManager:authenticate] (ProviderManager.java:152) - Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
DEBUG [org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider:authenticate] (AbstractLdapAuthenticationProvider.java:51) - Processing authentication request for user: John.A.Smith
DEBUG [org.springframework.security.ldap.authentication.BindAuthenticator:bindWithDn] (BindAuthenticator.java:108) - Attempting to bind as uid=John.A.Smith,ou=People,o=acme.com,o=acme.com
DEBUG [org.springframework.security.ldap.DefaultSpringSecurityContextSource$1:setupEnvironment] (DefaultSpringSecurityContextSource.java:76) - Removing pooling flag for user uid=John.A.Smith,ou=People,o=acme.com,o=acme.com
DEBUG [org.springframework.security.ldap.authentication.BindAuthenticator:handleBindException] (BindAuthenticator.java:152) - Failed to bind as uid=John.A.Smith,ou=People,o=acme.gov: org.springframework.ldap.AuthenticationException: [LDAP: error code 32 - No Such Object]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 32 - No Such Object]
DEBUG [org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter:unsuccessfulAuthentication] (AbstractAuthenticationProcessingFilter.java:340) - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
В моем *-security.xml я пытался использовать теги для сравнения паролей и кодирования, но это не помогло. Я пытался использовать md4,md5, обычный текст,sha,sha-256,{ssha},{sha} безрезультатно.
<s:authentication-manager>
<s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People,o=noaa.gov" >
<s:password-compare hash="md5">
<s:password-encoder hash="md5"/>
</s:password-compare>
</s:ldap-authentication-provider>
</s:authentication-manager>
Моя сетевая группа - большая медленная бюрократическая организация. Есть ли способ, которым я могу сказать, какую кодировку они используют, если таковые имеются, не связываясь с ними?
Любые идеи вещей, которые я мог бы проверить?
Это мой *-security.xml с моей последней попытки и демонстрационная версия java LDAP, с которой я смог связаться
Благодарю.
Мой *-security.xml файл:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<s:http auto-config="true" use-expressions="true">
**<s:intercept-url pattern="/welcome*" access="isAuthenticated()" />**
<s:form-login login-page="/login" default-target-url="/welcome"
authentication-failure-url="/loginfailed" />
<s:logout logout-success-url="/logout" />
</s:http>
<s:ldap-server url = "ldap://ldap-itc.sam.acme.com:636/o=acme.com"/>
<s:authentication-manager>
<s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People,o=noaa.gov" />
</s:authentication-manager>
</beans>
Вот LDAP-программа в стиле JNDI, работающая с теми же учетными данными:
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
import java.sql.*;
public class LDAPDEMO {
public static void main(String args[]) {
String lcf = "com.sun.jndi.ldap.LdapCtxFactory";
String ldapurl = "ldap://ldap-itc.sam.acme.com:636/o=acme.com";
String loginid = "John.A.Smith";
String password = "passowordforjohn";
DirContext ctx = null;
Hashtable env = new Hashtable();
Attributes attr = null;
Attributes resultsAttrs = null;
SearchResult result = null;
NamingEnumeration results = null;
int iResults = 0;
env.put(Context.INITIAL_CONTEXT_FACTORY, lcf);
env.put(Context.PROVIDER_URL, ldapurl);
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=" + loginid + ",ou=People,o=acme.com");
env.put(Context.SECURITY_CREDENTIALS, password);
try {
ctx = new InitialDirContext(env);
attr = new BasicAttributes(true);
attr.put(new BasicAttribute("uid",loginid));
results = ctx.search("ou=People",attr);
while (results.hasMore()) {
result = (SearchResult)results.next();
resultsAttrs = result.getAttributes();
for (NamingEnumeration enumAttributes = resultsAttrs.getAll(); enumAttributes.hasMore();) {
Attribute a = (Attribute)enumAttributes.next();
System.out.println("attribute: " + a.getID() + " : " + a.get().toString());
}// end for loop
iResults++;
}// end while loop
System.out.println("iResults == " + iResults);
}// end try
catch (Exception e) {
e.printStackTrace();
}
}// end function main()
}// end class LDAPDEMO
Решение
Этот комментарий от Люка Тейлора помог мне настроить мою конфигурацию:
Ваша конфигурация неверна в том, что у вас есть "o=acme.com" в URL-адресе сервера LDAP, а также вы используете "o=acme.com" в шаблоне DN пользователя.
Я выбрал "o=acme.com" из шаблона DN, и LDAP сработал. Первоначально я поместил "o=acme.com" в URL-адрес LDAP и шаблон DN, потому что я новичок в Spring 3.1 и LDAP, и это похоже на то, как это было / было сделано в Java-версии JNDI LDAP демонстрация, которую я написал на основе устаревшего кода, который я заменяю.
Вот окончательная рабочая версия моего *-security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<s:http auto-config="true" use-expressions="true">
**<s:intercept-url pattern="/welcome*" access="isAuthenticated()" />**
<s:form-login login-page="/login" default-target-url="/welcome"
authentication-failure-url="/loginfailed" />
<s:logout logout-success-url="/logout" />
</s:http>
<s:ldap-server url = "ldap://ldap-itc.sam.acme.com:636/o=acme.com"/>
<s:authentication-manager>
<s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People" />
</s:authentication-manager>
</beans>
Я собираюсь изучить его другой комментарий и посмотреть, смогу ли я вернуть кодировку пароля или мне нужно.
2 ответа
В вашем примере с Java используется стандартная аутентификация связывания, но вы настроили конфигурацию Spring Security для выполнения операции сравнения LDAP с паролем пользователя. Это не удастся, поскольку сервер LDAP не использует тот же формат кодировки паролей, что и кодер MD5 Spring Security. Для успешного выполнения операции сравнения сохраненное значение должно соответствовать строке, отправленной в каталог. В большинстве случаев вы хотите использовать стандартную аутентификацию LDAP (bind). Возможно, вам понадобится использовать конфигурацию компонента для провайдера аутентификации. Попробуйте использовать:
<s:ldap-server id="contextSource" url="ldap://ldap-itc.sam.acme.com:636/o=acme.com"/>
<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>uid={0},ou=People</value></list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.NullLdapAuthoritiesPopulator"/>
</constructor-arg>
<property name="authoritiesMapper">
<bean class="class="org.springframework.security.core.authority.mapping">
<property name="defaultAuthority" value="ROLE_USER" />
</bean>
</property>
</bean>
<s:authentication-manager>
<s:authentication-manager ref="ldapAuthProvider" />
</s:authentication-manager>
Я бы рекомендовал вам также прочитать главу LDAP справочного руководства.
Кроме того, если вы хотите знать, почему не удается выполнить аутентификацию, лучше всего узнать журнал самого сервера LDAP. Если у вас нет полного доступа, узнайте, как он настроен, и используйте локальный сервер (например, OpenLDAP), где у вас есть полный контроль.
Я попробую удачу. Несколько недель назад у меня была похожая проблема. Нет ошибок, правильный пользователь / пароль и ошибка Bad Credentials.
Во-первых, я рекомендую вам активировать уровень отладки для безопасности весны. Вы получите больше информации. В моем случае это помогло мне понять, что проблема заключалась в том, что у моего пользователя не было никакой связанной роли, и Spring считал ее ошибкой "неверных учетных данных". Это может быть ваш случай. Проверь это.
В любом случае, плохие учетные данные не всегда означают, что пользователь / пароль неверен.
РЕДАКТИРОВАТЬ: Для активации уровня отладки с помощью log4j:
<logger name="org.springframework.security">
<level value="DEBUG" />
</logger>
В вашей конфигурации можно прочитать, что для доступа к странице приветствия требуется роль администратора: ROLE_ADMIN. Если вы не хотите роли, попробуйте что-то вроде этого:
<s:intercept-url pattern="/welcome*" access="isAuthenticated()" />