1. Let's start with some updates to the Permission and Strategy entities. The changes are highlighted in the code fragments below.
... @Override public boolean equals(Object o) { if (this == o) return true; if (o == null) return false; if (o instanceof Permission) { final Permission other = (Permission) o; return Objects.equal(getId(), other.getId()) && Objects.equal(getPermissionname(), other.getPermissionname()); } return false; } ...
... public class Strategy extends BaseEntity implements Serializable { private static final long serialVersionUID = 96285180113476324L; static Logger logger = LoggerFactory.getLogger(Strategy.class); @NotNull(message = "{error.strategy.type.null}") @NotEmpty(message = "{error.strategy.type.empty}") @Size(max = 50, message = "{error.strategy.type.max}") @Column(name = "TYPE", length = 50) private String type; @NotNull(message = "{error.strategy.name.null}") @NotEmpty(message = "{error.strategy.name.empty}") @Size(max = 50, message = "{error.strategy.name.max}") @Column(name = "NAME", length = 50) private String name; ...The defect in the first fragment (Permission.java) was related to an incorrect Object comparison, due to copy-paste. The second change (in Strategy.java) was to increase the field size in both the entity and database DDL.
2. In the DAO layer, I discovered some defects related to the update methods, specifically around an update creating a duplicate entry. Also, I've changed the getList methods on the DAOs to return sorted lists. The relevant updates are in the fragments below.
... @Override public void updateStrategy(Strategy strategy) throws StrategyNotFoundException, DuplicateStrategyException { Strategy strategyToUpdate = getStrategy(strategy.getId()); // iterated to see if this update is a duplicate List<Strategy> strategies = getStrategies(); for (Strategy singleStrategy : strategies) { if (singleStrategy.getType().equals(strategy.getType()) && singleStrategy.getName().equals(strategy.getName())) { String message = "The Strategy [" + singleStrategy.getName() + "] already exists in the system."; throw new DuplicateStrategyException(message); } } // no exception thrown, so it is not a duplicate strategyToUpdate.setName(strategy.getName()); strategyToUpdate.setType(strategy.getType()); getCurrentSession().update(strategyToUpdate); } ... @Override @SuppressWarnings("unchecked") public List<Strategy> getStrategies() { String hql = "FROM Strategy s ORDER BY s.id"; return getCurrentSession().createQuery(hql).list(); } ...
... @Override public void updateUser(User user) throws UserNotFoundException, DuplicateUserException { User userToUpdate = getUser(user.getId()); try { User userCheck = getUser(user.getUsername()); if (userCheck.getId() == userToUpdate.getId()) { userToUpdate.setEnabled(user.getEnabled()); userToUpdate.setPassword(user.getPassword()); userToUpdate.setUsername(user.getUsername()); userToUpdate.setRole(user.getRole()); getCurrentSession().update(userToUpdate); } else { String message = "The user [" + userCheck.getUsername() + "] already exists"; throw new DuplicateUserException(message); } } catch (UserNotFoundException e) { userToUpdate.setEnabled(user.getEnabled()); userToUpdate.setPassword(user.getPassword()); userToUpdate.setUsername(user.getUsername()); userToUpdate.setRole(user.getRole()); getCurrentSession().update(userToUpdate); } } ... @Override @SuppressWarnings("unchecked") public List<User> getUsers() { String hql = "FROM User u ORDER BY u.id"; return getCurrentSession().createQuery(hql).list(); } ...
... @Override public void updateRole(Role role) throws RoleNotFoundException, DuplicateRoleException { Role roleToUpdate = getRole(role.getId()); try { Role roleCheck = getRole(role.getRolename()); if (roleCheck.getId() == roleToUpdate.getId()) { roleToUpdate.setId(role.getId()); roleToUpdate.setRolename(role.getRolename()); } else { String message = "The role [" + roleCheck.getRolename() + "] already exists"; throw new DuplicateRoleException(message); } } catch (RoleNotFoundException e) { roleToUpdate.setId(role.getId()); roleToUpdate.setRolename(role.getRolename()); getCurrentSession().update(roleToUpdate); } } ... @Override @SuppressWarnings("unchecked") public List<Role> getRoles() { String hql = "FROM Role r ORDER BY r.id"; return getCurrentSession().createQuery(hql).list(); } ...
... @Override public void updatePermission(Permission permission) throws PermissionNotFoundException, DuplicatePermissionException { Permission permToUpdate = getPermission(permission.getId()); try { Permission permissionCheck = getPermission(permission.getPermissionname()); if (permToUpdate.getId() == permissionCheck.getId()) { permToUpdate.setId(permission.getId()); permToUpdate.setPermissionname(permission.getPermissionname()); permToUpdate.setPermRoles(permission.getPermRoles()); getCurrentSession().update(permToUpdate); } else { String message = "The permission [" + permissionCheck.getPermissionname() + "] already exists"; throw new DuplicatePermissionException(message); } } catch (PermissionNotFoundException e) { permToUpdate.setId(permission.getId()); permToUpdate.setPermissionname(permission.getPermissionname()); permToUpdate.setPermRoles(permission.getPermRoles()); getCurrentSession().update(permToUpdate); } } @Override @SuppressWarnings("unchecked") public List<Permission> getPermissions() { String hql = "FROM Permission p ORDER BY p.id"; return getCurrentSession().createQuery(hql).list(); } ...
3. Now that we're finished with the refactoring and defects, we will update the security configuration to allow access to the Role controller methods.
package com.dtr.oas.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ComponentScan; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; import org.springframework.security.core.userdetails.UserDetailsService; import com.dtr.oas.exception.AccessDeniedExceptionHandler; @Configuration @EnableWebMvcSecurity @ComponentScan(basePackageClasses=com.dtr.oas.service.UserServiceImpl.class) @EnableGlobalMethodSecurity(prePostEnabled=true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService); } @Autowired AccessDeniedExceptionHandler accessDeniedExceptionHandler; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/resources/**").permitAll() .antMatchers("/error/**").permitAll() .antMatchers("/strategy/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("ADMIN") .antMatchers("/role/**").hasRole("ADMIN") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/") .permitAll() .and() .logout() .permitAll() .and() .exceptionHandling() .accessDeniedHandler(accessDeniedExceptionHandler); } }
4. We're ready for the Role controller now. I won't discuss this controller, since this one should look pretty similar to the Strategy and User controllers that we created in past posts.
package com.dtr.oas.controller; import java.util.List; import java.util.Locale; import javax.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.dtr.oas.exception.DuplicateRoleException; import com.dtr.oas.exception.RoleNotFoundException; import com.dtr.oas.model.Role; import com.dtr.oas.service.RoleService; @Controller @RequestMapping(value = "/role") @PreAuthorize("denyAll") public class RoleController { static Logger logger = LoggerFactory.getLogger(RoleController.class); static String businessObject = "role"; //used in RedirectAttributes messages @Autowired private RoleService roleService; @Autowired private MessageSource messageSource; @RequestMapping(value = {"/", "/list"}, method = RequestMethod.GET) @PreAuthorize("hasRole('CTRL_ROLE_LIST_GET')") public String listOfRoles(Model model) { logger.debug("IN: Role/list-GET"); List<Role> roles = roleService.getRoles(); model.addAttribute("roles", roles); // if there was an error in /add, we do not want to overwrite // the existing role object containing the errors. if (!model.containsAttribute("role")) { logger.debug("Adding Role object to model"); Role role = new Role(); model.addAttribute("role", role); } return "role-list"; } @RequestMapping(value = "/add", method = RequestMethod.POST) @PreAuthorize("hasRole('CTRL_ROLE_ADD_POST')") public String addRole(@Valid @ModelAttribute Role role, BindingResult result, RedirectAttributes redirectAttrs) { logger.debug("IN: Role/add-POST"); if (result.hasErrors()) { logger.debug("Role-add error: " + result.toString()); redirectAttrs.addFlashAttribute("org.springframework.validation.BindingResult.role", result); redirectAttrs.addFlashAttribute("role", role); return "redirect:/role/list"; } else { try { roleService.addRole(role); String message = messageSource.getMessage("ctrl.message.success.add", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("message", message); return "redirect:/role/list"; } catch (DuplicateRoleException e) { String message = messageSource.getMessage("ctrl.message.error.duplicate", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("error", message); return "redirect:/role/list"; } } } @RequestMapping(value = "/edit", method = RequestMethod.GET) @PreAuthorize("hasRole('CTRL_ROLE_EDIT_GET')") public String editRolePage(@RequestParam(value = "id", required = true) Integer id, Model model, RedirectAttributes redirectAttrs) { logger.debug("IN: Role/edit-GET: ID to query = " + id); try { if (!model.containsAttribute("role")) { logger.debug("Adding Role object to model"); Role role = roleService.getRole(id); logger.debug("Role/edit-GET: " + role.toString()); model.addAttribute("role", role); } return "role-edit"; } catch (RoleNotFoundException e) { String message = messageSource.getMessage("ctrl.message.error.notfound", new Object[] {"role id", id}, Locale.US); model.addAttribute("error", message); return "redirect:/role/list"; } } @RequestMapping(value = "/edit", method = RequestMethod.POST) @PreAuthorize("hasRole('CTRL_ROLE_EDIT_POST')") public String editRole(@Valid @ModelAttribute Role role, BindingResult result, RedirectAttributes redirectAttrs, @RequestParam(value = "action", required = true) String action) { logger.debug("IN: Role/edit-POST: " + action); if (action.equals(messageSource.getMessage("button.action.cancel", null, Locale.US))) { String message = messageSource.getMessage("ctrl.message.success.cancel", new Object[] {"Edit", businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("message", message); } else if (result.hasErrors()) { logger.debug("Role-edit error: " + result.toString()); redirectAttrs.addFlashAttribute("org.springframework.validation.BindingResult.role", result); redirectAttrs.addFlashAttribute("role", role); return "redirect:/role/edit?id=" + role.getId(); } else if (action.equals(messageSource.getMessage("button.action.save", null, Locale.US))) { logger.debug("Role/edit-POST: " + role.toString()); try { roleService.updateRole(role); String message = messageSource.getMessage("ctrl.message.success.update", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("message", message); } catch (RoleNotFoundException snf) { String message = messageSource.getMessage("ctrl.message.error.notfound", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("error", message); return "redirect:/role/list"; } catch (DuplicateRoleException dse) { String message = messageSource.getMessage("ctrl.message.error.duplicate", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("error", message); return "redirect:/role/list"; } } return "redirect:/role/list"; } @RequestMapping(value = "/delete", method = RequestMethod.GET) @PreAuthorize("hasRole('CTRL_ROLE_DELETE_GET')") public String deleteRolePage( @RequestParam(value = "id", required = true) Integer id, @RequestParam(value = "phase", required = true) String phase, Model model, RedirectAttributes redirectAttrs) { Role role; String message; try { role = roleService.getRole(id); } catch (RoleNotFoundException e) { message = messageSource.getMessage("ctrl.message.error.notfound", new Object[] {"Role number", id}, Locale.US); redirectAttrs.addFlashAttribute("error", message); return "redirect:/role/list"; } logger.debug("IN: Role/delete-GET | id = " + id + " | phase = " + phase + " | " + role.toString()); if (phase.equals(messageSource.getMessage("button.action.cancel", null, Locale.US))) { message = messageSource.getMessage("ctrl.message.success.cancel", new Object[] {"Delete", businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("message", message); return "redirect:/role/list"; } else if (phase.equals(messageSource.getMessage("button.action.stage", null, Locale.US))) { model.addAttribute("role", role); return "role-delete"; } else if (phase.equals(messageSource.getMessage("button.action.delete", null, Locale.US))) { try { roleService.deleteRole(id); message = messageSource.getMessage("ctrl.message.success.delete", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("message", message); return "redirect:/role/list"; } catch (RoleNotFoundException e) { message = messageSource.getMessage("ctrl.message.error.notfound", new Object[] {businessObject, role.getRolename()}, Locale.US); redirectAttrs.addFlashAttribute("error", message); return "redirect:/role/list"; } } return "redirect:/role/list"; } }
In part two we will create the three Thymeleaf html pages that are needed for the Role CRUD functionality.
No comments:
Post a Comment