tutorial sesiones manejo español con spring spring-security load-balancing amazon-ec2

sesiones - spring security tutorial español pdf



¿Cómo puedo usar Spring Security sin sesiones? (7)

Después de luchar con las numerosas soluciones publicadas en esta respuesta, para intentar que funcione algo cuando uso la configuración del espacio de nombres <http> , finalmente encontré un enfoque que realmente funciona para mi caso de uso. En realidad, no necesito que Spring Security no inicie una sesión (porque utilizo la sesión en otras partes de la aplicación), solo que no "recuerda" la autenticación en la sesión (debe volver a verificarse) cada solicitud).

Para empezar, no pude averiguar cómo hacer la técnica de "implementación nula" descrita anteriormente. No estaba claro si se supone que debes configurar el securityContextRepository como null o como una implementación no operativa. El primero no funciona porque se lanza una NullPointerException dentro de SecurityContextPersistenceFilter.doFilter() . En cuanto a la implementación no operativa, traté de implementar de la manera más simple que pude imaginar:

public class NullSpringSecurityContextRepository implements SecurityContextRepository { @Override public SecurityContext loadContext(final HttpRequestResponseHolder requestResponseHolder_) { return SecurityContextHolder.createEmptyContext(); } @Override public void saveContext(final SecurityContext context_, final HttpServletRequest request_, final HttpServletResponse response_) { } @Override public boolean containsContext(final HttpServletRequest request_) { return false; } }

Esto no funciona en mi aplicación, debido a algún extraño ClassCastException tiene que ver con el tipo response_ .

Incluso suponiendo que logré encontrar una implementación que funciona (simplemente no almacenando el contexto en sesión), todavía existe el problema de cómo inyectar eso en los filtros creados por la configuración <http> . No puede simplemente reemplazar el filtro en la posición SECURITY_CONTEXT_FILTER , según los docs . La única forma que encontré para engancharme en el SecurityContextPersistenceFilter que se creó debajo de las cubiertas fue escribir un bean de ApplicationContextAware feo:

public class SpringSecuritySessionDisabler implements ApplicationContextAware { private final Logger logger = LoggerFactory.getLogger(SpringSecuritySessionDisabler.class); private ApplicationContext applicationContext; @Override public void setApplicationContext(final ApplicationContext applicationContext_) throws BeansException { applicationContext = applicationContext_; } public void disableSpringSecuritySessions() { final Map<String, FilterChainProxy> filterChainProxies = applicationContext .getBeansOfType(FilterChainProxy.class); for (final Entry<String, FilterChainProxy> filterChainProxyBeanEntry : filterChainProxies.entrySet()) { for (final Entry<String, List<Filter>> filterChainMapEntry : filterChainProxyBeanEntry.getValue() .getFilterChainMap().entrySet()) { final List<Filter> filterList = filterChainMapEntry.getValue(); if (filterList.size() > 0) { for (final Filter filter : filterList) { if (filter instanceof SecurityContextPersistenceFilter) { logger.info( "Found SecurityContextPersistenceFilter, mapped to URL ''{}'' in the FilterChainProxy bean named ''{}'', setting its securityContextRepository to the null implementation to disable caching of authentication", filterChainMapEntry.getKey(), filterChainProxyBeanEntry.getKey()); ((SecurityContextPersistenceFilter) filter).setSecurityContextRepository( new NullSpringSecurityContextRepository()); } } } } } } }

De todos modos, a la solución que realmente funciona, aunque muy hackish. Simplemente use un Filter que elimine la entrada de sesión que HttpSessionSecurityContextRepository busca cuando hace su trabajo:

public class SpringSecuritySessionDeletingFilter extends GenericFilterBean implements Filter { @Override public void doFilter(final ServletRequest request_, final ServletResponse response_, final FilterChain chain_) throws IOException, ServletException { final HttpServletRequest servletRequest = (HttpServletRequest) request_; final HttpSession session = servletRequest.getSession(); if (session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY) != null) { session.removeAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); } chain_.doFilter(request_, response_); } }

Luego en la configuración:

<bean id="springSecuritySessionDeletingFilter" class="SpringSecuritySessionDeletingFilter" /> <sec:http auto-config="false" create-session="never" entry-point-ref="authEntryPoint"> <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_REMEMBERED" /> <sec:intercept-url pattern="/static/**" filters="none" /> <sec:custom-filter ref="myLoginFilterChain" position="FORM_LOGIN_FILTER" /> <sec:custom-filter ref="springSecuritySessionDeletingFilter" before="SECURITY_CONTEXT_FILTER" /> </sec:http>

Estoy construyendo una aplicación web con Spring Security que vivirá en Amazon EC2 y usará Elastic Load Balancers de Amazon. Desafortunadamente, ELB no es compatible con sesiones fijas, por lo que debo asegurarme de que mi aplicación funcione correctamente sin sesiones.

Hasta ahora, he configurado RememberMeServices para asignar un token a través de una cookie, y esto funciona bien, pero quiero que la cookie caduque con la sesión del navegador (por ejemplo, cuando el navegador se cierra).

Tengo que imaginar que no soy el primero en querer usar Spring Security sin sesiones ... ¿Alguna sugerencia?


Eche un vistazo a SecurityContextPersistenceFilter clase SecurityContextPersistenceFilter . Define cómo se rellena SecurityContextHolder . Por defecto, utiliza HttpSessionSecurityContextRepository para almacenar el contexto de seguridad en la sesión http.

Implementé este mecanismo bastante fácilmente, con SecurityContextRepository personalizado.

Vea el securityContext.xml continuación:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"> <context:annotation-config/> <sec:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/> <bean id="securityContextRepository" class="com.project.server.security.TokenSecurityContextRepository"/> <bean id="securityContextFilter" class="com.project.server.security.TokenSecurityContextPersistenceFilter"> <property name="repository" ref="securityContextRepository"/> </bean> <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <constructor-arg value="/login.jsp"/> <constructor-arg> <list> <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/> </list> </constructor-arg> </bean> <bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationSuccessHandler"> <bean class="com.project.server.security.TokenAuthenticationSuccessHandler"> <property name="defaultTargetUrl" value="/index.html"/> <property name="passwordExpiredUrl" value="/changePassword.jsp"/> <property name="alwaysUseDefaultTargetUrl" value="true"/> </bean> </property> <property name="authenticationFailureHandler"> <bean class="com.project.server.modules.security.CustomUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/login.jsp?failure=1"/> </bean> </property> <property name="filterProcessesUrl" value="/j_spring_security_check"/> <property name="allowSessionCreation" value="false"/> </bean> <bean id="servletApiFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/> <bean id="anonFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter"> <property name="key" value="ClientApplication"/> <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/> </bean> <bean id="exceptionTranslator" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <property name="authenticationEntryPoint"> <bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp"/> </bean> </property> <property name="accessDeniedHandler"> <bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/login.jsp?failure=2"/> </bean> </property> <property name="requestCache"> <bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/> </property> </bean> <alias name="filterChainProxy" alias="springSecurityFilterChain"/> <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy"> <sec:filter-chain-map path-type="ant"> <sec:filter-chain pattern="/**" filters="securityContextFilter, logoutFilter, formLoginFilter, servletApiFilter, anonFilter, exceptionTranslator, filterSecurityInterceptor"/> </sec:filter-chain-map> </bean> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="securityMetadataSource"> <sec:filter-security-metadata-source use-expressions="true"> <sec:intercept-url pattern="/staticresources/**" access="permitAll"/> <sec:intercept-url pattern="/index.html*" access="hasRole(''USER_ROLE'')"/> <sec:intercept-url pattern="/rpc/*" access="hasRole(''USER_ROLE'')"/> <sec:intercept-url pattern="/**" access="permitAll"/> </sec:filter-security-metadata-source> </property> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> </bean> <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <bean class="org.springframework.security.access.vote.RoleVoter"/> <bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/> </list> </property> </bean> <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <bean name="authenticationProvider" class="com.project.server.modules.security.oracle.StoredProcedureBasedAuthenticationProviderImpl"> <property name="dataSource" ref="serverDataSource"/> <property name="userDetailsService" ref="userDetailsService"/> <property name="auditLogin" value="true"/> <property name="postAuthenticationChecks" ref="customPostAuthenticationChecks"/> </bean> </list> </property> </bean> <bean id="customPostAuthenticationChecks" class="com.project.server.modules.security.CustomPostAuthenticationChecks"/> <bean name="userDetailsService" class="com.project.server.modules.security.oracle.UserDetailsServiceImpl"> <property name="dataSource" ref="serverDataSource"/> </bean> </beans>


En Spring Security 3 con Java Config , puede usar HttpSecurity.sessionManagement() :

@Override protected void configure(final HttpSecurity http) throws Exception { http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); }


En realidad create-session="never" no significa ser completamente apátrida. Hay un problema para eso en la administración de problemas de Spring Security.


Parece ser aún más fácil en Spring Securitiy 3.0. Si está utilizando la configuración del espacio de nombres, simplemente puede hacer lo siguiente:

<http create-session="never"> <!-- config --> </http>

O podría configurar el SecurityContextRepository como nulo, y tampoco se guardará nada de esa manera.


Solo una nota rápida: es "crear-sesión" en lugar de "crear-sesiones"

create-session

Controla el entusiasmo con el que se crea una sesión HTTP.

Si no está establecido, el valor predeterminado es "ifRequired". Otras opciones son "siempre" y "nunca".

La configuración de este atributo afecta a las propiedades allowSessionCreation y forceEagerSessionCreation de HttpSessionContextIntegrationFilter. allowSessionCreation siempre será verdadero a menos que este atributo se establezca en "nunca". forceEagerSessionCreation es "falso" a menos que esté configurado a "siempre".

Entonces la configuración predeterminada permite la creación de la sesión pero no la fuerza. La excepción es si el control de sesión simultánea está habilitado, cuando forceEagerSessionCreation se establecerá en verdadero, independientemente de la configuración aquí. El uso de "nunca" provocaría una excepción durante la inicialización de HttpSessionContextIntegrationFilter.

Para detalles específicos sobre el uso de la sesión, hay una buena documentación en el HttpSessionSecurityContextRepository javadoc.


Trabajamos en el mismo problema (inyectando un SecurityContextRepository personalizado a SecurityContextPersistenceFilter) durante 4-5 horas hoy. Finalmente, lo descubrimos. En primer lugar, en la sección 8.3 de Spring Security ref. doc, hay una definición de SecurityContextPersistenceFilter bean

<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"> <property name=''securityContextRepository''> <bean class=''org.springframework.security.web.context.HttpSessionSecurityContextRepository''> <property name=''allowSessionCreation'' value=''false'' /> </bean> </property> </bean>

Y después de esta definición, existe esta explicación: "Alternativamente, podría proporcionar una implementación nula de la interfaz SecurityContextRepository, lo que evitará que se almacene el contexto de seguridad, incluso si ya se creó una sesión durante la solicitud".

Necesitábamos inyectar nuestro SecurityContextRepository personalizado en SecurityContextPersistenceFilter. Así que simplemente cambiamos la definición de bean anterior con nuestra impl personalizada y la colocamos en el contexto de seguridad.

Cuando ejecutamos la aplicación, rastreamos los registros y vimos que SecurityContextPersistenceFilter no estaba utilizando nuestra impl personalizada, sino que estaba utilizando el HttpSessionSecurityContextRepository.

Después de algunas otras cosas que probamos, nos dimos cuenta de que teníamos que darle a nuestro impl SecurityContextRepository personalizado el atributo "security-context-repository-ref" del espacio de nombres "http". Si usa el espacio de nombres "http" y quiere inyectar su propia impl SecurityContextRepository, pruebe el atributo "security-context-repository-ref".

Cuando se utiliza el espacio de nombres "http", se ignora una definición separada de SecurityContextPersistenceFilter. Como he copiado anteriormente, el documento de referencia. no dice eso.

Por favor corrígeme si malinterpreté las cosas.