From 9a545d5802320be4404bd871bff5a8fa817616cb Mon Sep 17 00:00:00 2001 From: chasegawa Date: Wed, 21 Jun 2023 10:55:15 -0700 Subject: [PATCH 1/9] SHIBUI-2586 Added logging output when data is sent to beacon --- .../admin/ui/scheduled/BeaconReportingTask.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java index 5c25c8603..65d430b40 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.scheduled; import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService; +import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.beans.factory.annotation.Autowired; @@ -14,11 +15,13 @@ import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.List; @Configuration @ConditionalOnProperty(name = "shibui.beacon.enabled", matchIfMissing=true) @EnableSchedulerLock(defaultLockAtMostFor = "${shibui.maxTask.lockTime:30m}") +@Slf4j public class BeaconReportingTask { @Autowired IBeaconDataService dataService; @@ -38,11 +41,13 @@ public void sendBeaconData() { con.setRequestProperty("Content-Type", "application/json; utf-8"); con.setRequestProperty("Accept", "application/json"); con.setDoOutput(true); - try(OutputStream os = con.getOutputStream()){ - byte[] input = dataService.getBeaconData().getBytes("utf-8"); + try (OutputStream os = con.getOutputStream()) { + byte[] input = dataService.getBeaconData().getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } - } catch (IOException e) { + log.info("TIER Beacon data sent to {} with response code: {}", url, con.getResponseCode()); + } + catch (IOException e) { e.printStackTrace(); } }); From 783557d8e6553b1f700b6ce5410bc704fae07ced Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 29 Jun 2023 13:53:25 -0700 Subject: [PATCH 2/9] SHIBUI-2584 Added additional beacon data collection --- .../CoreShibUiConfiguration.java | 7 ++- .../ui/controller/ActivateController.java | 13 ++++- .../controller/MetadataFiltersController.java | 22 +++++---- .../MetadataResolversController.java | 25 ++++++---- .../admin/ui/domain/beacon/BeaconEvent.java | 30 ++++++++++++ .../ui/domain/beacon/BeaconEventType.java | 7 +++ .../ui/repository/BeaconEventRepository.java | 7 +++ .../ui/service/BeaconDataServiceImpl.java | 24 ++++++++-- .../admin/ui/service/IBeaconDataService.java | 5 ++ .../JPAEntityDescriptorServiceImpl.java | 19 +++++++- .../ui/service/JPAFilterServiceImpl.java | 3 ++ .../ui/BaseDataJpaTestConfiguration.groovy | 48 ++++++++++++++++++- .../MetadataFiltersControllerTests.groovy | 5 ++ 13 files changed, 183 insertions(+), 32 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEvent.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index 88607722e..92f0210d6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -4,6 +4,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.BeaconConfiguration; import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconConfigurationRepository; +import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconEventRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.FilterRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; @@ -46,7 +47,6 @@ import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions; import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; -import org.apache.commons.lang3.StringUtils; import org.apache.lucene.analysis.Analyzer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -67,7 +67,6 @@ import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; @@ -285,8 +284,8 @@ public String getBeaconCronValue(BeaconConfigurationRepository repo) public IBeaconDataService getBeaconDataService(@Value("${shibui.beacon.productName:ShibUi}") String productName, InfoEndpoint info, @Value("#{environment.TIERVERSION}") String tierVersion, EntityDescriptorRepository entityDescriptorRepository, MetadataResolverRepository metadataResolverRepository, FilterRepository filterRepository, GroupsRepository groupsRepository, RoleRepository roleRepository, BeaconConfigurationRepository beaconConfigurationRepository, - UserService userService, HealthEndpoint healthEndpoint) { - BeaconDataServiceImpl result = new BeaconDataServiceImpl(productName, info, tierVersion, entityDescriptorRepository, metadataResolverRepository, filterRepository, groupsRepository, roleRepository, beaconConfigurationRepository, userService, healthEndpoint); + UserService userService, HealthEndpoint healthEndpoint, BeaconEventRepository beaconEventRepository) { + BeaconDataServiceImpl result = new BeaconDataServiceImpl(productName, info, tierVersion, entityDescriptorRepository, metadataResolverRepository, filterRepository, groupsRepository, roleRepository, beaconConfigurationRepository, userService, healthEndpoint, beaconEventRepository); return result; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateController.java index c3d69d88b..2d22a172d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateController.java @@ -1,8 +1,9 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType; import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; -import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.DynamicRegistrationRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; @@ -12,6 +13,7 @@ import edu.internet2.tier.shibboleth.admin.ui.service.DynamicRegistrationService; import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService; import edu.internet2.tier.shibboleth.admin.ui.service.FilterService; +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tags; @@ -41,6 +43,9 @@ public class ActivateController { @Autowired private MetadataResolverService metadataResolverService; + + @Autowired + private IBeaconDataService beaconDataService; @PatchMapping(path = "/DynamicRegistration/{resourceId}/{mode}") @Transactional @@ -70,6 +75,9 @@ public ResponseEntity enableEntityDescriptor(@PathVariable String resourceId, 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); + if (status) { + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_FILTER_ENABLED)); + } return ResponseEntity.ok(persistedFilter); } @@ -78,6 +86,9 @@ public ResponseEntity enableFilter(@PathVariable String metadataResolverId, @ public ResponseEntity enableProvider(@PathVariable String resourceId, @PathVariable String mode) throws PersistentEntityNotFound, ForbiddenException, MetadataFileNotFoundException, InitializationException { boolean status = "enable".equalsIgnoreCase(mode); MetadataResolver metadataResolver = metadataResolverService.updateMetadataResolverEnabledStatus(resourceId, status); + if (status) { + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_PROVIDER_ENABLED)); + } return ResponseEntity.ok(metadataResolver); } } \ No newline at end of file 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 f61e82508..62f54310e 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,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType; 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; @@ -7,6 +9,7 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; 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.IBeaconDataService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tags; @@ -46,6 +49,9 @@ public class MetadataFiltersController { private static final Supplier HTTP_400_BAD_REQUEST_EXCEPTION = () -> new HttpClientErrorException(BAD_REQUEST); private static final Supplier HTTP_404_CLIENT_ERROR_EXCEPTION = () -> new HttpClientErrorException(NOT_FOUND); + @Autowired + private IBeaconDataService beaconDataService; + @Autowired org.opensaml.saml.metadata.resolver.MetadataResolver chainingMetadataResolver; @@ -77,16 +83,13 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques reloadFiltersAndHandleScriptException(persistedMr.getResourceId()); MetadataFilter persistedFilter = newlyPersistedFilter(persistedMr.getMetadataFilters().stream(), createdFilter.getResourceId()); - - return ResponseEntity - .created(getResourceUriFor(persistedMr, createdFilter.getResourceId())) - .body(persistedFilter); + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_FILTER_CREATED)); + return ResponseEntity.created(getResourceUriFor(persistedMr, createdFilter.getResourceId())).body(persistedFilter); } @DeleteMapping("/Filters/{resourceId}") @Transactional - public ResponseEntity delete(@PathVariable String metadataResolverId, - @PathVariable String resourceId) { + public ResponseEntity delete(@PathVariable String metadataResolverId, @PathVariable String resourceId) { MetadataResolver resolver = findResolverOrThrowHttp404(metadataResolverId); MetadataFilter filterToDelete = findFilterOrThrowHttp404(resourceId); @@ -109,6 +112,7 @@ public ResponseEntity delete(@PathVariable String metadataResolverId, //TODO: do we need to reload filters here?!? //metadataResolverService.reloadFilters(persistedMr.getName()); + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_FILTER_REMOVED)); return ResponseEntity.noContent().build(); } @@ -188,9 +192,7 @@ private void reloadFiltersAndHandleScriptException(String resolverResourceId) { @PutMapping("/Filters/{resourceId}") @Transactional - public ResponseEntity update(@PathVariable String metadataResolverId, - @PathVariable String resourceId, - @RequestBody MetadataFilter updatedFilter) { + public ResponseEntity update(@PathVariable String metadataResolverId, @PathVariable String resourceId, @RequestBody MetadataFilter updatedFilter) { MetadataResolver metadataResolver = findResolverOrThrowHttp404(metadataResolverId); @@ -228,7 +230,7 @@ public ResponseEntity update(@PathVariable String metadataResolverId, // TODO: do we need to reload filters here? reloadFiltersAndHandleScriptException(metadataResolver.getResourceId()); - + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_FILTER_MODIFIED)); return ResponseEntity.ok().body(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 51d0d4753..05ce3eb55 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 @@ -1,12 +1,15 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType; import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException; 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.domain.resolvers.validator.MetadataResolverValidationService; import edu.internet2.tier.shibboleth.admin.ui.domain.versioning.Version; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService; import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; @@ -52,27 +55,29 @@ @Slf4j @Tags(value = {@Tag(name = "metadata resolvers")}) public class MetadataResolversController { + @Autowired + private IBeaconDataService beaconDataService; @Autowired - MetadataResolverRepository resolverRepository; + org.opensaml.saml.metadata.resolver.MetadataResolver chainingMetadataResolver; @Autowired - MetadataResolverValidationService metadataResolverValidationService; + IndexWriterService indexWriterService; @Autowired - MetadataResolverService metadataResolverService; + MetadataResolverConverterService metadataResolverConverterService; @Autowired - MetadataResolversPositionOrderContainerService positionOrderContainerService; + MetadataResolverService metadataResolverService; @Autowired - IndexWriterService indexWriterService; + MetadataResolverValidationService metadataResolverValidationService; @Autowired - org.opensaml.saml.metadata.resolver.MetadataResolver chainingMetadataResolver; + MetadataResolversPositionOrderContainerService positionOrderContainerService; @Autowired - MetadataResolverConverterService metadataResolverConverterService; + MetadataResolverRepository resolverRepository; @Autowired MetadataResolverVersionService versionService; @@ -156,7 +161,7 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) throw MetadataResolver persistedResolver = resolverRepository.save(newResolver); positionOrderContainerService.appendPositionOrderForNew(persistedResolver); doResolverInitialization(persistedResolver); - + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_PROVIDER_CREATED)); return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } @@ -168,8 +173,7 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me return ResponseEntity.notFound().build(); } if (existingResolver.getVersion() != updatedResolver.getVersion()) { - log.info("Metadata Resolver version conflict. Latest resolver in database version: {}. Resolver version sent from UI: {}", - existingResolver.getVersion(), updatedResolver.getVersion()); + log.info("Metadata Resolver version conflict. Latest resolver in database version: {}. Resolver version sent from UI: {}", existingResolver.getVersion(), updatedResolver.getVersion()); return ResponseEntity.status(HttpStatus.CONFLICT).build(); } @@ -182,6 +186,7 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); doResolverInitialization(persistedResolver); + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_PROVIDER_MODIFIED)); return ResponseEntity.ok(resolverRepository.findByResourceId(resourceId)); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEvent.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEvent.java new file mode 100644 index 000000000..74eb6cf40 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEvent.java @@ -0,0 +1,30 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.beacon; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import java.util.Date; + +@Entity +@Data +public class BeaconEvent { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private Long id; + + private Date eventTime; + + private String eventName; + + public BeaconEvent() { + eventTime = new Date(); + } + + public BeaconEvent(BeaconEventType eventType) { + eventTime = new Date(); + this.eventName = eventType.name(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java new file mode 100644 index 000000000..6856ea4a5 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java @@ -0,0 +1,7 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.beacon; + +public enum BeaconEventType { + METADATA_SOURCE_MODIFIED, METADATA_SOURCE_REMOVED, METADATA_SOURCE_ENABLED, METADATA_SOURCE_CREATED, + METADATA_PROVIDER_MODIFIED, METADATA_PROVIDER_REMOVED, METADATA_PROVIDER_ENABLED, METADATA_PROVIDER_CREATED, + METADATA_FILTER_MODIFIED, METADATA_FILTER_REMOVED, METADATA_FILTER_ENABLED, METADATA_FILTER_CREATED +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java new file mode 100644 index 000000000..966b295cf --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java @@ -0,0 +1,7 @@ +package edu.internet2.tier.shibboleth.admin.ui.repository; + +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BeaconEventRepository extends JpaRepository { +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java index 97cb5f06d..962b9e6e1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java @@ -2,23 +2,26 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; -import edu.internet2.tier.shibboleth.admin.ui.service.beacon.BeaconDetail; -import edu.internet2.tier.shibboleth.admin.ui.service.beacon.ShibuiDetail; import edu.internet2.tier.shibboleth.admin.ui.domain.BeaconConfiguration; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType; import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconConfigurationRepository; +import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconEventRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; 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.repository.GroupsRepository; import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository; import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService; +import edu.internet2.tier.shibboleth.admin.ui.service.beacon.BeaconDetail; +import edu.internet2.tier.shibboleth.admin.ui.service.beacon.ShibuiDetail; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.info.InfoEndpoint; +import org.springframework.stereotype.Service; import java.util.Arrays; -import java.util.HashMap; import java.util.Map; public class BeaconDataServiceImpl implements IBeaconDataService { @@ -35,11 +38,12 @@ public class BeaconDataServiceImpl implements IBeaconDataService { private RoleRepository roleRepository; private BeaconConfigurationRepository beaconConfigurationRepository; private UserService userService; + private BeaconEventRepository beaconEventRepository; public BeaconDataServiceImpl(String productName, InfoEndpoint info, String tierVersion, EntityDescriptorRepository entityDescriptorRepository, MetadataResolverRepository metadataResolverRepository, FilterRepository filterRepository, GroupsRepository groupsRepository, RoleRepository roleRepository, BeaconConfigurationRepository beaconConfigurationRepository, UserService userService, - HealthEndpoint health) { + HealthEndpoint health, BeaconEventRepository beaconEventRepository) { mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // skip any null values @@ -56,16 +60,26 @@ public BeaconDataServiceImpl(String productName, InfoEndpoint info, String tierV this.roleRepository = roleRepository; this.beaconConfigurationRepository = beaconConfigurationRepository; this.userService = userService; + this.beaconEventRepository = beaconEventRepository; } @Override @SneakyThrows public String getBeaconData() { BeaconDetail detail = new BeaconDetail().setTbProduct(productName).setTbProductVersion(version).setTbTIERRelease(tierVersion).setShibui(getShibuiDetailData()); - return mapper.writeValueAsString(detail); } + @Override + public void addBeaconEvent(BeaconEvent event) { + beaconEventRepository.save(event); + } + + @Override + public void addEntityDescEnabledEvent() { + addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_SOURCE_ENABLED)); + } + private ShibuiDetail getShibuiDetailData() { BeaconConfiguration configuration = beaconConfigurationRepository.getReferenceById(1); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java index 4509b0584..ccbd4563e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java @@ -1,7 +1,12 @@ package edu.internet2.tier.shibboleth.admin.ui.service; import com.fasterxml.jackson.core.JsonProcessingException; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; public interface IBeaconDataService { String getBeaconData() throws JsonProcessingException; + + void addBeaconEvent(BeaconEvent event); + + void addEntityDescEnabledEvent(); } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java index 93a1dbce6..2d31663b3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java @@ -10,6 +10,8 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.X509Data; import edu.internet2.tier.shibboleth.admin.ui.domain.XSBoolean; import edu.internet2.tier.shibboleth.admin.ui.domain.XSInteger; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.AssertionConsumerServiceRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.ContactRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation; @@ -72,6 +74,9 @@ @Slf4j @Service public class JPAEntityDescriptorServiceImpl implements EntityDescriptorService { + @Autowired + private IBeaconDataService beaconDataService; + @Autowired private EntityDescriptorRepository entityDescriptorRepository; @@ -257,6 +262,10 @@ public EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation e ownershipRepository.deleteEntriesForOwnedObject(ed); ownershipRepository.save(new Ownership(userService.getCurrentUserGroup(), ed)); + if(ed.isServiceEnabled()) { + beaconDataService.addEntityDescEnabledEvent(); + } + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_SOURCE_CREATED)); return createRepresentationFromDescriptor(entityDescriptorRepository.save(ed)); } @@ -274,6 +283,7 @@ public EntityDescriptorRepresentation createNewEntityDescriptorFromXMLOrigin(Ent ed.setApproved(true); } EntityDescriptor savedEntity = entityDescriptorRepository.save(ed); + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_SOURCE_CREATED)); return createRepresentationFromDescriptor(savedEntity); } @@ -468,7 +478,7 @@ public void delete(String resourceId) throws ForbiddenException, PersistentEntit } ownershipRepository.deleteEntriesForOwnedObject(ed); entityDescriptorRepository.delete(ed); - + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_SOURCE_REMOVED)); } private EntityDescriptorProtocol determineEntityDescriptorProtocol(EntityDescriptor ed) { @@ -640,6 +650,8 @@ public EntityDescriptorRepresentation update(EntityDescriptorRepresentation edRe } validateEntityIdAndACSUrls(edRep); + boolean updateEnablesEd = !existingEd.isServiceEnabled() && edRep.isServiceEnabled(); + updateDescriptorFromRepresentation(existingEd, edRep); existingEd = entityDescriptorRepository.save(existingEd); ownershipRepository.deleteEntriesForOwnedObject(existingEd); @@ -647,6 +659,10 @@ public EntityDescriptorRepresentation update(EntityDescriptorRepresentation edRe public String getOwnerId() { return edRep.getIdOfOwner(); } public OwnerType getOwnerType() { return OwnerType.GROUP; } }, existingEd)); + if (updateEnablesEd) { + beaconDataService.addEntityDescEnabledEvent(); + } + beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_SOURCE_MODIFIED)); return createRepresentationFromDescriptor(existingEd); } @@ -680,6 +696,7 @@ public EntityDescriptorRepresentation updateEntityDescriptorEnabledStatus(String ed.setServiceEnabled(enabled); if (enabled == true) { ed.setApproved(true); + beaconDataService.addEntityDescEnabledEvent(); } ed = entityDescriptorRepository.save(ed); return createRepresentationFromDescriptor(ed); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAFilterServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAFilterServiceImpl.java index 03a72602e..ddfeef564 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAFilterServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAFilterServiceImpl.java @@ -28,6 +28,9 @@ */ @Service public class JPAFilterServiceImpl implements FilterService { + @Autowired + IBeaconDataService beaconDataService; + @Autowired EntityDescriptorService entityDescriptorService; diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy index 97e826003..c8432661a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/BaseDataJpaTestConfiguration.groovy @@ -9,7 +9,11 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.StringTrimModule import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconConfigurationRepository +import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconEventRepository import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository +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.listener.GroupUpdatedEntityListener import edu.internet2.tier.shibboleth.admin.ui.security.model.listener.UserUpdatedEntityListener import edu.internet2.tier.shibboleth.admin.ui.security.permission.IShibUiPermissionEvaluator @@ -17,13 +21,26 @@ import edu.internet2.tier.shibboleth.admin.ui.security.permission.ShibUiPermissi import edu.internet2.tier.shibboleth.admin.ui.security.repository.DynamicRegistrationInfoRepository import edu.internet2.tier.shibboleth.admin.ui.security.repository.GroupsRepository import edu.internet2.tier.shibboleth.admin.ui.security.repository.OwnershipRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository import edu.internet2.tier.shibboleth.admin.ui.security.service.GroupServiceForTesting import edu.internet2.tier.shibboleth.admin.ui.security.service.GroupServiceImpl import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService +import edu.internet2.tier.shibboleth.admin.ui.service.BeaconDataServiceImpl +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityServiceImpl import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions +import org.springframework.boot.actuate.endpoint.annotation.Selector +import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry +import org.springframework.boot.actuate.health.Health +import org.springframework.boot.actuate.health.HealthComponent +import org.springframework.boot.actuate.health.HealthEndpoint +import org.springframework.boot.actuate.health.HealthEndpointGroup +import org.springframework.boot.actuate.health.HealthEndpointGroups +import org.springframework.boot.actuate.health.Status +import org.springframework.boot.actuate.info.InfoContributor +import org.springframework.boot.actuate.info.InfoEndpoint import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration @@ -111,7 +128,36 @@ class BaseDataJpaTestConfiguration { } @Bean - public IShibUiPermissionEvaluator shibUiPermissionEvaluator(DynamicRegistrationInfoRepository driRepo, EntityDescriptorRepository entityDescriptorRepository, UserService userService) { + IShibUiPermissionEvaluator shibUiPermissionEvaluator(DynamicRegistrationInfoRepository driRepo, EntityDescriptorRepository entityDescriptorRepository, UserService userService) { return new ShibUiPermissionDelegate(driRepo, entityDescriptorRepository, userService); } + + @Bean + InfoEndpoint getInfoEndpoint() { + return new InfoEndpoint(new ArrayList()); + } + + @Bean + HealthEndpoint getHealthEndpoint() { + return new HealthEndpoint(new DefaultHealthContributorRegistry(), new HealthEndpointGroups() { + @Override HealthEndpointGroup getPrimary() { return null } + + @Override Set getNames() { return null } + + @Override HealthEndpointGroup get(String name) { return null } + }) { + @Override + HealthComponent healthForPath(@Selector(match = Selector.Match.ALL_REMAINING) String... path) { + return new Health(new Status(""), new HashMap()); + } + } + } + + @Bean + IBeaconDataService getBeaconDataService(InfoEndpoint info, EntityDescriptorRepository entityDescriptorRepository, MetadataResolverRepository metadataResolverRepository, FilterRepository filterRepository, + GroupsRepository groupsRepository, RoleRepository roleRepository, BeaconConfigurationRepository beaconConfigurationRepository, + UserService userService, HealthEndpoint healthEndpoint, BeaconEventRepository beaconEventRepository) { + BeaconDataServiceImpl result = new BeaconDataServiceImpl("SHIBUI_UNIT_TESTS", info, "NA", entityDescriptorRepository, metadataResolverRepository, filterRepository, groupsRepository, roleRepository, beaconConfigurationRepository, userService, healthEndpoint, beaconEventRepository); + return result; + } } \ 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 1107af074..a666f102b 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 @@ -15,6 +15,7 @@ import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects 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.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityServiceImpl import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator @@ -47,6 +48,9 @@ class MetadataFiltersControllerTests extends AbstractBaseDataJpaTest { @Autowired AttributeUtility attributeUtility + @Autowired + private IBeaconDataService beaconDataService + @Autowired CustomPropertiesConfiguration customPropertiesConfiguration @@ -77,6 +81,7 @@ class MetadataFiltersControllerTests extends AbstractBaseDataJpaTest { controller = new MetadataFiltersController ( repository: metadataResolverRepository, filterRepository: metadataFilterRepository, + beaconDataService: beaconDataService, groupService: groupService, userService: userService, metadataResolverService: new MetadataResolverService() { From 888131990501ab0437dedb7dd4c786c33fda550e Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 29 Jun 2023 16:37:57 -0700 Subject: [PATCH 3/9] SHIBUI-2584 Added additional beacon data collection to the output --- .../admin/ui/repository/BeaconEventRepository.java | 9 +++++++++ .../admin/ui/service/BeaconDataServiceImpl.java | 14 ++++++++++++-- .../admin/ui/service/beacon/BeaconDetail.java | 6 ++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java index 966b295cf..a6e2ee483 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/BeaconEventRepository.java @@ -2,6 +2,15 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.List; public interface BeaconEventRepository extends JpaRepository { + + @Query(value = "SELECT be FROM BeaconEvent be WHERE be.eventTime >= :sinceDate") + List getEventsSince(@Param("sinceDate") Date sinceDate); + } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java index 962b9e6e1..45b6ff2ff 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java @@ -16,13 +16,17 @@ import edu.internet2.tier.shibboleth.admin.ui.service.beacon.BeaconDetail; import edu.internet2.tier.shibboleth.admin.ui.service.beacon.ShibuiDetail; import lombok.SneakyThrows; +import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.info.InfoEndpoint; -import org.springframework.stereotype.Service; import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class BeaconDataServiceImpl implements IBeaconDataService { private ObjectMapper mapper; @@ -66,10 +70,16 @@ public BeaconDataServiceImpl(String productName, InfoEndpoint info, String tierV @Override @SneakyThrows public String getBeaconData() { - BeaconDetail detail = new BeaconDetail().setTbProduct(productName).setTbProductVersion(version).setTbTIERRelease(tierVersion).setShibui(getShibuiDetailData()); + BeaconDetail detail = new BeaconDetail().setTbProduct(productName).setTbProductVersion(version).setTbTIERRelease(tierVersion).setShibui(getShibuiDetailData()).setBeaconEvents(getBeaconEvents()); return mapper.writeValueAsString(detail); } + private Map getBeaconEvents() { + List results = beaconEventRepository.getEventsSince(DateUtils.addDays(new Date(), -1)); + Map counts = results.stream().collect(Collectors.groupingBy(e -> e.getEventName(), Collectors.counting())); + return counts; + } + @Override public void addBeaconEvent(BeaconEvent event) { beaconEventRepository.save(event); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/beacon/BeaconDetail.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/beacon/BeaconDetail.java index bef94540f..78503cf50 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/beacon/BeaconDetail.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/beacon/BeaconDetail.java @@ -1,8 +1,12 @@ package edu.internet2.tier.shibboleth.admin.ui.service.beacon; +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; import lombok.Data; import lombok.experimental.Accessors; +import java.util.List; +import java.util.Map; + @Data @Accessors(chain = true) public class BeaconDetail { @@ -16,4 +20,6 @@ public class BeaconDetail { private String tbMaintainer = "Unicon"; private ShibuiDetail shibui; + + private Map beaconEvents; } \ No newline at end of file From 4e2282c2226de67118cb55e1076ba78ca3784b41 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 29 Jun 2023 16:46:12 -0700 Subject: [PATCH 4/9] SHIBUI-2584 Added additional beacon data collection to the output --- .../tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java index 6856ea4a5..ae108ae89 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/beacon/BeaconEventType.java @@ -2,6 +2,6 @@ public enum BeaconEventType { METADATA_SOURCE_MODIFIED, METADATA_SOURCE_REMOVED, METADATA_SOURCE_ENABLED, METADATA_SOURCE_CREATED, - METADATA_PROVIDER_MODIFIED, METADATA_PROVIDER_REMOVED, METADATA_PROVIDER_ENABLED, METADATA_PROVIDER_CREATED, + METADATA_PROVIDER_MODIFIED, METADATA_PROVIDER_ENABLED, METADATA_PROVIDER_CREATED, METADATA_FILTER_MODIFIED, METADATA_FILTER_REMOVED, METADATA_FILTER_ENABLED, METADATA_FILTER_CREATED } \ No newline at end of file From f9968481ca04628c663bf825521c5047f7c73329 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Fri, 30 Jun 2023 13:05:35 -0700 Subject: [PATCH 5/9] SHIBUI-2584 Added beacon data collection unit testing --- .../MetadataResolversController.java | 1 + .../ui/service/BeaconDataServiceImpl.java | 4 +-- .../admin/ui/service/IBeaconDataService.java | 4 +++ .../controller/ActivateControllerTests.groovy | 24 +++++++++++-- .../EntityDescriptorControllerTests.groovy | 36 +++++++++++++++++++ ...taFiltersControllerIntegrationTests.groovy | 20 ++++++++++- .../MetadataFiltersControllerTests.groovy | 6 ++-- ...ResolversControllerIntegrationTests.groovy | 18 ++++++++++ 8 files changed, 106 insertions(+), 7 deletions(-) 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 05ce3eb55..ca065e7b2 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 @@ -162,6 +162,7 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) throw positionOrderContainerService.appendPositionOrderForNew(persistedResolver); doResolverInitialization(persistedResolver); beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_PROVIDER_CREATED)); + newResolver.getMetadataFilters().forEach(f -> beaconDataService.addBeaconEvent(new BeaconEvent(BeaconEventType.METADATA_FILTER_CREATED))); return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java index 45b6ff2ff..13657aae6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/BeaconDataServiceImpl.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -74,7 +73,8 @@ public String getBeaconData() { return mapper.writeValueAsString(detail); } - private Map getBeaconEvents() { + @Override + public Map getBeaconEvents() { List results = beaconEventRepository.getEventsSince(DateUtils.addDays(new Date(), -1)); Map counts = results.stream().collect(Collectors.groupingBy(e -> e.getEventName(), Collectors.counting())); return counts; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java index ccbd4563e..1b0615945 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IBeaconDataService.java @@ -3,9 +3,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEvent; +import java.util.Map; + public interface IBeaconDataService { String getBeaconData() throws JsonProcessingException; + Map getBeaconEvents(); + void addBeaconEvent(BeaconEvent event); void addEntityDescEnabledEvent(); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateControllerTests.groovy index 6354f5538..e79ec24ef 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateControllerTests.groovy @@ -3,6 +3,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType import edu.internet2.tier.shibboleth.admin.ui.domain.oidc.DynamicRegistrationInfo import edu.internet2.tier.shibboleth.admin.ui.domain.oidc.GrantType import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException @@ -16,6 +17,7 @@ import edu.internet2.tier.shibboleth.admin.ui.security.repository.DynamicRegistr import edu.internet2.tier.shibboleth.admin.ui.service.DynamicRegistrationService import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService import edu.internet2.tier.shibboleth.admin.ui.service.EntityService +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.util.WithMockAdmin import edu.internet2.tier.shibboleth.admin.util.EntityDescriptorConversionUtils import org.springframework.beans.factory.annotation.Autowired @@ -34,6 +36,9 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { @Subject def controller + @Autowired + private IBeaconDataService service + @Autowired ObjectMapper mapper @@ -114,9 +119,9 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { entityManager.clear() EntityDescriptor entityDescriptor = new EntityDescriptor(resourceId: 'uuid-1', entityID: 'eid1', serviceProviderName: 'sp1', serviceEnabled: false, idOfOwner: 'AAA') - entityDescriptor = entityDescriptorRepository.save(entityDescriptor) + def edRep = entDescriptorService.createNew(entityDescriptor) - defaultEntityDescriptorResourceId = entityDescriptor.getResourceId() + defaultEntityDescriptorResourceId = edRep.id def dynReg = new DynamicRegistrationInfo(resourceId: 'uuid-1', enabled: false, idOfOwner: "AAA", applicationType: 'apptype', approved: true, contacts: 'contacts', jwks: 'jwks', logoUri: 'logouri', policyUri: 'policyuri', @@ -145,6 +150,8 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()) == null } @WithMockUser(value = "DUser", roles = ["USER"]) @@ -156,10 +163,17 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()) == null } @WithMockUser(value = "DUser", roles = ["USER"]) def 'non-owner group cannot activate entity descriptor'() { + given: + EntityDescriptor ed = entityDescriptorRepository.findByResourceId(defaultEntityDescriptorResourceId) + ed.setIdOfOwner('AAA') + entityDescriptorRepository.saveAndFlush(ed) + expect: try { mockMvc.perform(patch("/api/activate/entityDescriptor/" + defaultEntityDescriptorResourceId + "/enable")) @@ -167,6 +181,8 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()) == null } // @WithMockAdmin @@ -196,6 +212,8 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { result.andExpect(status().isOk()) .andExpect(jsonPath("\$.id").value(defaultEntityDescriptorResourceId)) .andExpect(jsonPath("\$.serviceEnabled").value(true)) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()).longValue() == 1 } // @WithMockUser(value = "AUser", roles = ["USER"]) @@ -231,5 +249,7 @@ class ActivateControllerTests extends AbstractBaseDataJpaTest { result.andExpect(status().isOk()) .andExpect(jsonPath("\$.id").value('uuid-2')) .andExpect(jsonPath("\$.serviceEnabled").value(true)) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()).longValue() == 1 } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy index e5f542e3a..5e85f1a47 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy @@ -3,6 +3,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.AssertionConsumerServiceRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException @@ -17,6 +18,7 @@ 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.service.EntityDescriptorVersionService import edu.internet2.tier.shibboleth.admin.ui.service.EntityService +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityDescriptorServiceImpl import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator import edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers @@ -50,6 +52,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { + @Autowired + private IBeaconDataService service + @Autowired EntityDescriptorRepository entityDescriptorRepository @@ -235,6 +240,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { } catch (NestedServletException expected) { expected.getCause() instanceof InvalidPatternMatchException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()) == null } @WithMockUser(value = "someUser", roles = ["USER"]) @@ -264,6 +271,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath("\$.serviceEnabled").value(false)) .andExpect(jsonPath("\$.idOfOwner").value("testingGroupBBB")) + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 + when: "ACS url is bad" expectedEntityId = 'https://shib.org/blah/blah/again' edRep = new EntityDescriptorRepresentation() @@ -285,6 +294,9 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { } catch (NestedServletException expected) { expected.getCause() instanceof InvalidPatternMatchException } + + // Still just the one + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -321,6 +333,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath("\$.entityId").value("https://shib")) .andExpect(jsonPath("\$.serviceEnabled").value(true)) .andExpect(jsonPath("\$.idOfOwner").value("admingroup")) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 } @WithMockUser(value = "someUser", roles = ["USER"]) @@ -357,6 +371,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_ENABLED.name()) == null } @WithMockAdmin @@ -397,6 +413,9 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ObjectIdExistsException } + + // because we created the test objects directly in the repository, there should be no beacon records + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()) == null } @WithMockAdmin @@ -587,12 +606,15 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath("\$.assertionConsumerServices[0].makeDefault").value(false)) .andExpect(jsonPath("\$.assertionConsumerServices[0].locationUrl").value("https://test.scaldingspoon.org/test1/acs")) + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 + try { mockMvc.perform(post("/api/EntityDescriptor").contentType(APPLICATION_XML).content(postedBody).param("spName", spName)) } catch (Exception e) { e instanceof ObjectIdExistsException } + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -632,6 +654,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ObjectIdExistsException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()) == null } @WithMockAdmin @@ -658,6 +682,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath("\$.serviceEnabled").value(false)) .andExpect(jsonPath("\$.idOfOwner").value("admingroup")) .andExpect(jsonPath("\$.serviceProviderName").value("newName")) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_MODIFIED.name()).longValue() == 1 } @WithMockUser(value = "someUser", roles = ["USER"]) @@ -683,6 +709,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_MODIFIED.name()) == null } @WithMockUser(value = "someUser", roles = ["USER"]) @@ -708,6 +736,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ForbiddenException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_MODIFIED.name()) == null } @WithMockAdmin @@ -731,6 +761,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { catch (Exception e) { e instanceof ConcurrentModificationException } + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_MODIFIED.name()) == null } @WithMockAdmin @@ -769,6 +801,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath(shortNameToOAuth + "defaultAcrValues").isArray()) .andExpect(jsonPath(shortNameToOAuth + "attributes.requireAuthTime").value(Boolean.FALSE)) .andExpect(jsonPath(shortNameToOAuth + "attributes.defaultMaxAge").value(Integer.valueOf(0))) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -825,6 +859,8 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { .andExpect(jsonPath(shortNameToOAuth + "defaultAcrValues").isArray()) .andExpect(jsonPath(shortNameToOAuth + "attributes.requireAuthTime").value(Boolean.FALSE)) .andExpect(jsonPath(shortNameToOAuth + "attributes.defaultMaxAge").value(Integer.valueOf(0))) + + service.getBeaconEvents().get(BeaconEventType.METADATA_SOURCE_CREATED.name()).longValue() == 1 } @SneakyThrows 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 index c5a843b22..2bb7c3660 100644 --- 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 @@ -4,10 +4,13 @@ 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.configuration.CustomPropertiesConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.repository.BeaconEventRepository import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility @@ -55,6 +58,12 @@ class MetadataFiltersControllerIntegrationTests extends Specification { @Autowired MetadataResolver chainingMetadataResolver + @Autowired + private IBeaconDataService beaconDataService + + @Autowired + private BeaconEventRepository beaconEventRepository + ObjectMapper mapper TestObjectGenerator generator @@ -71,6 +80,7 @@ class MetadataFiltersControllerIntegrationTests extends Specification { def cleanup() { metadataResolverRepository.deleteAll() + beaconEventRepository.deleteAll() } def "PUT EntityAttributesFilter"() { @@ -94,7 +104,9 @@ class MetadataFiltersControllerIntegrationTests extends Specification { createRequestHttpEntityFor { JsonOutput.toJson(existingFilterMap) }, String) then: - updatedResultFromPUT.statusCode.value() == 200 + updatedResultFromPUT.statusCode.value() == 200 + + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_MODIFIED.name()).longValue() == 1 } def "PUT EntityAttributesFilter and update it"() { @@ -120,6 +132,7 @@ class MetadataFiltersControllerIntegrationTests extends Specification { then: updatedResultFromPUT.statusCode.value() == 200 + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_MODIFIED.name()).longValue() == 1 } def "DELETE Filter"() { @@ -215,6 +228,7 @@ class MetadataFiltersControllerIntegrationTests extends Specification { } def "EntityAttributesFilter with invalid script does not result in persisting that filter"() { + given: def resolver = generator.buildRandomMetadataResolverOfType('FileBacked') def resolverResourceId = resolver.resourceId metadataResolverRepository.save(resolver) @@ -233,6 +247,9 @@ class MetadataFiltersControllerIntegrationTests extends Specification { it } + expect: + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_CREATED.name()) == null + when: def result = restTemplate.postForEntity("$BASE_URI/$resolverResourceId/Filters", filter, String) @@ -244,6 +261,7 @@ class MetadataFiltersControllerIntegrationTests extends Specification { then: result.body.metadataFilters.size == 0 + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_CREATED.name()) == null } private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { 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 a666f102b..48ecfc602 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 @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver @@ -244,8 +245,8 @@ class MetadataFiltersControllerTests extends AbstractBaseDataJpaTest { then: def expectedJson = new JsonSlurper().parseText(updatedFilterJson) expectedJson << [version: updatedFilter.getVersion()] - result.andExpect(status().isOk()) - .andExpect(content().json(JsonOutput.toJson(expectedJson), true)) + result.andExpect(status().isOk()).andExpect(content().json(JsonOutput.toJson(expectedJson), true)) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_MODIFIED.name()).longValue() == 1 where: filterType | _ @@ -281,6 +282,7 @@ class MetadataFiltersControllerTests extends AbstractBaseDataJpaTest { then: result.andExpect(status().is(409)) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_MODIFIED.name()) == null } @TestConfiguration 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 0f52dc668..a9ee46b25 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 @@ -8,6 +8,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConf import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConverterConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverValidationConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.beacon.BeaconEventType import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver @@ -20,6 +21,7 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolversPositi import edu.internet2.tier.shibboleth.admin.ui.service.DefaultMetadataResolversPositionOrderContainerService import edu.internet2.tier.shibboleth.admin.ui.service.DirectoryService import edu.internet2.tier.shibboleth.admin.ui.service.DirectoryServiceImpl +import edu.internet2.tier.shibboleth.admin.ui.service.IBeaconDataService import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService @@ -54,6 +56,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration, PlaceholderResolverComponentsConfiguration, MRCILocalConfig]) class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTest { + @Autowired + IBeaconDataService beaconDataService + @Autowired AttributeUtility attributeUtility @@ -112,6 +117,7 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: result.andExpect(status().isCreated()).andExpect(content().contentType(APPLICATION_JSON)) .andExpect(jsonPath("\$.name").value("HTTPMetadata")) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -213,6 +219,7 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: result.andExpect(status().isCreated()).andExpect(content().contentType(APPLICATION_JSON)) .andExpect(jsonPath("\$.name").value(expectedName)) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -232,6 +239,8 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes result.andExpect(status().isCreated()).andExpect(content().contentType(APPLICATION_JSON)) .andExpect(jsonPath("\$.['@type']").value(resolver.getType())) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_CREATED.name()).longValue() == 1 + cleanup: if (sourceDirectory != null) { def tmpDirectory = new File(sourceDirectory) @@ -266,6 +275,7 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: result.andExpect(status().isCreated()) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -293,6 +303,8 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes updatedResult.andExpect(status().isOk()).andExpect(content().contentType(APPLICATION_JSON)) .andExpect(jsonPath("\$.name").value('Updated Resolver Name')) + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_MODIFIED.name()).longValue() == 1 + cleanup: if (sourceDirectory != null) { def tmpDirectory = new File(sourceDirectory) @@ -339,6 +351,8 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: updatedResult.andExpect(status().isConflict()) + + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_MODIFIED.name()) == null } @WithMockAdmin @@ -362,6 +376,9 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: createdResolver.metadataFilters.size() == 1 createdResolver.metadataFilters[0] instanceof EntityAttributesFilter + + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_CREATED.name()).longValue() == 1 + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_FILTER_CREATED.name()).longValue() == 1 } @WithMockAdmin @@ -386,6 +403,7 @@ class MetadataResolversControllerIntegrationTests extends AbstractBaseDataJpaTes then: updatedResultFromPUT == updatedResultFromGET + beaconDataService.getBeaconEvents().get(BeaconEventType.METADATA_PROVIDER_MODIFIED.name()).longValue() == 1 } @TestConfiguration From 20a04a7ef2627b855f88d66095818c5ec5ca608b Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 6 Jul 2023 12:33:06 -0700 Subject: [PATCH 6/9] SHIBUI-2584 Correcting/updating the scheduler. Additional debug logging setup when data is sent. --- .../CoreShibUiConfiguration.java | 20 +++++++++++++++++-- .../configuration/auto/WebSecurityConfig.java | 2 +- .../admin/ui/controller/BeaconController.java | 3 ++- .../ui/scheduled/BeaconReportingTask.java | 4 +++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index 92f0210d6..1e5582651 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -45,6 +45,7 @@ import edu.internet2.tier.shibboleth.admin.util.EntityDescriptorConversionUtils; import edu.internet2.tier.shibboleth.admin.util.LuceneUtility; import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions; +import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; import org.apache.lucene.analysis.Analyzer; @@ -82,11 +83,13 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.Random; @Configuration @Import(SearchConfiguration.class) @ComponentScan(basePackages = "{ edu.internet2.tier.shibboleth.admin.ui.service }") @EnableConfigurationProperties({CustomPropertiesConfiguration.class, ShibUIConfiguration.class}) +@Slf4j public class CoreShibUiConfiguration { @Bean public OpenSamlObjects openSamlObjects() { @@ -276,8 +279,21 @@ public LockProvider lockProvider(DataSource dataSource) { @Bean public String getBeaconCronValue(BeaconConfigurationRepository repo) { - Optional bc = repo.findById(1); - return bc.isPresent() ? bc.get().getSendCron() : "0 3 * * * *"; + Optional obc = repo.findById(1); + BeaconConfiguration bc; + if (obc.isEmpty()) { + //set random cron in db + BeaconConfiguration newbc = new BeaconConfiguration(); + Random rand = new Random(); + String cron = "0 " + rand.nextInt(60) + " " + rand.nextInt(4) + " * * ?"; + newbc.setSendCron(cron); + repo.save(newbc); + bc = repo.findById(1).get(); + } else { + bc = obc.get(); + } + log.info("Scheduling beacon cron: {}", bc.getSendCron()); + return bc.getSendCron(); } @Bean diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java index 2b44f5b01..d62d76d43 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java @@ -93,7 +93,7 @@ protected void configure(HttpSecurity http) throws Exception { .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .authorizeRequests() - .antMatchers("/unsecured/**/*","/entities/**/*", "/health").permitAll() + .antMatchers("/unsecured/**/*","/entities/**/*", "/health", "/api/beacon/send").permitAll() .anyRequest().hasAnyRole(acceptedAuthenticationRoles) .and() .exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> response.sendRedirect("/unsecured/error.html")) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/BeaconController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/BeaconController.java index e41f17f39..9b047142b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/BeaconController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/BeaconController.java @@ -26,7 +26,8 @@ public ResponseEntity getDetail() throws JsonProcessingException { return ResponseEntity.ok(service.getBeaconData()); } - @PostMapping("/send") + // This should be a POST, but to make it easier to hit, this is a GET + @GetMapping("/send") public ResponseEntity forceSendBeaconData() { beaconReporter.sendBeaconData(); return ResponseEntity.ok("Manual push of beacon data completed"); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java index 65d430b40..92708363a 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/BeaconReportingTask.java @@ -36,16 +36,18 @@ public class BeaconReportingTask { public void sendBeaconData() { endpointUrls.forEach(url -> { try { + String dataOutput = dataService.getBeaconData(); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json; utf-8"); con.setRequestProperty("Accept", "application/json"); con.setDoOutput(true); try (OutputStream os = con.getOutputStream()) { - byte[] input = dataService.getBeaconData().getBytes(StandardCharsets.UTF_8); + byte[] input = dataOutput.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } log.info("TIER Beacon data sent to {} with response code: {}", url, con.getResponseCode()); + log.debug("TIER Beacon data load: {}", dataOutput); } catch (IOException e) { e.printStackTrace(); From 5991dba9389225b0b255ff2d9657e16e457b6926 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Wed, 12 Jul 2023 11:55:10 -0700 Subject: [PATCH 7/9] SHIBUI-2596 Adjustments to the cron for sending --- backend/src/main/app-resources/default.yml | 5 ++--- .../ui/configuration/CoreShibUiConfiguration.java | 12 ++++++++++-- .../admin/ui/domain/BeaconConfiguration.java | 4 ++++ backend/src/main/resources/application.properties | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/backend/src/main/app-resources/default.yml b/backend/src/main/app-resources/default.yml index 5ba247176..aa73f8627 100644 --- a/backend/src/main/app-resources/default.yml +++ b/backend/src/main/app-resources/default.yml @@ -24,14 +24,13 @@ ## Only set the installationID if you wish to define the ID used by the beacon. RECOMMENDED: ignore - a default random value will be used ## Only change the urls if instructed or if you wish to redirect for testing (if multiple, separate list with commas ## Only change the productName for testing purposes -## Set the cron time to send the beacon data at a specific time - if unset, the system will send at a random time between 12AM and 4AM once per day +## Set the cron time to send the beacon data at a specific time - if unset, the system will send at a random time between 12AM and 4AM once per day (random preferred) # beacon: # enabled: ture # installationID: [user-defined value] # urls: http://collector.testbed.tier.internet2.edu:5001 # productName: ShibUI -# send: -# cron: 0 4 * * * * +# cron: 0 59 3 * * ? # pac4j-enabled: true # pac4j: diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index 1e5582651..8e746bbf1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -277,7 +277,7 @@ public LockProvider lockProvider(DataSource dataSource) { } @Bean - public String getBeaconCronValue(BeaconConfigurationRepository repo) + public String getBeaconCronValue(BeaconConfigurationRepository repo, @Value("${shibui.beacon.cron}") String valueFromConfig) { Optional obc = repo.findById(1); BeaconConfiguration bc; @@ -286,8 +286,16 @@ public String getBeaconCronValue(BeaconConfigurationRepository repo) BeaconConfiguration newbc = new BeaconConfiguration(); Random rand = new Random(); String cron = "0 " + rand.nextInt(60) + " " + rand.nextInt(4) + " * * ?"; + if (valueFromConfig.endsWith("?")) { + cron = valueFromConfig; + } newbc.setSendCron(cron); - repo.save(newbc); + try { + repo.save(newbc); + } + catch(Exception e) { + log.debug("Error trying to create new BEACON CRON - should be ok"); + } bc = repo.findById(1).get(); } else { bc = obc.get(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BeaconConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BeaconConfiguration.java index c3b263c77..b78034dbf 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BeaconConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BeaconConfiguration.java @@ -6,6 +6,7 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Transient; +import javax.persistence.Version; @Data @Entity @@ -17,6 +18,9 @@ public class BeaconConfiguration { private String sendCron; + @Version + private Long version; + // Comma separated list of the auth mechanisms used. @Setter @Transient diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 14f726125..e46938360 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -123,6 +123,7 @@ shibui.beacon.enabled=true shibui.beacon.productName=ShibUi shibui.beacon.installationID=UNICON-SHIBUI-TESTING shibui.beacon.url=http://collector.testbed.tier.internet2.edu:5001 +#shibui.beacon.cron=0 59 3 * * ? ### Swagger/Springdoc patterns springdoc.use-management-port=true From 4b59d2639407245cb2cd1efa8757ed2c16adb557 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Wed, 12 Jul 2023 13:19:30 -0700 Subject: [PATCH 8/9] SHIBUI-2596 Fixing unit tests --- ...esUiDefinitionControllerIntegrationTests.groovy | 7 ++++++- ...ntrollerSchemaValidationIntegrationTests.groovy | 14 +++++++++++++- ...esUiDefinitionControllerIntegrationTests.groovy | 13 ++++++++++++- ...etadataFiltersControllerIntegrationTests.groovy | 8 +++++++- ...ntrollerSchemaValidationIntegrationTests.groovy | 13 ++++++++++++- ...sPositionOrderControllerIntegrationTests.groovy | 14 +++++++++++++- ...ntrollerSchemaValidationIntegrationTests.groovy | 14 ++++++++++++-- 7 files changed, 75 insertions(+), 8 deletions(-) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index d1a31e703..1acd0a080 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -26,7 +26,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResour /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) @ActiveProfiles(["no-auth", "badjson"]) class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Specification { @@ -48,6 +48,11 @@ class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Speci @TestConfiguration @Profile('badjson') static class Config { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + @Bean JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(ResourceLoader resourceLoader, ObjectMapper jacksonMapper) { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy index 3dc9fee6e..f7d38f69b 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy @@ -3,12 +3,15 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) +@Import([LocalConfig.class]) @ActiveProfiles(["no-auth", "dev"]) class EntityDescriptorControllerSchemaValidationIntegrationTests extends Specification { @@ -51,4 +54,13 @@ class EntityDescriptorControllerSchemaValidationIntegrationTests extends Specifi private static HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) } + + @org.springframework.boot.test.context.TestConfiguration + private static class LocalConfig { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + } + } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index 07bcefff5..0fa1b3545 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -3,13 +3,16 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import spock.lang.Specification /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) +@Import([LocalConfig.class]) @ActiveProfiles("no-auth") class GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Specification { @@ -26,4 +29,12 @@ class GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Spec result.statusCodeValue == 200 result.body.properties.entityId.title == 'label.entity-id' } + + @org.springframework.boot.test.context.TestConfiguration + private static class LocalConfig { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + } } \ No newline at end of file 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 index 2bb7c3660..176dd946f 100644 --- 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 @@ -36,7 +36,8 @@ import static org.springframework.http.HttpMethod.PUT * @author Dmitriy Kopylenko */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", - "shibui.beacon.productName=shibuiProdName"]) + "shibui.beacon.productName=shibuiProdName", + "shibui.beacon.cron=0 3 3 * * ?"]) @ActiveProfiles(["no-auth", "mfci-test"]) class MetadataFiltersControllerIntegrationTests extends Specification { @@ -279,5 +280,10 @@ class MetadataFiltersControllerIntegrationTests extends Specification { return it } } + + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy index 5dbc39d64..5e1849c72 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy @@ -6,12 +6,15 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverReposit import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) +@Import([LocalConfig.class]) @ActiveProfiles(["no-auth", "dev"]) class MetadataFiltersControllerSchemaValidationIntegrationTests extends Specification { @@ -99,4 +102,12 @@ class MetadataFiltersControllerSchemaValidationIntegrationTests extends Specific private static resourceUriFor(String uriTemplate, String resourceId) { String.format(uriTemplate, resourceId) } + + @org.springframework.boot.test.context.TestConfiguration + private static class LocalConfig { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy index e1ed71aa4..365e22e45 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy @@ -1,18 +1,22 @@ package edu.internet2.tier.shibboleth.admin.ui.controller + 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 org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import spock.lang.Specification /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) +@Import([LocalConfig.class]) @ActiveProfiles("no-auth") class MetadataFiltersPositionOrderControllerIntegrationTests extends Specification { @@ -145,4 +149,12 @@ class MetadataFiltersPositionOrderControllerIntegrationTests extends Specificati private static resourceUriFor(String resolverResourceId) { String.format(RESOURCE_URI, resolverResourceId) } + + @org.springframework.boot.test.context.TestConfiguration + private static class LocalConfig { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy index 1fc0374f8..bc9759d64 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy @@ -3,13 +3,17 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", - "shibui.beacon.productName=shibuiProdName"]) + "shibui.beacon.productName=shibuiProdName", + "shibui.beacon.cron=0 3 3 * * ?"]) +@Import([LocalConfig.class]) @ActiveProfiles(["no-auth", "dev"]) class MetadataResolverControllerSchemaValidationIntegrationTests extends Specification { @@ -148,5 +152,11 @@ class MetadataResolverControllerSchemaValidationIntegrationTests extends Specifi new HttpEntity(jsonBody, ['Content-Type': 'application/json'] as HttpHeaders) } - + @org.springframework.boot.test.context.TestConfiguration + private static class LocalConfig { + @Bean + public String getBeaconCronValue() { + return "0 3 3 * * ?"; + } + } } \ No newline at end of file From 00df9bdc49a2dea63059b1a5c54d73ff62334e94 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Wed, 12 Jul 2023 14:29:48 -0700 Subject: [PATCH 9/9] SHIBUI-2596 Fixing unit tests and startup without a default value for beacon cron. Renamed property for beacon cron frmo code review feedback --- backend/src/main/app-resources/default.yml | 3 ++- .../ui/configuration/CoreShibUiConfiguration.java | 2 +- backend/src/main/resources/application.properties | 2 +- ...esUiDefinitionControllerIntegrationTests.groovy | 7 +------ ...ntrollerSchemaValidationIntegrationTests.groovy | 14 +------------- ...esUiDefinitionControllerIntegrationTests.groovy | 13 +------------ ...etadataFiltersControllerIntegrationTests.groovy | 4 +--- ...ntrollerSchemaValidationIntegrationTests.groovy | 13 +------------ ...sPositionOrderControllerIntegrationTests.groovy | 14 +------------- ...ntrollerSchemaValidationIntegrationTests.groovy | 14 +------------- 10 files changed, 11 insertions(+), 75 deletions(-) diff --git a/backend/src/main/app-resources/default.yml b/backend/src/main/app-resources/default.yml index aa73f8627..9ea447808 100644 --- a/backend/src/main/app-resources/default.yml +++ b/backend/src/main/app-resources/default.yml @@ -30,7 +30,8 @@ # installationID: [user-defined value] # urls: http://collector.testbed.tier.internet2.edu:5001 # productName: ShibUI -# cron: 0 59 3 * * ? +# send: +# cron: 0 59 3 * * ? # pac4j-enabled: true # pac4j: diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index 8e746bbf1..6e839b0df 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -277,7 +277,7 @@ public LockProvider lockProvider(DataSource dataSource) { } @Bean - public String getBeaconCronValue(BeaconConfigurationRepository repo, @Value("${shibui.beacon.cron}") String valueFromConfig) + public String getBeaconCronValue(BeaconConfigurationRepository repo, @Value("${shibui.beacon.send.cron:nodefault}") String valueFromConfig) { Optional obc = repo.findById(1); BeaconConfiguration bc; diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index e46938360..f61974456 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -123,7 +123,7 @@ shibui.beacon.enabled=true shibui.beacon.productName=ShibUi shibui.beacon.installationID=UNICON-SHIBUI-TESTING shibui.beacon.url=http://collector.testbed.tier.internet2.edu:5001 -#shibui.beacon.cron=0 59 3 * * ? +#shibui.beacon.send.cron=0 59 3 * * ? ### Swagger/Springdoc patterns springdoc.use-management-port=true diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index 1acd0a080..d1a31e703 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -26,7 +26,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResour /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles(["no-auth", "badjson"]) class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Specification { @@ -48,11 +48,6 @@ class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Speci @TestConfiguration @Profile('badjson') static class Config { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - @Bean JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(ResourceLoader resourceLoader, ObjectMapper jacksonMapper) { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy index f7d38f69b..3dc9fee6e 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerSchemaValidationIntegrationTests.groovy @@ -3,15 +3,12 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) -@Import([LocalConfig.class]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles(["no-auth", "dev"]) class EntityDescriptorControllerSchemaValidationIntegrationTests extends Specification { @@ -54,13 +51,4 @@ class EntityDescriptorControllerSchemaValidationIntegrationTests extends Specifi private static HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) } - - @org.springframework.boot.test.context.TestConfiguration - private static class LocalConfig { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - } - } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index 0fa1b3545..07bcefff5 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -3,16 +3,13 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import spock.lang.Specification /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) -@Import([LocalConfig.class]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles("no-auth") class GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Specification { @@ -29,12 +26,4 @@ class GoodJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Spec result.statusCodeValue == 200 result.body.properties.entityId.title == 'label.entity-id' } - - @org.springframework.boot.test.context.TestConfiguration - private static class LocalConfig { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - } } \ No newline at end of file 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 index 176dd946f..de2cbd8fa 100644 --- 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 @@ -35,9 +35,7 @@ import static org.springframework.http.HttpMethod.PUT /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", - "shibui.beacon.productName=shibuiProdName", - "shibui.beacon.cron=0 3 3 * * ?"]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles(["no-auth", "mfci-test"]) class MetadataFiltersControllerIntegrationTests extends Specification { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy index 5e1849c72..5dbc39d64 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerSchemaValidationIntegrationTests.groovy @@ -6,15 +6,12 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverReposit import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) -@Import([LocalConfig.class]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles(["no-auth", "dev"]) class MetadataFiltersControllerSchemaValidationIntegrationTests extends Specification { @@ -102,12 +99,4 @@ class MetadataFiltersControllerSchemaValidationIntegrationTests extends Specific private static resourceUriFor(String uriTemplate, String resourceId) { String.format(uriTemplate, resourceId) } - - @org.springframework.boot.test.context.TestConfiguration - private static class LocalConfig { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy index 365e22e45..e1ed71aa4 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersPositionOrderControllerIntegrationTests.groovy @@ -1,22 +1,18 @@ package edu.internet2.tier.shibboleth.admin.ui.controller - 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 org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import spock.lang.Specification /** * @author Dmitriy Kopylenko */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName", "shibui.beacon.cron=0 3 3 * * ?"]) -@Import([LocalConfig.class]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles("no-auth") class MetadataFiltersPositionOrderControllerIntegrationTests extends Specification { @@ -149,12 +145,4 @@ class MetadataFiltersPositionOrderControllerIntegrationTests extends Specificati private static resourceUriFor(String resolverResourceId) { String.format(RESOURCE_URI, resolverResourceId) } - - @org.springframework.boot.test.context.TestConfiguration - private static class LocalConfig { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy index bc9759d64..b08a19f9c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerSchemaValidationIntegrationTests.groovy @@ -3,17 +3,13 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Import import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.test.context.ActiveProfiles import spock.lang.Specification @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = ["management.endpoints.web.exposure.include=info, health", - "shibui.beacon.productName=shibuiProdName", - "shibui.beacon.cron=0 3 3 * * ?"]) -@Import([LocalConfig.class]) + "shibui.beacon.productName=shibuiProdName"]) @ActiveProfiles(["no-auth", "dev"]) class MetadataResolverControllerSchemaValidationIntegrationTests extends Specification { @@ -151,12 +147,4 @@ class MetadataResolverControllerSchemaValidationIntegrationTests extends Specifi private static HttpEntity createRequestHttpEntityFor(String jsonBody) { new HttpEntity(jsonBody, ['Content-Type': 'application/json'] as HttpHeaders) } - - @org.springframework.boot.test.context.TestConfiguration - private static class LocalConfig { - @Bean - public String getBeaconCronValue() { - return "0 3 3 * * ?"; - } - } } \ No newline at end of file