web-dev-qa-db-fra.com

DropWizard Auth par exemple

J'essaie de comprendre comment fonctionnent l'authentification et l'autorisation dans DropWizard . J'ai lu leur guide d'authentification ainsi que le projet dropwizard-security sur GitHub, mais j'ai l'impression qu'il me manque encore quelques concepts importants.

public class SimpleCredential {
    private String password;

    public SimpleCredential(String password) {
        super();

        this.password = password;
    }
}

public class SimplePrincipal {
    pivate String username;

    public SimplePrincipal(String username) {
        super();

        this.username = username;
    }
}

public class SimpleAuthenticator implements Authenticator<SimpleCredential, SimplePrincipal> {
    @Override
    public Optional<SimplePrincipal> authenticate(SimpleCredential credential) throws AuthenticationException {
        if(!"12345".equals(credential.getPassword())) {
            throw new AuthenticationException("Sign in failed.");
        }

        Optional.fromNullable(new SimplePrincipal("simple_user"));
    }
}

Et puis dans ma sous-classe Application:

@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
    environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}

Et puis dans une méthode de ressource:

@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
    addressDao.getAddressById(id);
}

Je pense que je l'ai correctement configuré à moitié pour l'authentification de base, mais je ne comprends pas le rôle que SimpleCredential et SimplePrincipal jouent. Plus précisément:

  1. Comment définir le nom d'utilisateur/mot de passe d'authentification de base à partir du client Jersey/JAX-RS?
  2. Quel rôle jouent SimpleCredential et SimplePrincipal avec l'authentification de base? Dois-je ajouter quoi que ce soit à eux ou à d'autres classes pour que l'authentification de base fonctionne de telle sorte que le seul nom d'utilisateur valide soit simple_user et le seul mot de passe valide est 12345?
  3. Comment appliquer l'accès/l'authentification/les rôles via SimplePrincipal? Ou le concept d'autorisation est-il inexistant avec les services Web?
21
IAmYourFaja

Question 1:

Authentification de base le protocole indique que la demande du client doit avoir un en-tête sous la forme de

Authorization: Basic Base64Encoded(username:password)

Base64Encoded(username:password) est une chaîne codée Base64 réelle du username:password. Par exemple, si mon nom d'utilisateur et mon mot de passe sont peeskillet:pass, L'en-tête doit être envoyé sous la forme

Authorization: Basic cGVlc2tpbGxldDpwYXNz

Cela étant dit, le client Jersey (en supposant 1.x) a un HTTPBasicAuthFilter, qui est un filtre côté client, qui gérera la partie encodage pour nous. Ainsi, la demande côté client pourrait ressembler à quelque chose comme

Client client = Client.create();
WebResource resource = client.resource(BASE_URI);
client.addFilter(new HTTPBasicAuthFilter("peeskillet", "pass"));
String response = resource.get(String.class);

C'est tout ce dont nous aurions besoin pour faire une simple demande GET avec l'en-tête d'autorisation.

Question 2:

SimpleCredential: Pour l'authentification de base, nous serions en fait tenus d'utiliser BasicCredentials, au lieu de nos propres informations d'identification. Fondamentalement, la demande passera par le BasicAuthProvider. Le fournisseur analysera l'en-tête d'autorisation et créera un objet BasicCredentials à partir du nom d'utilisateur et du mot de passe analysés. Une fois ce traitement terminé, le BasicCredentials sera transmis à nos SimpleAuthenticator. Nous utilisons ces informations d'identification pour authentifier l'utilisateur.

SimplePrincipal: est fondamentalement ce que nous utiliserons pour autoriser le client. À partir du processus d'authentification, nous pouvons créer un principal, qui sera utilisé pour autoriser plus tard (voir la question 3). Donc, un exemple pourrait ressembler à quelque chose

import com.google.common.base.Optional;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;

public class SimpleAuthenticator implements Authenticator<BasicCredentials,
                                                          SimplePrincipal> {
    @Override
    public Optional<SimplePrincipal> authenticate(BasicCredentials credentials)
            throws AuthenticationException {

        // Note: this is horrible authentication. Normally we'd use some
        // service to identify the password from the user name.
        if (!"pass".equals(credentials.getPassword())) {
            throw new AuthenticationException("Boo Hooo!");
        }

        // from some user service get the roles for this user
        // I am explicitly setting it just for simplicity
        SimplePrincipal prince = new SimplePrincipal(credentials.getUsername());
        prince.getRoles().add(Roles.ADMIN);

        return Optional.fromNullable(prince);
    }
}

J'ai un peu modifié la classe SimplePrincipal et créé une simple classe Roles.

public class SimplePrincipal {

    private String username;
    private List<String> roles = new ArrayList<>();

    public SimplePrincipal(String username) {
        this.username = username;
    }

    public List<String> getRoles() {
        return roles;
    }

    public boolean isUserInRole(String roleToCheck) {
        return roles.contains(roleToCheck);
    }

    public String getUsername() {
        return username;
    }
}

public class Roles {
    public static final String USER = "USER";
    public static final String ADMIN = "ADMIN";
    public static final String EMPLOYEE = "EMPLOYEE";
}

Question 3:

Certains pourraient préférer avoir une couche de filtre supplémentaire pour l'autorisation, mais Dropwizard semble avoir l'opinion d'opinion que l'autorisation devrait se produire dans la classe de ressources (j'ai oublié exactement où je l'ai lu, mais je croyez leur argument est la testabilité). Ce qui se passe avec le SimplePrincial que nous avons créé dans le SimpleAuthenticator, c'est qu'il peut être injecté dans notre méthode de ressource, avec l'utilisation des annotations @Auth. Nous pouvons utiliser le SimplePrincipal pour autoriser. Quelque chose comme

import dropwizard.sample.helloworld.security.Roles;
import dropwizard.sample.helloworld.security.SimplePrincipal;
import io.dropwizard.auth.Auth;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/simple")
public class SimpleResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getResponse(@Auth SimplePrincipal principal) {
        if (!principal.isUserInRole(Roles.ADMIN)) {
            throw new WebApplicationException(Response.Status.FORBIDDEN);
        }
        return Response.ok(
                "{\"Hello\": \"" + principal.getUsername() + "\"}").build();
    }
}

Donc, tout mettre ensemble, avec cette configuration

environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
                                            new SimpleAuthenticator(), 
                                            "Basic Example Realm")
);

et les informations d'identification du client que j'ai publiées précédemment, lorsque nous faisons la demande, nous devrions obtenir un retour

{"Hello": "peeskillet"}

Il convient également de mentionner que l'authentification de base seule n'est pas sécurisée, et il est recommandé de le faire via SSL


Voir aussi:


METTRE À JOUR

Quelques choses:

  • Pour Dropwizard 0.8.x, la configuration de Basic Auth a un peu changé. Vous pouvez voir plus ici . Un exemple simple serait

    SimpleAuthenticator auth = new SimpleAuthenticator();
    env.jersey().register(AuthFactory.binder(
            new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
    
  • Voir le lien ci-dessus pour l'utilisation recommandée de AuthenticationException

37
Paul Samsotha