Двойная аутентификация с пружинной безопасностью (с помощью формы входа и запроса)
В настоящее время я работаю над проектом, включающим GWT 2.5 + Spring 3.1 + Hibernate 3.10.
Веб-приложение в настоящее время находится в производстве и имеет защищенные ресурсы. В целях безопасности мы используем Spring security 3.1 с аутентификацией LDAP.
В настоящее время у нас есть форма входа в систему, в которой мы вводим имя пользователя и пароль и перенаправляем на соответствующую html-страницу (в обработчике успеха), если все в порядке, в противном случае мы перенаправляем на страницу сбоя (благодаря обработчику сбоя).
Теперь клиент хочет сохранить эту функциональность и добавить новую функциональность, которая состоит в добавлении имени пользователя и пароля непосредственно в URL без прохождения через форму входа в систему. Это будет аутентифицировать успешно, если учетные данные в порядке, в противном случае он будет перенаправлен на страницу сбоя.
Я прочитал много вещей на эту тему, и у меня не получается работать.
Вот мой существующий файл spring-security.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
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">
<!-- ================================================== -->
<!-- SECURITE -->
<!-- ================================================== -->
<security:http pattern="/jsp/static/**" security="none"/>
<security:http pattern="/PIE.htc" security="none"/>
<security:http pattern="/ConsultationAccords.css" security="none"/>
<!--Allow everyone to access the JSP login page -->
<security:intercept-url pattern="/app/auth/**" access="permitAll"/>
<security:intercept-url pattern="/jsp/*" access="permitAll"/>
<!-- Limitation d'accès aux différentes partie de l'appli, les pattern sont basés sur les déclaration dans le fichier web.xml -->
<security:intercept-url pattern="/consultationaccords/**" access="isAuthenticated()"/>
<security:intercept-url pattern="/DownloadCourrierServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/*.gupId" access="isAuthenticated()"/>
<security:intercept-url pattern="/DownloadServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/ConsultationAccords.html" access="isAuthenticated()"/>
<security:intercept-url pattern="/ExportServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/ManuelUtilisateurServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/**" access="denyAll" />
<!-- If the user is authorized, he will be redirected to the success-handler.
The sucess-handler is responsible of interpreting what to do next.
Same principle with the failure-handler -->
<security:form-login authentication-success-handler-ref="authenticationSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler" />
<!-- These are the login and logout URLs -->
<security:logout invalidate-session="true" logout-success-url="/app/auth/login" logout-url="/app/auth/logout"/>
<security:session-management invalid-session-url="/app/auth/login"/>
</security:http>
<!-- Point d'entrée pour indiquer à l'utilisateur qu'il doit s'authentifier d'abord -->
<beans:bean id="authenticationEntryPoint" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationEntryPoint" />
<!-- Handler appelé si l'utilisateur a été authetifié avec succès -->
<beans:bean id="authenticationSuccessHandler" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationSuccessHandler"/>
<!-- Handler appelé si l'authetification de l'utilisateur a échoué -->
<beans:bean id="authenticationFailureHandler" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationFailureHandler"/>
<!-- ================================================== -->
<!-- ********************************* -->
<!-- ================================================== -->
<security:authentication-manager>
<security:authentication-provider ref='ldapAuthProvider' />
</security:authentication-manager>
<!-- ================================================== -->
<!-- CONNEXION AU LDAP -->
<!-- ================================================== -->
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://${ldap.server_ip}:${ldap.server_port}"/>
<property name="userDn" value="${ldap.user_reader_account}" />
<property name="password" value="${ldap.password_reader_account}" />
</bean>
<!-- ================================================== -->
<!-- AUTHENTIFICATION + AUTORISATION -->
<!-- ================================================== -->
<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="userSearch">
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="${ldap.user_base_search}"/>
<constructor-arg index="1" value="(uid={0}@${ldap.domain_name})"/>
<constructor-arg index="2" ref="contextSource" />
</bean>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="${ldap.group_base_search}" />
<property name="groupSearchFilter" value="(uniqueMember={0})"/>
<property name="rolePrefix" value="ROLE_"/>
<property name="searchSubtree" value="true"/>
<property name="convertToUpperCase" value="true"/>
<property name="groupRoleAttribute" value="${ldap.group_role_attribute}"/>
</bean>
</constructor-arg>
</bean>
Соответствующая часть моего web.xml
<!-- The Spring Security Filter Chain -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<!-- Pay attention to the url-pattern -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Front Controller for all Spring based servlets -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
/WEB-INF/spring-servlet.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Don't forget to declare a spring-servlet.xml -->
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
Вот что я сделал:
Объявлен и настроен bean-компонент, который представляет собой UsernamePasswordAuthenticationFilter (с обработчиком успеха, обработчиком ошибок, менеджером аутентификации, usernameParameter и passwordParameter)
Добавил его в тег security-http + настройка позиции FIRST
мой web.xml содержит springSecurityFilterChain
Моя весна-security.xml модифицирована:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
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">
<!-- ================================================== -->
<!-- SECURITE -->
<!-- ================================================== -->
<security:http pattern="/jsp/static/**" security="none"/>
<security:http pattern="/PIE.htc" security="none"/>
<security:http pattern="/ConsultationAccords.css" security="none"/>
<security:http pattern="/app/auth/images/**" security="none"/>
<security:custom-filter ref="requestAuthenticationFilter" position="FIRST" />
<!--Allow everyone to access the JSP login page -->
<security:intercept-url pattern="/app/auth/**" access="permitAll"/>
<security:intercept-url pattern="/jsp/*" access="permitAll"/>
<!-- Limitation d'accès aux différentes partie de l'appli, les pattern sont basés sur les déclaration dans le fichier web.xml -->
<security:intercept-url pattern="/consultationaccords/**" access="isAuthenticated()"/>
<security:intercept-url pattern="/DownloadCourrierServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/*.gupId" access="isAuthenticated()"/>
<security:intercept-url pattern="/DownloadServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/ConsultationAccords.html" access="isAuthenticated()"/>
<security:intercept-url pattern="/ExportServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/ManuelUtilisateurServ" access="isAuthenticated()"/>
<security:intercept-url pattern="/**" access="denyAll" />
<security:form-login authentication-success-handler-ref="authenticationSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler" />
<!-- These are the login and logout URLs -->
<security:logout invalidate-session="true" logout-success-url="/app/auth/login" logout-url="/app/auth/logout" />
<security:session-management invalid-session-url="/app/auth/login"/>
</security:http>
<beans:bean id="requestAuthenticationFilter" class="fr.gouv.travail.consultationAccords.server.auth.RequestAuthenticationFilter">
<beans:property name="usernameParameter" value="${ldap.user_request_param_direct_logging}" />
<beans:property name="passwordParameter" value="${ldap.password_request_param_direct_logging}" />
<beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
<beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<!-- Point d'entrée pour indiquer à l'utilisateur qu'il doit s'authentifier d'abord -->
<beans:bean id="authenticationEntryPoint" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationEntryPoint" />
<!-- Handler appelé si l'utilisateur a été authetifié avec succès -->
<beans:bean id="authenticationSuccessHandler" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationSuccessHandler"/>
<!-- Handler appelé si l'authetification de l'utilisateur a échoué -->
<beans:bean id="authenticationFailureHandler" class="fr.gouv.travail.consultationAccords.server.auth.GAAuthenticationFailureHandler"/>
<!-- ================================================== -->
<!-- ********************************* -->
<!-- ================================================== -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref='ldapAuthProvider' />
</security:authentication-manager>
<!-- ================================================== -->
<!-- CONNEXION AU LDAP -->
<!-- ================================================== -->
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://${ldap.server_ip}:${ldap.server_port}"/>
<property name="userDn" value="${ldap.user_reader_account}" />
<property name="password" value="${ldap.password_reader_account}" />
</bean>
<!-- ================================================== -->
<!-- AUTHENTIFICATION + AUTORISATION -->
<!-- ================================================== -->
<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="userSearch">
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="${ldap.user_base_search}"/>
<constructor-arg index="1" value="(uid={0}@${ldap.domain_name})"/>
<constructor-arg index="2" ref="contextSource" />
</bean>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="${ldap.group_base_search}" />
<property name="groupSearchFilter" value="(uniqueMember={0})"/>
<property name="rolePrefix" value="ROLE_"/>
<property name="searchSubtree" value="true"/>
<property name="convertToUpperCase" value="true"/>
<property name="groupRoleAttribute" value="${ldap.group_role_attribute}"/>
</bean>
</constructor-arg>
</bean>
Можно ли добиться такой вещи? Если да, можете ли вы помочь мне решить эту проблему?
Большое спасибо!
1 ответ
Сначала вам нужно определить свой собственный фильтр
package com.example;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.*;
import java.io.IOException;
public class CustomAuthFilter implements Filter {
private AuthenticationManager authenticationManager;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String username = servletRequest.getParameter("username");
String password = servletRequest.getParameter("password");
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
Authentication successfulAuthentication;
try {
successfulAuthentication = authenticationManager.authenticate(authRequest);
} catch (Exception exception) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
}
Определите этот фильтр как весенний боб
<bean id="customFilter" class="com.example.CustomAuthFilter">
<property name="authenticationManager" ref="authenticationManager" />
<bean>
Добавьте этот фильтр в цепочку фильтров безопасности весны
<security:http ...>
<custom-filter ref="customFilter" position="PRE_AUTH_FILTER" />
</security:http>