Re: Unauthenticated access returns 204.
Hello Matt, I've entered on issue for this topic: http://restlet.tigris.org/issues/show_bug.cgi?id=985 Thanks for your report. Best regards, Thierry Boileau > I've always thought that 401 "Not Authorized" was poorly chosen wording, > because it really says the same thing as 403 "Forbidden". However, the > requirement that a 401 status also MUST send a WWW-Authenticate header I > think in practice has led 401 to really mean "Not Authenticated" and 403 to > really mean "Not Authorized". Whereas in the description of 403 in rfc2616 > section 10 explicitly states that "Authentication will not help", which > implies that either no authentication is possible, the user is simply trying > to do something the server doesn't want done, or it implies that the user is > in fact authenticated, and the server is saying the authenticated user isn't > authorized to do that. > > So where does that leave us? I guess I think that the abstract > implementation of Authenticator should not simply return 204 to the client if > Authentication has been set to be required, and a concrete subclass has > returned false in the authenticate() method. It is OK, because it does in > fact stop the filter, but I think it could be a little bit easier on the > programmer implementing the concrete subclass. Perhaps setting the status to > 403 is more appropriate in this case. Anyway, I trust the restlet team's > judgement here, but if you decide to keep the behavior as it is, then I > encourage you to document clearly that the unauthenticated() method will also > need to be overridden in subclasses in order to produce behavior that results > in a 401 or 403 upon returning false from the authenticate() method. I would > be happy to look at possible implementations of changing the default behavior > if it is something the restlet team thinks would be worthwhile. > > The good news is that as far as my current project goes, I have custom > subclasses of Authenticators and Authorizers working very well and I really > like the new security architecture, I'm just trying to figure out if this > particular aspect of the behavior is as simple as it could be. > > Thanks for your time, > Matt > > -- > http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2429029 > > -- http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2431078
Re: Unauthenticated access returns 204.
I've always thought that 401 "Not Authorized" was poorly chosen wording, because it really says the same thing as 403 "Forbidden". However, the requirement that a 401 status also MUST send a WWW-Authenticate header I think in practice has led 401 to really mean "Not Authenticated" and 403 to really mean "Not Authorized". Whereas in the description of 403 in rfc2616 section 10 explicitly states that "Authentication will not help", which implies that either no authentication is possible, the user is simply trying to do something the server doesn't want done, or it implies that the user is in fact authenticated, and the server is saying the authenticated user isn't authorized to do that. So where does that leave us? I guess I think that the abstract implementation of Authenticator should not simply return 204 to the client if Authentication has been set to be required, and a concrete subclass has returned false in the authenticate() method. It is OK, because it does in fact stop the filter, but I think it could be a little bit easier on the programmer implementing the concrete subclass. Perhaps setting the status to 403 is more appropriate in this case. Anyway, I trust the restlet team's judgement here, but if you decide to keep the behavior as it is, then I encourage you to document clearly that the unauthenticated() method will also need to be overridden in subclasses in order to produce behavior that results in a 401 or 403 upon returning false from the authenticate() method. I would be happy to look at possible implementations of changing the default behavior if it is something the restlet team thinks would be worthwhile. The good news is that as far as my current project goes, I have custom subclasses of Authenticators and Authorizers working very well and I really like the new security architecture, I'm just trying to figure out if this particular aspect of the behavior is as simple as it could be. Thanks for your time, Matt -- http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2429029
Re: Unauthenticated access returns 204.
Hi Matt, basically, an authenticator aims at extracting all interesting data from the request in order to authenticate the request, that is to say check that the credentials conveyed by the request correspond to a known user. The enroler is then used to complete the Request#clientInfo attribute in order to give the application all necessary data about the current user. Another step is to say that this user is authorized according to the application policy to access the requested resource (via an authorizer filter). If the current user is not authorized, a 401 status code is returned. Having said that, one subclass of Authenticator, called ChallengeAuthenticator aims at handling requests based on "challenge schemes". This filter relies on an instance of the Verifier class that checks the credentials and authenticates users. In addition, due to the challenge mecanism, it ensures that the response to a unauthenticated request contains the necessary data (a ChallengeRequest object, corresponding to the "WWW-Authenticate" HTTP header) that will help the client to understand what happens and to correctly fulfill the next request. Thus, the 401 status code is used (perhaps a "unauthenticated request" status code would be better). I should mention that the DigestAuthenticator class is a subclass of ChallengeAuthenticator that specifically handles the case of the HTTP_DIGEST challenge scheme. Of course, this must not be confused with the "authorization" step which help to decides if an authenticated user is allowed or not to access precisely to a resource. Best regards, Thierry Boileau > 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=2428784
Re: Unauthenticated access returns 204.
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
Re: Unauthenticated access returns 204.
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