Error creating bean with name 'securityConfiguration' when running test - java

I'm creating a Spring Boot application with Spring Security. I've created a custom login page that uses an auth endpoint in our AuthController. My SecurityConfiguration class extends WebSecurityConfigurerAdapter.
At the moment, I'm trying to create tests for this without any results. Most of this is new to me and I'm still learning, specially testing. I'm not even sure if I've done this right at all.
Any help is appreciated.
SECURITYCONFIGURATION
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final PasswordEncoder passwordEncoder;
private final ApplicationUserService applicationUserService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/register", "/index*", "/static/**", "/*.js", "/*.json", "/*.ico").permitAll()
.antMatchers(HttpMethod.POST,"/api/auth/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
//.loginProcessingUrl("/api/auth/authenticate")
.defaultSuccessUrl("/home", true);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(applicationUserService);
return provider;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AUTHCONTROLLER
#RequiredArgsConstructor
#RestController
#RequestMapping("api/auth/")
public class AuthController {
private final UserService userService;
#PostMapping("authenticate")
public ResponseEntity<?> verifyUser(#RequestBody User user) throws Exception {
return userService.authenticateUser(user);
}
}
USERSERVICE
#Service
#RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final AuthenticationManager authenticationManager;
public ResponseEntity<?> authenticateUser(User user) throws Exception {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(user.getEmail(),user.getPassword()));
if (!authentication.isAuthenticated())
return new ResponseEntity<>(new ResponseObject("Error"), HttpStatus.UNAUTHORIZED);
else {
SecurityContextHolder.getContext().setAuthentication(authentication);
return new ResponseEntity<>(user,HttpStatus.OK);
}
}
}
TESTCLASS
#WebMvcTest(AuthController.class)
class AuthControllerTest {
User user;
#MockBean
UserService userService;
#Autowired
MockMvc mockMvc;
#BeforeEach
void setUp() {
user = User.builder()
.email("test#hotmail.com")
.password("password")
.id(1L).build();
}
#Test
void verifyUser() throws Exception {
given(userService.authenticateUser(any(User.class))).willReturn(new ResponseEntity<>(HttpStatus.OK));
mockMvc.perform(post("/api/auth/authenticate")
.contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
.andExpect(status().isOk());
}
}
ERRORS
Failed to load ApplicationContext java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfiguration' defined in file [\SecurityConfiguration.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Related

Spring security test with userDetailsService gives illegalStateException in test case

I have some spring controller tests that worked fine before.
I recently added authentication using a userDetailsService, and now when i run controller tests it says this:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'nl.kars.lms.service.MyUserDetailsService' available:
expected at least 1 bean which qualifies as autowire candidate.
I don't understand why, because everything should be configured correctly. It only happens when running the controller tests, running the app works perfectly fine. Here are my classes.
Test case
#RunWith(SpringRunner.class)
#WebMvcTest(ActionController.class)
public class ActionControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private ActionService service;
#Test
public void testGetActions_returns_result_from_service() throws Exception {
int actionId = 1;
Action action = new Action();
action.setId(actionId);
List<Action> actionsList = Arrays.asList(action);
given(service.getActions()).willReturn(actionsList);
mvc.perform(get("/actions")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].id", Matchers.is(actionId)));
}
}
Configuration
#EnableWebSecurity
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
MyUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**")
.fullyAuthenticated()
.and().httpBasic();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
UserDetailsService
#Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private EmployeeService employeeService;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return new EmployeeDetails(employeeService.getEmployeeByEmail(email));
}
}
My question is, how do i stop the error from occuring? What am i doing wrong? I am lost at this point.
Thanks
Since you have named Your MyUserDetailsService as userDetailsService in #Service("userDetailsService") you have two options
First One :
Use #Qualifier("userDetailsService") in SecurityConfiguration.
Second Option: Autowire UserDetailsService instead of MyUserDetailsService in SecurityConfiguration.
I suggest you try the first option
#Autowired
#Qualifier("userDetailsService")
MyUserDetailsService userDetailsService;

Spring mvc hide one package from others

As it can be seen in picutre, my ComponentScan is set to whole project. But somehow 'config' package doesn't see any other package and vice versa.
If I run my project, i get an error on startup that No qualifying bean of type 'com.rjproject.dao.UserDao' available, and the same for all other beans, that autowired in this package. But they autowiring perfectly fine in all other packages.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through field 'myUserDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.rjproject.service.MyUserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
But this bean exists and autowires fine in any other package.
here webSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
MyUserDetailsService myUserDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/login").failureUrl("/login?error")
.usernameParameter("username")
.passwordParameter("password")
.and().logout().logoutSuccessUrl("/login?logout")
.and().csrf()
.and().exceptionHandling().accessDeniedPage("/403");
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
and here MyUserDetailService
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserDao userDao;
#Transactional(readOnly=true)
#Override
public UserDetails loadUserByUsername(final String username)
throws UsernameNotFoundException {
com.rjproject.entities.User user = userDao.findByUserName(username);
List<GrantedAuthority> authorities =
buildUserAuthority(user.getAuthorities());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(com.rjproject.entities.User user,
List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(),
user.isEnabled(), true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<Authorities> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (Authorities userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getAuthority()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
}
UPD
As i figured out, the problem is that spring beans doesn't created already when i want to autowire it in config. But every online example says that it should work.
It doesn't hide. You just need to set #ComponentScan annotation to all of your config classes. Each config class should have its own #ComponentScan

Spring-boot OAuth2 implementation: NoSuchBeanDefinitionException: No qualifying bean of type AuthenticationManager

org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'authorizationServerConfig': Unsatisfied
dependency expressed through field 'authenticationManager'; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'org.springframework.security.authentication.AuthenticationManager'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Hi I have spring-boot web app and I'm trying to implement login/authorization -authentication system using Spring Security and OAuth2 by following this example: https://www.youtube.com/watch?v=dTAgI_UsqMg&t=1307s
Every thing was good but when I run my application I get exception saying it can+t find bean for AuthenticationManager even thought it is there and autowired.
Looking across internet this seems like a know or common issue with Oauth2 but I can't find right workaround
Some people suggested to "expose" the AuthenticationManager bean, I'm not sure what that means in this context
This is link to my current project on github: https://github.com/chenchi13/spring-boot-cms
Can anyone help me figure this out?
class that is throwing exception:
#EnableResourceServer
#Configuration
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService customUserDetailService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.parentAuthenticationManager(authenticationManager)
// .inMemoryAuthentication()
// .withUser("Peter")
// .password("peter")
// .roles("USER");
auth.parentAuthenticationManager(authenticationManager)
.userDetailsService(customUserDetailService);
}
}
Authorization Server Config:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("ClientId")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
Remove the following from ResourceServerConfig:
#Autowired
private AuthenticationManager authenticationManager;
And change configure method like following:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService);
}
Also override the following method in ResourceServerConfig:
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
This should fix your issue.
I think you are missing definition for authenticationManager bean. I am adding the lines below, check it out once:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Other Details
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new ShaPasswordEncoder(encodingStrength));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName(securityRealm)
.and()
.csrf()
.disable();
}
// Other Details
}
You can go through reference link below.
Reference: Spring Boot with JWT and OAuth2.0
Hope this helps you :)

Spring Boot Testing - No Qualifying Bean Exception

While attempting some tests using the Spring Boot framework, I am running into an issue with finding a Bean that the test unit depends on.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authServerApplication': Unsatisfied dependency expressed through field 'passwordEncoder'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.crypto.password.PasswordEncoder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
My test class:
#RunWith(SpringRunner.class)
#DataJpaTest
#SpringBootTest
public class UserDetailsTest {
#Autowired
private TestEntityManager entityManager;
// #MockBean
// private PasswordEncoder passwordEncoder;
#Autowired
private UserRepository userRepo;
#Test
public void test() {
OAuthUser user = null;
this.entityManager.persist(new OAuthUser("Kelly", "Marchewa", "kmarchewa", "password"));
user = userRepo.findByUserName("kmarchewa");
System.out.println(user.getPassword());
assertThat(user.getUserName()).isEqualTo("kmarchewa");
}
}
If I uncomment the #MockBean portion, the code will compile fine. However, I want to test the repository on its ability to encode and decode passwords too. To my understanding of the documentation, the #SpringBootTest annotation should be able to automatically "pick-up" the #Configuration classes. I have a main #SpringBootApplication:
#SpringBootApplication
public class AuthServerApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(AuthServerApplication.class, args);
}
#Bean
public CommandLineRunner demo(UserRepository repository) {
return(args) -> {
OAuthUser user = new OAuthUser();
user.setFirstName("Kelly");
user.setLastName("Marchewa");
user.setPassword(passwordEncoder.encode("Admin"));
user.setUserName("Admin");
// repository.save(user);
};
}
}
This Spring Boot Application depends on three other #Configuration classes: AppConfig, SecurityConfig, and AuthServerConfig. For this issue, the SecurityConfig and AppConfig classes are relevant (they include references to the PasswordEncoder bean).
AppConfig (partial)
#Configuration
public class AppConfig {
#Value("${spring.datasource.url}")
private String datasourceUrl;
#Value("${spring.datasource.driverClassName}")
private String dbDriverClassName;
#Value("${spring.datasource.username}")
private String dbUsername;
#Value("${spring.datasource.password}")
private String dbPassword;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/// more code here
}
SecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private OAuthUserDetailsService userService;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
// Hash password
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName("test")
.and()
.csrf()
.disable();
}
}
The UserRepository class is very simple:
public interface UserRepository extends CrudRepository<OAuthUser, Long> {
public OAuthUser findByUserName(String name);
}
How can I ensure all required beans are found for my tests?
Thanks.
EDIT:
I receive the same error if I attempt to #Autowire the bean in my test class.
#Autowired
private PasswordEncoder passwordEncoder;
The problem is #DataJpaTest this annotation should be used only for Data repositories test and not full integration (which is what you are doing) as because it only persistence beans are created in context and not all you beans (the reason bean can not be found). What you need to do is use only #SpringBootTest and declared h2 as testing dependency, in that way a full recreation of your application will be created using in memory database

Unresolved circular reference when trying to deploy a spring boot war to tomcat8?

I am new to spring and trying to create a web app using spring boot and jsp which I can deploy using tomcat8 on a raspberry pi. I can deploy my app through sts on an embedded tomcat instance and I can also deploy a war file to Jenkins without any errors. However, when I add the war to tomcat8 webapps folder and start tomcat I get the following error:
2016-04-19 10:54:41.384 WARN 5525 --- [ost-startStop-1] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.rcctv.controllers.UserController.setUserService(com.rcctv.services.UserService); nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceImpl' defined in file [/usr/share/tomcat8/webapps/RaspberryCCTV-0.0.1-SNAPSHOT/WEB-INF/classes/com/rcctv/services/UserServiceImpl.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [org.springframework.security.crypto.password.PasswordEncoder]: : Error creating bean with name 'webSecurityConfig': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'userServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'userServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?
I have tried annotating my configuration class with #Lazy and added setter methods to my userServiceImpl class but I still got the issue. Any help would be greatly appreciated?
webConfig class
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${rememberMe.privateKey}")
private String rememberMeKey;
#Value("${spring.profiles.active}")
private String env;
#Resource
private UserDetailsService userService;
#Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
#Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(rememberMeKey, userService);
return rememberMeServices;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/",
"/home",
"/error",
"/signup",
"/forgot-password",
"/reset-password/*",
"/public/**",
"/users/*").permitAll()
.anyRequest().authenticated();
http
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/raspberrycctv")
.permitAll().and()
.rememberMe().key(rememberMeKey).rememberMeServices(rememberMeServices()).and()
.logout()
.permitAll();
if (!env.equals("dev"))
http.requiresChannel().anyRequest().requiresSecure();
}
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
}
UserSeviceImpl
#Service
#Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class UserServiceImpl implements UserService, UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
private UserRepository userRepository;
private PasswordEncoder passwordEncoder;
private MailSender mailSender;
#Autowired
public UserServiceImpl(UserRepository userRepository,
PasswordEncoder passwordEncoder,
MailSender mailSender) {
this.mailSender = mailSender;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
#Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Autowired
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
#Autowired
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
#Override
#Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void signup(SignupForm signupForm) {
final User user = new User();
user.setEmail(signupForm.getEmail());
user.setName(signupForm.getName());
user.setPassword(passwordEncoder.encode(signupForm.getPassword()));
user.getRoles().add(Role.UNVERIFIED);
user.setVerificationCode(RandomStringUtils.randomAlphanumeric(16));
userRepository.save(user);
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
try {
String verifyLink = Utilities.hostUrl() + "/users/" + user.getVerificationCode() + "/verify";
mailSender.send(user.getEmail(), Utilities.getMessage("verifySubject"), Utilities.getMessage("verifyEmail", verifyLink));
logger.info("Verification mail to " + user.getEmail() + " queued.");
} catch (MessagingException e) {
logger.error(ExceptionUtils.getStackTrace(e));
}
}
});
}
}
I think you should go through Spring Reference about IoC container.
WebSecurityConfig class requires UserDetailsService, which is implemented by UserServiceImpl. Also, UserServiceImpl requires PasswordEncoder which is provided by WebSecurityConfig. This causes a circular reference. Removing constructor injection should be enough to resolve your problem.
Side note: Try not to use constructor injection. Spring is clever when it comes to DI, but if you use constructor injection you are forcing spring to use your way. This can also cause circular reference errors.
I recommend you to at least skim this article: https://steveschols.wordpress.com/2012/06/05/i-was-wrong-constructor-vs-setter-injection/

Categories