dev@glassfish.java.net

Re: Strange form authentification behaviour

From: Ron Monzillo <Ronald.Monzillo_at_Sun.COM>
Date: Thu, 13 Dec 2007 19:21:06 -0500

Jan.Luehe_at_Sun.COM wrote:
> Hi Ron,
>
> Ron Monzillo wrote:
>
>> Jan,
>>
>> thanks for the explanation.
>>
>> If I undersatnd correctly, a request uri always saved. when someone
>> accesses the login page directly and the saved uri is not protected,
>> the authenticator will not be called to match the request and the
>> authentication state (that is stored in the session) is unrecognizable
>> without further processing by the authenticator (including request
>> matching). As such it will not be applied to subsequent requests.
>>
>> when the authenticator knows that that the redirection will not result
>> in the authenticator being recalled to match the saved request
>> (because the saved uri is not protected), then the authenticator will
>> need to do the registration, or the effects of the authentication will
>> be lost.
>
>
>
> Yes, I believe we're on the same page. :)
>
> The code that was added in an effort to fix Issue 1933:
>
> requestURI = savedRequestURL(session);
>
> // BEGIN FIX FOR Issue 1933
> if (requestURI == null) {
> // requestURI will be null if the login form is submitted
> // directly, i.e., if there has not been any original request
> // that was stored away before the redirect to the login form was
> // issued. In this case, assume that the original request has been
> // for the context root, and have the welcome page mechanism take
> // care of it
> requestURI = hreq.getContextPath() + "/";
> saveRequest(requestURI, hreq.getMethod(), session);
> }
> // END FIX FOR Issue 1933
>
> needs to check whether the "manufactured" requestURI for the
> redirect (i.e., "<context_root>/"), which may be mapped to one of the
> webapp's welcome pages, is mapped by one of the webapp's security
> constraints. In other words, it needs to determine
> whether the redirected request will be intercepted by the
> FormAuthenticator.
> Only if the redirected request will be intercepted by the FormAuthenticator
> will matchRequest() and register() be called.
>
> If the above code determines that the redirected request will not be
> intercepted by the FormAuthenticator, it must perform the registration
> itself.
>
> Again, this is an issue only if the login page is accessed
> directly. Otherwise, the requestURI (for the protected resource) that
> caused the FormAuthenticator to be invoked in the first place will
> have been saved away, and it is certain that the redirect request (to
> this requestURI) will again be intercepted by the FormAuthenticator
> and cause matchRequest() and register() to be called.
>
> Can you confirm that this is your understanding as well?

Jan,

yes, I think so. Is there any reason why the registration must be
delayed to the resubmit of the "matching request" (in this case, and
maybe even in the general case).

when a form action arrives directly (i.e. no matching request has been
previously saved), if the registration could be performed independent of
the nature (wrt to protection) of the redirect uri, would there be any
need to save and match the subsequent request to the welcome page?

Ron
>
> Thanks,
>
>
> Jan
>
>>
>> Ron
>>
>> Roman Pokhodzhay wrote:
>>
>>> Hi Ron, Jan
>>>
>>> It seems fix for
>>> https://glassfish.dev.java.net/issues/show_bug.cgi?id=1933
>>> <https://glassfish.dev.java.net/issues/show_bug.cgi?id=1933> should
>>> help, but as for me in some strange manner. Why you can simply
>>> register user when authentification passed (you can put register
>>> method call after auth passed), and why user should be registered
>>> when he/she only requests protected resource but not direct requets
>>> to login page? Currently such method is called only within "if
>>> (matchRequest(request)) {" block.
>>> (FormAuthenticator.java). For example BasicAuthenticator do it after
>>> successful realm authentication:
>>>
>>> if (authorization != null) {
>>> String username = parseUsername(authorization);
>>> String password = parsePassword(authorization);
>>> principal = context.getRealm().authenticate(username, password);
>>> if (principal != null) {
>>> register(request, response, principal,
>>> Constants.BASIC_METHOD,username, password);
>>> String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
>>> if (ssoId != null) {
>>> getSession(request, true);
>>> }
>>> return (true);
>>> }
>>> }
>>>
>>> ________________________________
>>>
>>> From: Jan.Luehe_at_Sun.COM [mailto:Jan.Luehe_at_Sun.COM]
>>> Sent: Чт 13.12.2007 3:02
>>> To: dev_at_glassfish.dev.java.net
>>> Subject: Re: Strange form authentification behaviour
>>>
>>>
>>>
>>> Hi Ron,
>>>
>>> Ron Monzillo wrote:
>>>
>>>
>>>>>
>>>>> Hello!
>>>>>
>>>>> I can’t retrieve currently logged in user from request (When I go to
>>>>> the login page directly and login via form base method). It happens
>>>>> because method /authenticate// /in
>>>>> /org.apache.catalina.authenticator//.//FormAuthenticator// /doesn’t
>>>>> call method /register//(/org.apache.catalina.authenticator.
>>>>> AuthenticatorBase/)/ which save principal in request.
>>>>>
>>>>> But FormAuthenticator do it only in case when resource is secure and
>>>>> if the re-submit happens of the original request URI.
>>>>>
>>>>>
>>>>>
>>>>> Is this standart behavior?
>>>>>
>>>>
>>>> Roman,
>>>>
>>>> I think this is a bug (which, fwiw, appears to have been around for
>>>> some time). Thanks for bringing it to our attention.
>>>>
>>>> Have you tested, or can you suggest a fix?
>>>>
>>>> It looks to me like maybe the following block from
>>>> FormAuthenticator.authenticate should be changed to call register, and
>>>> maybe it need not call saveRequest when the current request contains
>>>> the loginAction.
>>>>
>>>> requestURI = savedRequestURL(session);
>>>> if (requestURI == null) {
>>>> // requestURI will be null if the login form is submitted
>>>> // directly, i.e., if there has not been any original request
>>>> // that was stored away before the redirect to the login form was
>>>> // issued. In this case, assume that the original request has been
>>>> // for the context root, and have the welcome page mechanism take
>>>> // care of it
>>>> requestURI = hreq.getContextPath() + "/";
>>>> saveRequest(requestURI, hreq.getMethod(), session);
>>>> }
>>>
>>>
>>>
>>>
>>>
>>> the above code was added in an effort to fix:
>>>
>>> https://glassfish.dev.java.net/issues/show_bug.cgi?id=1933
>>> ("Admin login screen gives "Error Accessing Page:" error after
>>> logging in")
>>>
>>> Assume the FORM's login page was accessed directly, so the first
>>> invocation of FormAuthenticator.authenticate() will authenticate the
>>> user, store the autenticated principal in the session:
>>>
>>> session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
>>>
>>> and then attempt to restore the original request URI (which prompted
>>> authentication in the first place) and redirect to it:
>>>
>>> // Redirect the user to the original request URI (which will cause
>>> // the original request to be restored)
>>> requestURI = savedRequestURL(session);
>>> if (requestURI == null) {
>>> // requestURI will be null if the login form is submitted
>>> // directly, i.e., if there has not been any original request
>>> // that was stored away before the redirect to the login form was
>>> // issued. In this case, assume that the original request has been
>>> // for the context root, and have the welcome page mechanism take
>>> // care of it
>>> requestURI = hreq.getContextPath() + "/";
>>> saveRequest(requestURI, hreq.getMethod(), session);
>>> }
>>> .
>>> If the login page was accessed directly, "requestURI" will be null
>>> (there
>>> is nothing to restore in this case), so what the above code does is to
>>> pretend
>>> that the original request was for "<context_root>/". This "requestURI"
>>> is then
>>> saved in the session, using saveRequest() (see further down for why
>>> calling
>>> saveRequest() is necessary in this case).
>>>
>>> The request is then redirected to the restored "requestURI", which in
>>> this
>>> case will be equal to "<context_root>/":
>>>
>>> hres.sendRedirect(hres.encodeRedirectURL(requestURI));
>>>
>>> This will trigger another invocation of FormAuthenticator.authenticate()
>>> down
>>> the line, but this time, matchRequest() will return true (this is why
>>> the above
>>> code had to call saveRequest(), since matchRequest() matches the
>>> redirected
>>> request against whatever was saved):
>>>
>>> if (matchRequest(request)) {
>>>
>>> Since matchRequest() will return true, the principal is retrieved from
>>> the session, and register() is called:
>>>
>>> session = getSession(request, true);
>>> principal = (Principal)
>>> session.getNote(Constants.FORM_PRINCIPAL_NOTE);
>>> register(request, response, principal, Constants.FORM_METHOD,
>>> (String) session.getNote(Constants.SESS_USERNAME_NOTE),
>>> (String) session.getNote(Constants.SESS_PASSWORD_NOTE));
>>>
>>> So from what I can tell, the existing code is correct, i.e., it is
>>> necessary to call
>>> saveRequest() if the login page was accessed directly, and
>>> FormAuthenticator.register()
>>> will still be called.
>>>
>>> Let me know if I missed anything.
>>>
>>> Thanks,
>>>
>>>
>>> Jan
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>>>
>>>
>>>
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>