Home > Enterprise >  allow access to controller based on user's role. 403 error on all of them
allow access to controller based on user's role. 403 error on all of them

Time:10-28

I am trying to allow user with certain role to access a department controller of my Spring boot app. But getting a 403 error on all user roles. I know that I am missing something, but don't have any idea what. Here is what I have so far:

WebSecurityConfiguration:

package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import 

org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         @Qualifier("userDetailsServiceImpl")
            @Autowired
            private UserDetailsService userDetailsService;
        
         
         @Bean
            public BCryptPasswordEncoder bCryptPasswordEncoder() {
                return new BCryptPasswordEncoder();
            }
    
         @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .authorizeRequests()
                      
                    .antMatchers("/resources/**", "/registration").permitAll()
                    .antMatchers("/department/list").hasRole("ADMIN")
    
                    .anyRequest().authenticated()
                        .and()
                    .formLogin()
                        .loginPage("/login")
                        .permitAll()
                        .and()
                    .logout()
                        .permitAll();
            }
         
         @Bean
            public AuthenticationManager customAuthenticationManager() throws Exception {
                return authenticationManager();
            }
    
         @Autowired
            public void configureGlobal(AuthenticationManagerBuilder auth,AuthenticationManagerBuilder auth2) throws Exception {
                        
                    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
            }

}

My Users model is as follows

    package com.example.model;
    import javax.persistence.*;
    import java.util.Set;
    @Entity
    @Table(name = "users")

  
public class Users {
      @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
      private String username;
      private String password;
      @Transient
      private String passwordconfirm;
      
      @ManyToMany
        private Set<Roles> roles;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getpasswordconfirm() {
        return passwordconfirm;
    }

    public void setpasswordconfirm(String passwordconfirm) {
        this.passwordconfirm = passwordconfirm;
    }

    public Set<Roles> getRoles() {
        return roles;
    }

    public void setRoles(Set<Roles> roles) {
        this.roles = roles;
    }
      
      
}

And the roles model:

package com.example.model;
import javax.persistence.*;
import java.util.Set;

@Entity
@Table(name = "roles")
public class Roles {

     @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
        
        private String name;
        @ManyToMany(mappedBy = "roles")
        private Set<Users> users;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Set<Users> getUsers() {
            return users;
        }
        public void setUsers(Set<Users> users) {
            this.users = users;
        }
        
}

And here is my UsersRepository:

package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Users;
public interface UsersRepository extends JpaRepository<Users, Integer> {
    Users findByUsername(String username);

}

RolesRepository:

package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Roles;
public interface RolesRepository extends JpaRepository<Roles, Integer> {

}

My SecurityServiceImplementation is as follows:

package com.example.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

@Service
public class SecurityServiceImplementation implements SecurityService {
     @Autowired
        private AuthenticationManager authenticationManager;
     @Autowired
        private UserDetailsService userDetailsService;
        private static final Logger logger = 

LoggerFactory.getLogger(SecurityServiceImplementation.class);

        
        @Override
        public String findLoggedInUsername() {
            Object userDetails = 

SecurityContextHolder.getContext().getAuthentication().getDetails();

            if (userDetails instanceof UserDetails) {
                return ((UserDetails)userDetails).getUsername();
            }

            return null;
        }
        
        @Override
        public void autoLogin(String username, String password) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new 

UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());


            authenticationManager.authenticate(usernamePasswordAuthenticationToken);

            if (usernamePasswordAuthenticationToken.isAuthenticated()) {
            

SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

                logger.debug(String.format("Auto login %s successfully!", username));
            }
        }
}

And My userDetailsService is as follows

package com.example.services;
import com.example.model.Users;
import com.example.model.Roles;
import com.example.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.Set;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UsersRepository usersRepository;
    
     @Override
        @Transactional(readOnly = true)
        public UserDetails loadUserByUsername(String username) {
            Users user = usersRepository.findByUsername(username);
            if (user == null) throw new UsernameNotFoundException(username);

            Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
            for (Roles roles : user.getRoles()){
                grantedAuthorities.add(new SimpleGrantedAuthority(roles.getName()));
            }

            return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
        }
}

My UserServiceImplementation:

package com.example.services;
import com.example.model.Users;
import com.example.repository.UsersRepository;
import com.example.repository.RolesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashSet;

@Service
public class UsersServiceImplementation implements UsersService {
    @Autowired
    private UsersRepository usersRepository;
    @Autowired
    private RolesRepository rolesRepository;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public void save(Users user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        user.setRoles(new HashSet<>(rolesRepository.findAll()));
        usersRepository.save(user);
    }

    @Override
    public Users findByUsername(String username) {
        return usersRepository.findByUsername(username);
    }
}

Finaly my controller is as follows:

package com.example.controller;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.model.Users;
import com.example.services.SecurityService;
import com.example.services.UsersService;
import com.example.validators.UsersValidator;

import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@Controller

@SpringBootApplication

public class IndexController {

     @Autowired
        private UsersService usersService;

        @Autowired
        private SecurityService securityService;

        @Autowired
        private UsersValidator usersValidator;
    
        @GetMapping("/registration")
        public String registration(Model model) {
            model.addAttribute("userForm", new Users());

            return "registration";
        }
        
        @PostMapping("/registration")
        public String registration(@ModelAttribute("userForm") Users userForm, BindingResult 

bindingResult) {

            usersValidator.validate(userForm, bindingResult);

            if (bindingResult.hasErrors()) {
                return "registration";
            }

            usersService.save(userForm);

            securityService.autoLogin(userForm.getUsername(), userForm.getpasswordconfirm());

            return "redirect:/welcome";
        }
        
        @GetMapping("/login")
        public String login(Model model, String error, String logout) {
            if (error != null)
                model.addAttribute("error", "Имя пользователя или пароль не верн.");

            if (logout != null)
                model.addAttribute("message", "Вы успешно вышли из системыy.");

            return "login";
        }
        
        @GetMapping({"/", "/welcome"})
        public String welcome(Model model) {
            return "welcome";
        }
}

For authenticating users I am using MySQL tables users, roles and users_roles. Sory for alot of code in question, but I am scroed up and have no idea where to look.

Login.JSP if it will be helpful:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<c:set var="contextPath" value="${pageContext.request.contextPath}"/>

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="utf-8">
      <title>Вход</title>
 <link href="../../webjars/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />

 <script src="../../webjars/bootstrap/4.0.0/js/bootstrap.min.js"></script>
 <script src="../../webjars/jquery/3.0.0/js/jquery.min.js"></script>
  </head>

  <body>

    <div class="container">
      <form method="POST" action="${contextPath}/login" class="form-signin">
        <h2 class="form-heading">Вход</h2>

        <div class="form-group ${error != null ? 'has-error' : ''}">
            <span>${message}</span>
            <input name="username" type="text" class="form-control" placeholder="Логин"
                   autofocus="true"/>
            <input name="password" type="password" class="form-control" placeholder="Пароль"/>
            <span>${error}</span>
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

            <button class="btn btn-lg btn-primary btn-block" type="submit">Вход</button>
            <h4 class="text-center"><a href="${contextPath}/registration">Зарегистрироватся</a></h4>
        </div>
      </form>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
 
  </body>
</html>    

CodePudding user response:

if you look at hasRole method you see it will add a ROLE_ prefix to it:

private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    Assert.isTrue(!role.startsWith("ROLE_"), () -> {
        return "role should not start with 'ROLE_' since it is automatically inserted. Got '"   role   "'";
    });
    return "hasRole('ROLE_"   role   "')";
}

I suspect that you named your role like ADMIN or MANAGER and use them like that. I suggest try to rename your roles and add ROLE_ prefix to them like ROLE_ADMIN or ROLE_MANAGER and try again.

here make sure when you getName() your role name has a ROLE_ prefix like ROLE_ADMIN

for (Roles roles : user.getRoles()){
    grantedAuthorities.add(new SimpleGrantedAuthority(roles.getName()));

}
  • Related