简体   繁体   English

使用spring-security-oauth2的SSO:永远不会读取身份验证代码

[英]SSO using spring-security-oauth2 : Authentication Code never read

Using : 使用:

  • spring-security 3.2.5 春季安全性3.2.5
  • spring-security-oauth 2.0.7 春季安全oauth 2.0.7

I have a working oauth2 provider built with spring-security-oauth (oauth2). 我有一个使用spring-security-oauth(oauth2)构建的可工作的oauth2提供程序。

I have my client configured in it to use authorization_code grant type. 我在其中配置了客户端以使用authorization_code授予类型。

The provider works perfectly : Testing with curl, I can get an authorization code and exchange it for an access token. 该提供程序运行良好:使用curl进行测试,我可以获得授权码并将其交换为访问令牌。 So on the service provider part, all is fine. 因此,在服务提供商方面,一切都很好。

Now I'm trying to implements the client application, also with spring-security-oauth. 现在,我正在尝试使用spring-security-oauth实现客户端应用程序。 I'm using xml configuration, strongly based on the example here , but using my own provider (mentionned above) instead of google. 我使用的是xml配置,强烈基于此处的示例,但使用的是我自己的提供程序(上面已提及)而不是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. 当我在客户端上调用受保护资源时, OAuth2ClientAuthenticationProcessingFilter尝试获取访问令牌,因此它将重定向到我的服务提供商。 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 ). 这将迫使用户按预期方式登录,然后将其重定向到已配置的redirect_uri(重定向uri是为我的OAuth2ClientAuthenticationProcessingFilter配置的uri:类似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. 因此, OAuth2ClientAuthenticationProcessingFilter重新启动该流程,要求输入授​​权码。

I've been able to make it work by modifying the OAuth2ClientAuthenticationProcessingFilter to read the request and set the authorization code in the AccessTokenRequest . 通过修改OAuth2ClientAuthenticationProcessingFilter来读取请求并在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. 在尝试此操作之前,我尝试在方法org.springframework.security.oauth2.client.token.AccessTokenRequest.setAuthorizationCode()上创建“调用层次结构”,以查找spring在代码中确实调用该方法的位置,但未返回任何内容。

Is that a bug ? 那是个错误吗? I really would like not to have to replace the OAuth2ClientAuthenticationProcessingFilter with my own. 我真的OAuth2ClientAuthenticationProcessingFilter用我自己的OAuth2ClientAuthenticationProcessingFilter替换。

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). 永远不会调用setAuthorizationCode()方法(我最初的问题是错误)。 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). 我可以断言OAuth2ClientContextFilter是在OAuth2ClientAuthenticationProcessingFilter之前OAuth2ClientAuthenticationProcessingFilter (我已通过调试器进行了检查)。

What I found, but don't know if it is normal : 我发现了什么,但不知道这是否正常:

The default constructor of DefaultAccessTokenRequest is only called once : at the application startup. DefaultAccessTokenRequest的默认构造函数仅在应用程序启动时被调用一次: 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. 由于我在RestTemplateBeanDefinitionParser中看到访问令牌请求的作用域是“请求”,因此我希望带有参数映射的构造函数在对我的客户端应用程序的每个新http请求上都被调用。 In the RestTemplateBeanDefinitionParser : 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. 现在,我得到csrf保护错误,因为当我假设一旦获得访问令牌就不再需要stateKey时, AccessTokenRequest stateKey记住一些stateKey

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). 您需要一个OAuth2ClientContextFilter ,它需要在身份验证处理过滤器之前触发(它基本上会执行您自定义过滤器中的工作)。 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 : 永远不要像这样配置Oauth2RestTemplate

<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. 这就解释了为什么DefaultAccessTokenRequest不在请求范围内,因此调用了它的默认控制器,而不是一个接受请求的参数映射。 Don't do like me and use the xml namespace ! 不要像我一样使用xml名称空间! :

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

Still wondering why I've done that :P 仍然想知道为什么我这样做了:P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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