with example java jersey jax-rs basic-authentication dropwizard

java - example - rest token authentication



DropWizard Auth por ejemplo (1)

Pregunta 1:

El protocolo de autenticación básico indica que la solicitud del cliente debe tener un encabezado en forma de

Authorization: Basic Base64Encoded(username:password)

donde Base64Encoded(username:password) es una cadena codificada en Base64 real del username:password de username:password . Por ejemplo, si mi nombre de usuario y contraseña son peeskillet:pass , el encabezado debe enviarse como

Authorization: Basic cGVlc2tpbGxldDpwYXNz

Dicho esto, el cliente de Jersey (suponiendo que 1.x) tiene un HTTPBasicAuthFilter , que es un filtro del lado del cliente, que manejará la parte de codificación para nosotros. Así que la solicitud del lado del cliente podría verse algo así como

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

Eso es todo lo que necesitaríamos para realizar una solicitud GET simple con el encabezado de autorización.

Pregunta 2:

SimpleCredential: para la autenticación básica, en realidad BasicCredentials usar BasicCredentials , en lugar de nuestras propias credenciales. Básicamente, la solicitud pasará por el BasicAuthProvider . El proveedor analizará el encabezado de Autorización y creará un objeto BasicCredentials partir del nombre de usuario y la contraseña analizados. Una vez que el procesamiento haya finalizado, las BasicCredentials pasarán a nuestro SimpleAuthenticator ''s. Usamos esas credenciales para autenticar al usuario.

SimplePrincipal: es básicamente lo que usaremos para autorizar al cliente. Desde el proceso de autenticación, podemos crear un principal, que se usará para autorizar más adelante (consulte la pregunta 3). Así que un ejemplo podría parecer algo como

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); } }

SimplePrincipal un poco la clase SimplePrincipal y creé una clase de Roles simple.

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"; }

Pregunta 3:

Algunos pueden preferir tener una capa de filtro adicional para la autorización, pero Dropwizard parece tener la opinión de que la autorización debe ocurrir en la clase de recurso (olvidé exactamente dónde lo leí, pero creo que su argumento es verificable). Lo que sucede con el SimplePrincial que creamos en SimpleAuthenticator es que se puede inyectar en nuestro método de recursos, con el uso de las anotaciones de @Auth . Podemos usar el SimplePrincipal para autorizar. Algo como

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(); } }

Así que poniéndolo todo junto, con esta configuración.

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

y las credenciales del cliente que publiqué anteriormente, cuando hacemos la solicitud, debemos obtener un

{"Hello": "peeskillet"}

También se debe mencionar que la autenticación básica por sí sola no es segura, y se recomienda realizarla sobre SSL

Ver Relacionados:

ACTUALIZAR

Un par de cosas:

  • Para Dropwizard 0.8.x, la configuración de Autenticación básica ha cambiado un poco. Puedes ver más aquí . Un ejemplo simple sería

    SimpleAuthenticator auth = new SimpleAuthenticator(); env.jersey().register(AuthFactory.binder( new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));

  • Vea el enlace anterior para el uso recomendado de AuthenticationException

Estoy tratando de entender cómo funcionan la autenticación y la autorización en DropWizard . He leído su guía de autenticación y el dropwizard-security en GitHub, pero siento que todavía me faltan algunos conceptos importantes.

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")); } }

Y luego en mi subclase de Application :

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

Y luego en un método de recursos:

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

Creo que lo tengo medio configurado correctamente para la autenticación básica, pero no entiendo el rol que desempeñan SimpleCredential y SimplePrincipal . Específicamente:

  1. ¿Cómo establezco un nombre de usuario / contraseña de autenticación básica desde el cliente de Jersey / JAX-RS?
  2. ¿Qué papel desempeñan SimpleCredential y SimplePrincipal con la autenticación básica? ¿Debo agregar algo a ellos u otras clases para hacer que la autenticación básica funcione de manera que el único nombre de usuario válido sea simple_user y la única contraseña válida sea 12345 ?
  3. ¿Cómo hago cumplir el acceso / autenticación / roles a través de SimplePrincipal ? ¿O es que el concepto de autorización no existe con los servicios web?