I want to expose a resource using RESTlet with a fine-grained authentication. My ServerResource
should be accessable via GET
only for authenticated members (using BASIC Authentication). However, requests using POST
should be available also for callers without any authentication.
In order to clearify:
http://path/myapp/user should allow anyone to register using POST
, but only registered members should be able to GET
a list of all users.
I'm unfortunately not much into RESTlet and I only find examples using coarser authentication for whole Restlet
s or Router
s.
So how do I enable optional authentication for resources and check them on a per-method level?
Thanks in advance!
To do basic authentication in RESTlet 2.0 (I assume you're using 2.0 since you mention ServerResource
), you need to use a ChallengeAuthenticator
. If this is configured with optional = true
then authentication will only be requested if you invoke ChallengeAuthenticator.challenge()
.
You can create your application with an authenticate()
method, and call this whenever you need access to a resource to be secured:
Application:
package example;
import org.restlet.*;
import org.restlet.data.ChallengeScheme;
import org.restlet.routing.Router;
import org.restlet.security.*;
public class ExampleApp extends Application {
private ChallengeAuthenticator authenticatior;
private ChallengeAuthenticator createAuthenticator() {
Context context = getContext();
boolean optional = true;
ChallengeScheme challengeScheme = ChallengeScheme.HTTP_BASIC;
String realm = "Example site";
// MapVerifier isn't very secure; see docs for alternatives
MapVerifier verifier = new MapVerifier();
verifier.getLocalSecrets().put("user", "password".toCharArray());
ChallengeAuthenticator auth = new ChallengeAuthenticator(context, optional, challengeScheme, realm, verifier) {
@Override
protected boolean authenticate(Request request, Response response) {
if (request.getChallengeResponse() == null) {
return false;
} else {
return super.authenticate(request, response);
}
}
};
return auth;
}
@Override
public Restlet createInboundRoot() {
this.authenticatior = createAuthenticator();
Router router = new Router();
router.attach("/user", UserResource.class);
authenticatior.setNext(router);
return authenticatior;
}
public boolean authenticate(Request request, Response response) {
if (!request.getClientInfo().isAuthenticated()) {
authenticatior.challenge(response, false);
return false;
}
return true;
}
}
Resource:
package example;
import org.restlet.data.MediaType;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;
public class UserResource extends ServerResource {
@Override
public Representation get() {
ExampleApp app = (ExampleApp) getApplication();
if (!app.authenticate(getRequest(), getResponse())) {
// Not authenticated
return new EmptyRepresentation();
}
// Generate list of users
// ...
}
@Override
public Representation post(Representation entity) {
// Handle post
// ...
}
}