7

Everyone, I am aware that there is already a solution for similar kind of issue but this question is different.

I also read the link present, but the solution didn't apply to me.

My Question is that I am trying to secure my Java+Spring+Jersey webservice application using oauth2.0 and have been using spring-security-oauth2 library version.

Whenever I make a call to the /oauth/token the application verifies the details provided under the header( client_secret, client_id and grant_type), the client is successfully authenticated but token data is not returned from the server rather a 404 page not found response is shown.

here is the below configurations:

  1. web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        version="2.5">
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/spring/dispatcher-servlet.xml</param-value>
        </context-param>
    
        <servlet>
            <servlet-name>jersey-servlet</servlet-name>
            <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>com.tprivity.babycenter.ws</param-value>
            </init-param>
            <init-param>
                <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
                <param-value>true</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>jersey-servlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
        <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>
    </web-app>
    
  2. dispatcher-servlet.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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:security="http://www.springframework.org/schema/security"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
            http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
    
        <security:http pattern="/oauth/token" create-session="stateless"
            authentication-manager-ref="authenticationManager">
            <security:intercept-url pattern="/oauth/token"
                access="IS_AUTHENTICATED_FULLY" />
            <security:anonymous enabled="false" />
            <security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
            <security:custom-filter ref="clientCredentialsTokenEndpointFilter"
                before="BASIC_AUTH_FILTER" />
            <security:access-denied-handler ref="oauthAccessDeniedHandler" />
        </security:http>
    
        <security:http pattern="/ws/**" create-session="never"
            authentication-manager-ref="authenticationManager" entry-point-ref="oauthAuthenticationEntryPoint">
            <security:anonymous enabled="false" />
            <security:intercept-url pattern="/ws/**"
                method="GET" access="IS_AUTHENTICATED_FULLY" />
            <security:intercept-url pattern="/ws/**"
                method="POST" access="IS_AUTHENTICATED_FULLY" />
            <security:custom-filter ref="resourceServerFilter"
                before="PRE_AUTH_FILTER" />
            <security:access-denied-handler ref="oauthAccessDeniedHandler" />
        </security:http>
    
        <bean id="oauthAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        </bean>
    
        <bean id="clientAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="springsec/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="authenticationManager" />
        </bean>
    
        <security:authentication-manager alias="authenticationManager">
            <security:authentication-provider
                user-service-ref="clientDetailsUserService" />
        </security:authentication-manager>
    
        <bean id="clientDetailsUserService"
            class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
            <constructor-arg ref="clientDetails" />
        </bean>
    
        <bean id="clientDetails"
            class="org.springframework.security.oauth2.provider.client.JdbcClientDetailsService">
            <constructor-arg index="0">
                <ref bean="dataSource" />
            </constructor-arg>
        </bean>
    
        <security:authentication-manager id="userAuthenticationManager">
            <security:authentication-provider
                ref="customUserAuthenticationProvider" />
        </security:authentication-manager>
    
        <bean id="customUserAuthenticationProvider"
            class="com.tprivity.babycenter.ws.security.CustomUserAuthenticationProvider">
        </bean>
    
        <!-- Authorization Server Configuration of the server is used to provide 
            implementations of the client details service and token services and to enable 
            or disable certain aspects of the mechanism globally. -->
        <oauth2:authorization-server
            client-details-service-ref="clientDetails" token-services-ref="tokenServices"
            user-approval-handler-ref="userApprovalHandler">
            <oauth2:authorization-code />
            <oauth2:implicit />
            <oauth2:refresh-token />
            <oauth2:client-credentials />
            <oauth2:password authentication-manager-ref="userAuthenticationManager" />
        </oauth2:authorization-server>
    
        <oauth2:resource-server id="resourceServerFilter"
            resource-id="springsec" token-services-ref="tokenServices" />
    
        <bean id="tokenStore"
            class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
    
        <!-- Configure Authentication manager -->
        <bean id="passwordEncoder"
            class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
            <constructor-arg name="strength" value="11" />
        </bean>
    
        <!-- Grants access if only grant (or abstain) votes were received. We can 
            protect REST resource methods with JSR-250 annotations such as @RolesAllowed -->
        <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
            <property name="decisionVoters">
                <list>
                    <bean class="org.springframework.security.access.annotation.Jsr250Voter" />
                </list>
            </property>
        </bean>
    
        <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>
            <property name="clientDetailsService" ref="clientDetails" />
        </bean>
    
        <!-- A user approval handler that remembers approval decisions by consulting 
            existing tokens -->
        <bean id="oAuth2RequestFactory"
            class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
            <constructor-arg ref="clientDetails" />
        </bean>
    
        <bean id="userApprovalHandler"
            class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
            <property name="requestFactory" ref="oAuth2RequestFactory" />
            <property name="tokenStore" ref="tokenStore" />
        </bean>
    </beans>
    

below is the logs for the same.

DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - <Checking match of request : '/oauth/token'; against '/oauth/token'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 1 of 7 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 2 of 7 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 3 of 7 in additional filter chain; firing Filter: 'ClientCredentialsTokenEndpointFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 4 of 7 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'>
DEBUG [org.springframework.security.web.authentication.www.BasicAuthenticationFilter] - <Basic Authentication Authorization header found for user 'bccws'>
DEBUG [org.springframework.security.authentication.ProviderManager] - <Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [messages] not found for MessageSource: Can't find bundle for base name messages, locale en_US>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [labels] not found for MessageSource: Can't find bundle for base name labels, locale en_US>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [errors] not found for MessageSource: Can't find bundle for base name errors, locale en_US>
DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <Executing prepared SQL query>
DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <Executing prepared SQL statement [select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details where client_id = ?]>
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Fetching JDBC Connection from DataSource>
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
DEBUG [org.springframework.security.web.authentication.www.BasicAuthenticationFilter] - <Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f9d8c511: Principal: org.springframework.security.core.userdetails.User@593829e: Username: bccws; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ADMIN>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 5 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 6 of 7 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 7 of 7 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'>
DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - <Checking match of request : '/oauth/token'; against '/oauth/token'>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Secure object: FilterInvocation: URL: /oauth/token; Attributes: [IS_AUTHENTICATED_FULLY]>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f9d8c511: Principal: org.springframework.security.core.userdetails.User@593829e: Username: bccws; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ADMIN>
DEBUG [org.springframework.security.access.vote.AffirmativeBased] - <Voter: org.springframework.security.access.vote.RoleVoter@6dbd30e2, returned: 0>
DEBUG [org.springframework.security.access.vote.AffirmativeBased] - <Voter: org.springframework.security.access.vote.AuthenticatedVoter@19d7bbb3, returned: 1>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Authorization successful>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <RunAsManager did not change Authentication object>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token reached end of additional filter chain; proceeding with original chain>
DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] - <Chain processed normally>
DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - <SecurityContextHolder now cleared, as request processing completed>

I have still been looking at the problem but not heading to any solution. Any help would be appreciated.

Community
  • 1
  • 1
Vivek Singh
  • 2,047
  • 11
  • 24
  • Would it be possible to upload the source code of the relevant parts of your web application(e.g. a runnable version)? I have some ideas about what might be wrong, but hard to tell for sure without being able to debug. – Integrating Stuff Nov 06 '15 at 19:56

2 Answers2

2

This happens when your security filter does not have oauth/token endpoint in its context. Try adding context attribute in web.xml while registering the springSecurityFilterChain

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
    <param-name>contextAttribute</param-name>
    <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher</param-value>
</init-param>

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

Imrank
  • 1,009
  • 5
  • 15
0

The things happening behind scene is that the /oauth/token request needs to be served by below endpoint class

http://docs.spring.io/spring-security/oauth/xref/org/springframework/security/oauth2/provider/endpoint/TokenEndpoint.html

@RequestMapping(value = "/oauth/token")
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam

And the TokenEndpoint instance is created by oauth2:authorization-server tag. From the log, your client and user credentials have passed the validation of all the security filters you have seen in the log. After that the request is supposed to be passed to the TokenEndpoint by the MVC web framework, but seems not.

You need to turn on the org.springframework.web trace log to see what is happening.

And you may check your web.xml, you need to configure /oauth/token binding to Spring MVC Dispatcher Servlet.

Such as

 <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/oauth/*</url-pattern>
</servlet-mapping>
Popeye
  • 2,002
  • 20
  • 14