From 115c53ec899710f29953b71b9ea35b4a3e8b7b93 Mon Sep 17 00:00:00 2001 From: Jj! Date: Wed, 22 May 2019 14:52:41 -0500 Subject: [PATCH 1/8] [SHIBUI-1253] file writing service implementation that checks the file before writing --- .../CoreShibUiConfiguration.java | 9 +++- .../EntityDescriptorFilesScheduledTasks.java | 9 +++- .../FileCheckingFileWritingService.java | 51 ++++++++++++++++++ .../admin/ui/service/FileWritingService.java | 19 +++++++ ...yDescriptorFilesScheduledTasksTests.groovy | 3 +- ...FileCheckingFileWritingServiceTests.groovy | 53 +++++++++++++++++++ 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy 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 8f964b96a..a339e90ee 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 @@ -17,6 +17,8 @@ import edu.internet2.tier.shibboleth.admin.ui.service.EntityIdsSearchService; import edu.internet2.tier.shibboleth.admin.ui.service.EntityIdsSearchServiceImpl; import edu.internet2.tier.shibboleth.admin.ui.service.EntityService; +import edu.internet2.tier.shibboleth.admin.ui.service.FileCheckingFileWritingService; +import edu.internet2.tier.shibboleth.admin.ui.service.FileWritingService; import edu.internet2.tier.shibboleth.admin.ui.service.FilterService; import edu.internet2.tier.shibboleth.admin.ui.service.FilterTargetService; import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityDescriptorServiceImpl; @@ -98,7 +100,7 @@ public AttributeUtility attributeUtility() { @Bean @ConditionalOnProperty(name = "shibui.metadata-dir") public EntityDescriptorFilesScheduledTasks entityDescriptorFilesScheduledTasks(EntityDescriptorRepository entityDescriptorRepository, @Value("${shibui.metadata-dir}") final String metadataDir) { - return new EntityDescriptorFilesScheduledTasks(metadataDir, entityDescriptorRepository, openSamlObjects()); + return new EntityDescriptorFilesScheduledTasks(metadataDir, entityDescriptorRepository, openSamlObjects(), fileWritingService()); } @Bean @@ -202,4 +204,9 @@ public ModelRepresentationConversions modelRepresentationConversions() { public UserService userService(RoleRepository roleRepository, UserRepository userRepository) { return new UserService(roleRepository, userRepository); } + + @Bean + public FileWritingService fileWritingService() { + return new FileCheckingFileWritingService(); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java index d7bb02282..e6cb670f2 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java @@ -4,6 +4,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor; import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; +import edu.internet2.tier.shibboleth.admin.ui.service.FileWritingService; import org.bouncycastle.util.encoders.Hex; import org.opensaml.core.xml.io.MarshallingException; import org.slf4j.Logger; @@ -49,12 +50,16 @@ public class EntityDescriptorFilesScheduledTasks { private static final String TARGET_FILE_TEMPLATE = "%s/%s"; + private final FileWritingService fileWritingService; + public EntityDescriptorFilesScheduledTasks(String metadataDirName, EntityDescriptorRepository entityDescriptorRepository, - OpenSamlObjects openSamlObjects) { + OpenSamlObjects openSamlObjects, + FileWritingService fileWritingService) { this.metadataDirName = metadataDirName; this.entityDescriptorRepository = entityDescriptorRepository; this.openSamlObjects = openSamlObjects; + this.fileWritingService = fileWritingService; } @Scheduled(fixedRateString = "${shibui.taskRunRate:30000}") @@ -71,7 +76,7 @@ public void generateEntityDescriptorFiles() throws MarshallingException { try { String xmlContent = this.openSamlObjects.marshalToXmlString(ed); - Files.write(targetFilePath, xmlContent.getBytes()); + fileWritingService.write(targetFilePath, xmlContent); } catch (MarshallingException | IOException e) { //TODO: any other better way to handle it? LOGGER.error("Error marshalling entity descriptor into a file {} - {}", ed.getEntityID(), e.getMessage()); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java new file mode 100644 index 000000000..a520be60a --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java @@ -0,0 +1,51 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +public class FileCheckingFileWritingService implements FileWritingService { + private static final String DEFAULT_ALGORITHM = "MD5"; + private final String algorithm; + + public FileCheckingFileWritingService() { + this(DEFAULT_ALGORITHM); + } + + public FileCheckingFileWritingService(String algorithm) { + this.algorithm = algorithm; + } + + @Override + public void write(Path path, String content) throws IOException { + if (Files.exists(path)) { + try { + MessageDigest md = MessageDigest.getInstance(this.algorithm); + try ( + InputStream is = Files.newInputStream(path); + DigestInputStream dis = new DigestInputStream(is, md) + ) { + byte[] buf = new byte[4096]; + while (dis.read(buf) > -1){} + } + byte[] fileDigest = md.digest(); + byte[] contentDigest = md.digest(content.getBytes()); + if (Arrays.equals(fileDigest, contentDigest)) { + return; + } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + writeContent(path, content.getBytes()); + } + + void writeContent(Path path, byte[] bytes) throws IOException { + Files.write(path, bytes); + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java new file mode 100644 index 000000000..93de34da6 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java @@ -0,0 +1,19 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * Service interface for writing files. Implementations may perform various tasks + * before or after writing the file. + */ +public interface FileWritingService { + /** + * write the file + * + * @param path target file Path + * @param content content to write + * @throws IOException + */ + void write(Path path, String content) throws IOException; +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasksTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasksTests.groovy index 117c0fbd4..f47928082 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasksTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasksTests.groovy @@ -11,6 +11,7 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorReposit import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService +import edu.internet2.tier.shibboleth.admin.ui.service.FileCheckingFileWritingService import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityDescriptorServiceImpl import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityServiceImpl import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator @@ -57,7 +58,7 @@ class EntityDescriptorFilesScheduledTasksTests extends Specification { randomGenerator = new RandomGenerator() tempPath = tempPath + randomGenerator.randomRangeInt(10000, 20000) service = new JPAEntityDescriptorServiceImpl(openSamlObjects, new JPAEntityServiceImpl(openSamlObjects), new UserService(roleRepository, userRepository)) - entityDescriptorFilesScheduledTasks = new EntityDescriptorFilesScheduledTasks(tempPath, entityDescriptorRepository, openSamlObjects) + entityDescriptorFilesScheduledTasks = new EntityDescriptorFilesScheduledTasks(tempPath, entityDescriptorRepository, openSamlObjects, new FileCheckingFileWritingService()) directory = new File(tempPath) directory.mkdir() } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy new file mode 100644 index 000000000..3d88836d7 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy @@ -0,0 +1,53 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +import spock.lang.Specification + +import java.nio.file.Files +import java.security.NoSuchAlgorithmException + +class FileCheckingFileWritingServiceTests extends Specification { + def writer = Spy(FileCheckingFileWritingService) + + def file1 = Files.createTempFile('test1', '.txt') + def file2 = Files.createTempFile('test2', '.txt') + + def "test bad algorithm"() { + setup: + def badWriter = new FileCheckingFileWritingService('badAlGoreRhythm') + + when: + badWriter.write(Files.createTempFile('testbadalgorithm', '.txt'), 'bad') + + then: + RuntimeException ex = thrown() + assert ex.cause instanceof NoSuchAlgorithmException + } + + def "test a single write"() { + when: + writer.write(file1, 'testme') + + then: + 1 * writer.writeContent(file1, 'testme'.bytes) + } + + def "test writes with changed content"() { + when: + writer.write(file2, 'testme') + writer.write(file2, 'anothertest') + + then: + 1 * writer.writeContent(file2, 'testme'.bytes) + 1 * writer.writeContent(file2, 'anothertest'.bytes) + } + + def "test writes with unchanged content, should only write once"() { + when: + (1..5).each { + writer.write(file1, 'testme') + } + + then: + 1 * writer.writeContent(file1, 'testme'.bytes) + } +} From c1a55bf79b9c3148927f2cd10a0d06fd585febd5 Mon Sep 17 00:00:00 2001 From: Jj! Date: Thu, 23 May 2019 12:50:43 -0500 Subject: [PATCH 2/8] [SHIBUI-1253] use file writing service for metadata providers refactor tests --- .../CoreShibUiConfiguration.java | 2 +- .../MetadataProvidersScheduledTasks.java | 5 +- .../FileCheckingFileWritingService.java | 52 ++++++++++---- .../admin/ui/service/FileWritingService.java | 13 +++- ...FileCheckingFileWritingServiceTests.groovy | 71 +++++++++++++++---- 5 files changed, 112 insertions(+), 31 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 a339e90ee..da33c53f8 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 @@ -106,7 +106,7 @@ public EntityDescriptorFilesScheduledTasks entityDescriptorFilesScheduledTasks(E @Bean @ConditionalOnProperty(name = "shibui.metadataProviders.target") public MetadataProvidersScheduledTasks metadataProvidersScheduledTasks(@Value("${shibui.metadataProviders.target}") final Resource resource, final MetadataResolverService metadataResolverService) { - return new MetadataProvidersScheduledTasks(resource, metadataResolverService); + return new MetadataProvidersScheduledTasks(resource, metadataResolverService, fileWritingService()); } @Bean diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java index 49048f39b..1f6ce7e69 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.scheduled; +import edu.internet2.tier.shibboleth.admin.ui.service.FileWritingService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,10 +27,12 @@ public class MetadataProvidersScheduledTasks { private final Resource target; private final MetadataResolverService metadataResolverService; + private final FileWritingService fileWritingService; - public MetadataProvidersScheduledTasks(Resource target, MetadataResolverService metadataResolverService) { + public MetadataProvidersScheduledTasks(Resource target, MetadataResolverService metadataResolverService, FileWritingService fileWritingService) { this.target = target; this.metadataResolverService = metadataResolverService; + this.fileWritingService = fileWritingService; } @Scheduled(fixedRateString = "${shibui.metadataProviders.taskRunRate:30000}") diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java index a520be60a..6c05fa987 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java @@ -1,7 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.io.WritableResource; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestInputStream; @@ -24,28 +27,49 @@ public FileCheckingFileWritingService(String algorithm) { @Override public void write(Path path, String content) throws IOException { if (Files.exists(path)) { - try { - MessageDigest md = MessageDigest.getInstance(this.algorithm); - try ( - InputStream is = Files.newInputStream(path); - DigestInputStream dis = new DigestInputStream(is, md) - ) { - byte[] buf = new byte[4096]; - while (dis.read(buf) > -1){} + try (InputStream is = Files.newInputStream(path)) { + if (checkContentMatches(is, content)) { + return; } - byte[] fileDigest = md.digest(); - byte[] contentDigest = md.digest(content.getBytes()); - if (Arrays.equals(fileDigest, contentDigest)) { + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + writeContent(path, content); + } + + @Override + public void write(WritableResource resource, String content) throws IOException { + if (resource.exists()) { + try (InputStream is = resource.getInputStream()) { + if (checkContentMatches(is, content)) { return; } } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } - writeContent(path, content.getBytes()); + writeContent(resource, content); + } + + private boolean checkContentMatches(InputStream inputStream, String content) throws NoSuchAlgorithmException, IOException { + MessageDigest md = MessageDigest.getInstance(this.algorithm); + try (DigestInputStream dis = new DigestInputStream(inputStream, md)) { + byte[] buf = new byte[4096]; + while (dis.read(buf) > -1) {} + } + byte[] fileDigest = md.digest(); + byte[] contentDigest = md.digest(content.getBytes()); + return Arrays.equals(fileDigest, contentDigest); } - void writeContent(Path path, byte[] bytes) throws IOException { - Files.write(path, bytes); + void writeContent(Path path, String content) throws IOException { + Files.write(path, content.getBytes()); + } + + void writeContent(WritableResource resource, String content) throws IOException { + try (OutputStream os = resource.getOutputStream()) { + os.write(content.getBytes()); + } } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java index 93de34da6..80493c4c0 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.io.WritableResource; + import java.io.IOException; import java.nio.file.Path; @@ -9,11 +11,20 @@ */ public interface FileWritingService { /** - * write the file + * Write content to a file * * @param path target file Path * @param content content to write * @throws IOException */ void write(Path path, String content) throws IOException; + + /** + * Write content to a writeable resource + * + * @param resource + * @param content + * @throws IOException + */ + void write(WritableResource resource, String content) throws IOException; } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy index 3d88836d7..45465475a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy @@ -1,17 +1,26 @@ package edu.internet2.tier.shibboleth.admin.ui.service +import org.springframework.core.io.PathResource +import org.springframework.core.io.WritableResource import spock.lang.Specification import java.nio.file.Files +import java.nio.file.Path import java.security.NoSuchAlgorithmException class FileCheckingFileWritingServiceTests extends Specification { def writer = Spy(FileCheckingFileWritingService) - def file1 = Files.createTempFile('test1', '.txt') - def file2 = Files.createTempFile('test2', '.txt') + Path file - def "test bad algorithm"() { + WritableResource resource + + def setup() { + file = Files.createTempFile('test1', '.txt') + resource = new PathResource(file) + } + + def 'test bad algorithm'() { setup: def badWriter = new FileCheckingFileWritingService('badAlGoreRhythm') @@ -23,31 +32,65 @@ class FileCheckingFileWritingServiceTests extends Specification { assert ex.cause instanceof NoSuchAlgorithmException } - def "test a single write"() { + def 'test a single write to a Path'() { + when: + writer.write(file, 'testme') + + then: + 1 * writer.writeContent(file, 'testme') + assert file.text == 'testme' + } + + def 'test writes with changed content to a Path'() { + when: + writer.write(file, 'testme') + writer.write(file, 'anothertest') + + then: + 1 * writer.writeContent(file, 'testme') + 1 * writer.writeContent(file, 'anothertest') + assert file.text == 'anothertest' + } + + def 'test writes with unchanged content, should only write once to a Path'() { + when: + (1..5).each { + writer.write(file, 'testme2') + } + + then: + 1 * writer.writeContent(file, 'testme2') + assert file.text == 'testme2' + } + + def 'test a single write to a WriteableResource'() { when: - writer.write(file1, 'testme') + writer.write(resource, 'testme') then: - 1 * writer.writeContent(file1, 'testme'.bytes) + 1 * writer.writeContent(resource, 'testme') + assert resource.getFile().text == 'testme' } - def "test writes with changed content"() { + def 'test write with changed content to a WritableResource'() { when: - writer.write(file2, 'testme') - writer.write(file2, 'anothertest') + writer.write(resource, 'testme') + writer.write(resource, 'anothertest') then: - 1 * writer.writeContent(file2, 'testme'.bytes) - 1 * writer.writeContent(file2, 'anothertest'.bytes) + 1 * writer.writeContent(resource, 'testme') + 1 * writer.writeContent(resource, 'anothertest') + assert resource.getFile().text == 'anothertest' } - def "test writes with unchanged content, should only write once"() { + def 'test writes with unchanged content, should only write once to a WriteableResource'() { when: (1..5).each { - writer.write(file1, 'testme') + writer.write(resource, 'testme2') } then: - 1 * writer.writeContent(file1, 'testme'.bytes) + 1 * writer.writeContent(resource, 'testme2') + assert resource.getFile().text == 'testme2' } } From 714a7daa04377457cad85ca56ebe756fb0db743a Mon Sep 17 00:00:00 2001 From: Jj! Date: Thu, 30 May 2019 09:11:32 -0500 Subject: [PATCH 3/8] [SHIBUI-1253] fix property condition include writing of metadata providers --- .../ui/scheduled/EntityDescriptorFilesScheduledTasks.java | 2 +- .../admin/ui/scheduled/MetadataProvidersScheduledTasks.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java index e6cb670f2..35f819165 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/EntityDescriptorFilesScheduledTasks.java @@ -35,7 +35,7 @@ * @since 1.0 */ @Configuration -@ConditionalOnProperty(name = "shibui-metadata-dir") +@ConditionalOnProperty(name = "shibui.metadata-dir") public class EntityDescriptorFilesScheduledTasks { private static final Logger LOGGER = LoggerFactory.getLogger(EntityDescriptorFilesScheduledTasks.class); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java index 1f6ce7e69..a58b0df24 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java @@ -19,6 +19,7 @@ import javax.xml.transform.stream.StreamResult; import java.io.IOException; import java.io.OutputStream; +import java.io.StringWriter; @Configuration @ConditionalOnProperty("shibui.metadataProviders.target") @@ -38,13 +39,14 @@ public MetadataProvidersScheduledTasks(Resource target, MetadataResolverService @Scheduled(fixedRateString = "${shibui.metadataProviders.taskRunRate:30000}") @Transactional(readOnly = true) public void generateMetadataProvidersFile() { - try (OutputStream os = ((WritableResource)target).getOutputStream()) { + try (StringWriter os = new StringWriter()) { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.transform(new DOMSource(metadataResolverService.generateConfiguration()), new StreamResult(os)); + this.fileWritingService.write((WritableResource)this.target, os.toString()); } catch (IOException | TransformerException e) { logger.error(e.getLocalizedMessage(), e); } From e2513ceeda8cf8544c1be2dda79bfe1a89e574b1 Mon Sep 17 00:00:00 2001 From: Jj! Date: Thu, 30 May 2019 15:08:12 -0500 Subject: [PATCH 4/8] [RELEASE] v1.5.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 01ee65808..4905012c7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ name=shibui group=edu.internet2.tier.shibboleth.admin.ui -version=1.6.0-SNAPSHOT +version=1.5.2 shibboleth.version=3.4.0 opensaml.version=3.4.0 From 14b2f1965dc44acffa635290201ca1327e729278 Mon Sep 17 00:00:00 2001 From: Jj! Date: Thu, 30 May 2019 15:18:51 -0500 Subject: [PATCH 5/8] preparing for further development --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4905012c7..01ee65808 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ name=shibui group=edu.internet2.tier.shibboleth.admin.ui -version=1.5.2 +version=1.6.0-SNAPSHOT shibboleth.version=3.4.0 opensaml.version=3.4.0 From 1cd26348960682c47a37f2f8432ed28ab6a5d63f Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 6 Jun 2019 09:58:12 -0700 Subject: [PATCH 6/8] SHIBUI-nojira fixed issue with app locking up on navigation to editors --- ui/src/app/metadata/domain/domain.util.ts | 1 + .../container/provider-edit.component.spec.ts | 8 -------- .../provider/container/provider-edit.component.ts | 6 ------ .../provider/container/provider-select.component.ts | 12 +++++++++--- .../provider/container/provider.component.spec.ts | 13 +------------ .../provider/container/provider.component.ts | 4 +--- .../metadata/provider/effect/collection.effect.ts | 8 ++++---- .../metadata/provider/reducer/collection.reducer.ts | 2 +- .../resolver/container/resolver-edit.component.ts | 6 ------ 9 files changed, 17 insertions(+), 43 deletions(-) diff --git a/ui/src/app/metadata/domain/domain.util.ts b/ui/src/app/metadata/domain/domain.util.ts index 2aeeac247..1080d5237 100644 --- a/ui/src/app/metadata/domain/domain.util.ts +++ b/ui/src/app/metadata/domain/domain.util.ts @@ -7,6 +7,7 @@ import { Metadata } from './domain.type'; export const combineAllFn = (d, p) => [...p, ...d]; export const doesExistFn = (ids, selected) => ids.indexOf(selected) > -1; export const getInCollectionFn = (entities, selectedId) => { + console.log(entities, selectedId); return selectedId && entities[selectedId]; }; export const getEntityIdsFn = list => list.map(entity => entity.entityId); diff --git a/ui/src/app/metadata/provider/container/provider-edit.component.spec.ts b/ui/src/app/metadata/provider/container/provider-edit.component.spec.ts index 83d6288f0..bd6ed6698 100644 --- a/ui/src/app/metadata/provider/container/provider-edit.component.spec.ts +++ b/ui/src/app/metadata/provider/container/provider-edit.component.spec.ts @@ -97,14 +97,6 @@ describe('Provider Edit Component', () => { expect(app).toBeTruthy(); })); - describe('go method', () => { - it('should route to the given child form', () => { - spyOn(router, 'navigate'); - app.go('common'); - expect(router.navigate).toHaveBeenCalled(); - }); - }); - describe('save method', () => { it('should route to the given child form', () => { app.save(); diff --git a/ui/src/app/metadata/provider/container/provider-edit.component.ts b/ui/src/app/metadata/provider/container/provider-edit.component.ts index a0a3ad0ea..c00da63e2 100644 --- a/ui/src/app/metadata/provider/container/provider-edit.component.ts +++ b/ui/src/app/metadata/provider/container/provider-edit.component.ts @@ -60,8 +60,6 @@ export class ProviderEditComponent implements OnDestroy, CanComponentDeactivate let startIndex$ = this.route.firstChild.params.pipe(map(p => p.form || 'filters')); startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index))); - this.index$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(id => id && this.go(id)); - this.store .select(fromWizard.getCurrentWizardSchema) .pipe(filter(s => !!s)) @@ -77,10 +75,6 @@ export class ProviderEditComponent implements OnDestroy, CanComponentDeactivate this.canFilter$ = this.definition$.pipe(map(def => FilterableProviders.indexOf(def.type) > -1)); } - go(id: string): void { - this.router.navigate(['./', id], { relativeTo: this.route }); - } - ngOnDestroy() { this.clear(); this.ngUnsubscribe.next(); diff --git a/ui/src/app/metadata/provider/container/provider-select.component.ts b/ui/src/app/metadata/provider/container/provider-select.component.ts index baba7f626..a704afcb2 100644 --- a/ui/src/app/metadata/provider/container/provider-select.component.ts +++ b/ui/src/app/metadata/provider/container/provider-select.component.ts @@ -3,7 +3,7 @@ import { Subscription, Observable } from 'rxjs'; import { Store } from '@ngrx/store'; import { ActivatedRoute } from '@angular/router'; -import { map, distinctUntilChanged, skipWhile } from 'rxjs/operators'; +import { map, distinctUntilChanged, skipWhile, filter } from 'rxjs/operators'; import { SelectProviderRequest, ClearProviderSelection } from '../action/collection.action'; import * as fromProviders from '../reducer'; import { MetadataProvider } from '../../domain/model'; @@ -31,9 +31,15 @@ export class ProviderSelectComponent implements OnDestroy { map(params => new SelectProviderRequest(params.providerId)) ).subscribe(store); - this.provider$ = this.store.select(fromProviders.getSelectedProvider).pipe(skipWhile(p => !p)); + this.provider$ = this.store.select(fromProviders.getSelectedProvider).pipe(filter(p => { + console.log(p); + return p; + })); - this.provider$.subscribe(provider => this.setDefinition(provider)); + this.provider$.subscribe(provider => { + console.log(provider); + this.setDefinition(provider); + }); } setDefinition(provider: MetadataProvider): void { diff --git a/ui/src/app/metadata/provider/container/provider.component.spec.ts b/ui/src/app/metadata/provider/container/provider.component.spec.ts index 430c248b2..c04839b6f 100644 --- a/ui/src/app/metadata/provider/container/provider.component.spec.ts +++ b/ui/src/app/metadata/provider/container/provider.component.spec.ts @@ -1,13 +1,10 @@ import { Component, ViewChild } from '@angular/core'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { StoreModule, Store, combineReducers } from '@ngrx/store'; import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { ProviderComponent } from './provider.component'; -import * as fromRoot from '../reducer'; -import * as fromWizard from '../../../wizard/reducer'; @Component({ template: ` @@ -24,17 +21,12 @@ describe('Provider Component', () => { let fixture: ComponentFixture; let instance: TestHostComponent; let app: ProviderComponent; - let store: Store; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ NgbDropdownModule, - RouterTestingModule, - StoreModule.forRoot({ - provider: combineReducers(fromRoot.reducers), - wizard: combineReducers(fromWizard.reducers) - }) + RouterTestingModule ], declarations: [ ProviderComponent, @@ -42,9 +34,6 @@ describe('Provider Component', () => { ], }).compileComponents(); - store = TestBed.get(Store); - spyOn(store, 'dispatch'); - fixture = TestBed.createComponent(TestHostComponent); instance = fixture.componentInstance; app = instance.componentUnderTest; diff --git a/ui/src/app/metadata/provider/container/provider.component.ts b/ui/src/app/metadata/provider/container/provider.component.ts index c23dc7066..54757e53d 100644 --- a/ui/src/app/metadata/provider/container/provider.component.ts +++ b/ui/src/app/metadata/provider/container/provider.component.ts @@ -8,7 +8,5 @@ import * as fromProvider from '../reducer'; styleUrls: [] }) export class ProviderComponent { - constructor( - private store: Store - ) {} + constructor() {} } diff --git a/ui/src/app/metadata/provider/effect/collection.effect.ts b/ui/src/app/metadata/provider/effect/collection.effect.ts index 8b19d6d3a..7091e46d8 100644 --- a/ui/src/app/metadata/provider/effect/collection.effect.ts +++ b/ui/src/app/metadata/provider/effect/collection.effect.ts @@ -82,14 +82,14 @@ export class CollectionEffects { ofType(ProviderCollectionActionTypes.SELECT_PROVIDER_REQUEST), map(action => action.payload), debounceTime(500), - switchMap(id => - this.providerService + switchMap(id => { + return this.providerService .find(id) .pipe( map(provider => new SelectProviderSuccess(provider)), catchError(error => of(new SelectProviderError(error))) - ) - ) + ); + }) ); @Effect() diff --git a/ui/src/app/metadata/provider/reducer/collection.reducer.ts b/ui/src/app/metadata/provider/reducer/collection.reducer.ts index de1439821..a04e940af 100644 --- a/ui/src/app/metadata/provider/reducer/collection.reducer.ts +++ b/ui/src/app/metadata/provider/reducer/collection.reducer.ts @@ -23,7 +23,7 @@ export function reducer(state = initialState, action: ProviderCollectionActionsU case ProviderCollectionActionTypes.SELECT_PROVIDER_SUCCESS: { return { ...state, - selectedProviderId: action.payload.id as string + selectedProviderId: action.payload.resourceId }; } diff --git a/ui/src/app/metadata/resolver/container/resolver-edit.component.ts b/ui/src/app/metadata/resolver/container/resolver-edit.component.ts index 6161919f9..f793ef96e 100644 --- a/ui/src/app/metadata/resolver/container/resolver-edit.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-edit.component.ts @@ -56,8 +56,6 @@ export class ResolverEditComponent implements OnDestroy, CanComponentDeactivate let startIndex$ = this.route.firstChild.params.pipe(map(p => p.form)); startIndex$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(index => this.store.dispatch(new SetIndex(index))); - this.index$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(index => index && this.go(index)); - this.store .select(fromWizard.getCurrentWizardSchema) .pipe(filter(s => !!s)) @@ -67,10 +65,6 @@ export class ResolverEditComponent implements OnDestroy, CanComponentDeactivate this.store.select(fromResolver.getEntityChanges).subscribe(changes => this.latest = changes); } - go(index: string): void { - this.router.navigate(['./', index], { relativeTo: this.route }); - } - ngOnDestroy() { this.clear(); this.ngUnsubscribe.next(); From 841ab6c72da21b55b8083e08484c138800188e45 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 6 Jun 2019 10:00:39 -0700 Subject: [PATCH 7/8] removed console log statements --- ui/src/app/metadata/domain/domain.util.ts | 1 - .../metadata/provider/container/provider-select.component.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/ui/src/app/metadata/domain/domain.util.ts b/ui/src/app/metadata/domain/domain.util.ts index 1080d5237..2aeeac247 100644 --- a/ui/src/app/metadata/domain/domain.util.ts +++ b/ui/src/app/metadata/domain/domain.util.ts @@ -7,7 +7,6 @@ import { Metadata } from './domain.type'; export const combineAllFn = (d, p) => [...p, ...d]; export const doesExistFn = (ids, selected) => ids.indexOf(selected) > -1; export const getInCollectionFn = (entities, selectedId) => { - console.log(entities, selectedId); return selectedId && entities[selectedId]; }; export const getEntityIdsFn = list => list.map(entity => entity.entityId); diff --git a/ui/src/app/metadata/provider/container/provider-select.component.ts b/ui/src/app/metadata/provider/container/provider-select.component.ts index a704afcb2..b0c07f6fd 100644 --- a/ui/src/app/metadata/provider/container/provider-select.component.ts +++ b/ui/src/app/metadata/provider/container/provider-select.component.ts @@ -32,12 +32,10 @@ export class ProviderSelectComponent implements OnDestroy { ).subscribe(store); this.provider$ = this.store.select(fromProviders.getSelectedProvider).pipe(filter(p => { - console.log(p); return p; })); this.provider$.subscribe(provider => { - console.log(provider); this.setDefinition(provider); }); } From ccff5b5f89f63815a718300ef00ce338933538c1 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 6 Jun 2019 13:33:43 -0700 Subject: [PATCH 8/8] shibui-nojira: changed npm install command to use ci --- ui/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/build.gradle b/ui/build.gradle index 7735a3116..64fe2e561 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -9,6 +9,8 @@ node { download = true } +npmInstall.setNpmCommand('ci') + npm_run_build { inputs.dir 'src' outputs.dir 'dist'