User Authorization with custom roles - spring

My database is a table with Users with {Username, Password, Role}. This role can either be Administrator or student.
I want my security Config file to permit some pages for students while others are only for administrators. For now this SecurityConfig looks like this...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/reservation").hasRole("administrator")
.antMatchers("/api/reservation/**").hasRole("student")
.antMatchers("/api/rooms/**")
.permitAll()
.antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**")
.permitAll()
.anyRequest()
.authenticated();
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
I think you also need my UserDetailsImplementation in order to help:
#Service
#AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepo userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
Optional<User> userOptional = userRepository.findByUsername(username);
User user = userOptional.orElseThrow(() -> new UsernameNotFoundException("No user " + "Found with username : " + username));
String rol = "";
if (user.getRole().equals("administrator")) {
rol = "ADMIN";
}
else if (user.getRole().equals("student")) {
rol = "STUDENT";
}
return new org.springframework.security
.core.userdetails.User(user.getUsername(), user.getPassword(),
user.isEnabled(), true, true,
true, getAuthorities(rol));
}
private Collection<? extends GrantedAuthority> getAuthorities(String role) {
return singletonList(new SimpleGrantedAuthority(role));
}
}
I already tried the SecurityConfig with .hasRole("student"), etc. But it didn't work.
I found this old project of mine that worked with a inMemory DB and used this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// users worden hier gedefined
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("t")).roles("USER")
.and()
.withUser("admin").password(encoder.encode("t")).roles("ADMIN", "USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// welke httprequests afgeschermd moeten worden
http
.authorizeRequests()
// hier patronen definieren die moeten matchen
.antMatchers("/").hasRole("USER")
.antMatchers("/maincontroller/add-bus").hasRole("ADMIN")
.antMatchers("/maincontroller/add-team").hasRole("ADMIN")
.antMatchers("/maincontroller/add-speler").hasRole("ADMIN")
.antMatchers("/maincontroller/add-wedstrijd").hasRole("ADMIN")
.antMatchers("/maincontroller/update-bus/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-team/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-speler/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-wedstrijd/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-bus/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-team/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-speler/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-wedstrijd/*").hasRole("ADMIN")
.antMatchers("/maincontroller/*").hasRole("USER")
.antMatchers("/api/**").permitAll()
So to summarize my problem: I would like to link the roles in my database with the hasRole() function in my securityConfig.
Thanks in advance!

Related

Spring Security password fails verification

I was following Spring Security articles:
[Spring Security without WebSecurityConfigurerAdapter]: https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
[Spring Security Blog]: http://staging5.baeldung.com/spring-deprecated-websecurityconfigureradapter
and I keep getting the error:
o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since password does not match stored value
Below is my SecurityConfig class:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,
jsr250Enabled=true)
public class WebSecurityConfig {
private static final String ROLE_ADMIN_USER = "ADMIN_USER";
private static final String ROLE_POWER_USER = "POWER_USER";
private static final String ROLE_GUEST_USER = "GUEST_USER";
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder().encode("user1abc"))
.roles(ROLE_ADMIN_USER).build();
UserDetails user2 = User.withUsername("user2")
.password(passwordEncoder().encode("user2abc"))
.roles(ROLE_POWER_USER).build();
UserDetails user3 = User.withUsername("user3")
.password(passwordEncoder().encode("user3abc"))
.roles(ROLE_GUEST_USER).build();
return new InMemoryUserDetailsManager(user1, user2, user3);
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/index").hasAnyRole(ROLE_ADMIN_USER, ROLE_POWER_USER, ROLE_GUEST_USER)
.antMatchers("/inventory").hasAnyRole(ROLE_ADMIN_USER, ROLE_POWER_USER)
.antMatchers("/guest").hasAnyRole(ROLE_GUEST_USER)
.antMatchers("/login*").permitAll()
.antMatchers("/doLogin").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/index", true)
.successHandler(new AuthenticationSuccessHandler() {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("--- Login successful ---");
}
})
.failureUrl("/login");
return http.build();
}

Spring-boot Spring Security; Users without the correct roles are still accessing role-specific pages

I am attempting to make a web page that is only accessible by the 'Admin' role, however all users are able to access it. I have User and Role entities with a functioning ManyToMany relationship set up.
Here is my SecurityConfig.java:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/registration",
"/js/**",
"/css/**",
"/img/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/competition/**").hasRole("Admin")
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
as you can see with the line
.antMatchers("/competition/**").hasRole("Admin")
I'm trying to make link /competition/** admin-only.
Here is the controller:
#Controller
public class CompetitionController {
#Autowired
CompetitionRepository competitionRepository;
#GetMapping("/competition/{competitors}")
public String match(ModelMap map, #PathVariable(value = "competitors") String competitors, Principal principal) {
String[] parts = competitors.split("-");
String part1 = parts[0];
String part2 = parts[1];
map.addAttribute("part1", part1);
map.addAttribute("part2", part2);
return "match";
}
}
Finally here is my UserService:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if (user == null){
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles()));
}
public User findByEmail(String email){
return userRepository.findByEmail(email);
}
public User save(UserRegistrationDto registration){
User user = new User();
user.setFirstName(registration.getFirstName());
user.setLastName(registration.getLastName());
user.setEmail(registration.getEmail());
user.setPassword(passwordEncoder.encode(registration.getPassword()));
user.setRoles(Arrays.asList(new Role("ROLE_USER")));
User userAdmin = userRepository.findByEmail("admin#email.com");
if (userAdmin == null){
userAdmin = new User();
userAdmin.setFirstName("Admin");
userAdmin.setLastName("");
userAdmin.setEmail("admin#email.com");
userAdmin.setPassword(passwordEncoder.encode("admin"));
userAdmin.setRoles(Arrays.asList(new Role("ROLE_Admin")));
userRepository.save(userAdmin);
}
return userRepository.save(user);
}
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles){
return roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
I attempted to change .hasRole to .hasAuthority as seen in this answer (to no avail): Spring Security Java configuration for authenticated users with a role.

How to change intercept url in Spring Security without having to re-deploy the application?

I'm currently trying to build a database UI implementing spring security, but i'm stuck on how to change the intercept url access from access=hasRole('ROLE_ADMIN') to access=denyAll and deny any user from accessing that particular page without having me to logout.
this is my WebSecurityConfig class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Value("${users-by-username-query}")
private String usersQuery;
#Value("${authorities-by-username-query}")
private String authoritiesQuery;
#Autowired
private MyAuthenticationHandler myAuthenticationHandler;
private CustomAccessDecisionManager customAccessDecisionManager;
#Autowired
private Service service;
#Override
protected void configure(HttpSecurity http) throws Exception {
List<UrlRole> viewPermissions = service.findAllUrlRole();
System.out.println("Return from service class with size "+viewPermissions.size());
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http
// .authorizeRequests().antMatchers("/","/hello.html","/footer.jsp","/header.jsp","/sidebar.jsp","/reg_issuer.jsp","/reg_user.jsp","/rest/**","/IssuerList.jsp","/loginSecurity","/index.jsp","/verify_otp.jsp")
.authorizeRequests().antMatchers("/","/rest/**")
.permitAll();
for (int i = 0;i<viewPermissions.size();i++) {
String url = viewPermissions.get(i).getUrl();
String string = "";
if(viewPermissions.get(i).getRole().equalsIgnoreCase("denyAll")){
string = viewPermissions.get(i).getRole();
}else{
string = "hasRole('"+viewPermissions.get(i).getRole()+"')";
for (int j = 0;j<viewPermissions.size();j++) {
if(j!=i && viewPermissions.get(j).getUrl().equalsIgnoreCase(url) ){
string+=" or hasRole('"+viewPermissions.get(j).getRole()+"')";
}
}
}
interceptUrlRegistry.antMatchers(viewPermissions.get(i).getUrl()).access(string);
}
interceptUrlRegistry.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").successHandler(myAuthenticationHandler)
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/403");
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(authoritiesQuery);
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/assets/**");
}
}
Currently i am looping the "antMatchers(viewPermissions.get(i).getUrl()).access(string)" to get the url and roles from database but it only been done when the first time i deploy it in wildfly. That is why the new access for url will not be implemented unless i restart the wildfly server.
Is there anyway to implement it without having to restart the server?
THE ANSWERED I GOT AND WORKS FOR ME IS AS BELOW.
this is my new WebSecurityConfig class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Value("${users-by-username-query}")
private String usersQuery;
#Value("${authorities-by-username-query}")
private String authoritiesQuery;
#Autowired
private MyAuthenticationHandler myAuthenticationHandler;
#Autowired
private Service service;
#Override
protected void configure(HttpSecurity http) throws Exception {
List<UrlRole> viewPermissions = service.findAllUrlRole();
System.out.println("Return from service class with size "+viewPermissions.size());
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http
.authorizeRequests().antMatchers("/rest/**")
.permitAll();
interceptUrlRegistry.antMatchers("/login").access("hasRole('ROLE_ANONYMOUS')");
interceptUrlRegistry.anyRequest().authenticated().accessDecisionManager(accessDecisionManager())
.and()
.formLogin()
.loginPage("/login").successHandler(myAuthenticationHandler)
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/403");
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(authoritiesQuery);
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/assets/**","/rest/findAllUrlRole","/error","/403","/404","/500");
}
#SuppressWarnings("unchecked")
#Bean
public AccessDecisionManager accessDecisionManager() {
System.out.println("Arrive AccessDecisionManager");
List<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(),
new RoleVoter(),
new AuthenticatedVoter(),
new MinuteBasedVoter());
System.out.println("End of AccessDecisionManager: "+ decisionVoters);
return new UnanimousBased(decisionVoters);
}
}
this is my MinuteBasedVoter class:
#SuppressWarnings("rawtypes")
public class MinuteBasedVoter implements AccessDecisionVoter {
#Override
public int vote(
Authentication authentication, Object object, Collection collection) {
WebServiceTester a = new WebServiceTester();
String username = authentication.getName(); //to get current user role
String url = ((FilterInvocation) object).getRequestUrl(); // to get current url
boolean NONanonymous = true;
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
if(grantedAuthority.getAuthority().equalsIgnoreCase("ROLE_ANONYMOUS")){
NONanonymous = false;
}
}
int vote = ACCESS_ABSTAIN;
boolean NONexist = true;
if(NONanonymous){
List<Role> roles = new ArrayList<Role>();
Role role = new Role();
vote = ACCESS_DENIED;
try{
List<UrlRole> urlroles = a.findAllUrlRole(); // to get all url and its respective role
// below is how i match the role of current user and the role that can access the current url
for(int i = 0; i<urlroles.size();i++){
if(url.startsWith(urlroles.get(i).getUrl())){
NONexist = false;
System.out.println("URL: "+url+" , Role: "+urlroles.get(i).getRole());
role.setRole(urlroles.get(i).getRole());
roles.add(role);
for (GrantedAuthority grantedAuthority : authorities) {
if(grantedAuthority.getAuthority().equalsIgnoreCase(urlroles.get(i).getRole())){
vote = ACCESS_GRANTED;
}
}
}
}
}catch(Exception e){
System.out.println("Error at MinuteBasedVoter: "+e);
}
if(NONexist){
vote = ACCESS_GRANTED;
}
}
return vote;
}
#Override
public boolean supports(ConfigAttribute attribute) {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean supports(Class clazz) {
// TODO Auto-generated method stub
return true;
}
}
i got this solution from http://www.baeldung.com/spring-security-custom-voter but with a twist of my own.

spring security - role based access

I have implemented spring security for my webapp.
I want to configure role based access. Only users with the role "ROLE_ADMIN" should be abeĺe to login.
I added the model "Role" and added a table in my database.
However users with the role "ROLE_USER" are still able to login.
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**").hasRole("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks!
Edit: complete spring security config
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = UserDetailsServiceImpl.class)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/css/**", "/js/**");
}
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
} catch (Exception e) {
e.printStackTrace();
}
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authProvider;
}
#Autowired
public void globalSecurityConfiguration(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Are you extending WebMvcConfigurerAdapter ? Also hasRole will prefix the provided string with "ROLE_"
from doc:
the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as this is automatically inserted.
example:
#SpringBootApplication
public class SampleWebSecureJdbcApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(SampleWebSecureJdbcApplication.class).run(args);
}
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource);
}
}
}
I have implemented a Role based access where after the login admin user will be directed to the admin homepage and normal user will be redirected to the user homepage.
Below is my SecurityConfiguration class.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
final String sqlUserName = "select email, password, active from user where email=?";
final String sqlAuthorities= "select u.email, r.role from user u inner join user_role ur on(u.user_id=ur.user_id) inner join role r on(ur.role_id=r.role_id) where u.email=?";
auth.
jdbcAuthentication()
.usersByUsernameQuery(sqlUserName)
.authoritiesByUsernameQuery(sqlAuthorities)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http. authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/resources/**", "/static/**", "/static.css/**", "/js/**", "/static.images/**").permitAll()
.antMatchers("/user").hasAuthority("USER")
.antMatchers("/home").hasAuthority("ADMIN").anyRequest()
.authenticated().and().csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/loginroute",true)
.usernameParameter("email")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/static.css/**", "/js/**", "/static.images/**");
}
}
.defaultSuccessUrl("/loginroute",true) will redirect to the /loginroute controller. Below is the controller methods.
#RequestMapping (value = "/loginroute",method = RequestMethod.GET)
public String sample(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
String rolevalue = null;
for (Role role : user.getRoles()) {
rolevalue = role.getRole();
}
System.out.println(user.getRoles().contains("role"));
if(rolevalue.equals("ADMIN"))
return "redirect:home";
else if(rolevalue.equals("USER"))
return "redirect:user";
return "User does not have permission";
}
#RequestMapping(value="/home", method = RequestMethod.GET)
public ModelAndView home(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("userName", "Welcome " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
modelAndView.addObject("adminMessage","Content Available Only for Users with Admin Role");
modelAndView.setViewName("home");
return modelAndView;
}
#RequestMapping(value="/user", method = RequestMethod.GET)
public ModelAndView userhome(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("userName", "Welcome user: " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
modelAndView.addObject("userMessage","Content Available Only for Users with User Role");
modelAndView.setViewName("user");
return modelAndView;
}

Spring injection of userdetailsservice in security config class fails

I am new to spring security and i am trying to configure it using java but when i try to inject a UserDetailsService into a security config class i get a 404 error page but when i inject it into a controller the injection works. am using spring version 4.1.6 and spring security 4.0.0
here is my security config class
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("loginService")
UserDetailsService loginService; //THIS IS THE POINT OF FAILURE
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/userlist")
.failureUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/*auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");*/
auth.userDetailsService(loginService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Bean
public Md5PasswordEncoder passwordEncoder(){
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
}
This is the UserDetailsService class
#Service("loginService")
public class LoginService implements UserDetailsService{
#Autowired
UserRepository userRepository;
#Transactional
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SiteUser user = userRepository.findByUsername(username);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
User u = null;
if(user == null)
throw new UsernameNotFoundException("No such User: " + username);
else
{
if (user.getRole().equals("USER"))
authorities.add(userAuthority);
else if (user.getRole().equals("ADMIN"))
{
authorities.add(userAuthority);
authorities.add(adminAuthority);
}
u = new User(user.getUsername(), user.getPassword(), authorities);
}
return u;
}
}
The rest of the project is available
here
The solution was to add
#ComponentScan("com.ashken.*")
on top of the securityconfig class
I've found that it is less troublesome to simply register your implementation of UserDetailsService as a bean in SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserRepository userRepository;
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
#Transactional
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SiteUser user = userRepository.findByUsername(username);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
User u = null;
if(user == null) {
throw new UsernameNotFoundException("No such User: " + username);
} else {
if (user.getRole().equals("USER")) {
authorities.add(userAuthority);
} else if (user.getRole().equals("ADMIN")) {
authorities.add(userAuthority);
authorities.add(adminAuthority);
}
u = new User(user.getUsername(), user.getPassword(), authorities);
}
return u;
}
};
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/userlist")
.failureUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/*auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");*/
auth.userDetailsService(loginService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Bean
public Md5PasswordEncoder passwordEncoder(){
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
}

Resources