Skip to content

Commit

Permalink
SHIBUI-517[532] work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
dima767 committed Jun 8, 2018
1 parent 7d0c33c commit f96a45d
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import com.google.common.base.Predicate;
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter;
import com.google.common.base.Predicate
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository
import groovy.util.logging.Slf4j
import groovy.xml.DOMBuilder
import groovy.xml.MarkupBuilder;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
import org.opensaml.saml.common.profile.logic.EntityIdPredicate;
import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver;
import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;

public class JPAMetadataResolverServiceImpl implements MetadataResolverService {
private static final Logger logger = LoggerFactory.getLogger(JPAMetadataResolverServiceImpl.class);
import groovy.xml.MarkupBuilder
import net.shibboleth.utilities.java.support.resolver.ResolverException
import org.opensaml.saml.common.profile.logic.EntityIdPredicate
import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver
import org.opensaml.saml.metadata.resolver.MetadataResolver
import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter
import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain
import org.opensaml.saml.saml2.core.Attribute
import org.opensaml.saml.saml2.metadata.EntityDescriptor

import org.springframework.beans.factory.annotation.Autowired
import org.w3c.dom.Document

@Slf4j
class JPAMetadataResolverServiceImpl implements MetadataResolverService {

@Autowired
private MetadataResolver metadataResolver
Expand All @@ -35,52 +36,52 @@ public class JPAMetadataResolverServiceImpl implements MetadataResolverService {

// TODO: enhance
@Override
public void reloadFilters(String metadataResolverName) {
ChainingMetadataResolver chainingMetadataResolver = (ChainingMetadataResolver)metadataResolver;

// MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().stream().filter(r -> r.getId().equals(metadataResolverName)).findFirst().get();
void reloadFilters(String metadataResolverName) {
ChainingMetadataResolver chainingMetadataResolver = (ChainingMetadataResolver)metadataResolver
MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { it.id == metadataResolverName }
edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByName(metadataResolverName);
edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByName(metadataResolverName)

if (targetMetadataResolver && targetMetadataResolver.getMetadataFilter() instanceof MetadataFilterChain) {
MetadataFilterChain metadataFilterChain = (MetadataFilterChain)targetMetadataResolver.getMetadataFilter();
MetadataFilterChain metadataFilterChain = (MetadataFilterChain)targetMetadataResolver.getMetadataFilter()

List<MetadataFilter> metadataFilters = new ArrayList<>();
List<MetadataFilter> metadataFilters = new ArrayList<>()

for (edu.internet2.tier.shibboleth.admin.ui.domain.MetadataFilter metadataFilter : jpaMetadataResolver.getMetadataFilters()) {
if (metadataFilter instanceof EntityAttributesFilter) {
EntityAttributesFilter entityAttributesFilter = (EntityAttributesFilter) metadataFilter;
EntityAttributesFilter entityAttributesFilter = (EntityAttributesFilter) metadataFilter

org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter();
Map<Predicate<EntityDescriptor>, Collection<Attribute>> rules = new HashMap<>();
org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter target = new org.opensaml.saml.metadata.resolver.filter.impl.EntityAttributesFilter()
Map<Predicate<EntityDescriptor>, Collection<Attribute>> rules = new HashMap<>()
if (entityAttributesFilter.getEntityAttributesFilterTarget().getEntityAttributesFilterTargetType() == EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY) {
rules.put(
new EntityIdPredicate(entityAttributesFilter.getEntityAttributesFilterTarget().getValue()),
(List<Attribute>)(List<? extends Attribute>)entityAttributesFilter.getAttributes()
);
)
}
target.setRules(rules);
metadataFilters.add(target);
target.setRules(rules)
metadataFilters.add(target)
}
}
metadataFilterChain.setFilters(metadataFilters);
metadataFilterChain.setFilters(metadataFilters)
}

if (metadataResolver instanceof RefreshableMetadataResolver) {
try {
((RefreshableMetadataResolver)metadataResolver).refresh();
((RefreshableMetadataResolver)metadataResolver).refresh()
} catch (ResolverException e) {
logger.warn("error refreshing metadataResolver " + metadataResolverName, e);
log.warn("error refreshing metadataResolver " + metadataResolverName, e)
}
}
}

// TODO: enhance
@Override
public Document generateConfiguration() {
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',
Expand Down Expand Up @@ -135,4 +136,17 @@ public class JPAMetadataResolverServiceImpl implements MetadataResolverService {
return DOMBuilder.newInstance().parseText(writer.toString())
}
}

void constructXmlNodeFor(FileBackedHttpMetadataResolver resolver, def markupBuilderDelegate) {
def attributes = [id: "${resolver.name}",
'xsi:type': 'FileBackedHTTPMetadataProvider',
backingFile: resolver.backingFile,
metadataURL: resolver.metadataURL,
minRefreshDelay: resolver.reloadableMetadataResolverAttributes?.minRefreshDelay,
maxRefreshDelay: resolver.reloadableMetadataResolverAttributes?.maxRefreshDelay,
refreshDelayFactor: resolver.reloadableMetadataResolverAttributes?.refreshDelayFactor]

markupBuilderDelegate.MetadataProvider(attributes)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
@ToString
public class FileBackedHttpMetadataResolver extends MetadataResolver {

private String metadataURL;

private String backingFile;

private Boolean initializeFromBackupFile;

private String backupFileInitNextRefreshDelay;


@Embedded
private ReloadableMetadataResolverAttributes reloadableMetadataResolverAttributes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetada
class FileBackedHttpMetadataResolverRepositoryTests extends Specification {

@Autowired
FileBackedHttpMetadataResolverRepository repositoryUnderTest
MetadataResolverRepository repositoryUnderTest

@Autowired
EntityManager entityManager
Expand Down Expand Up @@ -119,9 +119,9 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification {
entityManager.flush()

then:
def item1 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId)
def item1 = repositoryUnderTest.findByName(persistedResolver.name)
entityManager.clear()
def item2 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId)
def item2 = repositoryUnderTest.findByName(persistedResolver.name)

item1.hashCode() == item2.hashCode()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget
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.util.TestObjectGenerator
import edu.internet2.tier.shibboleth.admin.util.AttributeUtility
import groovy.xml.DOMBuilder
import groovy.xml.MarkupBuilder
import net.shibboleth.ext.spring.resource.ResourceHelper
import net.shibboleth.utilities.java.support.resolver.CriteriaSet
import org.joda.time.DateTime
Expand All @@ -28,6 +33,8 @@ import org.xmlunit.builder.DiffBuilder
import org.xmlunit.builder.Input
import spock.lang.Specification

import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedXmlIsTheSameAsExpectedXml

@SpringBootTest
@DataJpaTest
@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration])
Expand All @@ -50,6 +57,30 @@ class JPAMetadataResolverServiceImplTests extends Specification {
@Autowired
OpenSamlObjects openSamlObjects

@Autowired
AttributeUtility attributeUtility

TestObjectGenerator testObjectGenerator

DOMBuilder domBuilder

StringWriter writer

MarkupBuilder markupBuilder

def setup() {
testObjectGenerator = new TestObjectGenerator(attributeUtility)
domBuilder = DOMBuilder.newInstance()
writer = new StringWriter()
markupBuilder = new MarkupBuilder(writer)
markupBuilder.omitNullAttributes = true
markupBuilder.omitEmptyAttributes = true
}

def cleanup() {
writer.close()
}

def 'test adding a filter'() {
given:
def expectedXML = '''<?xml version="1.0" encoding="UTF-8"?>
Expand Down Expand Up @@ -98,6 +129,28 @@ class JPAMetadataResolverServiceImplTests extends Specification {
!diff.hasDifferences()
}

def 'test generating FileBackedHttMetadataResolver xml snippet'() {
given:
def resolver = testObjectGenerator.fileBackedHttpMetadataResolver()

when:
genXmlSnippet(markupBuilder) { JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeFor(resolver, it) }

then:
assert generatedXmlIsTheSameAsExpectedXml('/conf/532.xml', domBuilder.parseText(writer.toString()))
}

static genXmlSnippet(MarkupBuilder xml, Closure xmlNodeGenerator) {
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'
) {
xmlNodeGenerator(delegate)
}
}

@TestConfiguration
static class Config {
@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package edu.internet2.tier.shibboleth.admin.ui.util

import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.RelyingPartyOverridesRepresentation
import org.apache.commons.lang.StringUtils
import org.w3c.dom.Document
import org.xmlunit.builder.DiffBuilder
import org.xmlunit.builder.Input

/**
* @author Bill Smith (wsmith@unicon.net)
Expand All @@ -22,4 +25,13 @@ class TestHelpers {

return count
}

static generatedXmlIsTheSameAsExpectedXml(String expectedXmlResource, Document generatedXml) {
def diffs = DiffBuilder.compare(Input.fromStream(this.getResourceAsStream(expectedXmlResource))).withTest(Input.fromDocument
(generatedXml))
.ignoreComments().ignoreWhitespace().build().differences

!DiffBuilder.compare(Input.fromStream(this.getResourceAsStream(expectedXmlResource))).withTest(Input.fromDocument(generatedXml))
.ignoreComments().ignoreWhitespace().build().hasDifferences()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.OrganizationURL
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterRepresentation
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterTargetRepresentation
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.RelyingPartyOverridesRepresentation
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ReloadableMetadataResolverAttributes
import edu.internet2.tier.shibboleth.admin.util.AttributeUtility
import edu.internet2.tier.shibboleth.admin.util.MDDCConstants
import org.opensaml.saml.saml2.metadata.Organization

import static edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY
import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes.HttpCachingType.memory

/**
* @author Bill Smith (wsmith@unicon.net)
*/
Expand Down Expand Up @@ -190,6 +196,22 @@ class TestObjectGenerator {
return contactPerson
}

FileBackedHttpMetadataResolver fileBackedHttpMetadataResolver() {
new FileBackedHttpMetadataResolver().with {
it.name = 'HTTPMetadata'
it.backingFile = '%{idp.home}/metadata/incommonmd.xml'
it.metadataURL = 'http://md.incommon.org/InCommon/InCommon-metadata.xml'

it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes().with {
it.minRefreshDelay = 'PT5M'
it.maxRefreshDelay = 'PT1H'
it.refreshDelayFactor = 0.75
it
}
it
}
}

/**
* This method takes a type and a size and builds a List of that size containing objects of that type. This is
* intended to be used with things that extend LocalizedName such as {@link OrganizationName}, {@link OrganizationDisplayName},
Expand Down
15 changes: 15 additions & 0 deletions backend/src/test/resources/conf/532.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is an EXAMPLE metadata configuration file. -->
<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">
<MetadataProvider id="HTTPMetadata"
xsi:type="FileBackedHTTPMetadataProvider"
backingFile="%{idp.home}/metadata/incommonmd.xml"
metadataURL="http://md.incommon.org/InCommon/InCommon-metadata.xml"
minRefreshDelay="PT5M"
maxRefreshDelay="PT1H"
refreshDelayFactor="0.75" />
</MetadataProvider>

0 comments on commit f96a45d

Please sign in to comment.