J'ai le scénario suivant:
Serveur: Jetée (avec JAAS configuré)
Client: Jersey appelé via JUnit (via Maven)
JAAS est installé sur le serveur Web. J'utilise la partie client comme test.
Du côté du serveur, les utilisateurs sont authentifiés via un formulaire avec l’authentification de base gérée via JAAS. De toute évidence, les utilisateurs doivent être authentifiés avant de pouvoir afficher certaines pages.
J'aimerais pouvoir me connecter via le Jersey avant d'essayer d'accéder à une page sécurisée. Comment cela peut-il être fait? J'ai vérifié que vous pouvez définir un filtre, mais je ne sais pas trop comment l'utiliser. Et - une fois que l'utilisateur est connecté via le formulaire, comment puis-je aller (du côté client) à la page qui m'intéresse réellement?
J'apprécierais vraiment si quelqu'un pouvait me montrer un exemple de la façon dont cela se passe du côté des clients avec Jersey.
J'ai la méthode de test élémentaire JUnit suivante:
@Test
public void testLogin()
throws IOException
{
String URL_LOGIN = "http://localhost:9080/foo/auth.html";
Client client = Client.create();
String username = "me";
String password = "me";
final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(username, password);
client.addFilter(authFilter);
client.addFilter(new LoggingFilter());
WebResource webResource = client.resource(URL_LOGIN);
// I even tried:
// webResource.header("Authorization", "Basic " + "base64encoded_userid:password").type("application/xml");
String page = webResource.post(String.class);
System.out.println(page);
}
Notez s'il vous plaît:
1) http: // localhost: 9080/foo/auth.html est la page que je suis censé voir en cas d'authentification réussie.
2) Je vois actuellement le résultat de http: // localhost: 9080/foo/login.html .
3) Évidemment, via un navigateur, je peux me connecter avec succès via la page login.html.
Qu'est-ce que je semble manquer ici?
Avec l’authentification de base, vous n’avez pas besoin de vous rendre sur une page de connexion. Si le serveur est configuré pour utiliser l'authentification de base, vous pouvez alors envoyer des requêtes à n'importe quelle page protégée si vous incluez l'en-tête d'authentification de base dans vos requêtes. Le filtre Jersey prend soin de cela. Donc, si l'authentification de base correspond vraiment à ce que le serveur utilise, votre code devrait alors fonctionner.
Étant donné que cela ne fonctionne pas et que cela ne fonctionne pas, je suis pratiquement sûr que le serveur est configuré pour utiliser l'authentification par formulaire au lieu de l'authentification de base.
Pour que l’authentification basée sur un formulaire fonctionne, vous devez envoyer une demande de publication avec les données du formulaire, y compris nom d’utilisateur et mot de passe, pour vous connecter, puis définir les cookies que vous recevez du serveur pour vos demandes ultérieures (depuis le serveur - une fois que vous vous êtes connecté). in - définira le cookie de session).
Regardez à quoi ressemble le fichier login.html - il devrait contenir un formulaire. S'il utilise l'authentification de formulaire de servlet standard, l'URL d'action de ce formulaire doit être "j_security_check" et il doit exister deux paramètres de formulaire: j_username et j_password. Si tel est le cas, vous pouvez essayer l'une des solutions suivantes:
String URL_LOGIN = "http://localhost:9080/foo/j_security_check";
String URL_DATA = "http://localhost:9080/foo/auth.html";
Client client = Client.create();
// add a filter to set cookies received from the server and to check if login has been triggered
client.addFilter(new ClientFilter() {
private ArrayList<Object> cookies;
@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
if (cookies != null) {
request.getHeaders().put("Cookie", cookies);
}
ClientResponse response = getNext().handle(request);
// copy cookies
if (response.getCookies() != null) {
if (cookies == null) {
cookies = new ArrayList<Object>();
}
// A simple addAll just for illustration (should probably check for duplicates and expired cookies)
cookies.addAll(response.getCookies());
}
return response;
}
});
String username = "me";
String password = "me";
// Login:
WebResource webResource = client.resource(URL_LOGIN);
com.Sun.jersey.api.representation.Form form = new Form();
form.putSingle("j_username", username);
form.putSingle("j_password", password);
webResource.type("application/x-www-form-urlencoded").post(form);
// Get the protected web page:
webResource = client.resource(URL_DATA);
String response = webResource.get(String.class);
Je n'ai pas testé cela, alors peut-être y aura-t-il des fautes de frappe ou des bugs.
Je n'utilise pas Jersey mais ce n'est pas un problème de Jersey en soi.
Vous devez d’abord utiliser soit le login de type FORM ou l’authentification BASIC; À moins qu'il ne s'agisse d'un développement personnalisé, je doute que vous utilisiez un «formulaire avec authentification de base».
Si vous utilisez l'authentification de base, les choses sont assez simples (bien qu'inefficaces): l'authentification BASIC est sans état et vous devez envoyer le Autorisation: Basic xxxx En-tête HTTP sur CHAQUE demande.
Si vous utilisez le login FORM, les choses sont un peu plus compliquées. À chaque demande, vous êtes censé envoyer l'identifiant de session (stocké dans un cookie ou en utilisant la réécriture d'URL). Si vous n'en envoyez pas ou si la session associée est invalidée (parce qu'elle a expiré, par exemple), le serveur enverra un message 302 (redirection) et le formulaire de connexion. Vous êtes alors censé effectuer un FORM POST sur l'URL indiquée dans le formulaire avec le nom d'utilisateur et le mot de passe en tant que paramètres. Si l'authentification réussit, le serveur envoie alors la réponse à la demande d'origine (et un nouvel identifiant de session). Dans ce scénario, la demande par programme doit donc pouvoir
Alternativement, une solution spécifique à Jersey est disponible en interceptant les appels, ici:
Autorisation pour JAAS:
String URL_DATA = "http://localhost:9080/foo/auth.html";
Client client = Client.create();
String username = "me";
String password = "me";
client.addFilter(new HTTPBasicAuthFilter(username, password));
// Get the protected web page:
WebResource webResource = client.resource(URL_DATA);
String response = webResource.get(String.class);
System.out.println(response);
Pour accéder au point de fin de repos à partir de l'authentification par formulaire Il est nécessaire d'enregistrer un filtre d'authentification de formulaire auprès du client Jersey JAX-RS. Une classe de filtre utile est donnée sur le lien suivant git hub.
utilisez FormAuthenticator.Java dans votre projet et dans le client Rest Jersey, procédez comme suit:
// Constructor of jersey Rest client
public RestClass(String username, String password)
{
private WebTarget webTarget;
private Client client;
private static final String BASE_URI = "http://localhost:8080/SampleRest/webresources";
client = javax.ws.rs.client.ClientBuilder.newClient();
client.register(new FormAuthenticator(BASE_URI, user, password));
webTarget = client.target(BASE_URI).path("restpath");
}
Et tout fonctionne bien. Je l'ai utilisé et ce problème est résolu. L'API JAX-RS doit indiquer cet authentificateur dans sa version.
Remarque: les mêmes nom d'utilisateur et mot de passe utilisés dans l'authentification par formulaire doivent être fournis à partir du client appelant dans les servlets.
as RestClient rs = new RestClient(username, password);
** La classe d'application devrait enregistrer RolesAllowedDynamicFeature pour que les rôles prennent effet ** MyApplication.Java dans un projet Web où la classe Rest et FormAuthenticator.Java résident dans le package rest
@ApplicationPath("webresources")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("entity.service");
packages("rest");
register(RolesAllowedDynamicFeature.class);
}
}
Pour moi, ces changements ont résolu le problème:
String URL_LOGIN = "http://localhost:9080/foo/j_security_check";
String URL_DATA = "http://localhost:9080/foo/auth.html";
Client client = Client.create();
// add a filter to set cookies received from the server and to check if login has been triggered
client.addFilter(new ClientFilter() {
private ArrayList<Object> cookies;
@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
if (cookies != null) {
request.getHeaders().put("Cookie", cookies);
}
ClientResponse response = getNext().handle(request);
// copy cookies
if (response.getCookies() != null) {
if (cookies == null) {
cookies = new ArrayList<Object>();
}
// A simple addAll just for illustration (should probably check for duplicates and expired cookies)
cookies.addAll(response.getCookies());
}
return response;
}
});
String username = "me";
String password = "me";
// Get the protected web page: (this will make the server know that someone will try to access the protected resource)
WebResource webResource = client.resource(URL_DATA);
String response = webResource.get(String.class);
// Login:
webResource = client.resource(URL_LOGIN);
com.Sun.jersey.api.representation.Form form = new Form();
form.putSingle("j_username", username);
form.putSingle("j_password", password);
webResource.type("application/x-www-form-urlencoded").post(form);
// Get the protected web page: (this time the service will return the data)
webResource = client.resource(URL_DATA);
response = webResource.get(String.class);