3

Web アプリケーションの構成を最小限に抑えようとしていますが、削除したいものの 1 つはポート番号のマッピングです。

  • 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>

上記のブロックは、サーブレット コンテナーに、http 要求を対応する https にリダイレクトするように指示します。明らかに、Tomcat は要求の送信元のコネクタを認識し、server.xml でそのコネクタの「redirectPort」属性を検索し、それを使用して https URL を構築します。

これらの以前の/関連する質問によると、リクエストに対応する https ポートを取得する標準または tomcat 固有の方法はないようです。

TL;DR: 私の質問は、Web アプリケーションで明示的に構成せずに、安全でない要求に対応する https ポート番号を取得するためのアイデアはありますか?

私が持っている 1 つのアイデアは、現在の要求と同じポート番号を使用して、webapp からそれ自体への http 呼び出しをセキュリティ制約の背後のパスに作成し、応答からリダイレクトの場所を解析することです。もちろん、応答はキャッシュする必要があります。もっと簡単な方法はありますか?

編集:アイデアのコードを含む回答を追加しました。

4

2 に答える 2

1

質問で提供したアイデアを実装する方法を誰かが知りたい場合のために、それをテストするためにまとめたサンプルコードを次に示します。しかし、私はこの解決策を採用しているとは思いません。

これは、質問本文の security-constraint ブロックで機能します。

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;
}
于 2012-09-14T03:08:51.060 に答える
-1

安全なポート番号を知る必要がある理由がまったくわかりません。アクセスされているリソースが SSL を必要としているとマークされている場合、Tomcat は https: と適切なセキュア ポートにリダイレクトを送信します。それが server.xml の構成の目的です。

于 2012-09-13T22:12:31.980 に答える