title: Fronting Tomcat with Apache for Spring MVC ERR_TOO_MANY_REDIRECTS error
body: <p>I have a Spring MVC (v4.3.1) Web application running on a Tomcat server(v8.5) which is fronted by an Apache(v2.4) application server being used as a reverse proxy. </p>
  
  <p>I have SSL certificate installed on Apache so that it handles all secure(:443) and non-secure (:80) incoming requests and redirects them to the Tomcat instance.</p>
  
  <p>I want to handle all communication as secured (SSL) with the outside world. But inside between Apache and Tomcat, it is not necessary to communicate through the secure port. That is why Apache redirects all <strong>HTTP</strong> requests to <strong>HTTPS</strong> </p>
  
  <p>I also use Spring Security (v4) to handle all user authorization/authentication work, so I have even Register/Login/Logout, etc. </p>
  
  <p>My current server architecture is shown below,</p>
  
  <p><a href="https://i.stack.imgur.com/k2lwP.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/k2lwP.jpg" alt="enter image description here"></a></p>
  
  <p>After giving the summary, the problem is,<br>
  Whenever <strong>I try to access my login page</strong>, I am getting <strong>ERR_TOO_MANY_REDIRECTS</strong> error from Chrome.</p>
  
  <p><strong>Moreover</strong>, when I access Tomcat Manager (<a href="http://myapp.net:8080/manager/html" rel="nofollow noreferrer">http://myapp.net:8080/manager/html</a>) and click on my application URL (/MyApp-1.0.0) then ** I can successfully view** my login page without https. (After clicking the application link deployed on tomcat, it opens page: <a href="http://myapp.net:8080/MyApp-1.0.0/login" rel="nofollow noreferrer">http://myapp.net:8080/MyApp-1.0.0/login</a>) I believe it shows that there is no problem when my web application is running on tomcat instance. They are good together. It suspects me that my problem starts from Apache with SSL.</p>
  
  <p><strong>Apache configuration for virtual hosts:</strong></p>
  
  <pre><code>Listen 80
  Listen 443
  
  &lt;VirtualHost *:80&gt;
  
     ServerAdmin emrecaglar@gmail.com
     ServerName myapp.net
     ServerAlias www.myapp.net
     Redirect  / https://www.myapp.net/
  
  &lt;/VirtualHost&gt;
  &lt;VirtualHost *:443&gt;
  
          ServerName  myapp.net
          ServerAlias www.myapp.net
          ProxyPreserveHost On
          ProxyPass /  http://127.0.0.1:8080/MyApp-1.0.0/
          ProxyPassReverse /  http://127.0.0.1:8080/MyApp-1.0.0/
  
          SSLEngine on
          SSLCertificateFile /root/WWW.myapp.NET.crt
          SSLCertificateKeyFile /root/www.myapp.net.key
          SSLCertificateChainFile /root/dv_chain.txt
  
          ErrorLog ${APACHE_LOG_DIR}/error.log
          CustomLog ${APACHE_LOG_DIR}/access.log combined
  
  &lt;/VirtualHost&gt;
  </code></pre>
  
  <p>I dont want to use rewrite rules unless it is critical. I want to handle with Redirect.</p>
  
  <p><strong>Tomcat server.xml configuration :</strong>  </p>
  
  <pre><code>&lt;Connector   port="8080" protocol="HTTP/1.1"  connectionTimeout="20000" /&gt;
  </code></pre>
  
  <p>There is no connector defined for <strong>:8443</strong> as I dont want Tomcat to run on a secure port. Tomcat will communicate only with Apache server.</p>
  
  <p><strong>Spring Security configuration:</strong></p>
  
  <pre><code>@Override
  protected void configure(HttpSecurity http) throws Exception {
         http
             .authorizeRequests()
             .antMatchers("/static/**").permitAll()
             .antMatchers("/register*").permitAll()
             .anyRequest().authenticated()
          .and()
             .formLogin()
                    .loginPage("/login")
                    .failureUrl("/login?error=true")
                    .defaultSuccessUrl("/view/home")
                    .permitAll()
          .and()
              .logout().logoutUrl("/logout").logoutSuccessUrl("/login? 
               logout").invalidateHttpSession(true).deleteCookies("auth_code", 
                "JSESSIONID").permitAll();
      }
  
  }  
  </code></pre>
  
  <p>I have also read some posts about permitAll(), and anonymous() is different, so permitAll() might even trigger a redirect loop so for login page it should be anonymous() however I couldn't validate it. I believe it also needs additional role from spring security perspective. </p>
  
  <p><strong>My Spring Controllers:</strong></p>
  
  <pre><code> @RequestMapping(value = "/", method = RequestMethod.GET)
      public String homePage(Principal principal) {
  
          /**
           * Initialize session user if not initialized
           */
  
            return "redirect:/view/home";
      }
  </code></pre>
  
  <p>another:</p>
  
  <pre><code>@Controller
  @RequestMapping(value = "/view")
  public class ViewController
  {
   @RequestMapping(value = "/home")
      public String getHomePage(Model model, Principal principal)
      {
  
          //some logic
  
          return "home";
      }
  }
  </code></pre>
  
  <p>Web MVC config for login:</p>
  
  <pre><code>@Override
      public void addViewControllers(ViewControllerRegistry registry) {
          registry.addViewController("/login").setViewName("login");
  
      }
  </code></pre>
  
  <p>I have related <strong>view resolvers</strong> and <strong>views (home.jsp, login.jsp)</strong></p>
  
  <p><strong>Chrome Developer console debug outputs for redirects</strong>  </p>
  
  <pre><code> General
      Request URL: http://www.myapp.net/MyApp-1.0.0/login
      Request Method: GET
      Status Code: 302 Found
      Remote Address: 207.154.208.158:80
      Referrer Policy: no-referrer-when-downgrade
   Response Header
      HTTP/1.1 302 Found
      Date: Sat, 17 Nov 2018 08:40:04 GMT
      Server: Apache/2.4.18 (Ubuntu)
      Location: https://www.myapp.net/MyApp-1.0.0/login
      Content-Length: 314
      Keep-Alive: timeout=5, max=92
      Connection: Keep-Alive
  
   Request Header
      Content-Type: text/html; charset=iso-8859-1
      GET /MyApp-1.0.0/login HTTP/1.1
      Host: www.myapp.net
      Connection: keep-alive
      Pragma: no-cache
      Cache-Control: no-cache
      Upgrade-Insecure-Requests: 1
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate
      Accept-Language: en-US,en;q=0.9
      Cookie: JSESSIONID=8A4E001A841DBC4D55509605FF3E7E23
  
  
  
  
  General
      Request URL: https://www.myapp.net/MyApp-1.0.0/login
      Request Method: GET
      Status Code: 302 
      Remote Address: 207.154.208.158:443
      Referrer Policy: no-referrer-when-downgrade
  Response Header
      Cache-Control: no-cache, no-store, max-age=0, must-revalidate
      Connection: Keep-Alive
      Content-Length: 0
      Date: Sat, 17 Nov 2018 08:40:04 GMT
      Expires: 0
      Keep-Alive: timeout=5, max=92
      Location: http://www.myapp.net/MyApp-1.0.0/login
      Pragma: no-cache
      Server: Apache/2.4.18 (Ubuntu)
      X-Content-Type-Options: nosniff
      X-Frame-Options: DENY
      X-XSS-Protection: 1; mode=block
   Request Header
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate, br
      Accept-Language: en-US,en;q=0.9
      Cache-Control: no-cache
      Connection: keep-alive
      Cookie: JSESSIONID=8A4E001A841DBC4D55509605FF3E7E23
      Host: www.myapp.net
      Pragma: no-cache
      Upgrade-Insecure-Requests: 1
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
  </code></pre>
  
  <p><strong>Requests loop between these two requests from HTTPS to HTTP and HTPPS again</strong>  </p>
  
  <p><strong>Apache access.log</strong></p>
  
  <pre><code>67.171.8.29 - - [17/Nov/2018:08:41:59 +0000] "GET /MyApp-1.0.0/login HTTP/1.1" 302 429 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36"
  </code></pre>
  
  <p><strong>Apache error.log</strong>  </p>
  
  <pre><code>[Sat Nov 17 08:37:59.376633 2018] [mpm_event:notice] [pid 20673:tid 140534533293952] AH00489: Apache/2.4.18 (Ubuntu) mod_jk/1.2.41 OpenSSL/1.0.2g configured -- resuming normal operations
  [Sat Nov 17 08:37:59.376707 2018] [core:notice] [pid 20673:tid 140534533293952] AH00094: Command line: '/usr/sbin/apache2'
  </code></pre>
  
  <p>As you can see, i dont have any SSL related code / config for my spring mvs application and tomcat. They dont need to be aware of that as i want apache be only responsible for SSL and handling https requests and directing to Tomcat. </p>
  
  <p>What i am missing here so that i am causing a redirection loop?</p>
  
  <p>Thanks</p>