Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Add InCommonEntityOrderingStrategy
Initial implementation and basic test. See incommon/inc-meta#55.
Showing
7 changed files
with
285 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false"> | ||
<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false"> | ||
<local-check-config name="Shibboleth" location="/Users/iay/git/github/ukf/ukf-mda/checkstyle.xml" type="external" description="Variant of Shibboleth checkstyle.xml"> | ||
<additional-data name="protect-config-file" value="false"/> | ||
</local-check-config> | ||
<fileset name="all" enabled="true" check-config-name="Shibboleth" local="true"> | ||
<file-match-pattern match-pattern="." include-pattern="true"/> | ||
<file-match-pattern match-pattern="src/main/java/" include-pattern="true"/> | ||
</fileset> | ||
</fileset-config> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
/target/ | ||
/test-output/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
src/main/java/uk/org/iay/incommon/dom/saml/InCommonEntityOrderingStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package uk.org.iay.incommon.dom.saml; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import javax.annotation.Nonnull; | ||
import javax.annotation.concurrent.ThreadSafe; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.w3c.dom.Element; | ||
|
||
import net.shibboleth.metadata.Item; | ||
import net.shibboleth.metadata.ItemId; | ||
import net.shibboleth.metadata.dom.saml.EntitiesDescriptorAssemblerStage.ItemOrderingStrategy; | ||
import net.shibboleth.metadata.dom.saml.mdrpi.RegistrationAuthority; | ||
import net.shibboleth.metadata.pipeline.StageProcessingException; | ||
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements; | ||
|
||
/** | ||
* Implements an ordering strategy for InCommon federation aggregates. | ||
* | ||
* The input list contains entities registered by InCommon in a specific | ||
* order which must not be disturbed. They are followed by entities registered | ||
* elsewhere; these are to be grouped by registrar and then within registrar | ||
* ordered by entityID. | ||
* | ||
* The registrar and entityID values used for ordering are required to be | ||
* present in the item's item metadata. | ||
*/ | ||
@ThreadSafe | ||
public class InCommonEntityOrderingStrategy implements ItemOrderingStrategy { | ||
|
||
/** Class logger. */ | ||
private final Logger log = LoggerFactory.getLogger(InCommonEntityOrderingStrategy.class); | ||
|
||
/** The registrar whose entities should always appear first, in the provided order. */ | ||
private final String distinguishedRegistrar; | ||
|
||
/** | ||
* Helper class which wraps an {@link Element} {@link Item} but extracts any | ||
* associated {@link RegistrationAuthority} and {@link ItemId} for simpler comparisons. | ||
*/ | ||
private static class OrderableItem implements Comparable<OrderableItem> { | ||
|
||
/** The wrapped {@link Element} {@link Item}. */ | ||
private final Item<Element> item; | ||
|
||
/** The registrar for this entity. */ | ||
private final String registrar; | ||
|
||
/** The entityID for this entity. */ | ||
private final String entityID; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param domItem the {@link Element} {@link Item} to wrap | ||
* @param reg the registrar for this entity | ||
* @param entity the entityID for this entity | ||
*/ | ||
public OrderableItem(@Nonnull final Item<Element> domItem, | ||
@Nonnull final String reg, @Nonnull final String entity) { | ||
item = domItem; | ||
registrar = reg; | ||
entityID = entity; | ||
} | ||
|
||
@Override | ||
public int compareTo(@Nonnull final OrderableItem o) { | ||
// compare registrar values | ||
final int c = registrar.compareTo(o.registrar); | ||
// done if unequal | ||
if (c != 0) { | ||
return c; | ||
} | ||
// compare entityID values if registrars equal | ||
return entityID.compareTo(o.entityID); | ||
} | ||
|
||
/** | ||
* Unwrap the wrapped {@link Element} {@link Item}. | ||
* | ||
* @return the wrapped {@link Element} {@link Item}. | ||
*/ | ||
public Item<Element> unwrap() { | ||
return item; | ||
} | ||
} | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param registrar distinguished registrar, whose entities sort first | ||
*/ | ||
public InCommonEntityOrderingStrategy(@Nonnull final String registrar) { | ||
distinguishedRegistrar = registrar; | ||
} | ||
|
||
@Override | ||
public List<Item<Element>> order(@Nonnull @NonnullElements final Collection<Item<Element>> items) { | ||
|
||
// Collect the results here | ||
final List<Item<Element>> results = new ArrayList<>(items.size()); | ||
|
||
/* | ||
* Construct an orderable list wrapping the original items. | ||
* | ||
* Any belonging to the distinguished registrar are instead put straight in the | ||
* results list. | ||
*/ | ||
final List<OrderableItem> orderableList = new ArrayList<>(items.size()); | ||
try { | ||
for (Item<Element> item : items) { | ||
final List<RegistrationAuthority> registrars = item.getItemMetadata().get(RegistrationAuthority.class); | ||
final String registrar; | ||
if (registrars.size() == 0) { | ||
throw new StageProcessingException("entity does not have RegistrationAuthority item metadata"); | ||
} else { | ||
registrar = registrars.get(0).getRegistrationAuthority(); | ||
if (distinguishedRegistrar.equals(registrar)) { | ||
results.add(item); | ||
continue; | ||
} | ||
} | ||
|
||
final List<ItemId> itemids = item.getItemMetadata().get(ItemId.class); | ||
final String entityID; | ||
if (itemids.size() == 0) { | ||
throw new StageProcessingException("entity does not have ItemId item metadata"); | ||
} else { | ||
entityID = itemids.get(0).getId(); | ||
} | ||
|
||
orderableList.add(new OrderableItem(item, registrar, entityID)); | ||
} | ||
} catch (StageProcessingException e) { | ||
/* | ||
* If the ordering operation fails because we can't create an OrderableItem | ||
* for each original item, it's probably because we are missing some item | ||
* metadata on one or more items. The signature for the order method does | ||
* not allow this to be reported as of MDA 0.9.x. | ||
* | ||
* This will change in MDA 0.10.0 (see IDP-175) but for now all we | ||
* can really do is log an error and return the items in their | ||
* original order. | ||
*/ | ||
log.error("could not order entities because of lack of entity metadata; returning original ordering"); | ||
return new ArrayList<>(items); | ||
} | ||
|
||
// sort the orderable list | ||
Collections.sort(orderableList); | ||
|
||
// Add the ordered results into the results collection | ||
for (OrderableItem result : orderableList) { | ||
results.add(result.unwrap()); | ||
} | ||
|
||
return results; | ||
} | ||
|
||
} |
78 changes: 78 additions & 0 deletions
78
src/test/java/uk/org/iay/incommon/dom/saml/InCommonEntityOrderingStrategyTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
|
||
package uk.org.iay.incommon.dom.saml; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.testng.Assert; | ||
import org.testng.annotations.Test; | ||
import org.w3c.dom.Element; | ||
|
||
import net.shibboleth.metadata.Item; | ||
import net.shibboleth.metadata.ItemId; | ||
import net.shibboleth.metadata.dom.DOMElementItem; | ||
import net.shibboleth.metadata.dom.saml.mdrpi.RegistrationAuthority; | ||
import uk.org.ukfederation.mda.BaseDOMTest; | ||
|
||
public class InCommonEntityOrderingStrategyTest extends BaseDOMTest { | ||
|
||
protected InCommonEntityOrderingStrategyTest() { | ||
super(InCommonEntityOrderingStrategy.class); | ||
} | ||
|
||
private Item<Element> makeItem(String registrar, String entityID) throws Exception { | ||
final Item<Element> item = new DOMElementItem(readXmlData("trivial.xml")); | ||
item.getItemMetadata().put(new ItemId(entityID)); | ||
item.getItemMetadata().put(new RegistrationAuthority(registrar)); | ||
return item; | ||
} | ||
|
||
@Test | ||
public void testOrder() throws Exception { | ||
// distinguished registrar | ||
final String registrar_d = "http://d"; | ||
|
||
// other registrars | ||
final String registrar_1 = "http://registrar1"; | ||
final String registrar_2 = "http://registrar2"; | ||
|
||
// create some items in the order they will end up | ||
final Item<Element> i00 = makeItem(registrar_d, "entity-id-999"); | ||
final Item<Element> i01 = makeItem(registrar_d, "entity-id-777"); | ||
final Item<Element> i10 = makeItem(registrar_1, "entity-id-0"); | ||
final Item<Element> i11 = makeItem(registrar_1, "entity-id-5"); | ||
final Item<Element> i12 = makeItem(registrar_1, "entity-id-9"); | ||
final Item<Element> i20 = makeItem(registrar_2, "entity-id-a"); | ||
final Item<Element> i21 = makeItem(registrar_2, "entity-id-m"); | ||
final Item<Element> i22 = makeItem(registrar_2, "entity-id-z"); | ||
|
||
// Make a collection containing those items in an arbitrary order | ||
// Note that the registrar_d items must be in the final order | ||
final List<Item<Element>> items = new ArrayList<>(); | ||
items.add(i22); | ||
items.add(i11); | ||
items.add(i00); | ||
items.add(i12); | ||
items.add(i20); | ||
items.add(i21); | ||
items.add(i01); | ||
items.add(i10); | ||
Assert.assertEquals(items.size(), 8); | ||
|
||
// Order the collection | ||
final InCommonEntityOrderingStrategy strat = new InCommonEntityOrderingStrategy(registrar_d); | ||
final List<Item<Element>>items2 = strat.order(items); | ||
|
||
// Check that everything is in the right place afterwards | ||
Assert.assertEquals(items2.size(), items.size()); | ||
Assert.assertEquals(items2.get(0), i00, "i00"); | ||
Assert.assertEquals(items2.get(1), i01, "i01"); | ||
Assert.assertEquals(items2.get(2), i10, "i10"); | ||
Assert.assertEquals(items2.get(3), i11, "i11"); | ||
Assert.assertEquals(items2.get(4), i12, "i12"); | ||
Assert.assertEquals(items2.get(5), i20, "i20"); | ||
Assert.assertEquals(items2.get(6), i21, "i21"); | ||
Assert.assertEquals(items2.get(7), i22, "i22"); | ||
} | ||
|
||
} |
4 changes: 4 additions & 0 deletions
4
src/test/resources/uk/org/iay/incommon/dom/saml/InCommonEntityOrderingStrategy-trivial.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<trivial> | ||
<!-- nothing here, really --> | ||
</trivial> |