具有spring security的双重身份验证(具有表单登录和请求)

时间:2014-07-30 12:19:56

标签: java spring authentication spring-security spring-ldap

我目前正在开发一个涉及GWT 2.5 + Spring 3.1 + Hibernate 3.10的项目。

Web应用程序目前正在生产中并且具有受保护的资源。 为了安全起见,我们使用带有LDAP身份验证的Spring security 3.1。

我们目前有一个表单登录,我们填写用户名和密码并重定向到适当的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

  4. 我修改了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"/>
    <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 个答案:

答案 0 :(得分:0)

首先,您需要定义自定义过滤器

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;
    }
}

将此过滤器定义为spring bean

<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>