Thanks Tim for the report. Entered an issue and will try to fix it tomorrow
for 2.2 M1:
https://github.com/restlet/restlet-framework-java/issues/697

Thanks,
Jerome
--
http://www.restlet.com
http://twitter.com/#!/jlouvel



2012/12/10 Tim Peierls <[email protected]>

> Here's a better candidate for the default implementation of
> CookieAuthenticator.challenge:
>
>     @Override public void challenge(Response response, boolean stale) {
>         Reference ref = response.getRequest().getResourceRef();
>         String redirectQueryName = getRedirectQueryName();
>         String redirectQueryValue =
> ref.getQueryAsForm().getFirstValue(redirectQueryName, "");
>
>         if ("".equals(redirectQueryValue)) {
>             redirectQueryValue = new Reference(getLoginFormPath())
>                 .addQueryParameter(redirectQueryName, ref.toString())
>                 .toString();
>         }
>
>         response.redirectSeeOther(redirectQueryValue);
>     }
>
> If the redirect URI already contains a redirect query value we use it
> directly, because it means we're creating a challenge after a failed login
> attempt, so by using the redirect query value, we're restarting the whole
> process. Otherwise, this is a first login attempt, so we create a new
> reference to the login path with a redirect query.
>
> For example, suppose the user tries to access a resource at /foo that
> requires authentication/authorization. Since /foo does not contain a
> targetUri query parameter, the if-test succeeds and this will result in a
> challenge redirection to /login?targetUri=/foo. If that login attempt
> fails, the authentication machinery now tries to authenticate
> /login?targetUri=/foo. This time, redirectQueryValue will be /foo, the if
> clause will be skipped, and the redirection will be to /foo, back to our
> starting point.
>
> This is slightly brittle because of the possibility that other resources
> might use the redirect query name in queries, too, which would confuse this
> logic. Consider using a name other than the default "targetUri" if this
> worries you.
>
> --tim
>
> On Sun, Dec 9, 2012 at 4:44 PM, Tim Peierls <[email protected]> wrote:
>
>> No one answered the question below, and I'd still like to get an answer,
>> but in the meantime I got CookieAuthenticator to work by overriding
>> challenge(Response, boolean) as follows.
>>
>>     @Override public void challenge(Response response, boolean stale) {
>>         response.redirectSeeOther(
>>             new Reference(getLoginFormPath())
>>                 .addQueryParameter(
>>                     getRedirectQueryName(),
>>                     response.getRequest().getResourceRef().toString()
>>                 )
>>                 .toString() // Interpret URI relative to this host.
>>         );
>>     }
>>
>> This would seem to be a good candidate for a default implementation of
>> CookieAuthenticator.challenge(Response, boolean).
>>
>>  Here's the rest of the story: I have an AuthApplication to which /auth
>> requests are routed in my main component.
>>
>>     // MainComponent initialization:
>>     host.attach("/auth", authApplication);
>>
>> That application routes /loginForm to a login form resource and routes
>> everything else to an instance of my CookieAuthenticator extension around a
>> Restlet that does nothing. (If you leave out this vacuous Restlet, the
>> machinery complains about a Filter with no target.)
>>
>>     // In AuthApplication.createInboundRoot:
>>     Authenticator authenticator = ... my CookieAuthenticator extension
>> ...;
>>     authenticator.setNext(new Restlet() {
>>         @Override public void handle(Request request, Response response) {
>>             getLogger().debug("Null restlet");
>>         }
>>     });
>>
>>     router.attach("/loginForm", LoginFormServerResource.class);
>>     router.attachDefault(authenticator);
>>
>> LoginFormServerResource is a straighforward use of Freemarker's
>> TemplateRepresentation:
>>
>>     @Get public Representation showLoginForm() {
>>         ImmutableMap<String, String> dataModel = ImmutableMap.of(
>>             "targetUri", getQuery().getFirstValue("targetUri")
>>         );
>>         return new TemplateRepresentation(
>>             LOGIN_FORM_TEMPLATE, freemarkerConfiguration,
>>             dataModel, MediaType.TEXT_HTML
>>         );
>>     }
>>
>> The template has a form element with an action to post to the login
>> resource, using the default values of CookieAuthenticator's
>> identifierFormName and secretFormName properties ("login", "password"). A
>> stripped-down example:
>>
>>     <form action="/auth/login?targetUri=${targetUri}" method="POST">
>>         <input type="text" id="login" name="login" size="15" />
>>         <input type="password" id="password" name="password" size="15" />
>>         <input type="submit" value="Login" />
>>     </form>
>>
>> Because I've made authentication/authorization a separate Application, I
>> had to set the cookie path to "/" in my CookieAuthenticator extension in
>> order to have the credentials in the cookie apply to the entire URI-space
>> of my Restlet Component.
>>
>>     @Override protected CookieSetting getCredentialsCookie(Request
>> request, Response response) {
>>         CookieSetting credentialsCookie =
>> super.getCredentialsCookie(request, response);
>>         credentialsCookie.setPath("/");
>>         return credentialsCookie;
>>     }
>>
>> --tim
>>
>>
>> On Mon, Dec 3, 2012 at 3:38 PM, Tim Peierls <[email protected]> wrote:
>>
>>> The class javadoc for CookieAuthenticator says:
>>>
>>> When the credentials are missing or stale, the challenge(Response,
>>>> boolean)<http://www.restlet.org/documentation/2.1/jee/ext/org/restlet/ext/crypto/CookieAuthenticator.html#challenge(org.restlet.Response,%20boolean)>
>>>>  method
>>>> is invoked by the parent class, and its default behavior is to redirect the
>>>> user's browser to the 
>>>> getLoginFormPath()<http://www.restlet.org/documentation/2.1/jee/ext/org/restlet/ext/crypto/CookieAuthenticator.html#getLoginFormPath()>
>>>>  URI,
>>>> adding the URI of the target resource as a query parameter of name
>>>> getRedirectQueryName()<http://www.restlet.org/documentation/2.1/jee/ext/org/restlet/ext/crypto/CookieAuthenticator.html#getRedirectQueryName()>
>>>> .
>>>
>>>
>>> But the javadoc for CookieAuthenticator.challenge(Response, boolean)
>>> says it must be overridden to return a login form representation, and
>>> in fact the implementation of challenge(Response, boolean) is to call
>>> super.challenge(response, stale), in both stable and unstable versions. The
>>> supertype version (ChallengeAuthenticator.challenge) sets the status to
>>> unauthorized and creates a challenge request from the challenge scheme and
>>> puts it in the response. This fails because the HTTP_Cookie scheme is not
>>> meant to be used in this way.
>>>
>>> My question is whether the class comment is the intent, and the current
>>> implementation of CookieAuthenticator.challenge is incomplete, or if the
>>> class comment is out of date. If the latter is the case, then can someone
>>> give an example of how to override challenge?
>>>
>>> --tim
>>>
>>
>>
>

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=3037701

Reply via email to