How to pass GenericFilterBean data to WebSecurityConfigurerAdapter in Spring Boot?

ASR4 :

I am trying to redirect http to https in my spring boot application using:

http.requiresChannel().anyRequest().requiresSecure();

But I am getting ERR_TOO_MANY_REDIRECTS. The reason for this is that the load balancer converts all the https to http and directs the http to port 8082, therefore the app never seems to see the https.

I tried to fix this by adding isSecure before the http to https redirection, like this in my configuration:

public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
        //variables
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/css/**", "/js/**", "/admin/**")
                .permitAll().anyRequest().authenticated().and()
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
                .formLogin().loginPage("/login").permitAll().and()
                .logout().logoutSuccessUrl("/");

        //hsts
        http.headers().httpStrictTransportSecurity()
        .includeSubDomains(true).maxAgeInSeconds(31536000); 

        http.addFilterBefore(new IsSecureFilter(), ChannelProcessingFilter.class);

        //https compulsion
        if(!isSecureFilter.isSecure()) {
                http.requiresChannel().anyRequest().requiresSecure();
        }           
    }
       //rest of the code
}

I am trying to use HttpServletRequestWrapper so that I can repeatedly use isSecure in WebSecurityConfiguration above through the IsSecureFilter I have created below, to prevent infinite redirects:

public class RequestWrapper extends HttpServletRequestWrapper {
    private boolean isSecure;

    public RequestWrapper(HttpServletRequest request) throws IOException
    {
        //So that other request method behave just like before
        super(request);
        this.isSecure = request.isSecure();       
    }

    //Use this method to read the request isSecure N times
    public boolean isSecure() {
        return this.isSecure;
    }  
}

Below is the filter that I am trying to inject in WebSecurityConfiguration, to use it's isSecure value above :

@Component
public class IsSecureFilter extends GenericFilterBean {

    private boolean isSecure;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = new RequestWrapper((HttpServletRequest) request);

        this.isSecure = req.isSecure();

        chain.doFilter(req, response);
    }

    public boolean isSecure() {
        return this.isSecure;
    }
}

So running the above code and putting example.com/login in the browser does redirect to https://example.com/login, but i am still getting ERR_TOO_MANY_REDIRECTS. I can't understand what I am doing wrong? My first thoughts are:

  • Can I inject the IsSecureFilter in WebSecurityConfiguration to retrieve isSecure?

  • Am I adding the IsSecureFilter filter in a correct way to the configuration.

  • Is the wrapper filter relationship defined correctly?

EDIT

1) I changed http.addFilterAfter(new isSecureFilter(), ChannelProcessingFilter.class); to http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);, still no effect.

2) I tried changing http.addFilterBefore(isSecureFilter, ChannelProcessingFilter.class); to http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class); but that still did not change anything.

Qing :

Here is the solution to resolve this issue. Based on investigation, since 8080 and 8082 are used to identify HTTP traffic and HTTPS traffic, some code are added to check the port number instead "isSecure" to decide whether redirect HTTP request or not. The code is like following:

public class IsSecureFilter extends GenericFilterBean {

private boolean isSecure;
private int port;

@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = new RequestWrapper((HttpServletRequest) request);
    HttpServletResponse res = (HttpServletResponse) response;
    this.isSecure = req.isSecure();
    this.port = req.getLocalPort();


    System.out.println("[DEBUG] : isSecure FILTER :: " + isSecure);
    System.out.println("[DEBUG] : port FILTER :: " + port);
    System.out.println("[DEBUG] : URL :: " + req.getRequestURL());
    String url = req.getRequestURL().toString().toLowerCase();
    if(url.endsWith("/login") && url.startsWith("http:") && port == 8080){
        url = url.replace("http:", "https:");
        String queries = req.getQueryString();
        if (queries == null) {
            queries = "";
        } else {
            queries = "?" + queries;
        }
        url += queries;
        res.sendRedirect(url);
    }
    else {
        chain.doFilter(req, response);
    }
}

public boolean isSecure() {
    return this.isSecure;
}

public boolean setIsSecure(boolean isSecure) {
    return this.isSecure = isSecure;
}

public int getPort() {
    return port;
}

public void setPort(int port) {
    this.port = port;
}

}

and remove http.requiresChannel().anyRequest().requiresSecure() in WebSecurityConfiguration class.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=152334&siteId=1