I have an auth-cas library that provides authentication to my spring boot project.
In this auth-cas library there is a class that extends
WebSecurityConfigurerAdapter with following configure function
#Override
#ConditionalOnProperty(value = "ugent.cas.serviceUrl", matchIfMissing = true)
#ConditionalOnClass(Cas.class)
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint());
if (basicAuthenticationProviders != null) {
http.addFilter(basicAuthFilter());
}
http.addFilter(casAuthenticationFilter())
.addFilter(requestSSOLogoutToCASServerLogoutFilter())
.logout()
.deleteCookies("JSESSIONID")
.permitAll()
.logoutSuccessUrl("/logout.html")
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable();
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
.antMatchers("/**").authenticated();
}
As this should be black box I've added my own WebSecurityConfigurerAdapter that looks like this:
#Configuration
//#Order(Integer.MAX_VALUE)
//#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#Order(1)
public class AuthSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring()
// All of Spring Security will ignore the requests
.antMatchers("/choose.html")
.antMatchers("/account/*");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http/*.addFilter(usernamePasswordAuthenticationFilter())
.formLogin()
.permitAll()
.and()
.logout()
.deleteCookies("JSESSIONID")
.permitAll()
.logoutSuccessUrl("/logout.html")
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable();
*/
.authorizeRequests()
.anyRequest().authenticated()
.and()
.authenticationProvider(AuthenticationProvider())
.formLogin()
.permitAll()
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
;
}
#Bean
public AuthenticationProvider AuthenticationProvider() {
return new LCAAuthenticationProvider();
}
#Bean
public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter () throws Exception{
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter ();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
My Custom AuthenticationProvider implements ´AuthenticationProvider´ and works as in the page redirects me to the /login page and I can login with credentials in my user base.
Only problem is when I am already logged in on another auth cas network I should be authenticated but it still prompts me with my custom Authentication Provider.
How Do I need to configure HttpSecurity so that it works with my 2 Authentication Providers.
Other related question, how can I from the ignored page /choose.html give the option between logging in with one of the 2 authentication providers?
EDIT
This is my current configuration of ´WebSecurityConfigurererAdapter´
#Configuration
//#Order(Integer.MAX_VALUE)
//#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#Order(0)
public class AuthSecurityConfiguration extends WebSecurityConfigurerAdapter {
/**
* The authProvider bean used as a cas authentication provider.
*/
#Autowired
private LCAAuthenticationProvider authProvider;
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring()
// All of Spring Security will ignore the requests
.antMatchers("/choose.html")
.antMatchers("/account/*");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
/**
* The authenticationManagerBean bean.
*
* #return the authenticationManagerBean
* #throws Exception
*/
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* The loginUrlAuthenticationEntryPoint bean
*
* #return the loginUrlAuthenticationEntryPoint
*/
#Bean
public LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
LoginUrlAuthenticationEntryPoint ep = new LoginUrlAuthenticationEntryPoint("/choose.html");
//ep.setLoginUrl(cas.getLoginUrl());
return ep;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(loginUrlAuthenticationEntryPoint());
http.addFilter(usernamePasswordAuthenticationFilter())
.formLogin()
.permitAll()
.and()
.logout()
.deleteCookies("JSESSIONID")
.permitAll()
.logoutSuccessUrl("/logout.html")
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable();
/*
.authorizeRequests()
.anyRequest().authenticated()
.and()
.authenticationProvider(AuthenticationProvider())
.formLogin()
.loginPage("choose.html")
.permitAll()
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
;
*/
}
#Bean
public LCAAuthenticationProvider lcaAuthenticationProvider() {
return new LCAAuthenticationProvider();
}
#Bean
public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter () throws Exception{
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter ();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
But I'm getting following error:
Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:62)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:54)
... 1 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:296)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180)
at be.ugent.lca.Application.main(Application.java:16)
... 6 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 26 more
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:44)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:105)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$699e3cc3.CGLIB$springSecurityFilterChain$2(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$699e3cc3$$FastClassBySpringCGLIB$$e656a0ba.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:355)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$699e3cc3.springSecurityFilterChain(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
I can trace the error to line 44 in https://github.com/spring-projects/spring-security/blob/master/config/src/main/java/org/springframework/security/config/annotation/AbstractSecurityBuilder.java but I can't find what's causing this
You need put the auth filter and username password filter to your own configuration(AuthSecurityConfiguration), and make it first, and then define an entry point for choose.html, and a filter to handle the request from choose.html and then redirect to different url(e.g /login or /auth) depend on the choice. so it will be like following.(I have done something like this before, So I just copy them, you can change to your own)
<security:http xmlns="http://www.springframework.org/schema/security" entry-point-ref="clientAuthenticationEntryPoint">
<intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/choose.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/autherror" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/**" access="IS_AUTHENTICATED_FULLY"/>
<custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
<custom-filter ref="authenticationBrokerProcessingFilter" after="LOGOUT_FILTER" />
<custom-filter ref="oauth2ClientContextFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
<custom-filter ref="oAuth2AuthenticationProcessingFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
<form-login
login-page="/login"
default-target-url="/main"
username-parameter="username"
password-parameter="password"
login-processing-url="/loginSubmit"
authentication-failure-handler-ref="passwordFailureHandler"
authentication-success-handler-ref="passwordAuthenticationSuccessHandler"
always-use-default-target="false"
/>
<csrf />
<access-denied-handler ref="accessDeniedHandler" />
</security:http>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg name="loginFormUrl" value="/choose.html"/>
</bean>
As you can see the xml, there are two authentication method, auth2 and username password.
authenticationBrokerProcessingFilter will handle the request from choose.html;
username password filter will handle the request /loginSubmit from login page;
auth2 filter will handle the request /oauth2-login from sso with code.
Related
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(cUserDetailService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/**").authenticated()
.and()
.csrf().disable()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.successHandler(successHandler)
.failureHandler(failureHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(authEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.maxSessionsPreventsLogin(false);
}
public class CUserDetailService implements UserDetailsService {
#Autowired
private UserDetailDataEntityRepository userDetailDataEntityRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username: " + username + ", " );
log.info(username == null);
Optional<UserDetailDataEntity> optional = userDetailDataEntityRepository.findByUsername(username);
if (optional.isPresent()) {
return optional.get();
} else {
throw new UsernameNotFoundException(username);
}
}
}
I used this config for my spring security, and got success login at first.
but then we find that if nobody access the server(even the login url) for a few days, and do login again the loadUserByUsername username will be empty and get login fail
FYI I used redis for session manage by adding dependency
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
and the login request is a form request
I am using Spring boot 1.3.2 with Spring Security.
I have following configure(HttpSecurity http) method to inforce authentication
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher csrfRequestMatcher = new RequestMatcher() {
private AntPathRequestMatcher[] requestMatchers = {
new AntPathRequestMatcher("/iams/w/*")
};
#Override
public boolean matches(HttpServletRequest request) {
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) { return true; }
}
return false;
} // method matches
};
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
}
and I have following configure(WebSecurity web) method to ignore some of the urls as below;
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/myapp/docs/**",
"/myapp/docs/*",
"/myapp/docs/index.html",
"/resources/**",
"/static/**");
}
But http request to http://127.0.0.1:9000/myapp/docs/index.html still reuires username/password ( authentication ) and returns "status":401,"error":"Unauthorized"...
Actually none of the ignore url on WebSecurity is working since it also requires authentication. If I provide the auth then it works. How can I simply ignore some urls (like "/myapp/docs/**" ) here. I have following definition in the SecurityConfig class
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
What am I missing ? Please Advise.
It would probably be easier to use as simple a set of patterns as possible to leave unsecured, and then simply say that everything else IS secured.
This may be closer to what you want:
public static final String[] NOT_SECURED = {"/iams/docs/**","/static/**"};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(NOT_SECURED);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(NOT_SECURED).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.csrf().disable();
}
There is an error order in your code.
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
Therefore, any request is needed to be authenticated. You can directly use antMatchers.
http
.authorizeRequests()
.antMatchers("/iams/w/*")
.authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.csrf().disable()
I hope it's helpful for you.
Thank you for your response but with your suggestion, my "/iams/w/*" is not protected at all. I can get to all these urls; "/iams/docs/**" , "/iams/w/" and "/iams/api/" without basic auth. Below is the set up as per your suggestion. Here I want to protect "/iams/w" and "/iams/api/" with username/password but let everyone get to "/iams/docs/*" without username/password. This is spring boot restful based implementation but want to expose some urls like docs so that it can be accessed by all and not the api calls.
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/iams/docs/**",
"/iams/docs/*",
"/iams/docs/index.html",
"/static/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/iams/api/**","/iams/api/v1/*")
.authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.csrf().disable();
}
I am developing a project using spring boot with spring security, below is my security configuration
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource datasource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.authorizeRequests()
.antMatchers("/ideate","/homecreate").permitAll()
.anyRequest().authenticated();
http
.authorizeRequests().anyRequest().authenticated();
http
.formLogin().failureUrl("/login?error")
.defaultSuccessUrl("/")
.loginPage("/login")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
JdbcUserDetailsManager userDetailsService = new JdbcUserDetailsManager();
userDetailsService.setDataSource(datasource);
PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
auth.jdbcAuthentication().dataSource(datasource);
}
}
After successful Log in of the user, i am calling a request mapping "/" written in the controller, the method will return a page which should contain username as model attribute how do i get the current logged in username?
Use the below code in your jsp ...
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<sec:authentication property="principal.username" />
This bit of code helped me to fetch the user information to the jsp.
I am working on converting a Spring 3 project to Spring 4 + Spring Boot. I don't know whether it is a right thing to do or not yet. I convert the Spring Security XML configuration to a Java based configuration as the following:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home").permitAll()
.anyRequest().authenticated();
http.formLogin()
.defaultSuccessUrl("/afterLogin")
.loginPage("/profiles/lognin/form")
.failureUrl("/accessDenied")
.and()
.authorizeRequests()
.regexMatchers("....")
.hasRole("ROLE_USER")
.antMatchers("....")
.hasRole("ROLE_USER")
//....
;
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder)
throws Exception {
authManagerBuilder.authenticationProvider(this.getDaoAuthenticationProvider());
}
// ....
}
I get the Spring Security default login popup panel when I hit the home URL. It seem to me that the above configuration doesn't take effect, but the default Spring Security configuration in Spring Boot doesn't. If so, how to override the default one?
I found the answer. I need to create a file called application.properties with the following line:
security.basic.enabled=false
and place this file under src/main/resource. That is it.
Configure your spring like that.
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.exceptionHandling()
.and()
.rememberMe()
.and()
.formLogin()
.loginProcessingUrl("/user") // rest apiyi yaz.
//.usernameParameter("username")
//.passwordParameter("password")
.permitAll()
.and()
.logout()
//.logoutUrl("/api/logout")
//.deleteCookies("JSESSIONID", "CSRF-TOKEN")
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/#/dashboard/home").permitAll()
;
}
I'm upgrading Spring security from 3.1 to 3.2 in my project. Since 3.2 supports code based configurations I have decided to convert old XML based configuration to Java code.
I receive the exception said that no bean with name "authenticationManager" has been found every time I try to start an application. This exception start appearing after #EnableGlobalMethodSecurity annotation been added to the configuration class.
Spring framework version: 4.0.0.RELEASE
Spring security version: 3.2.0.RELEASE
Old Xml config looks like that:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security secured-annotations="enabled"
jsr250-annotations="enabled"
pre-post-annotations="enabled"
proxy-target-class="true"/>
<http auto-config="true" use-expressions="true" >
<form-login login-page="/login"
default-target-url="/home"
authentication-failure-url = "/login?login_error=1" />
<logout logout-url="/logout" logout-success-url="/index" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="authUserDetailService">
<password-encoder hash="plaintext"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
New Java config class looks like that:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Bean
public UserDetailsService userDetailsServiceBean() {
return new UserDetailsService() {
private final Logger logger = LoggerFactory.getLogger(UserDetailsService.class);
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> list = new ArrayList<>();
String login = null;
String password = null;
logger.debug("Started loading user by name: " + username);
if (username.equals("admin")) {
login = "admin";
password = "admin";
list.add(new SimpleGrantedAuthority("ROLE_USER"));
list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
if (username.equals("user")) {
login = "user";
password = "user";
list.add(new SimpleGrantedAuthority("ROLE_USER"));
}
logger.debug("User " + username + ": " + login + ", " + password);
return new User(login, password, true, true, true, true, list);
}
};
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?login_error=1")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/index");
}
}
Text of exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webAppFrontController' defined in file [/mnt/data/Docs/IdeaProjects/test/target/test/WEB-INF/classes/sample/web/controllers/WebAppFrontController.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Unexpected AOP exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1551)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.springframework.aop.framework.AopConfigException: Unexpected AOP exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:224)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
... 54 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor.getAdvice(MethodSecurityMetadataSourceAdvisor.java:96)
at org.springframework.aop.framework.CglibAopProxy$ProxyCallbackFilter.hashCode(CglibAopProxy.java:916)
at org.springframework.cglib.proxy.Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$4ce19e8f.hashCode(<generated>)
at java.util.HashMap.hash(HashMap.java:366)
at java.util.HashMap.getEntry(HashMap.java:466)
at java.util.HashMap.get(HashMap.java:421)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:199)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
... 61 more
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
... 79 more
Caused by: java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
at org.springframework.util.Assert.isTrue(Assert.java:65)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.lazyBean(GlobalMethodSecurityConfiguration.java:377)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.authenticationManager(GlobalMethodSecurityConfiguration.java:262)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor(GlobalMethodSecurityConfiguration.java:123)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerByCGLIB$$8215642a.CGLIB$methodSecurityInterceptor$10(<generated>)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerByCGLIB$$8215642a$$FastClassByCGLIB$$8ae0c10a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerByCGLIB$$8215642a.methodSecurityInterceptor(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
... 80 more
I've been looking at this for a two days now but can't find a solution for this issue.
UPDATE
Root config:
#Configuration
#ComponentScan(basePackages = "sample.service")
#Import({SecurityConfig.class, MvcConfiguration.class, RepositoryConfig.class})
public class RootConfig {
#Bean
public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("db.properties"));
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
Web application Initializer:
public class WebAppInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final String DISPATCHER_SERVLET_MAPPING = "/";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
FilterRegistration.Dynamic sessionInView = servletContext.addFilter("sessionInView", new OpenEntityManagerInViewFilter());
sessionInView.addMappingForUrlPatterns(null, true, "/*");
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
Stack trace already contains all information needed to find solution. There is no AuthenticationManager bean in Spring context. So it need to be defined explicitly.
WebSecurityConfigurerAdapter class contains authenticationManagerBean() method. Its JavaDoc says:
Override this method to expose the AuthenticationManager from
configure(AuthenticationManagerBuilder) to be exposed as a
Bean. For example:
#Bean(name="myAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
Another thing (I don't actually understand why this is so) is that you need to configure AuthenticationManagerBuilder using configure(AuthenticationManagerBuilder) method defined in WebSecurityConfigurerAdapter and not with configureGlobal() method.
So the last version of my SecurityConfig is that:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Bean #Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?login_error=1")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/index");
}
}