webentwicklung-frage-antwort-db.com.de

Konfigurieren von Spring Security 3.x für mehrere Einstiegspunkte

Ich habe Spring Security 3.x verwendet, um die Benutzerauthentifizierung für meine Projekte durchzuführen. Bisher hat es einwandfrei funktioniert.

Ich habe kürzlich die Voraussetzungen für ein neues Projekt erhalten. In diesem Projekt sind zwei Gruppen von Benutzerauthentifizierungen erforderlich: Einer für die Authentifizierung der Mitarbeiter gegenüber LDAP und der andere für die Authentifizierung des Kunden gegenüber der Datenbank. Ich bin etwas ratlos, wie man das in Spring Security konfiguriert.

Meine ursprüngliche Idee war es, einen Anmeldebildschirm zu erstellen, der die folgenden Felder enthält: -

  • optionsfeld - Benutzer können wählen, ob sie Mitarbeiter oder Kunden sind.
  • j_username Benutzerfeld.
  • j_password Kennwortfeld.

Wenn der Benutzer "Mitarbeiter" auswählt, möchte ich, dass Spring Security sie anhand von LDAP authentifiziert. Andernfalls werden die Anmeldeinformationen anhand der Datenbank authentifiziert. Das Problem ist jedoch, dass das Formular an /j_spring_security_check gesendet wird, und ich kann das Optionsfeld nicht an meinen implementierten benutzerdefinierten Authentifizierungsanbieter senden. Mein erster Gedanke ist, dass ich wahrscheinlich zwei Formularübermittlungs-URLs brauche, anstatt mich auf den Standardcode /j_spring_security_check zu verlassen. Jede URL wird von verschiedenen Authentifizierungsanbietern verarbeitet, aber ich bin nicht sicher, wie sie in Spring Security konfiguriert werden soll.

Ich weiß, dass ich in Spring Security die Fall-Back-Authentifizierung konfigurieren kann. Wenn beispielsweise die LDAP-Authentifizierung fehlschlägt, wird auf die Datenbankauthentifizierung zurückgegriffen. Dies ist jedoch nicht das, was ich in diesem neuen Projekt suche. 

Kann jemand mitteilen, wie genau ich dies in Spring Security 3.x konfigurieren sollte?

Vielen Dank.


UPDATE - 28.01.2011 - @ EasyAngels Technik

Ich versuche folgendes zu tun: -

  • Anmeldung des Mitarbeiterformulars an /j_spring_security_check_for_employee
  • Anmeldung des Kundenformulars an /j_spring_security_check_for_customer

Ich möchte zwei verschiedene Formularanmeldungen haben, da ich die Authentifizierung je nach Benutzer unterschiedlich behandeln kann, anstatt eine Fall-Back-Authentifizierung durchzuführen. In meinem Fall haben Mitarbeiter und Kunde möglicherweise dieselbe Benutzer-ID.

Ich habe die Idee von @ EasyAngel übernommen, muss aber einige veraltete Klassen ersetzen. Das Problem, mit dem ich aktuell konfrontiert bin, ist, dass beide Filterprozesse nicht in Spring Security registriert sind, da ich Error 404: SRVE0190E: File not found: /j_spring_security_check_for_employee bekomme. Mein Bauchgefühl ist, dass die springSecurityFilterChain-Bean nicht richtig verdrahtet ist, daher werden meine benutzerdefinierten Filter überhaupt nicht verwendet.

Übrigens verwende ich WebSphere und habe die com.ibm.ws.webcontainer.invokefilterscompatibility=true-Eigenschaft auf dem Server festgelegt. Ich kann den Standardcode /j_spring_security_check ohne Probleme erreichen.

Hier ist meine vollständige Sicherheitskonfiguration: -

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

Ich fange hier mit einer Kopfprämie an, weil ich das scheinbar nicht für mehrere Tage schaffen kann ... Frustration ist das Wort. Ich hoffe, dass jemand auf die Probleme aufmerksam macht oder ob Sie mir einen besseren oder saubereren Weg zeigen können, um damit umzugehen (im Code). 

Ich verwende Spring Security 3.x. 

Vielen Dank.


UPDATE 29.01.2011 - @ Ritesh-Technik

Okay, ich habe es geschafft, @ Ritesh's Ansatz so zu gestalten, dass ich genau auf meine Wünsche eingehen konnte. Ich habe den Radiobutton, mit dem der Benutzer auswählen kann, ob er Kunde oder Mitarbeiter ist. Es scheint, dass dieser Ansatz ziemlich gut funktioniert, mit einem Problem ... 

  • Wenn sich der Mitarbeiter mit dem richtigen Berechtigungsnachweis anmeldet, ist er in ... ARBEITET WIE ERWARTET erlaubt.
  • Wenn sich ein Mitarbeiter mit einem falschen Berechtigungsnachweis anmeldet, ist er nicht in ... ARBEITET WIE ERWARTET .
  • Wenn sich der Kunde mit dem richtigen Berechtigungsnachweis anmeldet, ist er in ... ARBEIT WIE ERWARTET erlaubt.
  • Wenn sich der Kunde mit einem falschen Berechtigungsnachweis anmeldet, greift die Authentifizierung auf die Mitarbeiterauthentifizierung zurück ... FUNKTIONIERT NICHT . Dies ist riskant, da ich, wenn ich die Kundenauthentifizierung auswähle und den Mitarbeiterausweis stelle, auch den Benutzer zulässt, und dies ist nicht das, was ich will.
    <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>

Hier ist meine aktualisierte Konfiguration. Es muss ein wirklich kleiner Tweak sein, den ich machen muss, um zu verhindern, dass die Authentifizierung zurückfällt, aber ich scheine es jetzt nicht zu verstehen. 

Vielen Dank.

UPDATE - LÖSUNG für @ Ritesh-Technik

Okay, ich glaube, ich habe das Problem hier gelöst. Anstatt EmployeeCustomAuthenticationProvider auf den Standard UsernamePasswordAuthenticationToken zurückgreifen zu müssen, habe ich EmployeeUsernamePasswordAuthenticationToken erstellt, genau wie der, den ich CustomerUsernamePasswordAuthenticationToken für CustomerCustomAuthenticationProvider erstellt habe. Diese Anbieter überschreiben dann die supports(): -

CustomerCustomAuthenticationProvider-Klasse

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

EmployeeCustomAuthenticationProvider-Klasse

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

MyAuthenticationFilter-Klasse

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

... und WALAA! Nach einigen Tagen der Frustration funktioniert es jetzt perfekt! 

Hoffentlich kann dieser Beitrag jemandem helfen, der dasselbe tut wie ich hier.

60
limc

Sie müssen nicht /j_spring_security_check_for_employee und /j_security_check_for_customerfilterProcessingUrl erstellen. 

Die Standardeinstellung funktioniert gut mit der Radio Button-Idee.

Im benutzerdefinierten Login LoginFilter müssen Sie unterschiedliche Token für Mitarbeiter und Kunden erstellen.

Hier sind die Schritte:

  1. Verwenden Sie die Standardeinstellung UsernamePasswordAuthenticationToken für die Mitarbeiteranmeldung.

  2. Erstellen Sie CustomerAuthenticationToken für die Kundenanmeldung. Erweitern Sie AbstractAuthenticationToken, sodass sich der Klassentyp von UsernamePasswordAuthenticationToken unterscheidet.

  3. Definieren Sie einen benutzerdefinierten Anmeldefilter:

    <security:http>
        <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" />
    </security:http>
    
  4. Überschreiben Sie customFormLoginFilter in attemptAuthentication wie folgt (Pseudocode):

    if (radiobutton_param value employee) {
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        setDetails(whatever);
        return getAuthenticationManager().authenticate(authRequest);
    } else if (radiobutton_param value customer) {
        CustomerAuthenticationToken authRequest = new CustomerAuthenticationToken(username, password);
        setDetails(whatever);
        return getAuthenticationManager().authenticate(authRequest);
    }
    
  5. Überschreiben Sie die supports-Methode in EmployeeCustomAuthenticationProvider, um UsernamePasswordAuthenticationToken zu unterstützen.

  6. Überschreiben Sie die supports-Methode in CustomerCustomAuthenticationProvider, um CustomerAuthenticationToken zu unterstützen.

    @Override
    public boolean supports(Class<?> authentication) {
        return (CustomerAuthenticationToken.class.isAssignableFrom(authentication));
    }
    
  7. Verwenden Sie beide Provider in authentication-manager:

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref='employeeCustomAuthenticationProvider ' />
        <security:authentication-provider ref='customerCustomAuthenticationProvider ' />
    </security:authentication-manager>
    
23
Ritesh

Sie können mehrere AuthenticationProcessingFilter-Filter definieren. Jede von ihnen kann eine andere URL haben, wie/j_security_check_for_employee und/j_security_check_for_customer . Hier ist ein Beispiel für den Sicherheitsanwendungskontext, der diese Idee veranschaulicht:

<bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy">
     <security:filter-chain-map pathType="ant">
         <security:filter-chain pattern="/**" filters="authenticationProcessingFilterForCustomer, authenticationProcessingFilterForEmployee, ..." />
     </security:filter-chain-map>
</bean>


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

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

<bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager">
    <property name="providers">
        <list>
            <bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
                <property name="userDetailsService">
                    <ref bean="customerUserDetailsServiceThatUsesDB"/>
                </property>
            </bean>
        </list>
    </property>
</bean>

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

Wie Sie sehen, haben Sie in diesem Szenario auch unterschiedliche UserDetailServices - für DB-Authentifizierung und LDAP. 

Ich denke, es ist eine gute Idee, unterschiedliche Authentifizierungs-URLs für Kunden und Mitarbeiter zu haben (insbesondere, wenn andere Authentifizierungsstrategien verwendet werden). Sie können sogar unterschiedliche Anmeldeseiten dafür haben.

4
tenshi

ich bin es wieder :) Kannst du versuchen, Filter wie folgt zu verwenden:

<sec:http auto-config="true">
    ...
    <sec:custom-filter ref="authenticationProcessingFilterForCustomer" after="FIRST"/>
    <sec:custom-filter ref="authenticationProcessingFilterForEmployee" after="FIRST"/>
</sec:http>

anstatt Bean springSecurityFilterChain zu definieren.

0
tenshi

Sie können diese Informationen in der DB speichern. Sie können beispielsweise eine Spalte mit dem Namen ldap_auth in der Tabelle Users haben. Sie können sich meine andere Antwort (als Beispiel) ansehen:

Beispiel für ein Anmeldeformular für Spring

Wenn Sie sich die Klasse UserService genau ansehen, werden Sie feststellen, dass ich dieses LDAP-Flag tatsächlich teste und das Benutzerkennwort entweder aus LDAP oder aus der Datenbank nehme.

0
tenshi