Autenticación de grano fino con Restlet
-
19-09-2019 - |
Pregunta
Quiero exponer un recurso mediante Restlet con una autenticación de grano fino. Mi ServerResource
debe ser accesible a través de GET
sólo para los miembros autenticados (mediante la autenticación básica). Sin embargo, las solicitudes utilizando POST
deben estar disponibles también para las personas que llaman sin ningún tipo de autenticación.
Para clearify:
http: // ruta / miaplicacion / usuario debe permitir que nadie se registra utilizando POST
, pero sólo los usuarios registrados debe ser capaz de GET
una lista de todos los usuarios.
Estoy por desgracia no mucho en Restlet y sólo encuentro ejemplos más grueso mediante la autenticación de Restlet
s enteros o Router
s.
Entonces, ¿cómo puedo activar la autenticación opcional para los recursos y que no estén en un nivel por método?
Gracias de antemano!
Solución
Para realizar la autenticación básica en Restlet 2.0 (supongo que está utilizando 2.0 ya que mencionas ServerResource
), es necesario utilizar un ChallengeAuthenticator
. Si esto se configura con optional = true
entonces sólo se solicitará la autenticación si se invoca ChallengeAuthenticator.challenge()
.
Puede crear su aplicación con un método authenticate()
, y llamar a esto cada vez que necesite acceso a un recurso para ser asegurado:
Aplicación:
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;
}
}
Recurso:
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
// ...
}
}
Otros consejos
Estoy utilizando actualmente v2.0.10 Restlet.
El problema con ChallengeAuthenticator.isOptional()
es que es todo o nada. Una alternativa a la respuesta proporcionada por @ sea36 anterior es para anular ChallengeAuthenticator.beforeHandle()
ya sea a realizar la autenticación o saltar basado en método de la petición. Por ejemplo, el recurso a continuación sólo se requiere autenticación cuando se utiliza el método GET.
Aplicación:
package example;
import org.restlet.*;
import org.restlet.data.ChallengeScheme;
import org.restlet.routing.Router;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.MapVerifier;
public class ExampleApp extends Application {
private ChallengeAuthenticator createAuthenticator() {
Context context = getContext();
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 authOnGet = new ChallengeAuthenticator(context, challengeScheme, realm) {
@Override
protected int beforeHandle(Request request, Response response) {
if (request.getMethod() == Method.GET)
return super.beforeHandle(request, response);
response.setStatus(Status.SUCCESS_OK);
return CONTINUE;
}
};
return authOnGet;
}
@Override
public Restlet createInboundRoot() {
ChallengeAuthenticator userResourceWithAuth = createAuthenticator();
userResourceWithAuth.setNext(UserResource.class);
Router router = new Router();
router.attach("/user", userResourceWithAuth);
return router;
}
}
Recurso:
package example;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.representation.Representation;
import org.restlet.resource.ServerResource;
public class UserResource extends ServerResource {
@Get
public Representation listUsers() {
// retrieve list of users and generate response
// ...
}
@Post
public void register(Representation entity) {
// handle post
// ...
}
}
Tenga en cuenta que este ejemplo se aplica la política de autenticación de obtener sólo a los UserResource
y no otros recursos manejados por el router.