View Javadoc

    1   /*
    2    * Licensed to the University Corporation for Advanced Internet Development,
    3    * Inc. (UCAID) under one or more contributor license agreements.  See the
    4    * NOTICE file distributed with this work for additional information regarding
    5    * copyright ownership. The UCAID licenses this file to You under the Apache
    6    * License, Version 2.0 (the "License"); you may not use this file except in
    7    * compliance with the License.  You may obtain a copy of the License at
    8    *
    9    *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package edu.internet2.middleware.shibboleth.idp.profile;
    19
    20  import java.util.HashMap;
    21  import java.util.Map;
    22  import java.util.concurrent.locks.Lock;
    23
    24  import javax.servlet.ServletRequest;
    25  import javax.servlet.http.HttpServletRequest;
    26
    27  import org.slf4j.Logger;
    28  import org.slf4j.LoggerFactory;
    29  import org.springframework.context.ApplicationContext;
    30
    31  import edu.internet2.middleware.shibboleth.common.config.BaseReloadableService;
    32  import edu.internet2.middleware.shibboleth.common.profile.AbstractErrorHandler;
    33  import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
    34  import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
    35  import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractRequestURIMappedProfileHandler;
    36  import edu.internet2.middleware.shibboleth.common.service.ServiceException;
    37  import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
    38
    39  /**
    40   * Implementation of a {@link ProfileHandlerManager} that maps the request path, without the servlet context, to a
    41   * profile handler and adds support for authentication handlers.
    42   */
    43  public class IdPProfileHandlerManager extends BaseReloadableService implements ProfileHandlerManager {
    44
    45      /** Class logger. */
    46      private final Logger log = LoggerFactory.getLogger(IdPProfileHandlerManager.class);
    47
    48      /** Handler used for errors. */
    49      private AbstractErrorHandler errorHandler;
    50
    51      /** Map of request paths to profile handlers. */
    52      private Map<String, AbstractRequestURIMappedProfileHandler> profileHandlers;
    53
    54      /** Map of authentication methods to login handlers. */
    55      private Map<String, LoginHandler> loginHandlers;
    56
    57      /** Constructor. */
    58      public IdPProfileHandlerManager() {
    59          super();
    60          profileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
    61          loginHandlers = new HashMap<String, LoginHandler>();
    62      }
    63
    64      /** {@inheritDoc} */
    65      public AbstractErrorHandler getErrorHandler() {
    66          return errorHandler;
    67      }
    68
    69      /**
    70       * Sets the error handler.
    71       *
    72       * @param handler error handler
    73       */
    74      public void setErrorHandler(AbstractErrorHandler handler) {
    75          if (handler == null) {
    76              throw new IllegalArgumentException("Error handler may not be null");
    77          }
    78          errorHandler = handler;
    79      }
    80
    81      /** {@inheritDoc} */
    82      public ProfileHandler getProfileHandler(ServletRequest request) {
    83          ProfileHandler handler;
    84
    85          String requestPath = ((HttpServletRequest) request).getPathInfo();
    86          log.debug("{}: Looking up profile handler for request path: {}", getId(), requestPath);
    87
    88          Lock readLock = getReadWriteLock().readLock();
    89          readLock.lock();
    90          try{
    91              handler = profileHandlers.get(requestPath);
    92          }finally{
    93              readLock.unlock();
    94          }
    95
    96          if (handler != null) {
    97              log.debug("{}: Located profile handler of the following type for the request path: {}", getId(), handler
    98                      .getClass().getName());
    99          } else {
    100             log.debug("{}: No profile handler registered for request path {}", getId(), requestPath);
    101         }
    102         return handler;
    103     }
    104
    105     /**
    106      * Gets the registered profile handlers.
    107      *
    108      * @return registered profile handlers
    109      */
    110     public Map<String, AbstractRequestURIMappedProfileHandler> getProfileHandlers() {
    111         return profileHandlers;
    112     }
    113
    114     /**
    115      * Gets the registered authentication handlers.
    116      *
    117      * @return registered authentication handlers
    118      */
    119     public Map<String, LoginHandler> getLoginHandlers() {
    120         return loginHandlers;
    121     }
    122
    123     /** {@inheritDoc} */
    124     protected void onNewContextCreated(ApplicationContext newServiceContext) throws ServiceException {
    125         log.debug("{}: Loading new configuration into service", getId());
    126         AbstractErrorHandler oldErrorHandler = errorHandler;
    127         Map<String, AbstractRequestURIMappedProfileHandler> oldProfileHandlers = profileHandlers;
    128         Map<String, LoginHandler> oldLoginHandlers = loginHandlers;
    129
    130         try {
    131             loadNewErrorHandler(newServiceContext);
    132             loadNewProfileHandlers(newServiceContext);
    133             loadNewLoginHandlers(newServiceContext);
    134         } catch (Exception e) {
    135             errorHandler = oldErrorHandler;
    136             profileHandlers = oldProfileHandlers;
    137             loginHandlers = oldLoginHandlers;
    138             throw new ServiceException(getId() + " configuration is not valid, retaining old configuration", e);
    139         }
    140     }
    141
    142     /**
    143      * Reads the new error handler from the newly created application context and loads it into this manager.
    144      *
    145      * @param newServiceContext newly created application context
    146      */
    147     protected void loadNewErrorHandler(ApplicationContext newServiceContext) {
    148         String[] errorBeanNames = newServiceContext.getBeanNamesForType(AbstractErrorHandler.class);
    149         log.debug("{}: Loading {} new error handler.", getId(), errorBeanNames.length);
    150
    151         errorHandler = (AbstractErrorHandler) newServiceContext.getBean(errorBeanNames[0]);
    152         log.debug("{}: Loaded new error handler of type: {}", getId(), errorHandler.getClass().getName());
    153     }
    154
    155     /**
    156      * Reads the new profile handlers from the newly created application context and loads it into this manager.
    157      *
    158      * @param newServiceContext newly created application context
    159      */
    160     protected void loadNewProfileHandlers(ApplicationContext newServiceContext) {
    161         String[] profileBeanNames = newServiceContext.getBeanNamesForType(AbstractRequestURIMappedProfileHandler.class);
    162         log.debug("{}: Loading {} new profile handlers.", getId(), profileBeanNames.length);
    163
    164         Map<String, AbstractRequestURIMappedProfileHandler> newProfileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
    165         AbstractRequestURIMappedProfileHandler<?, ?> profileHandler;
    166         for (String profileBeanName : profileBeanNames) {
    167             profileHandler = (AbstractRequestURIMappedProfileHandler) newServiceContext.getBean(profileBeanName);
    168             for (String requestPath : profileHandler.getRequestPaths()) {
    169                 newProfileHandlers.put(requestPath, profileHandler);
    170                 log.debug("{}: Loaded profile handler for handling requests to request path {}", getId(), requestPath);
    171             }
    172         }
    173         profileHandlers = newProfileHandlers;
    174     }
    175
    176     /**
    177      * Reads the new authentication handlers from the newly created application context and loads it into this manager.
    178      *
    179      * @param newServiceContext newly created application context
    180      */
    181     protected void loadNewLoginHandlers(ApplicationContext newServiceContext) {
    182         String[] authnBeanNames = newServiceContext.getBeanNamesForType(LoginHandler.class);
    183         log.debug("{}: Loading {} new authentication handlers.", getId(), authnBeanNames.length);
    184
    185         Map<String, LoginHandler> newLoginHandlers = new HashMap<String, LoginHandler>();
    186         LoginHandler authnHandler;
    187         for (String authnBeanName : authnBeanNames) {
    188             authnHandler = (LoginHandler) newServiceContext.getBean(authnBeanName);
    189             log.debug("{}: Loading authentication handler of type supporting authentication methods: {}", getId(),
    190                     authnHandler.getSupportedAuthenticationMethods());
    191
    192             for (String authnMethod : authnHandler.getSupportedAuthenticationMethods()) {
    193                 newLoginHandlers.put(authnMethod, authnHandler);
    194             }
    195         }
    196         loginHandlers = newLoginHandlers;
    197     }
    198 }