...
LoA (Level of Assurance) es el grado de confiabilidad de la identidad obtenida por un usuario autenticado en un sistema, es decir, el nivel de seguridad de un usuario autenticado en un sistema mediante un mecanismo concreto.
Por ejemplo, en nuestro contexto UMU, la identidad obtenida por un usuario autenticado en CAS con su correo y contraseña tendrá el nivel LoA más bajo (LOW).
El mismo usuario, autenticado en CAS con un certificado digital, obtendrá un nivel LoA medio (MEDIUMSUBSTANTIAL).
Esta guía detalla los pasos a configurar en nuestras APIs REST FundeWebJS para securizarlas permitiendo solo el acceso a las identidades con un nivel LoA mínimo.
| Advertencia |
|---|
Esta página va dirigida a APIs FundeWebJS que necesitan configurar expresamente un nivel LoA mínimo MEDIUM SUBSTANTIAL o superior. Por ejemplo, algunas APIs de EADMON. En otro caso, no es necesario realizar ninguna configuración. |
...
Dependiendo de la situación, se distinguen dos tipos de configuraciones:
- Global: Todos los endpoints de nuestra API requerirán el nivel LoA establecido en su configuración.
- Por endpoint: Configurar el nivel LoA de forma independiente para cada endpoint.
| Tabla de contenidos |
|---|
CONFIGURACIÓN
COMÚN
Esta configuración debe realizarse siempre, independientemente del tipo de configuración que se vaya a realizar.
Añadir en el pom.xml la siguiente dependencia:
Bloque de código language xml <dependency> <groupId>es.um.atica.fundewebjs.fundewebjs-api</groupId> <artifactId>fundewebjs-security</artifactId> <version>${fdwjs.version}</version> </dependency>Info La librería se encuentra a partir de la versión fdwjs 1.0.7-SNAPSHOT.
GLOBAL
Configuración para establecer el mismo nivel LoA mínimo en todos los endpoints de una API:
Clase Configuration (SecurityConfig)
En la clase con la configuración de seguridad (generalmente SecurityConfig.java), añadir el siguiente Bean para configurar el filtro para LoA, estableciendo el nivel mínimo que se desea establecer en toda nuestra API:
Bloque de código @Bean public UmuJwtLoaAuthenticationFilter loaFilterBean() { return new UmuJwtLoaAuthenticationFilter( UmuJwtLoaLevelEnum.MEDIUM SUBSTANTIAL); }En la misma clase, en el método configure, añadir el filtro configurado en el paso anterior de la siguiente forma:
Bloque de código language java .addFilterAfter( loaFilterBean(), BearerTokenAuthenticationFilter.class )
Hay que añadirlo justo antes de .oauth2ResourceServer().jwt().
Por ejemplo:Bloque de código language java @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .mvcMatchers("/actuator/**").permitAll() .mvcMatchers("/api-docs").permitAll() .mvcMatchers(apiPath+"/public/**").permitAll() .mvcMatchers(apiPath+"/private/**").hasAnyAuthority(serverScopes) .anyRequest().authenticated().and() .addFilterAfter( loggingFilterBean(), BearerTokenAuthenticationFilter.class ) .addFilterAfter( loaFilterBean(), BearerTokenAuthenticationFilter.class ) .oauth2ResourceServer().jwt(); http.csrf().disable(); }
POR MÉTODO
Configuración para establecer niveles LoA mínimos (o diferentes) en un/os endpoints concretos de nuestra API:
Clase Configuration (SecurityConfig)
En la clase con la configuración de seguridad (generalmente SecurityConfig.java), añadir el siguiente Bean para configurar el filtro para LoA, estableciendo el nivel mínimo que se desea establecer en toda nuestra API:
1 .@EnableGlobalMethodSecurity( prePostEnabled = true )
2. @Bean
UmuJwtLoaAccessDeniedHandler accessDeniedHandler() {
return new UmuJwtLoaAccessDeniedHandler();
}
...
la siguiente anotación en la declaración de la clase:
Bloque de código language java @EnableGlobalMethodSecurity( prePostEnabled = true )Añadir el siguiente Bean:
Bloque de código language java @Bean UmuJwtLoaAccessDeniedHandler accessDeniedHandler() { return new UmuJwtLoaAccessDeniedHandler(); }En la misma clase, en el método configure, añadir el accessDeniedHandler configurado en el paso anterior de la siguiente forma:
Bloque de código language java .and().exceptionHandling().accessDeniedHandler( accessDeniedHandler() )Ejemplo de configuración completa:
Bloque de código language java @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .mvcMatchers("/actuator/**").permitAll() .mvcMatchers("/api-docs").permitAll() .mvcMatchers(apiPath+"/public/**").permitAll() .mvcMatchers(apiPath+"/private/**").hasAnyAuthority(serverScopes) .anyRequest().authenticated() .and().exceptionHandling().accessDeniedHandler( accessDeniedHandler() ) .and()
...
.addFilterAfter( loggingFilterBean(), BearerTokenAuthenticationFilter.class ) .oauth2ResourceServer().jwt(); http.csrf().disable(); }
RestController
Ahora, en nuestro RestController, anotar el método con nuestro endpoint a securizar con la siguiente anotación:Bloque de código language java @PreAuthorize( "@umuJwtLoaAuthenticator.isSubstantialLoA(authentication)" )Advertencia El método isSubstantialLoA del componente umuJwtLoaAuthenticator establece el nivel mínimo de LoA para acceder al endpoint a medio (Substantial del eIDAS).
Para establecer el nivel alto (High), es necesario utilizar el método isHighLoA(authentication).
Por ejemplo:Bloque de código language java @GetMapping( "/private/afiliacion" ) @Operation( summary = "Endpoint test /afiliacion", description = "Obtiene el dto de afiliación del token llamando a serviciosgente internamente", tags = {"Serviciosgente"}, security = {@SecurityRequirement( name = "OIDC", scopes = "openid" )}, responses = { @ApiResponse( responseCode = "401", description = "Token inválido o LoA mínimo no alcanzado", content = @Content ), @ApiResponse( responseCode = "500", description = "Error de comunicación con serviciosgente", content = @Content ), @ApiResponse( responseCode = "200", description = "Token subject.", content = @Content( schema = @Schema( implementation = AfiliacionDTO.class ) ) ) } ) @PreAuthorize( "@umuJwtLoaAuthenticator.isSubstantialLoA(authentication)" ) public ResponseEntity<AfiliacionDTO> getAfiliacionGente( @AuthenticationPrincipal Jwt jwt ) {
RESPUESTA
TABLA DE EQUIVALENCIAS
| Advertencia |
|---|
Estas equivalencias son TEMPORALES y todavía pueden estar sujetas a modificaciones. |
...