jricher
jricher

Reputation: 2677

Save and re-use a request in a servlet filter?

I am writing an OpenID filter based on the JOID library to allow applications to transparently authenticate against our local OpenID Server. Since OpenID works via HTTP redirects, I end up losing the original request object in the process, especially if it's a POST with a data body. Is it possible to save the request object in a way that I can reuse it later in the transaction, after the user has been authenticated? Even just saving the message body itself should suffice, as I can preserve the query URL easily enough with a roundtrip redirect (by using the OpenID's return-to-url).

I want to make this completely transparent to the underlying servlets, so they behave the same whether the user went through the OpenID flow for this particular request or just has a valid/authenticated local session.

Upvotes: 7

Views: 4083

Answers (4)

jricher
jricher

Reputation: 2677

For what it's worth (and for anyone coming here in the future), after fighting with this for about another week, I ended up switching my app over to use Spring Security entirely instead of a standalone custom filter and it works great. The Spring Security framework handles a lot of the odd issues with redirects and postponed requests that I was starting to have to write on my own.

Thanks to everyone for their suggestions.

Upvotes: 0

BalusC
BalusC

Reputation: 1109132

Store the data of interest (request parameters, request attributes, etc) in a Map in session scope by an unique ID as key which you add to the return-to-url.

String id = UUID.randomUUID().toString();
DataOfInterest data = new DataOfInterest(request);
Map<String, DataOfInterest> map = (Map<String, DataOfInterest) session.getAttribute("dataOfInterest");
map.put(id, data);
returnToUrl += "?token=" + URLEncoder.encode(id, "UTF-8");
// ...

And then when it comes back, use HttpServletRequestWrapper to wrap the current request wherein you override the getParameter() and consorts to return the original data of interest. Do this in a Filter.

String id = request.getParameter(token);
Map<String, DataOfInterest> map = (Map<String, DataOfInterest) session.getAttribute("dataOfInterest");
DataOfInterest data = map.remove(id);
chain.doFilter(new HttpServletRequestWithDataOfInterest(request, data), response);

The HttpServletRequestWithDataOfInterest can look like this:

public class HttpServletRequestWithDataOfInterest extends HttpServletRequestWrapper {

    private DataOfInterest data;

    public HttpServletRequestWithDataOfInterest(HttpServletRequest request, DataOfInterest data) {
        super(request);
        this.data = data;
    }

    public String getParameter(String name) {
        return data.getParameter(name);
    }

    public String[] getParameterValues(String name) {
        return data.getParameterValues(name);
    }

    // Etc, only when necessary.
}

Note: any obvious nullcheck handling etc is up to you.

Upvotes: 7

axtavt
axtavt

Reputation: 242716

For general purpose usage it would be more complex than save just a request body, you also need to save headers and so on.

You may check how it's implemented in Spring Security.

Upvotes: 2

duffymo
duffymo

Reputation: 308918

No, you can't save a request. But you can have your filter create a session and add the object to session scope. Objects that have access to the session can use any object they find.

Upvotes: 1

Related Questions