View Javadoc

1   /*
2    * Copyright 2008 University Corporation for Advanced Internet Development, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package edu.internet2.middleware.shibboleth.wayf.plugins.provider;
18  
19  import java.util.Collection;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Set;
24  
25  import org.opensaml.saml2.metadata.EntitiesDescriptor;
26  import org.opensaml.saml2.metadata.EntityDescriptor;
27  import org.opensaml.saml2.metadata.provider.FilterException;
28  import org.opensaml.saml2.metadata.provider.MetadataFilter;
29  import org.opensaml.xml.XMLObject;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  import org.w3c.dom.Element;
33  import org.w3c.dom.NodeList;
34  
35  import edu.internet2.middleware.shibboleth.wayf.XMLConstants;
36  
37  /**
38   * See SDSJ-57.  Explicit 
39   * 
40   * @author Rod Widdowson
41   *
42   */
43  public class ListFilter implements MetadataFilter {
44  
45      /**
46       * Log for any messages.
47       */
48      private static final Logger LOG = LoggerFactory.getLogger(ListFilter.class.getName());
49      
50      /**
51       * Set if this is a blacklist.
52       */
53      private boolean excludeEntries;
54      
55      /**
56       * The list of entities.
57       */
58      private final Set<String> filterEntities;
59      
60      /**
61       * The name of the filter (needed for debug).
62       */
63      private final String filterName;
64      
65      /**
66       * Only the protected constructor should be visible.
67       */
68      private ListFilter() {
69          this.excludeEntries = false;
70          this.filterEntities = new HashSet<String>(0);
71          this.filterName = "anonymous";
72      }
73      
74      /**
75       * Initialize the filter.
76       * @param config the configuration
77       *
78       * The configuration looks liken this
79       * <code> <Filter identifier="WhiteList" 
80       *                type ="edu.internet2.middleware.shibboleth.wayf.plugins.provider.ListFilter"
81       *                excludeEntries = "true" >
82       *        <EntityId>foo</EntityId>
83       *        [...]
84       *        </Filter>
85       *  </code>
86       */
87      public ListFilter(Element config) {
88          String excludeEntriesValue;
89          this.filterEntities = new HashSet<String>(10);
90          this.filterName = config.getAttribute("identifier");
91          excludeEntriesValue = config.getAttribute("excludeEntries");
92          
93          if (null == excludeEntriesValue || 0 == excludeEntriesValue.length()) {
94              this.excludeEntries = true;
95          } else {
96              this.excludeEntries = Boolean.parseBoolean(excludeEntriesValue);
97          }
98          
99          NodeList itemElements = config.getElementsByTagNameNS(XMLConstants.CONFIG_NS, "EntityId");
100         
101         if (excludeEntries) {
102             LOG.debug("Populating blacklist " + filterName);
103         } else {
104             LOG.debug("Populating whitelist " + filterName);
105         }  
106         
107         for (int i = 0; i < itemElements.getLength(); i++) {
108             Element element = (Element) itemElements.item(i);
109             String entityId = element.getTextContent();
110             
111             LOG.debug("\t" + entityId);
112             this.filterEntities.add(entityId);
113         }
114     }
115     
116     /**
117      * Apply the filter.
118      * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
119      * @param metadata what to filter.
120      * @throws FilterException if it sees any missed or bad bindings.
121      */
122     public void doFilter(XMLObject metadata) throws FilterException {
123 
124         if (metadata instanceof EntitiesDescriptor) { 
125             filterEntities((EntitiesDescriptor)metadata);
126         } else if (metadata instanceof EntityDescriptor) {
127             EntityDescriptor entity = (EntityDescriptor) metadata;
128             String entityName = entity.getEntityID();
129             
130             if (excludeEntries) {
131                 if (filterEntities.contains(entityName)) {
132                     LOG.error("Metadata provider contains a single <EntityDescriptor> (" + entityName + 
133                               ") which is in exclude list");
134                 }
135             } else if (!filterEntities.contains(entity.getEntityID())) {
136                 LOG.error("Metadata provider contains a single <EntityDescriptor>  (" + entityName + 
137                           ") which is not on include list");
138             }
139         }
140     }
141 
142     /**
143      * Filter an EntitiesDescriptor .  We do this explictly for the Entities and call ourselves
144      *  recursively for the EntitesDescriptors.
145      *  
146      * @param entities what to check.
147      */
148     private void filterEntities(EntitiesDescriptor entities) {
149         String entitiesName = entities.getName();
150         List<EntitiesDescriptor> childEntities = entities.getEntitiesDescriptors();
151         List<EntityDescriptor> children = entities.getEntityDescriptors();
152         Collection<EntityDescriptor> excludes = new HashSet<EntityDescriptor>();
153         
154         //
155         // Go through and apply the filter
156         //
157 
158         if (children != null) {
159             Iterator<EntityDescriptor> itr;
160             EntityDescriptor entity;
161             itr = children.iterator();
162             
163             while (itr.hasNext()) {
164                 entity = itr.next();
165                 String entityName = entity.getEntityID();
166                 if (excludeEntries) {
167 
168                     if (filterEntities.contains(entityName)) {
169                         LOG.debug("Filter " + filterName + ": Removing blacklisted "  
170                                 + entityName + " from " + entitiesName);
171                         excludes.add(entity);
172                     }
173                 } else if (!filterEntities.contains(entityName)) {
174                     LOG.debug("Filter " + filterName + ": Removing non-whitelisted "  
175                             + entityName + " from " + entitiesName);
176 
177                     excludes.add(entity);
178                 }
179             } 
180             children.removeAll(excludes);
181         }
182         
183         if (childEntities != null) {
184             for (EntitiesDescriptor descriptor : childEntities) {
185                 filterEntities(descriptor);
186             }
187         }
188     }
189 }