Spring Boot + REST Jersey (Adding Spring Security 4) Part 4


In the previous post we explained how to use HATEOAS step by step using Spring boot Spring Boot + REST Jersey (Adding Spring HATEOAS and MapStruct) Part 3, and we are going to use this project as base to implement Spring Security with basic authentication.

Step 1: Configuration

Spring boot has starter dependencies that are very useful to add new modules to our application, in this example we will add the spring-boot-starter-security dependency as follows:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Step 2: Modifying our Repository

In the post Spring Boot + REST Jersey (Adding Spring HATEOAS and MapStruct) Part 3 we created the repositories UserRepository and RoleRepository. In this example we are going to add a method to UserRepository that will find a user by username.

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;
import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends CrudRepository<User, Integer> {
	User findByUsername(String username);
}

We don’t need to implement the method findByUsername(String username) because Spring data will create the implementation based in a convention.

Step 3: Adding an AuthenticatorService

AuthenticatorService will be the responsible to execute the authentication in the application, the logic will be: Find a user and its role and return it, we don’t need to create a logic to compare users or passwords it will be done by Spring.

/**
 *
 */
package com.raidentrance.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;

/**
 * @author raidentrance
 *
 */
@Service
public class AuthenticatorService implements UserDetailsService {
	@Autowired
	private UserRepository userRepository;

	private static final Logger LOG = LoggerFactory.getLogger(AuthenticatorService.class);

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		LOG.info("Trying to authenticate to {}", username);
		User user = userRepository.findByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException("Username " + username + " not found");
		} else {
			Collection<? extends GrantedAuthority> authorities = getGrantedAuthorities(user);
			return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);
		}
	}

	private Collection<? extends GrantedAuthority> getGrantedAuthorities(User user) {
		List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
		list.add(new GrantedAuthority() {
			private static final long serialVersionUID = 2409931876244987359L;
			@Override
			public String getAuthority() {
				return user.getRole().getName();
			}
		});
		return list;
	}
}

Step 4: Configuring Spring security

Once we created the AuthenticatorService we need to define which endpoints do we want to authenticate.

/**
 *
 */
package com.raidentrance.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import com.raidentrance.service.AuthenticatorService;

/**
 * @author raidentrance
 *
 */
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	@Autowired
	private AuthenticatorService authenticatorService;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(authenticatorService);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.httpBasic().and().authorizeRequests().anyRequest().authenticated();
	}
}

The method configureGlobal is used to define who is going to search the user, in this example it will use AuthenticatorService previously created.

The method configure is used to define the protected url’s and the authentication mechanism. In this example we are going to use Basic authentication.

Enpoint:  http://localhost:8080/users

Header: Authorization Basic cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0

How to create the header

The value of the header Authorization is created in the following way:

Authorization Basic   :  It is the name of the header and the authentication mechanism

cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0 : This is the value and it is the user:password in base64, in this way it is raidentrance:superSecret in base64.

Testing with CURL

curl http://localhost:8080/users -XGET --user raidentrance:superSecret

Testing with Postman

captura-de-pantalla-2016-09-08-a-las-10-14-35-a-m

captura-de-pantalla-2016-09-08-a-las-10-14-58-a-m

You can find the complete code in the following link : https://github.com/raidentrance/spring-boot-example/tree/part4-adding-security

If you want to learn more about Spring and REST we recommend the following books:

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Crea una aplicación Web+REST (Spring boot + AngularJS) en minutos utilizando JHipster


JHipster es una herramienta de Scaffolding creada por Yeoman utilizada para crear proyectos utilizando Spring Boot + AngularJs.

Instalación

Antes de iniciar con la creación de las aplicaciones debemos asegurarnos que tenemos el ambiente de trabajo instalado y configurado correctamente. Para esto debemos seguir los siguientes pasos:

  • Instalar y configurar la versión 8 de Java
  • Instalar Node.js del sitio web, esto instalará el comando npm.
  • Instalar Yeoman utilizando el comando npm install -g yo 
  • Instalar Bower utilizando el comando npm install -g bower
  • Instalar Gulp utilizando el comando npm install -g gulp-cli
  • Instalar JHipster utilizando el comando npm install -g generator-jhipster

Con estos sencillos pasos JHipster ha sido instalado de forma exitosa.

Creando una aplicación en minutos utilizando JHipster

Una vez instalado JHipster el siguiente paso es crear una aplicación para esto seguiremos los siguientes pasos:

  • Crear una carpeta vacía la cuál contendrá el proyecto que se genere:
mkdir jhipster-example
  • Ir al directorio creado utilizando:
cd jhipster-example
  • Crear la aplicación utilizando el comando:
yo jhipster

JHipster preguntará por  lo siguiente:

  • Permiso para utilizar estadísticas de uso.
  • El tipo de aplicación que se desea construir como se muestra en la imagen:
    • Monolithic application

captura-de-pantalla-2016-09-29-a-las-9-00-07-a-m

  • El nombre de la aplicación
    • raidentrance
  • Nombre del paquete base
    • com.raidentrance.jhipster
  • Tipo de autenticación que se desea utilizar,
    • HTTP Session Authentication (stateful, default Spring Security mechanism)

  • Tipo de base de datos  a utilizar
    • SQL
  • Base de datos a utilizar en producción
    •  MySQL
  • Base de datos a utilizar en desarrollo
    • MySQL
  • Si se utilizará el segundo nivel de cache de Hibernate
    • Yes, with ehcache (local cache, for a single node)

  • Herramienta para construcción del proyecto
    • para nuestro ejemplo utilizaremos Maven.
  • Herramientas adicionales
    • No se selecciona ninguna opción
  • Utilizar LibSass para el procesamiento de CSS
    • Yes
  • Soporte para internacionalización
    • No
  • Framework de testing a utilizar
    • Gatling
  • Sobre escribir el archivo .gitignore
    • Si

Con estos pasos JHipster generará la aplicación completa y mostrará el siguiente mensaje:

captura-de-pantalla-2016-09-29-a-las-9-09-49-a-m

Iniciar la aplicación

Una vez creado el proyecto el siguiente paso es iniciar la aplicación, para esto se deben seguir los siguientes pasos:

  • Compilar el proyecto con maven utilizando el comando mvn clean install
  • Crear una base de datos vacía para el proyecto
  • Modificar configuraciones del proyecto, para esto abriremos el archivo application-dev.yml ubicado en src/main/resources/config.Para este ejemplo se modificará lo siguiente:
    • URL de la base de datos
    • Usuario de la base de datos
    • Password de la base de datos
  • Para ejecutar el proyecto es posible hacer lo siguiente:
    • Ejecutar en el IDE la clase RaidentranceApp.java como Spring boot application
    • Utilizar el plugin de Spring boot con el comando mvn spring-boot:run
  • Abrir en el navegador la dirección http://127.0.0.1:8080. Se mostrará lo siguiente:

 

Captura de pantalla 2016-09-29 a las 12.25.30 p.m..png

Puntos a analizar:

  • En la parte superior izquierda muestra que se está utilizando el perfil dev
  • En la pestaña de Account se tiene la posibilidad de registrar a un usuario nuevo o autenticar uno existente.
  • Al seleccionar Sign in se mostrará lo siguiente

Captura de pantalla 2016-09-29 a las 12.27.23 p.m..png

  • Por default en desarrollo JHipster crea un usuario llamado admin con el password admin, al autenticarte se mostrará la siguiente página de bienvenida:

 

Captura de pantalla 2016-09-29 a las 12.23.47 p.m..png

  • En la sección entities se mostrarán las entidades propias del proyecto, en este momento no ha creado ninguna por lo que aparecerá vacía.
  • Account muestra lo siguiente:
    • Settings: Permite modificar nombre, apellido y correo electrónico
    • Password: Permite cambiar el password del usuario autenticado
    • Sessions: Muestra las sesiones activas del usuario
    • Sign out: Permite cerrar sesión en la aplicación
  • Administración muestra lo siguiente:
    • User management: Permite llevar acabo la administración de usuarios de la aplicación
    • Metrics: Muestra métricas de la aplicación, por ejemplo (número de peticiones http, estadísticas de uso de los web services REST, estadísticas de uso de cache y estadísticas de uso del datasource)
  • Health muestra lo siguiente:
    • Muestra los health checks definidos en la aplicación
  • Configuration
    • Muestra todas las configuraciones de la aplicación
  • Audits
    • Muestra los registros para hacer auditoría en el sistema
  • Logs
    • Muestra y permite cambiar los niveles de log de la aplicación
  • API
    • Muestra los web services de la aplicación así como una explicación de como utilizarlos como se muestra en la siguiente imagen

Captura de pantalla 2016-09-29 a las 12.37.41 p.m..png

Toda la funcionalidad mostrada fue creada siguiendo buenas prácticas de desarrollo solo ejecutando un solo comando y llenando un wizard sencillo.

En el siguiente POST se explicará cómo crear nuevas páginas en minutos, la idea será crear una aplicación completa en minutos.

Subiré el código completo en el siguiente post con el fin de que esté completo.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

 

Spring Boot + REST Jersey (Agregando Spring Security 4) Parte 4


En el último post se explicó paso a paso la configuración de HATEOAS utilizando Spring boot Spring Boot + REST Jersey (Agregando Spring Hateoas y Dto) Parte 3, se tomará ese proyecto como base. Ahora se explicará de forma simple la configuración de Spring security, para este ejemplo se utilizará Basic authentication.

1. Configuración, Spring boot generó starter dependencies, estas dependencias contienen todos los recursos necesarios para utilizar el módulo de spring deseado de una forma simple y manejable de una forma más simple, las versiones de estas dependencias no son requeridas ya que se heredan del proyecto padre de spring boot. Para configurar Spring Security se requiere agregar la siguiente dependencia:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2.Modificando nuestro repositorio, En el post Spring Boot + REST Jersey (Agregando Spring Hateoas y Dto) Parte 3 se crearon los repositorios UserRepository y RoleRepository. En este ejemplo se agregará un método a UserRepository que realizará una búsqueda de usuario por username.

/**
 *
 */
package com.raidentrance.repositories;

import org.springframework.data.repository.CrudRepository;
import com.raidentrance.entities.User;

/**
 * @author raidentrance
 *
 */
public interface UserRepository extends CrudRepository<User, Integer> {
	User findByUsername(String username);
}

No se debe realizar ninguna implementación de findByUsername, Spring data detectará en base a convención que se desea buscar un objeto Usuario a través del atributo username y realizará la implementación.

3. Agregando AuthenticatorService, AuthenticatorService será el responsable de realizar la autenticación en la aplicación, de tal modo que la lógica de esta clase será buscar al usuario en la base de datos así como su rol y devolverlo, la comparación entre el usuario y la contraseña enviada con lo que este autenticator devuelve será realizada por Spring.

/**
 *
 */
package com.raidentrance.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.raidentrance.entities.User;
import com.raidentrance.repositories.UserRepository;

/**
 * @author raidentrance
 *
 */
@Service
public class AuthenticatorService implements UserDetailsService {
	@Autowired
	private UserRepository userRepository;

	private static final Logger LOG = LoggerFactory.getLogger(AuthenticatorService.class);

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		LOG.info("Trying to authenticate to {}", username);
		User user = userRepository.findByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException("Username " + username + " not found");
		} else {
			Collection<? extends GrantedAuthority> authorities = getGrantedAuthorities(user);
			return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);
		}
	}

	private Collection<? extends GrantedAuthority> getGrantedAuthorities(User user) {
		List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
		list.add(new GrantedAuthority() {
			private static final long serialVersionUID = 2409931876244987359L;
			@Override
			public String getAuthority() {
				return user.getRole().getName();
			}
		});
		return list;
	}
}

4. Configurando Spring security,el siguiente paso es configurar los endpoints que serán protegidos así como el mecanismo de autenticación a utilizar.

/**
 *
 */
package com.raidentrance.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import com.raidentrance.service.AuthenticatorService;

/**
 * @author raidentrance
 *
 */
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	@Autowired
	private AuthenticatorService authenticatorService;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(authenticatorService);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.httpBasic().and().authorizeRequests().anyRequest().authenticated();
	}
}

El método configureGlobal es utilizado para definir quién va a realizar la búsqueda de los usuarios, para este ejemplo se utilizará  el AuthenticatorService creado previamente.

El método configure es utilizado para definir las url a las que se realizará la autenticación y que mecanismo se utilizará. En este caso al ser servicios web se realiza Basic authentication pero no es el único.

Enpoint:  http://localhost:8080/users

Header: Authorization Basic cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0

El valor header Authorization está compuesto del siguiente modo

Authorization Basic   : Nombre del header y tipo de autenticación.

cmFpZGVudHJhbmNlOnN1cGVyU2VjcmV0 : Valor, está compuesto del siguiente modo.

raidentrance:superSecret En base 64 de tal modo que :

raidentrance=username

superSecret=password

Probando utilizando CURL:

curl http://localhost:8080/users -XGET --user raidentrance:superSecret

Probando utilizando Postman

captura-de-pantalla-2016-09-08-a-las-10-14-35-a-m

captura-de-pantalla-2016-09-08-a-las-10-14-58-a-m

Puedes encontrar el código completo del ejemplo en el siguiente enlace:

https://github.com/raidentrance/spring-boot-example/tree/part4-adding-security

 

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com