Spring Security #PreAuthorize on controller method not invoked - spring

I'm trying to use Spring Security (3.2.4) to authorise access to controller methods. I'm using Spring JavaConfig to configure my application. The application starts successfully, unfortunately the #PreAuthoize expression never gets executed.
Here's how I've configured my application:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {WebSecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebAppConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
public class WebAppSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
#Configuration
#EnableWebMvc
#Import({ CoreAppConfig.class })
#ComponentScan(basePackageClasses = ControllerScanningMarker.class)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebAppConfig extends WebMvcConfigurerAdapter {
}
At the moment, I'm not actually authenticating any users so I was expecting that access to a #PreAuthorize annotated controller method would be denied to everyone but that's not happening. Obviously, the end goal is to actually authenticate users as well.
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
#Controller
#RequestMapping(produces = APPLICATION_JSON_VALUE)
public class RegistrationController {
#Autowired
private RegistrationService registrationService;
#PreAuthorize("hasRole('ROLE_USER')")
#RequestMapping(value = "/orders/{orderId}/registrations", method = POST, consumes = APPLICATION_JSON_VALUE)
#ResponseBody
public RegistrationResponse registerVerification(#PathVariable String orderId, #RequestBody #Valid Registration registration) {
RegistrationResult result = registrationService.registerVerification(registration);
return new RegistrationResponse(result);
}
}
If anyone has seen something like this before, I would greatly appreciate a tip.
Thank you.
Updated 11/07/2014
I have revisited this and fixed the issue with the authentication manager not being found but I still can't get the #PreAuthorize annotation to work (see all changes above).
I'm getting the following warnings in the logs:
00:04:06.090 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#5c694679' of type [class org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
00:04:06.154 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'enableGlobalAuthenticationAutowiredConfigurer' of type [class org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
00:04:06.161 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration' of type [class org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$$EnhancerByCGLIB$$47d25495] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
00:04:06.188 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration' of type [class org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerByCGLIB$$6313a932] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
00:04:06.223 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'methodSecurityMetadataSource' of type [class org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
00:04:06.229 [localhost-startStop-1] INFO org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Bean 'metaDataSourceAdvisor' of type [class org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

I was able to define users and roles for my application in my implementation of
protected void configureGlobal(AuthenticationManagerBuilder auth) in my security configurer class.
auth.inMemoryAuthentication().withUser("user").roles("user","otherrole").and().withUser("user2").roles("otherrole")
The #PreAuthorize("hasRole('ROLE_USER')") annotation denied access to user2 but not to user on controller methods annotated

#EnableGlobalMethodSecurity(prePostEnabled = true) work in java config

Related

How to migrate from AnnotationMethodHandlerAdapter to RequestMappingHandlerAdapter

I'm building REST services via Spring MVC in the application where the GUI is managed by Wicket. Basically, all I need is the DispatcherServlet and a controller with #RequestMapping/#RequestBody.
Because services serve JSON, I need to set MappingJackson2HttpMessageConverter. I can do this via AnnotationMethodHandlerAdapter and that works fine:
#Configuration
#ComponentScan("cz.swsamuraj.wicketspring")
public class SpringRestConfiguration {
#Bean
public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter() {
HttpMessageConverter<?>[] converters = { new MappingJackson2HttpMessageConverter()};
AnnotationMethodHandlerAdapter adapter = new AnnotationMethodHandlerAdapter();
adapter.setMessageConverters(converters);
return adapter;
}
}
The problem is that AnnotationMethodHandlerAdapter is deprecated and it's recommended to use RequestMappingHandlerAdapter instead.
But if I use this configuration:
#Configuration
#ComponentScan("cz.swsamuraj.wicketspring")
public class SpringRestConfiguration {
#Bean
public RequestMappingHandlerAdapter requestHandler() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
return adapter;
}
}
I receive an exception:
javax.servlet.ServletException: No adapter for handler [cz.swsamuraj.wicketspring.ws.api.QuestionApiController#69f8a79f]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1198)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
So, my question is: how can I set up a handler adapter in the RequestMappingHandlerAdapter?
I spent couple of days of research, but I didn't find any useful example of how to configure RequestMappingHandlerAdapter. All the advices just says to put #EnableWebMvc on the configuration, but this is not the way because of this Wicket-Spring coexistence.
Just to provide a full context, I've created a small buildable and runnable project on Bitbucket: sw-samuraj/blog-wicket-spring-rest
I was able to solve my problem with different approach - with usage of WebApplicationInitializer, I was able to put the #EnableWebMvc annotation on my configuration class and therefore neither the bean RequestMappingHandlerAdapter, nor AnnotationMethodHandlerAdapter are necessary. JSON now works fine, out-of-the-box.
Configuration
#Configuration
#EnableWebMvc
#ComponentScan("cz.swsamuraj.wicketspring")
public class SpringRestConfiguration {
// some additional beans needed for business logic
}
WebApplicationInitializer
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(SpringRestConfiguration.class);
servletContext.addListener(new ContextLoaderListener(dispatcherContext));
ServletRegistration.Dynamic dispatcher =
servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/rest/*");
}
}
Example project
Complete working example is on Bitbucket: blog-wicket-spring-rest

Custom RequestMappingHandlerMapping causes an error with Swagger

I have created a custom RequestMappingHandlerMapping with the latest version of Spring as follows so I can define a custom version annotation.
WebConfiguration,
#Configuration
#ConditionalOnClass({ ApiVersionedResource.class })
public class WebConfiguration {
#Bean
#Primary
public ContentNegotiationManager contentNegotiationManager() {
ContentNegotiationManagerFactoryBean contentNegotiationManagerFactoryBean = new ContentNegotiationManagerFactoryBean();
Map<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
contentNegotiationManagerFactoryBean.addMediaTypes(mediaTypes);
contentNegotiationManagerFactoryBean.afterPropertiesSet();
return contentNegotiationManagerFactoryBean.getObject();
}
#Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
#Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
CustomRequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setRemoveSemicolonContent(false);
handlerMapping.setContentNegotiationManager(contentNegotiationManager());
return handlerMapping;
}
};
}
}
CustomRequestMappingHandlerMapping,
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
#Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersionedResource typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersionedResource.class);
return createCondition(typeAnnotation);
}
#Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
ApiVersionedResource methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersionedResource.class);
return createCondition(methodAnnotation);
}
#Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && (AnnotationUtils.findAnnotation(beanType, ApiVersionedResource.class) != null);
}
private RequestCondition<?> createCondition(ApiVersionedResource versionMapping) {
if (versionMapping != null) {
return new ApiVersionedResourceRequestCondition(versionMapping.media(), versionMapping.version());
}
return null;
}
}
However, this is causing the following error during compilation and I have no idea what is causing it.
2017-03-15 16:44:58.215 DEBUG 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : 6 request handler methods found on class com.test.web.rest.OrganizationResource: {public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.createOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException={[/organizations],methods=[POST],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.updateOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException={[/organizations],methods=[PUT],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.getAllOrganizations(org.springframework.data.domain.Pageable) throws java.net.URISyntaxException={[/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.deleteOrganization(java.lang.Long)={[/organizations/{id}],methods=[DELETE],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.searchOrganizations(java.lang.String,org.springframework.data.domain.Pageable) throws java.net.URISyntaxException={[/search/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.getOrganization(java.lang.Long)={[/organizations/{id}],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}}
2017-03-15 16:44:58.238 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[POST],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.createOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[PUT],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.updateOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.test.service.dto.OrgDetailsDTO>> com.test.web.rest.OrganizationResource.getAllOrganizations(org.springframework.data.domain.Pageable) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations/{id}],methods=[DELETE],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.lang.Void> com.test.web.rest.OrganizationResource.deleteOrganization(java.lang.Long)
2017-03-15 16:44:58.240 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/search/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.test.service.dto.OrgDetailsDTO>> com.test.web.rest.OrganizationResource.searchOrganizations(java.lang.String,org.springframework.data.domain.Pageable) throws java.net.URISyntaxException
2017-03-15 16:44:58.240 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations/{id}],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.getOrganization(java.lang.Long)
2017-03-15 16:44:58.314 WARN 63518 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'documentationPluginsBootstrapper' defined in URL [jar:file:/Users/kasunt/.m2/repository/io/springfox/springfox-spring-web/2.6.1/springfox-spring-web-2.6.1.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL [jar:file:/Users/kasunt/.m2/repository/io/springfox/springfox-spring-web/2.6.1/springfox-spring-web-2.6.1.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'requestMappingHandlerMapping' is expected to be of type 'org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping' but was actually of type 'com.sun.proxy.$Proxy232'
Specially this right at the end,
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'requestMappingHandlerMapping' could not be injected as a 'org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping' because it is a JDK dynamic proxy that implements:
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
I seem to have fixed the problem by refactoring WebConfiguration as follows. Im not entirely sure why instantiating CustomRequestMappingHandlerMapping as a public class didn't work. Id be happy to listen to anyone who can think of a reason why.
#Configuration
#ConditionalOnClass({ ApiVersionedResource.class })
public class WebConfiguration {
#Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
#Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new CustomRequestMappingHandlerMapping();
}
};
}
private final class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
#Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersionedResource typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersionedResource.class);
return createCondition(typeAnnotation);
}
#Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
ApiVersionedResource methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersionedResource.class);
return createCondition(methodAnnotation);
}
#Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && (AnnotationUtils.findAnnotation(beanType, ApiVersionedResource.class) != null);
}
private RequestCondition<?> createCondition(ApiVersionedResource versionMapping) {
if (versionMapping != null) {
return new ApiVersionedResourceRequestCondition(versionMapping.media(), versionMapping.version());
}
return null;
}
}
}
In Spring Boot 2.0.0, there is a simpler way to achieve this.
Create an instance of WebMvcRegistrations interface as a bean and override appropriate method to return the customized version of that object. Spring boot will read and use that instance.
In this case only the getRequestMappingHandlerMapping() needs to be overridden and a custom implementation returned

Spring Social -ConnecController connect/twitter not initiating connection with twitter

I have been working on integrating my project with twitter api,
connectController, which i have declared as bean in springsocialconfig, is perfectly handling get requests of /connect/twitter that's after including csrf token in jsp..... but when im about to send post request from connectTwitter.jsp its redirecting back to connectTwitter.jsp page viz how many times i hit the button.
No idea whats happening background , i have set up callback url as 127.0.0.1 in app settings
I am using Spring Mvc 4.2.5, Spring Security 4.0.4 , Spring Social 1.1.2
my springSocialConfiguration classs
#Configuration
#EnableSocial
#PropertySource(value = { "classpath:twitter.properties" })
public class SpringSocialConfig implements SocialConfigurer {
#Inject
private DataSource dataSource;
#Autowired
private Environment environment;
//
// SocialConfigurer implementation methods
//
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
cfConfig.addConnectionFactory(new TwitterConnectionFactory(environment.getProperty("twitter.consumerKey"), environment.getProperty("twitter.consumerSecret")));
}
#Override
public UserIdSource getUserIdSource() {
return new UserIdSource() {
#Override
public String getUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
}
return authentication.getName();
}
};
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
return new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
}
//
// API Binding Beans
//
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter(ConnectionRepository repository) {
Connection<Twitter> connection = repository.findPrimaryConnection(Twitter.class);
return connection != null ? connection.getApi() : null;
}
//
// Web Controller and Filter Beans
//
#Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
ConnectController connectController = new ConnectController(connectionFactoryLocator, connectionRepository);
return connectController;
}
#Bean
public ReconnectFilter apiExceptionHandler(UsersConnectionRepository usersConnectionRepository, UserIdSource userIdSource) {
return new ReconnectFilter(usersConnectionRepository, userIdSource);
}
}
my SecurityConfiguration class
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
PersistentTokenRepository tokenRepository;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?param.error=bad_credentials").defaultSuccessUrl("/dashboard")
.usernameParameter("userName").passwordParameter("password").and()
.rememberMe().rememberMeParameter("remember-me").tokenRepository(tokenRepository)
.tokenValiditySeconds(86400)
.and()
.logout()
.logoutUrl("/signout")
.deleteCookies("JSESSIONID")
.and()
.authorizeRequests()
.antMatchers("/static/**", "/auth/**", "/login/**", "/signup/**","/","/home/**").permitAll()
.antMatchers("/**").authenticated();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public TextEncryptor textEncryptor() {
return Encryptors.noOpText();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Bean
public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
"remember-me", userDetailsService, tokenRepository);
return tokenBasedservice;
}
#Bean
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
return new AuthenticationTrustResolverImpl();
}
#Bean(name="authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
iam getting this on my console
INFO: Initializing Spring root WebApplicationContext
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Thu Nov 24 16:11:21 IST 2016]; root of context hierarchy
INFO : org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Registering annotated classes: [class com.twittermarketingtool.configuration.SpringSocialConfig,class com.twittermarketingtool.configuration.AppConfig,class com.twittermarketingtool.configuration.HibernateConfig]
WARN : org.springframework.context.annotation.ConfigurationClassEnhancer - #Bean method AppConfig.propertyPlaceHolderConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as #Autowired, #Resource and #PostConstruct within the method's declaring #Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see #Bean javadoc for complete details.
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
WARN : org.hibernate.dialect.Oracle9Dialect - HHH000063: The Oracle9Dialect dialect has been deprecated; use either Oracle9iDialect or Oracle10gDialect instead
INFO : org.springframework.security.web.DefaultSecurityFilterChain - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#7affc10f, org.springframework.security.web.context.SecurityContextPersistenceFilter#35bcf2b2, org.springframework.security.web.header.HeaderWriterFilter#5b2f3e74, org.springframework.security.web.csrf.CsrfFilter#165241a7, org.springframework.security.web.authentication.logout.LogoutFilter#5863f8aa, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#55794086, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#30dfc977, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#6f9bdfe3, org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#4abc2a35, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#2cdbfedf, org.springframework.security.web.session.SessionManagementFilter#468410cd, org.springframework.security.web.access.ExceptionTranslationFilter#d813edb, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#1000d825]
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/login],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.loginPage()
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/error],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.errorPage()
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/delete-user-{userName}],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.deleteUser(java.lang.String)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/edit-user-{userName}],methods=[POST]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.updateUser(com.twittermarketingtool.model.User,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,java.lang.String)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/logout],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.logoutPage(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/signup],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.newUser(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/ || /home],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.homePage()
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/signup],methods=[POST]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.saveUser(com.twittermarketingtool.model.User,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/edit-user-{userName}],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.editUser(java.lang.String,org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/dashboard],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.profilePage(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/Access_Denied],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.AppController.accessDeniedPage(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/add_t_accounts/connect/twitter],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.TwitterIntegraionController.helloTwitter(org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/add_t_accounts],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.TwitterIntegraionController.addTwitterAccountsPage(org.springframework.ui.ModelMap)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/twitter],methods=[GET]}" onto public java.lang.String com.twittermarketingtool.controller.TwitterProfileController.home(java.security.Principal,org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[POST]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.connect(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[DELETE]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.removeConnections(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}/{providerUserId}],methods=[DELETE]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.removeConnection(java.lang.String,java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[oauth_token]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth1Callback(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[code]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth2Callback(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[error]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth2ErrorCallback(java.lang.String,java.lang.String,java.lang.String,java.lang.String,org.springframework.web.context.request.NativeWebRequest)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET]}" onto public java.lang.String org.springframework.social.connect.web.ConnectController.connectionStatus(java.lang.String,org.springframework.web.context.request.NativeWebRequest,org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect],methods=[GET]}" onto public java.lang.String org.springframework.social.connect.web.ConnectController.connectionStatus(org.springframework.web.context.request.NativeWebRequest,org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for #ControllerAdvice: Root WebApplicationContext: startup date [Thu Nov 24 16:11:21 IST 2016]; root of context hierarchy
INFO : org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/static/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
INFO : org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler]
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 9448 ms
Nov 24, 2016 4:11:31 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'dispatcher'
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcher': initialization started
INFO : org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Refreshing WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Nov 24 16:11:31 IST 2016]; parent: Root WebApplicationContext
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcher': initialization completed in 95 ms
ERROR: org.springframework.social.support.LoggingErrorHandler - Response body: {"errors":[{"code":32,"message":"Could not authenticate you."}]}

Spring is ignoring #Transactional annotations in Apache Shiro Realm class

I am using Spring for IOC and transaction management, and am planning to use Apache Shiro as the security library.
Whenever I want to check a user's permissions, I call subject.isPermitted("right"), whereupon Shiro checks for the permission using a datastore. Within these calls, a database connection is established, and I have annotated the method with #Transactional. However, I always receive an error that there is no Hibernate session bound to the thread whenever I execute the permission check.
The method is in the Realm class. I defined a custom Shiro Realm class:
#Component
public class MainRealm extends AuthorizingRealm {
#Autowired
protected SysUserDao userDao;
#Transactional
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
...
final SysUser user = this.userDao.findByUsername(un);
...
return authInfo;
}
#Transactional
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
...
permissions = this.userDao.getAccessRights(un);
...
return authInfo;
}
}
Apache Shiro uses a Servlet Filter, so I have the following defined in web.xml:
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
I am using programmatic configuration for Spring. Here is my App Config class:
#Configuration //Replaces Spring XML configuration
#ComponentScan(basePackages = "com.mycompany")
#EnableTransactionManagement //Enables declarative Transaction annotations
public class SpringAppConfig {
#Bean
public DataSource sqlServerDataSource() throws Exception {...}
#Bean
#Autowired
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) {...}
#Bean
public AnnotationSessionFactoryBean getSessionFactory() throws Exception {...}
#Bean
public static PersistenceExceptionTranslationPostProcessor exceptionTranslation() {...}
#Bean
#Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
hcm.setHashIterations(shiroIter);
hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
mainRealm.setCredentialsMatcher(hcm);
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
sm.setRealm(mainRealm);
return sm;
}
#Bean
#Autowired
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
final ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(securityManager);
return filter;
}
/**
* This method needs to be static due to issues defined here:<br>
* https://issues.apache.org/jira/browse/SHIRO-222
*/
#Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
LifecycleBeanPostProcessor lbpp = new LifecycleBeanPostProcessor();
return lbpp;
}
#Bean
#DependsOn("lifecycleBeanPostProcessor")
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
#Bean
#Autowired
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager secMan) {
AuthorizationAttributeSourceAdvisor advBean = new AuthorizationAttributeSourceAdvisor();
advBean.setSecurityManager(secMan);
return advBean;
}
}
To summarize the issue, I believe my MainRealm class is being wired properly (it has an #Autowired dependency to a DAO object and I verified that it is not null) with the exception of the #Transactional annotation. Due to this, I cannot directly call user.isPermitted("") as it prompts an error: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
Would like to ask for help in checking whether I missed anything in my Spring configuration.
In the meantime I have hacked over this issue by calling the user.isPermitted("") function within a method in my Service class that's correctly bound by a #Transactional.
EDIT When I checked the logs for Spring initialization I can see this:
Bean 'mainRealm' of type [class com.x.security.MainRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
According to this SO answer it means MainRealm isn't being postprocessed by the transaction manager therefore any #Transactional annotations get ignored. If so, how can I correct this?
EDIT 2 According to this SO question: "In other words, if I write my own BeanPostProcessor, and that class directly references other beans in the context, then those referenced beans will not be eligible for auto-proxying, and a message is logged to that effect." I just checked ShiroFilterFactoryBean and it is in fact a BeanPostProcessor. And the problem is it requires a SecurityManager instance that in turn requires a MainRealm instance. So both beans are autowired and are thus ineligible for proxying. I feel like I'm closer to the solution but I still can't resolve it.
The root cause of the issue is in fact due to the following:
All BeanPostProcessors and their directly referenced beans will be instantiated on startup... Since AOP auto-proxying is implemented as a BeanPostProcessor itself, no BeanPostProcessors or directly referenced beans are eligible for auto-proxying (and thus will not have aspects 'woven' into them.
Referenced SO question is here.
I have resolved this issue by decoupling the Realm bean creation from the SecurityManager bean creation.
The relevant change is from the following code:
#Bean
#Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
hcm.setHashIterations(shiroIter);
hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
mainRealm.setCredentialsMatcher(hcm);
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
sm.setRealm(mainRealm);
return sm;
}
to the following code:
#Bean
public DefaultWebSecurityManager securityManager() {
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
//sm.setRealm(mainRealm); -> set this AFTER Spring initialization so no dependencies
return sm;
}
Then I use a ServletContextListener which listens to when the Spring context initialization completes and I have the both the MainRealm and SecurityManager beans. Then I just plug one bean inside another.
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
//Initialize realms
final MainRealm mainRealm = (MainRealm)ctx.getBean("mainRealm");
final DefaultWebSecurityManager sm = (DefaultWebSecurityManager)ctx.getBean("securityManager");
sm.setRealm(mainRealm);
} catch (Exception e) {
System.out.println("Error loading: " + e.getMessage());
throw new Error("Critical system error", e);
}
}
#Transactional annotation can be used before :
An interface def
An interface method
A class def
A PUBLIC method of a class
As explained in the documentation
The fact that your method is protected must be the reason of your problem, and your service method was maybe declared as public which would explained why it worked in that case

How to get Spring WebContext in class annotated #controller

In Spring MVC with annotation, we mark any POJO with #Controller.
In this controller we can get WebApplicationContext, using autowired property.
#Controller
public class HomePageController {
#Autowired
ApplicationContext act;
#RequestMapping("/*.html")
public String handleBasic(){
SimpleDomain sd = (SimpleDomain)act.getBean("sd1");
System.out.println(sd.getFirstProp());
return "hello";
}
But in this approach we do not have servletContext handy with us. So is there way we can still use older way of getting WebApplicationContext ? i.e.
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
How will we get servletContext here ?
I am not facing any compulsion to use old way; so this question is just out of curiosity to check flexibility of spring.
Also It can be a interview question.
You can just inject it into your controller:
#Autowired private ServletContext servletContext;
Or take HttpServletRequest as a parameter and get it from there:
#RequestMapping(...)
public ModelAndView myMethod(HttpServletRequest request ...){
ServletContext servletContext = request.getServletContext()
}
The following is correct approach :
#Autowired
ServletContext context;
Otherwise instead of auto wiring the ServletContext, you can implement ServletContextAware. Spring will notice this when running in a web application context and inject the ServletContext. Read this.
You can also do it inline:
#RequestMapping(value = "/demp", method = RequestMethod.PUT)
public String demo(#RequestBody String request) {
HttpServletRequest re3 = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
return "sfsdf";
}
You can implement an Interface from Spring called org.springframework.web.context.ServletContextAware
public class MyController implements ServletContextAware {
private ServletContext servletContext;
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext=servletContext;
}
}
Then you can use the servletContext any place in the class.
By accessing the session you can get the servlet context, sample code:
#Controller
public class MyController{
....
#RequestMapping(...)
public ModelAndView myMethod(HttpSession session ...){
WebApplicationContextUtils.getRequiredWebApplicationContext(session.getServletContext())
}
}
You can get the HttpSession from the HttpServletRequest also.

Resources