Circular dependency error. As I'm new to this technology i couldn't solve this. i need some here to clear this issue.
This code is to secure few pages in the existing project. I have to secure only 3 pages to access only by admin. Any solution which can escape circular dependency or which can fulfil my task will help.
My task is to complete secure few pages from accessing the user. This code is taken from a stackoverflow snippet.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/editincident","editaccident","editreqeust").authenticated()
.anyRequest().permitAll()
.and()
.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
you can write one line in your application.properties file to remove this error.
spring.main.allow-circular-references= true
In spring.io docs there is
"If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.
One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection."
So you should change the way you create one of your beans with using constructor method
Related
I'm developing a library that introduces a new authentication filter, that should be used in the spring-security chain
I know I can add the filter via something like:
#EnableResourceServer
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
class AmazingSecurityConfiguration extends WebSecurityConfigurerAdapter {
// filter bean
#Autowired
private MyFilter myFilter;
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// ... bunch of requirements per path
// ... or ignore path "/bla"
// etc.
.anyRequest().authenticated();
http.addFilterBefore(myFilter.getFilter(),
AbstractPreAuthenticatedProcessingFilter.class);
}
}
However, this wouldn't work alongside a user defined config. Really, I want to be configuring this bean within my library AutoConfigure class, that's triggered by the spring factories.
Looking around online, I see examples where they extend the WebSecurityConfigurerAdapter class themselves, and have the user extend this new config. But I don't know if this blocks a user from doing something else, and it also relies on the user first calling super.configure(http) to have the filter loaded.
What's the correct way here?
I was able to configure my own http configuration by fiddling with the invocation order of the beans within the autoconfiguration
#Configuration
#ConditionalOnClass(WebSecurityConfigurerAdapter.class)
// Two annotations below ensure that this is not the only WebSecurityConfigurerAdapter,
// as it might otherwise disable security for the rest of the application
// The Order ensures that Spring default which uses ConditionalOnMissingBean is still configured before this class
#AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
#ConditionalOnBean(WebSecurityConfigurerAdapter.class)
class LibraryFooSecurityConfig {
#RequiredArgsConstructor
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// autowired in from elsewhere in the autoconfig
private final MyFilter filter;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(filter,
AbstractPreAuthenticatedProcessingFilter.class);
}
}
}
This allows a user-defined security config to extend WebSecurityConfigurerAdapter and apply their own rules, while still allowing our library to add it's own items after that of the actual spring-boot application
When configuring Spring Security :
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
//#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
when running, with or without #Autowired, it works.
where AuthenticationManagerBuilder come from if it's not Autowired ?
There is no "injection" going on there. 'configure' is just a method that takes a AuthenticationManagerBuilder object.
Your SecurityConfig object implements WebSecurityConfigurerAdapter, and is a Spring Bean because of the annotations on it. You also enable security behavior via an annotation. All of this will cause Spring to be looking for beans of type WebSecurityConfigurerAdapter to serve a purpose in the set up of security. It finds your bean because it is one of these objects.
Spring knows what this type of bean is supposed to do, so it just calls the appropriate methods on that bean.
Because you have overloaded one of the methods of WebSecurityConfigurerAdapter, your version of that method will be called.
#Autowired is only for member variables that reference beans.
It is injected automatically in the method by the caller. Anyway #Autowiring has no role to play in a method argument.
I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.
I am relatively new to Spring in general but have read through the Apress Spring Rest text and gotten the examples running in Eclipse without problem.
Something that puzzles me in the examples is how objects appear to be automatically injected.
For example in chapter 8 security there is a QuickPollUserDetailsService class which implements the spring UserDetailsService class.
The text says the following:
"The SecurityConfig class declares a userDetailsService property, which gets injected with a QuickPollUserDetailsService instance at runtime."
#Configuration
#EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Inject
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder());
}}
Nowhere in any file does it specify QuickPollUserDetailsService is to be set.
Is Spring being smart here and noticing that QuickPollUserDetailsService is the only implementer of UserDetailsService and therefore assuming that it must be injected?
If that is the case what if I had 2 or more implementer's of UserDetailsService
By default, Spring Boot will recursively scan the packages and available implementation will be automatically injected. If there is more than one implementation available, startup will fail.
I am working on Spring Security Java-based configuration.
I have created my own MyAuthenticationProvider which I want to register in the ProviderManager (single instance of AuthenticationManager).
I have found that ProviderManager has a list of providers to which I can register my single
MyAuthenticationProvider.
Here is the part of my Configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(MyAuthenticationProvider);
}
}
I found out that AuthenticationManagerBuilder has parentAuthenticationManager, defaultUserDetailsService and many other fields.
My questions are:
Where is this #Autowired annotation adding AuthenticationManagerBuilder auth from?
Is the AuthenticationManagerBuilder already created in the application context?
What would be the default state of AuthenticationManagerBuilder which is being injected? By default state I mean will there be some parentAuthenticationManager, authenticationProviders already registered in the AuthenticationManagerBuilder?
If I am adding auth.authenticationProvider(MyAuthenticationProvider), does this mean that I am adding one more provider in the AuthenticationManagerBuilder?
What does this mean? Taken from Spring Documentation
The name of the configureGlobal method is not important. However, it
is important to only configure AuthenticationManagerBuilder in a class
annotated with either #EnableWebSecurity, #EnableWebMvcSecurity,
#EnableGlobalMethodSecurity, or #EnableGlobalAuthentication. Doing
otherwise has unpredictable results.
Answer for 1:
#EnableWebSecurity is meta-annotated with #EnableGlobalAuthentication
...
#EnableGlobalAuthentication
#Configuration
public #interface EnableWebSecurity {
...
and #EnableGlobalAuthentication imports AuthenticationConfiguration:
...
#Import(AuthenticationConfiguration.class)
#Configuration
public #interface EnableGlobalAuthentication {
}
In AuthenticationConfiguration, you'll see that an AuthenticationManagerBuilder bean is declared:
...
#Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
...
}
When you #Autowire an AuthenticationManagerBuilder, this is the one that you will get. You have several methods at your disposal to easily configure in-memory, jdbc, ldap,... authentication.
Answer for 2:
Background:
The Spring Security Java config goes through several stages to seamlessly incorporate your configurations with the ApplicationContext.One place where this comes together is in the getHttp() method in WebSecurityConfigurerAdapter.
For example, this is an excerpt:
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
To give you an idea of how "not-straightforward" the sequence of configuration is, the authenticationManager variable above will be either:
The authentication manager you added by overriding configure(AuthenticationManagerBuilder auth)
OR: The authentication manager you added in the method that #Autowired the AuthenticationManagerBuilder bean from AuthenticationConfiguration
OR: an AuthenticationManager bean found in the context
By default state I mean will there be some [...] authenticationProviders already registered in the AuthenticationManagerBuilder
If you look at AuthenticationConfiguration, you'll see that by default, the InitializeUserDetailsBeanManagerConfigurer is applied to the AuthenticationManagerBuilder bean. As long as it finds a UserDetailsService bean in the context and no other provider has been added, it will add a DaoAuthenticationProvider. This is why in the Spring Security reference, only providing a #Bean UserDetailsService bean is sufficient.
But once you add an authentication provider as you did, the "default" provider is not registered.
Answer for 3:
Yes. The code of AuthenticationManagerBuilder adds your provider:
public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
Answer for 4 is simple:
It means that, once you have one of that annotations, you can name your method as you wish:
#Configuration
#EnableWebSecurity //or #EnableWebMvcSecurity or #EnableGlobalMethodSecurity....
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void myCoolMethodName(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(MyAuthenticationProvider);
}
}
"Doing otherwise has unpredictable results"
If you keep the name but not the annotations, it may not work.