Двойная аутентификация с пружинной безопасностью (с помощью формы входа и запроса)

В настоящее время я работаю над проектом, включающим 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>

Вот что я сделал:

  1. Объявлен и настроен bean-компонент, который представляет собой UsernamePasswordAuthenticationFilter (с обработчиком успеха, обработчиком ошибок, менеджером аутентификации, usernameParameter и passwordParameter)

  2. Добавил его в тег security-http + настройка позиции FIRST

  3. мой 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>
Другие вопросы по тегам