Skip to content

Commit

Permalink
Merged in feature/shibui-2059 (pull request #527)
Browse files Browse the repository at this point in the history
Feature/shibui 2059
  • Loading branch information
chasegawa committed Sep 13, 2021
2 parents 8b116e4 + 81c3405 commit 8047d03
Show file tree
Hide file tree
Showing 17 changed files with 559 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.GroupDeleteException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.GroupExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.service.AttributeBundleService;
import lombok.extern.slf4j.Slf4j;
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;

@RestController
@RequestMapping("/api/custom/entity/bundles")
@Slf4j
public class AttributeBundleController {
@Autowired AttributeBundleService attributeBundleService;

@Secured("ROLE_ADMIN")
@PostMapping
@Transactional
public ResponseEntity<?> create(@RequestBody AttributeBundle bundle) throws ObjectIdExistsException {
AttributeBundle result = attributeBundleService.create(bundle);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

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

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

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

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
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;

@ControllerAdvice(assignableTypes = {AttributeBundleController.class})
public class AttributeBundleExceptionHandler 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({ ObjectIdExistsException.class })
public ResponseEntity<?> handleObjectIdExistsException(ObjectIdExistsException e, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage()));
return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse(
String.valueOf(HttpStatus.CONFLICT.value()),
String.format("The attribute bundle with resource id [%s] already exists.", e.getMessage())));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,21 @@

import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.domain.versioning.Version;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
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.service.UserService;
import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService;
import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorVersionService;
import lombok.extern.slf4j.Slf4j;

import org.opensaml.core.xml.io.MarshallingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpHeaders;
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.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -39,8 +32,6 @@

import java.net.URI;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api")
Expand Down Expand Up @@ -73,7 +64,8 @@ public EntityDescriptorController(EntityDescriptorVersionService versionService)

@PostMapping("/EntityDescriptor")
@Transactional
public ResponseEntity<?> create(@RequestBody EntityDescriptorRepresentation edRepresentation) throws ForbiddenException, EntityIdExistsException {
public ResponseEntity<?> create(@RequestBody EntityDescriptorRepresentation edRepresentation) throws ForbiddenException,
ObjectIdExistsException {
EntityDescriptorRepresentation persistedEd = entityDescriptorService.createNew(edRepresentation);
return ResponseEntity.created(getResourceUriFor(persistedEd.getId())).body(persistedEd);
}
Expand Down Expand Up @@ -171,4 +163,4 @@ public ResponseEntity<?> upload(@RequestParam String metadataUrl, @RequestParam
.body(String.format("Error fetching XML metadata from the provided URL. Error: %s", e.getMessage()));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;

Expand All @@ -22,23 +22,23 @@ public ResponseEntity<?> handleConcurrentModificationException(ConcurrentModific
return ResponseEntity.status(HttpStatus.CONFLICT).body(new ErrorResponse(HttpStatus.CONFLICT, e.getMessage()));
}

@ExceptionHandler({ EntityIdExistsException.class })
public ResponseEntity<?> handleEntityExistsException(EntityIdExistsException e, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage()));
return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse(
String.valueOf(HttpStatus.CONFLICT.value()),
String.format("The entity descriptor with entity id [%s] already exists.", e.getMessage())));

}

@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({ ForbiddenException.class })
public ResponseEntity<?> handleForbiddenAccess(ForbiddenException e, WebRequest request) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, e.getMessage()));
}
}

@ExceptionHandler({ ObjectIdExistsException.class })
public ResponseEntity<?> handleObjectIdExistsException(ObjectIdExistsException e, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage()));
return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse(
String.valueOf(HttpStatus.CONFLICT.value()),
String.format("The entity descriptor with entity id [%s] already exists.", e.getMessage())));

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

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.Data;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Entity(name = "attribute_bundle_definition")
@Data
public class AttributeBundle {
@Column(nullable = false)
@ElementCollection
Set<BundleableAttributeType> attributes = new HashSet<>();

@Column(name = "name", nullable = true)
String name;

@Id
@Column(name = "resource_id", nullable = false)
String resourceId = UUID.randomUUID().toString();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import edu.internet2.tier.shibboleth.admin.util.BundleableAttributeTypeValueSerializer;

@JsonSerialize(using = BundleableAttributeTypeValueSerializer.class)
public enum BundleableAttributeType {
EDUPERSONPRINCIPALNAME("eduPersonPrincipalName"),
UID("uid"),
MAIL("mail"),
SURNAME("surname"),
GIVENNAME("givenName"),
EDUPERSONAFFILIATE("eduPersonAffiliation"),
EDUPERSONSCOPEDAFFILIATION("eduPersonScopedAffiliation"),
EDUPERSONPRIMARYAFFILIATION("eduPersonPrimaryAffiliation"),
EDUPERSONENTITLEMENT("eduPersonEntitlement"),
EDUPERSONASSURANCE("eduPersonAssurance"),
EDUPERSONUNIQUEID("eduPersonUniqueId"),
EMPLOYEENUMBER("employeeNumber");

String label;

BundleableAttributeType(String val) {
label = val;
}

public String label() {return label;}

@JsonCreator
public static BundleableAttributeType valueOfLabel(String label) {
for (BundleableAttributeType e : values()) {
if (e.label.equals(label)) {
return e;
}
}
return null;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package edu.internet2.tier.shibboleth.admin.ui.exception;

public class ObjectIdExistsException extends Exception {
public ObjectIdExistsException(String entityId) {
super(entityId);
}

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

import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle;
import org.springframework.data.jpa.repository.JpaRepository;

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

/**
* Repository to manage {@link edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle} instances.
*/
public interface AttributeBundleRepository extends JpaRepository<AttributeBundle, String> {
List<AttributeBundle> findAll();

Optional<AttributeBundle> findByResourceId(String resourceId);

AttributeBundle save(AttributeBundle target);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class AttributeBundleService {
@Autowired
AttributeBundleRepository attributeBundleRepository;

public AttributeBundle create(AttributeBundle bundle) throws ObjectIdExistsException {
if (attributeBundleRepository.findByResourceId(bundle.getResourceId()).isPresent()) {
throw new ObjectIdExistsException(bundle.getResourceId());
}
return attributeBundleRepository.save(bundle);
}

public List<AttributeBundle> findAll() {
return attributeBundleRepository.findAll();
}

public void deleteDefinition(String resourceId) throws EntityNotFoundException {
if (attributeBundleRepository.findByResourceId(resourceId).isEmpty()) {
throw new EntityNotFoundException(String.format("Unable to find attribute bundle with resource id: [%s] for deletion", resourceId));
}
attributeBundleRepository.deleteById(resourceId);
}

public AttributeBundle updateBundle(AttributeBundle bundle) throws EntityNotFoundException {
Optional<AttributeBundle> dbBundle = attributeBundleRepository.findByResourceId(bundle.getResourceId());
if (dbBundle.isEmpty()) {
throw new EntityNotFoundException(String.format("Unable to find attribute bundle with resource id: [%s] for update", bundle.getResourceId()));
}
AttributeBundle bundleToUpdate = dbBundle.get();
bundleToUpdate.setName(bundle.getName());
bundleToUpdate.setAttributes(bundle.getAttributes());
return attributeBundleRepository.save(bundleToUpdate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute;
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;

Expand All @@ -29,17 +29,18 @@ public interface EntityDescriptorService {
* @param ed - JPA EntityDescriptor to base creation on
* @return EntityDescriptorRepresentation of the created object
* @throws ForbiddenException If user is unauthorized to perform this operation
* @throws EntityIdExistsException If any EntityDescriptor already exists with the same EntityId
* @throws ObjectIdExistsException If any EntityDescriptor already exists with the same EntityId
*/
EntityDescriptorRepresentation createNew(EntityDescriptor ed) throws ForbiddenException, EntityIdExistsException;
EntityDescriptorRepresentation createNew(EntityDescriptor ed) throws ForbiddenException, ObjectIdExistsException;

/**
* @param edRepresentation Incoming representation to save
* @return EntityDescriptorRepresentation
* @throws ForbiddenException If user is unauthorized to perform this operation
* @throws EntityIdExistsException If the entity already exists
* @throws ObjectIdExistsException If the entity already exists
*/
EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRepresentation) throws ForbiddenException, EntityIdExistsException;
EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRepresentation) throws ForbiddenException,
ObjectIdExistsException;

/**
* Map from opensaml implementation of entity descriptor model to front-end data representation of entity descriptor
Expand Down
Loading

0 comments on commit 8047d03

Please sign in to comment.