使用 Spring Cloud OAuth2 的 SSL / 代理问题
Posted
技术标签:
【中文标题】使用 Spring Cloud OAuth2 的 SSL / 代理问题【英文标题】:SSL / Proxy Issue using Spring Cloud OAuth2 【发布时间】:2015-07-21 18:30:39 【问题描述】:我改编了以下 OAauth2 Spring Cloud 示例:
Authserver/SSO
我所做的唯一更改是在 Authserver 端使用 JPA 来检查数据库中的凭据。一切正常,除了将它部署在 nginx 代理后面。如上面示例应用程序中使用的那样,使用了 Spring Boot 和嵌入式 Tomcat。我还正确配置了代理标头:
server.tomcat.protocol-header=X-Forwarded-Proto
server.tomcat.remote-ip-header=X-Real-IP
代理 HTTP 工作正常:
accessTokenUri: http://uaa.sample.com/oauth/token
userAuthorizationUri: http://uaa.sample.com/oauth/authorize
到目前为止一切顺利,但我需要使用 SSL(显然):
accessTokenUri: https://uaa.sample.com/oauth/token
userAuthorizationUri: https://uaa.sample.com/oauth/authorize
如果我切换到 SSL,在身份验证服务器从授权重定向回来后,我会从客户端应用程序收到 401。我捕获了 HTTP 流量,一切似乎都正常:
对客户端应用程序的 GET 请求 客户端应用重定向到 /login /login 重定向到https://uaa.sample.com/oauth/authorize?client_id=reprisk&redirect_uri=http://test.sample.com/login&response_type=code&state=9prwi2 身份验证服务器重定向到https://uaa.sample.com/login 登录后再次调用authorize,服务器最终重定向到http://test.sample.com/login?code=212eRK&state=9prwi2HTTP 和 HTTPS 的 HTTP 流量完全相同,除了 HTTP 为最后一个请求设置了正确的引用者(AFAIK,在 OAuth 身份验证期间不检查引用者,对吗?):
HTTP:
GET /login?code=212eRK&state=9prwi2 HTTP/1.1
Host: test.sample.com
...
Referer: http://uaa.sample.com/login
Cookie: JSESSIONID=401EB8D1D1F4297160D518EC253A0CB5; XSRF-TOKEN=95a00a0d-3362-4e9b-b7eb-45addf2d10b4
...
---
HTTP/1.1 302 Found
HTTPS:
GET /login?code=212eRK&state=9prwi2 HTTP/1.1
Host: test.sample.com
...
Cookie: JSESSIONID=401EB8D1D1F4297160D518EC253A0CB5; XSRF-TOKEN=95a00a0d-3362-4e9b-b7eb-45addf2d10b4
...
---
HTTP/1.1 401 Unauthorized
来自客户端应用程序的相应日志消息:
Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token.
任何想法为什么使用代理和 SSL 不起作用?我很高兴分享更多代码和/或日志输出!
谢谢!!!
【问题讨论】:
日志可能会告诉你(org.springframework.security
的调试日志记录)。
@DaveSyer 我也有同样的问题。调整日志级别并没有显示有关可能根本原因的更多信息
我无法从这种详细程度中分辨出更多信息。一个示例应用程序会很有帮助。
刚刚花了一些时间在我的调试器中运行似乎类似的情况。在我的例子中,在抛出 BadCredentialsException 的时候,底层的链式异常是一个 InvalidRequestException,带有消息:检测到可能的 CSRF:需要状态参数,但找不到。 BadCredentialsException 有点误导我天真的(csrf 很重要)的想法。
我在尝试获取网络代理后面的 oauth(uaa/oauth/token) 令牌时遇到示例错误。
【参考方案1】:
在 SSO 应用尝试将身份验证代码交换为令牌时,它似乎失败了。 在此之前的所有步骤都是浏览器重定向,这是 SSO 服务器上尝试调用身份验证服务器的代码。 您在身份验证服务器上使用什么 SSL 证书?它们是否由受信任方在 Java 信任库中使用 CA 签署? 如果不是,这可能就是它失败的原因,因为 BadCredentialsException 是底层 HTTP 请求失败的最终结果。
另一种选择是没有直接从 SSO 服务器到 Auth 服务器地址的路由。
我相信最终将由 Apache Commons HttpClient 代码处理请求,因此您应该尝试为这些类 (org.apache.http) 增加调试并查看报告的内容。
【讨论】:
对我来说,将 JDK 更新到最新版本解决了这个问题,因为根本原因是 SSL 握手。当我打开安全调试日志记录时,我开始看到这个异常 - 原因:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径【参考方案2】:可能有点晚了,但我遇到了完全相同的事情。
我的设置是一个 NGINX,它使用 Spring oAuth2 对正在运行的 Spring Boot 应用程序进行 SSL 代理。
在 nginx 配置中解决这个问题
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
这在你的 spring application.yml
server.tomcat.remote_ip_header: X-Forwarded-For
server.tomcat.protocol_header: X-Forwarded-Proto
security.require_ssl: true
来源: http://docs.spring.io/spring-boot/docs/current/reference/html/howto-security.html#howto-enable-https
现在 Spring 检测到正确的 URL,并且 request.getRequestURL 现在返回正确的 URL,包括 https://
@Controller
public class HomeController
@RequestMapping("/")
@ResponseBody
public String rootLandingPage(HttpServletRequest request) throws Exception
return "url: " + request.getRequestURL();
【讨论】:
执行此操作后,我得到The redirect URI in the request, https://localhost/login/google, does not match the ones authorized for the OAuth client. Visit https://console.developers.google.com/apis/credentials/oauthclient/477999739807-d0t4443rdep6jfnmjr4aufuh389tn2sk.apps.googleusercontent.com?project=477999739807 to update the authorized redirect URIs.
【参考方案3】:
可能值得仔细研究一下为什么 BadCredentialsException 会冒泡,我的意思是使用调试器逐步执行 Spring Security OAuth2 代码。
我之所以这么说是因为根据我的经验,BadCredentialsException 可能是由于潜在的 InvalidRequestException 引起的,以下是违规行:
throw new InvalidRequestException(
"Possible CSRF detected - state parameter was required but no state could be found");
我在这里提出了一个与上述相关的单独问题:
Why is AccessTokenRequest's PreservedState perpetually null with a resultant CSRF related InvalidRequestException?
因此,就您的情况而言,使用新引入的 nginx 代理,我只是想知道您是否可能没有看到误导性异常。也就是说,在 oauth2 和 spring security oauth 2 方面会误导未经训练的人,而 CSRF 是处理的额外复杂性。
【讨论】:
以上是关于使用 Spring Cloud OAuth2 的 SSL / 代理问题的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Cloud Security 实现 OAuth2“令牌交换”
什么是使用 Spring Cloud 微服务的 OAuth2 中的资源服务器
Spring Cloud Gateway OAuth2 with Spring Security OAuth2 Authorization Server = loop
使用 OAuth2 保护服务,JWT 令牌不起作用 Spring Cloud
使用 spring-session 和 spring-cloud-security 时,OAuth2ClientContext (spring-security-oauth2) 不会保留在 Redis