From afbe10e51dc508b7fda3fb751e1afb48b69fff62 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Thu, 29 Jul 2021 21:47:40 -0700 Subject: [PATCH] SHIBUI-2001 Enable endpoint --- .../JPAMetadataResolverServiceImpl.groovy | 454 ++++++++++-------- .../admin/ui/service/UserBootstrap.groovy | 7 +- .../CoreShibUiConfiguration.java | 73 ++- ...etadataResolverConverterConfiguration.java | 17 - .../ui/controller/ActivateController.java | 21 +- .../controller/ActivateExceptionHandler.java | 16 + .../ui/exception/InitializationException.java | 7 + .../ui/security/service/UserService.java | 8 + .../JPAEntityDescriptorServiceImpl.java | 3 + .../ui/service/JPAFilterServiceImpl.java | 2 + .../MetadataResolverConverterServiceImpl.java | 2 + .../ui/service/MetadataResolverService.java | 12 +- .../MetadataFiltersControllerTests.groovy | 16 + ...JPAMetadataResolverServiceImplTests.groovy | 3 +- ...taResolverConverterServiceImplTests.groovy | 4 + .../ui/service/UserBootstrapTests.groovy | 12 +- 16 files changed, 392 insertions(+), 265 deletions(-) delete mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/InitializationException.java diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy index 5dfbf65eb..f8f2118cb 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy @@ -2,6 +2,7 @@ package edu.internet2.tier.shibboleth.admin.ui.service import com.google.common.base.Predicate import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException 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.filters.EntityRoleWhiteListFilter @@ -20,8 +21,13 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMet import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.TemplateScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.Refilterable +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException +import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException +import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService +import edu.internet2.tier.shibboleth.admin.util.OpenSamlChainingMetadataResolverUtil import groovy.util.logging.Slf4j import groovy.xml.DOMBuilder import groovy.xml.MarkupBuilder @@ -34,9 +40,11 @@ import org.opensaml.saml.metadata.resolver.filter.impl.NameIDFormatFilter import org.opensaml.saml.saml2.core.Attribute import org.opensaml.saml.saml2.metadata.EntityDescriptor import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service import org.w3c.dom.Document import javax.annotation.Nonnull +import javax.transaction.Transactional import static edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilterTarget.NameIdFormatFilterTargetType.ENTITY import static edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilterTarget.NameIdFormatFilterTargetType.CONDITION_SCRIPT @@ -45,171 +53,32 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBa import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.SVN @Slf4j +@Service class JPAMetadataResolverServiceImpl implements MetadataResolverService { + + @Autowired + org.opensaml.saml.metadata.resolver.MetadataResolver chainingMetadataResolver @Autowired private MetadataResolver metadataResolver @Autowired - private MetadataResolverRepository metadataResolverRepository + MetadataResolverConverterService metadataResolverConverterService + @Autowired + private MetadataResolverRepository metadataResolverRepository + @Autowired private OpenSamlObjects openSamlObjects - + @Autowired private MetadataResolversPositionOrderContainerService resolversPositionOrderContainerService - + @Autowired private ShibUIConfiguration shibUIConfiguration - - // TODO: enhance - @Override - void reloadFilters(String metadataResolverResourceId) { - OpenSamlChainingMetadataResolver chainingMetadataResolver = (OpenSamlChainingMetadataResolver) metadataResolver - MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { - it.id == metadataResolverResourceId - } - edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByResourceId(metadataResolverResourceId) - - if (targetMetadataResolver && targetMetadataResolver.getMetadataFilter() instanceof MetadataFilterChain) { - MetadataFilterChain metadataFilterChain = (MetadataFilterChain) targetMetadataResolver.getMetadataFilter() - - List metadataFilters = new ArrayList<>() - - // set up namespace protection - if (shibUIConfiguration.protectedAttributeNamespaces && shibUIConfiguration.protectedAttributeNamespaces.size() > 0 && targetMetadataResolver && jpaMetadataResolver.type in ['FileBackedHttpMetadataResolver', 'DynamicHttpMetadataResolver']) { - def target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter() - target.attributeFilter = new ScriptedPredicate(new EvaluableScript(protectedNamespaceScript())) - metadataFilters.add(target) - } - - for (edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter metadataFilter : jpaMetadataResolver.getMetadataFilters()) { - if (metadataFilter instanceof EntityAttributesFilter) { - EntityAttributesFilter entityAttributesFilter = (EntityAttributesFilter) metadataFilter - - org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter() - Map, Collection> rules = new HashMap<>() - switch (entityAttributesFilter.getEntityAttributesFilterTarget().getEntityAttributesFilterTargetType()) { - case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY: - rules.put( - new EntityIdPredicate(entityAttributesFilter.getEntityAttributesFilterTarget().getValue()), - (List) (List) entityAttributesFilter.getAttributes() - ) - break - case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.CONDITION_SCRIPT: - rules.put(new ScriptedPredicate(new EvaluableScript(entityAttributesFilter.entityAttributesFilterTarget.value[0])), - (List) (List) entityAttributesFilter.getAttributes()) - break - case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.REGEX: - rules.put(new ScriptedPredicate(new EvaluableScript(generateJavaScriptRegexScript(entityAttributesFilter.entityAttributesFilterTarget.value[0]))), - (List) (List) entityAttributesFilter.getAttributes()) - break - default: - // do nothing, we'd have exploded elsewhere previously. - break - } - target.setRules(rules) - metadataFilters.add(target) - } - if (metadataFilter instanceof NameIdFormatFilter) { - NameIdFormatFilter nameIdFormatFilter = NameIdFormatFilter.cast(metadataFilter) - NameIDFormatFilter openSamlTargetFilter = new OpenSamlNameIdFormatFilter() - openSamlTargetFilter.removeExistingFormats = nameIdFormatFilter.removeExistingFormats - Map, Collection> predicateRules = [:] - def type = nameIdFormatFilter.nameIdFormatFilterTarget.nameIdFormatFilterTargetType - def values = nameIdFormatFilter.nameIdFormatFilterTarget.value - switch (type) { - case ENTITY: - predicateRules[new EntityIdPredicate(values)] = nameIdFormatFilter.formats - break - case CONDITION_SCRIPT: - predicateRules[new ScriptedPredicate(new EvaluableScript(values[0]))] = nameIdFormatFilter.formats - break - case REGEX: - predicateRules[new ScriptedPredicate(new EvaluableScript(generateJavaScriptRegexScript(values[0])))] = nameIdFormatFilter.formats - break - default: - // do nothing, we'd have exploded elsewhere previously. - break - } - openSamlTargetFilter.rules = predicateRules - metadataFilters << openSamlTargetFilter - } - } - metadataFilterChain.setFilters(metadataFilters) - } - - if (targetMetadataResolver != null && targetMetadataResolver instanceof Refilterable) { - (Refilterable) targetMetadataResolver.refilter() - } else { - //TODO: Do something here if we need to refilter other non-Batch resolvers - log.warn("Target resolver is not a Refilterable resolver. Skipping refilter()") - } - } - - private String protectedNamespaceScript() { - return """(function (attribute) { - "use strict"; - var namespaces = [${shibUIConfiguration.protectedAttributeNamespaces.collect({"\"${it}\""}).join(', ')}]; - // check the parameter - if (attribute === null) { return true; } - for (var i in namespaces) { - if (attribute.getName().startsWith(namespaces[i])) { - return false; - } - } - return true; - }(input));""" - } - - private class ScriptedPredicate extends net.shibboleth.utilities.java.support.logic.ScriptedPredicate { - protected ScriptedPredicate(@Nonnull EvaluableScript theScript) { - super(theScript) - } - } - - // TODO: enhance - @Override - Document generateConfiguration() { - // TODO: this can probably be a better writer - new StringWriter().withCloseable { writer -> - def xml = new MarkupBuilder(writer) - xml.omitEmptyAttributes = true - xml.omitNullAttributes = true - - xml.MetadataProvider(id: 'ShibbolethMetadata', - xmlns: 'urn:mace:shibboleth:2.0:metadata', - 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:type': 'ChainingMetadataProvider', - 'xsi:schemaLocation': 'urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd urn:mace:shibboleth:2.0:resource http://shibboleth.net/schema/idp/shibboleth-resource.xsd urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd' - ) { - - - resolversPositionOrderContainerService.allMetadataResolversInDefinedOrderOrUnordered.each { - edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr -> - //TODO: We do not currently marshall the internal incommon chaining resolver (with BaseMetadataResolver type) - if ((mr.type != 'BaseMetadataResolver') && (mr.enabled)) { - constructXmlNodeForResolver(mr, delegate) { - //TODO: enhance - def didNamespaceProtectionFilter = !(shibUIConfiguration.protectedAttributeNamespaces && shibUIConfiguration.protectedAttributeNamespaces.size() > 0) - def doNamespaceProtectionFilter = { def filter -> - if (mr.type in ['FileBackedMetadataResolver', 'DynamicHttpMetadataResolver'] && (filter == null || filter instanceof EntityAttributesFilter) && !didNamespaceProtectionFilter) { - constructXmlNodeForEntityAttributeNamespaceProtection(delegate) - didNamespaceProtectionFilter = true - } - } - mr.metadataFilters.each { edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter filter -> - doNamespaceProtectionFilter() - constructXmlNodeForFilter(filter, delegate) - } - doNamespaceProtectionFilter() - } - } - } - } - return DOMBuilder.newInstance().parseText(writer.toString()) - } - } + + @Autowired + private UserService userService void constructXmlNodeForEntityAttributeNamespaceProtection(def markupBuilderDelegate) { markupBuilderDelegate.MetadataFilter('xsi:type': 'EntityAttributes') { @@ -221,21 +90,6 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } - void constructXmlNodeForFilter(SignatureValidationFilter filter, def markupBuilderDelegate) { - if (filter.xmlShouldBeGenerated()) { - markupBuilderDelegate.MetadataFilter(id: filter.name, - 'xsi:type': 'SignatureValidation', - 'xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata', - 'requireSignedRoot': !filter.requireSignedRoot ?: null, - 'certificateFile': filter.certificateFile, - 'defaultCriteriaRef': filter.defaultCriteriaRef, - 'signaturePrevalidatorRef': filter.signaturePrevalidatorRef, - 'dynamicTrustedNamesStrategyRef': filter.dynamicTrustedNamesStrategyRef, - 'trustEngineRef': filter.trustEngineRef, - 'publicKey': filter.publicKey) - } - } - void constructXmlNodeForFilter(EntityAttributesFilter filter, def markupBuilderDelegate) { markupBuilderDelegate.MetadataFilter('xsi:type': 'EntityAttributes') { // TODO: enhance. currently this does weird things with namespaces @@ -274,12 +128,6 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } - private String generateJavaScriptRegexScript(String regex) { - return """ - "use strict"; - ${regex.startsWith('/') ? '' : '/'}${regex}${regex.endsWith('/') ? '' : '/'}.test(input.getEntityID());\n""" - } - void constructXmlNodeForFilter(EntityRoleWhiteListFilter filter, def markupBuilderDelegate) { if (!filter.retainedRoles?.isEmpty()) { markupBuilderDelegate.MetadataFilter( @@ -294,15 +142,6 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } - void constructXmlNodeForFilter(RequiredValidUntilFilter filter, def markupBuilderDelegate) { - if (filter.xmlShouldBeGenerated()) { - markupBuilderDelegate.MetadataFilter( - 'xsi:type': 'RequiredValidUntil', - maxValidityInterval: filter.maxValidityInterval - ) - } - } - void constructXmlNodeForFilter(NameIdFormatFilter filter, def markupBuilderDelegate) { def type = filter.nameIdFormatFilterTarget.nameIdFormatFilterTargetType markupBuilderDelegate.MetadataFilter( @@ -341,27 +180,27 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } - void constructXmlNodeForResolver(FilesystemMetadataResolver resolver, def markupBuilderDelegate, Closure childNodes) { - markupBuilderDelegate.MetadataProvider(id: resolver.xmlId, - 'xsi:type': 'FilesystemMetadataProvider', - metadataFile: resolver.metadataFile, - - requireValidMetadata: !resolver.requireValidMetadata ?: null, - failFastInitialization: !resolver.failFastInitialization ?: null, - sortKey: resolver.sortKey, - criterionPredicateRegistryRef: resolver.criterionPredicateRegistryRef, - useDefaultPredicateRegistry: !resolver.useDefaultPredicateRegistry ?: null, - satisfyAnyPredicates: resolver.satisfyAnyPredicates ?: null, - - parserPoolRef: resolver.reloadableMetadataResolverAttributes?.parserPoolRef, - minRefreshDelay: resolver.reloadableMetadataResolverAttributes?.minRefreshDelay, - maxRefreshDelay: resolver.reloadableMetadataResolverAttributes?.maxRefreshDelay, - refreshDelayFactor: resolver.reloadableMetadataResolverAttributes?.refreshDelayFactor, - indexesRef: resolver.reloadableMetadataResolverAttributes?.indexesRef, - resolveViaPredicatesOnly: resolver.reloadableMetadataResolverAttributes?.resolveViaPredicatesOnly ?: null, - expirationWarningThreshold: resolver.reloadableMetadataResolverAttributes?.expirationWarningThreshold) { + void constructXmlNodeForFilter(RequiredValidUntilFilter filter, def markupBuilderDelegate) { + if (filter.xmlShouldBeGenerated()) { + markupBuilderDelegate.MetadataFilter( + 'xsi:type': 'RequiredValidUntil', + maxValidityInterval: filter.maxValidityInterval + ) + } + } - childNodes() + void constructXmlNodeForFilter(SignatureValidationFilter filter, def markupBuilderDelegate) { + if (filter.xmlShouldBeGenerated()) { + markupBuilderDelegate.MetadataFilter(id: filter.name, + 'xsi:type': 'SignatureValidation', + 'xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata', + 'requireSignedRoot': !filter.requireSignedRoot ?: null, + 'certificateFile': filter.certificateFile, + 'defaultCriteriaRef': filter.defaultCriteriaRef, + 'signaturePrevalidatorRef': filter.signaturePrevalidatorRef, + 'dynamicTrustedNamesStrategyRef': filter.dynamicTrustedNamesStrategyRef, + 'trustEngineRef': filter.trustEngineRef, + 'publicKey': filter.publicKey) } } @@ -483,6 +322,30 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } + void constructXmlNodeForResolver(FilesystemMetadataResolver resolver, def markupBuilderDelegate, Closure childNodes) { + markupBuilderDelegate.MetadataProvider(id: resolver.xmlId, + 'xsi:type': 'FilesystemMetadataProvider', + metadataFile: resolver.metadataFile, + + requireValidMetadata: !resolver.requireValidMetadata ?: null, + failFastInitialization: !resolver.failFastInitialization ?: null, + sortKey: resolver.sortKey, + criterionPredicateRegistryRef: resolver.criterionPredicateRegistryRef, + useDefaultPredicateRegistry: !resolver.useDefaultPredicateRegistry ?: null, + satisfyAnyPredicates: resolver.satisfyAnyPredicates ?: null, + + parserPoolRef: resolver.reloadableMetadataResolverAttributes?.parserPoolRef, + minRefreshDelay: resolver.reloadableMetadataResolverAttributes?.minRefreshDelay, + maxRefreshDelay: resolver.reloadableMetadataResolverAttributes?.maxRefreshDelay, + refreshDelayFactor: resolver.reloadableMetadataResolverAttributes?.refreshDelayFactor, + indexesRef: resolver.reloadableMetadataResolverAttributes?.indexesRef, + resolveViaPredicatesOnly: resolver.reloadableMetadataResolverAttributes?.resolveViaPredicatesOnly ?: null, + expirationWarningThreshold: resolver.reloadableMetadataResolverAttributes?.expirationWarningThreshold) { + + childNodes() + } + } + void constructXmlNodeForResolver(LocalDynamicMetadataResolver resolver, def markupBuilderDelegate, Closure childNodes) { markupBuilderDelegate.MetadataProvider(sourceDirectory: resolver.sourceDirectory, sourceManagerRef: resolver.sourceManagerRef, @@ -556,7 +419,194 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { childNodes() } + } + public edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver findByResourceId(String resourceId) throws EntityNotFoundException { + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver result = metadataResolverRepository.findByResourceId(resourceId) + if (result == null ) { + throw new EntityNotFoundException("No Provider with resourceId[" + resourceId + "] was found") + } + return result + } + + // TODO: enhance + @Override + Document generateConfiguration() { + // TODO: this can probably be a better writer + new StringWriter().withCloseable { writer -> + def xml = new MarkupBuilder(writer) + xml.omitEmptyAttributes = true + xml.omitNullAttributes = true + + xml.MetadataProvider(id: 'ShibbolethMetadata', + xmlns: 'urn:mace:shibboleth:2.0:metadata', + 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:type': 'ChainingMetadataProvider', + 'xsi:schemaLocation': 'urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd urn:mace:shibboleth:2.0:resource http://shibboleth.net/schema/idp/shibboleth-resource.xsd urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd' + ) { + + + resolversPositionOrderContainerService.allMetadataResolversInDefinedOrderOrUnordered.each { + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr -> + //TODO: We do not currently marshall the internal incommon chaining resolver (with BaseMetadataResolver type) + if ((mr.type != 'BaseMetadataResolver') && (mr.enabled)) { + constructXmlNodeForResolver(mr, delegate) { + //TODO: enhance + def didNamespaceProtectionFilter = !(shibUIConfiguration.protectedAttributeNamespaces && shibUIConfiguration.protectedAttributeNamespaces.size() > 0) + def doNamespaceProtectionFilter = { def filter -> + if (mr.type in ['FileBackedMetadataResolver', 'DynamicHttpMetadataResolver'] && (filter == null || filter instanceof EntityAttributesFilter) && !didNamespaceProtectionFilter) { + constructXmlNodeForEntityAttributeNamespaceProtection(delegate) + didNamespaceProtectionFilter = true + } + } + mr.metadataFilters.each { edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter filter -> + doNamespaceProtectionFilter() + constructXmlNodeForFilter(filter, delegate) + } + doNamespaceProtectionFilter() + } + } + } + } + return DOMBuilder.newInstance().parseText(writer.toString()) + } + } + + private String generateJavaScriptRegexScript(String regex) { + return """ + "use strict"; + ${regex.startsWith('/') ? '' : '/'}${regex}${regex.endsWith('/') ? '' : '/'}.test(input.getEntityID());\n""" + } + + private String protectedNamespaceScript() { + return """(function (attribute) { + "use strict"; + var namespaces = [${shibUIConfiguration.protectedAttributeNamespaces.collect({"\"${it}\""}).join(', ')}]; + // check the parameter + if (attribute === null) { return true; } + for (var i in namespaces) { + if (attribute.getName().startsWith(namespaces[i])) { + return false; + } + } + return true; + }(input));""" + } + + // TODO: enhance + @Override + void reloadFilters(String metadataResolverResourceId) { + OpenSamlChainingMetadataResolver chainingMetadataResolver = (OpenSamlChainingMetadataResolver) metadataResolver + MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { + it.id == metadataResolverResourceId + } + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByResourceId(metadataResolverResourceId) + + if (targetMetadataResolver && targetMetadataResolver.getMetadataFilter() instanceof MetadataFilterChain) { + MetadataFilterChain metadataFilterChain = (MetadataFilterChain) targetMetadataResolver.getMetadataFilter() + + List metadataFilters = new ArrayList<>() + + // set up namespace protection + if (shibUIConfiguration.protectedAttributeNamespaces && shibUIConfiguration.protectedAttributeNamespaces.size() > 0 && targetMetadataResolver && jpaMetadataResolver.type in ['FileBackedHttpMetadataResolver', 'DynamicHttpMetadataResolver']) { + def target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter() + target.attributeFilter = new ScriptedPredicate(new EvaluableScript(protectedNamespaceScript())) + metadataFilters.add(target) + } + + for (edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter metadataFilter : jpaMetadataResolver.getMetadataFilters()) { + if (metadataFilter instanceof EntityAttributesFilter) { + EntityAttributesFilter entityAttributesFilter = (EntityAttributesFilter) metadataFilter + + org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter() + Map, Collection> rules = new HashMap<>() + switch (entityAttributesFilter.getEntityAttributesFilterTarget().getEntityAttributesFilterTargetType()) { + case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY: + rules.put( + new EntityIdPredicate(entityAttributesFilter.getEntityAttributesFilterTarget().getValue()), + (List) (List) entityAttributesFilter.getAttributes() + ) + break + case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.CONDITION_SCRIPT: + rules.put(new ScriptedPredicate(new EvaluableScript(entityAttributesFilter.entityAttributesFilterTarget.value[0])), + (List) (List) entityAttributesFilter.getAttributes()) + break + case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.REGEX: + rules.put(new ScriptedPredicate(new EvaluableScript(generateJavaScriptRegexScript(entityAttributesFilter.entityAttributesFilterTarget.value[0]))), + (List) (List) entityAttributesFilter.getAttributes()) + break + default: + // do nothing, we'd have exploded elsewhere previously. + break + } + target.setRules(rules) + metadataFilters.add(target) + } + if (metadataFilter instanceof NameIdFormatFilter) { + NameIdFormatFilter nameIdFormatFilter = NameIdFormatFilter.cast(metadataFilter) + NameIDFormatFilter openSamlTargetFilter = new OpenSamlNameIdFormatFilter() + openSamlTargetFilter.removeExistingFormats = nameIdFormatFilter.removeExistingFormats + Map, Collection> predicateRules = [:] + def type = nameIdFormatFilter.nameIdFormatFilterTarget.nameIdFormatFilterTargetType + def values = nameIdFormatFilter.nameIdFormatFilterTarget.value + switch (type) { + case ENTITY: + predicateRules[new EntityIdPredicate(values)] = nameIdFormatFilter.formats + break + case CONDITION_SCRIPT: + predicateRules[new ScriptedPredicate(new EvaluableScript(values[0]))] = nameIdFormatFilter.formats + break + case REGEX: + predicateRules[new ScriptedPredicate(new EvaluableScript(generateJavaScriptRegexScript(values[0])))] = nameIdFormatFilter.formats + break + default: + // do nothing, we'd have exploded elsewhere previously. + break + } + openSamlTargetFilter.rules = predicateRules + metadataFilters << openSamlTargetFilter + } + } + metadataFilterChain.setFilters(metadataFilters) + } + + if (targetMetadataResolver != null && targetMetadataResolver instanceof Refilterable) { + (Refilterable) targetMetadataResolver.refilter() + } else { + //TODO: Do something here if we need to refilter other non-Batch resolvers + log.warn("Target resolver is not a Refilterable resolver. Skipping refilter()") + } + } + + public edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver updateMetadataResolverEnabledStatus(edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver updatedResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException { + // @TODO: when merged with groups, this should maybe be merged with group check as they have to have the role in the right group + if (!userService.currentUserHasExpectedRole(["ROLE_ADMIN", "ROLE_ENABLE"])) { + throw new ForbiddenException("You do not have the permissions necessary to change the enable status of this filter.") + } + + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver persistedResolver = metadataResolverRepository.save(updatedResolver) + + if (persistedResolver.getDoInitialization()) { + MetadataResolver openSamlRepresentation = null + try { + openSamlRepresentation = metadataResolverConverterService.convertToOpenSamlRepresentation(persistedResolver) + } catch (FileNotFoundException e) { + throw new MetadataFileNotFoundException("message.file-doesnt-exist") + } + try { + OpenSamlChainingMetadataResolverUtil.updateChainingMetadataResolver((OpenSamlChainingMetadataResolver) chainingMetadataResolver, openSamlRepresentation); + } + catch (Throwable e) { + throw new InitializationException(e); + } + } + + } + + private class ScriptedPredicate extends net.shibboleth.utilities.java.support.logic.ScriptedPredicate { + protected ScriptedPredicate(@Nonnull EvaluableScript theScript) { + super(theScript) + } } } diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy index 4ca5b435b..2635f908c 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrap.groovy @@ -6,6 +6,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.security.repository.RoleRepository import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository +import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService import groovy.util.logging.Slf4j import org.springframework.boot.context.event.ApplicationStartedEvent import org.springframework.context.event.EventListener @@ -19,11 +20,13 @@ class UserBootstrap { private final ShibUIConfiguration shibUIConfiguration private final UserRepository userRepository private final RoleRepository roleRepository + private final UserService userService - UserBootstrap(ShibUIConfiguration shibUIConfiguration, UserRepository userRepository, RoleRepository roleRepository) { + UserBootstrap(ShibUIConfiguration shibUIConfiguration, UserRepository userRepository, RoleRepository roleRepository, UserService userService) { this.shibUIConfiguration = shibUIConfiguration this.userRepository = userRepository this.roleRepository = roleRepository + this.userService = userService } @Transactional @@ -50,7 +53,7 @@ class UserBootstrap { it.emailAddress = email it } - userRepository.saveAndFlush(user) + userService.save(user) } } } 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 da33c53f8..06299172a 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 @@ -1,6 +1,27 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; +import javax.servlet.http.HttpServletRequest; + +import org.apache.lucene.analysis.Analyzer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.support.ResourceBundleMessageSource; +import org.springframework.core.io.Resource; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.util.UrlPathHelper; + import com.fasterxml.jackson.databind.Module; + 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.repository.MetadataResolverRepository; @@ -13,49 +34,25 @@ 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.EntityDescriptorService; 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; import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityServiceImpl; -import edu.internet2.tier.shibboleth.admin.ui.service.JPAFilterServiceImpl; import edu.internet2.tier.shibboleth.admin.ui.service.JPAFilterTargetServiceImpl; -import edu.internet2.tier.shibboleth.admin.ui.service.JPAMetadataResolverServiceImpl; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolversPositionOrderContainerService; import edu.internet2.tier.shibboleth.admin.util.AttributeUtility; import edu.internet2.tier.shibboleth.admin.util.LuceneUtility; import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions; -import org.apache.lucene.analysis.Analyzer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.ResourceBundleMessageSource; -import org.springframework.core.io.Resource; -import org.springframework.web.servlet.LocaleResolver; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; -import org.springframework.web.util.UrlPathHelper; - -import javax.servlet.http.HttpServletRequest; @Configuration +@Import(SearchConfiguration.class) +@ComponentScan(basePackages="{ edu.internet2.tier.shibboleth.admin.ui.service }") @EnableConfigurationProperties({CustomPropertiesConfiguration.class, ShibUIConfiguration.class}) public class CoreShibUiConfiguration { - private static final Logger logger = LoggerFactory.getLogger(CoreShibUiConfiguration.class); - @Bean public OpenSamlObjects openSamlObjects() { return new OpenSamlObjects(); @@ -66,25 +63,25 @@ public EntityService jpaEntityService() { return new JPAEntityServiceImpl(openSamlObjects()); } - @Bean - public EntityDescriptorService jpaEntityDescriptorService(UserService userService) { - return new JPAEntityDescriptorServiceImpl(openSamlObjects(), jpaEntityService(), userService); - } +// @Bean +// public EntityDescriptorService JPAEntityDescriptorServiceImpl(UserService userService) { +// return new JPAEntityDescriptorServiceImpl(openSamlObjects(), jpaEntityService(), userService); +// } - @Bean - public FilterService jpaFilterService() { - return new JPAFilterServiceImpl(); - } +// @Bean +// public FilterService jpaFilterService() { +// return new JPAFilterServiceImpl(); +// } @Bean public FilterTargetService jpaFilterTargetService() { return new JPAFilterTargetServiceImpl(); } - @Bean - public MetadataResolverService metadataResolverService() { - return new JPAMetadataResolverServiceImpl(); - } +// @Bean +// public MetadataResolverService metadataResolverService() { +// return new JPAMetadataResolverServiceImpl(); +// } @Bean public AttributeUtility attributeUtility() { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java deleted file mode 100644 index 6380e0018..000000000 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.configuration; - -import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService; -import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterServiceImpl; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Bill Smith (wsmith@unicon.net) - */ -@Configuration -public class MetadataResolverConverterConfiguration { - @Bean - public MetadataResolverConverterService metadataResolverConverterService() { - return new MetadataResolverConverterServiceImpl(); - } -} 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 1a3ecf0a4..60705cd15 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 @@ -3,19 +3,25 @@ import javax.script.ScriptException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +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.EntityDescriptorRepresentation; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; +import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException; 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.MetadataResolverService; @RestController @RequestMapping("/api/activate") @@ -27,6 +33,9 @@ public class ActivateController { @Autowired private FilterService filterService; + @Autowired + private MetadataResolverService metadataResolverService; + @PatchMapping(path = "/entityDescriptor/{resourceId}/{mode}") @Transactional public ResponseEntity enableEntityDescriptor(@PathVariable String resourceId, @PathVariable String mode) throws EntityNotFoundException, ForbiddenException { @@ -42,5 +51,15 @@ public ResponseEntity enableFilter(@PathVariable String metadataResolverId, @ MetadataFilter persistedFilter = filterService.updateFilterEnabledStatus(metadataResolverId, resourceId, status); return ResponseEntity.ok(persistedFilter); } -// Enable/disable for : , provider + + @PatchMapping("/MetadataResolvers/{resourceId}/{mode}") + @Transactional + public ResponseEntity enableProvider(@PathVariable String resourceId, @PathVariable String mode) throws EntityNotFoundException, ForbiddenException, MetadataFileNotFoundException, InitializationException { + boolean status = "enable".equalsIgnoreCase(mode); + MetadataResolver existingResolver = metadataResolverService.findByResourceId(resourceId); + existingResolver.setEnabled(status); + existingResolver = metadataResolverService.updateMetadataResolverEnabledStatus(existingResolver); + + return ResponseEntity.ok(existingResolver); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateExceptionHandler.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateExceptionHandler.java index 85264b582..0c766c53c 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateExceptionHandler.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/ActivateExceptionHandler.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; + import javax.script.ScriptException; import org.springframework.http.HttpStatus; @@ -9,8 +11,10 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; +import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException; @ControllerAdvice(assignableTypes = {ActivateController.class}) public class ActivateExceptionHandler extends ResponseEntityExceptionHandler { @@ -25,8 +29,20 @@ public ResponseEntity handleForbiddenAccess(ForbiddenException e, WebRequest return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(String.valueOf(HttpStatus.FORBIDDEN.value()), e.getMessage())); } + @ExceptionHandler({ InitializationException.class }) + public ResponseEntity handleInitializationException(InitializationException e, WebRequest request) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), e.getMessage())); + } + + @ExceptionHandler({ MetadataFileNotFoundException.class }) + public ResponseEntity handleMetadataFileNotFoundException(MetadataFileNotFoundException e, WebRequest request) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse(INTERNAL_SERVER_ERROR.toString(), e.getLocalizedMessage())); + } + @ExceptionHandler({ ScriptException.class }) public ResponseEntity handleScriptException(ScriptException e, WebRequest request) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), e.getMessage())); } + + } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/InitializationException.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/InitializationException.java new file mode 100644 index 000000000..f18483176 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/InitializationException.java @@ -0,0 +1,7 @@ +package edu.internet2.tier.shibboleth.admin.ui.exception; + +public class InitializationException extends Exception { + public InitializationException(Exception e) { + super(e); + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java index 898e99e00..c3bac03de 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/service/UserService.java @@ -5,6 +5,8 @@ import java.util.Optional; import java.util.Set; +import javax.transaction.Transactional; + import org.apache.commons.lang.StringUtils; import org.springframework.security.core.context.SecurityContextHolder; @@ -80,4 +82,10 @@ public boolean currentUserHasExpectedRole(List acceptedRoles) { User user = getCurrentUser(); return acceptedRoles.contains(user.getRole()); } + + @Transactional + public User save(User user) { + // NOTE: REPLACE ENTIRELY WITH 1740 code + return userRepository.save(user); + } } 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 ab93343c8..291e300c2 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 @@ -58,6 +58,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; @@ -78,6 +79,7 @@ * * @since 1.0 */ +@Service public class JPAEntityDescriptorServiceImpl implements EntityDescriptorService { @Autowired private EntityDescriptorRepository entityDescriptorRepository; @@ -88,6 +90,7 @@ public class JPAEntityDescriptorServiceImpl implements EntityDescriptorService { @Autowired private EntityService entityService; + @Autowired private UserService userService; public JPAEntityDescriptorServiceImpl(OpenSamlObjects openSamlObjects, EntityService entityService, UserService userService) { 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 6810fa243..23a70268a 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 @@ -11,6 +11,7 @@ import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.util.ArrayList; @@ -26,6 +27,7 @@ * @since 1.0 * @author Bill Smith (wsmith@unicon.net) */ +@Service public class JPAFilterServiceImpl implements FilterService { @Autowired EntityDescriptorService entityDescriptorService; 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 ee5f8cec3..2343206a7 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 @@ -22,6 +22,7 @@ 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 java.io.File; import java.io.FileNotFoundException; @@ -32,6 +33,7 @@ /** * @author Bill Smith (wsmith@unicon.net) */ +@Service public class MetadataResolverConverterServiceImpl implements MetadataResolverConverterService { @Autowired diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java index 376c34aa5..5fd205c20 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java @@ -2,8 +2,18 @@ import org.w3c.dom.Document; +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.exception.EntityNotFoundException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; +import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException; + public interface MetadataResolverService { - public void reloadFilters(String metadataResolverName); + public MetadataResolver findByResourceId(String resourceId) throws EntityNotFoundException; public Document generateConfiguration(); + + public void reloadFilters(String metadataResolverName); + + public MetadataResolver updateMetadataResolverEnabledStatus(MetadataResolver existingResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException; } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy index 280294aa1..b915d6fac 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 @@ -7,10 +7,14 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.Internationalization import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException +import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException +import edu.internet2.tier.shibboleth.admin.ui.exception.InitializationException 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 @@ -86,6 +90,18 @@ class MetadataFiltersControllerTests extends Specification { Document generateConfiguration() { return null } + + @Override + public MetadataResolver updateMetadataResolverEnabledStatus(MetadataResolver existingResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException { + // This won't get called + return null + } + + @Override + public MetadataResolver findByResourceId(String resourceId) throws EntityNotFoundException { + // This won't get called + return null + } }, chainingMetadataResolver: new OpenSamlChainingMetadataResolver().with { it.id = 'chain' diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy index 3ab2154ea..1f3c7962a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy @@ -2,7 +2,6 @@ package edu.internet2.tier.shibboleth.admin.ui.service import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration -import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConverterConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration @@ -51,7 +50,7 @@ import spock.lang.Unroll import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedXmlIsTheSameAsExpectedXml @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, MetadataResolverConverterConfiguration, SearchConfiguration, InternationalizationConfiguration, PlaceholderResolverComponentsConfiguration, edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration ,Config]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration, PlaceholderResolverComponentsConfiguration, edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration ,Config]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 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 index 8a261565e..f5d0f72e3 100644 --- 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 @@ -1,9 +1,13 @@ package edu.internet2.tier.shibboleth.admin.ui.service +import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration 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 org.springframework.test.context.ContextConfiguration + import spock.lang.Specification @SpringBootTest diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrapTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrapTests.groovy index 0a5db2bcf..93857449e 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrapTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/UserBootstrapTests.groovy @@ -7,6 +7,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration 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 org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest @@ -33,12 +34,19 @@ class UserBootstrapTests extends Specification { @Autowired RoleRepository roleRepository + + @Autowired + UserService userService + def setup() { + roleRepository.deleteAll(); + } + def "simple test"() { setup: shibUIConfiguration.roles = [] shibUIConfiguration.userBootstrapResource = new ClassPathResource('/conf/1044.csv') - def userBootstrap = new UserBootstrap(shibUIConfiguration, userRepository, roleRepository) + def userBootstrap = new UserBootstrap(shibUIConfiguration, userRepository, roleRepository, userService) when: userBootstrap.bootstrapUsersAndRoles(null) @@ -52,7 +60,7 @@ class UserBootstrapTests extends Specification { def "bootstrap roles"() { setup: shibUIConfiguration.roles = ['ROLE_ADMIN', 'ROLE_USER'] - def userbootstrap = new UserBootstrap(shibUIConfiguration, userRepository, roleRepository) + def userbootstrap = new UserBootstrap(shibUIConfiguration, userRepository, roleRepository, userService) when: userbootstrap.bootstrapUsersAndRoles(null)