I am implementing a RESTful API in Grails, and use a custom authentication scheme that involves signing the body of the request (in a manner similar to Amazon's S3 authentication scheme). Therefore, to authenticate the request, I need to access the raw POST or PUT body content to calculate and verify the digital signature.
I am doing authentication in a beforeInterceptor in the controller. So I want something like request.body to be accessible in the interceptor, and still be able to use request.JSON in the actual action. I am afraid if I read the body in the interceptor using getInputStream or getReader (methods provided by ServletRequest), the body will appear empty in the action when I try to access it via request.JSON.
I am migrating from Django to Grails, and I had the exact same issue in Django a year ago, but it was quickly patched. Django provides a request.raw_post_data attribute you can use for this purpose.
Lastly, to be nice and RESTful, I'd like this to work for POST and PUT requests.
Any advice or pointers would be greatly appreciated. If it doesn't exist, I'd prefer pointers on how to implement an elegant solution over ideas for quick and dirty hacks. =) In Django, I edited some middleware request handlers to add some properties to the request. I am very new to Groovy and Grails, so I have no idea where that code lives, but I wouldn't mind doing the same if necessary.
Best Solution
It is possible by overriding the HttpServletRequest in a Servlet Filter.
You need to implement a HttpServletRequestWrapper that stores the request body: src/java/grails/util/http/MultiReadHttpServletRequest.java
A Servlet Filter that overrides the current servletRequest: src/java/grails/util/http/MultiReadServletFilter.java
Then you need to run
grails install-templates
and edit the web.xml in src/templates/war and add this after the charEncodingFilter definition:You should then be able to call
request.inputStream
as often as you need.I haven't tested this concrete code/procedure but I've done similar things in the past, so it should work ;-)
Note: be aware that huge requests can kill your application (OutOfMemory...)