taglibs sec hasrole spring authentication spring-security filter jwt

spring - hasrole - sec:authorize thymeleaf



Cómo funciona la cadena de filtros Spring Security (2)

UsernamePasswordAuthenticationFilter solo se usa para /login , y los últimos filtros no.

No, UsernamePasswordAuthenticationFilter extiende AbstractAuthenticationProcessingFilter , y este contiene un RequestMatcher , eso significa que puede definir su propia url de procesamiento, este filtro solo maneja RequestMatcher coincide con la url de solicitud, la url de procesamiento predeterminada es /login .

Los filtros posteriores aún pueden manejar la solicitud, si UsernamePasswordAuthenticationFilter ejecuta chain.doFilter(request, response); .

Más detalles sobre los montadores centrales

¿El elemento de espacio de nombres de inicio de sesión configura automáticamente estos filtros?

UsernamePasswordAuthenticationFilter es creado por <form-login> , estos son alias de filtro estándar y pedidos

¿Cada solicitud (autenticada o no) llega a FilterSecurityInterceptor para la URL que no es de inicio de sesión?

Depende de si los instaladores anteriores tienen éxito, pero FilterSecurityInterceptor es el último instalador normalmente.

¿La configuración de dos elementos http crea dos springSecurityFitlerChains?

Sí, cada fitlerChain tiene un RequestMatcher , si RequestMatcher coincide con la solicitud, la solicitud será manejada por los instaladores en la cadena de instaladores.

RequestMatcher predeterminado coincide con todas las solicitudes si no configura el patrón, o puede configurar la URL específica ( <http pattern="/rest/**" ).

Si quieres saber más sobre los fitlers, creo que puedes consultar el código fuente en seguridad de primavera. doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)

Me doy cuenta de que la seguridad de Spring se basa en una cadena de filtros, que interceptará la solicitud, detectará (ausencia de) autenticación, redirigirá al punto de entrada de autenticación o pasará la solicitud al servicio de autorización y, finalmente, dejará que la solicitud llegue al servlet o arroje una excepción de seguridad (no autenticado o no autorizado). DelegatingFitlerProxy pega estos filtros juntos. Para realizar sus tareas, estos servicios de acceso de filtro como UserDetailsService y AuthenticationManager .

Los filtros clave en la cadena son (en el orden)

  • SecurityContextPersistenceFilter (restaura la autenticación de JSESSIONID)
  • UsernamePasswordAuthenticationFilter (realiza la autenticación)
  • ExceptionTranslationFilter (captura excepciones de seguridad de FilterSecurityInterceptor)
  • FilterSecurityInterceptor (puede arrojar excepciones de autenticación y autorización)

Estoy confundido sobre cómo se usan estos filtros. ¿Es que para el inicio de sesión proporcionado por la primavera, UsernamePasswordAuthenticationFilter solo se usa para / login , y los últimos filtros no? ¿El elemento de espacio de nombres de inicio de sesión configura automáticamente estos filtros? ¿Cada solicitud (autenticada o no) llega a FilterSecurityInterceptor para la URL que no es de inicio de sesión?

¿Qué sucede si deseo asegurar mi API REST con JWT-token , que se recupera del inicio de sesión? Debo configurar dos etiquetas http configuración de espacio de nombres, ¿derechos? Otro para / iniciar sesión con UsernamePasswordAuthenticationFilter , y otro para REST url''s, con JwtAuthenticationFilter personalizado.

¿La configuración de dos elementos http crea dos springSecurityFitlerChains ? ¿ UsernamePasswordAuthenticationFilter está desactivado por defecto, hasta que declare form-login ? ¿Cómo puedo reemplazar SecurityContextPersistenceFilter con uno, que obtendrá la Authentication del JWT-token existente JWT-token lugar de JSESSIONID ?


La cadena de filtros de seguridad Spring es un motor muy complejo y flexible.

Los filtros clave en la cadena son (en el orden)

  • SecurityContextPersistenceFilter (restaura la autenticación de JSESSIONID)
  • UsernamePasswordAuthenticationFilter (realiza la autenticación)
  • ExceptionTranslationFilter (captura excepciones de seguridad de FilterSecurityInterceptor)
  • FilterSecurityInterceptor (puede arrojar excepciones de autenticación y autorización)

Mirando la documentación actual de la versión estable 4.2.1 , sección 13.3 Orden de filtros , puede ver toda la organización de filtros de la cadena de filtros:

13.3 Ordenar filtros

El orden en que se definen los filtros en la cadena es muy importante. Independientemente de los filtros que esté utilizando, el orden debe ser el siguiente:

  1. ChannelProcessingFilter , porque podría necesitar redirigir a un protocolo diferente

  2. SecurityContextPersistenceFilter , por lo que se puede configurar un SecurityContext en SecurityContextHolder al comienzo de una solicitud web, y cualquier cambio en SecurityContext se puede copiar en HttpSession cuando finaliza la solicitud web (listo para usar con la próxima solicitud web)

  3. ConcurrentSessionFilter , porque utiliza la funcionalidad SecurityContextHolder y necesita actualizar SessionRegistry para reflejar las solicitudes en curso del director

  4. Mecanismos de procesamiento de autenticación - UsernamePasswordAuthenticationFilter , CasAuthenticationFilter , BasicAuthenticationFilter , etc. - para que SecurityContextHolder pueda modificarse para que contenga un token de solicitud de autenticación válido

  5. El SecurityContextHolderAwareRequestFilter , si lo está utilizando para instalar un HttpServletRequestWrapper consciente de Spring Security en su contenedor de servlet

  6. JaasApiIntegrationFilter , si un JaasAuthenticationToken está en SecurityContextHolder, procesará FilterChain como Asunto en JaasAuthenticationToken

  7. RememberMeAuthenticationFilter , de modo que si ningún mecanismo de procesamiento de autenticación anterior actualizó SecurityContextHolder y la solicitud presenta una cookie que permite que se realicen los servicios recordar, se colocará allí un objeto de autenticación recordado adecuado

  8. AnonymousAuthenticationFilter , de modo que si ningún mecanismo de procesamiento de autenticación anterior actualizara el SecurityContextHolder, se colocará un objeto de autenticación anónimo

  9. ExceptionTranslationFilter , para detectar cualquier excepción de Spring Security para que se pueda devolver una respuesta de error HTTP o se pueda iniciar un AuthenticationEntryPoint apropiado

  10. FilterSecurityInterceptor , para proteger los URI web y generar excepciones cuando se deniega el acceso

Ahora, intentaré continuar con sus preguntas una por una:

Estoy confundido sobre cómo se usan estos filtros. ¿Es que para el inicio de sesión proporcionado por la primavera, UsernamePasswordAuthenticationFilter solo se usa para / login, y los últimos filtros no? ¿El elemento de espacio de nombres de inicio de sesión configura automáticamente estos filtros? ¿Cada solicitud (autenticada o no) llega a FilterSecurityInterceptor para la URL que no es de inicio de sesión?

Una vez que esté configurando una sección <security-http> , para cada una debe proporcionar al menos un mecanismo de autenticación. Este debe ser uno de los filtros que coincidan con el grupo 4 en la sección 13.3 Orden de filtros de la documentación de Spring Security que acabo de mencionar.

Esta es la seguridad mínima válida: elemento http que se puede configurar:

<security:http authentication-manager-ref="mainAuthenticationManager" entry-point-ref="serviceAccessDeniedHandler"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole(''ROLE_ADMIN'')"/> </security:http>

Al hacerlo, estos filtros se configuran en el proxy de la cadena de filtros:

{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "8": "org.springframework.security.web.session.SessionManagementFilter", "9": "org.springframework.security.web.access.ExceptionTranslationFilter", "10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }

Nota: Los obtengo creando un RestController simple que @Autowires FilterChainProxy y devuelve su contenido:

@Autowired private FilterChainProxy filterChainProxy; @Override @RequestMapping("/filterChain") public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ return this.getSecurityFilterChainProxy(); } public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>(); int i = 1; for(SecurityFilterChain secfc : this.filterChainProxy.getFilterChains()){ //filters.put(i++, secfc.getClass().getName()); Map<Integer, String> filters = new HashMap<Integer, String>(); int j = 1; for(Filter filter : secfc.getFilters()){ filters.put(j++, filter.getClass().getName()); } filterChains.put(i++, filters); } return filterChains; }

Aquí podríamos ver que con solo declarar el elemento <security:http> con una configuración mínima, se incluyen todos los filtros predeterminados, pero ninguno de ellos es del tipo Autenticación (4to grupo en la sección 13.3 Orden de filtros). Entonces, en realidad significa que con solo declarar la security:http elemento security:http , SecurityContextPersistenceFilter, ExceptionTranslationFilter y FilterSecurityInterceptor se configuran automáticamente.

De hecho, se debe configurar un mecanismo de procesamiento de autenticación, e incluso el procesamiento de beans de espacio de nombres de seguridad reclama eso, arrojando un error durante el inicio, pero se puede omitir agregando un atributo de punto de entrada-ref en <http:security>

Si agrego un <form-login> básico a la configuración, de esta manera:

<security:http authentication-manager-ref="mainAuthenticationManager"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole(''ROLE_ADMIN'')"/> <security:form-login /> </security:http>

Ahora, el filterChain será así:

{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter", "6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter", "7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "10": "org.springframework.security.web.session.SessionManagementFilter", "11": "org.springframework.security.web.access.ExceptionTranslationFilter", "12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }

Ahora, estos dos filtros org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter y org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter se crean y configuran en FilterChainProxy.

Entonces, ahora, las preguntas:

¿Es que para el inicio de sesión proporcionado por la primavera, UsernamePasswordAuthenticationFilter solo se usa para / login, y los últimos filtros no?

Sí, se utiliza para intentar completar un mecanismo de procesamiento de inicio de sesión en caso de que la solicitud coincida con la URL de UsernamePasswordAuthenticationFilter. Esta url se puede configurar o incluso cambiar su comportamiento para que coincida con cada solicitud.

También podría tener más de un mecanismo de procesamiento de autenticación configurado en el mismo FilterchainProxy (como HttpBasic, CAS, etc.).

¿El elemento de espacio de nombres de inicio de sesión configura automáticamente estos filtros?

No, el elemento form-login configura UsernamePasswordAUthenticationFilter, y en caso de que no proporcione una URL de página de inicio de sesión, también configura org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, que termina en un inicio de sesión simple autogenerado página.

Los otros filtros se configuran automáticamente de forma predeterminada simplemente creando un elemento <security:http> sin atributo security:"none" .

¿Cada solicitud (autenticada o no) llega a FilterSecurityInterceptor para la URL que no es de inicio de sesión?

Cada solicitud debe llegar a ella, ya que es el elemento que se encarga de si la solicitud tiene los derechos para llegar a la URL solicitada. Pero algunos de los filtros procesados ​​antes podrían detener el procesamiento de la cadena de filtros simplemente no llamando a FilterChain.doFilter(request, response); . Por ejemplo, un filtro CSRF podría detener el procesamiento de la cadena de filtros si la solicitud no tiene el parámetro csrf.

¿Qué sucede si deseo asegurar mi API REST con JWT-token, que se recupera del inicio de sesión? Debo configurar dos etiquetas http de configuración de espacio de nombres, ¿derechos? Otro para / iniciar sesión con UsernamePasswordAuthenticationFilter , y otro para REST url''s, con JwtAuthenticationFilter personalizado.

No, no estás obligado a hacerlo de esta manera. Puede declarar UsernamePasswordAuthenticationFilter y JwtAuthenticationFilter en el mismo elemento http, pero depende del comportamiento concreto de cada uno de estos filtros. Ambos enfoques son posibles, y cuál elegir finalmente depende de sus propias preferencias.

¿La configuración de dos elementos http crea dos springSecurityFitlerChains?

Sí, eso es verdad

¿UsernamePasswordAuthenticationFilter está desactivado por defecto, hasta que declare el inicio de sesión de formulario?

Sí, puedes verlo en los filtros generados en cada una de las configuraciones que publiqué

¿Cómo puedo reemplazar SecurityContextPersistenceFilter con uno, que obtendrá la autenticación del token JWT existente en lugar de JSESSIONID?

Puede evitar SecurityContextPersistenceFilter, simplemente configurando la estrategia de sesión en <http:element> . Solo configúrelo así:

<security:http create-session="stateless" >

O, en este caso, podría sobrescribirlo con otro filtro, de esta manera dentro del elemento <security:http> :

<security:http ...> <security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/> </security:http> <beans:bean id="myCustomFilter" class="com.xyz.myFilter" />

EDITAR:

Una pregunta sobre "También podría tener más de un mecanismo de procesamiento de autenticación configurado en el mismo FilterchainProxy". ¿Este último sobrescribirá la autenticación realizada por el primero, si declara múltiples filtros de autenticación (implementación Spring)? ¿Cómo se relaciona esto con tener múltiples proveedores de autenticación?

Esto finalmente depende de la implementación de cada filtro en sí, pero es cierto el hecho de que los últimos filtros de autenticación al menos pueden sobrescribir cualquier autenticación previa que eventualmente haya realizado los filtros anteriores.

Pero esto no necesariamente sucederá. Tengo algunos casos de producción en servicios REST seguros donde utilizo un tipo de token de autorización que se puede proporcionar tanto como un encabezado Http o dentro del cuerpo de la solicitud. Así que configuro dos filtros que recuperan ese token, en un caso desde el Encabezado Http y el otro desde el cuerpo de la solicitud de descanso. Es cierto el hecho de que si una solicitud http proporciona ese token de autenticación como encabezado Http y dentro del cuerpo de la solicitud, ambos filtros intentarán ejecutar el mecanismo de autenticación delegándolo al administrador, pero podría evitarse fácilmente simplemente verificando si la solicitud es ya autenticado justo al comienzo del método doFilter() de cada filtro.

Tener más de un filtro de autenticación está relacionado con tener más de un proveedor de autenticación, pero no lo fuerce. En el caso que expuse antes, tengo dos filtros de autenticación pero solo tengo un proveedor de autenticación, ya que ambos filtros crean el mismo tipo de objeto de autenticación, por lo que en ambos casos el administrador de autenticación lo delega al mismo proveedor.

Y frente a esto, yo también tengo un escenario en el que publico solo un UsernamePasswordAuthenticationFilter pero las credenciales del usuario pueden estar contenidas en DB o LDAP, por lo que tengo dos proveedores de soporte UsernamePasswordAuthenticationToken, y AuthenticationManager delega cualquier intento de autenticación del filtro a los proveedores. secuencialmente para validar las credenciales.

Por lo tanto, creo que está claro que ni la cantidad de filtros de autenticación determina la cantidad de proveedores de autenticación ni la cantidad de proveedores determina la cantidad de filtros.

Además, la documentación indica que SecurityContextPersistenceFilter es responsable de limpiar SecurityContext, que es importante debido a la agrupación de subprocesos. Si lo omito o proporciono una implementación personalizada, tengo que implementar la limpieza manualmente, ¿verdad? ¿Hay más trucos similares al personalizar la cadena?

No examiné cuidadosamente este filtro antes, pero después de su última pregunta, he estado verificando su implementación y, como generalmente en Spring, casi todo se puede configurar, extender o sobrescribir.

SecurityContextPersistenceFilter delega en una implementación de SecurityContextRepository la búsqueda de SecurityContext. Por defecto, se utiliza un HttpSessionSecurityContextRepository , pero esto podría cambiarse utilizando uno de los constructores del filtro. Por lo tanto, puede ser mejor escribir un SecurityContextRepository que se ajuste a sus necesidades y simplemente configurarlo en SecurityContextPersistenceFilter, confiando en su comportamiento comprobado en lugar de comenzar a hacer todo desde cero.