1

我在重定向到访问令牌入口点 /oauth/token 时遇到问题,这将在下面详细说明。我希望有人能给我一些启示,因为我花了很多时间来实现它。

此外,有趣的是,即使按照他们的说明,我也无法使用 SoapUI 5.0 社区版进行测试。它获取授权代码,但稍后失败,因为您需要将重定向 URI 设置为“urn:ietf:wg:oauth:2.0:oob”。

由于 Spring-Security-Oauth2 缺乏很多好的文档,而且我花了很多时间调试和记录工作,我决定在这里分享我的评论和配置代码,这可能对其他人也有帮助。

我在我的 pom 上使用以下依赖项版本:

<org.springframework-version>4.0.5.RELEASE</org.springframework-version>
<org.springframework.security-version>3.2.5.RELEASE</org.springframework.security-version>
<org.springframework.security.oauth2-version>2.0.3.RELEASE</org.springframework.security.oauth2-version>

现在,想法是使用 Cassandra 作为持久性存储来实现所有 clientId 对象、UserPrincipal、访问、nonce 和令牌存储。所有这些组件都运行良好并经过测试。事实上,它获取所有的身份验证/授权,创建授权代码。

我最近在 Spring Oauth2 github 上测试 JDBC 存储时看到了一个错误,但这与测试而不是实际实现有关,特别是因为不使用 JDBC。

我编写了一个客户端 Web 应用程序来访问与 OAuth2 服务器和 Spring Security 一起登录的 REST 资源。一切顺利,直到我向 /oauth/token 请求访问令牌。

当我首先点击安全的 Rest 服务时,它会正确地开始进行重定向并执行 DefaultOAuth2RequestFactory createAuthorizationRequest() 方法。使用存储中的秘密等完美加载 ClientDetails 对象。因此它具有 Oauth2 客户端的所有范围、授权等。它还正确验证了 redirectURIParameter 并解析了重定向。然后它转到 TokenStoreUserApprovalHandler 并创建 OAuth2Request 对象。然后,当然会尝试查找工作流中尚不存在的现有访问令牌。它从 authenticationKeyGenerator 创建 authenticationkey 并查询此时正确返回 null 的存储。然后它重定向回 /oauth/authorize 两次,第二次它有一个授权码并在approveOrDeny() 方法中标记为已批准(AuthorizationEndPoint)。authorizationCodeServices 创建代码并将其正确存储在我的 Cassandra 存储中。

此时它调用 ( AuthorizationEndPoint)getSuccessfulRedirect()将状态参数添加到模板。

然后它调用(OAuth2RestTemplate类)getAccessToken()方法。由于访问令牌很好且有效,因此它调用acquireAccessToken()返回一个accessTokenRequestwith {code=[Q19Y6u], state=[1PyzHf]}。然后它调用 以accessTokenProvider在 获取访问令牌obtainAccessToken()。然后调用OAuth2AccessTokenSupportretrieveToken()方法中调用。并在getRestTemplate. 使用AuthorizationCodeResourceDetails授权类型完美创建authorization_code,它同时具有authorizationSchemeclientAuthenticationScheme作为标题。clientId是正确的clientSecretAuthorizationCodeResourceDetailsisoAuth2ClientBeanuserAuthorizationURIis 的 id http://myhost.com:8080/MyAPI/oauth/authorize。标题显示为

{Authorization=[Basic .....]}

提取器是org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport。形式是{grant_type=[authorization_code], code=[Xc7yni], redirect_uri=[http://myhost.com:8080/OAuthClient/support]}

然后应用程序冻结并显示在日志中:

DEBUG: org.springframework.security.authentication.DefaultAuthenticationEventPublisher - No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException
DEBUG: org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException

然后我的客户端 Web 应用程序出现以下异常:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is error="access_denied", error_description="Error requesting access token."
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)

现在,我相信我的 OAuth2 和 Spring Security 的 xml 配置有一些问题。所以配置文件如下。

我确实有一些关于它的问题,所以这里首先是问题:

1)<oauth2:authorization-server>我不确定我是否正确配置了这个。请查看我对我的 xml 文件的评论。我添加了指向我的 userAuthenticationManager bean 的 authentication-request-manager-ref 参数,这是一个身份验证管理器,它采用身份验证提供者 user-service-ref="userService"

<oauth2:authorization-server client-details-service-ref="webServiceClientService" 
    token-services-ref="tokenServices" user-approval-page="/oauth/userapproval" 
    error-page="/oauth/error" authorization-endpoint-url="/oauth/authorize" 
    token-endpoint-url="/oauth/token" user-approval-handler-ref="userApprovalHandler" 
    redirect-resolver-ref="resolver">
    <oauth2:authorization-code
        authorization-code-services-ref="codes" />
    <oauth2:implicit/>
    <oauth2:refresh-token/>
    <oauth2:client-credentials/>
    <oauth2:password authentication-manager-ref="userAuthenticationManager"/>
    <!-- <oauth2:custom-grant token-granter-ref=""/> -->
</oauth2:authorization-server>

2) authentication-manager oauthClientAuthenticationManager 在“/oauth/token”被拦截时使用。这定义如下:

<sec:authentication-manager id="oauthClientAuthenticationManager">
    <sec:authentication-provider user-service-ref="clientDetailsUserService">
        <sec:password-encoder ref="passwordEncoder" />
    </sec:authentication-provider>
</sec:authentication-manager>

3) 我定义了以下在 sec:global-method-security 中使用的 methodSecurityExpressionHandler bean。不确定这是否正确。

<beans:bean id="methodSecurityExpressionHandler"
        class="org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler" />

4)我还有一个我认为不推荐的bean“clientCredentialsTokenEndpointFilter”。我将其用作入口点“/oauth/token”的自定义过滤器,但我认为这是错误的。

<beans:bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <beans:property name="authenticationManager" ref="oauthClientAuthenticationManager"/>
</beans:bean>
A filter and authentication endpoint for the OAuth2 Token Endpoint. Allows clients to authenticate using request
parameters if included as a security filter, as permitted by the specification (but not recommended). It is
recommended by the specification that you permit HTTP basic authentication for clients, and not use this filter at
all.

5) 现在是 Oauth 令牌端点:这是端点 /oauth/token 因为我在这里有很多问题:

  1. 这是永远达不到的。
  2. 我应该有一个喜欢的自定义过滤器clientCredentialsTokenEndpointFilter吗?
  3. 我必须有一个 http-basic 入口点吗?
  4. 我应该有一个访问属性,IS_AUTHENTICATED_FULLY或者我可以使用我在我的UserPrincipal对象上定义的权限,比如OAUTH_CLIENT我在那里添加的权限吗?
  5. 会议呢?我应该说“无国籍”还是“从不”
  6. 我也应该添加corsFilter它吗?
  7. 入口点是否正确?哪个是OAuth2AuthenticationEntryPoint班级?
  8. 我必须添加 csrf 令牌吗?我相信不会,因为它会限制它更多。
  9. 表达式处理程序是否正确org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandle
  10. 我可以将 authentication-manager-ref 从更改oauthClientAuthenticationManageruserAuthenticationManager.

<sec:http use-expressions="true" create-session="stateless" authentication-manager-ref="userAuthenticationManager" entry-point-ref="oauthAuthenticationEntryPoint" pattern="/oauth/token"> <sec:intercept-url pattern="/oauth/token" access="hasAuthority('OAUTH_CLIENT')" /> <!-- <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" /> --> <sec:http-basic entry-point-ref="oauthAuthenticationEntryPoint"/> <!-- <sec:http-basic/> --> <sec:anonymous enabled="false" /> <sec:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" /> <sec:access-denied-handler ref="oauthAccessDeniedHandler" /> <sec:expression-handler ref="webSecurityExpressionHandler" /> <!-- <sec:custom-filter ref="corsFilter" after="LAST"/> --> </sec:http>

我想在这里添加完整的配置文件,但有一个限制。

4

1 回答 1

0

/oauth/token 端点应使用客户端凭据进行保护,看起来您将其连接到用户身份验证管理器。您没有显示它的配置或实现,但从它的判断来看,InternalAuthenticationServiceException它失败了,并出现了一个未被归类为安全异常的异常。解决这两个问题,你可能会做生意。

(顺便说一下,这种@Configuration风格更方便,我建议开始使用它以及它提供的更多默认值,直到你掌握它为止。)

于 2014-10-19T08:28:20.217 回答