Why do I still get an AuthenticationCredentialsNotFoundException? - spring

I thought I had the solution to this but unfortunately the problem does still occur and I have no idea what else I could do.
What I do is login as a user. My AuthenticationProvider does not check anything which means that any user can login at the moment.
The thing is, that sometimes the login does work. I get a request through and load data from the server. Sometimes I have to wait a little while, 1 or 2 minutes, and all of a sudden I start receive the AuthenticationCredentialsNotFoundException. From time to time I can not login at all at the first time. I have to send another request in order to be able to successfully login.
I can't see a pattern or anything that would lead me to the cause of this. So, here I start with my LoginService and my implementation of the AuthenticationProvider:
public class LoginService {
private AuthenticationProvider adminAuthenticationProvider;
public LoginService(DSLContext ctx, AuthenticationProvider adminAuthenticationProvider) {
this.adminAuthenticationProvider = adminAuthenticationProvider;
}
#Transactional
public void login(String userId, String password) {
CustomUserDetails user = new CustomUserDetails(userId, password, true, true, true, true, new ArrayList<GrantedAuthority>());
Authentication auth = new UsernamePasswordAuthenticationToken(user, password,
new ArrayList<GrantedAuthority>());
try {
auth = this.adminAuthenticationProvider.authenticate(auth);
} catch(BadCredentialsException e) {
throw e;
}
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
public class AdminAuthenticationProvider implements AuthenticationProvider {
private RestaurantAdminRepository restaurantAdminRepository;
public AdminAuthenticationProvider(DSLContext ctx) {
this.restaurantAdminRepository = new RestaurantAdminRepository(ctx);
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
CustomUserDetails user = (CustomUserDetails) authentication.getPrincipal();
List<String> roles = new ArrayList<>();
roles.add("ROLE_ADMIN");
Authentication customAuthentication = new CustomUserAuthentication(roles, authentication);
customAuthentication.setAuthenticated(true);
return customAuthentication;
}
#Override
public boolean supports(Class<? extends Object> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
Nothing special about that I guess. My calls are secured just by isAuthenticated()
#PreAuthorize("isAuthenticated()")
public List<StoreDTO> getAvailableStores() {
// ..
return result;
}
The next thing is the debug output including the output of my own code and org.springframework on TRACE debug level. You can see that the authorization is successful but that after some requests the exception gets thrown. Sorry for this large output. You can also look at it here.
[http-bio-8080-exec-2] DEBUG com.mz.server.web.servlet.LoginServletImpl - Login request by userId: sfalk
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.LoginService - Login for sfalk
[http-bio-8080-exec-2] INFO com.mz.server.web.auth.AdminAuthenticationProvider - authenticate(), Username: sfalk
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - findByUsername(): sfalk
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/mz_db]
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - User found.
[http-bio-8080-exec-2] INFO com.mz.server.web.repository.StoreAdminRepository - Checking password for sfalk
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/mz_db]
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - Password valid.
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - getPrincipal()
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - Setting user com.mz.server.web.auth.CustomUserDetails#684666d: Username: sfalk; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities to 'authenticated'.
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.LoginService - User successfully authenticated [userId=sfalk]
[http-bio-8080-exec-2] DEBUG com.mz.server.web.servlet.StoreServletImpl - Requested available stores.
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.StoreService.getAvailableStores(); target is of class [com.mz.server.web.service.StoreService]; Attributes: [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - isAuthenticate(): true
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Previously Authenticated: com.mz.server.web.auth.CustomUserAuthentication#7d055aa6
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#36d4a51, returned: 1
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Authorization successful
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - RunAsManager did not change Authentication object
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.StoreService - Trying to get available stores for ..
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - getPrincipal()
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.StoreService - sfalk
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - Fetching stores for store_admin_id 1
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/mz_db]
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - Stores found..
[http-bio-8080-exec-2] DEBUG com.mz.server.web.servlet.StoreServletImpl - Requesting items for store ..
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.Map com.mz.server.web.service.StoreService.getItems(java.lang.Long); target is of class [com.mz.server.web.service.StoreService]; Attributes: [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - isAuthenticate(): true
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Previously Authenticated: com.mz.server.web.auth.CustomUserAuthentication#7d055aa6
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#36d4a51, returned: 1
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Authorization successful
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - RunAsManager did not change Authentication object
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.StoreService - Getting items.
[http-bio-8080-exec-2] DEBUG com.mz.server.web.repository.StoreAdminRepository - getItems
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/mz_db]
[http-bio-8080-exec-2] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
[http-bio-8080-exec-2] DEBUG com.mz.server.web.servlet.StoreServletImpl - Requested offers from 2016-01-11T00:00:00.278+01:00 to 2016-01-17T00:00:00.278+01:00.
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.StoreService.getUpcomingOffersForCalendarWeek(java.lang.Long,java.lang.String,java.lang.String); target is of class [com.mz.server.web.service.StoreService]; Attributes: [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - isAuthenticate(): true
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Previously Authenticated: com.mz.server.web.auth.CustomUserAuthentication#7d055aa6
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#36d4a51, returned: 1
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Authorization successful
[http-bio-8080-exec-2] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - RunAsManager did not change Authentication object
[http-bio-8080-exec-2] DEBUG com.mz.server.web.service.StoreService - Getting offers ..
[http-bio-8080-exec-2] DEBUG com.mz.server.web.auth.CustomUserAuthentication - getPrincipal()
[http-bio-8080-exec-1] DEBUG com.mz.server.web.servlet.StoreServletImpl - Requested offers from 2016-01-11T00:00:00.167+01:00 to 2016-01-17T00:00:00.167+01:00.
[http-bio-8080-exec-1] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.StoreService.getUpcomingOffersForCalendarWeek(java.lang.Long,java.lang.String,java.lang.String); target is of class [com.mz.server.web.service.StoreService]; Attributes: [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[http-bio-8080-exec-1] TRACE org.springframework.web.context.support.XmlWebApplicationContext - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent[source=ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.StoreService.getUpcomingOffersForCalendarWeek(java.lang.Long,java.lang.String,java.lang.String); target is of class [com.mz.server.web.service.StoreService]]
[http-bio-8080-exec-1] DEBUG com.mz.server.web.auth.CustomHttpSessionListener - AuthenticationCredentialsNotFoundEvent
Jän 12, 2016 11:27:02 PM org.apache.catalina.core.ApplicationContext log
SEVERE: Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.util.List com.mz.shared.web.service.store.StoreServlet.getUpcomingOffersForCalendarWeek(java.lang.Long,java.lang.String,java.lang.String)' threw an unexpected exception: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at com.google.gwt.user.server.rpc.RPC.encodeResponseForFailure(RPC.java:416)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:605)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:333)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:303)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:373)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:378)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:222)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.mz.server.web.service.StoreService$$EnhancerBySpringCGLIB$$b5728734.getUpcomingOffersForCalendarWeek(<generated>)
at com.mz.server.web.servlet.StoreServletImpl.getUpcomingOffersForCalendarWeek(StoreServletImpl.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:587)
... 25 more
The last thing are my application context configuration files. This is my configuration applicationContext-spring-acl.xml
<?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:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd">
<!-- Imports -->
<import resource="applicationContext-jooq.xml"/>
<!-- See 15.3.2 Built-In Expression #http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html#el-permission-evaluator -->
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<!-- To use hasPermission() in expressions, configure a PermissionEvaluator -->
<property name="permissionEvaluator" ref="permissionEvaluator" />
<property name="roleHierarchy" ref="roleHierarchy" />
</bean>
<bean class="com.mahlzeit.server.web.auth.permission.CustomAclPermissionEvaluator" id="permissionEvaluator">
<constructor-arg ref="aclService" />
</bean>
<!-- Declare an acl service -->
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
<constructor-arg ref="aclCache" />
</bean>
<!-- Declare a lookup strategy -->
<bean id="lookupStrategy"
class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="auditLogger" />
</bean>
<!-- Declare an acl cache -->
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true"/>
</property>
<property name="cacheName" value="aclCache" />
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ACL_ADMIN" />
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<!-- Declare an acl authorization strategy -->
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
</list>
</constructor-arg>
</bean>
<!-- Declare an audit logger -->
<bean id="auditLogger"
class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
<!-- http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.html -->
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
ROLE_USER > ROLE_VISITOR
</value>
</property>
</bean>
<sec:global-method-security authentication-manager-ref="authenticationManager" pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
</beans>
And this is applicationContext-spring-security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd"
>
<!-- Imports -->
<import resource="applicationContext-spring-acl.xml"/>
<sec:http pattern="/**" auto-config="true" use-expressions="true"/>
<bean id="httpSessionSecurityContextRepository" class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='false' />
</bean>
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<constructor-arg ref="httpSessionSecurityContextRepository" />
</bean>
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<constructor-arg>
<list>
<sec:filter-chain pattern="/**" filters="securityContextPersistenceFilter" />
</list>
</constructor-arg>
</bean>
<bean id="authenticationListener" class="com.mahlzeit.server.web.auth.CustomAuthenticationListener"/>
<bean id="adminAuthenticationProvider" class="com.mahlzeit.server.web.auth.AdminAuthenticationProvider">
<constructor-arg ref="dslContext" />
</bean>
<bean id="userDetailsService" class="com.mahlzeit.server.web.service.CustomUserDetailsService"/>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="adminAuthenticationProvider"/>
</sec:authentication-manager>
</beans>
Thank you for any help that sheds some light on this.

It seems to me that the SecurityContextPersistenceFilter doesn't execute around your requests. I can see it is defined in your applicationContext-spring-security.xml but, since you didn't post your web.xml, I can only assume you don't have the corresponding filter entry in your web.xml with DelegatingFilterProxy as a filter class. You can define the filter in the web.xml like this:
<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Note that the filter-name references a bean from your spring context with the name filterChainProxy.
From the DelegatingFilterProxy javadoc:
Proxy for a standard Servlet 2.3 Filter, delegating to a
Spring-managed bean that implements the Filter interface. Supports a
"targetBeanName" filter init-param in web.xml, specifying the name of
the target bean in the Spring application context.
web.xml will usually contain a DelegatingFilterProxy definition, with
the specified filter-name corresponding to a bean name in Spring's
root application context. All calls to the filter proxy will then be
delegated to that bean in the Spring context, which is required to
implement the standard Servlet 2.3 Filter interface.
I hope this helps.

I wonder if the issue is related to your empty GrantedAuthority List in the login method.
In my implementation LocalAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider and in the GrantedAuthority list I add user role that comes from my domain.
final List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
for(com.tony.trip.domain.Role role:user.getRoles()){
auths.add(new SimpleGrantedAuthority(role.getRolename()));
}
Hope this hepls

Related

HTTP 404 Not Found after successful Spring Security authentication

I am trying to implement Spring Security Authentication and Authorization using Database. Spring security authentication is working good. But I am getting HTTP 404 NOT FOUND page with URL /Sample_App/j_spring_security_check, instead of default-target-url it should goto.
Here is my spring-security file
<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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<beans:import resource="im-jndi-datasource.xml" />
<http pattern="/inventory/auth/login" security="none"/>
<http pattern="/inventory/auth/deny" security="none"/>
<http pattern="/images/**" security="none"/>
<http pattern="/css/**" security="none"/>
<http pattern="/js/**" security="none"/>
<http auto-config="true">
<intercept-url pattern="/inventory/**" access="ROLE_ADMIN" />
<form-login
login-page="/inventory/auth/login"
default-target-url="/inventory/landing/loadDashBoardPage"
authentication-failure-url="/inventory/auth/login?error"
username-parameter="username"
password-parameter="password" />
<access-denied-handler error-page="/inventory/auth/deny"/>
<logout logout-success-url="/logout" />
<session-management
session-authentication-error-url="/inventory/auth/login"
invalid-session-url="/inventory/auth/login">
<concurrency-control max-sessions="1" error-if-maximum-exce eded="true"/>
</session-management>
</http>
<authentication-manager>
<authentication-provider>
<!-- <security:user-service> <security:user name="dineshonjava" password="sweety"
authorities="ROLE_USER" /> </security:user-service> -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username, password, status as enabled from bbp_user where username=?"
authorities-by-username-query="select us.username, ur.rolename as authority from bbp_user us, bbp_users_and_roles bur, bbp_role ur
where us.user_id = bur.user_id and bur.role_id =ur.role_id and us.username =? " />
</authentication-provider>
</authentication-manager>
</beans:beans>
Here is the part of spring-servlet.xml file
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/eimsgo-security.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/inventory/*</url-pattern>
</servlet-mapping>
<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>
</filter-mapping>
I use tiles2.TilesViewResolver and ContentNegotiatingViewResolver
Here is my tiles-context xml
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/views.xml</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
My welcome file index.jsp hits the LoginController.java with URL (/inventory/auth/login)
LoginController.java
#Controller
#RequestMapping("/auth")
public class LoginController {
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout,
#RequestParam(value = "invalid", required = false) String invalid) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
if(invalid != null) {
model.addObject("invalid", "Invalid session!!");
}
model.setViewName("home_creation");
return model;
}
}
After successful login, it should goto /inventory/landing/loadDashBoardPage as per default-target-url defined in the security xml file.
Where /landing is one of my Spring Controller, and loadDashBoarPage is method level mapping. The loadDashBoardPage interacts with the database and set the Map object and retuns the View string "DashBoardPage". TilesViewResolver now should render this page.
InventoryController.java
#Controller
#RequestMapping("/landing")
public class InventoryController {
#RequestMapping(value = { "/loadDashBoardPage" }, method = { GET, POST })
public String loadDashBoardPage(Map<String, Object> model,
HttpServletRequest request, HttpSession session) {
List lobList = new ArrayList();
InventoryService inventoryService = (InventoryService) InventoryApplicationContext
.getBean("inventoryService");
lobList = inventoryService.loadLob();
model.put("lob", lobList);
model.put("leftTreee", inventoryService.loadDataforNavigator());
return "DashBoardPage";
}
Please find the log below
2014-12-05 22:55:27,419 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
2014-12-05 22:55:27,420 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [jdbc:oracle:thin:#10.237.31.14:1521:xe, UserName=ADMIN, Oracle JDBC driver]
2014-12-05 22:55:27,422 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [jdbc:oracle:thin:#10.237.31.14:1521:xe, UserName=ADMIN, Oracle JDBC driver] after transaction
2014-12-05 22:55:27,422 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
2014-12-05 22:55:27,425 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver - Requested media types are [image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, /] (based on Accept header)
2014-12-05 22:55:27,425 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.atom'
2014-12-05 22:55:27,426 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.json'
2014-12-05 22:55:27,429 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.html'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver - Returning [org.springframework.web.servlet.view.tiles2.TilesView: name 'DashBoardPage'; URL [DashBoardPage]] based on requested media type '/'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.tiles2.TilesView: name 'DashBoardPage'; URL [DashBoardPage]] in DispatcherServlet with name 'spring'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.tiles2.TilesView - Added model object 'lob' of type [java.util.ArrayList] to request in view with name 'DashBoardPage'
2014-12-05 22:55:27,431 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.tiles2.TilesView - Added model object 'leftTreee' of type [java.util.HashMap] to request in view with name 'DashBoardPage'
2014-12-05 22:55:27,431 [http-bio-8090-exec-8] DEBUG org.apache.tiles.impl.BasicTilesContainer - Render request recieved for definition 'DashBoardPage'
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Spring Security authenticates successfully here and the view resolver is not rendering the requested page.
Instead I am getting http://abc.xyz.com/Sample_App/j_spring_security_check
It should allow the user to goto the URL as defined in the default-target-url
/Sample_App/inventory/landing/loadDashBoardPage
Please advise!!
I resolved the issue myself. Spring Security tightly intercepts all the URLs including CSS, Images, JavaScripts, JSP files and everything.
The problem here is, I am using TilesViewResolver
<definition name="LogoutPage" template="/jsp/logout.jsp">
<put-attribute name="header" value="/jsp/tiles/logoutHeader.jsp" />
<put-attribute name="footer" value="/jsp/tiles/footer.jsp" />
<put-attribute name="content" value="/jsp/logout_creation.jsp" />
</definition>
I forget to configure the spring security that intercept all the sub-URLs that these tiles pages use with authentication based on roles.

Spring taking long time to return cached instance of singleton bean - transactionManager

All API call are taking long time to respond because, spring is taking long time to return cached instance of singleton bean - transactionManager. Please see log, this behaviour is consistent for each request.
2
014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/emsp/locations]
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Looking up handler method for path /locations
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Did not find handler method for [/locations]
2014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - Last-Modified value for [/emsp/locations] is: -1
2014-09-24 08:09:02,240 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'integrationEvaluationContext'
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Creating new transaction with name [com.***.emsp.service.impl.EndpointLookupServiceImpl.getEndpointLocations]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtaining JDBC connection
2014-09-24 08:09:07,407 DEBUG resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool#7cfea9ab [managed: 1, unused: 0, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection#6a4d7764)
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtained JDBC connection
2014-09-24 08:09:07,407 DEBUG spi.AbstractTransactionImpl - begin
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - initial autocommit status: true
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - disabling autocommit
2014-09-24 08:09:07,408 DEBUG hibernate4.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection#3c0b2e6e]
2014-09-24 08:09:07,408 INFO impl.EndpointLookupServiceImpl - EndpointLookupServiceImpl::getEndpointLocations - called (Custom log - after this is almost instantaneous)
If you see these two lines specifically in the above line - there is a 5sec delay - this keeps increasing after a while but comes down once tomcat is restarted.
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
My spring config
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.****.emsp" />
<!-- Transaction Manager Declaration -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/emsp" />
<property name="user" value="***" />
<property name="password" value="***" />
<!-- C3P0 properties -->
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="300" />
<property name="idleConnectionTestPeriod" value="3000" />
<!--property name="testConnectionOnCheckout" value="true" /> <property
name="preferredTestQuery" value="select 1;" / -->
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.****.emsp.entity" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
</beans>
And i'm using #Transactional annotation for my service APIs involving DB transaction.
Please suggest how to go about debugging this. Also let me know if any another info is required.
Request Handling code:
#Service
public class EndpointLookupServiceImpl implements EndpointLookupService {
private static final Logger logger = Logger
.getLogger(EndpointLookupServiceImpl.class);
#Autowired
EndpointLocationDaoImpl endpointLoctionDao;
#Autowired
SsidDaoImpl ssidDao;
#Override
#Transactional
public EndpointLocationsResp getEndpointLocations(
String xJwtAssertionHeader, Map<String, List<String>> reqParams) {
logger.info("EndpointLookupServiceImpl::getEndpointLocations - called with xJwtAssertionHeader:"
+ xJwtAssertionHeader + " reqParams:" + reqParams);
.....
}
}
Using spring integration as controller for invoking the service:
<int-http:inbound-gateway id="endpointLocById"
request-channel="endpointLocByIdIn"
supported-methods="GET"
path="/locations/{locationId}"
mapped-request-headers="*"
payload-expression="#pathVariables.locationId" >
</int-http:inbound-gateway>
<int:channel id="endpointLocByIdIn"/>
<int:service-activator input-channel="endpointLocByIdIn" expression="#endpointLookupService.getEndpointLocationByLocationId(headers['x-jwt-assertion'], payload)" output-channel="out" />
Take thread dumps just before and after you see the blocking to see what your main thread is doing, Spring loads beans in a single thread, so you should be able to see where it is stuck and debug that even more.

Spring #Preauthorize not working properly when provided with hierachical roles?

I have a Spring-based application which defines a hierarchical set of roles for its users, like the following :
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ROOT > ROLE_SUDOER
ROLE_SUDOER > ROLE_USER
ROLE_USER > ROLE_DUMB
</value>
</property>
</bean>
so in my AccessDecisionManager, I am using 4 voters this way :
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="methodSecurityExpressionHandler"/>
</sec:global-method-security>
even though, I have configured this set of hierarchical roles, I am having an ACCESS DENIED exception when a user having the highest role, ROLE_ROOT, is trying to access the /myUrl url in the following controller:
#Controller
#PreAuthorize("hasRole('ROLE_SUDOER')")
#RequestMapping(value = "/myUrl")
public class BuggyController extends AbstractController {
#RequestMapping(value = "", method = RequestMethod.GET)
#ResponseBody
public List<SensitiveItem> getSensitiveItems(final Principal principal)
{
// removed for brievety
}
}
Here is the stacktrace (a part of it actually):
10:55:16.012 [ajp-bio-8029-exec-4] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - [ ] - Authorization successful
10:55:16.012 [ajp-bio-8029-exec-4] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - [ ] - RunAsManager did not change Authentication object
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - [ 192.168.xx.yyy] - Secure object: ReflectiveMethodInvocation: public java.util.List com.xxxx.yyyy.BuggyController.getSensitiveItems(java.security.Principal); target is of class [com.xxxx.yyyy.BuggyController.getSensitiveItems]; Attributes: [[authorize: 'hasRole('ROLE_SUDOER')', filter: 'null', filterTarget: 'null']]
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - [ 192.168.xx.yyy] - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#8bc6b2e4: Principal: org.springframework.security.core.userdetails.User#7a85da9c: Username: sudoer; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ROOT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#2cd90: RemoteIpAddress: 192.168.22.112; SessionId: 8CE7068F50AD373ED2194B76A188BCEF; Granted Authorities: ROLE_ROOT
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.h.RoleHierarchyImpl - [ 192.168.xx.yyy] - getReachableGrantedAuthorities() - From the roles [ROLE_ROOT] one can reach [ROLE_ROOT, ROLE_SUDOER, ROLE_USER, ROLE_DUMB] in zero or more steps.
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#65685e97, returned: -1
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.vote.RoleVoter#29800e27, returned: 0
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.access.vote.AffirmativeBased - [ 192.168.xx.yyy] - Voter: org.springframework.security.access.vote.AuthenticatedVoter#162137ba, returned: 0
10:55:16.015 [ajp-bio-8029-exec-4] WARN c.d.d.utils.ExceptionResolver - [ 192.168.xx.yyy] - catched an exception: Access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
Logs clearly state that the ROLE_ROOT can escalate down to the ROLE_SUDOER:
10:55:16.013 [ajp-bio-8029-exec-4] DEBUG o.s.s.a.h.RoleHierarchyImpl - [ 192.168.xx.yyy] - getReachableGrantedAuthorities() - From the roles [ROLE_ROOT] one can reach [ROLE_ROOT, ROLE_SUDOER, ROLE_USER, ROLE_DUMB] in zero or more steps.
So my question is, if the ROLE_SUDOER is reachable from a higher priority role (here ROLE_ROOT), why is my call failing ?
In order to get it running, I had to explicitly add the highest role ROLE_ROOT as part of the method security control expression :
#Controller
#PreAuthorize("hasAnyRole('ROLE_ROOT', 'ROLE_SUDOER')")
#RequestMapping(value = "/myUrl")
public class BuggyController extends AbstractController {
#RequestMapping(value = "", method = RequestMethod.GET)
#ResponseBody
public List<SensitiveItem> getSensitiveItems(final Principal principal)
{
// removed for brievety
}
}
Which is really stupid since, it can become quite complicated if your hierarchical role set is huge : and that's exactly what hierarchical roles are for. It allows efficient role security control so that higher-priority roles can include lower priority ones.
Can someone help me on this issue ? Thanks in advance.

JTA EntityManager cannot use getTransaction() [Spring + Hibernate + EntityManager]

I am using Spring + JPA + Hibernate + EntityManager to talk to the database. I am getting 'A JTA EntityManager cannot use getTransaction()' error. Please provide your insights and help me resolve the issue.
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
... xmlns definitions...
xsi:schemaLocation="...">
<context:component-scan base-package="com.mycompany.myproject" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="myDAO" class="com.mycompany.myproject.dao.myDAO" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence ... xmlns definitions xsi:schemaLocation="..." version="1.0">
<persistence-unit name="TEST_DS">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/TEST_DS</jta-data-source>
<class>com.twinspires.exchange.model.Test</class>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" /> <!-- create-drop update -->
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
</properties>
</persistence-unit>
</persistence>
Exception Stack Trace (Excerpt)
15:47:43,340 INFO [STDOUT] DEBUG: org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'getName' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
15:47:43,343 INFO [STDOUT] DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
15:47:43,356 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.twinspires.exchange.dao.PicDAO.getName]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
15:47:44,114 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#c629e5] for JPA transaction
15:47:44,124 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Could not rollback EntityManager after failed transaction begin
15:47:44,125 INFO [STDOUT] java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
15:47:44,125 INFO [STDOUT] at org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:818)
15:47:44,126 INFO [STDOUT] at org.springframework.orm.jpa.JpaTransactionManager.closeEntityManagerAfterFailedBegin(JpaTransactionManager.java:412)
15:47:44,127 INFO [STDOUT] at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:381)
15:47:44,128 INFO [STDOUT] at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
15:47:44,129 INFO [STDOUT] at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
15:47:44,129 INFO [STDOUT] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
15:47:44,130 INFO [STDOUT] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
15:47:44,131 INFO [STDOUT] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
15:47:44,131 INFO [STDOUT] at $Proxy175.getName(Unknown Source)
Folowing is my dao class:-
public class MyDao implements IMyDao {
#PersistenceContext(unitName = "TEST_DS")
private EntityManager entityManager;
#Transactional
public String getName() {
final Query query = entityManager.createQuery("from TestTable");
final Object obj = query.getResultList().get(0);
return obj == null ? "Empty" : (String) obj;
}
}
Your help highly appreciated.
Remove the jta-datasource from persitence.xml, configure datasource as a bean j2ee:jdni-lookup and inject it into the LocalContainerEntityManagerFactoryBean
Remove this from persistence.xml
<jta-data-source>java:/TEST_DS</jta-data-source>
Configure the transaction-type to resource local
<persistence-unit name="TEST_DS" transaction-type="RESOURCE_LOCAL">
Change to your beans.xml
<j2ee:jndi-lookup id="dataSource" jndi-name="java:/TEST_DS"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
First of all I want to tell you I had the same problem. Researching about that I found this page with your post and the answer by "gkamal".
I think that the answer comes to say that if you are trying to use "global" JTA transaction in your application and it doesn't work then don't use it, use in its place a "local" JDBC transaction.
But if you need to use global JTA transaction then you must use it.
Well I am going to give you the solution I found in my resarch.
There are properties that are application server dependent. I use glassfish and this solution works fine, but I think you are using JBOSS (due to the value you are using in the jta-data-source in your persistence.xml) I will write the values for a JBOSS AS, but in JBOSS AS I don't prove it, I just prove it only in glassfish.
In your persistence.xml you have to put another property:
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
The value of this property is AP server dependent.
In your beans.xml file you have to take a look in the entity manager factory and transaction manager. Morover you have indicate in your web.xml which persistence units you are referencing in your application.
beans.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="TEST_DS"/>
</bean>
In your transaction manager you are using entity manager factory but you don't have to do that. You have to indicate the transaction manager and user transaction used by your app server, this way
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:appserver/TransactionManager"/>
<property name="userTransactionName" value="java:comp/UserTransaction"/>
</bean>
The values of those properties are app server dependent (I use glassfish). I think you have to use the values for jboss ap:
<property name="transactionManagerName" value="java:/TransactionManager"/>
<property name="userTransactionName" value="UserTransaction"/>
But I didn't prove it.
Last, in glassfish I have to put in beans.xml (and I don't know why) the following bean (I think in jboss ap it isn't necessary but you might prove it)
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
<property name="persistenceUnits">
<map>
<entry key="TEST_DS" value="persistence/TEST_DS"/>
</map>
</property>
</bean>
In your web.xml you need reference the persistence units your application will use.
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/TEST_DS</persistence-unit-ref-name>
<persistence-unit-name>TEST_DS</persistence-unit-name>
</persistence-unit-ref>
I hope that the solution is of help for you. It works for me.

PreAuthorize doesn't work

I'm writing a socket server (no web-application !) application and want to use method-based security to handle my ACL needs. i followed a small tutorial i found spring security by example
so far i configured:
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean id="permissionEvaluator" class="myPermissionEvaluator" />
</property>
</bean>
<security:authentication-manager id="authenticationmanager">
<security:authentication-provider ref="authenticationprovider" />
</security:authentication-manager>
<bean id="authenticationprovider" class="myAuthenticationProvider" />
With a service bean:
#Named
public class ChannelService {
#PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')")
public void writeMessage(Channel channel, String message) { ... }
}
Everything compiles and the application starts and works fine, but without access control. My debug log shows that my Evaluator is never called.
When i tried something similar with a #Secured annotation the annotation was evaluated and access was denied. but simple role based security isn't enough for my requirements.
EDIT
did some more tests: when i configure only secured-annotations="enabled" the role based security works. when configure pre-post-annotations="enabled" in ADDITION neither secured nor preauthorize works. when i configure only pre-post-annotations it still doesn't work.
EDIT2
some more tests:
with only secured_annotations="enabled" the call to my channelservice goes through the Cglib2AopProxy
as soon as i activate pre-post-annotations the call lands directly in the channelservice. no interceptor, no proxy, nothing.
I'm getting kind of desperate...
EDIT3
I debug-logged my testruns here is the part for spring-security
with only secured-annotations="enabled"
2012-04-12 13:36:46,171 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE
2012-04-12 13:36:46,174 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE
2012-04-12 13:36:49,042 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.UserService; public void mystuff.UserService.serverBan(java.lang.String,mystuff.models.User,org.joda.time.DateTime)]] with attributes [user]
2012-04-12 13:36:49,138 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes
2012-04-12 13:36:49,221 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.ChannelService; public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String)]] with attributes [blubb]
2012-04-12 13:36:51,159 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:36:56,166 DEBUG [Timer-1] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:36:56,183 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String); target is of class [mystuff.ChannelService]; Attributes: [blubb]
2012-04-12 13:36:56,184 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#312e8aef: Principal: mystuff.UserId#ced1752b; Credentials: [PROTECTED]; Authenticated: true; Details: null; Not granted any authorities
Exception in thread "Timer-1" org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:88)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at mystuff.ChannelService$$EnhancerByCGLIB$$3ad5e57f.writeMessage(<generated>)
at mystuff.run(DataGenerator.java:109)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.RoleVoter#1cfe174, returned: 0
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.AuthenticatedVoter#da89a7, returned: 0
with pre-post-annotations="enabled"
2012-04-12 13:39:54,926 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE
2012-04-12 13:39:54,929 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE
2012-04-12 13:39:54,989 INFO [main] o.s.s.c.m.GlobalMethodSecurityBeanDefinitionParser - Using bean 'expressionHandler' as method ExpressionHandler implementation
2012-04-12 13:39:59,812 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:39:59,850 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes
As far as i understand this log output spring doesn't realize my beans need to be proxied, so they aren't and so i don't get security.
EDIT4
I debug-logged the complete sprint startup... (thats one big log) and there i find:
2012-04-12 14:40:41,385 INFO [main] o.s.c.s.ClassPathXmlApplicationContext - Bean 'channelService' of type [class mystuff.ChannelService] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
is there a way to figure out why? because as far as i understand it. because of #preauthorize the bean should be eligible. with only secured-annotations="enabled" i get a post processing log.
This configuration worked just as expected for me:
<bean id="securityExpressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" />
<bean id="preInvocationAdvice"
class="org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice"
p:expressionHandler-ref="securityExpressionHandler" />
<util:list id="decisionVoters">
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter"
c:pre-ref="preInvocationAdvice" />
</util:list>
<bean id="accessDecisionManager"
class="org.springframework.security.access.vote.UnanimousBased"
c:decisionVoters-ref="decisionVoters" />
<sec:global-method-security
authentication-manager-ref="authenticationManager"
access-decision-manager-ref="accessDecisionManager"
pre-post-annotations="enabled" />
I got the log message:
WARN org.springframework.security.access.expression.DenyAllPermissionEvaluator -
Denying user jack permission 'CHANNEL_WRITE' on object Channel[ name=null ]
And an exception:
org.springframework.security.access.AccessDeniedException: Access is denied
From a simple test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:META-INF/spring/application-context.xml")
public class SpringSecurityPrePostTest {
#Autowired
ChannelService channelService;
#Test
public void shouldSecureService() throws Exception {
Authentication authentication = new UsernamePasswordAuthenticationToken("jack", "sparrow");
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
channelService.writeMessage(new Channel(), "test");
}
}
One thing I did diffrent was to use interface on a service and JDK proxies instead of cglib:
public interface ChannelService {
void writeMessage(Channel channel, String message);
}
and:
#Component
public class ChannelServiceImpl implements ChannelService {
private static final Logger LOG = LoggerFactory.getLogger(ChannelServiceImpl.class);
#Override
#PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')")
public void writeMessage(Channel channel, String message) {
LOG.info("Writing message {} to: {}" , message, channel);
}
}
UPDATE1:
With this simplified config I get the same result:
<bean id="securityExpressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" />
<sec:global-method-security
authentication-manager-ref="authenticationManager"
pre-post-annotations="enabled">
<sec:expression-handler ref="securityExpressionHandler" />
</sec:global-method-security>
UPDATE2:
The debug message from Edit4 indicates that channelService may not have bean proxied at all as it got classified as not eligible for auto-proxying. This qiestion answers similar problem - try not to use #Autowired or any other mechanism based on BeanPostProcessors to set up the beans involved in security checks (i.e. myPermissionEvaluator).
UPDATE3:
You cannot use secured resources (i.e. services) within beans responsible for security checks! This creates a dependency loop and is a error in Your configuration. You must use lover level access (i.e. DAO) to check permissions, anything that is not secured! Implementing security checks using secured resources is not what You want to do.
If despite using not secured resources with #Autowired things don't work as expected, try using old-school XML confiuration style for all beans involved in security checks. Also remember that <context:component-scan /> is in fact a BeanDefinitionRegistryPostProcessor and introduces the scanned beans into the BeanFactory after all the ones declared in XML are already there.
it works,
make sure that you have <sec:global-method-security pre-post-annotations="enabled"/> in your spring servlet (ie where you may have your <mvc:annotation-driven/>)
"sec" is from xmlns:sec="http://www.springframework.org/schema/security"

Resources