Spring Security, Problem with PasswordEncoder - java

i have a problem with PasswordEncoder,
my code:
#Service
public class UserService {
private static final String DEFAULT_ROLE = "ROLE_USER";
private UserRepository userRepository;
private UserRoleRepository roleRepository;
public PasswordEncoder passwordEncoder;
#Autowired
public UserService(PasswordEncoder passwordEncoder){
this.passwordEncoder = passwordEncoder;
}
#Autowired
public void setUserRepository(UserRepository userRepository){
this.userRepository = userRepository;
}
#Autowired
public void setUserRoleRepository(UserRoleRepository roleRepository){
this.roleRepository = roleRepository;
}
public void addWithDefaultRole(User user){
UserRole defaultRole = roleRepository.findByRole(DEFAULT_ROLE);
user.getRoles().add(defaultRole);
String passwordHash = passwordEncoder.encode(user.getPassword());
user.setPassword(passwordHash);
userRepository.save(user);
}
}
error:
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in org.spring.service.UserService required a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration.
Process finished with exit code 1
I don't know how to fix it.

Try this way ( One of two bean, not both):
#Configuration
#EnableWebSecurity
public class WebSecurityConfigAuthentication extends WebSecurityConfigurerAdapter {
// For BCrypt Encoded password
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
OR
// For no Encoder, plain text password
#Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}

For dependency injection to work, you need to acually declare a bean of the appropriate type, otherwise there is nothing to be injected. Exactly that is telling you the exception.
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // or any other password encoder
}

Related

Spring Boot Order of Initialization for reading from Database

I am currently using hibernate repositories and I need roles in my database, as one of my service layers uses the roles at startup.
#SpringBootApplication
public class FedditBackendApplication {
public static void main(String[] args) {
SpringApplication.run(FedditBackendApplication.class, args);
}
#Bean
CommandLineRunner init (RoleRepository roleRepo) {
return args -> {
for(ERole role: ERole.values()) {
if (!roleRepo.existsByName(role)){
roleRepo.save(new Role(role));
}
}
};
}
#Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
To initialize my roles into my database, I let spring do my schema creation, however I need to put these rows into the database directly afterwards.
Is There a better way to do this? The issue I'm running into is that one of my Service components gets from the roleRepository in the constructor and it's not finding anything when I use this initialization method.
#Service
#Transactional
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final AuthenticationManager authenticationManager;
private final RoleRepository roleRepository;
private final PasswordEncoder encoder;
private final JwtUtils jwtUtils;
private final Set<Role> userRoles;
public UserServiceImpl(UserRepository userRepository, AuthenticationManager authenticationManager, RoleRepository roleRepository, PasswordEncoder encoder, JwtUtils jwtUtils,Set<Role> userRoles){
this.userRepository = userRepository;
this.authenticationManager = authenticationManager;
this.roleRepository = roleRepository;
this.encoder = encoder;
this.jwtUtils = jwtUtils;
this.userRoles = new HashSet<>();
Optional<Role> userRole = this.roleRepository.findByName(ERole.ROLE_USER);
// throws error on next line because userRole is not present in the DB
this.userRoles.add(userRole.get());
}
}
I've tried changing the order of the bean initialization with no success.
It seems that the CommandLineRunner bean initializes after the service layers.
#Bean
CommandLineRunner init (RoleRepository roleRepo) {
return args -> {
for(ERole role: ERole.values()) {
if (!roleRepo.existsByName(role)){
roleRepo.save(new Role(role));
}
}
};
}
I'd like to initialize these rows after the schema is created, though I'm not really sure how.
https://github.com/vw0389/feddit-backend/tree/comments is the repo and branch if relevant

Getting the error "The dependencies of some of the beans in the application context form a cycle"

Checked similar threads with the same errors, but still unable to find where is the cause of the error. I am following tutorial and trying to create simple login page with username and password using spring, as well as implementing two roles of user.
Here is my securityConfig file and my userServiceImplement file which are causing this error.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/ws").permitAll()
.antMatchers("/users").hasAnyAuthority(Role.ADMIN.name())
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/auth")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.csrf().disable();
}
}`
#Service
public class UserServiceImplement implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserServiceImplement(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
#Override
public boolean save(UserDTO userDto) {
if(!Objects.equals(userDto.getPassword(), userDto.getMatchingPassword())){
throw new RuntimeException("Password is not equal");
}
User user = User.builder()
.name(userDto.getUsername())
.password(passwordEncoder.encode(userDto.getPassword()))
.email(userDto.getEmail())
.role(Role.USER)
.build();
userRepository.save(user);
return true;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findFirstByName(username);
if (user == null) {
throw new UsernameNotFoundException("User was not found with this name" + username);
}
List<GrantedAuthority> roles = new ArrayList<>();
roles.add(new SimpleGrantedAuthority(user.getRole().name()));
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getPassword(),
roles
);
}
}
Class SecurityConfig provides a PasswordEncoder and requires a UserService. Class UserServiceImplement is a UserService and requires a PasswordEncoder. In other words, to create a SecurityConfig you need a UserService, but to create a UserService you need a SecurityConfig to provide the PasswordEncoder.
The easiest fix is probably to move the PasswordEncoder method outside of SecurityConfig.
An alternative is to treat UserServiceImplement as a POJO (remove the #Service annotation) and create it manually inside the authenticationProvider method. You'll need a UserRepository for that, but you can use method argument injection for that:
#Bean
public DaoAuthenticationProvider authenticationProvider(UserRepository userRepository) {
PasswordEncoder passwordEncoder = passwordEncoder();
UserService userService = new UserServiceImplement(userRepository, passwordEncoder);
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder);
return auth;
}

#Autowired service bean in Controller Class won't recognize the methods

I have this classes:
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Autowired
private EntityManager entityManager;
#Override
public UserDetails loadUserByUsername( String username) throws UsernameNotFoundException {
Optional<User> userOptional = userRepository.findUserByUsername(username);
User user = userOptional.orElseThrow(
()->new UsernameNotFoundException("Username not found in the database")
);
return new MyUserDetails(user);
}
public void saveUser(User user){
User newUser=new User();
newUser.setUsername(user.getUsername());
newUser.setPassword(passwordEncoder.encode(user.getPassword()));
newUser.setEnabled(true);
newUser.setRoles(List.of(entityManager.find(Role.class,1)
));
userRepository.save(newUser);
}
public void deleteUser(User user){
userRepository.delete(user);
}
public UserDetails getCurrentlyLoggedUser(Authentication authentication){
Object principal = authentication.getPrincipal();
if(principal instanceof UserDetails){
String username=((User) principal).getUsername();
UserDetails loggedUser = loadUserByUsername(username);
return loggedUser;
}
return null;
}}
#Controller
#RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
#Autowired
private final UserDetailsService userDetailsService;
#GetMapping("/orderlist")
public String showOrdeList(Model model, #AuthenticationPrincipal Authentication authentication){
userDetailsService.getCurrentlyLoggedUser
}
}
I want to know why the methods from UserDetailsServiceImpl class won't show up in the controller...
I can acces only the methods from the interface, but not the ones implemented besides them.
I tried to use qualifiers, and even made a config class to instantiate the impl class when injecting the bean by interface.
#Configuration
public class OrderConfig {
#Bean("userDetailsService")
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
Can anyone tell me what I'm doing wrong?
Methods defined in UserDetailsServiceImpl but not in UserDetailsService aren't accessible because you're injecting your service by interface UserDetailsService and compiler doesn't know which implementation will be injected in runtime.
So, you need to define your own interface with all methods that you want to expose or inject your service by class.
#Autowired
private final UserDetailsServiceImpl userDetailsService;
I would recommend a custom interface that extends UserDetailsService and injecting your service using your custom interface.

Field myUserDetailsService in com.api.WebSecurityConfig required a single bean, but 2 were found

Full error:
Field myUserDetailsService in com.api.WebSecurityConfig required a single bean, but 2 were found:
user1: defined in file [/tools/tomcat/instances/webapps/api/WEB-INF/classes/com/api/jwt/users/test1.class]
user2: defined in file [/tools/tomcat/instances/webapps/api/WEB-INF/classes/com/api/jwt/users/test2.class]
I have the following classes:
Test1.java
#Service
#Component("user1")
public class Test1 implements UserDetailsService {
#Value("${test1.username}")
private String test1Username;
#Value("${test1.password}")
private String test1Password;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && username.equals(test1Username)) {
return new User(username, test1Password, new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username not found: " + username);
}
}
}
Test2.java
#Service
#Component("user2")
public class Test2 implements UserDetailsService {
#Value("${test2.username}")
private String test2Username;
#Value("${test2.password}")
private String test2Password;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && username.equals(test2Username)) {
return new User(username, test2Password, new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username not found: " + username);
}
}
}
SpringMainApplication.java
#EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService myUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/**/access-token").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
JwtRequestFilter.java
#Component
public class JwtRequestFilter extends OncePerRequestFilter {
#Autowired
#Qualifier(value = "user1")
private Test1 test1;
#Autowired
#Qualifier(value = "user2")
private Test2 test2;
#Override
protected void doFilterInternal() throws ServletException, IOException {
// SOME CODE
}
I thought that by using #Component and #Qualifier, I would be able to set up two user detail classes, but it doesn't seem to be the case.
Is there anything that I am missing or is it just not possible in this design?
If I make another class named MyUserDetailsService.java then compiling works and the correct classes are being accessed in the respective endpoints. I just don't understand why MyUserDetailsService must exist and I cannot use the Test1 and Test2 as user classes.
EDIT:
Test1.java
#Service
#Component("myUserDetailsService")
public class Test1 implements UserDetailsService {
#Value("${test1.username}")
private String test1Username;
#Value("${test1.password}")
private String test1Password;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && username.equals(test1Username)) {
return new User(username, test1Password, new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username not found: " + username);
}
}
}
Test2.java
#Service
#Component("myUserDetailsService")
public class Test2 implements UserDetailsService {
#Value("${test2.username}")
private String test2Username;
#Value("${test2.password}")
private String test2Password;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username != null && username.equals(test2Username)) {
return new User(username, test2Password, new ArrayList<>());
} else {
throw new UsernameNotFoundException("Username not found: " + username);
}
}
}
SpringMainApplication.java
#EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier(value = "myUserDetailsService")
private UserDetailsService myUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/**/access-token").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
JwtRequestFilter.java
#Component
public class JwtRequestFilter extends OncePerRequestFilter {
#Autowired
private Test1 test1;
#Autowired
private Test2 test2;
#Override
protected void doFilterInternal() throws ServletException, IOException {
// SOME CODE
}
This gives me the following error:
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.api.SpringMainApplication];
nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'myUserDetailsService' for bean class [com.api.jwt.users.Test2DetailsService] conflicts with existing, non-compatible bean definition of same name and class [com.api.jwt.users.Test1DetailsService]
You don't need qualifiers for these declarations. Spring can inject those by type as there's a single matching bean for each type (Test1 and Test2).
#Autowired
#Qualifier(value = "user1")
private Test1 test1;
#Autowired
#Qualifier(value = "user2")
private Test2 test2;
However you do need need a qualifier for this declaration because you have two implementations of UserDetailsService and spring doesn't know which one to inject, resulting in your error.
#Autowired
private UserDetailsService myUserDetailsService;
Edit
In your updated example you are defining two beans with the same bean id
#Component("myUserDetailsService")
public class Test1 implements UserDetailsService {
#Component("myUserDetailsService")
public class Test2 implements UserDetailsService {
This causes the new error you're seeing (It might help to review Spring documentation):
Annotation-specified bean name 'myUserDetailsService' for bean class
[com.api.jwt.users.Test2DetailsService] conflicts with existing,
non-compatible bean definition of same name and class
[com.api.jwt.users.Test1DetailsService]
In your example it doesn't really make sense to have two UserDetailsService implementations. You could refactor by combining them into a single class.

Error creating bean with name 'webSecurityConfig' because UserService Bean doesn't exist when I try to autowire it into WebSecurityConfig

All spring mvc + hibernate + spring security examples say that I need to create MyUserService class which extends UserDetailsService from springSecurity to bind my database with spring security.
But when I do so I get:
Error creating bean with name 'webSecurityConfig' no such bean UserSerivce is defined
because it doesn't exist yet when I try to autowire it into SecurityConfig.
When I download any online example, it gives me the same error.
My project in Git - start_over branch.
My WebSecurityConfig class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login", "/").anonymous()
.antMatchers("/admin", "/admin**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().logoutSuccessUrl("/login").permitAll()
.and()
.csrf().disable();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
my UserService:
public interface UserService extends UserDetailsService {
void save(User user);
List<User> getAllUsers();
}
my UserServiceImpl
#Service
public class UserServiceImp implements UserService{
#Autowired
private UserDao userDao;
#Transactional
public void save(User user) {
userDao.save(user);
}
#Transactional(readOnly = true)
public List<User> getAllUsers() {
return userDao.getAllUsers();
}
#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 org.springframework.security.core.userdetails.User buildUserForAuthentication(com.rjproject.entities.User user,
List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.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:
I have RunJob Class that creates users on startup and UserService autowires there without errors. Here it is:
#Service
public class RunJob implements InitializingBean {
private static final Logger logger = Logger.getLogger(RunJob.class);
#Autowired
private UserService userService;
public void afterPropertiesSet() {
User userA = new User();
userA.setUsername("ARS");
userA.setPassword("ART");
Authorities authorityA = new Authorities();
authorityA.setAuthority("ADMIN");
authorityA.setUser(userA);
Set<Authorities> roles = new HashSet<>();
roles.add(authorityA);
userA.setAuthorities(roles);
userService.save(userA);
logger.info("user " + userA.getUsername() + " " + userA.getPassword() + " is saved with " + authorityA.getAuthority() + " authority");
User userB = new User();
userB.setUsername("John");
userB.setPassword("Doe");
Authorities authorityB = new Authorities();
authorityB.setAuthority("USER");
authorityB.setUser(userB);
roles.clear();
roles.add(authorityB);
userB.setAuthorities(roles);
userService.save(userB);
logger.info("user " + userB.getUsername() + " " + userB.getPassword() + " is saved with " + authorityB.getAuthority() + " authority");
}
}
I get exact same error when I download any online example. Something with SpringSecurity itself.
UPD2:
here is all config classes.
webMvcConfig
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.rjproject"})
public class WebMvcConfig implements WebMvcConfigurer {
#Autowired
private ApplicationContext applicationContext;
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
WebAppInit
public class WebAppInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HibernateConfig.class, WebSecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebMvcConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
If your project have multiple config classes like mine have WebMvcConfig and WebSecurityConfig you should define annotation #ComponentScan(basePackages = {"com.rjproject"})
for every config class.
1 : In your case (javaconfig) you have to define a Bean that return userService object, where did it defined?!
2 : Other way, I think if you add setter method for userService in WebSecurityConfig class then problem get solved! just like this
public void setUserService(UserService userService){
this.userService = userService;
}
and next step here, in implementing class from UserService interface you have to add #Service annotation above of class and set 'value' attribute of #Service to "userService".

Categories