Configurando o Spring Security 3.x para ter vários pontos de entrada

Eu tenho usado o Spring Security 3.x para manipular a autenticação do usuário para meus projetos e, até agora, funcionou perfeitamente.

Recentemente, recebi os requisitos para um novo projeto. Neste projeto, são necessários 2 conjuntos de autenticação de usuário: um para autenticar funcionários no LDAP e outro para autenticar o cliente no banco de dados. Estou um pouco confuso sobre como configurar isso no Spring Security.

Minha ideia inicial foi criar uma tela de login com os seguintes campos: -

campo do botão de opção - para que os usuários escolham se são funcionários ou clientes.j_username Campo do usuário.j_password campo de senha.

Se o usuário selecionar "empregado", desejo que o Spring Security os autentique no LDAP, caso contrário, a credencial será autenticada no banco de dados. No entanto, o problema é que o formulário será enviado para/j_spring_security_check e não há como enviar o campo do botão de opção ao meu provedor de autenticação personalizado implementado. Meu pensamento inicial é que provavelmente preciso de dois URLs de envio de formulários, em vez de confiar no padrão/j_spring_security_check. Cada URL será tratada por diferentes provedores de autenticação, mas não sei como configurá-lo no Spring Security.

Eu sei que no Spring Security, posso configurar a autenticação de fallback, por exemplo, se a autenticação LDAP falhar, ela voltará para a autenticação do banco de dados, mas não é para isso que estou procurando neste novo projeto.

Alguém pode compartilhar como exatamente eu devo configurar isso no Spring Security 3.x?

Obrigado.

ATUALIZAÇÃO - 28-01-2011 - técnica do @ EasyAngel

Estou tentando fazer o seguinte: -

O login do formulário do funcionário envia para/j_spring_security_check_for_employeeO login do formulário do cliente envia para/j_spring_security_check_for_customer

A razão pela qual eu quero dois logins de formulário diferentes é permitir que eu manipule a autenticação de maneira diferente com base no usuário, em vez de fazer uma autenticação de fallback. É possível que funcionário e cliente tenham o mesmo ID de usuário, no meu caso.

Incorporei a ideia do @ EasyAngel, mas tenho que substituir algumas classes obsoletas. O problema que estou enfrentando atualmente não é que os URLs dos processos de filtro parecem registrados no Spring Security porque eu continuo recebendoError 404: SRVE0190E: File not found: /j_spring_security_check_for_employee. Meu pressentimento é ospringSecurityFilterChain bean não está conectado corretamente, portanto, meus filtros personalizados não são usados.

A propósito, estou usando o WebSphere e tenhocom.ibm.ws.webcontainer.invokefilterscompatibility=true propriedade definida no servidor. Eu sou capaz de acertar o padrão/j_spring_security_check sem problema.

Aqui está minha configuração completa de segurança: -

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="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.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <sec:http auto-config="true">
        <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" default-target-url="/welcome.jsp"
            always-use-default-target="true" />
        <sec:logout logout-success-url="/login.jsp" />
        <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" />
        <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" />
        <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    </sec:http>

    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/**" filters="authenticationProcessingFilterForEmployee, authenticationProcessingFilterForCustomer" />
        </sec:filter-chain-map>
    </bean>

    <bean id="authenticationProcessingFilterForEmployee" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManagerForEmployee" />
        <property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" />
    </bean>

    <bean id="authenticationProcessingFilterForCustomer" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManagerForCustomer" />
        <property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" />
    </bean>

    <bean id="authenticationManagerForEmployee" class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <ref bean="employeeCustomAuthenticationProvider" />
            </list>
        </property>
    </bean>

    <bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <ref bean="customerCustomAuthenticationProvider" />
            </list>
        </property>
    </bean>

    <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider">
        <property name="userDetailsService">
            <bean class="ss.EmployeeUserDetailsService"/>
        </property>
    </bean>

    <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider">
        <property name="userDetailsService">
            <bean class="ss.CustomerUserDetailsService"/>
        </property>
    </bean>

    <sec:authentication-manager>
        <sec:authentication-provider ref="employeeCustomAuthenticationProvider" />
        <sec:authentication-provider ref="customerCustomAuthenticationProvider" />
    </sec:authentication-manager>

</beans>

Estou começando uma recompensa aqui porque parece que não consigo fazer isso funcionar há vários dias ... frustração é a palavra. Espero que alguém aponte o (s) problema (s) ou se você pode me mostrar uma maneira melhor ou mais limpa de lidar com isso (no código).

Estou usando o Spring Security 3.x.

Obrigado.

ATUALIZAÇÃO 29-01-2011 - técnica de @ Ritesh

Ok, consegui fazer com que a abordagem de @ Ritesh trabalhasse muito de perto do que eu queria. Eu tenho o botão de opção que permite ao usuário selecionar se é cliente ou funcionário. Parece que essa abordagem está funcionando muito bem, com um problema ...

Se o funcionário fizer logon com a credencial correta, ele poderá entrar em ...TRABALHO COMO ESPERADO.Se o funcionário efetuar login com credencial incorreta, ele não será permitido em ...TRABALHO COMO ESPERADO.Se o cliente efetuar login com credencial correta, ele será permitido em ...TRABALHO COMO ESPERADO.Se o cliente efetuar login com credencial incorreta, a autenticação voltará à autenticação do funcionário ...NÃO FUNCIONA. Isso é arriscado, porque se eu selecionar a autenticação do cliente e perfurar a credencial do funcionário, também permitirá que o usuário entre, e não é isso que eu quero.
    <sec:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
        <sec:logout logout-success-url="/login.jsp"/>
        <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE"/>
        <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER"/>
        <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

        <sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthenticationFilter"/>
    </sec:http>


    <bean id="myAuthenticationFilter" class="ss.MyAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationFailureHandler" ref="failureHandler"/>
        <property name="authenticationSuccessHandler" ref="successHandler"/>
    </bean>

    <bean id="loginUrlAuthenticationEntryPoint"
          class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <property name="loginFormUrl" value="/login.jsp"/>
    </bean>

    <bean id="successHandler"
          class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
        <property name="defaultTargetUrl" value="/welcome.jsp"/>
        <property name="alwaysUseDefaultTargetUrl" value="true"/>
    </bean>

    <bean id="failureHandler"
          class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/login.jsp?login_error=1"/>
    </bean>


    <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider">
        <property name="userDetailsService">
            <bean class="ss.EmployeeUserDetailsService"/>
        </property>
    </bean>

    <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider">
        <property name="userDetailsService">
            <bean class="ss.CustomerUserDetailsService"/>
        </property>
    </bean>


    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider ref="customerCustomAuthenticationProvider"/>
        <sec:authentication-provider ref="employeeCustomAuthenticationProvider"/>
    </sec:authentication-manager>
</beans>

Aqui está minha configuração atualizada. Tem que haver alguns ajustes realmente pequenos que eu preciso fazer para impedir que a autenticação caia, mas não consigo entender agora.

Obrigado.

UPDATE - SOLUÇÃO para a técnica de @ Ritesh

Ok, acho que resolvi o problema aqui. Em vez de terEmployeeCustomAuthenticationProvider confiar no padrãoUsernamePasswordAuthenticationToken, Eu crieiEmployeeUsernamePasswordAuthenticationToken por isso, assim como o que eu crieiCustomerUsernamePasswordAuthenticationToken paraCustomerCustomAuthenticationProvider. Esses provedores substituirão osupports(): -

Classe CustomerCustomAuthenticationProvider

@Override
public boolean supports(Class<? extends Object> authentication) {
    return (CustomerUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}

Classe EmployeeCustomAuthenticationProvider

@Override
public boolean supports(Class<? extends Object> authentication) {
    return (EmployeeUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}

Classe MyAuthenticationFilter

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

    ...

    UsernamePasswordAuthenticationToken authRequest = null;

    if ("customer".equals(request.getParameter("radioAuthenticationType"))) {
        authRequest = new CustomerUsernamePasswordAuthenticationToken(username, password);

    }
    else {
        authRequest = new EmployeeUsernamePasswordAuthenticationToken(username, password);
    }

    setDetails(request, authRequest);

    return super.getAuthenticationManager().authenticate(authRequest);
}

... e WALAA! Funciona perfeitamente agora após vários dias de frustração!

Felizmente, este post poderá ajudar alguém que está fazendo a mesma coisa que eu estou aqui.

questionAnswers(4)

yourAnswerToTheQuestion