com.nt.service.JwtUserDetailsService required a bean of type 'com.nt.dao.SpringSecurityDao' that could not be found - spring-boot

#SpringBootApplication
#ComponentScan(basePackages={"com.nt.controller","com.nt.config","com.nt.service","com.nt.dao"})
List item
public class SpringSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityApplication.class, args);
}
//service class
#Service
public class JwtUserDetailsService implements UserDetailsService {
#Autowired(required=true)
private SpringSecurityDao dao;
#Autowired
private PasswordEncoder bcryptEncoder;
public UserDetails loadUserByUsername(String username) {
// TODO Auto-generated method stub
/* UserDao user = dao.findByUsername(username);
if (user == null) {
//dao class
#Repository
public interface SpringSecurityDao extends CrudRepository<UserDao, Integer> {
UserDao findByUsername(String username);

It because you put #Autowired(required=true) , you remove it (required=true)

Related

I'm trying to use spring security with PostgreSQL, I want get users from database but getting StackOverflowError: null

#ComponentScan(basePackages = {"conf"})
#ComponentScan(basePackages = {"application.controller"})
#ComponentScan(basePackages = {"applicaion.model"})
#ComponentScan(basePackages = {"applicaion.dao"})
#ComponentScan(basePackages = {"usersDetails"})
#SpringBootApplication
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Security config part
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Override
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
#Bean
public PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
}
User Entity
"felhasznalonev"==username and "felhasznalo"==user
in hungarian
in the database table has theese names
#Entity
#Table( name="felhasznalo")
public class User {
#Id
#GeneratedValue
private int id;
#Column( unique=true, nullable=false )
private String felhasznalonev;
#Column( nullable=false )
private String jelszo;
private int statusz;
public User() {}
public User(String felhasznalonev,String jelszo,int statusz) {
this.felhasznalonev=felhasznalonev;
this.jelszo=jelszo;
this.statusz=statusz;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFelhasznalonev() {
return felhasznalonev;
}
public void setFelhasznalonev(String email) {
this.felhasznalonev = email;
}
public String getJelszo() {
return this.jelszo;
}
public void setPassword(String password) {
this.jelszo = password;
}
#Override
public String toString() {
return null;
}
public int getStatusz() {
return statusz;
}
public void setStatusz(int statusz) {
this.statusz = statusz;
}
}
userServiceimpl part
#Service("userDetailsService")
public class UserServiceImpl implements UserService, UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = findByUsername(username);
return new UserDetailsImpl(user);
}
#Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
UserDetailsImpl part
public class UserDetailsImpl implements UserDetails {
private User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public UserDetailsImpl() {}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("USER"));
}
#Override
public String getPassword() {
return user.getJelszo();
}
#Override
public String getUsername() {
return user.getFelhasznalonev();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
UserService part
public interface UserService {
public User findByUsername(String username);
}
UserRepository
public interface UserRepository extends JpaRepository<User,Integer> {
User findByUsername(String username);
}
When i run the code everything looks fine, the basic login page come in, i enter the username/password from the database but nothing happen
and IntellIj write this:
2021-11-25 13:12:48.870 ERROR 13928 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError: null
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:472) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:472) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
-||-
the connection with database is good, i can list users as well
Thanks for reading all this and sorry for bad english and mistakes, have a good day!
java.lang.StackOverflowError error tell you method declaration in service layer is not linked with any JpaRepository. Problem is came up from loadUserByUsername method in userServiceimpl. You declare method findByUsername without linked with Repository.
Change
User user = findByUsername(username);
To
User user = userRepository.findByUsername(username);
And UserServiceImpl Implements with UserDetailsService only. You need to change inSecurity config code because it has more problem like add wrong annotation and two method declare with same name etc...
Modified Security config
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService userDetailsService;
#Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
You have doubly declared userDetailsService with the same name,
First:
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
Second:
#Service("userDetailsService")
public class UserServiceImpl implements UserService, UserDetailsService {
It may cause the problem. You should have only one instance of userDetailService.
In your SecurityConfig Can you try removing
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
And changing the implementation for
#Override
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
to
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

where do I get the "username" value from in spring security to pass to the loadUserByUsername(String username) method of UserDetailsService interface

I am trying to get a user from the database by authenticating the user based on username and password. I am using basic authentication to do this.
I am sending username and password in the authorization header of the rest api
In my controller the getUser() method calls the getuser() method of the UserService class
#GetMapping("/user/self")
public ResponseEntity<UserDto> getUser() {
UserDto UserDto = userService.getUser();
return new ResponseEntity<>(UserDto, HttpStatus.OK);
}
#PutMapping("/user/self")
public ResponseEntity<User> updateUser(#Valid #RequestBody Map<String, String> userMap, Principal principal) {
String username = principal.getName();
String firstname = userMap.get("firstName");
String lastName = userMap.get("lastName");
String password = BCrypt.hashpw(userMap.get("password"), BCrypt.gensalt(10));
User user = userService.getUserByUserName(username);
user.setFirstName(firstname);
user.setLastName(lastName);
user.setPassword(password);
userService.save(user);
return new ResponseEntity<>(user, HttpStatus.NO_CONTENT);
}
UserService class implements UserDetailsService and overrides the loadUserByUsername method that requires a username to be passed as an argument. my question is: how do I pass username to loadUserByUsername() method from my UserService class that I am calling from my controller. where does username value reside?
my understanding is - the Authentication Object contains user credentials that are passed to authentication object when a user types their credentials and send their request, how do I retrieve this username value
#Service
public class UserService implements UserDetailsService {
#Autowired
UserRepository userRepository;
public UserDto save(User user) {
String hashedPassword = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(10));
user.setPassword(hashedPassword);
userRepository.save(user);
UserDto userDto = new UserDto();
userDto.setId(user.getId());
userDto.setFirstName(user.getFirstName());
userDto.setLastName(user.getLastName());
userDto.setUserName(user.getUserName());
userDto.setAccountUpdatedAt(user.getAccountUpdatedAt());
userDto.setAccountCreatedAt(user.getAccountCreatedAt());
return userDto;
}
#Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userRepository.findByUserName(userName);
if (user == null) {
throw new UsernameNotFoundException(userName + "was not found");
}
return new UserPrincipal(user);
}
here is my repository code:
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUserName(String userName);
}
here is my authentication code:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
UserService userService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests().antMatchers("/v1/user").permitAll()
.antMatchers("/v1/user/self").authenticated().and().httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
}
if you dealing with JPA then in your case you have to use userDetailsService instead of jdbcauthentication, therefor your security class would look like this :
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private UserService userService;
public SecurityConfig(UserService userService){
this.userService = userService;
}
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(10); // Number of rounds
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.userService).passwordEncoder(passwordEncoder());
}
}
then you can customize the authentication in the UserService class to satisfy the business need as the below sample :
#Service
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = userRepository.findByUsername(username);
if(user.isPresent()){
log.info("cretaed under User service : " + user.get());
return user.get();
}
throw new UsernameNotFoundException("empty or invalud user");
}
}
in addition, do not forget to create the findByUsername method in your repository also do not forget to implement org.springframework.security.core.userdetails.UserDetails in your module class:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String name);
}

Spring Security login issue when trying to access a url after authentication

I am learning spring security and has followed few tutorials on Youtube, I have completed the task as taught by the author/teacher but unfortunately i could not login when i try to access my urls for /user and /admin after login, though i receive granted authorities object from database with USER_USER and USER_ADMIN roles but still when i request those urls i throws exception for forbidden access, anyone can guide why this is happening?
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService userDetailsService;
/*Authentication method*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.inMemoryAuthentication().withUser("admin").password("admin").roles("Admin").and().withUser("user").password("user").roles("User");
auth.userDetailsService(userDetailsService);
}
// Authorization - Should be from most secure to least one
#Override
protected void configure(HttpSecurity http) throws Exception {
// To allow access to any url without permission is by using permitAll() method
System.out.println("Accessign URL : ");
http.authorizeRequests().
antMatchers("/admin").hasRole("USER_ADMIN").
antMatchers("/user").hasAnyRole("USER_USER", "USER_ADMIN").
antMatchers("/", "static/css", "static/js").
permitAll().
and().
formLogin();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
MyUserDetails Class :
package com.springsecurity.demo.models;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class MyUserDetails implements UserDetails {
private static final long serialVersionUID = -3042145577630945747L;
private String userName;
private String password;
private List<GrantedAuthority> authorityList;
public MyUserDetails() {
}
public MyUserDetails(User user) {
this.userName = user.getUserName();
this.password = user.getPassword();
this.authorityList = Arrays.stream(user.getUserRole().trim().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
System.out.println((this.authorityList.size() > 0 ? this.authorityList.get(0) : "Empty"));
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorityList;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return userName;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
MyUserDetailsService class :
#Service
public class MyUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
public MyUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Optional<User> user = userRepository.findByUserName(userName);
user.orElseThrow(() -> new UsernameNotFoundException("User not found with name : " + userName));
return user.map(MyUserDetails::new).get();
}
}
UserRepository Class :
#Repository
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByUserName(String userName);
}
Controller Class :
#RestController
public class GreetingController {
#RequestMapping(value = "/")
public String greet() {
return "Hello World!";
}
#RequestMapping(value = "/user")
public String greetUser() {
return ("<h1>Hello User!</h2");
}
#RequestMapping(value = "/admin")
public String greetAdmin() {
return ("<h1>Hello Admin!</h2");
}
}
Thanks
I found the answer with just updating my database user_roles column values from USER_USER & USER_ADMIN to ROLE_USER & ROLE_ADMIN it worked for me, I don't know exactly the reason but it was specified that SimpleGrantedAuthority class expects to have role names like Role_Admin & Role_User format and it worked perfectly for me.
Along with database change i updated my WebSecurity configure method to following,
protected void configure(HttpSecurity http) throws Exception {
// To allow access to any url without permission is by using permitAll() method
System.out.println("Accessign URL : ");
http.authorizeRequests().
antMatchers("/admin", "/api/v1/users").hasRole("ADMIN").
antMatchers("/api/v1/students", "/api/v1/courses").hasAnyRole("USER", "ADMIN").
antMatchers("/", "static/css", "static/js").
permitAll().
and().
formLogin();
}

String Boot REST security Error : type=Forbidden, status=403

This project I have used Spring boot, security authentication, JPA and REST
This gives me 403 error, which is of role base error. I have tried for 2 days could not solve please help.
Here I am sharing code.
This is my Security config class have roles based /hello for all user and /admin/all and /admin/add for admin user.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encodePsw());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/api/secure/admin/**").hasRole("ADMIN").antMatchers("/api/secure/**")
.hasAnyRole("USER", "ADMIN").anyRequest().authenticated().and().formLogin().permitAll();
}
#Bean
public BCryptPasswordEncoder encodePsw() {
return new BCryptPasswordEncoder();
}
}
This is my Controller class have 3 method which is or 3 role based /hello for all user and /admin/all and /admin/add for admin user.
#RestController
#RequestMapping("/api/secure")
public class AdminController {
#Autowired
private UserRepository userRepo;
#Autowired
private BCryptPasswordEncoder passEncp;
#RequestMapping(value = "/hello")
public String hello() {
return "Hello..";
}
//#PreAuthorize("hasAnyRole('ADMIN')")
#RequestMapping(value = "/admin/add", method = RequestMethod.POST)
public String addUserByAdmin(#RequestBody User user) {
user.setPassword(passEncp.encode(user.getPassword()));
userRepo.save(user);
return "Add User Successfully";
}
//#PreAuthorize("hasAnyRole('ADMIN')")
#GetMapping("/admin/all")
public String securedHello() {
return "Secured Hello";
}
}
This is Role bean
#Entity
#Data
public class Role {
#Id
#GeneratedValue
private int roleId;
private String role;
}
This User Bean
#Entity
#Setter
#Getter
public class User {
#Id
private int userId;
private String username;
private String password;
private String email;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(name="user_role", joinColumns = #JoinColumn(name="user_id"), inverseJoinColumns = #JoinColumn(name="role_id"))
private Set<Role> roles;
}
UserRepository interface
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
CustomUserDetails class
I think the problem in this part. I have save role like ROLE_USER, ROLE_ADMIN also tried without ROLE_
#Getter
#Setter
public class CustomUserDetails implements UserDetails {
private User user;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority(""+role))
.collect(Collectors.toList());
}
#Override
public String getPassword() {
// TODO Auto -generated method stub
return user.getPassword();
}
#Override
public String getUsername() {
// TODO Auto-generated method stub
return user.getUsername();
}
Service class CustomUserDetailsService
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findByUsername(username);
CustomUserDetails userDetails = null;
if(user!=null) {
userDetails = new CustomUserDetails();
userDetails.setUser(user);
}else {
throw new UsernameNotFoundException("User not found with name "+username);
}
return userDetails;
}
}
I have another Controller class having different URL mapping which is running
WebSecurityConfigurerAdapter has a overloaded configure message that takes WebSecurity as argument which accepts ant matchers on requests to be ignored.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/hello");
}
You can ignore /hello based url as its for all users.
Actual:
return user.getRoles().stream().map(role->new SimpleGrantedAuthority("ROLE_"+role)).collect(Collectors.toList());
Expected:
return user.getRoles().stream().map(role->new SimpleGrantedAuthority("ROLE_"+role.getRole_name())).collect(Collectors.toList());

Wiring ClientRegistrationService with jdbc datasource

I could successfully set the jdbc datasource to Spring OAuth2 using the following configuration. However I am struggling to wire ClientRegistrationService while it was easy to wire ClientDetailsService.
#Configuration
#EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
.....
}
Here is what I tried
Below code fails to find the ClientDetailsService is not instanceof or of assignableFrom JdbcClientDetailsService or ClientRegistrationService
#Controller
public class ClientPortalApplication {
private ClientRegistrationService clientService;
#Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
if (clientDetailsService instanceof JdbcClientDetailsService)) {
clientService = (ClientRegistrationService) clientDetailsService;
}
}
......
}
Below code wiring fails on finding a bean of type ClientRegistrationService
:
#Controller
public class ClientPortalApplication {
#Autowired
private ClientRegistrationService clientService;
......
}
The ClientDetailsService created in yout AuthorizationServerConfigurerAdapter is not a bean therefore can't be injected. A solution is to create a bean JdbcClientDetailsService inject it in the AuthorizationServerConfigurerAdapter and you will be able to inject it anywhere else:
#Configuration
public class MyConfiguration {
#Autowired
private DataSource dataSource;
#Bean
public JdbcClientDetailsService jdbcClientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
#Configuration
#EnableAuthorizationServer
protected class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private JdbcClientDetailsService jdbcClientDetailsService;
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(jdbcClientDetailsService);
}
}
}

Resources