From 0cfbe25838ee1d3dc8943369d7ebdedf50595053 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Fri, 28 May 2021 08:33:41 -0700 Subject: [PATCH] SHIBUI-1783 Backend updates to saving filter to include any custom entity attributes --- .../CustomEntityAttributeDefinition.java | 2 + .../CustomEntityAttributeFilterValue.java | 43 +++++++++ .../filters/EntityAttributesFilter.java | 16 ++++ ...mEntityAttributeFilterValueRepository.java | 12 +++ .../repository/FilterRepositoryTests.groovy | 92 +++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/CustomEntityAttributeFilterValue.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/CustomEntityAttributeFilterValueRepository.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/CustomEntityAttributeDefinition.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/CustomEntityAttributeDefinition.java index b2be0f503..d852ba5ea 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/CustomEntityAttributeDefinition.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/CustomEntityAttributeDefinition.java @@ -3,12 +3,14 @@ import java.util.HashSet; import java.util.Set; +import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; import org.hibernate.envers.Audited; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/CustomEntityAttributeFilterValue.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/CustomEntityAttributeFilterValue.java new file mode 100644 index 000000000..ed6715631 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/CustomEntityAttributeFilterValue.java @@ -0,0 +1,43 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.hibernate.envers.Audited; + +import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition; +import lombok.Getter; +import lombok.Setter; + + +@Entity(name = "custom_entity_attr_filter_value") +@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "filter_id", "custom_entity_attribute_name" }) }) +@Audited +// NOTE: lombok's toString and equals cause an infinite loop somewhere that causes stack overflows, so if we need impls, +// do it manually. Do not replace the Getter and Setter with @Data... +@Getter +@Setter +public class CustomEntityAttributeFilterValue { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "generated_id") + private Integer id; + + @ManyToOne + @JoinColumn(name = "filter_id", nullable = false) + EntityAttributesFilter entityAttributesFilter; + + @ManyToOne + @JoinColumn(name = "custom_entity_attribute_name", referencedColumnName = "name", nullable = false) + CustomEntityAttributeDefinition customEntityAttributeDefinition; + + @Column(name = "value", nullable = false) + String value; +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java index 83ce3a66e..28926358f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java @@ -9,16 +9,21 @@ import org.hibernate.envers.Audited; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.OrderColumn; import javax.persistence.PostLoad; import javax.persistence.Transient; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getAttributeListFromAttributeReleaseList; import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getAttributeListFromRelyingPartyOverridesRepresentation; @@ -32,6 +37,7 @@ @ToString @Audited public class EntityAttributesFilter extends MetadataFilter { + private static final long serialVersionUID = 1L; public EntityAttributesFilter() { type = "EntityAttributes"; @@ -47,7 +53,16 @@ public EntityAttributesFilter() { @Transient private List attributeRelease = new ArrayList<>(); + + @JsonIgnore + @OneToMany(cascade = CascadeType.ALL, mappedBy = "entityAttributesFilter", orphanRemoval = true) + private Set customEntityAttributes = new HashSet<>(); + public void setCustomEntityAttributes (Set newValues) { + customEntityAttributes.clear(); + customEntityAttributes.addAll(newValues); + } + public void setAttributeRelease(List attributeRelease) { this.attributeRelease = attributeRelease; this.rebuildAttributes(); @@ -80,6 +95,7 @@ private EntityAttributesFilter updateConcreteFilterTypeData(EntityAttributesFilt filterToBeUpdated.setEntityAttributesFilterTarget(getEntityAttributesFilterTarget()); filterToBeUpdated.setRelyingPartyOverrides(getRelyingPartyOverrides()); filterToBeUpdated.setAttributeRelease(getAttributeRelease()); + filterToBeUpdated.setCustomEntityAttributes(customEntityAttributes); return filterToBeUpdated; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/CustomEntityAttributeFilterValueRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/CustomEntityAttributeFilterValueRepository.java new file mode 100644 index 000000000..72507d24a --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/CustomEntityAttributeFilterValueRepository.java @@ -0,0 +1,12 @@ +package edu.internet2.tier.shibboleth.admin.ui.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.CustomEntityAttributeFilterValue; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; + +// Not entirely sure this is needed for the core, but it did make validation/unit testing a whole lot easier +public interface CustomEntityAttributeFilterValueRepository extends JpaRepository { + CustomEntityAttributeFilterValue findByEntityAttributesFilterAndCustomEntityAttributeDefinition(EntityAttributesFilter eaf , CustomEntityAttributeDefinition cead); +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy index d39cddc93..c8bbe9d74 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy @@ -5,6 +5,8 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfigurat import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.CustomEntityAttributeFilterValue import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import org.springframework.beans.factory.annotation.Autowired @@ -27,6 +29,12 @@ class FilterRepositoryTests extends Specification { @Autowired FilterRepository repositoryUnderTest + @Autowired + CustomEntityAttributeDefinitionRepository ceadRepo + + @Autowired + CustomEntityAttributeFilterValueRepository ceafvRepo + @Autowired EntityManager entityManager @@ -85,4 +93,88 @@ class FilterRepositoryTests extends Specification { persistedFilter.audId > 0L persistedFilter.formats.size() == 1 } + + def "FilterRepository + EntityAttributesFilter CRUD ops with custom entity attributes correctly"(){ + given: + def ca = new CustomEntityAttributeDefinition().with { + it.name = "ca-name" + it.attributeType = "STRING" + it.defaultValue = "foo" + it + } + ceadRepo.save(ca) + entityManager.flush() + entityManager.clear() + + def entityAttributesFilterJson = '''{ + "name": "EntityAttributes", + "resourceId": "29a5d409-562a-41cd-acee-e9b3d7098d05", + "filterEnabled": false, + "entityAttributesFilterTarget": { + "entityAttributesFilterTargetType": "CONDITION_SCRIPT", + "value": [ + "TwUuSOz5O6" + ] + }, + "attributeRelease": [ + "WbkhLQNI3m" + ], + "relyingPartyOverrides": { + "signAssertion": true, + "dontSignResponse": true, + "turnOffEncryption": true, + "useSha": true, + "ignoreAuthenticationMethod": false, + "omitNotBefore": true, + "responderId": null, + "nameIdFormats": [ + "xLenUFmCLn" + ], + "authenticationMethods": [] + }, + "@type": "EntityAttributes" + }''' + def filter = new ObjectMapper().readValue(entityAttributesFilterJson.bytes, EntityAttributesFilter.class) + def persistedFilter = repositoryUnderTest.save(filter) + entityManager.flush() + + def savedFilter = repositoryUnderTest.findByResourceId(persistedFilter.resourceId) + def saveEAD = ceadRepo.findByName("ca-name"); + + def ceafv = new CustomEntityAttributeFilterValue().with { + it.entityAttributesFilter = savedFilter + it.customEntityAttributeDefinition = saveEAD + it.value = "bar" + it + } + + def customEntityAttributes = new HashSet() + + when: + customEntityAttributes.add(ceafv) // nothing to do yet, just here to let us verify nothing in the CEAFV table in 'then' block + + then: + ((Set)ceafvRepo.findAll()).size() == 0 //nothing yet + ((EntityAttributesFilter)savedFilter).setCustomEntityAttributes(customEntityAttributes) + repositoryUnderTest.save(savedFilter) + entityManager.flush() + + then: + def listOfceafv = ceafvRepo.findAll() + listOfceafv.size() == 1 + + def ceafvFromDb = listOfceafv.get(0).asType(CustomEntityAttributeFilterValue) + ceafvFromDb.getEntityAttributesFilter().getResourceId().equals("29a5d409-562a-41cd-acee-e9b3d7098d05") + + def filterFromDb = (EntityAttributesFilter) repositoryUnderTest.findByResourceId("29a5d409-562a-41cd-acee-e9b3d7098d05") + filterFromDb.getCustomEntityAttributes().size() == 1 + + // now remove all + def emptySet = new HashSet() + filterFromDb.setCustomEntityAttributes(emptySet) + repositoryUnderTest.save(filterFromDb) + entityManager.flush() + + ceafvRepo.findAll().size() == 0 + } }