diff --git a/.gitignore b/.gitignore index 934a0cec0..050e01025 100644 --- a/.gitignore +++ b/.gitignore @@ -390,4 +390,8 @@ pac4j-module/out/ r #Local integration test run shell script wrapper -rinteg \ No newline at end of file +rinteg + +#Local run with durable H2 shell script wrapper +**/application-h2durable.properties +rdurable \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java index 8088793a9..ee5f8cec3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java @@ -13,6 +13,7 @@ import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import net.shibboleth.ext.spring.resource.ResourceHelper; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.logic.ConstraintViolationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; import net.shibboleth.utilities.java.support.resource.Resource; import org.apache.lucene.index.IndexWriter; @@ -21,13 +22,10 @@ import org.opensaml.saml.metadata.resolver.MetadataResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; -import org.springframework.stereotype.Service; -import javax.validation.ConstraintViolationException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.URL; import static edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers.placeholderResolverService; @@ -46,8 +44,8 @@ private OpenSamlFunctionDrivenDynamicHTTPMetadataResolver convertToOpenSamlRepre IndexWriter indexWriter = indexWriterService.getIndexWriter(resolver.getResourceId()); OpenSamlFunctionDrivenDynamicHTTPMetadataResolver openSamlResolver = new OpenSamlFunctionDrivenDynamicHTTPMetadataResolver(openSamlObjects.getParserPool(), - indexWriter, - resolver); + indexWriter, + resolver); openSamlResolver.initialize(); return openSamlResolver; } @@ -68,31 +66,25 @@ private OpenSamlFilesystemMetadataResolver convertToOpenSamlRepresentation(Files } OpenSamlFilesystemMetadataResolver openSamlResolver = new OpenSamlFilesystemMetadataResolver(openSamlObjects.getParserPool(), - indexWriter, - resolver, - metadataFile); + indexWriter, + resolver, + metadataFile); openSamlResolver.initialize(); return openSamlResolver; } private OpenSamlLocalDynamicMetadataResolver convertToOpenSamlRepresentation(LocalDynamicMetadataResolver resolver) throws IOException, ComponentInitializationException { - IndexWriter indexWriter = indexWriterService.getIndexWriter(resolver.getResourceId()); - - XMLObjectLoadSaveManager manager = null; - if (resolver.getDoInitialization()) { - try { - manager = new FilesystemLoadSaveManager(placeholderResolverService() - .resolveValueFromPossibleTokenPlaceholder(resolver.getSourceDirectory())); - } catch (ConstraintViolationException e) { - // the base directory string instance was null or empty - //TODO: What should we do here? Currently, this causes a test to fail. - throw new RuntimeException("An exception occurred while attempting to instantiate a FilesystemLoadSaveManger for the path: " + resolver.getSourceDirectory(), e); - } + try { + IndexWriter indexWriter = indexWriterService.getIndexWriter(resolver.getResourceId()); + XMLObjectLoadSaveManager manager = new FilesystemLoadSaveManager(new AlwaysExistingVirtualMetadataDirectory(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(resolver.getSourceDirectory()))); + OpenSamlLocalDynamicMetadataResolver openSamlResolver = new OpenSamlLocalDynamicMetadataResolver(openSamlObjects.getParserPool(), indexWriter, resolver, manager); + openSamlResolver.initialize(); + return openSamlResolver; + } catch (ConstraintViolationException e) { + // the base directory string instance was null or empty + throw new RuntimeException("An exception occurred while attempting to instantiate a FilesystemLoadSaveManger for the path: " + resolver.getSourceDirectory(), e); } - - OpenSamlLocalDynamicMetadataResolver openSamlResolver = new OpenSamlLocalDynamicMetadataResolver(openSamlObjects.getParserPool(), indexWriter, resolver, manager); - openSamlResolver.initialize(); - return openSamlResolver; } private OpenSamlResourceBackedMetadataResolver convertToOpenSamlRepresentation(ResourceBackedMetadataResolver resolver) throws IOException, ComponentInitializationException { @@ -112,9 +104,9 @@ private OpenSamlResourceBackedMetadataResolver convertToOpenSamlRepresentation(R } OpenSamlResourceBackedMetadataResolver openSamlResolver = new OpenSamlResourceBackedMetadataResolver(openSamlObjects.getParserPool(), - indexWriter, - resolver, - resource); + indexWriter, + resolver, + resource); openSamlResolver.initialize(); return openSamlResolver; } @@ -136,4 +128,27 @@ public MetadataResolver convertToOpenSamlRepresentation(edu.internet2.tier.shibb throw new RuntimeException("Unsupported metadata resolver type!"); } } + + /** + * Use this class when creating FilesystemLoadSaveManager for OpenSamlLocalDynamicMetadataResolver + * as we guard the system from any file-related exceptions during init of open saml object representation. + * File with the same name might exist and we don't force the + * system to create a directory in this case. Shibboleth Idp would take care of these directory-creating aspects + * instead. + */ + private static class AlwaysExistingVirtualMetadataDirectory extends File { + public AlwaysExistingVirtualMetadataDirectory(String pathname) { + super(pathname); + } + + @Override + public boolean exists() { + return true; + } + + @Override + public boolean isDirectory() { + return true; + } + } } diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 714bf14bb..1c0e50f0d 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -58,6 +58,7 @@ action.back-to-top=Back to Top action.restore=Restore action.view-only-changes=View Only Changes action.user-role=User Role +action.toggle-view=Toggle view value.enabled=Enabled value.disabled=Disabled @@ -560,7 +561,7 @@ tooltip.enable-provider-upon-saving=If checkbox is clicked, the metadata provide tooltip.max-validity-interval=Defines the window within which the metadata is valid. tooltip.require-signed-root=If true, this fails to load metadata with no signature on the root XML element. -tooltip.certificate-file=A path (on the local file system) to a certificate file whose key used to verify the signature. Conflicts with trustEngineRef and both of the child elements. +tooltip.certificate-file=A path (on the local file system) to a certificate file whose key is used to verify the signature. Conflicts with trustEngineRef and both of the child elements. tooltip.retained-roles=Note that property replacement cannot be used on this element. tooltip.remove-roleless-entity-descriptors=Controls whether to keep entity descriptors that contain no roles. Note: If this attribute is set to false, the resulting output may not be schema-valid since an element must include at least one role descriptor. tooltip.remove-empty-entities-descriptors=Controls whether to keep entities descriptors that contain no entity descriptors. Note: If this attribute is set to false, the resulting output may not be schema-valid since an element must include at least one child element, either an element or an element. diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImplTests.groovy new file mode 100644 index 000000000..8a261565e --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImplTests.groovy @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicMetadataResolverAttributes +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest +class MetadataResolverConverterServiceImplTests extends Specification { + + @Autowired + MetadataResolverConverterService mrConverterServiceUnderTest + + def "conversion to OpenSamlLocalDynamicMetadataResolver with source directory name matching existing file (non-directory) succeeds"() { + given: + LocalDynamicMetadataResolver mr = new LocalDynamicMetadataResolver().with { + it.name = 'SHIBUI-1639' + it.sourceDirectory = File.createTempFile('foo', null).absolutePath + it.dynamicMetadataResolverAttributes = new DynamicMetadataResolverAttributes() + it + } + when: + mrConverterServiceUnderTest.convertToOpenSamlRepresentation(mr) + + then: + noExceptionThrown() + } +} diff --git a/ui/package-lock.json b/ui/package-lock.json index e563a1f26..717b0f7ad 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -339,6 +339,23 @@ } } }, + "@angular/cdk": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz", + "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^1.7.1" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + } + } + }, "@angular/cli": { "version": "8.3.12", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.12.tgz", @@ -12255,8 +12272,7 @@ "tslib": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz", - "integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=", - "dev": true + "integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=" }, "tslint": { "version": "5.3.2", diff --git a/ui/package.json b/ui/package.json index b47cb0463..f0fa2d460 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,6 +18,7 @@ "private": true, "dependencies": { "@angular/animations": "8.2.11", + "@angular/cdk": "^8.2.3", "@angular/common": "8.2.11", "@angular/compiler": "8.2.11", "@angular/core": "8.2.11", @@ -73,4 +74,4 @@ "typescript": "3.5.3", "webpack-bundle-analyzer": "^3.3.2" } -} \ No newline at end of file +} diff --git a/ui/src/app/metadata/configuration/container/metadata-options.component.html b/ui/src/app/metadata/configuration/container/metadata-options.component.html index 54c969b5e..09b72b7f9 100644 --- a/ui/src/app/metadata/configuration/container/metadata-options.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-options.component.html @@ -20,15 +20,17 @@

Filters - diff --git a/ui/src/app/metadata/configuration/container/metadata-xml.component.html b/ui/src/app/metadata/configuration/container/metadata-xml.component.html index e682a556d..2b5837944 100644 --- a/ui/src/app/metadata/configuration/container/metadata-xml.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-xml.component.html @@ -6,8 +6,14 @@

diff --git a/ui/src/app/metadata/manager/component/resolvers-list.component.html b/ui/src/app/metadata/manager/component/resolvers-list.component.html index de54eebae..c221fbcff 100644 --- a/ui/src/app/metadata/manager/component/resolvers-list.component.html +++ b/ui/src/app/metadata/manager/component/resolvers-list.component.html @@ -16,9 +16,11 @@ {{ resolver.name }} - {{ resolver.getDisplayId() }} - {{ resolver.createdBy }} - {{ resolver.getCreationDate() ? (resolver.getCreationDate() | customDate) : '—' }} + {{ resolver.getDisplayId() }} + {{ resolver.createdBy ? resolver.createdBy : '—' }} + + {{ resolver.getCreationDate() ? (resolver.getCreationDate() | customDate) : '—' }} +   - Incomplete Form @@ -42,10 +44,13 @@ - - Enabled - Disabled + {{ (resolver.enabled ? 'value.enabled' : 'value.disabled') | translate }} diff --git a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html index 22823cc35..00e11d268 100644 --- a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html +++ b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html @@ -52,11 +52,12 @@ {{ provider.createdBy }} {{ provider.createdDate | customDate }} - - Enabled - Enabled + {{ (provider.enabled ? 'value.enabled' : 'value.disabled') | translate }} diff --git a/ui/src/app/metadata/resolver/container/copy-resolver.component.html b/ui/src/app/metadata/resolver/container/copy-resolver.component.html index fb3832558..fb850e9bb 100644 --- a/ui/src/app/metadata/resolver/container/copy-resolver.component.html +++ b/ui/src/app/metadata/resolver/container/copy-resolver.component.html @@ -28,6 +28,7 @@

-