Problem in Spring Security

 avatar
unknown
java
5 hours ago
6.1 kB
16
Indexable
// trying to implement basic username-password authentication in spring.. no JWT yet


// application flow, as per my understanding: -  FilterChain => AuthenticaionManager (ProviderManager) => accesses AuthenticationProvider (in my case, its DaoAuthenticationProvider) => accesses UserDetailsService (in this case, JdbcUserDetailsService) => accesses DataSource to connect to DB 

// conclusion reached by me: Create custom UserDetailsService, create custom User model; tell spring security to use these custom ones instead of its default values


// 1. Created CustomUserDetailsService and its implemmentation

// CustomUserDetailsService.java
@Service
public interface CustomUserDetailsService extends UserDetailsService{
	
	public String create(String username, String password, String email);

}

// CustomUserDetailsServiceImpl.java
@Component
public class CustomUserDetailsService implements CustomUserDetailsService {

	@Autowired
	private CustomUserRepository userRepo;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		return userRepo.findByUsername(username);
	}

	public String create(String username, String password, String email) {
		// Encodes the password and creates a new User object
		CustomUser u = new CustomUser(username, new BCryptPasswordEncoder().encode(password), email);
		u.setRole(List.of("USER"));

		// Saves the new user to the database
        userRepo.save(u);

		return "Create Successfully !";

	}
}



// CustomUserRepository.java
public interface CustomUserRepository extends JpaRepository<CustomUser, Long> {
	
	public UserDetails findByUsername(String username);

}


// 2. Created Custom User model


// CustomUser.java

@Entity
public class CustomUser implements UserDetails {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long id;
	private String username;
	private String email;
	private String password;
	private List<String> role;
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		 return role.stream()
		            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
		            .collect(Collectors.toList());
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return null;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}

	public List<String> getRole() {
		return role;
	}


	public void setRole(List<String> role) {
		this.role = role;
	}


	public CustomUser() {
		super();
		// TODO Auto-generated constructor stub
	}

	public CustomUser(long id, String username, String email) {
		super();
		this.id = id;
		this.username = username;
		this.email = email;
	}

	public CustomUser(String username, String email, String password) {
		super();
		this.username = username;
		this.email = email;
		this.password = password;
	}

	
}




// 3. Telling Spring Security to use these custom objects instead of its own default config

// WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
	
	@Autowired
	private CustomUserService customUserService;
	
	@Value("${spring.datasource.driver-class-name}")
	public String databaseDriverClassName;

	@Value("${spring.datasource.url}")
	public String databaseUrlName;

	@Value("${spring.datasource.username}")
	public String databaseUsername;

	@Value("${spring.datasource.password}")
	public String databasePassword;
	
	
//	1. custom security filter chain for authorization and authentication paths
	
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
		return httpSecurity
				.csrf(csrf -> csrf.disable())
				.authorizeHttpRequests(auth -> auth
						.requestMatchers("/unauth/*").permitAll()
						.requestMatchers("/login/").permitAll()
						.anyRequest().denyAll()
						)
				.httpBasic(Customizer.withDefaults())
				.build();
		
	}
	
	
//	2. setup datasource to connect to database	--> This is causing problem (the circular dependency error I mentioned)
//	@Bean
//	public DriverManagerDataSource dataSource() {
//		DriverManagerDataSource dataSource = new DriverManagerDataSource();
//		dataSource.setDriverClassName(databaseDriverClassName);
//		dataSource.setUrl(databaseUrlName);
//		dataSource.setUsername(databaseUsername);
//		dataSource.setPassword(databasePassword);
//		System.out.println("datasource initialized");
//		return dataSource;
//	}

	
}


// Here is complete error log

// Description:

// The dependencies of some of the beans in the application context form a cycle:

//    entityManagerFactory defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
// ┌─────┐
// |  dataSourceScriptDatabaseInitializer defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]
// ↑     ↓
// |  webSecurityConfig (field private com.sample.springsecurity.service.CustomUserDetailsService com.sample.springsecurity.config.WebSecurityConfig.customUserDetailsService)
// ↑     ↓
// |  customUserDetailsServiceImpl (field private com.sample.springsecurity.repository.CustomUserRepository com.sample.springsecurity.serviceImpl.CustomUserDetailsServiceImpl.userRepo)
// ↑     ↓
// |  customUserRepository defined in com.sample.springsecurity.repository.CustomUserRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
// ↑     ↓
// |  jpaSharedEM_entityManagerFactory
// └─────┘


// Action:

// Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.





// What I cannot understand -> Where exactly is spring injecting this datasource bean? from what I have understood, it should only be injecting it inside the 

Editor is loading...
Leave a Comment