Spring Security - Ошибка: запрещенный ответ от конечной точки отдыха

Я настраиваю Spring Security в своем проекте, и у меня возникают проблемы с доступом к одной из моих конечных точек отдыха. Я получаю ответ «Ошибка: Запрещено» от сервера, когда я попадаю в конечную точку через своего клиента.

Что я делаю, так это иду на страницу входа (я предполагаю, что на данный момент я анонимный пользователь с ROLE_ANONYMOUS) и щелкаю вкладку, которая показывает мне форму создания новой учетной записи.

Когда я заполняю поля и нажимаю «Отправить», вызывается остальная конечная точка, и данные JSON отправляются на сервер. В моей конфигурации безопасности я разместил ниже URL-адрес конечной точки, который я использую, /createUserAccount/submit, настроен на работу с ролями ROLE_ANONYMOUS и ROLE_ADMIN в XML-компоненте filterSecurityInterceptor.

Поскольку я анонимный пользователь на странице входа, я думал, что попадание в эту конечную точку сработает, но это не так. Все файлы, относящиеся к моей проблеме, находятся ниже.

Вот мой контроллер:

@Controller
@RequestMapping("/createUserAccount")
@SessionAttributes("userAccount")
public class CreateUserAccountController {
    private final String loginViewName = "login";
    private CreateUserAccountValidator validator;
    private UserAccountManager userAccountManager;

    @Autowired
    public CreateUserAccountController(
            @Qualifier("createUserAccountValidator") CreateUserAccountValidator validator,
            @Qualifier("userAccountManager") UserAccountManager userAccountManager) {
        this.validator = validator;
        this.userAccountManager = userAccountManager;
    }

    @RequestMapping(value="/submit", method = RequestMethod.POST)
    @ResponseBody
    public GenericJsonDTO submitForm(@RequestBody UserAccount userAccount, BindingResult result, SessionStatus status){
        JsonFactory jsonFactory = new JsonFactory(result, "/gravytrack/dashboard");
        validator.validate(userAccount, result);

        if(!result.hasErrors()) {
            userAccountManager.createUserAccount(userAccount);
            status.setComplete();
        }
        return jsonFactory.getDto();
    }
}

У меня есть настройка сервера, поэтому я могу отлаживать во время выполнения, я ставлю точку останова в строке

JsonFactory jsonFactory = new JsonFactory(result, "/gravytrack/dashboard");

чтобы увидеть, была ли когда-либо введена функция при вызове конечной точки /createUserAccount/submit. Функция никогда не вводится.

Ниже приведена моя конфигурация безопасности. Я начал внедрять безопасность ACL, поэтому файл конфигурации довольно длинный. Я думаю, что проблема либо в http element, либо в filterSecurityInterceptor конфигурации bean-компонента xml. filterSecurityInterceptor XML — это место, где определяются мои разрешения URI.

<global-method-security pre-post-annotations="enabled"
                            secured-annotations="enabled">
        <expression-handler ref="expressionHandler" />
    </global-method-security>

    <http use-expressions="true">
        <intercept-url pattern="/**" requires-channel="https" />
        <!--<intercept-url pattern="/gravytrack/dashboard**" requires-channel="https" access="ROLE_USER"/>-->
        <http-basic />
        <session-management>
            <concurrency-control max-sessions="10"
                                 error-if-maximum-exceeded="true" />
        </session-management>
        <anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
    </http>

    <beans:bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder" />

    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <password-encoder ref="passwordEncoder"/>
            <jdbc-user-service data-source-ref="dataSource"
                users-by-username-query="SELECT email, password, enabled FROM user_account
                                            WHERE email = ?" />

        </authentication-provider>
    </authentication-manager>

    <beans:bean id="springSecurityFilterChain"
                class="org.springframework.security.web.FilterChainProxy">
        <beans:constructor-arg>
            <util:list>
                <filter-chain pattern="/images/**" filters="" />
                <filter-chain pattern="/**"
                              filters="securityContextPersistenceFilterWithASCFalse,
                                   basicAuthenticationFilter,
                                   basicExceptionTranslationFilter,
                                   filterSecurityInterceptor" />
            </util:list>
        </beans:constructor-arg>
    </beans:bean>
    <beans:bean id="securityContextPersistenceFilterWithASCFalse"
                class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    </beans:bean>

    <beans:bean id="securityContextPersistenceFilterWithASCTrue"
                class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    </beans:bean>

    <!--......................-->
    <!-- basic authentication -->
    <!--......................-->
    <beans:bean id="basicAuthenticationFilter"
                class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
        <beans:constructor-arg name="authenticationManager">
            <beans:ref bean="authenticationManager" />
        </beans:constructor-arg>
        <beans:constructor-arg name="authenticationEntryPoint">
            <beans:ref bean="basicAuthenticationEntryPoint" />
        </beans:constructor-arg>
    </beans:bean>
    <beans:bean id="basicAuthenticationEntryPoint"
                class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
        <beans:property name="realmName" value="gravytrack.com" />
    </beans:bean>

    <beans:bean id="basicExceptionTranslationFilter"
                class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <beans:constructor-arg name="authenticationEntryPoint" ref="basicAuthenticationEntryPoint" />
        <beans:property name="accessDeniedHandler" ref="basicAccessDeniedHandler" />
    </beans:bean>

    <beans:bean id="basicAccessDeniedHandler"
                class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
    </beans:bean>

    <!--......................-->
    <!--       security       -->
    <!--......................-->
    <beans:bean id="filterSecurityInterceptor"
                class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">

        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="accessDecisionManager" ref="accessDecisionManager" />

        <beans:property name="securityMetadataSource">
            <filter-security-metadata-source use-expressions="false">
                <intercept-url pattern="/login.jsp*"
                               access="ROLE_ANONYMOUS,ROLE_ADMIN" />
                <intercept-url pattern="/gravytrack/createUserAccount/*"
                               access="ROLE_ANONYMOUS,ROLE_ADMIN" />
                <intercept-url pattern="/images/**"
                               access="ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN" />
                <intercept-url pattern="/admin.htm*" access="ROLE_ADMIN" />
                <intercept-url pattern="/**"
                               access="ROLE_USER,ROLE_ADMIN" />
            </filter-security-metadata-source>
        </beans:property>

    </beans:bean>

    <beans:bean id="accessDecisionManager"
                class="org.springframework.security.access.vote.AffirmativeBased">
        <beans:constructor-arg name="decisionVoters">
            <beans:list>
                <beans:bean class="org.springframework.security.access.vote.RoleVoter" />
                <beans:bean
                        class="org.springframework.security.access.vote.AuthenticatedVoter" />
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>


    <beans:bean id="expressionHandler"
                class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
        <beans:property name="permissionEvaluator" ref="permissionEvaluator" />
    </beans:bean>

    <beans:bean id="permissionEvaluator"
                class="org.springframework.security.acls.AclPermissionEvaluator">
        <beans:constructor-arg ref="aclService" />
    </beans:bean>

    <beans:bean id="aclService"
                class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
        <beans:constructor-arg ref="dataSource" />
        <beans:constructor-arg ref="lookupStrategy" />
        <beans:constructor-arg ref="aclCache" />
        <beans:property name="sidIdentityQuery"
                        value="SELECT max(id) FROM acl_sid" />
        <beans:property name="classIdentityQuery"
                        value="SELECT max(id) FROM acl_class" />
        <!--
        <beans:property name="sidIdentityQuery"
            value="select currval(pg_get_serial_sequence('acl_sid', 'id'))" />
        <beans:property name="classIdentityQuery"
            value="select currval(pg_get_serial_sequence('acl_class', 'id'))" />
        -->
    </beans:bean>

    <beans:bean id="consoleAuditLogger" class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>

    <beans:bean id="lookupStrategy"
                class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
        <beans:constructor-arg ref="dataSource" />
        <beans:constructor-arg ref="aclCache" />
        <beans:constructor-arg ref="aclAuthorizationStrategy" />
        <beans:constructor-arg ref="consoleAuditLogger"/>
    </beans:bean>

    <beans:bean id="aclAuthorizationStrategy"
            class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
        <beans:constructor-arg>
            <beans:list>
                <beans:bean
                        class="org.springframework.security.core.authority.SimpleGrantedAuthority">
                    <beans:constructor-arg value="ROLE_ADMIN" />
                </beans:bean>
                <beans:bean
                        class="org.springframework.security.core.authority.SimpleGrantedAuthority">
                    <beans:constructor-arg value="ROLE_ADMIN" />
                </beans:bean>
                <beans:bean
                        class="org.springframework.security.core.authority.SimpleGrantedAuthority">
                    <beans:constructor-arg value="ROLE_ADMIN" />
                </beans:bean>
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
        <beans:constructor-arg ref="consoleAuditLogger"/>
    </beans:bean>


    <beans:bean id="aclCache"
                class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
        <beans:constructor-arg>
            <beans:bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
                <beans:property name="cacheManager">
                    <beans:bean
                            class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
                </beans:property>
                <beans:property name="cacheName" value="aclCache" />
            </beans:bean>
        </beans:constructor-arg>
        <beans:constructor-arg ref="permissionGrantingStrategy" />
        <beans:constructor-arg ref="aclAuthorizationStrategy" />
    </beans:bean>


</beans:beans>

И последнее, но не менее важное: вот мой web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <!-- Log4j configuration loading -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/classes/log4j.xml</param-value>
    </context-param>
    <!-- Bootstrapping context loading -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/gravytrack-servlet.xml
            /WEB-INF/gravytrack-services.xml
            /WEB-INF/gravytrack-security.xml
           </param-value>
    </context-param>
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>gravytrack.root</param-value>
    </context-param>

    <!-- session management listener -->
    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>
    <session-config>
        <!-- session times out if no activities for 30 minutes -->
        <session-timeout>30</session-timeout>
    </session-config>


    <!-- defining the DispatcherServlet -->
    <servlet>
        <servlet-name>gravytrack</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>gravytrack</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>gravytrack</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <!--<servlet-mapping>-->
        <!--<servlet-name>gravytrack</servlet-name>-->
        <!--<url-pattern>*.html</url-pattern>-->
    <!--</servlet-mapping>-->

    <!-- Security entry point -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- webflow -->
    <!--
<servlet-mapping>
        <servlet-name>soba</servlet-name>
        <url-pattern>/flow/*</url-pattern>
    </servlet-mapping>
 -->
<!-- defining the DefaultServlet -->
<servlet>
        <servlet-name>DefaultServlet</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DefaultServlet</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>DefaultServlet</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <error-page>
        <error-code>404</error-code>
        <location>/WEB-INF/jsp/notfound.jsp</location>
    </error-page>
    <welcome-file-list>
        <welcome-file>
      login.jsp
    </welcome-file>
    </welcome-file-list>
    <!-- Spring jsp tag lib -->
    <jsp-config>
        <taglib>
            <taglib-uri>/spring</taglib-uri>
            <taglib-location>/WEB-INF/tld/spring-form.tld</taglib-location>
        </taglib>
    </jsp-config>

</web-app>

Мне трудно понять, что не так, поэтому любая помощь очень ценится.


person Graham    schedule 01.09.2015    source источник


Ответы (1)


По умолчанию безопасность Spring включает CSRF и каждый запрос POST, поскольку он ожидает токен csrf. Проверьте Spring. Документация по CSRF..

Вы можете отключить CSRF таким образом в своей конфигурации, чтобы уже проверить, является ли это проблемой.

<http auto-config="false">
        <csrf disabled="true"/> 

если вы не хотите отключать CSRF, вы должны POST токены csrf, как это

<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
  <input type="submit" value="Log out" />
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
person Anudeep Gade    schedule 01.09.2015