PreAuthorize doesn't work - spring

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"

Related

Spring Security RunAsManagerImpl doesn't work

I have Bean_1 which call method from Bean_2. Bean_1 has following security configuration:
<protect-pointcut expression="execution(* com.proficiency.cg.core.blc.Bean_1.*.*(..))" access="ROLE_Administrators,RUN_AS_InternalRole"/>
Bean_2 - has following security configuration:
<protect-pointcut expression="execution(* com.proficiency.cg.core.blc.Bean_2.*.*(..))" access="ROLE_InternalRole"/>
In additional - I set up the RunAsManager:
<b:bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
<b:property name="key" value="prof_key"/>
</b:bean>
<b:bean id="runAsAuthenticationProvider"
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<b:property name="key" value="prof_key"/>
</b:bean>
<global-method-security secured-annotations="enabled" run-as-manager-ref="runAsManager" authentication-manager-ref="authenticationManager">
When I run my test program - I get security exception while access to Bean_2.
Conclusion: RunAsManager - doesn't work properly or atoll.
Ok. looks like RunAsManager has a bug. While debug - I found following in implementation of original RunAsManagerImpl:
public Authentication buildRunAs(Authentication authentication, Object object,
Collection<ConfigAttribute> attributes) {
List<GrantedAuthority> newAuthorities = new ArrayList<GrantedAuthority>();
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
GrantedAuthority extraAuthority = new SimpleGrantedAuthority(
getRolePrefix() + attribute.getAttribute());
newAuthorities.add(extraAuthority);
}
}
Everything looks good, but...
this method run over all attributes (ROLE_Administrators,RUN_AS_InternalRole) and check is the string starts with "RUN_AS_".
If yes - (this.supports(...)) - create new GrantedAuthority (getRolePrefix() + attribute.getAttribute()).
Everything is good, but getRolePrefix() returns "ROLE_". In fact - it creates new GrantedAuthority something like : ROLE_RUN_AS_InternalRole - which is not exists!
As a solution - I created my own RunAsManagerImpl which overwrite this method and just cut of "RUN_AS" from attribute before create new GrantedAuthority
I hope this will be fixed in next version.

Why do I still get an AuthenticationCredentialsNotFoundException?

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

Spring JPA transaction over multiple methods

I'm using Spring 3.2 with JPA and Hibernate 4 in a web application running in Tomcat 7. The application is divided into controller, service an DAO classes. The service classes have an annotated transaction configuration at class and method level. The DAOs are plain JPA with entity manager injected by #PersistenceContext annotation.
#Service("galleryService")
#Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class GalleryServiceImpl implements GalleryService {
#Override
public Picture getPicture(Long pictureId) {
return pictureDao.find(pictureId);
}
#Override
public List<PictureComment> getComments(Picture picture) {
List<PictureComment> comments = commentDao.findVisibleByPicture(picture);
Collections.sort(comments, new Comment.ByCreatedOnComparator(Comment.ByCreatedOnComparator.SORT_DESCENDING));
return comments;
}
...
}
#Controller
#RequestMapping("/gallery/displayPicture.html")
public class DisplayPictureController extends AbstractGalleryController {
#RequestMapping(method = RequestMethod.GET)
public String doGet(ModelMap model, #RequestParam(REQUEST_PARAM_PICTURE_ID) Long pictureId) {
Picture picture = galleryService.getPicture(pictureId);
if (picture != null) {
model.addAttribute("picture", picture);
// Add comments
model.addAttribute("comments", galleryService.getComments(picture));
} else {
LOGGER.warn(MessageFormat.format("Picture {0} not found.", pictureId));
return ViewConstants.CONTENT_NOT_FOUND;
}
return ViewConstants.GALLERY_DISPLAY_PICTURE;
}
...
}
I switched on debug logging for org.springframework.transaction and noticed, that "Creating new transaction", "Opened new EntityManager", "Getting...", "Closing..." and "Committing transaction" is done for every call of a method in my service class. Even if those methods where called by one single method in my controller class. Here is an example of my log output:
2014-12-03 10:53:00,448 org.springframework.transaction.support.AbstractPlatformTransactionManager getTransaction
DEBUG: Creating new transaction with name [de.domain.webapp.gallery.service.GalleryServiceImpl.getPicture]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2014-12-03 10:53:00,448 org.springframework.orm.jpa.JpaTransactionManager doBegin
DEBUG: Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#6133a72f] for JPA transaction
2014-12-03 10:53:00,468 org.springframework.orm.jpa.JpaTransactionManager doBegin
DEBUG: Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#5182c1b7]
2014-12-03 10:53:00,468 org.springframework.transaction.interceptor.TransactionAspectSupport prepareTransactionInfo
TRACE: Getting transaction for [de.domain.webapp.gallery.service.GalleryServiceImpl.getPicture]
2014-12-03 10:53:00,489 org.springframework.transaction.interceptor.TransactionAspectSupport commitTransactionAfterReturning
TRACE: Completing transaction for [de.domain.webapp.gallery.service.GalleryServiceImpl.getPicture]
2014-12-03 10:53:00,489 org.springframework.transaction.support.AbstractPlatformTransactionManager processCommit
DEBUG: Initiating transaction commit
2014-12-03 10:53:00,489 org.springframework.orm.jpa.JpaTransactionManager doCommit
DEBUG: Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#6133a72f]
2014-12-03 10:53:00,489 org.springframework.orm.jpa.JpaTransactionManager doCleanupAfterCompletion
DEBUG: Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#6133a72f] after transaction
2014-12-03 10:53:00,489 org.springframework.orm.jpa.EntityManagerFactoryUtils closeEntityManager
DEBUG: Closing JPA EntityManager
I know that I can use an OpenSessionInView to hold the hibernate session for a complete request but some people said, OSIV is an antipattern. Instead I'm using SpringOpenEntityManagerInViewFilter. But with no success. How can I achieve, Spring uses a single transaction for multiple service layer method calls of my controller? Or did I missunderstand anything?
Here a part of my Spring configuration:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="false" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/tikron" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="de.domain.webapp">
<context:include-filter type="regex" expression=".*Service"/>
</context:component-scan>
My persistence unit:
<persistence-unit name="tikron-data" transaction-type="RESOURCE_LOCAL">
<!-- Entities located in external project tikron-data -->
<jar-file>/WEB-INF/lib/tikron-data-2.0.1-SNAPSHOT.jar</jar-file>
<!-- Enable JPA 2 second level cache -->
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
<property name="hibernate.generate_statistics" value="false" />
</properties>
</persistence-unit>
Some more log output from application startup:
2014-12-03 10:46:48,428 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA container EntityManagerFactory for persistence unit 'tikron-data'
2014-12-03 10:46:48,428 org.hibernate.ejb.HibernatePersistence logDeprecation
WARN: HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
2014-12-03 10:46:48,448 org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [
name: tikron-data
...]
...
2014-12-03 10:46:51,101 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#6cccf90d: defining beans [propertyConfigurer,messageSource,entityManagerFactory,dataSource]; root of factory hierarchy
2014-12-03 10:46:51,111 org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 3374 ms
Thanks in advance.
You need to play your PROPAGATION_LEVEL and structure your service bean calls properly. If you're using #Transactional on your Service classes, what you described is normal, since the transaction demarcation happens on public methods level. So depending on the propagation level when entering the public method of the service bean, the transaction will either start, join an existing transaction, throw an exception or execute non-transactionally.
To have service methods execute in one transaction, its enough to have the propagation level set to support as you do in your GalleryService (providing that you don't override it on a method level), and call these methods from a single method of another service which is annotated #Transactional(propagation=Propagation.REQUIRED). Its important to have you're calls pass through a bean e.g. (galleryService.getPicture instead of local call getPicture), 'cause aspects that inject the transaction semantics work against a proxy that wraps the bean
#Service("exampleService")
#Transactional(propagation=Propagation.REQUIRED)
public class ExampleServiceImpl implements ExampleService {
#Autowired
private GalleryService galleryService;
#Override
public void singleTransaction() {
galleryService.getPicture
galleryService.getComments
}
...
}
a brief PROPAGATION_LEVEL glossary
MANDATORY
Support a current transaction, throw an exception if none exists.
NESTED
Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
NEVER
Execute non-transactionally, throw an exception if a transaction exists.
NOT_SUPPORTED
Execute non-transactionally, suspend the current transaction if one exists.
REQUIRED
Support a current transaction, create a new one if none exists.
REQUIRES_NEW
Create a new transaction, suspend the current transaction if one exists.
SUPPORTS
Support a current transaction, execute non-transactionally if none exists.
UPDATE with respect to the comment
But is combining service method calls into one service method the only way to handle those calls in one single transaction?
No, but in my opinion its your best option. Consider the article http://www.ibm.com/developerworks/java/library/j-ts2/index.html. What I'm describing is whats referred to in the article as API layer strategy. Its defined as
The API Layer transaction strategy is used when you have
coarse-grained methods that act as primary entry points to back-end
functionality. (Call them services if you would like.) In this
scenario, clients (be they Web-based, Web services based,
message-based, or even desktop) make a single call to the back end to
perform a particular request.
Now in the standard three-layer architecture you have the presentation, a business and a persistence layer. In simple words you can annotate your controllers, services or DAOs. Services are the ones holding the logical unit of work. If you annotate your controllers, they are part of your presentation layer, if your transactional semantics is there, and you decide to switch or add a non-http client (e.g. Swing client), you're bound to either migrate or duplicate your transaction logic. DAO layers should also not be the owners of transaction, 'the granularity of the DAO methods is much less than what is a business logical unit. I'm restraining from points like best-practice etc. but, if you're uncertain, choose your business (service) as your API transaction layer :)
You have numerous posts discussing this topic in all directions
why use #transactional with #service insted of with #controller
Where should "#Transactional" be place Service Layer or DAO
very good and fun reading, many opinions and very context-dependant

Spring Security : How to access a protected service from the init method of a context bean?

My setup :
In a Spring MVC 3.1 application, I have a Spring Security protected service :
#PreAuthorize("isAnonymous()") // ("hasRole('USER')") doesn't work either
public interface UserService extends UserDetailsService, PasswordEncoder
I'm trying to use this service from the init() method of a bean declared in my context :
<bean class="com.xxx.scripts.FillDbWithInitialValues" init-method="contextInit" />
The class :
public class FillDbWithInitialValues
{
#Autowired
UserService userService;
public void contextInit()
{
User test = userService.getUser(1);
}
}
Extract of my security.xml file :
<sec:global-method-security pre-post-annotations="enabled" />
<sec:http auto-config="true" use-expressions="true">
(...)
</sec:http>
<sec:authentication-manager alias="authManager">
<sec:authentication-provider user-service-ref="userService">
<sec:password-encoder ref="userService" />
</sec:authentication-provider>
</sec:authentication-manager>
The problem :
When I start the application, I get an exception :
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
Why is this happening?
How can my bean be "authenticated" so it can use the service?
If there's no user authenticated there's no way of checking his roles. If you want that bean to be authenticated before calling the method i think you could try something in this way:
SecurityContextHolder.getContext().setAuthentication(new user here);
User test = userService.getUser(1);

Spring #Autowired OK on JUnit, NPE on main class

I have a open source project hosted at this github. I am facing a weird scenario. I found many people who could make #Autowired Spring annotation work on their main classes but not on their JUnit test classes. My problem is the other way around. I can successfully use #Autowired in my JUnit test class but when a test calls my main class, the dependencies don't get injected there. Here is my context (simplified version):
Login Class:
package net.openrally.restaurant.core.exposure.resource;
#Path("/login")
#Component
#Transactional
#Singleton
#Produces("application/json")
#Consumes("application/json")
public class Login extends BaseResource{
#Autowired
private UserDAO userDAO;
#POST
public Response post(String requestBody){
...
//NullPointerException
User user = userDAO.loadByCompanyIdAndLogin(companyId, login);
}
...
}
LoginTest Class:
package net.openrally.restaurant.core.exposure.resource;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/applicationContext.xml")
public class LoginTest extends BaseResourceTest {
#Autowired
private UserDAO userDAO;
...
#Test
public void testInvalidPassword() {
....
// Works perfectly!
userDAO.save(user);
....
}
}
applicationContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:configuration.properties</value>
</list>
</property>
</bean>
<context:annotation-config />
<context:component-scan base-package="net.openrally.restaurant.core" />
<import resource="db-config.xml" />
</beans>
I am searching for a solution for a few days now. From what I could find so far, most of the people who have #Autowired problems dont have either <context:annotation-config /> or xmlns:context="http://www.springframework.org/schema/context" in their spring xml or dont have a #Component family annotation in the class they want DI to take place, and as you can see, they are both there :(. I have only one applicationContext.xml in my project which suits for both runtime and test (I have distinct configuration.properties to set database credentials and log levels differently, but no spring configuration there)
I'm using:
Spring: 3.1.0.RELEASE
JUnit: 4.10
Jersey: 1.11
CLIB: 2.2.2
Any ideas, and I mean ANY :), is much appreciated.
UPDATE
The following logs come up when I run the test:
2012-03-27 07:37:02,457 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'login'
2012-03-27 07:37:02,457 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'login'
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Found injected element on class [net.openrally.restaurant.core.exposure.resource.Login]: AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.ConfigurationDAO net.openrally.restaurant.core.exposure.resource.Login.configurationDAO
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Found injected element on class [net.openrally.restaurant.core.exposure.resource.Login]: AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.UserDAO net.openrally.restaurant.core.exposure.resource.Login.userDAO
2012-03-27 07:37:02,459 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Eagerly caching bean 'login' to allow for resolving potential circular references
2012-03-27 07:37:02,459 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Getting BeanInfo for class [net.openrally.restaurant.core.exposure.resource.Login]
2012-03-27 07:37:02,462 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Caching PropertyDescriptors for class [net.openrally.restaurant.core.exposure.resource.Login]
2012-03-27 07:37:02,462 TRACE [main] org.springframework.beans.CachedIntrospectionResults - Found bean property 'class' of type [java.lang.Class]
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'login': AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.ConfigurationDAO net.openrally.restaurant.core.exposure.resource.Login.configurationDAO
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'configurationDAO'
2012-03-27 07:37:02,462 DEBUG [main] org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'login' to bean named 'configurationDAO'
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'login': AutowiredFieldElement for private net.openrally.restaurant.core.persistence.dao.UserDAO net.openrally.restaurant.core.exposure.resource.Login.userDAO
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDAO'
2012-03-27 07:37:02,463 DEBUG [main] org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'login' to bean named 'userDAO'
2012-03-27 07:37:02,464 DEBUG [main] org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator - Creating implicit proxy for bean 'login' with 0 common interceptors and 1 specific interceptors
2012-03-27 07:37:02,464 DEBUG [main] org.springframework.aop.framework.Cglib2AopProxy - Creating CGLIB2 proxy: target source is SingletonTargetSource for target object [net.openrally.restaurant.core.exposure.resource.Login#60532a0a]
2012-03-27 07:37:02,465 DEBUG [main] org.springframework.aop.framework.Cglib2AopProxy - Unable to apply any optimisations to advised method: public javax.ws.rs.core.Response net.openrally.restaurant.core.exposure.resource.Login.post(java.lang.String)
Could Spring be creating my bean correctly but Jersey using its own non-autowired instance?
After researching a while, I could not find a way to make GrizzlyWeb use the context loaded by spring, so I tried to find an alternative solution.
I then found Hifaces20, which will let you start and stop a jetty instance, within the same JVM (which means you may, for instance, use a memory database that will be seen both by your tests and your application)
I had the exact same issue and later found that it was a developer issue :)
I was creating a new object instead of using the spring bean.
Lets say class MyService autowires a dao class MyDao myDaoBean. Now lets say I want to use MyService in MyController, I should wire in the Spring bean myServiceSpringBean. If I try to create a new myServiceObject then Spring doesn't wire the myDaoBean into the myServiceObject because it's not aware about that new service object.
And that leads to myDaoBean being null.

Resources