Spring Security Oauth 2 custom token end point url

15.4k views Asked by At

Hello I have to integrate spring security oauth2 in my project. So I added the configuration related part and its working fine. But the problem is that the first request for token goes to "/oauth/token" and I want to change it to "api/v1/token" . I searched for that and find some solution like adding token-endpoint-url in oauth:authorization-server also adding custom filter class that will override ClientCredentialsTokenEndpointFilter and passing the url to constructor. But these didn't worked . I am getting following error for request to "api/v1/token"-

An Authentication object was not found in the SecurityContext

My configuration is mainly xml based . Spring-security.xml file-

<http pattern="/api/v1/token" create-session="stateless"
      authentication-manager-ref="authenticationManager"
      xmlns="http://www.springframework.org/schema/security" > 
    <intercept-url pattern="/api/v1/token" access="IS_AUTHENTICATED_FULLY" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
    <custom-filter ref="customClientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" /> 
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<http pattern="/test/**" create-session="never"
      entry-point-ref="oauthAuthenticationEntryPoint"       
      xmlns="http://www.springframework.org/schema/security">
    <anonymous enabled="false" />
    <intercept-url pattern="/test/**" access="ROLE_USER" />
    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<beans:bean id="oauthAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</beans:bean>
 <beans:bean id="oauthAccessDeniedHandler"
    class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
</beans:bean>
<beans:bean id="clientAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <beans:property name="realmName" value="springsec/client" />
    <beans:property name="typeName" value="Basic" />
</beans:bean>


 <beans:bean id="customClientCredentialsTokenEndpointFilter"
            class="com.walletdoc.oauth.web.security.CustomClientCredentialsTokenEndpointFilter">
     <beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

<authentication-manager alias="authenticationManager"
                        xmlns="http://www.springframework.org/schema/security">
    <authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<beans:bean id="clientDetails" class="com.walletdoc.oauth.web.security.SpringSecurityClientService">
    <beans:property name="id" value="mysupplycompany" />
    <beans:property name="secretKey" value="mycompanykey" />
    <beans:property name="authorities" value="ROLE_CLIENT" />
</beans:bean>
<beans:bean id="clientDetailsUserService"
            class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <beans:constructor-arg ref="clientDetails"/>
</beans:bean>



<authentication-manager id="userAuthenticationManager" 
                        xmlns="http://www.springframework.org/schema/security">
    <authentication-provider  ref="customUserAuthenticationProvider">
    </authentication-provider>
</authentication-manager>

<beans:bean id="customUserAuthenticationProvider"
            class="com.walletdoc.oauth.web.security.ClientAuthenticationProvider">
</beans:bean>

<oauth:authorization-server
    client-details-service-ref="clientDetails" token-services-ref="tokenServices" token-endpoint-url="/api/v1/token">
    <oauth:authorization-code />
    <oauth:implicit/>
    <oauth:refresh-token/>
    <oauth:client-credentials />
    <oauth:password authentication-manager-ref="userAuthenticationManager" />
</oauth:authorization-server>

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

<beans:bean id="tokenStore"
            class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

<beans:bean id="tokenServices"
            class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <beans:property name="tokenStore" ref="tokenStore" />
    <beans:property name="supportRefreshToken" value="true" />
    <beans:property name="accessTokenValiditySeconds" value="3600"></beans:property>
    <beans:property name="clientDetailsService" ref="clientDetails" />
</beans:bean>

I have been trying to solve this issue from last 2 days ,so any help will be appreciated.

2

There are 2 answers

0
Anita On BEST ANSWER

Finally got it working. One thing that was missing in this question was <beans:property name="filterProcessesUrl" value="/api/v1/token" /> in ClientCredentialsTokenEndpointFilter Bean definition.

In the custom-filter tag there is reference of ClientCredentialsTokenEndpointFilter Bean and in that Bean one property is defined that id filterProcessesUrl and the value is given as the desired url,as in my case it is /api/v1/token. And this solves the problem.

So basically for changing token-endpoint-url,we need to change at 4 place-

  1. Adding token-endpoint-url in authorization-server definition

  2. Change at <http pattern="changed URL"

  3. Change at <intercept-url pattern="changed URL"

  4. And, adding filterProcessesUrl property with value="changed url" in ClientCredentialsTokenEndpointFilter .

2
Michael Técourt On

Isn't the path "/oauth/token" kind of a defacto standard ?

Unfortunately I don't have the exact answer for XML configuration but maybe this Java config can give you hints.

When you extend AuthorizationServerConfigurerAdapter the following method gives you access to a Builder giving access to authorization server configuration :

@Override
public void configure(AuthorizationServerEndpointsConfigurer oauthServer) throws Exception {
    oauthServer

        // Here you can override the default endpoints mappings
        .pathMapping("/oauth/authorize", "/api/v1/authorize")
        .pathMapping("/oauth/token", "/api/v1/token")

        // .. rest of the authorization server customization
        .authenticationManager(authenticationManager)
        .tokenStore(tokenStore);
}

It is kind of weird because you override the mappings through a Map, you have to know each path you want to override, and there is not really any hint or documentation in the AuthorizationServerEndpointsConfigurer class.

In the end it works, as when the authorization server starts the logs show :

...
.s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/api/v1/authorize],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto ...
.s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/api/v1/token],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto ...

...

I guess in XML it should translate to some element inside <oauth:authorization-server> like :

<oauth:authorization-server>
  <!-- ... -->
  <pathMappings>
    <!-- key/value here -->
  </pathMappings>
</oauth:authorization-server>

EDIT : After checking the XML schema, you probably had it right at first, as the token-endpoint-url element should have done the math according to the comments :

        <xs:attribute name="token-endpoint-url" type="xs:string">
            <xs:annotation>
                <xs:documentation>
                    The URL at which a request for an access token
                    will be serviced.
                    Default value: "/oauth/token"
                </xs:documentation>
            </xs:annotation>
        </xs:attribute>

Maybe you should file an issue in the spring-security-oauth issue tracker ?