From 0294ca34286cf3dcba7ead1570ad51bb3015a8eb Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 19 Aug 2021 13:17:49 -0700 Subject: [PATCH] SHIBUI-2024 Including the entity targets for name and id filter --- .../controller/MetadataFiltersController.java | 9 ++- .../filters/EntityAttributesFilter.java | 73 ++++++++----------- .../filters/EntityAttributesFilterTarget.java | 27 ++++--- .../ui/domain/filters/IFilterTarget.java | 13 ++++ .../admin/ui/domain/filters/ITargetable.java | 5 ++ .../ui/domain/filters/NameIdFormatFilter.java | 26 +++---- .../filters/NameIdFormatFilterTarget.java | 32 ++++---- .../MetadataFiltersControllerTests.groovy | 58 +++++++++++++-- .../admin/ui/util/TestObjectGenerator.groovy | 4 +- 9 files changed, 158 insertions(+), 89 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/IFilterTarget.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/ITargetable.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java index 7f48faa1a..07d45a6f1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.ITargetable; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.repository.FilterRepository; @@ -234,10 +235,10 @@ public ResponseEntity update(@PathVariable String metadataResolverId, * IF the filter is of type "EntityAttributes" AND the target is "ENTITY" THEN check each of the values (which are entityIds) */ private void validateFilterOrThrowHttp400(MetadataFilter createdFilter) { - if ("EntityAttributes".equals(createdFilter.getType())) { - EntityAttributesFilter filter = (EntityAttributesFilter) createdFilter; - if ("ENTITY".equals(filter.getEntityAttributesFilterTarget().getEntityAttributesFilterTargetType())) { - for (String entityId : filter.getEntityAttributesFilterTarget().getValue()) { + if (createdFilter instanceof ITargetable){ + ITargetable filter = (ITargetable) createdFilter; + if ("ENTITY".equals(filter.getTarget().getTargetTypeValue())) { + for (String entityId : filter.getTarget().getValue()) { if (!groupService.doesStringMatchGroupPattern(userService.getCurrentUser().getGroupId(), entityId)) { throw HTTP_400_BAD_REQUEST_EXCEPTION.get(); } 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 7643f483d..c267d4204 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 @@ -8,44 +8,23 @@ import lombok.ToString; 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 javax.persistence.*; 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; -import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getAttributeReleaseListFromAttributeList; -import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getRelyingPartyOverridesRepresentationFromAttributeList; +import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.*; @Entity -@EqualsAndHashCode(callSuper = true, exclude={"attributeRelease", "relyingPartyOverrides"}) +@EqualsAndHashCode(callSuper = true, exclude = { "attributeRelease", "relyingPartyOverrides" }) @Getter @Setter @ToString @Audited -public class EntityAttributesFilter extends MetadataFilter { +public class EntityAttributesFilter extends MetadataFilter implements ITargetable { private static final long serialVersionUID = 1L; - public EntityAttributesFilter() { - type = "EntityAttributes"; - } - - @OneToOne(cascade = CascadeType.ALL) - private EntityAttributesFilterTarget entityAttributesFilterTarget; - @OneToMany(cascade = CascadeType.ALL) @OrderColumn @JsonIgnore @@ -53,25 +32,21 @@ public EntityAttributesFilter() { @Transient private List attributeRelease = new ArrayList<>(); - - public void setAttributeRelease(List attributeRelease) { - this.attributeRelease = attributeRelease; - this.rebuildAttributes(); - } + + @OneToOne(cascade = CascadeType.ALL) + private EntityAttributesFilterTarget entityAttributesFilterTarget; @Transient private Map relyingPartyOverrides; - public void setRelyingPartyOverrides(Map relyingPartyOverridesRepresentation) { - this.relyingPartyOverrides = relyingPartyOverridesRepresentation; - this.rebuildAttributes(); + public EntityAttributesFilter() { + type = "EntityAttributes"; } - //TODO: yeah, I'm not too happy, either - private void rebuildAttributes() { - this.attributes.clear(); - this.attributes.addAll((List) (List)getAttributeListFromAttributeReleaseList(this.attributeRelease)); - this.attributes.addAll((List) (List)getAttributeListFromRelyingPartyOverridesRepresentation(this.relyingPartyOverrides)); + @Override + @JsonIgnore + public IFilterTarget getTarget() { + return entityAttributesFilterTarget; } @PostLoad @@ -82,6 +57,23 @@ public void intoTransientRepresentation() { this.relyingPartyOverrides = getRelyingPartyOverridesRepresentationFromAttributeList(this.attributes); } + //TODO: yeah, I'm not too happy, either + private void rebuildAttributes() { + this.attributes.clear(); + this.attributes.addAll((List) (List) getAttributeListFromAttributeReleaseList(this.attributeRelease)); + this.attributes.addAll((List) (List) getAttributeListFromRelyingPartyOverridesRepresentation(this.relyingPartyOverrides)); + } + + public void setAttributeRelease(List attributeRelease) { + this.attributeRelease = attributeRelease; + this.rebuildAttributes(); + } + + public void setRelyingPartyOverrides(Map relyingPartyOverridesRepresentation) { + this.relyingPartyOverrides = relyingPartyOverridesRepresentation; + this.rebuildAttributes(); + } + private EntityAttributesFilter updateConcreteFilterTypeData(EntityAttributesFilter filterToBeUpdated) { filterToBeUpdated.setEntityAttributesFilterTarget(getEntityAttributesFilterTarget()); filterToBeUpdated.setRelyingPartyOverrides(getRelyingPartyOverrides()); @@ -89,8 +81,7 @@ private EntityAttributesFilter updateConcreteFilterTypeData(EntityAttributesFilt return filterToBeUpdated; } - @Override - public MetadataFilter updateConcreteFilterTypeData(MetadataFilter filterToBeUpdated) { + @Override public MetadataFilter updateConcreteFilterTypeData(MetadataFilter filterToBeUpdated) { return updateConcreteFilterTypeData((EntityAttributesFilter) filterToBeUpdated); } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java index 0a0da096f..8d9247074 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java @@ -1,15 +1,13 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.filters; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; import lombok.EqualsAndHashCode; import org.hibernate.envers.AuditOverride; import org.hibernate.envers.Audited; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.OrderColumn; +import javax.persistence.*; import java.util.ArrayList; import java.util.List; @@ -18,10 +16,7 @@ @Audited @AuditOverride(forClass = AbstractAuditable.class) @JsonIgnoreProperties({"handler", "hibernateLazyInitializer"}) -public class EntityAttributesFilterTarget extends AbstractAuditable { - public enum EntityAttributesFilterTargetType { - ENTITY, CONDITION_SCRIPT, CONDITION_REF, REGEX - } +public class EntityAttributesFilterTarget extends AbstractAuditable implements IFilterTarget { private EntityAttributesFilterTargetType entityAttributesFilterTargetType; @@ -34,14 +29,20 @@ public EntityAttributesFilterTargetType getEntityAttributesFilterTargetType() { return entityAttributesFilterTargetType; } - public void setEntityAttributesFilterTargetType(EntityAttributesFilterTargetType entityAttributesFilterTarget) { - this.entityAttributesFilterTargetType = entityAttributesFilterTarget; + @Override + @JsonIgnore + public String getTargetTypeValue() { + return entityAttributesFilterTargetType.name(); } public List getValue() { return value; } + public void setEntityAttributesFilterTargetType(EntityAttributesFilterTargetType entityAttributesFilterTarget) { + this.entityAttributesFilterTargetType = entityAttributesFilterTarget; + } + public void setSingleValue(String value) { List values = new ArrayList<>(); values.add(value); @@ -59,4 +60,8 @@ public String toString() { ", value=" + value + '}'; } -} + + public enum EntityAttributesFilterTargetType { + ENTITY, CONDITION_SCRIPT, CONDITION_REF, REGEX + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/IFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/IFilterTarget.java new file mode 100644 index 000000000..d0a2683b1 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/IFilterTarget.java @@ -0,0 +1,13 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +import java.util.List; + +public interface IFilterTarget { + String getTargetTypeValue(); + + List getValue(); + + void setSingleValue(String value); + + void setValue(List value); +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/ITargetable.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/ITargetable.java new file mode 100644 index 000000000..c46ff1c7f --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/ITargetable.java @@ -0,0 +1,5 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +public interface ITargetable { + public IFilterTarget getTarget(); +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilter.java index 47bb0810b..efd814375 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilter.java @@ -1,19 +1,14 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.filters; -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.OneToOne; -import javax.persistence.OrderColumn; - -import org.hibernate.envers.Audited; - +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.hibernate.envers.Audited; + +import javax.persistence.*; +import java.util.List; @Entity @EqualsAndHashCode(callSuper = true) @@ -21,7 +16,7 @@ @Setter @ToString @Audited -public class NameIdFormatFilter extends MetadataFilter { +public class NameIdFormatFilter extends MetadataFilter implements ITargetable { public NameIdFormatFilter() { type = "NameIDFormat"; @@ -36,6 +31,12 @@ public NameIdFormatFilter() { @OneToOne(cascade = CascadeType.ALL) private NameIdFormatFilterTarget nameIdFormatFilterTarget; + @Override + @JsonIgnore + public IFilterTarget getTarget() { + return nameIdFormatFilterTarget; + } + private NameIdFormatFilter updateConcreteFilterTypeData(NameIdFormatFilter filterToBeUpdated) { filterToBeUpdated.setRemoveExistingFormats(getRemoveExistingFormats()); filterToBeUpdated.setFormats(getFormats()); @@ -47,5 +48,4 @@ private NameIdFormatFilter updateConcreteFilterTypeData(NameIdFormatFilter filte public MetadataFilter updateConcreteFilterTypeData(MetadataFilter filterToBeUpdated) { return updateConcreteFilterTypeData((NameIdFormatFilter) filterToBeUpdated); } - -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java index eef906500..90445ff75 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.filters; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; import lombok.EqualsAndHashCode; @@ -10,6 +11,7 @@ import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.OrderColumn; +import javax.persistence.Transient; import java.util.ArrayList; import java.util.List; @@ -19,30 +21,32 @@ @Audited @AuditOverride(forClass = AbstractAuditable.class) @JsonIgnoreProperties({"handler", "hibernateLazyInitializer"}) -public class NameIdFormatFilterTarget extends AbstractAuditable { - - public enum NameIdFormatFilterTargetType { - ENTITY, CONDITION_SCRIPT, REGEX - } +public class NameIdFormatFilterTarget extends AbstractAuditable implements IFilterTarget { private NameIdFormatFilterTargetType nameIdFormatFilterTargetType; + @ElementCollection + @OrderColumn + private List value; + public NameIdFormatFilterTargetType getNameIdFormatFilterTargetType() { return nameIdFormatFilterTargetType; } - public void setNameIdFormatFilterTargetType(NameIdFormatFilterTargetType nameIdFormatFilterTargetType) { - this.nameIdFormatFilterTargetType = nameIdFormatFilterTargetType; + @Override + @JsonIgnore + public String getTargetTypeValue() { + return nameIdFormatFilterTargetType.name(); } - @ElementCollection - @OrderColumn - private List value; - public List getValue() { return value; } + public void setNameIdFormatFilterTargetType(NameIdFormatFilterTargetType nameIdFormatFilterTargetType) { + this.nameIdFormatFilterTargetType = nameIdFormatFilterTargetType; + } + public void setSingleValue(String value) { List values = new ArrayList<>(); values.add(value); @@ -53,5 +57,7 @@ public void setValue(List value) { this.value = value; } - -} + public enum NameIdFormatFilterTargetType { + ENTITY, CONDITION_SCRIPT, REGEX + } +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy index 280294aa1..d9fb504f8 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy @@ -13,6 +13,11 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.FilterRepository import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.security.model.Role +import edu.internet2.tier.shibboleth.admin.ui.security.model.User +import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository +import edu.internet2.tier.shibboleth.admin.ui.security.service.IGroupService +import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService import edu.internet2.tier.shibboleth.admin.ui.service.FilterService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator @@ -24,8 +29,10 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.ContextConfiguration import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional import org.w3c.dom.Document import spock.lang.Specification import spock.lang.Unroll @@ -53,6 +60,15 @@ class MetadataFiltersControllerTests extends Specification { @Autowired FilterService filterService + @Autowired + IGroupService groupService + + @Autowired + RoleRepository roleRepository + + @Autowired + UserService userService + TestObjectGenerator testObjectGenerator RandomGenerator randomGenerator ObjectMapper mapper @@ -67,7 +83,9 @@ class MetadataFiltersControllerTests extends Specification { static BASE_URI = '/api/MetadataResolvers' + @Transactional def setup() { + groupService.ensureAdminGroupExists() randomGenerator = new RandomGenerator() testObjectGenerator = new TestObjectGenerator(attributeUtility, customPropertiesConfiguration) mapper = new ObjectMapper() @@ -76,6 +94,8 @@ class MetadataFiltersControllerTests extends Specification { controller = new MetadataFiltersController ( repository: metadataResolverRepository, filterRepository: metadataFilterRepository, + groupService: groupService, + userService: userService, metadataResolverService: new MetadataResolverService() { @Override void reloadFilters(String metadataResolverName) { @@ -94,8 +114,33 @@ class MetadataFiltersControllerTests extends Specification { it } ) - mockMvc = MockMvcBuilders.standaloneSetup(controller).build() + + roleRepository.deleteAll() + roleRepository.flush() + if (roleRepository.count() == 0) { + def roles = [new Role().with { + name = 'ROLE_ADMIN' + it + }] + roles.each { + roleRepository.save(it) + } + } + roleRepository.flush() + + def users = [new User().with { + username = 'admin' + password = '{noop}adminpass' + firstName = 'Joe' + lastName = 'Doe' + emailAddress = 'joe@institution.edu' + roles.add(roleRepository.findByName('ROLE_ADMIN').get()) + it + }] + users.each { + it = userService.save(it) + } } def "FilterController.getAll gets all available types of filters"() { @@ -139,6 +184,7 @@ class MetadataFiltersControllerTests extends Specification { } @Unroll + @WithMockUser(value = "admin", roles = ["ADMIN"]) def "FilterController.create creates the desired filter (filterType: #filterType)"(String filterType) { given: def randomFilter = testObjectGenerator.buildRandomFilterOfType(filterType) @@ -161,10 +207,9 @@ class MetadataFiltersControllerTests extends Specification { def postedJsonBody = expectedJsonBody - ~/"id":.*?,/ // remove the "id:," when: - def result = mockMvc.perform( - post("$BASE_URI/foo/Filters") - .contentType(APPLICATION_JSON) - .content(postedJsonBody)) + def result = mockMvc.perform(post("$BASE_URI/foo/Filters") + .contentType(APPLICATION_JSON) + .content(postedJsonBody)) then: println postedJsonBody @@ -182,6 +227,7 @@ class MetadataFiltersControllerTests extends Specification { } @Unroll + @WithMockUser(value = "admin", roles = ["ADMIN"]) def "FilterController.update updates the target #filterType filter as desired"(String filterType) { given: def originalFilter = testObjectGenerator.buildRandomFilterOfType(filterType) @@ -251,4 +297,4 @@ class MetadataFiltersControllerTests extends Specification { then: result.andExpect(status().is(409)) } -} +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy index e28220cc6..677b159f9 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy @@ -275,6 +275,7 @@ class TestObjectGenerator { it.setEntityAttributesFilterTarget(entityAttributesFilter.entityAttributesFilterTarget) it.setAttributes(entityAttributesFilter.attributes) it.intoTransientRepresentation() + it.setEntityAttributesFilterTarget(entityAttributesFilter.getEntityAttributesFilterTarget()) it } } @@ -285,6 +286,7 @@ class TestObjectGenerator { it.resourceId = nameIdFormatFilter.resourceId it.removeExistingFormats = nameIdFormatFilter.removeExistingFormats it.formats = nameIdFormatFilter.formats + it.setNameIdFormatFilterTarget(nameIdFormatFilter.getNameIdFormatFilterTarget()) it } } @@ -659,4 +661,4 @@ class TestObjectGenerator { } return list } -} +} \ No newline at end of file