切换到 HTTPS 时出现 Grails + Tomcat + Apache 错误
Posted
技术标签:
【中文标题】切换到 HTTPS 时出现 Grails + Tomcat + Apache 错误【英文标题】:Grails + Tomcat + Apache error when switching to HTTPS 【发布时间】:2012-04-19 02:26:33 【问题描述】:我们有一个 Grails Web 应用程序,在 Apache2 后面的 tomcat7 中运行。使用 ProxyPass 和 ajp 协议一切正常:
ProxyPass / ajp://localhost:9013/
ProxyPas-s-reverse / ajp://localhost:9013/
其中 9013 是我们在 tomcat 的 server.xml
中的 AJP 端口。
现在,我们的问题是这样的。我们的 Grails 应用程序同时运行 HTTP 和 HTTPS。当转到应用程序中的某个区域时,Spring Security(Grails Spring Security Core 插件)会将您从使用 HTTP 的地址重定向到 HTTPS,例如当点击:
http://www.example.com/secure/path
Spring Security 会将您重定向到:
https://www.example.com/secure/path
但是现在,当它重定向到那里时,服务器挂起,最后 Firefox 给出 “Firefox 检测到服务器正在以永远不会完成的方式重定向该地址的请求。” 错误.
我是否正确假设使用 AJP 代理进行的某些重定向会变坏?谁能提供有关此设置如何工作的更多信息?
进一步观察,我们发现了以下内容:
当直接(通过 IP 和端口)在 tomcat 中点击应用程序时,一切正常 100%。但是一旦我们通过 Apache,Spring Security 重定向就不起作用了。您不断在 Apache 日志中获得以下信息:
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:41 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
...
而不是重定向到 https,似乎 apache 神奇地让它再次尝试 http。 谢谢
【问题讨论】:
是只有在有重定向时才会失败,还是在尝试直接进入HTTPS页面时也会失败? 【参考方案1】:虽然我不能告诉你如何解决它,但我可以告诉你问题是什么。
本质上是重写入口点。
所以你在这些情况下应该做的部分事情已经确定:
grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
如果我们真的在 http/https 上,这将通过设置标头来查找,默认为:
RequestHeader 设置 X-Forwarded-Proto "http"
现在我在 nginx 中可以正常工作。前面有 apache 的问题是重写规则 ARENT 拿起 apache 服务器。他们只是捡起自我。因此,当它运行时,它基本上会遇到无限重定向,因为它所知道的只是你所在的 9013 服务器。
现在我想我只是编写自己的自定义 HttpsEntry 但我想有一些 apache 设置可以使这项工作正常进行。
【讨论】:
【参考方案2】:Grails/Spring-Security 具有以下属性:
grails
// redirect ports
plugins
springsecurity
portMapper
httpPort = 80
httpsPort = 443
您可以使用 hongo 的上述 httpd-config(端口 80/443,SSL 终止于 Apache)。您可能还想适当地设置server.url
属性。
【讨论】:
【参考方案3】:免责声明,我不是 Grails 专家。
但根据您的描述,配置可能如下:
SSL 被卸载到 apache httpd。因此,只需要在 Tomcat 中配置 ajp 连接器,或者可能需要额外的 http 连接器来进行测试。 按照http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html 为 apache httpd 配置启用 SSL 和
<VirtualHost _default_:80>
RedirectPermanent /secure/path https://www.example.com/secure/path
ProxyPass / ajp://localhost:8009/
ProxyPas-s-reverse / ajp://localhost:8009/
</VirtualHost>
<VirtualHost _default_:443>
# SSL config
...
ProxyPass / ajp://localhost:8009/
ProxyPas-s-reverse / ajp://localhost:8009/
</VirtualHost>
应该可以。
另一个好处是,当 SSL 卸载到 apache httpd 时,您可能会看到性能提升。
另外,为什么不对所有东西强制使用 SSL:
<VirtualHost _default_:80>
RedirectPermanent / https://www.example.com/
</VirtualHost>
<VirtualHost _default_:443>
# SSL config
...
ProxyPass / ajp://localhost:8009/
ProxyPas-s-reverse / ajp://localhost:8009/
</VirtualHost>
至于为什么会有无限循环,可能与 Spring Security 的 sendRedirect 有关。 如果您可以发布完整的 apache VirtualHost 和 tomcat ajp 连接器配置,它可能会给我们更多线索。
【讨论】:
【参考方案4】:不确定 spring-security-core 在切换到 HTTPS 时如何决定使用哪个端口,但默认 Tomcat 配置为 AJP 连接器设置了 redirectPort="8443",也许您需要更改为 443 以便重定向命中Apache 的 HTTPS 端口。
【讨论】:
这不起作用,因为我们需要运行多个 tomcat 实例,所以一旦我们有两个都需要 https 的应用程序,一个将无法运行,因为它无法运行绑定到 443 端口。 这里不涉及绑定,它只是一个 Tomcat 在重定向到 HTTPS 时将使用的端口的属性。 但是如上所述,我不确定spring-security-core是否使用了这个属性。【参考方案5】:顺便说一句……这是你的答案。
端口映射器设置也是如此,并像我之前所说的那样使用通道安全性。
通道安全需要知道何时转发到 http/https
但在重定向中,您需要保留代理设置,以便 request.getServerPort() 可以找到它们。您可以将其添加到您的 Apache httpd.conf:
ProxyPreserveHost 开启
【讨论】:
以上是关于切换到 HTTPS 时出现 Grails + Tomcat + Apache 错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 Acegi 和 Grails 通过 LDAP 进行身份验证时出现 PartialResultException
尝试在 Tomcat 中启动 grails App 时出现“严重:错误 listenerStart”
为 grails 运行 test-app -coverage 命令时出现错误,即使所有测试用例都通过了