From 4aad65cea1918e94f632ac76e6dbffc26f36ebda Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Fri, 18 Jan 2019 16:25:34 -0700 Subject: [PATCH] [SHIBUI-1058] Added permissions checking. Unit tests/fixes forthcoming. --- .../EntityDescriptorController.java | 107 +++++++++++++----- .../admin/ui/controller/ErrorResponse.java | 6 + .../EntityDescriptorRepository.java | 1 + 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java index c3e76983e..f274dd871 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java @@ -4,7 +4,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation; import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; +import edu.internet2.tier.shibboleth.admin.ui.security.model.User; +import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService; +import org.apache.commons.lang.StringUtils; import org.opensaml.core.xml.io.MarshallingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +30,8 @@ import javax.annotation.PostConstruct; import java.net.URI; +import java.security.Principal; +import java.util.Optional; import java.util.stream.Collectors; @RestController @@ -45,6 +50,9 @@ public class EntityDescriptorController { @Autowired RestTemplateBuilder restTemplateBuilder; + @Autowired + private UserRepository userRepository; + private RestTemplate restTemplate; private static Logger LOGGER = LoggerFactory.getLogger(EntityDescriptorController.class); @@ -91,57 +99,87 @@ public ResponseEntity upload(@RequestParam String metadataUrl, @RequestParam } @PutMapping("/EntityDescriptor/{resourceId}") - public ResponseEntity update(@RequestBody EntityDescriptorRepresentation edRepresentation, @PathVariable String resourceId) { + public ResponseEntity update(Principal principal, @RequestBody EntityDescriptorRepresentation edRepresentation, @PathVariable String resourceId) { + User currentUser = getUserFromPrincipal(principal); EntityDescriptor existingEd = entityDescriptorRepository.findByResourceId(resourceId); if (existingEd == null) { return ResponseEntity.notFound().build(); + } else { + if (currentUser.getRole().equals("ROLE_ADMIN") || currentUser.getUsername().equals(existingEd.getCreatedBy())) { + // Verify we're the only one attempting to update the EntityDescriptor + if (edRepresentation.getVersion() != existingEd.hashCode()) { + return new ResponseEntity(HttpStatus.CONFLICT); + } + + EntityDescriptor updatedEd = + EntityDescriptor.class.cast(entityDescriptorService.createDescriptorFromRepresentation(edRepresentation)); + + updatedEd.setAudId(existingEd.getAudId()); + updatedEd.setResourceId(existingEd.getResourceId()); + updatedEd.setCreatedDate(existingEd.getCreatedDate()); + + updatedEd = entityDescriptorRepository.save(updatedEd); + + return ResponseEntity.ok().body(entityDescriptorService.createRepresentationFromDescriptor(updatedEd)); + } else { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, + "You are not authorized to perform the requested operation.")); + } } - - // Verify we're the only one attempting to update the EntityDescriptor - if (edRepresentation.getVersion() != existingEd.hashCode()) { - return new ResponseEntity(HttpStatus.CONFLICT); - } - - EntityDescriptor updatedEd = - EntityDescriptor.class.cast(entityDescriptorService.createDescriptorFromRepresentation(edRepresentation)); - - updatedEd.setAudId(existingEd.getAudId()); - updatedEd.setResourceId(existingEd.getResourceId()); - updatedEd.setCreatedDate(existingEd.getCreatedDate()); - - updatedEd = entityDescriptorRepository.save(updatedEd); - - return ResponseEntity.ok().body(entityDescriptorService.createRepresentationFromDescriptor(updatedEd)); } @GetMapping("/EntityDescriptors") @Transactional(readOnly = true) - public Iterable getAll() { - return entityDescriptorRepository.findAllByCustomQueryAndStream() - .map(ed -> entityDescriptorService.createRepresentationFromDescriptor(ed)) - .collect(Collectors.toList()); + public ResponseEntity getAll(Principal principal) { + User currentUser = getUserFromPrincipal(principal); + if (currentUser != null) { + if (currentUser.getRole().equals("ROLE_ADMIN")) { + return ResponseEntity.ok(entityDescriptorRepository.findAllByCustomQueryAndStream() + .map(ed -> entityDescriptorService.createRepresentationFromDescriptor(ed)) + .collect(Collectors.toList())); + } else { + return ResponseEntity.ok(entityDescriptorRepository.findAllByCreatedBy(currentUser.getUsername()) + .map(ed -> entityDescriptorService.createRepresentationFromDescriptor(ed)) + .collect(Collectors.toList())); + } + } else { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, + "You are not authorized to perform the requested operation.")); + } } @GetMapping("/EntityDescriptor/{resourceId}") - public ResponseEntity getOne(@PathVariable String resourceId) { + public ResponseEntity getOne(Principal principal, @PathVariable String resourceId) { + User currentUser = getUserFromPrincipal(principal); EntityDescriptor ed = entityDescriptorRepository.findByResourceId(resourceId); if (ed == null) { return ResponseEntity.notFound().build(); + } else { + if (currentUser != null && (currentUser.getRole().equals("ROLE_ADMIN") || currentUser.getUsername().equals(ed.getCreatedBy()))) { + EntityDescriptorRepresentation edr = entityDescriptorService.createRepresentationFromDescriptor(ed); + return ResponseEntity.ok(edr); + } else { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, + "You are not authorized to perform the requested operation.")); + } } - EntityDescriptorRepresentation edr = entityDescriptorService.createRepresentationFromDescriptor(ed); - - return ResponseEntity.ok(edr); } @GetMapping(value = "/EntityDescriptor/{resourceId}", produces = "application/xml") - public ResponseEntity getOneXml(@PathVariable String resourceId) throws MarshallingException { + public ResponseEntity getOneXml(Principal principal, @PathVariable String resourceId) throws MarshallingException { + User currentUser = getUserFromPrincipal(principal); EntityDescriptor ed = entityDescriptorRepository.findByResourceId(resourceId); if (ed == null) { return ResponseEntity.notFound().build(); + } else { + if (currentUser != null && (currentUser.getRole().equals("ROLE_ADMIN") || currentUser.getUsername().equals(ed.getCreatedBy()))) { + final String xml = this.openSamlObjects.marshalToXmlString(ed); + return ResponseEntity.ok(xml); + } else { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, + "You are not authorized to perform the requested operation.")); + } } - final String xml = this.openSamlObjects.marshalToXmlString(ed); - - return ResponseEntity.ok(xml); } private static URI getResourceUriFor(EntityDescriptor ed) { @@ -179,4 +217,15 @@ private ResponseEntity handleUploadingEntityDescriptorXml(byte[] rawXmlBytes, return ResponseEntity.created(getResourceUriFor(persistedEd)) .body(entityDescriptorService.createRepresentationFromDescriptor(persistedEd)); } + + private User getUserFromPrincipal(Principal principal) { + User user = null; + if (principal != null && StringUtils.isNotBlank(principal.getName())) { + Optional persistedUser = userRepository.findByUsername(principal.getName()); + if (persistedUser.isPresent()) { + user = persistedUser.get(); + } + } + return user; + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ErrorResponse.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ErrorResponse.java index fa91aa3e6..f3f84169d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ErrorResponse.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ErrorResponse.java @@ -4,6 +4,7 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.springframework.http.HttpStatus; /** * @author Bill Smith (wsmith@unicon.net) @@ -15,4 +16,9 @@ public class ErrorResponse { private String errorCode; private String errorMessage; + + public ErrorResponse(HttpStatus httpStatus, String errorMessage) { + this.errorCode = String.valueOf(httpStatus.value()); + this.errorMessage = errorMessage; + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepository.java index be729d489..07a3b5085 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepository.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepository.java @@ -21,4 +21,5 @@ public interface EntityDescriptorRepository extends CrudRepository findAllByCustomQueryAndStream(); + Stream findAllByCreatedBy(String username); }