Skip to content

Commit

Permalink
SHIBUI-2268
Browse files Browse the repository at this point in the history
initial commit, no working state
  • Loading branch information
chasegawa committed Jun 21, 2022
1 parent cc4a9f1 commit 9827498
Show file tree
Hide file tree
Showing 10 changed files with 533 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityRoleWhiteList
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.algorithm.AlgorithmFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.opensaml.OpenSamlNameIdFormatFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver
Expand Down Expand Up @@ -88,6 +89,16 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService {
}
}

void constructXmlNodeForFilter(AlgorithmFilter filter, def markupBuilderDelegate) {
if (!filter.isFilterEnabled()) { return }
markupBuilderDelegate.MetadataFilter('xsi:type': 'Algorithm') {
// TODO: enhance. currently this does weird things with namespaces
filter.unknownXMLObjects.each { xmlObject ->
mkp.yieldUnescaped(openSamlObjects.marshalToXmlString(xmlObject, false))
}
}
}

void constructXmlNodeForFilter(EntityAttributesFilter filter, def markupBuilderDelegate) {
if (!filter.isFilterEnabled()) { return }
markupBuilderDelegate.MetadataFilter('xsi:type': 'EntityAttributes') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.filters.algorithm;

import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractXMLObject;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.envers.Audited;
import org.opensaml.core.xml.ElementExtensibleXMLObject;
import org.opensaml.core.xml.XMLObject;

import javax.annotation.Nonnull;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* Following the pattern of AbstractElementExtensibleXMLObject - this XML type can hold a couple of different types of XML objects
*/
@Entity
@Audited
@Getter
@Setter
@ToString
@EqualsAndHashCode(callSuper = true)
public class AlgorithmFilter extends MetadataFilter {
@OneToMany(cascade = CascadeType.ALL)
@OrderColumn
private List<AbstractXMLObject> unknownXMLObjects = new ArrayList<>();

public void addUnknownXMLObject(AbstractXMLObject xmlObject) {
this.unknownXMLObjects.add(xmlObject);
}

@Nonnull
public List<XMLObject> getUnknownXMLObjects() {
return (List<XMLObject>) (List<? extends XMLObject>) this.unknownXMLObjects;
}

private AlgorithmFilter updateConcreteFilterTypeData(AlgorithmFilter filterToBeUpdated) {
for (XMLObject o : getUnknownXMLObjects()) {
filterToBeUpdated.addUnknownXMLObject((AbstractXMLObject) o);
}
return filterToBeUpdated;
}

@Override
public MetadataFilter updateConcreteFilterTypeData(MetadataFilter filterToBeUpdated) {
return updateConcreteFilterTypeData((AlgorithmFilter) filterToBeUpdated);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.filters.algorithm;

import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractXMLObject;

import javax.annotation.Nullable;

public class Entity extends AbstractXMLObject implements org.opensaml.core.xml.schema.XSString {
private String uri;

private Entity(){
setElementLocalName("Entity");
}

@Nullable
@Override
public String getValue() {
return this.uri;
}

@Override
public void setValue(@Nullable String newValue) {
this.uri = newValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ public void init() throws ComponentInitializationException {
this.unmarshallerFactory = registry.getUnmarshallerFactory();
}

public String marshalToXmlString(XMLObject ed, boolean includeXMLDeclaration) throws MarshallingException {
Marshaller marshaller = this.marshallerFactory.getMarshaller(ed);
ed.releaseDOM();
ed.releaseChildrenDOM(true);
String entityDescriptorXmlString = null;
public String marshalToXmlString(XMLObject xmlObject, boolean includeXMLDeclaration) throws MarshallingException {
Marshaller marshaller = this.marshallerFactory.getMarshaller(xmlObject);
xmlObject.releaseDOM();
xmlObject.releaseChildrenDOM(true);
String resultString = null;
if (marshaller != null) {
try (StringWriter writer = new StringWriter()) {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
Expand All @@ -101,22 +101,22 @@ public String marshalToXmlString(XMLObject ed, boolean includeXMLDeclaration) th
if (!includeXMLDeclaration) {
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
}
transformer.transform(new DOMSource(marshaller.marshall(ed)), new StreamResult(writer));
entityDescriptorXmlString = writer.toString();
transformer.transform(new DOMSource(marshaller.marshall(xmlObject)), new StreamResult(writer));
resultString = writer.toString();
} catch (TransformerException | IOException e) {
logger.error(e.getMessage(), e);
}
}

if (entityDescriptorXmlString == null) {
if (resultString == null) {
//Figure out the best way to deal with this case
throw new RuntimeException("Unable to marshal EntityDescriptor");
throw new RuntimeException("Unable to marshal xmlObject");
}
return entityDescriptorXmlString;
return resultString;
}

public String marshalToXmlString(XMLObject ed) throws MarshallingException {
return this.marshalToXmlString(ed, true);
public String marshalToXmlString(XMLObject xmlObject) throws MarshallingException {
return this.marshalToXmlString(xmlObject, true);
}

public EntityDescriptor unmarshalFromXml(byte[] entityDescriptorXml) throws Exception {
Expand Down Expand Up @@ -152,4 +152,4 @@ public <T extends XMLObject> T buildDefaultInstanceOfType(Class<T> type) {
throw new RuntimeException("there was a problem building an instance", e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package edu.internet2.tier.shibboleth.admin.ui.opensaml.config

import org.opensaml.core.xml.config.AbstractXMLObjectProviderInitializer

class JPAXMLObjectProviderInitializerForTest extends AbstractXMLObjectProviderInitializer {
@Override
protected String[] getConfigResources() {
return new String[]{
"/jpa-saml2-metadata-config.xml",
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package edu.internet2.tier.shibboleth.admin.ui.service
import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest
import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration
import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration
import edu.internet2.tier.shibboleth.admin.ui.domain.EncryptionMethod
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.MetadataFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.algorithm.Entity
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ClasspathMetadataResource
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver
Expand All @@ -16,6 +18,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.SvnMetadataResour
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.opensaml.OpenSamlObjects
import edu.internet2.tier.shibboleth.admin.ui.opensaml.config.JPAXMLObjectProviderInitializerForTest
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository
import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator
import groovy.xml.DOMBuilder
Expand All @@ -40,7 +43,7 @@ import java.time.Instant

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

@ContextConfiguration(classes=[ JPAMRSIConfig, PlaceholderResolverComponentsConfiguration ])
@ContextConfiguration(classes=[ JPAMRSIConfig, PlaceholderResolverComponentsConfiguration, JPAXMLObjectProviderInitializerForTest ])
class JPAMetadataResolverServiceImplTests extends AbstractBaseDataJpaTest {

@Autowired
Expand Down Expand Up @@ -137,6 +140,27 @@ class JPAMetadataResolverServiceImplTests extends AbstractBaseDataJpaTest {
!diff.hasDifferences()
}

def 'test generating AlgorithmFilter xml snippet'() {
given:
def filter = TestObjectGenerator.algorithmFilter()
EncryptionMethod encryptionMethod = new EncryptionMethod()
encryptionMethod.setAlgorithm("http://www.w3.org/2001/04/xmlenc#aes128-cbc")
encryptionMethod.setElementLocalName("EncryptionMethod")
filter.addUnknownXMLObject(encryptionMethod)
Entity entity = new Entity()
entity.setValue("https://broken.example.org/sp")
filter.addUnknownXMLObject(entity)
Entity entity2 = new Entity()
entity2.setValue("https://also-broken.example.org/sp")
filter.addUnknownXMLObject(entity2)

when:
genXmlSnippet(markupBuilder) { JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForFilter(filter, it) }

then:
generatedXmlIsTheSameAsExpectedXml('/conf/2268-simple.xml', domBuilder.parseText(writer.toString()))
}

def 'test generating EntityAttributesFilter xml snippet with condition script'() {
given:
def filter = testObjectGenerator.entityAttributesFilterWithConditionScript()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilterTarget
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.algorithm.AlgorithmFilter
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.resolvers.ClasspathMetadataResource
Expand Down Expand Up @@ -183,6 +184,14 @@ class TestObjectGenerator {
randomFilter
}

static AlgorithmFilter algorithmFilter() {
return new AlgorithmFilter().with {
it.name = "Algorithm"
it.enabled = true;
it
}
}

SignatureValidationFilter signatureValidationFilter() {
new SignatureValidationFilter().with {
it.name = 'SignatureValidation'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
edu.internet2.tier.shibboleth.admin.ui.opensaml.config.JPAXMLObjectProviderInitializerForTest
7 changes: 7 additions & 0 deletions backend/src/test/resources/conf/2268-simple.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<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'>
<MetadataFilter xsi:type='Algorithm'>
<md:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<Entity>https://broken.example.org/sp</Entity>
<Entity>https://also-broken.example.org/sp</Entity>
</MetadataFilter>
</MetadataProvider>
Loading

0 comments on commit 9827498

Please sign in to comment.