0

I have to read HttpServletRequest multiple times. I have wrapped HttpServletRequest like said in those posts Http Servlet request lose params from POST body after read it once

In my filter class which extends AbstractAuthenticationProcessingFilter, i can consume and chain request in successfulAuthentication method since it has chain parameter. But in addition to those solutions i have to chain request between attempt and succesful authentication steps:

public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
            // wrapping request and consuming
        }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // Since i couldn't chain wrapped httpServletRequest from attemptAuthentication step, this request still gets non-wrapping one and  inputstream is empty
    }

How can i pass wrapped request from attemptAuthentication to successfulAuthentication?

cmlonder
  • 2,370
  • 23
  • 35

2 Answers2

2

This is an old question but in case someone gets the same problem:

You can wrap a request like suggested in the previous answer but you need to wrap it before it gets filtered by Authentication filter:

Spring security configuration will look something like this:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthFilter authFilter = new AuthFilter();
        WrapperFilter wrapperFilter = new WrapperFilter();
        http    .cors()
                .and()
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(exceptionHandler)
                .and()
                .authorizeRequests()
                .antMatchers("/v1/*", "/api/*")
                .authenticated()
                .and()
                .addFilterBefore(authFilter, BasicAuthenticationFilter.class)
                .addFilterBefore(wrapperFilter, AuthFilter.class);
    }

So that wrapper filter goes before your auth filter and wrapper filter's doFilter wraps the request and passes it on:

@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        MultiReadHttpServletRequest wrapper = new MultiReadHttpServletRequest((HttpServletRequest) request);
        chain.doFilter(wrapper, response);
    }

And MultiReadHttpServletRequest is the following:

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {

    private byte[] body;

    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
        try {
            body = IOUtils.toByteArray(request.getInputStream());
        } catch (IOException ex) {
            body = new byte[0];
        }
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStream() {
            ByteArrayInputStream wrapperStream = new ByteArrayInputStream(body);

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return wrapperStream.read();
            }
        };
    }
}
Iwavenice
  • 556
  • 5
  • 22
0

There is no such way. The only thing you can do is wrap the request every time you gonna read it in one more filter. Just wrap the request every time before you read it copying body.

See some working code for a wrapper e.g. here

Dmitry Senkovich
  • 5,521
  • 8
  • 37
  • 74
  • Yes but wrapping is solution where i can chain wrapped object. But in this scenario succesfulAuthentication can't get wrapped request from atteptAuthentication step. How can i override HttpServletRequest in attemptAuthentication step like chain? – cmlonder Jun 23 '17 at 07:28
  • @cmlonder Do you want to replace the current instance of HttpServletRequest being passed to the instance of you wrapper and pass it along the rest of you filter and servlet chain? – Dmitry Senkovich Jun 23 '17 at 07:33
  • attemptAuthentication step is fired before succesfulAuthentication step by Spring. Wrapping is making wrapped request to be consumed multiple times. But to use this, i have to pass wrapped request from attemptAuthentication to succesfulAuthentication. If there was not any attemptAuthentication step, i was doing this eaisly in successfulAuthentication step by passing my wrapped request like chain(wrappedRequest, response) and it is redirecting to the corresponding web service. I just want to do this between attmpt and succesful auth steps but they are using different request objects. – cmlonder Jun 23 '17 at 07:47
  • @cmlonder ok, you want to do the same but one time only. so the answer is the same: unfortunately, you can't – Dmitry Senkovich Jun 23 '17 at 07:55