在IBM Cloud CF Java Buildpack上使用Spring Boot OAuth 2 ...
https://github.com/ericis/oauth-cf-https-issue
*我已经尝试过以下所有组合。
使用此配置,应用程序陷入了无限循环的重定向,其中OAuth重定向策略将其发送到http
,然后此配置将其发送到https
http.requiresChannel().anyRequest().requiresSecure()
没有此配置,用户可以通过http登录(不需要)。
完整配置:
http.
requiresChannel().anyRequest().requiresSecure().
authorizeRequests().
// allow access to...
antMatchers("favicon.ico", "/login", "/loginFailure", "/oauth2/authorization/ghe")
.permitAll().anyRequest().authenticated().and().oauth2Login().
// Codify "spring.security.oauth2.client.registration/.provider"
clientRegistrationRepository(this.clientRegistrationRepository()).
// setup OAuth2 client service to use clientRegistrationRepository
authorizedClientService(this.authorizedClientService()).
successHandler(this.successHandler()).
// customize login pages
loginPage("/login").failureUrl("/loginFailure").
userInfoEndpoint().
// customize the principal
userService(this.userService());
我也尝试过:
服务器配置以使用https
server:
useForwardHeaders: true
tomcat:
protocolHeader: x-forwarded-proto
Servlet过滤器
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class HttpToHttpsFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(HttpToHttpsFilter.class);
private static final String HTTP = "http";
private static final String SCHEME_HTTP = "http://";
private static final String SCHEME_HTTPS = "https://";
private static final String LOCAL_ID = "0:0:0:0:0:0:0:1";
private static final String LOCALHOST = "localhost";
@Value("${local.ip}")
private String localIp;
public HttpToHttpsFilter() {
// Sonar
}
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
// http, not localhost, not localhost ipv6, not local IP
if (HTTP.equals(request.getScheme()) &&
!LOCALHOST.equals(request.getRemoteHost()) &&
!LOCAL_ID.equals(request.getRemoteHost()) &&
(this.localIp != null && !this.localIp.equals(request.getRemoteHost()))) {
final String query = request.getQueryString();
String oldLocation = request.getRequestURL().toString();
if (query != null) {
oldLocation += "?" + query;
}
final String newLocation = oldLocation.replaceFirst(SCHEME_HTTP, SCHEME_HTTPS);
try {
log.info("HTTP redirect from {} to {} ", oldLocation, newLocation);
response.sendRedirect(newLocation);
} catch (IOException e) {
log.error("Cannot redirect to {} {} ", newLocation, e);
}
} else {
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
// Sonar
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// Sonar
}
}
依赖项
dependencies {
//
// BASICS
// health and monitoring
// compile('org.springframework.boot:spring-boot-starter-actuator')
// security
compile('org.springframework.boot:spring-boot-starter-security')
// configuration
compile('org.springframework.boot:spring-boot-configuration-processor')
//
// WEB
// web
compile('org.springframework.boot:spring-boot-starter-web')
// thymeleaf view render
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
// thymeleaf security extras
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4')
//
// OAUTH
// OAuth client
compile('org.springframework.security:spring-security-oauth2-client')
// OAuth lib
compile('org.springframework.security:spring-security-oauth2-jose')
// OAuth config
compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.0.RELEASE')
//
// CLOUD
// cloud connectors (e.g. vcaps)
compile('org.springframework.boot:spring-boot-starter-cloud-connectors')
//
// TOOLS
runtime('org.springframework.boot:spring-boot-devtools')
//
// TEST
// test
testCompile('org.springframework.boot:spring-boot-starter-test')
// security test
testCompile('org.springframework.security:spring-security-test')
}
答案 0 :(得分:3)
此问题已解决。有关此问题的详细信息,请参见: https://github.com/spring-projects/spring-security/issues/5535#issuecomment-407413944
正在运行的示例项目:https://github.com/ericis/oauth-cf-https-issue
简短答案:
需要将应用程序显式配置为了解代理标头。我曾经尝试过配置,但最终不得不使用最近添加到Spring的ForwardedHeaderFilter
类的实例。
@Bean
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
final FilterRegistrationBean<ForwardedHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<ForwardedHeaderFilter>();
filterRegistrationBean.setFilter(new ForwardedHeaderFilter());
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
答案 1 :(得分:1)
即使不涉及OAuth行为,应用程序在当前环境下也可能始终陷入当前设置的无限循环中。
虽然您可以告诉服务器使用转发头,
server:
useForwardHeaders: true
Tomcat不会信任所有来源的x-forwarded-*
标头。默认情况下,某些IP地址被视为内部地址(RemoteIpValve#internalProxies)。
但是,在您使用的环境中,报告的代理IP地址可能不在此范围内。您可以使用以下命令配置所有允许的IP地址:
server:
tomcat:
internal-proxies: .*
这允许所有代理,但是如果无法直接访问应用程序,则可以接受您的需要。
答案 2 :(得分:0)
由于使用Spring 5,决定采用下一个解决方案(安全配置):
http
.addFilterBefore(new ForwardedHeaderFilter(), OAuth2AuthorizationRequestRedirectFilter.class)
x-forwarded-* 标头参数现在已正确处理。