web-dev-qa-db-ja.com

SpringSecurityを備えたサイトのApacheリバースプロキシ設定

ログインにSpringSecurityを使用するSpringMVCアプリを使用しています。 ApacheWebサーバーをプロキシおよびTomcatとして使用しています。以下は私の/etc/Apache2/sites-enabled/example.com.confファイルです。

ServerAdmin [email protected]
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html

ProxyPreserveHost On
ProxyRequests off

ProxyPass /myapp/j_spring_security_check http://XX.YY.ZZ.WW:8080/myapp/j_spring_security_check
ProxyPassReverse /myapp/j_spring_security_check http://XX.YY.ZZ.WW:8080/myapp/j_spring_security_check

ProxyPass /myapp http://XX.YY.ZZ.WW:8080/myapp
ProxyPassReverse /myapp http://XX.YY.ZZ.WW:8080/myapp

私の問題は、次のように自分のサイトにアクセスする必要があることです。

www.example.com/myapp

どこにアクセスしたいのか

www.example.com

試してみましたが、ログインがうまくいきませんでした。これに対してProxyPassとProxyPassReverseをどのように設定する必要がありますか?

2
AAgg

私はこの同じ問題に数日間苦労していて、それをクラックしたかもしれません。私はSpringSecurityを初めて使用するので、これを福音と見なさないでください。他の人は反対するかもしれません...私はApache2.4(OS X上)とSpring Security4.1.1を使用しています。

すべてがローカルで完全に正常に実行されましたが、リバースプロキシの背後で実行するようにデプロイされると、ログインするたびに404エラーが発生しました。頭をかいてグーグルした後、次のことがわかりました。

(2つ以上のリンクを投稿するのに十分なレピュテーションポイントがないため、URLの「http://」の後にスペースを使用する必要がありました!)

ApacheとTomcatが同じホスト(localhost)で実行されており、Apacheがwww.example.comからコンテキストパス「/ webapp」の下にデプロイされたWebアプリにリクエストをプロキシするように構成されているとします。

    ProxyPass / http://localhost:8080/webapp/
    ProxyPassReverse / http://localhost:8080/webapp/
  1. 外部クライアントが保護されたURLを要求します:http://www.example.com/secret

    GET /secret HTTP/1.1
    
  2. Apacheはこれをhttp:// localhost:8080/webapp/secretにプロキシします

  3. Springのセキュリティフィルターの1つが介入し、/ loginへのリダイレクトで応答します

    HTTP/1.1 302 Found
    Location: http://www.example.com/login
    
  4. ブラウザはURLを取得します

    GET /login HTTP/1.1
    
  5. Apacheはこれをhttp:// localhost:8080/webapp/loginにプロキシします

  6. Springはデフォルトのログインページで応答します

    HTTP/1.1 200 OK
    
  7. この時点で注目すべき興味深い点は、Springによって生成されたログインフォームの前にコンテキストパス(つまり、action = "/ webapp/login")が付いていることです。次に送信ボタンをクリックすると、URL/webapp/loginに対してPOSTが実行されます

    POST /webapp/login HTTP/1.1
    

問題が発生しました。 Apacheがこれをバックエンドサーバーにプロキシすると、結果のURLはhttp:// localhost/webapp/webapp/loginになります。これはcatalina.outログで確認できます。これは、コンテキストパスがURLに2回表示されているため、リクエストを処理できるハンドラーがないことを示しています。

ここでの問題は、ProxyPassおよびProxyReversePassディレクティブ(mod_proxyモジュール)がHTTP Locationヘッダーのみを変更し、URLが変更されないままになることです。必要なのは、URLからコンテキストパスを削除してから、プロキシに到達して再度追加することです。 Apacheの RewriteRule はトリックを行うようです:

RewriteRule /webapp/(.*)$ http://localhost:8080/webapp/$1 [P]

これで404エラーが解決され、Apacheが正しいURLにプロキシしていることがわかりましたが、ログインするたびにログインページが常に再表示されていました。次の設定でこれを解決できるようです。

ProxyPassReverseCookieDomain localhost www.example.com
ProxyPassReverseCookiePath /webapp/ /

これは、プロキシによってCookieのドメインとパスが正しく設定されなかったことが原因である可能性がありますが、それについてもう少し詳しく読む必要があります。

これが他の誰かに役立つことを願っています。この分野で私よりも専門知識のある人が、これが公正な解決策であるかどうかについてコメントできます...

5
Paul

これは、フィルターを挿入して独自のFilter&HttpServletRequestWrapperを定義する場合に可能ですbefore SpringSecurityフィルター。 「getContextPath」をオーバーライドして空の文字列を返すことで、nginx/Apacheリバースプロキシを設定できます。 (これの基本的な概念は次のとおりです: http://www.lacerta.be/d7/content/keeping-real-user-ip-Java-web-apps-behind-nginx-proxy 、しかし、それはコンテキストパスをカバーしていません)

依存関係管理ソフトウェアで、サーブレットAPIを追加します。

   <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>

(もちろん、これは、Tomcat/J2EEコンテナで実行することを前提としています)。

次に、プロジェクトまたは場合によっては共有ライブラリ内で、次の2つのクラスを定義します。

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import Java.io.IOException;

    public class RealIPFilter implements Filter {

         public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

             if (request instanceof HttpServletRequest) {
                chain.doFilter(new RealIPWrapper((HttpServletRequest)request), response);
             } else {
                chain.doFilter(request, response);
             }
         }

         @Override
         public void destroy() {}

         @Override
         public void init(FilterConfig config) throws ServletException {}

   }

そしてラッパー:

    public class RealIPWrapper extends HttpServletRequestWrapper {

        public RealIPWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public String getContextPath() {
            return "";
        }

        @Override
        public String getRemoteAddr() {
            String realIP = super.getHeader("X-Real-IP");
            return realIP != null ? realIP : super.getRemoteAddr();
        }

        @Override
        public String getRemoteHost() {
            try {
                return InetAddress.getByName(this.getRemoteAddr()).getHostName();
            } catch (UnknownHostException|NullPointerException e) {
                return getRemoteAddr();
            }
        }
    }

次に、正しいフィルターを追加しますbeforeスプリングフィルター(web.xml)

<filter>
    <filter-name>RealIPFilter</filter-name>
    <filter-class>RealIPFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>RealIPFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

したがって、NGINXサーバーブロックでは次のようになります。

  location / {
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $Host;
     proxy_set_header X-NginX-Proxy true;

     proxy_cookie_path /<context-path>/ /;

     proxy_pass http://localhost:8080/<context>/;
     proxy_redirect off;

  }
0
rnovak1988

仮想ホストを定義できます。このようなことをする必要があると思います:

<VirtualHost *:80>
    ServerAdmin [email protected]
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / http://localhost:8080/myapp connectiontimeout=5 timeout=30
    ProxyPassReverse / http://localhost:8080/myapp
    ServerName youname.it
</VirtualHost>

ここでApache2.4を使用してこのようなセットアップを実行します

0
Marged