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 }