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 }