Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An Authentication object was not found in the SecurityContext - Spring 3.2.2

I'm trying to invoke a protected method from a class that implements the ApplicationListener<AuthenticationSuccessEvent> interface on successful login (Spring 3.2.2 and Spring Security 3.2.0 M1). This is my previous question.

The application runs under the following environment.

  • Spring 3.2.2
  • Spring Security 3.2.0
  • JPA 2.0
  • JSF 2.1.9
  • MySQL 5.6.11
  • JDK-7u11
  • NetBeans 7.2.1

I have added the following libraries related to Spring security to the classpath.

  • spring-security-core-3.2.0.M1.jar
  • spring-security-config-3.2.0.M1.jar
  • spring-security-web-3.2.0.M1.jar

The class that implements ApplicationListener<AuthenticationSuccessEvent> is as follows.

package loginsuccesshandler;  import admin.dao.service.StateService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.stereotype.Service;  @Service public final class AuthSuccessHandler implements ApplicationListener<AuthenticationSuccessEvent> {     @Autowired     private StateService stateService;      @Override     public void onApplicationEvent(AuthenticationSuccessEvent event)      {         System.out.println(event.getAuthentication());         System.out.println("rowCount = "+stateService.rowCount());     } } 

This prevents a user from being logged in even with correct credentials with the following message (it is just an example. Counting the number of states upon successful authentication is not required at all).

An Authentication object was not found in the SecurityContext


The event is raised. The first statement inside the onApplicationEvent() method displays the following.

org.springframework.security.authentication.UsernamePasswordAuthenticationToken@45264a59: Principal: org.springframework.security.core.userdetails.User@586034f:Username: admin;  Password: [PROTECTED];  Enabled: true;  AccountNonExpired: true;  credentialsNonExpired: true;  AccountNonLocked: true;  Granted Authorities: ROLE_ADMIN;  Credentials: [PROTECTED];  Authenticated: true;  Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 127.0.0.1;  SessionId: 88777A678DC5BB0272F84CA4BC61FAF2; Granted Authorities: ROLE_ADMIN 

So it appears that the user is authenticated and the authentication object is available.


My springSecurity.xml file simply looks like the following.

<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security"   xmlns:beans="http://www.springframework.org/schema/beans"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://www.springframework.org/schema/beans            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd            http://www.springframework.org/schema/security            http://www.springframework.org/schema/security/spring-security-3.1.xsd">      <http pattern="/utility/Login.jsf*" security="none"/>     <debug/>     <http auto-config='true' use-expressions="true" disable-url-rewriting="true">         <session-management session-fixation-protection="newSession">             <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />         </session-management>          <intercept-url pattern="/admin_side/**" access="hasRole('ROLE_ADMIN')" requires-channel="any"/>         <intercept-url pattern="/utility/Login.jsf" access="permitAll" requires-channel="any"/>         <http-basic />         <anonymous />          <form-login login-processing-url="/j_spring_security_check" login-page="/utility/Login.jsf" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/>         <logout logout-success-url="/utility/Login.jsf" invalidate-session="true" delete-cookies="JSESSIONID"/>     </http>      <authentication-manager>        <authentication-provider>             <jdbc-user-service data-source-ref="dataSource"                users-by-username-query="select email_id, password, enabled from user_table where lower(email_id)=lower(?)"                authorities-by-username-query="select ut.email_id, ur.authority from user_table ut, user_roles ur where ut.user_id=ur.user_id and lower(ut.email_id)=lower(?)"/>        </authentication-provider>     </authentication-manager>      <beans:bean id="loginSuccessHandler" class="loginsuccesshandler.LoginSuccessHandler"/>     <beans:bean id="authenticationFailureHandler" class="loginsuccesshandler.AuthenticationFailureHandler" />              <global-method-security secured-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="false">         <protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/>     </global-method-security> </beans:beans> 

The Spring security works fine, when the following lines of XML is omitted from the spring-security.xml file.

<global-method-security secured-annotations="enabled" proxy-target-class="false">      <protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/> </global-method-security> 

Can a protected method (with method security applied) be invoked from a class implementing the ApplicationListener<AuthenticationSuccessEvent> interface? If yes, then what is missing in my case? I have clicked thousands of links so far but couldn't find a single clue.


The application-context.xml file.

<?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:p="http://www.springframework.org/schema/p"        xmlns:aop="http://www.springframework.org/schema/aop"        xmlns:tx="http://www.springframework.org/schema/tx"        xmlns:context="http://www.springframework.org/schema/context"        xmlns:jee="http://www.springframework.org/schema/jee"        xmlns:mvc="http://www.springframework.org/schema/mvc"        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">      <context:component-scan base-package="admin.mangedbean loginsuccesshandler" use-default-filters="false">         <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>         <context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>       </context:component-scan>      <mvc:annotation-driven/>     <context:annotation-config/>      <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>                  <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory" >         <property name="jpaProperties">             <props>                 <prop key="hibernate.enable_lazy_load_no_trans">true</prop>             </props>         </property>          <property name="jpaPropertyMap">             <map>               <entry key="eclipselink.weaving" value="false"/>             </map>         </property>          <property name="loadTimeWeaver">             <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>         </property>     </bean>      <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">         <property name="entityManagerFactory" ref="entityManagerFactory"/>     </bean>      <tx:annotation-driven transaction-manager="transactionManager"/>      <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">         <property name="jndiName" value="java:comp/env/jdbc/social_networking"/>     </bean>      <!--The bean shown in the beginning is configured here-->     <bean id="authSuccessHandler" class="loginsuccesshandler.AuthSuccessHandler"/>       <bean id="testService" class="admin.dao.TestDAO"/>     <bean id="stateService" class="admin.dao.StateDAO"/>     <bean id="sharableService" class="admin.dao.SharableDAO"/> </beans> 

The web.xml file.

<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">              <context-param>         <param-name>contextConfigLocation</param-name>         <param-value>             /WEB-INF/applicationContext.xml             /WEB-INF/spring-security.xml         </param-value>     </context-param>      <context-param>         <param-name>javax.faces.PROJECT_STAGE</param-name>         <!--<param-value>Development</param-value>-->         <param-value>Production</param-value>     </context-param>      <context-param>         <param-name>log4jConfigLocation</param-name>         <param-value>/WEB-INF/log4j.properties</param-value>     </context-param>      <context-param>         <param-name>log4jExposeWebAppRoot</param-name>         <param-value>false</param-value>     </context-param>      <filter>         <filter-name>springSecurityFilterChain</filter-name>         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>     </filter>      <filter-mapping>         <filter-name>springSecurityFilterChain</filter-name>         <url-pattern>/*</url-pattern>         <dispatcher>REQUEST</dispatcher>         <dispatcher>FORWARD</dispatcher>     </filter-mapping>      <listener>         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>     </listener>      <listener>         <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>     </listener>              <listener>         <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>     </listener>      <listener>         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>     </listener>      <servlet>         <servlet-name>Faces Servlet</servlet-name>         <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>         <load-on-startup>1</load-on-startup>     </servlet>      <servlet-mapping>         <servlet-name>Faces Servlet</servlet-name>         <url-pattern>*.jsf</url-pattern>     </servlet-mapping>      <servlet-mapping>         <servlet-name>Faces Servlet</servlet-name>         <url-pattern>*.xhtml</url-pattern>     </servlet-mapping>      <security-constraint>         <display-name>Restrict direct access to XHTML files</display-name>         <web-resource-collection>             <web-resource-name>XHTML files</web-resource-name>             <url-pattern>*.xhtml</url-pattern>         </web-resource-collection>         <auth-constraint />     </security-constraint>       <session-config>         <session-timeout>             120         </session-timeout>     </session-config>     <welcome-file-list>         <welcome-file>/utility/Login.jsf</welcome-file>     </welcome-file-list>      <resource-ref>         <res-ref-name>jdbc/social_networking</res-ref-name>         <res-type>javax.sql.DataSource</res-type>         <res-auth>Container</res-auth>     </resource-ref> </web-app> 

The debug information can be seen below, when an attempt is made to login which ultimately fails.

DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf*' DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf*' DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 1 of 13 in additional filter chain; firing Filter: 'ChannelProcessingFilter' DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/admin_side/**' DEBUG [http-apr-8080-exec-55] (AntPathRequestMatcher.java:116) - Checking match of request : '/j_spring_security_check'; against '/utility/login.jsf' DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:139) - HttpSession returned null object for SPRING_SECURITY_CONTEXT DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:85) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1103da5. A new one will be created. DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 3 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter' DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 4 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter' DEBUG [http-apr-8080-exec-55] (FilterChainProxy.java:337) - /j_spring_security_check at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:189) - Request is to process authentication DEBUG [http-apr-8080-exec-55] (ProviderManager.java:152) - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:637) - Executing prepared SQL query DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:572) - Executing prepared SQL statement [select email_id, password, enabled from user_table where lower(email_id)=lower(?)] DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:110) - Fetching JDBC Connection from DataSource DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:327) - Returning JDBC Connection to DataSource DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:637) - Executing prepared SQL query DEBUG [http-apr-8080-exec-55] (JdbcTemplate.java:572) - Executing prepared SQL statement [select ut.email_id, ur.authority from user_table ut, user_roles ur where ut.user_id=ur.user_id and lower(ut.email_id)=lower(?)] DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:110) - Fetching JDBC Connection from DataSource DEBUG [http-apr-8080-exec-55] (DataSourceUtils.java:327) - Returning JDBC Connection to DataSource DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'authSuccessHandler' DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'org.springframework.security.core.session.SessionRegistryImpl#0' DEBUG [http-apr-8080-exec-55] (AbstractFallbackTransactionAttributeSource.java:106) - Adding transactional method 'rowCount' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '' DEBUG [http-apr-8080-exec-55] (DelegatingMethodSecurityMetadataSource.java:65) - Caching method [CacheKey[admin.dao.StateDAO; public abstract java.lang.Long admin.dao.service.StateService.rowCount()]] with attributes [ROLE_ADMIN] DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'transactionManager' DEBUG [http-apr-8080-exec-55] (AbstractPlatformTransactionManager.java:366) - Creating new transaction with name [admin.dao.StateDAO.rowCount]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '' DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:369) - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11] for JPA transaction DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:408) - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@84ff11] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@d9dbb8] does not support JDBC Connection retrieval DEBUG [http-apr-8080-exec-55] (AbstractSecurityInterceptor.java:194) - Secure object: ReflectiveMethodInvocation: public abstract java.lang.Long admin.dao.service.StateService.rowCount(); target is of class [admin.dao.StateDAO]; Attributes: [ROLE_ADMIN] DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'authSuccessHandler' DEBUG [http-apr-8080-exec-55] (AbstractBeanFactory.java:246) - Returning cached instance of singleton bean 'org.springframework.security.core.session.SessionRegistryImpl#0' DEBUG [http-apr-8080-exec-55] (AbstractPlatformTransactionManager.java:844) - Initiating transaction rollback DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:534) - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11] DEBUG [http-apr-8080-exec-55] (JpaTransactionManager.java:594) - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@84ff11] after transaction DEBUG [http-apr-8080-exec-55] (EntityManagerFactoryUtils.java:338) - Closing JPA EntityManager DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:346) - Authentication request failed: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:347) - Updated SecurityContextHolder to contain null Authentication DEBUG [http-apr-8080-exec-55] (AbstractAuthenticationProcessingFilter.java:348) - Delegating to authentication failure handler loginsuccesshandler.AuthenticationFailureHandler@14883a3 DEBUG [http-apr-8080-exec-55] (DefaultRedirectStrategy.java:36) - Redirecting to '/SocialNetworking/utility/Login.jsf' DEBUG [http-apr-8080-exec-55] (HttpSessionSecurityContextRepository.java:269) - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession. DEBUG [http-apr-8080-exec-55] (SecurityContextPersistenceFilter.java:97) - SecurityContextHolder now cleared, as request processing completed DEBUG [http-apr-8080-exec-49] (AntPathRequestMatcher.java:116) - Checking match of request : '/utility/login.jsf'; against '/utility/login.jsf*' DEBUG [http-apr-8080-exec-49] (AntPathRequestMatcher.java:116) - Checking match of request : '/utility/login.jsf'; against '/utility/login.jsf*' DEBUG [http-apr-8080-exec-49] (FilterChainProxy.java:180) - /utility/Login.jsf has an empty filter list 

The last thing:

When I give up this bean and unregister from the application-context.xml file, the login is made successfully but the following information can be seen on the server console.

DEBUG [http-apr-8080-exec-165] (HttpSessionSecurityContextRepository.java:139) - HttpSession returned null object for SPRING_SECURITY_CONTEXT DEBUG [http-apr-8080-exec-165] (HttpSessionSecurityContextRepository.java:85) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@b910c1. A new one will be created. 
like image 427
Tiny Avatar asked Mar 19 '13 13:03

Tiny


2 Answers

The security's authorization check part gets the authenticated object from SecurityContext, which will be set when a request gets through the spring security filter. My assumption here is that soon after the login this is not being set. You probably can use a hack as given below to set the value.

try {     SecurityContext ctx = SecurityContextHolder.createEmptyContext();     SecurityContextHolder.setContext(ctx);     ctx.setAuthentication(event.getAuthentication());      //Do what ever you want to do  } finally {     SecurityContextHolder.clearContext(); } 

Update:

Also you can have a look at the InteractiveAuthenticationSuccessEvent which will be called once the SecurityContext is set.

like image 150
Arun P Johny Avatar answered Sep 17 '22 06:09

Arun P Johny


This could also happens if you put a @PreAuthorize or @PostAuthorize in a Bean in creation. I would recommend to move such annotations to methods of interest.

like image 39
EliuX Avatar answered Sep 17 '22 06:09

EliuX