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