Stephan, I did call a 204 an error, didn't I? I should know better.
I have done some digging and I think I see what's going on. The
unauthenticated() method in the abstract Authenticator class never sets
CLIENT_ERROR_UNAUTHORIZED in the response object. I don't know whether it
should or not. It makes subclassing Authenticator slightly easier if it does
set that status. It seems to me that if authentication is not optional, and it
gets as far as the unauthenticated() method, then in addition to setting any
challengeResponse.authenticated property to false and the
clientInfo.authenticated property to false, the method can go ahead and set the
status in the response object as well. Otherwise, anybody writing a subclass of
Authenticator will have to subclass the unauthenticated() method as well in
order to return a 401. Which is completely fine, it just isn't as simple. I'm
going to get a checkout of svn tomorrow and I'll see if I can make this change
without breaking anything and submit the code if everything works OK.
-Matt
On Dec 5, 2009, at 8:16 AM, Stephan Koops wrote:
> Hi Matt,
>
> maybe the reason is, that the status is set to 204, if there is no
> entity (by Restlet). This must onky be done, if status is 200. Maybe
> this check is missing. Try to check it with the debugger.
>
> BTW: 204 is not an error, it means "ok, but no entity available".
>
> best regards
> Stephan
>
> Matt Kennedy schrieb:
>> I'm trying to implement a custom authenticator class and I'm a little
>> stumped by the behavior so far. When I override the authenticate() method
>> to always return false, I get back an HTTP 204 error. However, if I have it
>> always return true, then the request goes through correctly, so I think I
>> have everything wired up the right way. Based on my reading of the
>> available documentation, if authentication is set as required in the
>> Authenticator subclass (which is the default setting), then a 401 response
>> should be sent. Is this a bug? Or am I missing a required step in my
>> subclass implementation?
>>
>> Thanks,
>> Matt
>>
>> The following illustrates the problem (in Groovy):
>>
>> import org.restlet.*;
>> import org.restlet.data.*;
>> import org.restlet.security.Authenticator;
>> import org.restlet.representation.*;
>>
>> class TestAuthenticator extends Authenticator
>> {
>> @Override
>> public TestAuthenticator(Context ctx){ super(ctx); }
>>
>> @Override
>> protected boolean authenticate(Request request, Response response)
>> {
>> return false;
>> //return true;
>> }
>> }
>>
>> class TestRestlet extends Restlet
>> {
>> @Override
>> public void handle(Request request, Response response)
>> {
>> response.setEntity(new StringRepresentation("hello, world\n",
>> MediaType.TEXT_PLAIN));
>> }
>> }
>>
>> def component = new Component();
>> Server http = component.servers.add(Protocol.HTTP, 8181);
>> component.clients.add(Protocol.FILE);
>> Context workingCtx = http.context;
>> def guard = new TestAuthenticator(workingCtx);
>> def restlet = new TestRestlet();
>> guard.setNext(restlet);
>> component.defaultHost.attach(guard);
>> component.start();
>>
>> ------------------------------------------------------
>> http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2426801
>>
>
> ------------------------------------------------------
> http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2427447
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2428725