1

spring webflow 2 と spring ldap によるユーザー認証でログインサーブレットを実現しました。これまでのところ、すべて問題ありません。

今、ログインフローに春のセキュリティを導入しようとしています。そのため、Spring Web フロー リファレンス ガイド バージョン 2.4.0 (セクション 8) と Spring セキュリティ LDAP セクション ガイドに従って、構成を調整してフローを保護します。特に、ROLE_USERS ユーザーのみの成功ログイン ページを保護しようとしています。

私が試みたのは、ldap データベースからユーザー名、パスワード、およびユーザーの役割を抽出し、これらの情報を使用してフローにセキュリティを適用することです。そのため、プロジェクトに次の変更を加えます。

  1. loginflow.xml のdisplayLoginSuccessViewビューステートにsecure属性を追加

    <?xml version="1.0" encoding="UTF-8"?>
    <flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
    http://www.springframework.org/schema/webflow/spring-webflow-2.4.xsd">
    
    <var name="loginCredentials" class="com.folkture.login.LoginCredentials"/>
    
    <view-state id="displayLoginView" view="/WEB-INF/views/display_login.jsp" model="loginCredentials">
    <transition on="loginCredentialsEntered" to="performLoginAction"/>
    </view-state>
    
    <action-state id="performLoginAction">
    
    <evaluate expression="loginService.performLogin(loginCredentials)"/>
    
    <transition to="displayLoginSuccessView"/>
    
    <transition on-exception="com.folkture.login.IncorrectLoginCredentialsException"     to="displayLoginErrorView"/>
    </action-state>
    
    <view-state id="displayLoginSuccessView" view="/WEB-INF/views/display_login_success.jsp">
    <secured attributes="ROLE_USER" />
    </view-state>
    
    <view-state id="displayLoginErrorView" view="/WEB-INF/views/display_login_error.jsp"/>
    
    </flow>
    
  2. Bean SecurityFlowExecutionListenerwebflow-config.xmlに追加します

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:webflow="http://www.springframework.org/schema/webflow-config"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow-config
    http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.4.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    
    <webflow:flow-executor id="loginFlowExecutor"
        flow-registry="loginFlowRegistry">
        <webflow:flow-execution-listeners>
            <webflow:listener ref="sfel" />
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>
    <webflow:flow-registry id="loginFlowRegistry">
        <!-- Define the flow executor responsible for executing login web flow -->
        <webflow:flow-location id="loginFlow"
            path="/WEB-INF/flows/login-flow.xml" />
    </webflow:flow-registry>
    
    <!-- Installs a listener to apply Spring Security authorities -->
    <bean id="sfel"
        class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
    

  3. springSecurityFilterChainweb.xmlに追加します

  4. spring-config.xmlに春のセキュリティ構成を追加する

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:ldap="http://www.springframework.org/schema/ldap"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/ldap             
    http://www.springframework.org/schema/ldap/spring-ldap.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
    <context:property-placeholder location="classpath:/ldap.properties"
        system-properties-mode="OVERRIDE" />
    <context:annotation-config />
    
    <ldap:context-source id="contextSource" url="${sample.ldap.url}"
        base="${sample.ldap.base}" authentication-source-ref="springSecurityAuthenticationSource" />
    
    <ldap:ldap-template id="ldapTemplate"
        context-source-ref="contextSource" />
    
    <bean id="loginService" class="com.folkture.login.LoginService">
        <property name="ldapTemplate" ref="ldapTemplate" />
    </bean>
    
    <bean id="springSecurityAuthenticationSource"
        class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />
    
    <security:http auto-config="true">
        <security:intercept-url pattern="/**" access="ROLE_USER" />
        <security:form-login login-page="/views/display_login.jsp" />
    </security:http>
    
    <security:authentication-manager>
        <security:ldap-authentication-provider
            user-search-filter="(cn={0})" user-search-base="ou=users"
            group-search-filter="(member={0})" group-search-base="ou=Groups"
            group-role-attribute="cn" />
    </security:authentication-manager> 
    
    <security:ldap-server url="ldap://localhost:389" manager-dn="${sample.ldap.userDn}" 
        manager-password="${sample.ldap.password}" />
    

  5. そして、これはログインメソッドLoginService.javaを持つ私のJavaクラスです

    package com.folkture.login;
    
    import javax.naming.directory.DirContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.ldap.NamingException;
    import org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback;
    import org.springframework.ldap.core.DirContextOperations;
    import org.springframework.ldap.core.LdapEntryIdentification;
    import org.springframework.ldap.core.LdapTemplate;
    import org.springframework.ldap.filter.AndFilter;
    import org.springframework.ldap.filter.EqualsFilter;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.ldap.authentication.LdapAuthenticator;
    import org.springframework.stereotype.Service;
    
    @Service
    public class LoginService implements LdapAuthenticator{
    @Autowired
    private LdapTemplate ldapTemplate;
    
    public LoginService() {
        super();
    }
    
    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
        System.out.println("setLdapTemplate "+ ldapTemplate);
    }
    
    public String performLogin(LoginCredentials loginCredentials) throws Exception{
    
        if(login(loginCredentials.getLoginName(),loginCredentials.getPassword())) 
    
        {
            System.out.println("autenticato!");
            return "success";
        } else {
            throw new IncorrectLoginCredentialsException();
        }
    }
    
    public boolean login(String username, String password) throws Exception{
    
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectclass", "inetOrgPerson")).and(new EqualsFilter("cn", username));
    
        if(ldapTemplate.authenticate("ou=users", filter.toString(), password, contextCallback))
            return true;
        return false;
    
    }
    
    AuthenticatedLdapEntryContextCallback contextCallback = new AuthenticatedLdapEntryContextCallback() {
        @SuppressWarnings("deprecation")
        public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
            try {
                try {
                    ctx.lookup(ldapEntryIdentification.getRelativeDn());
                } catch (javax.naming.NamingException e) {
                    e.printStackTrace();
                }
            }
            catch (NamingException e) {
                throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeDn(), e);
            }
        }
    };
    
    @Override
    public DirContextOperations authenticate(Authentication authentication) {
        // TODO Auto-generated method stub
        return null;
        }
    }
    

ユーザー名とパスワードを入力すると、次のエラーが表示されます。

HTTP Status 500 - Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'performLoginAction' of flow 'loginFlow'
________________________________________
type Exception report   
message Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'performLoginAction' of flow 'loginFlow'
description The server encountered an internal error that prevented it from fulfilling this request.
exception 
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'performLoginAction' of flow 'loginFlow'
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
root cause 
org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'performLoginAction' of flow 'loginFlow'
    org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:573)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:263)
    org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
    org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
root cause 
java.lang.NullPointerException
    org.springframework.security.access.vote.RoleVoter.extractAuthorities(RoleVoter.java:115)
    org.springframework.security.access.vote.RoleVoter.vote(RoleVoter.java:96)
    org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
    org.springframework.webflow.security.SecurityFlowExecutionListener.decide(SecurityFlowExecutionListener.java:109)
    org.springframework.webflow.security.SecurityFlowExecutionListener.stateEntering(SecurityFlowExecutionListener.java:74)
    org.springframework.webflow.engine.impl.FlowExecutionListeners.fireStateEntering(FlowExecutionListeners.java:144)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.setCurrentState(FlowExecutionImpl.java:373)
    org.springframework.webflow.engine.impl.RequestControlContextImpl.setCurrentState(RequestControlContextImpl.java:189)
    org.springframework.webflow.engine.State.enter(State.java:191)
    org.springframework.webflow.engine.Transition.execute(Transition.java:228)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:395)
    org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214)
    org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:116)
    org.springframework.webflow.engine.Flow.handleEvent(Flow.java:547)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:390)
    org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
    org.springframework.webflow.engine.ActionState.doEnter(ActionState.java:105)
    org.springframework.webflow.engine.State.enter(State.java:194)
    org.springframework.webflow.engine.Transition.execute(Transition.java:228)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:395)
    org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214)
    org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:116)
    org.springframework.webflow.engine.Flow.handleEvent(Flow.java:547)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:390)
    org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
    org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:231)
    org.springframework.webflow.engine.ViewState.resume(ViewState.java:195)
    org.springframework.webflow.engine.Flow.resume(Flow.java:537)
    org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
    org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
    org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)

spring-config.xml の認証プロバイダーの設定が、認証と認可の Java クラスと適切に一致していないと思います。LDAP からロールを正常に取得するにはどうすればよいですか?

4

1 に答える 1