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