I am developing a application for test the resources of the Spring Security, and in the current state of it, I need one solution to implement Roles AND Permissions for my methods. I already using this annotation:
@Secured("ROLE_ADMIN")
to define which role should be able to access each method. In my database, I have this structure:
which means for each Role I can have a list of permissions. Anyone can point me a solution for define both restrictions for each one of my methods? I am configuring the Spring Security via Java code, this way:
https://github.com/klebermo/webapp2/tree/master/src/com/spring/webapp/lojavirtual/config/security
UPDATE
Following the presented sugestions, I change my AuthenticationService (which extends UserDetailsService) to this:
@Service
public class AuthenticationService implements UserDetailsService {
@Autowired
private UsuarioHome accountDao;
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Usuario account = accountDao.findByField("login", username);
if(account==null) {
System.out.println("No such user: " + username);
throw new UsernameNotFoundException("No such user: " + username);
} else if (account.getAutorizacao().isEmpty()) {
System.out.println("User " + username + " has no authorities");
throw new UsernameNotFoundException("User " + username + " has no authorities");
}
List<Permission> lista = new ArrayList<Permission>();
for(int i=0; i<account.getAutorizacao().size(); i++) {
for(int j=0; j<account.getAutorizacao().get(i).getPermissao().size(); j++) {
lista.add(account.getAutorizacao().get(i).getPermissao().get(j));
}
}
boolean accountIsEnabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(account.getLogin(), account.getSenha(), accountIsEnabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(lista));
}
public List<String> getRolesAsList(List<Permission> list) {
List <String> rolesAsList = new ArrayList<String>();
for(Permission role : list){
rolesAsList.add(role.getNome());
}
return rolesAsList;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
public Collection<? extends GrantedAuthority> getAuthorities(List<Permission> list) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRolesAsList(list));
return authList;
}
and in my methods, I change to that:
@Controller
@RequestMapping(value="privado")
public class PrivadoController {
@RequestMapping(value="admin")
@Secured("admin_main")
public ModelAndView admin() {
ModelAndView mav = new ModelAndView();
mav.setViewName("privado/admin");
return mav;
}
@RequestMapping(value="customer")
@Secured("customer_main")
public ModelAndView customer() {
ModelAndView mav = new ModelAndView();
mav.setViewName("privado/customer");
return mav;
}
}
But now when I try acess the page, I get my no_permit page. what's wrong now?
UPDATE
after some changes, I finally get to this code:
AuthenticationService.java
@Service
public class AuthenticationService implements UserDetailsService {
@Autowired
private UsuarioHome accountDao;
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Usuario account = accountDao.findByField("login", username);
if(account==null) {
System.out.println("No such user: " + username);
throw new UsernameNotFoundException("No such user: " + username);
} else if (account.getAutorizacao().isEmpty()) {
System.out.println("User " + username + " has no authorities");
throw new UsernameNotFoundException("User " + username + " has no authorities");
}
List<Permission> lista = new ArrayList<Permission>();
int max = account.getAutorizacao().size();
for(int i=0; i<max; i++) {
for(int j=0; j<max; j++) {
lista.add(account.getAutorizacao().get(i).getPermissao().get(j));
}
}
boolean accountIsEnabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(account.getLogin(), account.getSenha(), accountIsEnabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(lista));
}
public List<String> getRolesAsList(List<Permission> list) {
List <String> rolesAsList = new ArrayList<String>();
for(Permission role : list){
rolesAsList.add(role.getNome());
}
return rolesAsList;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
public Collection<? extends GrantedAuthority> getAuthorities(List<Permission> list) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRolesAsList(list));
return authList;
}
}
In my controller, I try use either the annotation @Secured or @PreAuthorize, in this way:
@Controller
@RequestMapping(value="privado")
public class PrivadoController {
@RequestMapping(value="admin")
//@Secured("admin_main")
@PreAuthorize("hasRole('admin_main')")
public ModelAndView admin() {
ModelAndView mav = new ModelAndView();
mav.setViewName("privado/admin");
return mav;
}
@RequestMapping(value="customer")
//@Secured("customer_main")
@PreAuthorize("hasRole('customer_main')")
public ModelAndView customer() {
ModelAndView mav = new ModelAndView();
mav.setViewName("privado/customer");
return mav;
}
}
But I am not getting access to any user, despite informing the right credencials. What's wrong in this current scenario?
UPDATE 2
Ok, it happens the problem with the access denied was becasue an error in the code in my CustomAuthenticationSuccessHandler, which now it is like that:
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
HttpSession session = request.getSession();
SavedRequest savedReq = (SavedRequest) session.getAttribute(WebAttributes.ACCESS_DENIED_403);
boolean isAdmin = false;
boolean isUser = false;
if (savedReq == null) {
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
if(grantedAuthority.getAuthority().equals("admin_main"))
isAdmin = true;
else if(grantedAuthority.getAuthority().equals("customer_main"))
isUser = true;
}
if(isAdmin)
response.sendRedirect(request.getContextPath() + "/privado/admin");
else if(isUser)
response.sendRedirect(request.getContextPath() + "/privado/customer");
else
response.sendRedirect(request.getContextPath() + "/erro/no_permit");
}
else {
response.sendRedirect(savedReq.getRedirectUrl());
}
}
}
But now when I try login in my appliation, I get the error described in this topic:
Any ideas in how to solve this one?