Skip to content

Commit

Permalink
SHIBUI-2394
Browse files Browse the repository at this point in the history
Incremental commit - non working tests
  • Loading branch information
chasegawa committed Oct 4, 2022
1 parent 5722aa8 commit 1af89c5
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,15 @@ public ResponseEntity<?> enableEntityDescriptor(@PathVariable String resourceId,

@PatchMapping(path = "/MetadataResolvers/{metadataResolverId}/Filter/{resourceId}/{mode}")
@Transactional
public ResponseEntity<?> enableFilter(@PathVariable String metadataResolverId, @PathVariable String resourceId, @PathVariable String mode) throws
PersistentEntityNotFound, ForbiddenException, ScriptException {
public ResponseEntity<?> enableFilter(@PathVariable String metadataResolverId, @PathVariable String resourceId, @PathVariable String mode) throws PersistentEntityNotFound, ForbiddenException, ScriptException {
boolean status = "enable".equalsIgnoreCase(mode);
MetadataFilter persistedFilter = filterService.updateFilterEnabledStatus(metadataResolverId, resourceId, status);
return ResponseEntity.ok(persistedFilter);
}

@PatchMapping("/MetadataResolvers/{resourceId}/{mode}")
@Transactional
public ResponseEntity<?> enableProvider(@PathVariable String resourceId, @PathVariable String mode) throws
PersistentEntityNotFound, ForbiddenException, MetadataFileNotFoundException, InitializationException {
public ResponseEntity<?> enableProvider(@PathVariable String resourceId, @PathVariable String mode) throws PersistentEntityNotFound, ForbiddenException, MetadataFileNotFoundException, InitializationException {
boolean status = "enable".equalsIgnoreCase(mode);
MetadataResolver existingResolver = metadataResolverService.findByResourceId(resourceId);
existingResolver.setEnabled(status);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
import edu.internet2.tier.shibboleth.admin.ui.exception.PersistentEntityNotFound;
import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.tags.Tags;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/approve")
@Tags(value = {@Tag(name = "approve")})
public class ApprovalController {
@Autowired
private EntityDescriptorService entityDescriptorService;

@PatchMapping(path = "/entityDescriptor/{resourceId}/{mode}")
@Transactional
public ResponseEntity<?> approveEntityDescriptor(@PathVariable String resourceId, @PathVariable String mode) throws PersistentEntityNotFound, ForbiddenException {
// boolean status = "approve".equalsIgnoreCase(mode); // can we un-approve?
EntityDescriptorRepresentation edr = entityDescriptorService.approveEntityDescriptor(resourceId);
return ResponseEntity.ok(edr);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException;
import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException;

@ControllerAdvice(assignableTypes = {ActivateController.class})
public class ActivateExceptionHandler extends ResponseEntityExceptionHandler {
@ControllerAdvice(assignableTypes = {ActivateController.class, ApprovalController.class})
public class ApproveAndActivateExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler({ PersistentEntityNotFound.class })
public ResponseEntity<?> handleEntityNotFoundException(PersistentEntityNotFound e, WebRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ public EntityDescriptorController(EntityDescriptorVersionService versionService)

@PostMapping("/EntityDescriptor")
@Transactional
public ResponseEntity<?> create(@RequestBody EntityDescriptorRepresentation edRepresentation)
throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException {
public ResponseEntity<?> create(@RequestBody EntityDescriptorRepresentation edRepresentation) throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException {
EntityDescriptorRepresentation persistedEd = entityDescriptorService.createNew(edRepresentation);
return ResponseEntity.created(getResourceUriFor(persistedEd.getId())).body(persistedEd);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;

import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Ownable;
import edu.internet2.tier.shibboleth.admin.ui.security.model.OwnableType;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.opensaml.core.xml.XMLObject;
import org.springframework.util.StringUtils;

import javax.annotation.Nullable;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderColumn;
Expand Down Expand Up @@ -53,6 +51,10 @@ public class EntityDescriptor extends AbstractDescriptor implements org.opensaml
@NotAudited
private AttributeAuthorityDescriptor attributeAuthorityDescriptor;

@ElementCollection (fetch = FetchType.EAGER)
@EqualsAndHashCode.Exclude
private List<String> approved = new ArrayList<>();

@OneToOne(cascade = CascadeType.ALL)
@NotAudited
private AuthnAuthorityDescriptor authnAuthorityDescriptor;
Expand Down Expand Up @@ -313,4 +315,12 @@ public OwnableType getOwnableType() {
@Override public ActivatableType getActivatableType() {
return ENTITY_DESCRIPTOR;
}

public void addApproval(Group group) {
approved.add(group.getName());
}

public int approvedCount() {
return approved.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ public UserService(IGroupService groupService, OwnershipRepository ownershipRepo
this.userRepository = userRepository;
}

public boolean currentUserCanApprove(List<Group> approverGroups) {
if (currentUserIsAdmin()) {
return true;
}
Group currentUserGroup = getCurrentUserGroup();
return approverGroups.contains(currentUserGroup);
}

public boolean currentUserCanEnable(IActivatable activatableObject) {
if (currentUserIsAdmin()) { return true; }
switch (activatableObject.getActivatableType()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,6 @@ EntityDescriptorRepresentation updateEntityDescriptorEnabledStatus(String resour
boolean entityExists(String entityID);

EntityDescriptorRepresentation updateGroupForEntityDescriptor(String resourceId, String groupId);

EntityDescriptorRepresentation approveEntityDescriptor(String resourceId) throws PersistentEntityNotFound, ForbiddenException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorProjection;
import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Approvers;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Owner;
import edu.internet2.tier.shibboleth.admin.ui.security.model.OwnerType;
Expand Down Expand Up @@ -74,6 +75,25 @@ public class JPAEntityDescriptorServiceImpl implements EntityDescriptorService {
@Autowired
private UserService userService;

@Override
public EntityDescriptorRepresentation approveEntityDescriptor(String resourceId) throws PersistentEntityNotFound, ForbiddenException {
EntityDescriptor ed = entityDescriptorRepository.findByResourceId(resourceId);
if (ed == null) {
throw new PersistentEntityNotFound("Entity with resourceid[" + resourceId + "] was not found for approval");
}
int approvedCount = ed.approvedCount();
List<Approvers> approversList = groupService.find(ed.getIdOfOwner()).getApproversList();
if (!approversList.isEmpty() && approversList.size() > approvedCount) {
Approvers approvers = approversList.get(approvedCount); // yea for index zero - use the count to get the next approvers
if (!userService.currentUserCanApprove(approvers.getApproverGroups())) {
throw new ForbiddenException("You do not have the permissions necessary to approve this entity descriptor.");
}
ed.addApproval(userService.getCurrentUserGroup());
ed = entityDescriptorRepository.save(ed);
}
return createRepresentationFromDescriptor(ed);
}

private EntityDescriptor buildDescriptorFromRepresentation(final EntityDescriptor ed, final EntityDescriptorRepresentation representation) {
ed.setEntityID(representation.getEntityId());
ed.setIdOfOwner(representation.getIdOfOwner());
Expand Down Expand Up @@ -128,8 +148,7 @@ public EntityDescriptorRepresentation updateGroupForEntityDescriptor(String reso
}

@Override
public EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRep)
throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException {
public EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRep) throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException {
if (edRep.isServiceEnabled() && !userService.currentUserIsAdmin()) {
throw new ForbiddenException("You do not have the permissions necessary to enable this service.");
}
Expand Down Expand Up @@ -167,6 +186,7 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope
representation.setCreatedBy(ed.getCreatedBy());
representation.setCurrent(ed.isCurrent());
representation.setIdOfOwner(ed.getIdOfOwner());
representation.setApproved(isEntityDescriptorApproved(ed));

if (ed.getSPSSODescriptor("") != null && ed.getSPSSODescriptor("").getSupportedProtocols().size() > 0) {
ServiceProviderSsoDescriptorRepresentation serviceProviderSsoDescriptorRepresentation = representation.getServiceProviderSsoDescriptor(true);
Expand Down Expand Up @@ -362,6 +382,17 @@ public EntityDescriptorRepresentation createRepresentationFromDescriptor(org.ope
return representation;
}

private boolean isEntityDescriptorApproved(EntityDescriptor ed) {
if (ed.isServiceEnabled()) {
return true;
}
Group ownerGroup = groupService.find(ed.getIdOfOwner());
if (ownerGroup == null) {
ownerGroup = Group.ADMIN_GROUP; // This should only happen in the large number of tests that were written prior to group implementation
}
return ed.approvedCount() >= ownerGroup.getApproversList().size();
}

@Override
public void delete(String resourceId) throws ForbiddenException, PersistentEntityNotFound {
EntityDescriptor ed = getEntityDescriptorByResourceId(resourceId);
Expand Down Expand Up @@ -424,8 +455,7 @@ public Map<String, Object> getRelyingPartyOverridesRepresentationFromAttributeLi
}

@Override
public EntityDescriptorRepresentation update(EntityDescriptorRepresentation edRep)
throws ForbiddenException, PersistentEntityNotFound, InvalidPatternMatchException {
public EntityDescriptorRepresentation update(EntityDescriptorRepresentation edRep) throws ForbiddenException, PersistentEntityNotFound, InvalidPatternMatchException {
EntityDescriptor existingEd = entityDescriptorRepository.findByResourceId(edRep.getId());
if (existingEd == null) {
throw new PersistentEntityNotFound(String.format("The entity descriptor with entity id [%s] was not found for update.", edRep.getId()));
Expand Down Expand Up @@ -473,6 +503,12 @@ public EntityDescriptorRepresentation updateEntityDescriptorEnabledStatus(String
if (!userService.currentUserCanEnable(ed)) {
throw new ForbiddenException("You do not have the permissions necessary to change the enable status of this entity descriptor.");
}
// check to see if approvals have been completed
int approvedCount = ed.approvedCount();
List<Approvers> approversList = groupService.find(ed.getIdOfOwner()).getApproversList();
if (!ed.isServiceEnabled() && !userService.currentUserIsAdmin() && approversList.size() > approvedCount) {
throw new ForbiddenException("Approval must be completed before you can change the enable status of this entity descriptor.");
}
ed.setServiceEnabled(status);
ed = entityDescriptorRepository.save(ed);
return createRepresentationFromDescriptor(ed);
Expand Down
1 change: 1 addition & 0 deletions backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ spring.liquibase.change-log=db/changelog/changelog.sql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.check_nullability=true
spring.jpa.hibernate.use-new-id-generator-mappings=true
Expand Down
Loading

0 comments on commit 1af89c5

Please sign in to comment.