pom.xml
Tendremos que añadir las siguientes dependencias en el pom.xml, entre </properties> y </project>
<dependencies>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.4.12.Final</version>
<scope>provided</scope>
</dependency>
<!-- Real DB -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>jdbc.driver</artifactId>
<version>11.2.0.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- UNDERTOW -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SECURITY -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Test DB -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<!-- <version>3.141.59</version> -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<repositories>
<repository>
<id>archiva.atica.umu.es</id>
<name>ATICA - UMU Repository</name>
<url>https://archiva.um.es/archiva/repository/FundeWeb/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
<enableDirtyTracking>true</enableDirtyTracking>
<enableAssociationManagement>true</enableAssociationManagement>
<enableExtendedEnhancement>false</enableExtendedEnhancement>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- JaCoCo configuration -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Enunciate -->
<plugin>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-maven-plugin</artifactId>
<version>2.13.0</version>
<dependencies>
<dependency>
<groupId>com.webcohesion.enunciate</groupId>
<artifactId>enunciate-lombok</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>fdwjs</id>
<configuration>
<docsDir>${basedir}/src/main/resources/</docsDir>
<docsSubdir>static/docs/</docsSubdir>
</configuration>
</execution>
</executions>
</plugin>
<!-- FIN Enunciate -->
</plugins>
</build>
application.properties
Como hemos visto en el apartado anterior, en el archivo application.properties incluiremos algunas variables de configuración del proyecto:
########## RUTA BASE REST ########## server.servlet.context-path=/api ########## BASE DE DATOS ########## spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect spring.jpa.hibernate.ddl-auto = validate spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@hydra-prescan.atica.um.es:1526/ZEUSDESA spring.datasource.username=USER spring.datasource.password=PASSWORD
Si queremos cambiar el puerto que utiliza nuestra aplicación, que por defecto es el 8080, podemos hacerlo con la propiedad server.port. Otras propiedades que haya que definirse para otras funcionalidades, como para el login, se incluyen en su página de documentación correspondiente. Si queremos ver las propiedades de configuración que ofrece Spring podemos consultarlas aquí.
WebSecurity
Por otro lado, nos haremos una clase java para especificar la configuración de seguridad web, que debe extender a WebSecurityConfigurerAdapter e incluir la anotación @EnableWebSecurity:
package es.um.atica.helloworld.config;
import java.util.Arrays;
import org.springframework.context.annotation.Bean;
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 org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// CORS y HTTPS obligatorio:
http.cors().and().requiresChannel().anyRequest().requiresSecure();
// Solo CORS:
// http.cors();
}
// Filtro CORS
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Esta configuración tendrá que ser ampliada si se incluye el login con el CAS, pero esa configuración se indicará en la página correspondiente. También hay que ver si en local y en otros entornos tenemos que poner configuración diferente (https obligatorio, por ejemplo). En este caso podemos definirnos una variable en application.properties que indique el entorno en el que estás, y comprobarlo con un if. Por ejemplo, si estás en local, la configuración sin https, si no, con https.
¡Ojo! En versiones anteriores de Spring Boot (anteriores a la 2.4.0), en el filtro del CORS, en vez de:
configuration.setAllowedOriginPatterns( Arrays.asList( "*" ) );
Utilizábamos:
configuration.setAllowedOrigins(Arrays.asList("*"));
Pero tras los cambios, con setAllowedOrigins nos salta el siguiente error:
2021-01-08 10:21:50.656 ERROR 10568 --- [ XNIO-1 task-1] io.undertow.request : UT005023: Exception handling request to /loquesea java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*"since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
Así que en función de la versión, podemos encontrarnos algún error, por lo que debemos tener esto en cuenta.
Con esta configuración ya podemos tener nuestra aplicación funcionando sin problemas, pero si por algún motivo queremos poner https para hacer pruebas en local, en nuestro equipo, podemos generarnos un certificado autofirmado.
Generar certificado autofirmado
Para generar un certificado autofirmado, utilizaremos el comando keytool desde la terminal de Windows (:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650 -storepass password
Donde:
-aliaspara establecer el nombre del certificado.-keystorepara establecer el archivo.p12que será nuestro almacén de certificados.-storepasspara establecer la contraseña del keystore.
Tras introducir el comando nos preguntará una serie de datos, que podemos pasar directamente con Enter, dejándolos sin indicar (no son necesarios). Para confirmar, tendremos que escribir “si” (o “yes”, si es que lo tenemos en inglés). Por último, nos preguntará la contraseña para el certificado, que si pulsamos Enter directamente será la misma que hemos puesto en el comando para el keystore:
What is your first and last name?
[Unknown]:
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <tomcat>
(RETURN if same as keystore password):
Importar certificado
Para importar un certificado, utilizaremos el siguiente comando:
keytool -import -alias tomcat -file myCertificate.crt -keystore keystore.p12 -storepass password
Donde:
-aliases el nombre del certificado.-fileel archivo del certificado.-keystoreel archivo del almacén del certificados al que importamos el certificado.-storepassla contraseña del keystore.
Añadir certificado a nuestra aplicación
En application.properties debemos añadir lo siguiente:
# The format used for the keystore. It could be set to JKS in case it is a JKS file server.ssl.key-store-type=PKCS12 # The path to the keystore containing the certificate server.ssl.key-store=C:/Users/guillermo.castillo/keystore.p12 # The password used to generate the keystore server.ssl.key-store-password=password # The password used to generate the certificate server.ssl.key-password=password # The alias mapped to the certificate server.ssl.key-alias=tomcat