001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 020 */ 021 022package org.nuxeo.ecm.platform.ui.web.auth.service; 023 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Map; 029import java.util.regex.Matcher; 030import java.util.regex.Pattern; 031 032import javax.servlet.ServletRequest; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpSession; 035 036import org.apache.commons.logging.Log; 037import org.apache.commons.logging.LogFactory; 038import org.nuxeo.ecm.platform.ui.web.auth.CachableUserIdentificationInfo; 039import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; 040import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationSessionManager; 041import org.nuxeo.ecm.platform.web.common.session.NuxeoHttpSessionMonitor; 042import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper; 043import org.nuxeo.runtime.model.ComponentContext; 044import org.nuxeo.runtime.model.ComponentInstance; 045import org.nuxeo.runtime.model.DefaultComponent; 046 047public class PluggableAuthenticationService extends DefaultComponent { 048 049 public static final String NAME = "org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService"; 050 051 public static final String EP_AUTHENTICATOR = "authenticators"; 052 053 public static final String EP_SESSIONMANAGER = "sessionManager"; 054 055 public static final String EP_CHAIN = "chain"; 056 057 public static final String EP_SPECIFIC_CHAINS = "specificChains"; 058 059 public static final String EP_STARTURL = "startURL"; 060 061 public static final String EP_OPENURL = "openUrl"; 062 063 public static final String EP_LOGINSCREEN = "loginScreen"; 064 065 private static final Log log = LogFactory.getLog(PluggableAuthenticationService.class); 066 067 private Map<String, AuthenticationPluginDescriptor> authenticatorsDescriptors; 068 069 private Map<String, NuxeoAuthenticationPlugin> authenticators; 070 071 private Map<String, NuxeoAuthenticationSessionManager> sessionManagers; 072 073 private List<String> authChain; 074 075 private final Map<String, SpecificAuthChainDescriptor> specificAuthChains = new HashMap<>(); 076 077 private final List<OpenUrlDescriptor> openUrls = new ArrayList<>(); 078 079 private final List<String> startupURLs = new ArrayList<>(); 080 081 private LoginScreenConfigRegistry loginScreenConfigRegistry; 082 083 @Override 084 public void activate(ComponentContext context) { 085 authenticatorsDescriptors = new HashMap<>(); 086 authChain = new ArrayList<>(); 087 authenticators = new HashMap<>(); 088 sessionManagers = new HashMap<>(); 089 loginScreenConfigRegistry = new LoginScreenConfigRegistry(); 090 } 091 092 @Override 093 public void deactivate(ComponentContext context) { 094 authenticatorsDescriptors = null; 095 authenticators = null; 096 authChain = null; 097 sessionManagers = null; 098 loginScreenConfigRegistry = null; 099 } 100 101 @Override 102 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 103 104 if (extensionPoint.equals(EP_AUTHENTICATOR)) { 105 AuthenticationPluginDescriptor descriptor = (AuthenticationPluginDescriptor) contribution; 106 if (authenticatorsDescriptors.containsKey(descriptor.getName())) { 107 mergeDescriptors(descriptor); 108 log.debug("merged AuthenticationPluginDescriptor: " + descriptor.getName()); 109 } else { 110 authenticatorsDescriptors.put(descriptor.getName(), descriptor); 111 log.debug("registered AuthenticationPluginDescriptor: " + descriptor.getName()); 112 } 113 114 // create the new instance 115 AuthenticationPluginDescriptor actualDescriptor = authenticatorsDescriptors.get(descriptor.getName()); 116 try { 117 NuxeoAuthenticationPlugin authPlugin = actualDescriptor.getClassName().getDeclaredConstructor().newInstance(); 118 authPlugin.initPlugin(actualDescriptor.getParameters()); 119 authenticators.put(actualDescriptor.getName(), authPlugin); 120 } catch (ReflectiveOperationException e) { 121 log.error( 122 "Unable to create AuthPlugin for : " + actualDescriptor.getName() + "Error : " + e.getMessage(), 123 e); 124 } 125 126 } else if (extensionPoint.equals(EP_CHAIN)) { 127 AuthenticationChainDescriptor chainContrib = (AuthenticationChainDescriptor) contribution; 128 log.debug("New authentication chain powered by " + contributor.getName()); 129 authChain.clear(); 130 authChain.addAll(chainContrib.getPluginsNames()); 131 } else if (extensionPoint.equals(EP_OPENURL)) { 132 OpenUrlDescriptor openUrlContrib = (OpenUrlDescriptor) contribution; 133 openUrls.add(openUrlContrib); 134 } else if (extensionPoint.equals(EP_STARTURL)) { 135 StartURLPatternDescriptor startupURLContrib = (StartURLPatternDescriptor) contribution; 136 startupURLs.addAll(startupURLContrib.getStartURLPatterns()); 137 } else if (extensionPoint.equals(EP_SESSIONMANAGER)) { 138 SessionManagerDescriptor smContrib = (SessionManagerDescriptor) contribution; 139 if (smContrib.enabled) { 140 try { 141 NuxeoAuthenticationSessionManager sm = smContrib.getClassName() 142 .getDeclaredConstructor() 143 .newInstance(); 144 sessionManagers.put(smContrib.getName(), sm); 145 } catch (ReflectiveOperationException e) { 146 log.error("Unable to create session manager", e); 147 } 148 } else { 149 sessionManagers.remove(smContrib.getName()); 150 } 151 } else if (extensionPoint.equals(EP_SPECIFIC_CHAINS)) { 152 SpecificAuthChainDescriptor desc = (SpecificAuthChainDescriptor) contribution; 153 specificAuthChains.put(desc.name, desc); 154 } else if (extensionPoint.equals(EP_LOGINSCREEN)) { 155 LoginScreenConfig newConfig = (LoginScreenConfig) contribution; 156 registerLoginScreenConfig(newConfig); 157 } 158 } 159 160 @Override 161 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 162 163 if (extensionPoint.equals(EP_AUTHENTICATOR)) { 164 AuthenticationPluginDescriptor descriptor = (AuthenticationPluginDescriptor) contribution; 165 authenticatorsDescriptors.remove(descriptor.getName()); 166 log.debug("unregistered AuthenticationPlugin: " + descriptor.getName()); 167 } else if (extensionPoint.equals(EP_LOGINSCREEN)) { 168 LoginScreenConfig newConfig = (LoginScreenConfig) contribution; 169 unregisterLoginScreenConfig(newConfig); 170 } 171 } 172 173 private void mergeDescriptors(AuthenticationPluginDescriptor newContrib) { 174 AuthenticationPluginDescriptor oldDescriptor = authenticatorsDescriptors.get(newContrib.getName()); 175 176 // Enable/Disable 177 oldDescriptor.setEnabled(newContrib.getEnabled()); 178 179 // Merge parameters 180 Map<String, String> oldParameters = oldDescriptor.getParameters(); 181 oldParameters.putAll(newContrib.getParameters()); 182 oldDescriptor.setParameters(oldParameters); 183 184 oldDescriptor.setStateful(newContrib.getStateful()); 185 186 if (newContrib.getClassName() != null) { 187 oldDescriptor.setClassName(newContrib.getClassName()); 188 } 189 190 oldDescriptor.setNeedStartingURLSaving(newContrib.getNeedStartingURLSaving()); 191 } 192 193 // Service API 194 195 public List<String> getStartURLPatterns() { 196 return startupURLs; 197 } 198 199 public List<String> getAuthChain() { 200 return authChain; 201 } 202 203 public List<String> getAuthChain(HttpServletRequest request) { 204 205 if (specificAuthChains == null || specificAuthChains.isEmpty()) { 206 return authChain; 207 } 208 209 SpecificAuthChainDescriptor desc = getAuthChainDescriptor(request); 210 211 if (desc != null) { 212 return desc.computeResultingChain(authChain); 213 } else { 214 return authChain; 215 } 216 } 217 218 public boolean doHandlePrompt(HttpServletRequest request) { 219 if (specificAuthChains == null || specificAuthChains.isEmpty()) { 220 return true; 221 } 222 223 SpecificAuthChainDescriptor desc = getAuthChainDescriptor(request); 224 225 return desc != null ? desc.doHandlePrompt() : SpecificAuthChainDescriptor.DEFAULT_HANDLE_PROMPT_VALUE; 226 227 } 228 229 private SpecificAuthChainDescriptor getAuthChainDescriptor(HttpServletRequest request) { 230 String specificAuthChainName = getSpecificAuthChainName(request); 231 SpecificAuthChainDescriptor desc = specificAuthChains.get(specificAuthChainName); 232 return desc; 233 } 234 235 public String getSpecificAuthChainName(HttpServletRequest request) { 236 for (String specificAuthChainName : specificAuthChains.keySet()) { 237 SpecificAuthChainDescriptor desc = specificAuthChains.get(specificAuthChainName); 238 239 List<Pattern> urlPatterns = desc.getUrlPatterns(); 240 if (!urlPatterns.isEmpty()) { 241 // test on URI 242 String requestUrl = request.getRequestURI(); 243 for (Pattern pattern : urlPatterns) { 244 Matcher m = pattern.matcher(requestUrl); 245 if (m.matches()) { 246 return specificAuthChainName; 247 } 248 } 249 } 250 251 Map<String, Pattern> headerPattern = desc.getHeaderPatterns(); 252 253 for (String headerName : headerPattern.keySet()) { 254 String headerValue = request.getHeader(headerName); 255 if (headerValue != null) { 256 Matcher m = headerPattern.get(headerName).matcher(headerValue); 257 if (m.matches()) { 258 return specificAuthChainName; 259 } 260 } 261 } 262 } 263 return null; 264 } 265 266 public List<NuxeoAuthenticationPlugin> getPluginChain() { 267 List<NuxeoAuthenticationPlugin> result = new ArrayList<>(); 268 269 for (String pluginName : authChain) { 270 if (authenticatorsDescriptors.containsKey(pluginName) 271 && authenticatorsDescriptors.get(pluginName).getEnabled()) { 272 if (authenticators.containsKey(pluginName)) { 273 result.add(authenticators.get(pluginName)); 274 } 275 } 276 } 277 return result; 278 } 279 280 public NuxeoAuthenticationPlugin getPlugin(String pluginName) { 281 if (authenticatorsDescriptors.containsKey(pluginName) 282 && authenticatorsDescriptors.get(pluginName).getEnabled()) { 283 if (authenticators.containsKey(pluginName)) { 284 return authenticators.get(pluginName); 285 } 286 } 287 return null; 288 } 289 290 public AuthenticationPluginDescriptor getDescriptor(String pluginName) { 291 if (authenticatorsDescriptors.containsKey(pluginName)) { 292 return authenticatorsDescriptors.get(pluginName); 293 } else { 294 log.error("Plugin " + pluginName + " not registered or not created"); 295 return null; 296 } 297 } 298 299 public void invalidateSession(ServletRequest request) { 300 boolean done = false; 301 if (!sessionManagers.isEmpty()) { 302 Iterator<NuxeoAuthenticationSessionManager> it = sessionManagers.values().iterator(); 303 while (it.hasNext() && !(done = it.next().invalidateSession(request))) { 304 } 305 } 306 if (!done) { 307 HttpServletRequest httpRequest = (HttpServletRequest) request; 308 HttpSession session = httpRequest.getSession(false); 309 if (session != null) { 310 session.invalidate(); 311 } 312 } 313 } 314 315 public HttpSession reinitSession(HttpServletRequest httpRequest) { 316 if (!sessionManagers.isEmpty()) { 317 for (String smName : sessionManagers.keySet()) { 318 NuxeoAuthenticationSessionManager sm = sessionManagers.get(smName); 319 sm.onBeforeSessionReinit(httpRequest); 320 } 321 } 322 323 HttpSession session = httpRequest.getSession(true); 324 325 if (!sessionManagers.isEmpty()) { 326 for (String smName : sessionManagers.keySet()) { 327 NuxeoAuthenticationSessionManager sm = sessionManagers.get(smName); 328 sm.onAfterSessionReinit(httpRequest); 329 } 330 } 331 return session; 332 } 333 334 public boolean canBypassRequest(ServletRequest request) { 335 if (!sessionManagers.isEmpty()) { 336 for (String smName : sessionManagers.keySet()) { 337 NuxeoAuthenticationSessionManager sm = sessionManagers.get(smName); 338 if (sm.canBypassRequest(request)) { 339 return true; 340 } 341 } 342 } 343 return false; 344 } 345 346 public boolean needResetLogin(ServletRequest request) { 347 if (!sessionManagers.isEmpty()) { 348 for (NuxeoAuthenticationSessionManager sm : sessionManagers.values()) { 349 if (sm.needResetLogin(request)) { 350 return true; 351 } 352 } 353 } 354 return false; 355 } 356 357 public String getBaseURL(ServletRequest request) { 358 return VirtualHostHelper.getBaseURL(request); 359 } 360 361 public void onAuthenticatedSessionCreated(ServletRequest request, HttpSession session, 362 CachableUserIdentificationInfo cachebleUserInfo) { 363 364 NuxeoHttpSessionMonitor.instance().associatedUser(session, cachebleUserInfo.getPrincipal().getName()); 365 366 if (!sessionManagers.isEmpty()) { 367 for (String smName : sessionManagers.keySet()) { 368 NuxeoAuthenticationSessionManager sm = sessionManagers.get(smName); 369 sm.onAuthenticatedSessionCreated(request, session, cachebleUserInfo); 370 } 371 } 372 } 373 374 public List<OpenUrlDescriptor> getOpenUrls() { 375 return openUrls; 376 } 377 378 public LoginScreenConfig getLoginScreenConfig() { 379 return loginScreenConfigRegistry.getConfig(); 380 } 381 382 /** 383 * @since 10.10 384 */ 385 public void registerLoginScreenConfig(LoginScreenConfig config) { 386 loginScreenConfigRegistry.addContribution(config); 387 } 388 389 /** 390 * @since 10.10 391 */ 392 public void unregisterLoginScreenConfig(LoginScreenConfig config) { 393 loginScreenConfigRegistry.removeContribution(config); 394 } 395 396}