Bug 1030050 - The FormAuthenticator loses post data
Summary: The FormAuthenticator loses post data
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: JBoss Enterprise Application Platform 6
Classification: JBoss
Component: Web
Version: 6.1.1
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ER9
: EAP 6.3.0
Assignee: Rémy Maucherat
QA Contact: Radim Hatlapatka
Russell Dickenson
URL:
Whiteboard:
Depends On:
Blocks: 1076163
TreeView+ depends on / blocked
 
Reported: 2013-11-13 19:48 UTC by Derek Horton
Modified: 2014-10-25 12:37 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2014-08-06 14:39:05 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Derek Horton 2013-11-13 19:48:29 UTC
Description of problem:

The FormAuthenticator loses post data.

Here is the setup:

example.html is a unprotected form that posts to a protected servlet
(ExampleServlet).  The servlet simply prints out the form data that it
receives.

When I submit the form, I am correctly prompted for a username/password.
On successful authentication, my servlet is called but it cannot
retrieve the form/post data.

I have recreated this issue on EAP 6.1.0 and 6.1.1.  However, the same
application works fine on EAP 5.2.0.

It looks like the FormAuthenticator is losing the post data because the
following if statement evaluates to false in saveRequest():

            if (body.getLength() == 0) {
                // It means that parameters have already been parsed.
                Enumeration e = request.getParameterNames();
                for ( ; e.hasMoreElements() ;) {
                    String name = (String) e.nextElement();
                    String[] val = request.getParameterValues(name);
                    saved.addParameter(name, val);
                }
            }

As a result, the parameters are not stored in the SavedRequest object.

The interesting thing is that if I call Request.getParameterMap() in the 
authenticator, then the if body.getLength() is 0 and the if statement is
entered (storing the parameters).

Comment 1 Aaron Ogburn 2013-11-13 22:22:30 UTC
When the parameters aren't parsed, the request body should be stored in a SavedRequest object.  After authentication, FormAuthenticator.restoreRequest should restore that body.  Debugging locally, I could clearly see the parameter there in the body set in the SavedRequest, so it's a matter of the request parsing the parameter from that saved body.  But it looks like connector.Request.parseParameters() was returning at this line, which is before it would ready the body:

         if (usingInputStream || usingReader)
             return;


The FormAuthenticator uses the inputstream to set the usingInputStream flag so looks like the issue is around here.  Haven't had a chance to test on EAP 5 to see how parseParameters or the inputstream flag is behaving differently.  But if you force the FormAuthenticator to read the body and get the parameters, the parameters themselves are then placed in and fetched from the SavedRequest object, so we don't reach the failure point trying to parse the parameters later from the restored request body.

Comment 2 Derek Horton 2013-12-03 22:40:54 UTC
The EAP 6 version of the FormAuthenticator has the following loop just above where the POST is handled in the restoreRequest method:

498         // Swallow any request body since we will be replacing it
499         byte[] buffer = new byte[4096];
500         InputStream is = request.getInputStream();
501         while (is.read(buffer) >= 0) {
502             // Ignore request body
503         }
504 
505         if ("POST".equalsIgnoreCase(saved.getMethod())) {

If I comment out that while loop, then the FormAuthenticator does not
lose the post data.

Comment 3 Rémy Maucherat 2013-12-05 15:27:08 UTC
I synced stuff with r2320, so maybe you can test it. Not using createInputStream could cause problems, that's one of the improvements.

Comment 4 Derek Horton 2013-12-05 21:46:46 UTC
It looks like r2320 only made changes to the FormAuthenticator so I grabbed it and ran a quick test.  Unfortunately, it did not resolve the issue.

Using createInputStream() changes the behavior up a bit but it
doesn't resolve the issue.

I think I have narrowed the issue down to the "BODY_REPLAY" logic.  The
POST section of the FormAuthenticator.restoreRequest() appears to
trigger this logic:

        if ("POST".equalsIgnoreCase(saved.getMethod())) {                                                              
            ByteChunk body = saved.getBody();                                                                          
                                                                                                                       
            if (body != null && body.getLength() > 0) {                                                                
                request.clearParameters();                                                                             
                request.getCoyoteRequest().action                                                                      
                    (ActionCode.ACTION_REQ_SET_BODY_REPLAY, body);    

This causes the Http11Processor to create a SavedRequestInputFilter and
add it as an ActiveFilter to the request's InternalInputBuffer.

Unfortunately, during the remaining processing, the
SavedRequestInputFilter's doRead() method is never called.

The problem appears to be that the connector.InputBuffer's eof variable
is set to true too early??  As a result,
connector.InputBuffer.realReadBytes() returns with a -1 before
coyoteRequest.doRead() is called.  I was able to use jdb to set eof to
false which allowed coyoteRequest.doRead() to get called.  This resulted
in the SavedRequestInputFilter.doRead() getting called which appears to
have correctly restored the request.

I'm not sure how this should be resolved in the code though.  Perhaps
connector.InputBuffer.recycle() needs to be called?

Comment 7 Radim Hatlapatka 2014-07-14 16:24:41 UTC
Verified in EAP 6.3.0.ER9


Note You need to log in before you can comment on or make changes to this bug.