Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

...

Dependiendo de la situación, se distinguen dos tipos de configuraciones:
- Global: Todos los endpoints de nuestra API requerirán el mismo nivel LoA establecido en su configuración.
- Por endpointmétodo: Configurar el nivel LoA de forma independiente para cada endpoint. 

Tabla de contenidos

Tabla de contenidos
outlinetrue

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:

Info

Con la configuración actual de las APIs, con el parent fundewebjs-api-parent (ver Creación y estructura de proyecto SpringBootMigración de APIs a Parent FundeWebJS),

no es necesario realizar ninguna configuración de librerías en pom.xml.

Expandir
titleVer configuración antigua.
Bloque de código
languagexml
	<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.

Clase Configuration (SecurityConfig)


Clase Configuration (SecurityConfig)

  1. Si no existe en nuestro proyecto, crear una clase SecurityConfig.java nueva a partir del código de FundeWebJSSecurityConfig.

    Bloque de código
    languagejava
    titleFundeWebJSSecurityConfig
    collapsetrue
    @Log4j2
    @Configuration
    public class FundeWebJSSecurityConfig {
    
    	@Value( "${server.scopes}" )
    	private String[] serverScopes;
    
    	@Value( "${app.server.path}" )
    	private String apiPath;
    
    
    	/**
    	 * Proveedor de gestion de acceoss
    	 */
    	@Bean( name = "fundeWebJsDefaultSecurityFilterChain" )
    	public SecurityFilterChain filterChain( HttpSecurity http ) throws Exception {
    
    		log.debug( "Carga SecurityFilterChain desde FundewebJs-Starter" );
    
    		http.requestMatchers().antMatchers( "/public/**" ).and().requestMatchers().antMatchers( apiPath + "/**" ).and()
    		.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS )
    		// configuro politica de sesion sin estado
    		.and().cors() // Aniado configuracion CORS por defecto
    		.and().csrf().disable().authorizeRequests().mvcMatchers( apiPath + "/public/**" ).permitAll()
    		.mvcMatchers( apiPath + "/**" ).hasAnyAuthority( serverScopes ).anyRequest().authenticated().and()
    		.addFilterAfter( new FundeWebJSLoggingAuthorizationFilter(), BearerTokenAuthenticationFilter.class )
    		.oauth2ResourceServer()
    		.jwt();
    
    		return http.build();
    	}
    
    }
    Si no existe en nuestro proyecto, crear una clase SecurityConfig.java nueva a partir del código de FundeWebJSSecurityConfig (ubicada en la librería fundewebjs-security).



  2. En el application.properties (de local y de los entornos en Helm Chart), añadir la siguiente property:

...

Configuración para establecer el mismo nivel LoA mínimo en todos los endpoints de una API:

  1. En la clase con la configuración de seguridad (ver pasos 1 y 2 de la configuración común), 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.SUBSTANTIAL);
    	}



  2. 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
    languagejava
    .addFilterAfter( loaFilterBean(), BearerTokenAuthenticationFilter.class )

    Hay que añadirlo justo antes de  .oauth2ResourceServer().jwt().
    Por ejemplo:

    Bloque de código
    languagejava
       @Override    
       public SecurityFilterChain filterChain( 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();        
           return http.build();
        }


    Advertencia

    Repetimos: ESTA CONFIGURACIÓN GLOBAL VALIDARÁ EL NIVEL DEL CLAIM LOA EN TODOS LOS ENDPOINTS DEL API.



POR MÉTODO

Configuración para establecer niveles LoA mínimos (o diferentes) en un/os endpoints concretos de nuestra API:

Clase Configuration (SecurityConfig)

  1. En la clase con la configuración de seguridad (ver pasos 1 y 2 de la configuración común), añadir la siguiente anotación en la declaración de la clase:

    Bloque de código
    languagejava
    @EnableGlobalMethodSecurity( prePostEnabled = true )


  2. Añadir el siguiente Bean:

    Bloque de código
    languagejava
    @Bean
    UmuJwtLoaAccessDeniedHandler accessDeniedHandler() {
       return new UmuJwtLoaAccessDeniedHandler();
    }


  3. 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
    languagejava
    .and().exceptionHandling().accessDeniedHandler( accessDeniedHandler() )

    Ejemplo de configuración completa:

    Bloque de código
    languagejava
    public SecurityFilterChain filterChain( 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();        
    	return http.build();     
    }


    RestController
    Ahora, en nuestro RestController, anotar el método con nuestro endpoint a securizar con la siguiente anotación:

    Bloque de código
    languagejava
    @PreAuthorize( "@umuJwtLoaAuthenticator.isSubstantialLoA(authentication)" )


    Advertenciainfo

    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
    languagejava
        @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.Datos de Afiliación del propietario del token obtenidos correctamente",	content = @Content( schema = @Schema( implementation = AfiliacionDTO.class ) ) )
    				} )
    	@PreAuthorize( "@umuJwtLoaAuthenticator.isSubstantialLoA(authentication)" )
    	public ResponseEntity<AfiliacionDTO> getAfiliacionGente( @AuthenticationPrincipal Jwt jwt ) {
    
    


    Advertencia

    Repetimos: ESTA CONFIGURACIÓN POR MÉTODO VALIDARÁ EL NIVEL DEL CLAIM LOA EN EL ENDPOINT CON LA ANOTACIÓN PREAUTHORIZE.


...

RESPUESTA DE ERROR

Cuando se intenta acceder a un endpoint securizado con un token sin el claim LoA mínimo (independientemente de la configuración elegida), se devolverá la siguiente información:

- Código HTTP: 401
- Cabecera en la respuesta: umu-authenticat: invalid_loa_claim 
- Cabecera en la respuesta: www-authenticate: Bearer error="invalid_loa_claim",error_description="Invalid LoA Claim. Excepted level 'SUBSTANTIAL' : Found level: 'LOW' ",error_uri="https://tools.ietf.org/html/rfc6750#section-3.1

...

Combinación de AutenticaciónLoA
LDAP (cuenta UM)LOW
LDAP (cuenta UM) + MFA (OTP)SUBSTANTIAL
CMNLOW
CMN + MFASUBSTANTIAL
Cl@ve certificadoSUBSTANTIAL
Cl@ve PIN (lleva implícito el OTP)SUBSTANTIAL
Cl@ve permanenteLOWSUBSTANTIAL
Cl@ve certificado + MFASUBSTANTIAL
Cl@ve PIN + MFASUBSTANTIAL
Cl@ve permanente + MFASUBSTANTIAL
*Cl@ve + DNIeHIGH

...