View Javadoc

1   /*
2    * Copyright [2007] [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 org.opensaml.saml2.metadata.provider;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import javax.xml.namespace.QName;
25  
26  import org.opensaml.common.xml.SAMLConstants;
27  import org.opensaml.saml2.metadata.EntitiesDescriptor;
28  import org.opensaml.saml2.metadata.EntityDescriptor;
29  import org.opensaml.saml2.metadata.RoleDescriptor;
30  import org.opensaml.xml.XMLObject;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  /**
35   * A filter the removes roles, from an entity descriptor. For those roles specified within the SAML metadata
36   * specification the role element QName is used to identify the role. For other roles, those that appear as
37   * <RoleDescriptor xsi:type="someRoleType"> the role schema type is used to identify the role.
38   * 
39   * If the entity descriptor does not contain any roles after filter it may, optionally be removed as well. If the root
40   * element of the metadata document is an entity descriptor it will never be removed, regardless of of whether it still
41   * contains roles.
42   * 
43   * If and entities descriptor does not contains any entity descriptors after filter it may, optionally, be removed as
44   * well. If the root element of the metadata document is an entities descriptor it will never be removed, regardless of
45   * of whether it still contains entity descriptors.
46   */
47  public class EntityRoleFilter implements MetadataFilter {
48  
49      /** Class logger. */
50      private final Logger log = LoggerFactory.getLogger(EntityRoleFilter.class);
51  
52      /** List of roles that are NOT removed by this filter. */
53      private List<QName> roleWhiteList;
54  
55      /** Whether to keep entity descriptors that contain no roles; default value: true. */
56      private boolean removeRolelessEntityDescriptors;
57  
58      /** Whether to keep entities descriptors that contain no entity descriptors; default value: true. */
59      private boolean removeEmptyEntitiesDescriptors;
60  
61      /** QName of extension role element. */
62      private final QName extRoleDescriptor = new QName(SAMLConstants.SAML20MD_NS, "RoleDescriptor");
63  
64      /**
65       * Constructor.
66       * 
67       * @param keptRoles list of roles NOT removed by this filter
68       */
69      public EntityRoleFilter(List<QName> keptRoles) {
70          roleWhiteList = new ArrayList<QName>();
71  
72          if (keptRoles != null) {
73              roleWhiteList.addAll(keptRoles);
74          }
75  
76          removeRolelessEntityDescriptors = true;
77          removeEmptyEntitiesDescriptors = true;
78      }
79  
80      /**
81       * Gets the unmodifiable list of roles that are NOT removed by this filter.
82       * 
83       * @return unmodifiable list of roles that are NOT removed by this filter
84       */
85      public List<QName> getRoleWhiteList() {
86          return Collections.unmodifiableList(roleWhiteList);
87      }
88  
89      /**
90       * Gets whether to remove an entity descriptor if it does not contain any roles after filtering.
91       * 
92       * @return whether to remove an entity descriptor if it does not contain any roles after filtering
93       */
94      public boolean getRemoveRolelessEntityDescriptors() {
95          return removeRolelessEntityDescriptors;
96      }
97  
98      /**
99       * Sets whether to remove an entity descriptor if it does not contain any roles after filtering.
100      * 
101      * @param remove whether to remove an entity descriptor if it does not contain any roles after filtering
102      */
103     public void setRemoveRolelessEntityDescriptors(boolean remove) {
104         removeRolelessEntityDescriptors = remove;
105     }
106 
107     /**
108      * Gets whether to remove an entities descriptor if it does not contain any entity descriptor or entities
109      * descriptors.
110      * 
111      * @return whether to remove an entities descriptor if it does not contain any entity descriptor or entities
112      *         descriptors
113      */
114     public boolean getRemoveEmptyEntitiesDescriptors() {
115         return removeEmptyEntitiesDescriptors;
116     }
117 
118     /**
119      * Sets whether to remove an entities descriptor if it does not contain any entity descriptor or entities
120      * descriptors.
121      * 
122      * @param remove whether to remove an entities descriptor if it does not contain any entity descriptor or entities
123      *            descriptors
124      */
125     public void setRemoveEmptyEntitiesDescriptors(boolean remove) {
126         removeEmptyEntitiesDescriptors = remove;
127     }
128 
129     /** {@inheritDoc} */
130     public void doFilter(XMLObject metadata) throws FilterException {
131         if (metadata == null) {
132             return;
133         }
134 
135         if (metadata instanceof EntitiesDescriptor) {
136             filterEntitiesDescriptor((EntitiesDescriptor) metadata);
137         } else {
138             filterEntityDescriptor((EntityDescriptor) metadata);
139         }
140     }
141 
142     /**
143      * Filters entities descriptor.
144      * 
145      * @param descriptor entities descriptor to filter
146      * 
147      * @throws FilterException thrown if an effective role name can not be determined
148      */
149     protected void filterEntitiesDescriptor(EntitiesDescriptor descriptor) throws FilterException {
150         // First we filter out any contained EntityDescriptors
151         List<EntityDescriptor> entityDescriptors = descriptor.getEntityDescriptors();
152         if (entityDescriptors != null && !entityDescriptors.isEmpty()) {
153             List<EntityDescriptor> emptyEntityDescriptors = new ArrayList<EntityDescriptor>();
154             Iterator<EntityDescriptor> entityDescriptorsItr = entityDescriptors.iterator();
155             EntityDescriptor entityDescriptor;
156             List<RoleDescriptor> entityRoles;
157             while (entityDescriptorsItr.hasNext()) {
158                 entityDescriptor = entityDescriptorsItr.next();
159                 filterEntityDescriptor(entityDescriptor);
160                 if (getRemoveRolelessEntityDescriptors()) {
161                     entityRoles = entityDescriptor.getRoleDescriptors();
162                     if (entityRoles == null || entityRoles.isEmpty()) {
163                         log.trace("Filtering out entity descriptor {} from entity group {}", entityDescriptor
164                                 .getEntityID(), descriptor.getName());
165                         emptyEntityDescriptors.add(entityDescriptor);
166                     }
167                 }
168             }
169             entityDescriptors.removeAll(emptyEntityDescriptors);
170         }
171 
172         // Next, contained EntityDescriptors
173         List<EntitiesDescriptor> entitiesDescriptors = descriptor.getEntitiesDescriptors();
174         if (entitiesDescriptors != null && !entitiesDescriptors.isEmpty()) {
175             List<EntitiesDescriptor> emptyEntitiesDescriptors = new ArrayList<EntitiesDescriptor>();
176             Iterator<EntitiesDescriptor> entitiesDescriptorsItr = entitiesDescriptors.iterator();
177             EntitiesDescriptor entitiesDescriptor;
178             while (entitiesDescriptorsItr.hasNext()) {
179                 entitiesDescriptor = entitiesDescriptorsItr.next();
180                 filterEntitiesDescriptor(entitiesDescriptor);
181                 if (getRemoveEmptyEntitiesDescriptors()) {
182                     // Remove the EntitiesDescriptor if does not contain any EntitiesDescriptors or EntityDescriptors
183                     if ((entitiesDescriptor.getEntityDescriptors() == null || entitiesDescriptor.getEntityDescriptors()
184                             .isEmpty())
185                             && (entitiesDescriptor.getEntitiesDescriptors() == null || entitiesDescriptor
186                                     .getEntitiesDescriptors().isEmpty())) {
187                         log.trace("Filtering out entity descriptor {} from entity group {}", entitiesDescriptor
188                                 .getName(), descriptor.getName());
189                         emptyEntitiesDescriptors.add(entitiesDescriptor);
190                     }
191                 }
192             }
193             entitiesDescriptors.removeAll(emptyEntitiesDescriptors);
194         }
195     }
196 
197     /**
198      * Filters entity descriptor roles.
199      * 
200      * @param descriptor entity descriptor to filter
201      * 
202      * @throws FilterException thrown if an effective role name can not be determined
203      */
204     protected void filterEntityDescriptor(EntityDescriptor descriptor) throws FilterException {
205         List<RoleDescriptor> roles = descriptor.getRoleDescriptors();
206 
207         if (roles != null && !roles.isEmpty()) {
208             Iterator<RoleDescriptor> rolesItr = roles.iterator();
209             QName roleName;
210             while (rolesItr.hasNext()) {
211                 roleName = getRoleName(rolesItr.next());
212                 if (!roleWhiteList.contains(roleName)) {
213                     log.trace("Filtering out role {} from entity {}", roleName, descriptor.getEntityID());
214                     rolesItr.remove();
215                 }
216             }
217         }
218     }
219 
220     /**
221      * Gets the effective name for the role. This is either the element QName for roles defined within the SAML metadata
222      * specification or the element schema type QName for those that are not.
223      * 
224      * @param role role to get the effective name for
225      * 
226      * @return effective name of the role
227      * 
228      * @throws FilterException thrown if the effective role name can not be determined
229      */
230     protected QName getRoleName(RoleDescriptor role) throws FilterException {
231         QName roleName = role.getElementQName();
232 
233         if (extRoleDescriptor.equals(roleName)) {
234             roleName = role.getSchemaType();
235             if (roleName == null) {
236                 throw new FilterException("Role descriptor element was " + extRoleDescriptor
237                         + " but did not contain a schema type.  This is illegal.");
238             }
239         }
240 
241         return roleName;
242     }
243 }