2012-09-13 72 views
3

我试图尽量减少我的web应用程序的配置,和我想删除的事情之一是端口号映射:获取相应的HTTPS端口号HTTP端口在Tomcat中

  • HTTP:80 - > HTTPS:443
  • HTTP:9080 - > HTTPS:9443

由于配置已经在的conf/server.xml中存在,我不希望我的应用程序重复这些设置。必须改变(并记住改变)多个配置文件是一种痛苦。此外,只要它支持http和https,应用程序不应该关心它部署到的环境/容器。

我有以下的在我的web.xml中配置,但我需要能够建立除HTTPS URL来重定向:

<security-constraint> 
    <web-resource-collection> 
     <web-resource-name>secure</web-resource-name> 
     <url-pattern>/https/*</url-pattern> 
    </web-resource-collection> 
    <user-data-constraint> 
     <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

以上块告诉servlet容器的HTTP请求重定向到其https对应。显然,Tomcat知道请求来自哪个连接器,查找该连接器的server.xml中的“redirectPort”属性并使用该URL来构建https URL。

根据这些以前的/相关的问题,似乎没有要得到相应的HTTPS端口的请求的标准或特定的Tomcat方式:

TL; DR:我的问题是,您有什么想法获得相应的https端口号为不安全的请求,而无需在您的webapp中明确配置它们?

我有一个想法是从webapp到自身到使用与当前请求相同的端口号的安全约束后面的路径进行http调用,并从响应中解析重定向位置。当然,这些回复应该被缓存。有更直接的方法吗?

编辑:增加了一个answer与该想法的代码。

回答

-1

我不明白你为什么需要知道安全端口号。如果被访问的资源被标记为需要SSL,Tomcat将发送重定向到https:以及相应的安全端口。这就是server.xml中的配置。

+0

嗨EJP,请考虑一个不安全的主页包含注册表单的情况(例如http://facebook.com,http://twitter.com)。如何在不知道https端口的情况下生成表单操作的https URL(如果它不是443)? Tomcat重定向是不够的,因为用户在他/她被重定向到安全URL之前将不安全地发布他/她的数据。 – andy

1

如果有人想知道如何实现我在问题中提供的想法,下面是一些示例代码,我将它们放在一起来测试它。尽管如此,我不认为我会采用这种解决方案。

这适用于问题主体的安全约束块。

private static final String HTTPS_CONSTRAINED_PATH = "/https"; 

private static ConcurrentHashMap<String, Integer> resolvedHttpsPortMap = new ConcurrentHashMap<String, Integer>(); 
private static final ReentrantLock portMapLock = new ReentrantLock(); 

public static int resolveHttpsPort(HttpServletRequest request) { 
    if (request.isSecure()) return request.getServerPort(); 
    String key = request.getServerName() + ":" + request.getServerPort(); 
    Integer port = resolvedHttpsPortMap.get(key); 
    if (port == null) { 
     portMapLock.lock(); 
     try { 
      port = resolvedHttpsPortMap.get(key); 
      if (port == null) { 
       URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath() + HTTPS_CONSTRAINED_PATH); 
       HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
       if (conn.getResponseCode() != 301 && conn.getResponseCode() != 302 
         && conn.getResponseCode() != 303 && conn.getResponseCode() != 307) { 
        throw new IllegalStateException("Got unexpected response code " + conn.getResponseCode() + " from URL: " + url); 
       } 
       String location = conn.getHeaderField("Location"); 
       if (location == null) { 
        throw new IllegalStateException("Did not get a Location header in the response from URL: " + url); 
       } 
       URL locationUrl = new URL(location); 
       port = locationUrl.getPort(); 
      } 
     } catch (Exception e) { 
      logger.warn("Could not determine corresponding HTTPS port for '" + key + "'", e); 
     } finally { 
      if (port == null) port = -1; 
      resolvedHttpsPortMap.put(key, port); 
      portMapLock.unlock(); 
     } 
    } 
    return port; 
}