View Javadoc

1   /*
2    * Copyright [2007] [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.idp.profile;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.concurrent.locks.Lock;
22  
23  import javax.servlet.ServletRequest;
24  import javax.servlet.http.HttpServletRequest;
25  
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  import org.springframework.context.ApplicationContext;
29  
30  import edu.internet2.middleware.shibboleth.common.config.BaseReloadableService;
31  import edu.internet2.middleware.shibboleth.common.profile.AbstractErrorHandler;
32  import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
33  import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
34  import edu.internet2.middleware.shibboleth.common.profile.provider.AbstractRequestURIMappedProfileHandler;
35  import edu.internet2.middleware.shibboleth.common.service.ServiceException;
36  import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
37  
38  /**
39   * Implementation of a {@link ProfileHandlerManager} that maps the request path, without the servlet context, to a
40   * profile handler and adds support for authentication handlers.
41   */
42  public class IdPProfileHandlerManager extends BaseReloadableService implements ProfileHandlerManager {
43  
44      /** Class logger. */
45      private final Logger log = LoggerFactory.getLogger(IdPProfileHandlerManager.class);
46  
47      /** Handler used for errors. */
48      private AbstractErrorHandler errorHandler;
49  
50      /** Map of request paths to profile handlers. */
51      private Map<String, AbstractRequestURIMappedProfileHandler> profileHandlers;
52  
53      /** Map of authentication methods to login handlers. */
54      private Map<String, LoginHandler> loginHandlers;
55  
56      /** Constructor. */
57      public IdPProfileHandlerManager() {
58          super();
59          profileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
60          loginHandlers = new HashMap<String, LoginHandler>();
61      }
62  
63      /** {@inheritDoc} */
64      public AbstractErrorHandler getErrorHandler() {
65          return errorHandler;
66      }
67  
68      /**
69       * Sets the error handler.
70       * 
71       * @param handler error handler
72       */
73      public void setErrorHandler(AbstractErrorHandler handler) {
74          if (handler == null) {
75              throw new IllegalArgumentException("Error handler may not be null");
76          }
77          errorHandler = handler;
78      }
79  
80      /** {@inheritDoc} */
81      public ProfileHandler getProfileHandler(ServletRequest request) {
82          ProfileHandler handler;
83  
84          String requestPath = ((HttpServletRequest) request).getPathInfo();
85          log.debug("{}: Looking up profile handler for request path: {}", getId(), requestPath);
86  
87          Lock readLock = getReadWriteLock().readLock();
88          readLock.lock();
89          handler = profileHandlers.get(requestPath);
90          readLock.unlock();
91  
92          if (handler != null) {
93              log.debug("{}: Located profile handler of the following type for the request path: {}", getId(), handler
94                      .getClass().getName());
95          } else {
96              log.debug("{}: No profile handler registered for request path {}", getId(), requestPath);
97          }
98          return handler;
99      }
100 
101     /**
102      * Gets the registered profile handlers.
103      * 
104      * @return registered profile handlers
105      */
106     public Map<String, AbstractRequestURIMappedProfileHandler> getProfileHandlers() {
107         return profileHandlers;
108     }
109 
110     /**
111      * Gets the registered authentication handlers.
112      * 
113      * @return registered authentication handlers
114      */
115     public Map<String, LoginHandler> getLoginHandlers() {
116         return loginHandlers;
117     }
118 
119     /** {@inheritDoc} */
120     protected void onNewContextCreated(ApplicationContext newServiceContext) throws ServiceException {
121         log.debug("{}: Loading new configuration into service", getId());
122         AbstractErrorHandler oldErrorHandler = errorHandler;
123         Map<String, AbstractRequestURIMappedProfileHandler> oldProfileHandlers = profileHandlers;
124         Map<String, LoginHandler> oldLoginHandlers = loginHandlers;
125 
126         try {
127             loadNewErrorHandler(newServiceContext);
128             loadNewProfileHandlers(newServiceContext);
129             loadNewLoginHandlers(newServiceContext);
130         } catch (Exception e) {
131             errorHandler = oldErrorHandler;
132             profileHandlers = oldProfileHandlers;
133             loginHandlers = oldLoginHandlers;
134             throw new ServiceException(getId() + " configuration is not valid, retaining old configuration", e);
135         }
136     }
137 
138     /**
139      * Reads the new error handler from the newly created application context and loads it into this manager.
140      * 
141      * @param newServiceContext newly created application context
142      */
143     protected void loadNewErrorHandler(ApplicationContext newServiceContext) {
144         String[] errorBeanNames = newServiceContext.getBeanNamesForType(AbstractErrorHandler.class);
145         log.debug("{}: Loading {} new error handler.", getId(), errorBeanNames.length);
146 
147         errorHandler = (AbstractErrorHandler) newServiceContext.getBean(errorBeanNames[0]);
148         log.debug("{}: Loaded new error handler of type: {}", getId(), errorHandler.getClass().getName());
149     }
150 
151     /**
152      * Reads the new profile handlers from the newly created application context and loads it into this manager.
153      * 
154      * @param newServiceContext newly created application context
155      */
156     protected void loadNewProfileHandlers(ApplicationContext newServiceContext) {
157         String[] profileBeanNames = newServiceContext.getBeanNamesForType(AbstractRequestURIMappedProfileHandler.class);
158         log.debug("{}: Loading {} new profile handlers.", getId(), profileBeanNames.length);
159 
160         Map<String, AbstractRequestURIMappedProfileHandler> newProfileHandlers = new HashMap<String, AbstractRequestURIMappedProfileHandler>();
161         AbstractRequestURIMappedProfileHandler<?, ?> profileHandler;
162         for (String profileBeanName : profileBeanNames) {
163             profileHandler = (AbstractRequestURIMappedProfileHandler) newServiceContext.getBean(profileBeanName);
164             for (String requestPath : profileHandler.getRequestPaths()) {
165                 newProfileHandlers.put(requestPath, profileHandler);
166                 log.debug("{}: Loaded profile handler for handling requests to request path {}", getId(), requestPath);
167             }
168         }
169         profileHandlers = newProfileHandlers;
170     }
171 
172     /**
173      * Reads the new authentication handlers from the newly created application context and loads it into this manager.
174      * 
175      * @param newServiceContext newly created application context
176      */
177     protected void loadNewLoginHandlers(ApplicationContext newServiceContext) {
178         String[] authnBeanNames = newServiceContext.getBeanNamesForType(LoginHandler.class);
179         log.debug("{}: Loading {} new authentication handlers.", getId(), authnBeanNames.length);
180 
181         Map<String, LoginHandler> newLoginHandlers = new HashMap<String, LoginHandler>();
182         LoginHandler authnHandler;
183         for (String authnBeanName : authnBeanNames) {
184             authnHandler = (LoginHandler) newServiceContext.getBean(authnBeanName);
185             log.debug("{}: Loading authentication handler of type supporting authentication methods: {}", getId(),
186                     authnHandler.getSupportedAuthenticationMethods());
187 
188             for (String authnMethod : authnHandler.getSupportedAuthenticationMethods()) {
189                 newLoginHandlers.put(authnMethod, authnHandler);
190             }
191         }
192         loginHandlers = newLoginHandlers;
193     }
194 }