diff --git a/.gitignore b/.gitignore index 3d9ba1c8d..934a0cec0 100644 --- a/.gitignore +++ b/.gitignore @@ -385,3 +385,9 @@ gradle-app.setting # pac4j pac4j-module/out/ + +#Local run shell script wrapper +r + +#Local integration test run shell script wrapper +rinteg \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/AttributeUtility.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/AttributeUtility.java index 20fca363c..7677c1b56 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/AttributeUtility.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/AttributeUtility.java @@ -64,7 +64,10 @@ public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWi } public edu.internet2.tier.shibboleth.admin.ui.domain.Attribute createAttributeWithStringValues(String name, String friendlyName, List values) { - return createAttributeWithStringValues(name, friendlyName, values.toArray(new String[]{})); + if(values.size() > 0) { + return createAttributeWithStringValues(name, friendlyName, values.toArray(new String[]{})); + } + return null; } /* Calling this method with name = MDDCConstants.RELEASE_ATTRIBUTES seems to be a special case. In this case, diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java index b1669d8a9..12a1bad82 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/ModelRepresentationConversions.java @@ -39,8 +39,7 @@ public ModelRepresentationConversions(CustomPropertiesConfiguration customProper OpenSamlObjects openSamlObjects = new OpenSamlObjects(); try { openSamlObjects.init(); - } - catch (ComponentInitializationException e) { + } catch (ComponentInitializationException e) { throw new IllegalStateException(e); } ATTRIBUTE_UTILITY = new AttributeUtility(openSamlObjects); @@ -81,7 +80,7 @@ public static List getStringListValueOfAttribute(Attribute attribute) { public static Optional getOverrideByAttributeName(String attributeName) { return customPropertiesConfiguration.getOverrides().stream().filter(it -> it.getAttributeName().equals(attributeName)).findFirst(); - } + } public static Map getRelyingPartyOverridesRepresentationFromAttributeList(List attributeList) { Map relyingPartyOverrides = new HashMap<>(); @@ -91,8 +90,8 @@ public static Map getRelyingPartyOverridesRepresentationFromAttr Optional override = getOverrideByAttributeName(jpaAttribute.getName()); if (override.isPresent()) { - relyingPartyOverrides.put(((RelyingPartyOverrideProperty)override.get()).getName(), - getOverrideFromAttribute(jpaAttribute)); + relyingPartyOverrides.put(((RelyingPartyOverrideProperty) override.get()).getName(), + getOverrideFromAttribute(jpaAttribute)); } } @@ -112,7 +111,7 @@ public static Object getOverrideFromAttribute(Attribute attribute) { .filter(it -> it.getAttributeFriendlyName().equals(attribute.getFriendlyName())).findFirst().get(); List attributeValues = attribute.getAttributeValues(); - switch(AttributeTypes.valueOf(relyingPartyOverrideProperty.getDisplayType().toUpperCase())) { + switch (AttributeTypes.valueOf(relyingPartyOverrideProperty.getDisplayType().toUpperCase())) { case BOOLEAN: if (relyingPartyOverrideProperty.getPersistType() != null && (!relyingPartyOverrideProperty.getPersistType().equalsIgnoreCase("boolean"))) { @@ -140,11 +139,11 @@ public static String getValueFromXMLObject(XMLObject xmlObject) { String objectType = xmlObject.getClass().getSimpleName(); switch (objectType) { case "XSAny": - return ((XSAny)xmlObject).getTextContent(); + return ((XSAny) xmlObject).getTextContent(); case "XSString": - return ((XSString)xmlObject).getValue(); + return ((XSString) xmlObject).getValue(); case "XSBoolean": - return ((XSBoolean)xmlObject).getStoredValue(); + return ((XSBoolean) xmlObject).getStoredValue(); default: throw new RuntimeException(String.format("Unsupported XML Object type [%s]", objectType)); } @@ -157,7 +156,7 @@ public static List getAttributeListFromA attributeList.add(ATTRIBUTE_UTILITY.createAttributeWithStringValues(MDDCConstants.RELEASE_ATTRIBUTES, attributeReleaseList)); } - return (List)(List)attributeList; + return (List) (List) attributeList; } public static List getAttributeListFromRelyingPartyOverridesRepresentation @@ -182,8 +181,8 @@ public static List getAttributeListFromA public static Attribute getAttributeFromObjectAndRelyingPartyOverrideProperty(Object o, RelyingPartyOverrideProperty overrideProperty) { switch (ModelRepresentationConversions.AttributeTypes.valueOf(overrideProperty.getDisplayType().toUpperCase())) { case BOOLEAN: - if ((o instanceof Boolean && ((Boolean)o)) || - (o instanceof String) && Boolean.valueOf((String)o)) { + if ((o instanceof Boolean && ((Boolean) o)) || + (o instanceof String) && Boolean.valueOf((String) o)) { if (overrideProperty.getPersistType() != null && !overrideProperty.getPersistType().equalsIgnoreCase("boolean")) { return ATTRIBUTE_UTILITY.createAttributeWithStringValues(overrideProperty.getAttributeName(), @@ -195,7 +194,7 @@ public static Attribute getAttributeFromObjectAndRelyingPartyOverrideProperty(Ob overrideProperty.getAttributeFriendlyName(), Boolean.valueOf((String) o)); } else { - Boolean value = Boolean.valueOf(overrideProperty.getInvert()) ^ (Boolean)o; + Boolean value = Boolean.valueOf(overrideProperty.getInvert()) ^ (Boolean) o; return ATTRIBUTE_UTILITY.createAttributeWithBooleanValue(overrideProperty.getAttributeName(), overrideProperty.getAttributeFriendlyName(), value); @@ -215,16 +214,17 @@ public static Attribute getAttributeFromObjectAndRelyingPartyOverrideProperty(Ob return ATTRIBUTE_UTILITY.createAttributeWithStringValues(overrideProperty.getAttributeName(), overrideProperty.getAttributeFriendlyName(), (List) o); + case LIST: return ATTRIBUTE_UTILITY.createAttributeWithStringValues(overrideProperty.getAttributeName(), overrideProperty.getAttributeFriendlyName(), (List) o); + default: throw new UnsupportedOperationException("getAttributeListFromRelyingPartyOverridesRepresentation was called with an unsupported type (" + overrideProperty.getDisplayType() + ")!"); } } - public enum AttributeTypes { BOOLEAN, INTEGER, diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImplTests.groovy index 1c1778c60..6b5fd4214 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImplTests.groovy @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.ShibbolethUiApplication import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor import edu.internet2.tier.shibboleth.admin.ui.domain.XSAny import edu.internet2.tier.shibboleth.admin.ui.domain.XSAnyBuilder @@ -25,6 +26,7 @@ import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility +import org.opensaml.saml.ext.saml2mdattr.EntityAttributes import org.skyscreamer.jsonassert.JSONAssert import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -877,6 +879,31 @@ class JPAEntityDescriptorServiceImplTests extends Specification { assert representation.relyingPartyOverrides.get('ignoreAuthenticationMethod') instanceof Boolean } + def "SHIBUI-1522"() { + when: + EntityDescriptor inputEd = openSamlObjects.unmarshalFromXml this.class.getResource('/metadata/SHIBUI-1522.xml').bytes + EntityDescriptorRepresentation edr = service.createRepresentationFromDescriptor(inputEd) + edr.relyingPartyOverrides = [nameIdFormats: [], authenticationMethods: []] + EntityDescriptor outputEd = service.createDescriptorFromRepresentation(edr) + + then: + outputEd.getExtensions().unknownXMLObjects[0].attributes.size() == 0 + + when: + edr.relyingPartyOverrides = [nameIdFormats: ['format1', 'format2']] + outputEd = service.createDescriptorFromRepresentation(edr) + + then: + outputEd.getExtensions().unknownXMLObjects[0].attributes.size() == 1 + + when: + edr.relyingPartyOverrides = [nameIdFormats: ['format1', 'format2'], authenticationMethods: ['auth1', 'auth2']] + outputEd = service.createDescriptorFromRepresentation(edr) + + then: + outputEd.getExtensions().unknownXMLObjects[0].attributes.size() == 2 + } + EntityDescriptor generateRandomEntityDescriptor() { EntityDescriptor ed = new EntityDescriptor() diff --git a/backend/src/test/resources/metadata/SHIBUI-1522.xml b/backend/src/test/resources/metadata/SHIBUI-1522.xml new file mode 100644 index 000000000..aa22bd172 --- /dev/null +++ b/backend/src/test/resources/metadata/SHIBUI-1522.xml @@ -0,0 +1,16 @@ + + + + + + Concur Solutions + + https://www.concur.com/sites/all/themes/Concur6/images/Concur_logo.png + + + urn:oid:1.3.6.1.4.1.5923.1.1.1.6 + + +