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 9d804eee4..d262e4651 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 @@ -59,6 +59,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -322,6 +323,7 @@ void setupSPSSODescriptor(EntityDescriptor ed, EntityDescriptorRepresentation re if (representation.getServiceProviderSsoDescriptor() != null) { SPSSODescriptor spssoDescriptor = getSPSSODescriptorFromEntityDescriptor(ed); + spssoDescriptor.setSupportedProtocols(Collections.EMPTY_LIST); if (!Strings.isNullOrEmpty(representation.getServiceProviderSsoDescriptor().getProtocolSupportEnum())) { spssoDescriptor.setSupportedProtocols( Arrays.stream(representation.getServiceProviderSsoDescriptor().getProtocolSupportEnum().split(",")).map(p -> MDDCConstants.PROTOCOL_BINDINGS.get(p.trim())).collect(Collectors.toList()) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityDescriptorServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityDescriptorServiceImplTests.groovy index 85f1202c6..04ae58e95 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityDescriptorServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryJPAEntityDescriptorServiceImplTests.groovy @@ -1,11 +1,19 @@ package edu.internet2.tier.shibboleth.admin.ui.service +import edu.internet2.tier.shibboleth.admin.ui.domain.ContactPerson +import edu.internet2.tier.shibboleth.admin.ui.domain.EmailAddress import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor +import edu.internet2.tier.shibboleth.admin.ui.domain.GivenName +import edu.internet2.tier.shibboleth.admin.ui.domain.NameIDFormat import edu.internet2.tier.shibboleth.admin.ui.domain.SPSSODescriptor import edu.internet2.tier.shibboleth.admin.ui.domain.SingleLogoutService +import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.ContactRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.LogoutEndpointRepresentation +import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.ServiceProviderSsoDescriptorRepresentation import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import org.opensaml.saml.common.xml.SAMLConstants +import org.opensaml.saml.saml2.metadata.ContactPersonTypeEnumeration import spock.lang.Shared import spock.lang.Specification import spock.lang.Unroll @@ -38,7 +46,7 @@ class AuxiliaryJPAEntityDescriptorServiceImplTests extends Specification { assert starter == expected where: - [method, description, representation, starter, expected] << Data.getData(openSAMLObjects) + [method, description, representation, starter, expected] << Data.getData(openSAMLObjects) } static class Data { @@ -138,6 +146,311 @@ class AuxiliaryJPAEntityDescriptorServiceImplTests extends Specification { it }, ) + data << new DataField( + method: 'setupContacts', + description: 'add contact to empty descriptor', + representation: new EntityDescriptorRepresentation().with { + it.contacts = [new ContactRepresentation(type: 'administrative', name: 'name', emailAddress: 'test@test', displayName: 'displayName', url: 'http://url')] + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class), + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.ADMINISTRATIVE + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test@test' + it + }) + it + }] + it + } + ) + data << new DataField( + method: 'setupContacts', + description: 'add contant to non-empty descriptor', + representation: new EntityDescriptorRepresentation().with { + it.contacts = [ + new ContactRepresentation(type: 'administrative', name: 'name', emailAddress: 'test@test', displayName: 'displayName', url: 'http://url'), + new ContactRepresentation(type: 'technical', name: 'name2', emailAddress: 'test2@test', displayName: 'displayName2', url: 'http://url2') + ] + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.ADMINISTRATIVE + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test@test' + it + }) + it + }] + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [ + openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.ADMINISTRATIVE + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test@test' + it + }) + it + }, + openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.TECHNICAL + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name2' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test2@test' + it + }) + it + }] + it + } + ) + data << new DataField( + method: 'setupContacts', + description: 'update contact', + representation: new EntityDescriptorRepresentation().with { + it.contacts = [new ContactRepresentation(type: 'technical', name: 'name2', emailAddress: 'test2@test', displayName: 'displayName', url: 'http://url')] + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.ADMINISTRATIVE + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test@test' + it + }) + it + }] + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.TECHNICAL + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name2' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test2@test' + it + }) + it + }] + it + } + ) + data << new DataField( + method: 'setupContacts', + description: 'delete contacts', + representation: new EntityDescriptorRepresentation(), + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.contactPersons = [openSAMLObjects.buildDefaultInstanceOfType(ContactPerson.class).with { + it.type = ContactPersonTypeEnumeration.ADMINISTRATIVE + it.givenName = openSAMLObjects.buildDefaultInstanceOfType(GivenName.class).with { + it.name = 'name' + it + } + it.emailAddresses.add(openSAMLObjects.buildDefaultInstanceOfType(EmailAddress.class).with { + it.address = 'test@test' + it + }) + it + }] + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class) + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'set SPSSODescriptor protocol support', + representation: new EntityDescriptorRepresentation().with { + it.serviceProviderSsoDescriptor = new ServiceProviderSsoDescriptorRepresentation().with { + it.protocolSupportEnum = 'SAML 2' + it + } + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class), + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.supportedProtocols = [SAMLConstants.SAML20P_NS] + it + } + ) + it + } + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'add SPSSODescriptor protocol support', + representation: new EntityDescriptorRepresentation().with { + it.serviceProviderSsoDescriptor = new ServiceProviderSsoDescriptorRepresentation().with { + it.protocolSupportEnum = 'SAML 1.1,SAML 2' + it + } + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.supportedProtocols = [SAMLConstants.SAML20P_NS] + it + } + ) + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.supportedProtocols = [SAMLConstants.SAML11P_NS, SAMLConstants.SAML20P_NS] + it + } + ) + it + } + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'remove SPSSODescriptor', + representation: new EntityDescriptorRepresentation(), + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.supportedProtocols = [SAMLConstants.SAML20P_NS] + it + } + ) + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class) + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'set nameid formats', + representation: new EntityDescriptorRepresentation().with { + it.serviceProviderSsoDescriptor = new ServiceProviderSsoDescriptorRepresentation().with { + it.nameIdFormats = ['testformat'] + it + } + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class), + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'testformat' + it + }) + it + } + ) + it + } + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'add nameid formats', + representation: new EntityDescriptorRepresentation().with { + it.serviceProviderSsoDescriptor = new ServiceProviderSsoDescriptorRepresentation().with { + it.nameIdFormats = ['testformat', 'anotherformat'] + it + } + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'testformat' + it + }) + it + } + ) + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'testformat' + it + }) + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'anotherformat' + it + }) + it + } + ) + it + } + ) + data << new DataField( + method: 'setupSPSSODescriptor', + description: 'remove nameid format', + representation: new EntityDescriptorRepresentation().with { + it.serviceProviderSsoDescriptor = new ServiceProviderSsoDescriptorRepresentation().with { + it.nameIdFormats = ['anotherformat'] + it + } + it + }, + starter: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'testformat' + it + }) + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'anotherformat' + it + }) + it + } + ) + it + }, + expected: openSAMLObjects.buildDefaultInstanceOfType(EntityDescriptor.class).with { + it.getRoleDescriptors().add( + openSAMLObjects.buildDefaultInstanceOfType(SPSSODescriptor.class).with { + it.nameIDFormats.add(openSAMLObjects.buildDefaultInstanceOfType(NameIDFormat.class).with { + it.format = 'anotherformat' + it + }) + it + } + ) + it + } + ) + return data }