Jakpren
Jakpren

Reputation: 91

In Broadleaf Project HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'

I trying to integrate Oauth2 Security in Broadleaf Commerce project for rest api call, It's working fine for web service. But when Login by web UI, it showing above error..

My product web.xml dependencies

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>

    <dependency>  
       <groupId>org.springframework.security.oauth</groupId>  
       <artifactId>spring-security-oauth2</artifactId>  
       <version>1.0.0.RELEASE</version>  
   </dependency>
   <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.2.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.1.2.RELEASE</version>
    </dependency>

My applicationContext-rest-api.xml is

<context:component-scan
    base-package="org.broadleafcommerce.core.web.api, com.test.api" />

<!-- This is default url to get a token from OAuth -->
<http pattern="/oauth/token" create-session="stateless"
    authentication-manager-ref="blAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <intercept-url pattern="/oauth/token" requires-channel="any" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <!-- include this only if you need to authenticate clients via request 
        parameters -->
    <custom-filter ref="clientCredentialsTokenEndpointFilter"
        after="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<!-- This is where we tells spring security what URL should be protected 
    and what roles have access to them -->
<http pattern="/api/v1/**" create-session="never"
    entry-point-ref="oauthAuthenticationEntryPoint"
    access-decision-manager-ref="accessDecisionManager"
    xmlns="http://www.springframework.org/schema/security">
    <anonymous enabled="false" />
    <intercept-url pattern="/api/v1/cart/**" requires-channel="http" />
    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<bean id="oauthAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="test" />
</bean>

<bean id="clientAuthenticationEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="test/client" />
    <property name="typeName" value="Basic" />
</bean>

<bean id="oauthAccessDeniedHandler"
    class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

<bean id="clientCredentialsTokenEndpointFilter"
    class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
    xmlns="http://www.springframework.org/schema/beans">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
            <bean class="org.springframework.security.access.vote.RoleVoter" />
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        </list>
    </constructor-arg>
</bean>

<authentication-manager id="clientAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>

<bean id="clientDetailsUserService"
    class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <constructor-arg ref="clientDetails" />
</bean>


<!-- This defined token store, we have used inmemory tokenstore for now 
    but this can be changed to a user defined one -->
<bean id="tokenStore"
    class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

<!-- This is where we defined token based configurations, token validity 
    and other things -->
<bean id="tokenServices"
    class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <property name="tokenStore" ref="tokenStore" />
    <property name="supportRefreshToken" value="true" />
    <property name="accessTokenValiditySeconds" value="120" />
    <property name="clientDetailsService" ref="clientDetails" />
</bean>

<bean id="userApprovalHandler"
    class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
    <property name="tokenServices" ref="tokenServices" />
</bean>


<!-- Used for REST api calls. This just takes in the passed in customerId 
    and uses it to establish the customer. -->
<!-- Additional considerations MUST be made for implementations that are 
    allowing external access to APIs. -->
<!-- <bean id="blRestCustomerStateFilter" class="org.broadleafcommerce.profile.web.core.security.RestApiCustomerStateFilter"/> -->

<oauth:authorization-server
    client-details-service-ref="clientDetails" token-services-ref="tokenServices"
    user-approval-handler-ref="userApprovalHandler">
    <oauth:authorization-code />
    <oauth:implicit />
    <oauth:refresh-token />
    <oauth:client-credentials />
    <oauth:password />
</oauth:authorization-server>

<oauth:resource-server id="resourceServerFilter"
    resource-id="test" token-services-ref="tokenServices" />

<oauth:client-details-service id="clientDetails">
    <!-- client -->

    <oauth:client client-id="restapp" authorized-grant-types="authorization_code,client_credentials" 
        authorities="ROLE_USER" scope="read,write,trust" secret="secret" />

    <oauth:client client-id="restapp"
        authorized-grant-types="password,authorization_code,refresh_token,implicit"
        secret="restapp" authorities="ROLE_USER" />   <!-- ,authorization_code,refresh_token,implicit -->

</oauth:client-details-service>

<sec:global-method-security
    pre-post-annotations="enabled" proxy-target-class="true">

    <sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>

<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />

Upvotes: 0

Views: 896

Answers (1)

phillipuniverse
phillipuniverse

Reputation: 2045

First of all, your dependencies are pretty weird. I'm not sure why you've specified your own versions of spring-beans etc. You could end up with Broadleaf dependency conflicts. Combine that with the fact that you have a 3.2 version of spring-web and a 4.2 version of spring-beans etc. These versions should match. Just these dependency configurations alone will set you up for weird, esoteric, hard to debug failures down the road.

To answer your question, Broadleaf has a CsrfFilter in place that requires all POST requests to include a _csrfToken in the form. This is done automatically with Thymeleaf by using the <blc:form> HTML tag as opposed to just <form>.

However, based on your specific error message it looks like you are running into the Spring Security CSRF filter not the Broadleaf one. See Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

Upvotes: 1

Related Questions