Configuração do proxy reverso do Apache para sites com Spring Security

2

Estou usando um aplicativo Spring MVC que usa o Spring Security para login. Eu estou usando o Apache Webserver como proxy e Tomcat. Abaixo está o meu arquivo /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

Meu problema agora é acessar o site como:

www.example.com/myapp

onde eu quero acessá-lo como

www.example.com

Eu tentei brincar com ele, mas o login não funcionou corretamente. Como devo definir o ProxyPass & ProxyPassReverse para isso?

    
por AAgg 25.12.2014 / 19:24

3 respostas

4

Eu tenho lutado com esse mesmo problema por alguns dias e eu poderia ter quebrado isso. Eu sou novo no Spring Security, então não tome isso como um evangelho! Outros podem objetar ... Estou usando o Apache 2.4 (no OS X) e o Spring Security 4.1.1.

Tudo correu perfeitamente bem a correr localmente, mas sempre que foi implementado para correr atrás de um proxy reverso, recebi erros 404 sempre que iniciei sessão. Depois de muito arranhão e pesquisando no Google, aqui está o que encontrei:

(Como não tenho pontos de reputação suficientes para postar mais do que 2 links, tive que usar um espaço depois de 'http: //' para as URLs!)

Suponha que o Apache e o Tomcat estejam sendo executados no mesmo host (localhost) com o Apache configurado para solicitações de proxy de www.example.com em nosso aplicativo da web implantado no caminho de contexto '/ webapp'

    ProxyPass / http://localhost:8080/webapp/
    ProxyPassReverse / http://localhost:8080/webapp/
  1. Cliente externo solicita URL protegida: http: // www.example.com/secret

    GET /secret HTTP/1.1
    
  2. O Apache faz proxy para http: // localhost: 8080 / webapp / secret

  3. Um dos filtros de segurança do Spring intervém e responde com um redirecionamento para / login

    HTTP/1.1 302 Found
    Location: http://www.example.com/login
    
  4. O navegador busca URL

    GET /login HTTP/1.1
    
  5. O Apache faz proxy para http: // localhost: 8080 / webapp / login

  6. O Spring responde com sua página de login padrão

    HTTP/1.1 200 OK
    
  7. O interessante a ser observado neste momento é que o formulário de login gerado pelo Spring prefixa o elemento de ação forms com o caminho do contexto (por exemplo, action="/ webapp / login"). Quando você clica no botão enviar, um POST é executado para o URL / webapp / login

    POST /webapp/login HTTP/1.1
    

Agora temos um problema. Quando o Apache faz proxy para o servidor backend, a URL resultante será http: // localhost / webapp / webapp / login. Você pode ver isso no log catalina.out mostrando que não existe um manipulador que possa manipular a solicitação, pois o caminho do contexto agora está aparecendo duas vezes na URL.

O problema aqui é que as diretivas ProxyPass e ProxyReversePass (módulo mod_proxy) apenas modificam o cabeçalho HTTP Location, a URL é deixada intacta. O que é necessário é retirar o caminho do contexto do URL antes que ele atinja o proxy que o adicionará novamente. O RewriteRule do Apache parece funcionar:

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

Embora isso resolvesse os erros 404 e eu pudesse ver que o Apache estava agora fazendo proxy para a URL correta, eu estava constantemente recebendo a página de login novamente toda vez que eu logado. Esse próximo bit de configuração parece resolver isso:

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

Eu acredito que isso pode ser porque o proxy estava causando o domínio e caminho no cookie para ser definido incorretamente, mas eu tenho que ler mais sobre isso!

Espero que isso ajude alguém mais por aí, e pessoas com mais experiência do que eu nesta área podem comentar se esta é uma solução justa ...

    
por 31.07.2016 / 02:00
0

Você pode definir virtualhosts. Algo como isso deveria fazer, eu acho:

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

Eu rodei uma configuração como esta com o Apache 2.4 aqui

    
por 19.01.2015 / 14:39
0

Isso é possível se você definir seu próprio Filtro & HttpServletRequestWrapper, com o filtro inserido antes do filtro Spring Security. Ao substituir o "getContextPath" para retornar a string vazia, você pode configurar um proxy reverso nginx / apache. (o conceito básico disso vem de: link , mas isso não cobre o caminho do contexto)

No seu software de gerenciamento de dependências, adicione a API do Servlet:

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

(isso obviamente pressupõe que você estará executando em um contêiner Tomcat / J2EE).

E, em seu projeto ou possivelmente em uma biblioteca compartilhada, defina duas classes:

    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 {}

   }

E depois o wrapper:

    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();
            }
        }
    }

E, em seguida, adicione o filtro correto antes do filtro de mola (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>

Então, no bloco do servidor 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;

  }
    
por 05.10.2015 / 22:41