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.Iterator;
20  import java.util.List;
21  
22  import org.opensaml.saml2.common.Extensions;
23  import org.opensaml.saml2.metadata.EntitiesDescriptor;
24  import org.opensaml.saml2.metadata.EntityDescriptor;
25  import org.opensaml.saml2.metadata.RoleDescriptor;
26  import org.opensaml.saml2.metadata.SPSSODescriptor;
27  import org.opensaml.saml2.metadata.provider.FilterException;
28  import org.opensaml.saml2.metadata.provider.MetadataFilter;
29  import org.opensaml.samlext.idpdisco.DiscoveryResponse;
30  import org.opensaml.xml.XMLObject;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  /**
35   * See SDSJ-48.  If we get a DS endpoint then we need to check that the binding is provided
36   * and that it is correct.
37   * 
38   * @author Rod Widdowson
39   *
40   */
41  public class BindingFilter implements MetadataFilter {
42  
43      /**
44       * Log for the warning. 
45       */
46      private static final Logger LOG = LoggerFactory.getLogger(BindingFilter.class.getName());
47      
48      /**
49       * Set if we just want to warn on failure.
50       */
51      private final boolean warnOnFailure;
52      
53      /**
54       * Only the protected constructor should be visible.
55       */
56      private BindingFilter() {
57          this.warnOnFailure = false;
58      }
59      
60      /**
61       * Initialize the filter.
62       * @param warn do we warn or do we fail if we see badness?
63       */
64      public BindingFilter(boolean warn) {
65          this.warnOnFailure = warn;
66      }
67      
68      /**
69       * Apply the filter.
70       * @see org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml.XMLObject)
71       * @param metadata what to filter.
72       * @throws FilterException if it sees any missed or bad bindings.
73       */
74      public void doFilter(XMLObject metadata) throws FilterException {
75  
76          if (metadata instanceof EntitiesDescriptor) {
77              
78              checkEntities((EntitiesDescriptor) metadata);
79              
80          } else if (metadata instanceof EntityDescriptor) {
81              EntityDescriptor entity = (EntityDescriptor) metadata;
82              
83              if (!checkEntity(entity)) {
84                  if (warnOnFailure) {
85                      LOG.warn("Badly formatted binding for " + entity.getEntityID());
86                  } else {
87                      LOG.error("Badly formatted binding for top level entity " + entity.getEntityID());
88                  }
89              }
90          }
91      }
92  
93      /**
94       * If the entity has an SP characteristic, and it has a DS endpoint
95       * then check its binding.
96       * 
97       * @param entity what to check.
98       * @return true if all is OK.
99       */
100     private static boolean checkEntity(EntityDescriptor entity) {
101         List<RoleDescriptor> roles = entity.getRoleDescriptors();
102         
103         for (RoleDescriptor role:roles) {
104             
105             //
106             // Check every role
107             //
108             if (role instanceof SPSSODescriptor) {
109                 
110                 //
111                 // Grab hold of all the extensions for SPSSO descriptors
112                 //
113                 
114                 Extensions exts = role.getExtensions();
115                 if (exts != null) {
116                     //
117                     // We have some children check them form <DiscoveryResponse>
118                     //
119                     List<XMLObject> children = exts.getOrderedChildren();
120                     
121                     for (XMLObject obj : children) {
122                         if (obj instanceof DiscoveryResponse) {
123                             //
124                             // And check or the binding
125                             //
126                             DiscoveryResponse ds = (DiscoveryResponse) obj;
127                             String binding = ds.getBinding(); 
128 
129                             if (!DiscoveryResponse.IDP_DISCO_NS.equals(binding)) {
130                                 return false;
131                             }
132                         }
133                     }
134                 }
135             }
136         }
137         return true;
138     }
139     
140     /**
141      * Check an EntitiesDescriptor call checkentities for the Entities and ourselves
142      *  recursively for the EntitesDescriptors.
143      *  
144      * @param entities what to check.
145      */
146     private void checkEntities(EntitiesDescriptor entities) {
147         List<EntitiesDescriptor> childEntities = entities.getEntitiesDescriptors();
148         List<EntityDescriptor> children = entities.getEntityDescriptors();
149         
150         if (children != null) {
151             Iterator<EntityDescriptor> itr;
152             EntityDescriptor entity;
153             itr = children.iterator();
154             
155             while (itr.hasNext()) {
156                 entity = itr.next();
157                 if (!checkEntity(entity)) { 
158                     if (warnOnFailure) {
159                         LOG.warn("Badly formatted binding for " + entity.getEntityID());
160                     } else {
161                         LOG.error("Badly formatted binding for " + entity.getEntityID() + ". Entity has been removed");
162                         itr.remove();
163                     }
164                 }
165             }
166         }
167         
168         if (childEntities != null) {
169             for (EntitiesDescriptor descriptor : childEntities) {
170                 checkEntities(descriptor);
171             }
172         }
173     }
174 }