Skip to content

Commit

Permalink
SHIBUI-1844
Browse files Browse the repository at this point in the history
Added controller for roles
  • Loading branch information
chasegawa committed Jul 14, 2021
1 parent 42792ca commit 2b0511f
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.exception;

public class EntityNotFoundException extends Exception {
public EntityNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package edu.internet2.tier.shibboleth.admin.ui.security.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleDeleteException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role;
import edu.internet2.tier.shibboleth.admin.ui.security.service.IRolesService;

@RestController
@RequestMapping("/api/admin/roles")
public class RolesController {
@Autowired
private IRolesService rolesService;

@Secured("ROLE_ADMIN")
@PostMapping
@Transactional
public ResponseEntity<?> create(@RequestBody Role role) throws RoleExistsConflictException {
Role result = rolesService.createRole(role);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

@Secured("ROLE_ADMIN")
@DeleteMapping("/{resourceId}")
@Transactional
public ResponseEntity<?> delete(@PathVariable String resourceId) throws EntityNotFoundException, RoleDeleteException {
rolesService.deleteDefinition(resourceId);
return ResponseEntity.noContent().build();
}

@GetMapping
@Transactional(readOnly = true)
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(rolesService.findAll());
}

@GetMapping("/{resourceId}")
@Transactional(readOnly = true)
public ResponseEntity<?> getOne(@PathVariable String resourceId) throws EntityNotFoundException {
Role role = rolesService.findByResourceId(resourceId);
return ResponseEntity.ok(role);
}

@Secured("ROLE_ADMIN")
@PutMapping
@Transactional
public ResponseEntity<?> update(@RequestBody Role role) throws EntityNotFoundException {
Role result = rolesService.updateRole(role);
return ResponseEntity.ok(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.internet2.tier.shibboleth.admin.ui.security.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleDeleteException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleExistsConflictException;

@ControllerAdvice(assignableTypes = {RolesController.class})
public class RolesExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler({ EntityNotFoundException.class })
public ResponseEntity<?> handleEntityNotFoundException(EntityNotFoundException e, WebRequest request) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage()));
}

@ExceptionHandler({ RoleDeleteException.class })
public ResponseEntity<?> handleForbiddenAccess(RoleDeleteException e, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/role/{resourceId}").build().toUri());
return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()), e.getMessage()));

}

@ExceptionHandler({RoleExistsConflictException.class})
public ResponseEntity<?> handleRoleExistsConflictException(RoleExistsConflictException e, WebRequest request) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(new ErrorResponse(HttpStatus.CONFLICT, e.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.security.exception;

public class RoleDeleteException extends Exception {
public RoleDeleteException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package edu.internet2.tier.shibboleth.admin.ui.security.exception;

public class RoleExistsConflictException extends Exception {

public RoleExistsConflictException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
package edu.internet2.tier.shibboleth.admin.ui.security.model;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import java.util.HashSet;
import java.util.Set;

/**
* Models a basic administrative role concept in the system.
*
Expand All @@ -29,24 +31,27 @@
@ToString(exclude = "users")
public class Role extends AbstractAuditable {

public Role(String name) {
this.name = name;
}

public Role(String name, int rank) {
this.name = name;
this.rank = rank;
}

@Column(unique = true)
private String name;

@Column(name = "ROLE_RANK")
private int rank;

@Column(name = "resource_id")
String resourceId = UUID.randomUUID().toString();

//Ignore properties annotation here is to prevent stack overflow recursive error during JSON serialization
@JsonIgnoreProperties("roles")
@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
private Set<User> users = new HashSet<>();

public Role(String name) {
this.name = name;
}

public Role(String name, int rank) {
this.name = name;
this.rank = rank;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
*/
public interface RoleRepository extends JpaRepository<Role, Long> {

void deleteByResourceId(String resourceId);

Optional<Role> findByName(final String name);

Optional<Role> findByResourceId(String resourceId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.List;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleDeleteException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role;

public interface IRolesService {

Role createRole(Role role) throws RoleExistsConflictException;

Role updateRole(Role role) throws EntityNotFoundException;

List<Role> findAll();

Role findByResourceId(String resourceId) throws EntityNotFoundException;

void deleteDefinition(String resourceId) throws EntityNotFoundException, RoleDeleteException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleDeleteException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role;
import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository;

@Service
public class RolesServiceImpl implements IRolesService {
@Autowired
private RoleRepository roleRepository;

@Override
public Role createRole(Role role) throws RoleExistsConflictException {
Optional<Role> found = roleRepository.findByName(role.getName());
// If already defined, we don't want to create a new one, nor do we want this call update the definition
if (found.isPresent()) {
throw new RoleExistsConflictException(
String.format("Call update (PUT) to modify the role with name: [%s]", role.getName()));
}
return roleRepository.save(role);
}

@Override
public void deleteDefinition(String resourceId) throws EntityNotFoundException, RoleDeleteException {
Optional<Role> found = roleRepository.findByResourceId(resourceId);
if (found.isPresent() && !found.get().getUsers().isEmpty()) {
throw new RoleDeleteException(String.format("Unable to delete role with resource id: [%s] - remove role from all users first", resourceId));
}
roleRepository.deleteByResourceId(resourceId);
}

@Override
public List<Role> findAll() {
return roleRepository.findAll();
}

@Override
public Role findByResourceId(String resourceId) throws EntityNotFoundException {
Optional<Role> found = roleRepository.findByResourceId(resourceId);
if (found.isEmpty()) {
throw new EntityNotFoundException(String.format("Unable to find role with resource id: [%s]", resourceId));
}
return found.get();
}

@Override
public Role updateRole(Role role) throws EntityNotFoundException {
Optional<Role> found = roleRepository.findByName(role.getName());
if (found.isEmpty()) {
throw new EntityNotFoundException(String.format("Unable to find role with name: [%s]", role.getName()));
}
return roleRepository.save(role);
}
}

0 comments on commit 2b0511f

Please sign in to comment.