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 7d873afa6..52122b64f 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 @@ -6,10 +6,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; +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.service.MetadataResolverService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -24,7 +24,6 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import java.net.URI; -import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,14 +31,15 @@ @RequestMapping("/api/MetadataResolvers/{metadataResolverId}") public class MetadataFiltersController { - private static Logger LOGGER = LoggerFactory.getLogger(MetadataFiltersController.class); - @Autowired private MetadataResolverRepository repository; @Autowired private MetadataResolverService metadataResolverService; + @Autowired + private FilterRepository filterRepository; + @GetMapping("/Filters") @Transactional(readOnly = true) public ResponseEntity getAll(@PathVariable String metadataResolverId) { @@ -68,18 +68,12 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques return ResponseEntity.notFound().build(); } metadataResolver.getMetadataFilters().add(createdFilter); - - //convert before saving into database - if(createdFilter instanceof EntityAttributesFilter) { - EntityAttributesFilter.class.cast(createdFilter).fromTransientRepresentation(); - } MetadataResolver persistedMr = repository.save(metadataResolver); // we reload the filters here after save metadataResolverService.reloadFilters(persistedMr.getName()); - MetadataFilter persistedFilter = - convertIntoTransientRepresentationIfNecessary(persistedMr.getMetadataFilters().stream(), createdFilter.getResourceId()); + MetadataFilter persistedFilter = newlyPersistedFilter(persistedMr.getMetadataFilters().stream(), createdFilter.getResourceId()); return ResponseEntity .created(getResourceUriFor(persistedMr, createdFilter.getResourceId())) @@ -91,30 +85,28 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques public ResponseEntity update(@PathVariable String metadataResolverId, @PathVariable String resourceId, @RequestBody MetadataFilter updatedFilter) { + MetadataFilter filterTobeUpdated = filterRepository.findByResourceId(resourceId); + if (filterTobeUpdated == null) { + return ResponseEntity.notFound().build(); + } MetadataResolver metadataResolver = repository.findByResourceId(metadataResolverId); if(metadataResolver == null) { return ResponseEntity.notFound().build(); } - if (!resourceId.equals(updatedFilter.getResourceId())) { - return new ResponseEntity(HttpStatus.CONFLICT); + // check to make sure that the relationship exists + if (!metadataResolver.getMetadataFilters().contains(filterTobeUpdated)) { + // TODO: find a better response + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - List filters = - metadataResolver.getMetadataFilters().stream() - .filter(f -> f.getResourceId().equals(updatedFilter.getResourceId())) - .collect(Collectors.toList()); - if (filters.size() > 1) { - // TODO: I don't think this should ever happen, but... if it does... - // do something? throw exception, return error? - LOGGER.warn("More than one filter was found for id {}! This is probably a bad thing.\n" + - "We're going to go ahead and use the first one, but .. look in to this!", updatedFilter.getResourceId()); + if (!resourceId.equals(updatedFilter.getResourceId())) { + return new ResponseEntity(HttpStatus.CONFLICT); } - MetadataFilter filterTobeUpdated = filters.get(0); // Verify we're the only one attempting to update the filter - if (updatedFilter.getVersion() != filterTobeUpdated.hashCode()) { + if (updatedFilter.getVersion() != filterTobeUpdated.getVersion()) { return new ResponseEntity(HttpStatus.CONFLICT); } @@ -122,32 +114,19 @@ public ResponseEntity update(@PathVariable String metadataResolverId, filterTobeUpdated.setFilterEnabled(updatedFilter.isFilterEnabled()); updateConcreteFilterTypeData(filterTobeUpdated, updatedFilter); - //convert before saving into database - if(filterTobeUpdated instanceof EntityAttributesFilter) { - EntityAttributesFilter.class.cast(filterTobeUpdated).fromTransientRepresentation(); - } + MetadataFilter persistedFilter = filterRepository.save(filterTobeUpdated); - MetadataResolver persistedMr = repository.save(metadataResolver); - - metadataResolverService.reloadFilters(persistedMr.getName()); - - MetadataFilter persistedFilter = - convertIntoTransientRepresentationIfNecessary(persistedMr.getMetadataFilters().stream(), updatedFilter.getResourceId()); - - persistedFilter.setVersion(persistedFilter.hashCode()); + // TODO: this is wrong + metadataResolverService.reloadFilters(metadataResolver.getName()); return ResponseEntity.ok().body(persistedFilter); } - private MetadataFilter convertIntoTransientRepresentationIfNecessary(Stream filters, final String filterResourceId) { + private MetadataFilter newlyPersistedFilter(Stream filters, final String filterResourceId) { MetadataFilter persistedFilter = filters .filter(f -> f.getResourceId().equals(filterResourceId)) .collect(Collectors.toList()).get(0); - //convert before saving into database - if(persistedFilter instanceof EntityAttributesFilter) { - EntityAttributesFilter.class.cast(persistedFilter).intoTransientRepresentation(); - } return persistedFilter; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java index 2b1ddc6b5..be6ab51a4 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java @@ -61,7 +61,6 @@ public ResponseEntity unableToParseJson(Exception ex) { @Transactional(readOnly = true) public ResponseEntity getAll() { List resolvers = positionOrderContainerService.getAllMetadataResolversInDefinedOrderOrUnordered(); - resolvers.forEach(MetadataResolver::updateVersion); return ResponseEntity.ok(resolvers); } @@ -86,7 +85,6 @@ public ResponseEntity getOne(@PathVariable String resourceId) { if (resolver == null) { return ResponseEntity.notFound().build(); } - resolver.updateVersion(); return ResponseEntity.ok(resolver); } @@ -102,12 +100,9 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) { return validationErrorResponse; } - newResolver.convertFiltersFromTransientRepresentationIfNecessary(); MetadataResolver persistedResolver = resolverRepository.save(newResolver); positionOrderContainerService.appendPositionOrderForNew(persistedResolver); - persistedResolver.updateVersion(); - persistedResolver.convertFiltersIntoTransientRepresentationIfNecessary(); return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } @@ -118,9 +113,9 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me if (existingResolver == null) { return ResponseEntity.notFound().build(); } - if (existingResolver.hashCode() != updatedResolver.getVersion()) { + if (existingResolver.getVersion() != updatedResolver.getVersion()) { log.info("Metadata Resolver version conflict. Latest resolver in database version: {}. Resolver version sent from UI: {}", - existingResolver.hashCode(), updatedResolver.getVersion()); + existingResolver.getVersion(), updatedResolver.getVersion()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } @@ -131,11 +126,7 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me updatedResolver.setAudId(existingResolver.getAudId()); - //If one needs to update filters, it should be dealt with via filters endpoints - updatedResolver.setMetadataFilters(existingResolver.getMetadataFilters()); - MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); - persistedResolver.updateVersion(); return ResponseEntity.ok(persistedResolver); } 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 0208f92c4..8492e745d 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 @@ -14,8 +14,6 @@ import javax.persistence.OneToOne; import javax.persistence.OrderColumn; import javax.persistence.PostLoad; -import javax.persistence.PrePersist; -import javax.persistence.PreUpdate; import javax.persistence.Transient; import java.util.ArrayList; @@ -48,25 +46,29 @@ public EntityAttributesFilter() { @Transient private List attributeRelease = new ArrayList<>(); + public void setAttributeRelease(List attributeRelease) { + this.attributeRelease = attributeRelease; + this.rebuildAttributes(); + } + @Transient private RelyingPartyOverridesRepresentation relyingPartyOverrides; + public void setRelyingPartyOverrides(RelyingPartyOverridesRepresentation relyingPartyOverridesRepresentation) { + this.relyingPartyOverrides = relyingPartyOverridesRepresentation; + this.rebuildAttributes(); + } + + //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)); + } + @PostLoad public void intoTransientRepresentation() { this.attributeRelease = getAttributeReleaseListFromAttributeList(this.attributes); this.relyingPartyOverrides = getRelyingPartyOverridesRepresentationFromAttributeList(attributes); - updateVersion(); - } - - @PrePersist - @PreUpdate - public void fromTransientRepresentation() { - List attributeList = new ArrayList<>(); - attributeList.addAll(getAttributeListFromAttributeReleaseList(this.attributeRelease)); - attributeList.addAll(getAttributeListFromRelyingPartyOverridesRepresentation(this.relyingPartyOverrides)); - - if(!attributeList.isEmpty()) { - this.attributes = (List) (List) attributeList; - } } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java index 0347de1f7..a80d538c9 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.filters; +import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -46,9 +47,13 @@ public class MetadataFilter extends AbstractAuditable { private boolean filterEnabled; @Transient - private int version; - - public void updateVersion() { - this.version = hashCode(); + private transient Integer version; + + @JsonGetter("version") + public int getVersion() { + if (version != null && version != 0) { + return this.version; + } + return this.hashCode(); } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java index 7d0fc03d1..599503f75 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java @@ -1,10 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; +import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; -import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -24,8 +24,6 @@ import java.util.List; import java.util.UUID; -import static java.util.stream.Collectors.toList; - @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @EqualsAndHashCode(callSuper = true, exclude = {"version"}) @@ -73,24 +71,13 @@ public class MetadataResolver extends AbstractAuditable { private List metadataFilters = new ArrayList<>(); @Transient - private int version; - - public void updateVersion() { - this.version = hashCode(); - } - - public void convertFiltersIntoTransientRepresentationIfNecessary() { - getAvailableEntityAttributesFilters().forEach(EntityAttributesFilter::intoTransientRepresentation); - } - - public void convertFiltersFromTransientRepresentationIfNecessary() { - getAvailableEntityAttributesFilters().forEach(EntityAttributesFilter::fromTransientRepresentation); - } - - private List getAvailableEntityAttributesFilters() { - return this.metadataFilters.stream() - .filter(EntityAttributesFilter.class::isInstance) - .map(EntityAttributesFilter.class::cast) - .collect(toList()); + private Integer version; + + @JsonGetter("version") + public int getVersion() { + if (this.version != null && this.version != 0 ) { + return this.version; + } + return this.hashCode(); } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy new file mode 100644 index 000000000..557fdf56e --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy @@ -0,0 +1,121 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator +import edu.internet2.tier.shibboleth.admin.util.AttributeUtility +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver +import org.opensaml.saml.metadata.resolver.MetadataResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.test.context.ActiveProfiles +import spock.lang.Specification + +import static org.springframework.http.HttpMethod.PUT + +/** + * @author Dmitriy Kopylenko + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("no-auth") +class MetadataFiltersControllerIntegrationTests extends Specification { + + @Autowired + private TestRestTemplate restTemplate + + @Autowired + MetadataResolverRepository metadataResolverRepository + + @Autowired + AttributeUtility attributeUtility + + ObjectMapper mapper + TestObjectGenerator generator + + JsonSlurper jsonSlurper = new JsonSlurper() + + static BASE_URI = '/api/MetadataResolvers' + + def setup() { + generator = new TestObjectGenerator(attributeUtility) + mapper = new ObjectMapper() + mapper.enable(SerializationFeature.INDENT_OUTPUT) + mapper.registerModule(new JavaTimeModule()) + } + + def cleanup() { + metadataResolverRepository.deleteAll() + } + + def "PUT EntityAttributesFilter"() { + given: 'MetadataResolver with attached entity attributes is available in data store' + def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') + resolver.metadataFilters << generator.entityAttributesFilter() + def filterResourceId = resolver.metadataFilters[0].resourceId + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + + when: 'GET request is made with resource Id matching the existing filter' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) + def existingFilterMap = jsonSlurper.parseText(result.body) + + and: 'PUT call is made with unmodified filter state' + def updatedResultFromPUT = this.restTemplate.exchange( + "$BASE_URI/$resolverResourceId/Filters/$filterResourceId", + PUT, + createRequestHttpEntityFor { JsonOutput.toJson(existingFilterMap) }, String) + + then: + updatedResultFromPUT.statusCode.value() == 200 + } + + def "PUT EntityAttributesFilter and update it"() { + given: 'MetadataResolver with attached entity attributes is available in data store' + def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') + resolver.metadataFilters << generator.entityAttributesFilter() + def filterResourceId = resolver.metadataFilters[0].resourceId + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + + when: 'GET request is made with resource Id matching the existing filter' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) + def existingFilterMap = jsonSlurper.parseText(result.body) + + and: 'PUT call is made with modified filter state' + existingFilterMap.name = 'Entity Attributes Filter Updated' + def updatedResultFromPUT = this.restTemplate.exchange( + "$BASE_URI/$resolverResourceId/Filters/$filterResourceId", + PUT, + createRequestHttpEntityFor { JsonOutput.toJson(existingFilterMap) }, String) + + then: + updatedResultFromPUT.statusCode.value() == 200 + } + + private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { + new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) + } + + @TestConfiguration + static class Config { + @Bean + MetadataResolver metadataResolver() { + new ChainingMetadataResolver().with { + it.id = 'tester' + it.initialize() + return it + } + } + } +} \ 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 0443a7e54..40c6cefef 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 @@ -9,6 +9,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter 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 import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.service.FilterService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService @@ -53,6 +54,8 @@ class MetadataFiltersControllerTests extends Specification { def metadataResolverRepository = Mock(MetadataResolverRepository) + def metadataFilterRepository = Mock(FilterRepository) + def controller def mockMvc @@ -67,6 +70,7 @@ class MetadataFiltersControllerTests extends Specification { controller = new MetadataFiltersController ( repository: metadataResolverRepository, + filterRepository: metadataFilterRepository, metadataResolverService: new MetadataResolverService() { @Override void reloadFilters(String metadataResolverName) { @@ -98,8 +102,8 @@ class MetadataFiltersControllerTests extends Specification { then: result.andExpect(expectedHttpResponseStatus) - .andExpect(content().contentType(expectedResponseContentType)) - .andExpect(content().json(mapper.writeValueAsString(expectedContent))) + .andExpect(content().contentType(expectedResponseContentType)) + .andExpect(content().json(mapper.writeValueAsString(expectedContent))) } def "FilterController.getOne gets the desired filter"() { @@ -156,11 +160,11 @@ class MetadataFiltersControllerTests extends Specification { .andExpect(header().string(expectedResponseHeader, containsString(expectedResponseHeaderValue))) where: - filterType | _ - 'entityAttributes' | _ - 'entityRoleWhiteList' | _ - 'signatureValidation' | _ - 'requiredValidUntil' | _ + filterType | _ + 'entityAttributes' | _ + 'entityRoleWhiteList' | _ + 'signatureValidation' | _ + 'requiredValidUntil' | _ } @Unroll @@ -173,7 +177,7 @@ class MetadataFiltersControllerTests extends Specification { def postedJsonBody = mapper.writeValueAsString(updatedFilter) def originalMetadataResolver = new MetadataResolver() - originalMetadataResolver.setResourceId(randomGenerator.randomId()) + originalMetadataResolver.setResourceId('foo') originalMetadataResolver.setMetadataFilters(testObjectGenerator.buildAllTypesOfFilterList()) originalMetadataResolver.metadataFilters.add(originalFilter) @@ -183,7 +187,8 @@ class MetadataFiltersControllerTests extends Specification { updatedMetadataResolver.getMetadataFilters().add(updatedFilter) 1 * metadataResolverRepository.findByResourceId(_) >> originalMetadataResolver - 1 * metadataResolverRepository.save(_) >> updatedMetadataResolver + 1 * metadataFilterRepository.findByResourceId(_) >> originalFilter + 1 * metadataFilterRepository.save(_) >> updatedFilter def filterUUID = updatedFilter.getResourceId() @@ -195,19 +200,16 @@ class MetadataFiltersControllerTests extends Specification { then: def expectedJson = new JsonSlurper().parseText(postedJsonBody) - if (filterType == 'entityAttributes') { - EntityAttributesFilter.cast(updatedFilter).fromTransientRepresentation() - } - expectedJson << [version: updatedFilter.hashCode()] + expectedJson << [version: updatedFilter.getVersion()] result.andExpect(status().isOk()) .andExpect(content().json(JsonOutput.toJson(expectedJson), true)) where: - filterType | _ - 'entityAttributes' | _ - 'entityRoleWhiteList' | _ - 'signatureValidation' | _ - 'requiredValidUntil' | _ + filterType | _ + 'entityAttributes' | _ + 'entityRoleWhiteList' | _ + 'signatureValidation' | _ + 'requiredValidUntil' | _ } def "FilterController.update filter 409's if the version numbers don't match"() { @@ -223,6 +225,7 @@ class MetadataFiltersControllerTests extends Specification { originalMetadataResolver.getMetadataFilters().add(randomFilter) 1 * metadataResolverRepository.findByResourceId(_) >> originalMetadataResolver + 1 * metadataFilterRepository.findByResourceId(_) >> randomFilter def filterUUID = randomFilter.getResourceId() @@ -235,4 +238,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/controller/MetadataResolversControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy index 25071cb98..3ceb55417 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy @@ -255,6 +255,33 @@ class MetadataResolversControllerIntegrationTests extends Specification { createdResolver.metadataFilters[0] instanceof EntityAttributesFilter } + def "PUT MetadataResolver with one EntityAttributesFilters attached and check version -> /api/MetadataResolvers"() { + given: 'MetadataResolver with attached entity attributes is available in data store' + def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') + resolver.metadataFilters << generator.entityAttributesFilter() + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + when: 'GET request is made with resource Id matching the existing resolver' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId", String) + def existingMetadataResolverMap = new JsonSlurper().parseText(result.body) + def existingMetadataVersion = existingMetadataResolverMap.version + + and: 'PUT call is made with' + existingMetadataResolverMap.name = 'Updated' + def updatedResultFromPUT = this.restTemplate.exchange( + "$BASE_URI/${existingMetadataResolverMap.resourceId}", + PUT, + createRequestHttpEntityFor { JsonOutput.toJson(existingMetadataResolverMap) }, + String) + def updatedResultFromGET = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId", String) + def updatedVersionReturnedFromPUT = new JsonSlurper().parseText(updatedResultFromPUT.body).version + def updatedVersionReturnedFromGET = new JsonSlurper().parseText(updatedResultFromGET.body).version + + then: + updatedVersionReturnedFromPUT == updatedVersionReturnedFromGET + } + private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy index 56112a350..7841e045b 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy @@ -73,7 +73,6 @@ class PolymorphicFiltersJacksonHandlingTests extends Specification { def simulatedPrePersistentFilter = new EntityAttributesFilter() simulatedPrePersistentFilter.attributeRelease = simulatedPersistentFilter.attributeRelease simulatedPrePersistentFilter.relyingPartyOverrides = simulatedPersistentFilter.relyingPartyOverrides - simulatedPrePersistentFilter.fromTransientRepresentation() expect: simulatedPersistentFilter.attributes.size() == simulatedPrePersistentFilter.attributes.size() diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index 646d3e4aa..872182ce8 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -88,9 +88,6 @@ class MetadataResolverRepositoryTests extends Specification { } MetadataResolver metadataResolver = metadataResolverRepository.findAll().iterator().next() - //convert before saving into database - filter.fromTransientRepresentation() - metadataResolver.getMetadataFilters().add(filter) MetadataResolver persistedMr = metadataResolverRepository.save(metadataResolver) @@ -141,8 +138,6 @@ class MetadataResolverRepositoryTests extends Specification { filterToBeUpdated.relyingPartyOverrides = filter.relyingPartyOverrides filterToBeUpdated.attributeRelease = filter.attributeRelease - //convert before saving into database - filterToBeUpdated.fromTransientRepresentation() entityManager.clear() persistedMr = metadataResolverRepository.save(metadataResolver)