简体   繁体   中英

SSO using spring-security-oauth2 : Authentication Code never read

Using :

  • spring-security 3.2.5
  • spring-security-oauth 2.0.7

I have a working oauth2 provider built with spring-security-oauth (oauth2).

I have my client configured in it to use authorization_code grant type.

The provider works perfectly : Testing with curl, I can get an authorization code and exchange it for an access token. So on the service provider part, all is fine.

Now I'm trying to implements the client application, also with spring-security-oauth. I'm using xml configuration, strongly based on the example here , but using my own provider (mentionned above) instead of google.

When I make a call to a protected resource on my client, the OAuth2ClientAuthenticationProcessingFilter tries to obtain an access token, so it redirect to my service provider. That one force the user to log in, as expected, and then redirect him to the configured redirect_uri (the redirect uri is the one configured for my OAuth2ClientAuthenticationProcessingFilter : something like http://myClient/context/external/login ). The problem is : the client never read the authorization code in the request returned from the service provider . So the OAuth2ClientAuthenticationProcessingFilter restarts the flow, asking for an authorization code.

I've been able to make it work by modifying the OAuth2ClientAuthenticationProcessingFilter to read the request and set the authorization code in the AccessTokenRequest . Here is the snippet :

OAuth2AccessToken accessToken;
try {
  String code = request.getParameter("code");
  if(code != null) {
    restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAuthorizationCode(code);
  }
  accessToken = restTemplate.getAccessToken();
  ...

Before trying this, I tried to make a "call hierarchy" on the method org.springframework.security.oauth2.client.token.AccessTokenRequest.setAuthorizationCode() , to find where in the code spring does call the method, but it returned nothing.

Is that a bug ? I really would like not to have to replace the OAuth2ClientAuthenticationProcessingFilter with my own.

Does someone made it work ( in that version or another) ?

Update

It's the setAuthorizationCode() method that is never called (error in my initial question). But I digged a little more and I realized this is not the problem.

I can assert that the OAuth2ClientContextFilter is called before OAuth2ClientAuthenticationProcessingFilter (I checked that with a debugger).

What I found, but don't know if it is normal :

The default constructor of DefaultAccessTokenRequest is only called once : at the application startup. The other constructor (the one taking the parameter's map), is never called. Since I've seen in RestTemplateBeanDefinitionParser that the access token request is scoped 'request', I would expect the constructor taking the parameter's map to be called on each new http request to my client application. In the RestTemplateBeanDefinitionParser :

BeanDefinitionBuilder request = BeanDefinitionBuilder.genericBeanDefinition(DefaultAccessTokenRequest.class);
request.setScope("request");
request.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
request.addConstructorArgValue("#{request.parameterMap}");
request.addPropertyValue("currentUri", "#{request.getAttribute('currentUri')}");

That can explain my problem with the authorization code never read from the request. The hack I mentionned in my initial question just pushed back the problem. Now I get csrf protection errors because the AccessTokenRequest always remembers some stateKey when I presume it does not need anymore once I get the access token.

Again, maybe I just misunderstand the hole think, so feel free to tell me :)

I did not post my configuration because it's pretty the same as that one here .

You need an OAuth2ClientContextFilter and it needs to fire before the authentication processing filter (it basically does that stuff you have in your custom filter). I can't tell from the code you posted if you have one and it isn't firing or you don't have one.

Sorry for all of you that spent precious time trying to help me. I was so focused debugging that I missed a configuration problem. Do never configure Oauth2RestTemplate like this :

<beans:bean id="myRestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
     <beans:constructor-arg ref="myResourceId"/>
</beans:bean>

That explain why the DefaultAccessTokenRequest was not request scoped, hence it's default controller called instead of the one taking request's parameter map. Don't do like me and use the xml namespace ! :

<oauth:rest-template id="myRestTemplate" resource="myResourceId"/>

Still wondering why I've done that :P

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM