001/* 002 * (C) Copyright 2006-2017 Nuxeo (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 * Thierry Delprat 018 * Bogdan Stefanescu 019 * Anahide Tchertchian 020 * Florent Guillaume 021 */ 022package org.nuxeo.ecm.platform.ui.web.auth; 023 024import static java.nio.charset.StandardCharsets.UTF_8; 025import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.CALLBACK_URL_PARAMETER; 026import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.DISABLE_REDIRECT_REQUEST_KEY; 027import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.DRIVE_PROTOCOL; 028import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.ERROR_AUTHENTICATION_FAILED; 029import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.ERROR_CONNECTION_FAILED; 030import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.FORCE_ANONYMOUS_LOGIN; 031import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.FORM_SUBMITTED_MARKER; 032import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGINCONTEXT_KEY; 033import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_ERROR; 034import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_FAILED; 035import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_MISSING; 036import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_PAGE; 037import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_STATUS_CODE; 038import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGOUT_PAGE; 039import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.MOBILE_PROTOCOL; 040import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.PAGE_AFTER_SWITCH; 041import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.REDIRECT_URL; 042import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.REQUESTED_URL; 043import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.SECURITY_ERROR; 044import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.SESSION_TIMEOUT; 045import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.SSO_INITIAL_URL_REQUEST_KEY; 046import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.START_PAGE_SAVE_KEY; 047import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.SWITCH_USER_KEY; 048import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.SWITCH_USER_PAGE; 049import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.USERIDENT_KEY; 050 051import java.io.IOException; 052import java.io.Serializable; 053import java.io.UnsupportedEncodingException; 054import java.net.SocketException; 055import java.net.URI; 056import java.net.URISyntaxException; 057import java.net.URLDecoder; 058import java.security.Principal; 059import java.util.ArrayList; 060import java.util.HashMap; 061import java.util.List; 062import java.util.Map; 063import java.util.concurrent.locks.ReentrantReadWriteLock; 064 065import javax.naming.NamingException; 066import javax.security.auth.callback.CallbackHandler; 067import javax.security.auth.login.LoginContext; 068import javax.security.auth.login.LoginException; 069import javax.servlet.Filter; 070import javax.servlet.FilterChain; 071import javax.servlet.FilterConfig; 072import javax.servlet.ServletException; 073import javax.servlet.ServletRequest; 074import javax.servlet.ServletResponse; 075import javax.servlet.http.Cookie; 076import javax.servlet.http.HttpServletRequest; 077import javax.servlet.http.HttpServletResponse; 078import javax.servlet.http.HttpServletResponseWrapper; 079import javax.servlet.http.HttpSession; 080import javax.ws.rs.core.Response; 081import javax.ws.rs.core.UriBuilder; 082 083import org.apache.commons.lang3.StringUtils; 084import org.apache.commons.lang3.exception.ExceptionUtils; 085import org.apache.commons.logging.Log; 086import org.apache.commons.logging.LogFactory; 087import org.apache.http.NameValuePair; 088import org.apache.http.client.utils.URLEncodedUtils; 089import org.nuxeo.common.utils.URIUtils; 090import org.nuxeo.ecm.core.api.NuxeoPrincipal; 091import org.nuxeo.ecm.core.api.impl.UserPrincipal; 092import org.nuxeo.ecm.core.api.local.ClientLoginModule; 093import org.nuxeo.ecm.core.event.EventContext; 094import org.nuxeo.ecm.core.event.EventProducer; 095import org.nuxeo.ecm.core.event.impl.UnboundEventContext; 096import org.nuxeo.ecm.directory.DirectoryException; 097import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; 098import org.nuxeo.ecm.platform.api.login.UserIdentificationInfoCallbackHandler; 099import org.nuxeo.ecm.platform.login.PrincipalImpl; 100import org.nuxeo.ecm.platform.login.TrustingLoginPlugin; 101import org.nuxeo.ecm.platform.ui.web.auth.interfaces.LoginResponseHandler; 102import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; 103import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension; 104import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPropagator; 105import org.nuxeo.ecm.platform.ui.web.auth.service.AuthenticationPluginDescriptor; 106import org.nuxeo.ecm.platform.ui.web.auth.service.OpenUrlDescriptor; 107import org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService; 108import org.nuxeo.ecm.platform.usermanager.UserManager; 109import org.nuxeo.ecm.platform.web.common.session.NuxeoHttpSessionMonitor; 110import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper; 111import org.nuxeo.runtime.api.Framework; 112import org.nuxeo.runtime.metrics.MetricsService; 113import org.nuxeo.runtime.model.ComponentManager; 114 115import com.codahale.metrics.Counter; 116import com.codahale.metrics.MetricRegistry; 117import com.codahale.metrics.SharedMetricRegistries; 118import com.codahale.metrics.Timer; 119 120/** 121 * Servlet filter handling Nuxeo authentication (JAAS + EJB). 122 * <p> 123 * Also handles logout and identity switch. 124 * 125 * @author Thierry Delprat 126 * @author Bogdan Stefanescu 127 * @author Anahide Tchertchian 128 * @author Florent Guillaume 129 */ 130public class NuxeoAuthenticationFilter implements Filter { 131 132 private static final Log log = LogFactory.getLog(NuxeoAuthenticationFilter.class); 133 134 // protected static final String EJB_LOGIN_DOMAIN = "nuxeo-system-login"; 135 136 /** 137 * @deprecated Since 8.4. Use {@link LoginScreenHelper#getStartupPagePath()} instead. 138 * @see LoginScreenHelper 139 */ 140 @Deprecated 141 public static final String DEFAULT_START_PAGE = "nxstartup.faces"; 142 143 /** 144 * LoginContext domain name in use by default in Nuxeo. 145 */ 146 public static final String LOGIN_DOMAIN = "nuxeo-ecm-web"; 147 148 protected static final String XMLHTTP_REQUEST_TYPE = "XMLHttpRequest"; 149 150 protected static final String LOGIN_CATEGORY = "NuxeoAuthentication"; 151 152 protected static volatile Boolean isLoginSynchronized; 153 154 /** Used internally as a marker. */ 155 protected static final Principal DIRECTORY_ERROR_PRINCIPAL = new PrincipalImpl("__DIRECTORY_ERROR__\0\0\0"); 156 157 protected static final String INDEX_JSP = "index.jsp"; 158 159 protected static final String SLASH_INDEX_JSP = "/" + INDEX_JSP; 160 161 /** The Seam conversation id query parameter. */ 162 protected static final String CONVERSATION_ID = "conversationId"; 163 164 private static String anonymous; 165 166 protected final boolean avoidReauthenticate = true; 167 168 protected volatile PluggableAuthenticationService service; 169 170 protected ReentrantReadWriteLock unAuthenticatedURLPrefixLock = new ReentrantReadWriteLock(); 171 172 protected List<String> unAuthenticatedURLPrefix; 173 174 /** 175 * On WebEngine (Jetty) we don't have JMS enabled so we should disable log 176 */ 177 protected boolean byPassAuthenticationLog = false; 178 179 /** 180 * Which security domain to use 181 */ 182 protected String securityDomain = LOGIN_DOMAIN; 183 184 // @since 5.7 185 protected final MetricRegistry registry = SharedMetricRegistries.getOrCreate(MetricsService.class.getName()); 186 187 protected final Timer requestTimer = registry.timer( 188 MetricRegistry.name("nuxeo", "web", "authentication", "requests", "count")); 189 190 protected final Counter concurrentCount = registry.counter( 191 MetricRegistry.name("nuxeo", "web", "authentication", "requests", "concurrent", "count")); 192 193 protected final Counter concurrentMaxCount = registry.counter( 194 MetricRegistry.name("nuxeo", "web", "authentication", "requests", "concurrent", "max")); 195 196 protected final Counter loginCount = registry.counter( 197 MetricRegistry.name("nuxeo", "web", "authentication", "logged-users")); 198 199 @Override 200 public void destroy() { 201 } 202 203 protected static boolean sendAuthenticationEvent(UserIdentificationInfo userInfo, String eventId, String comment) { 204 205 LoginContext loginContext = null; 206 try { 207 try { 208 loginContext = Framework.login(); 209 } catch (LoginException e) { 210 log.error("Unable to log in in order to log Login event" + e.getMessage()); 211 return false; 212 } 213 214 EventProducer evtProducer = Framework.getService(EventProducer.class); 215 NuxeoPrincipal principal = new UserPrincipal(userInfo.getUserName(), null, false, false); 216 217 Map<String, Serializable> props = new HashMap<>(); 218 props.put("AuthenticationPlugin", userInfo.getAuthPluginName()); 219 props.put("LoginPlugin", userInfo.getLoginPluginName()); 220 props.put("category", LOGIN_CATEGORY); 221 props.put("comment", comment); 222 223 EventContext ctx = new UnboundEventContext(principal, props); 224 evtProducer.fireEvent(ctx.newEvent(eventId)); 225 return true; 226 } finally { 227 if (loginContext != null) { 228 try { 229 loginContext.logout(); 230 } catch (LoginException e) { 231 log.error("Unable to logout: " + e.getMessage()); 232 } 233 } 234 } 235 } 236 237 protected boolean logAuthenticationAttempt(UserIdentificationInfo userInfo, boolean success) { 238 if (byPassAuthenticationLog) { 239 return true; 240 } 241 String userName = userInfo.getUserName(); 242 if (userName == null || userName.length() == 0) { 243 userName = userInfo.getToken(); 244 } 245 246 String eventId; 247 String comment; 248 if (success) { 249 eventId = "loginSuccess"; 250 comment = userName + " successfully logged in using " + userInfo.getAuthPluginName() + " authentication"; 251 loginCount.inc(); 252 } else { 253 eventId = "loginFailed"; 254 comment = userName + " failed to authenticate using " + userInfo.getAuthPluginName() + " authentication"; 255 } 256 257 return sendAuthenticationEvent(userInfo, eventId, comment); 258 } 259 260 protected boolean logLogout(UserIdentificationInfo userInfo) { 261 if (byPassAuthenticationLog) { 262 return true; 263 } 264 loginCount.dec(); 265 String userName = userInfo.getUserName(); 266 if (userName == null || userName.length() == 0) { 267 userName = userInfo.getToken(); 268 } 269 270 String eventId = "logout"; 271 String comment = userName + " logged out"; 272 273 return sendAuthenticationEvent(userInfo, eventId, comment); 274 } 275 276 protected static boolean isLoginSynchronized() { 277 if (isLoginSynchronized != null) { 278 return isLoginSynchronized; 279 } 280 if (Framework.getRuntime() == null) { 281 return false; 282 } 283 synchronized (NuxeoAuthenticationFilter.class) { 284 if (isLoginSynchronized != null) { 285 return isLoginSynchronized; 286 } 287 return isLoginSynchronized = !Boolean.parseBoolean(Framework.getProperty( 288 "org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter.isLoginNotSynchronized", "true")); 289 } 290 } 291 292 protected Principal doAuthenticate(CachableUserIdentificationInfo cachableUserIdent, 293 HttpServletRequest httpRequest) { 294 295 LoginContext loginContext; 296 try { 297 CallbackHandler handler = service.getCallbackHandler(cachableUserIdent.getUserInfo()); 298 loginContext = new LoginContext(securityDomain, handler); 299 300 if (isLoginSynchronized()) { 301 synchronized (NuxeoAuthenticationFilter.class) { 302 loginContext.login(); 303 } 304 } else { 305 loginContext.login(); 306 } 307 308 Principal principal = (Principal) loginContext.getSubject().getPrincipals().toArray()[0]; 309 cachableUserIdent.setPrincipal(principal); 310 cachableUserIdent.setAlreadyAuthenticated(true); 311 // re-set the userName since for some SSO based on token, 312 // the userName is not known before login is completed 313 cachableUserIdent.getUserInfo().setUserName(principal.getName()); 314 315 logAuthenticationAttempt(cachableUserIdent.getUserInfo(), true); 316 } catch (LoginException e) { 317 if (log.isInfoEnabled()) { 318 log.info(String.format("Login failed for %s on request %s", 319 cachableUserIdent.getUserInfo().getUserName(), httpRequest.getRequestURI())); 320 } 321 log.debug(e, e); 322 logAuthenticationAttempt(cachableUserIdent.getUserInfo(), false); 323 Throwable cause = e.getCause(); 324 if (cause instanceof DirectoryException) { 325 Throwable rootCause = ExceptionUtils.getRootCause(cause); 326 if (rootCause instanceof NamingException 327 && rootCause.getMessage().contains("LDAP response read timed out") 328 || rootCause instanceof SocketException) { 329 if (log.isDebugEnabled()) { 330 log.debug(String.format( 331 "Exception root cause is either a NamingException with \"LDAP response read timed out\"" 332 + " or a SocketException, setting the status code to %d," 333 + " more relevant than an illegitimate 401.", 334 HttpServletResponse.SC_GATEWAY_TIMEOUT)); 335 } 336 httpRequest.setAttribute(LOGIN_STATUS_CODE, HttpServletResponse.SC_GATEWAY_TIMEOUT); 337 } 338 return DIRECTORY_ERROR_PRINCIPAL; 339 } 340 return null; 341 } 342 343 // store login context for the time of the request 344 // TODO logincontext is also stored in cachableUserIdent - it is really 345 // needed to store it?? 346 httpRequest.setAttribute(LOGINCONTEXT_KEY, loginContext); 347 348 // store user ident 349 cachableUserIdent.setLoginContext(loginContext); 350 boolean createSession = needSessionSaving(cachableUserIdent.getUserInfo()); 351 HttpSession session = httpRequest.getSession(createSession); 352 if (session != null) { 353 session.setAttribute(USERIDENT_KEY, cachableUserIdent); 354 } 355 356 service.onAuthenticatedSessionCreated(httpRequest, session, cachableUserIdent); 357 358 return cachableUserIdent.getPrincipal(); 359 } 360 361 private boolean switchUser(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException { 362 HttpServletRequest httpRequest = (HttpServletRequest) request; 363 364 String deputyLogin = (String) httpRequest.getAttribute(SWITCH_USER_KEY); 365 String targetPageAfterSwitch = (String) httpRequest.getAttribute(PAGE_AFTER_SWITCH); 366 if (targetPageAfterSwitch == null) { 367 targetPageAfterSwitch = LoginScreenHelper.getStartupPagePath(); 368 } 369 370 CachableUserIdentificationInfo cachableUserIdent = retrieveIdentityFromCache(httpRequest); 371 String originatingUser = cachableUserIdent.getUserInfo().getUserName(); 372 373 if (deputyLogin == null) { 374 // simply switch back to the previous identity 375 NuxeoPrincipal currentPrincipal = (NuxeoPrincipal) cachableUserIdent.getPrincipal(); 376 String previousUser = currentPrincipal.getOriginatingUser(); 377 if (previousUser == null) { 378 return false; 379 } 380 deputyLogin = previousUser; 381 originatingUser = null; 382 } 383 384 try { 385 cachableUserIdent.getLoginContext().logout(); 386 } catch (LoginException e1) { 387 log.error("Error while logout from main identity", e1); 388 } 389 390 httpRequest.getSession(false); 391 service.reinitSession(httpRequest); 392 393 CachableUserIdentificationInfo newCachableUserIdent = new CachableUserIdentificationInfo(deputyLogin, 394 deputyLogin); 395 396 newCachableUserIdent.getUserInfo().setLoginPluginName(TrustingLoginPlugin.NAME); 397 newCachableUserIdent.getUserInfo().setAuthPluginName(cachableUserIdent.getUserInfo().getAuthPluginName()); 398 399 Principal principal = doAuthenticate(newCachableUserIdent, httpRequest); 400 if (principal != null && principal != DIRECTORY_ERROR_PRINCIPAL) { 401 NuxeoPrincipal nxUser = (NuxeoPrincipal) principal; 402 if (originatingUser != null) { 403 nxUser.setOriginatingUser(originatingUser); 404 } 405 propagateUserIdentificationInformation(cachableUserIdent); 406 } 407 408 // reinit Seam so the afterResponseComplete does not crash 409 // ServletLifecycle.beginRequest(httpRequest); 410 411 // flag redirect to avoid being caught by URLPolicy 412 request.setAttribute(DISABLE_REDIRECT_REQUEST_KEY, Boolean.TRUE); 413 String baseURL = service.getBaseURL(request); 414 ((HttpServletResponse) response).sendRedirect(baseURL + targetPageAfterSwitch); 415 416 return true; 417 } 418 419 @Override 420 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 421 throws IOException, ServletException { 422 final Timer.Context contextTimer = requestTimer.time(); 423 concurrentCount.inc(); 424 if (concurrentCount.getCount() > concurrentMaxCount.getCount()) { 425 concurrentMaxCount.inc(); 426 } 427 try { 428 doInitIfNeeded(); 429 doFilterInternal(request, response, chain); 430 } finally { 431 ClientLoginModule.clearThreadLocalLogin(); 432 contextTimer.stop(); 433 concurrentCount.dec(); 434 } 435 } 436 437 public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) 438 throws IOException, ServletException { 439 440 if (bypassAuth((HttpServletRequest) request)) { 441 chain.doFilter(request, response); 442 return; 443 } 444 445 String tokenPage = getRequestedPage(request); 446 if (tokenPage.equals(SWITCH_USER_PAGE)) { 447 boolean result = switchUser(request, response, chain); 448 if (result) { 449 return; 450 } 451 } 452 453 if (request instanceof NuxeoSecuredRequestWrapper) { 454 log.debug("ReEntering Nuxeo Authentication Filter ... exiting directly"); 455 chain.doFilter(request, response); 456 return; 457 } else if (service.canBypassRequest(request)) { 458 log.debug("ReEntering Nuxeo Authentication Filter after URL rewrite ... exiting directly"); 459 chain.doFilter(request, response); 460 return; 461 } else { 462 log.debug("Entering Nuxeo Authentication Filter"); 463 } 464 465 String targetPageURL = null; 466 HttpServletRequest httpRequest = (HttpServletRequest) request; 467 HttpServletResponse httpResponse = (HttpServletResponse) response; 468 Principal principal = httpRequest.getUserPrincipal(); 469 470 NuxeoAuthenticationPropagator.CleanupCallback propagatedAuthCb = null; 471 472 String forceAnonymousLoginParam = httpRequest.getParameter(FORCE_ANONYMOUS_LOGIN); 473 boolean forceAnonymousLogin = Boolean.parseBoolean(forceAnonymousLoginParam); 474 475 try { 476 if (principal == null) { 477 log.debug("Principal not found inside Request via getUserPrincipal"); 478 // need to authenticate ! 479 480 // retrieve user & password 481 CachableUserIdentificationInfo cachableUserIdent; 482 if (avoidReauthenticate) { 483 log.debug("Try getting authentication from cache"); 484 cachableUserIdent = retrieveIdentityFromCache(httpRequest); 485 } else { 486 log.debug("Principal cache is NOT activated"); 487 } 488 489 if (cachableUserIdent != null && cachableUserIdent.getUserInfo() != null) { 490 if (cachableUserIdent.getUserInfo().getUserName().equals(getAnonymousId())) { 491 if (forceAnonymousLogin) { 492 cachableUserIdent = null; 493 } 494 } 495 496 if (service.needResetLogin(request)) { 497 HttpSession session = httpRequest.getSession(false); 498 if (session != null) { 499 session.removeAttribute(USERIDENT_KEY); 500 } 501 // first propagate the login because invalidation may 502 // require 503 // an authenticated session 504 propagatedAuthCb = service.propagateUserIdentificationInformation(cachableUserIdent); 505 // invalidate Session ! 506 try { 507 service.invalidateSession(request); 508 } finally { 509 if (propagatedAuthCb != null) { 510 propagatedAuthCb.cleanup(); 511 propagatedAuthCb = null; 512 } 513 } 514 // TODO perform logout? 515 cachableUserIdent = null; 516 } 517 } 518 519 // identity found in cache 520 if (cachableUserIdent != null && cachableUserIdent.getUserInfo() != null) { 521 log.debug("userIdent found in cache, get the Principal from it without reloggin"); 522 523 NuxeoHttpSessionMonitor.instance().updateEntry(httpRequest); 524 525 principal = cachableUserIdent.getPrincipal(); 526 log.debug("Principal = " + principal.getName()); 527 propagatedAuthCb = service.propagateUserIdentificationInformation(cachableUserIdent); 528 529 String requestedPage = getRequestedPage(httpRequest); 530 if (LOGOUT_PAGE.equals(requestedPage)) { 531 boolean redirected = handleLogout(request, response, cachableUserIdent); 532 cachableUserIdent = null; 533 principal = null; 534 if (redirected && httpRequest.getParameter(FORM_SUBMITTED_MARKER) == null) { 535 return; 536 } 537 } else if (LOGIN_PAGE.equals(requestedPage)) { 538 if (handleLogin(httpRequest, httpResponse)) { 539 return; 540 } 541 } else { 542 targetPageURL = getSavedRequestedURL(httpRequest, httpResponse); 543 } 544 } 545 546 // identity not found in cache or reseted by logout 547 if (cachableUserIdent == null || cachableUserIdent.getUserInfo() == null) { 548 UserIdentificationInfo userIdent = handleRetrieveIdentity(httpRequest, httpResponse); 549 if (userIdent != null && userIdent.containsValidIdentity() 550 && userIdent.getUserName().equals(getAnonymousId())) { 551 if (forceAnonymousLogin) { 552 userIdent = null; 553 } 554 } 555 if ((userIdent == null || !userIdent.containsValidIdentity()) && !bypassAuth(httpRequest)) { 556 boolean res = handleLoginPrompt(httpRequest, httpResponse); 557 if (res) { 558 return; 559 } 560 } else { 561 String redirectUrl = VirtualHostHelper.getRedirectUrl(httpRequest); 562 HttpSession session = httpRequest.getSession(false); 563 if (session != null) { 564 session.setAttribute(REDIRECT_URL, redirectUrl); 565 } 566 // restore saved Starting page 567 targetPageURL = getSavedRequestedURL(httpRequest, httpResponse); 568 } 569 if (userIdent != null && userIdent.containsValidIdentity()) { 570 // do the authentication 571 cachableUserIdent = new CachableUserIdentificationInfo(userIdent); 572 principal = doAuthenticate(cachableUserIdent, httpRequest); 573 if (principal != null && principal != DIRECTORY_ERROR_PRINCIPAL) { 574 // Do the propagation too ???? 575 propagatedAuthCb = service.propagateUserIdentificationInformation(cachableUserIdent); 576 // setPrincipalToSession(httpRequest, principal); 577 // check if the current authenticator is a 578 // LoginResponseHandler 579 NuxeoAuthenticationPlugin plugin = getAuthenticator(cachableUserIdent); 580 if (plugin instanceof LoginResponseHandler) { 581 // call the extended error handler 582 if (((LoginResponseHandler) plugin).onSuccess((HttpServletRequest) request, 583 (HttpServletResponse) response)) { 584 return; 585 } 586 } 587 } else { 588 // first check if the current authenticator is a 589 // LoginResponseHandler 590 NuxeoAuthenticationPlugin plugin = getAuthenticator(cachableUserIdent); 591 if (plugin instanceof LoginResponseHandler) { 592 // call the extended error handler 593 if (((LoginResponseHandler) plugin).onError((HttpServletRequest) request, 594 (HttpServletResponse) response)) { 595 return; 596 } 597 } else { 598 // use the old method 599 String err = principal == DIRECTORY_ERROR_PRINCIPAL ? ERROR_CONNECTION_FAILED 600 : ERROR_AUTHENTICATION_FAILED; 601 httpRequest.setAttribute(LOGIN_ERROR, err); 602 boolean res = handleLoginPrompt(httpRequest, httpResponse); 603 if (res) { 604 return; 605 } 606 } 607 } 608 609 } 610 } 611 } 612 613 if (principal != null) { 614 if (targetPageURL != null && targetPageURL.length() > 0) { 615 // forward to target page 616 String baseURL = service.getBaseURL(request); 617 618 // httpRequest.getRequestDispatcher(targetPageURL).forward(new 619 // NuxeoSecuredRequestWrapper(httpRequest, principal), 620 // response); 621 if (XMLHTTP_REQUEST_TYPE.equalsIgnoreCase(httpRequest.getHeader("X-Requested-With"))) { 622 // httpResponse.setStatus(200); 623 return; 624 } else { 625 // In case of a download redirection, the base url is already contained in the target 626 String url = targetPageURL.startsWith(baseURL) ? targetPageURL : baseURL + targetPageURL; 627 httpResponse.sendRedirect(url); 628 return; 629 } 630 631 } else { 632 // simply continue request 633 chain.doFilter(new NuxeoSecuredRequestWrapper(httpRequest, principal), response); 634 } 635 } else { 636 chain.doFilter(request, response); 637 } 638 } finally { 639 if (propagatedAuthCb != null) { 640 propagatedAuthCb.cleanup(); 641 } 642 } 643 if (!avoidReauthenticate) { 644 // destroy login context 645 log.debug("Log out"); 646 LoginContext lc = (LoginContext) httpRequest.getAttribute("LoginContext"); 647 if (lc != null) { 648 try { 649 lc.logout(); 650 } catch (LoginException e) { 651 log.error(e, e); 652 } 653 } 654 } 655 log.debug("Exit Nuxeo Authentication filter"); 656 } 657 658 public NuxeoAuthenticationPlugin getAuthenticator(CachableUserIdentificationInfo ci) { 659 String key = ci.getUserInfo().getAuthPluginName(); 660 if (key != null) { 661 NuxeoAuthenticationPlugin authPlugin = service.getPlugin(key); 662 return authPlugin; 663 } 664 return null; 665 } 666 667 protected static CachableUserIdentificationInfo retrieveIdentityFromCache(HttpServletRequest httpRequest) { 668 669 HttpSession session = httpRequest.getSession(false); 670 if (session != null) { 671 CachableUserIdentificationInfo cachableUserInfo = (CachableUserIdentificationInfo) session.getAttribute( 672 USERIDENT_KEY); 673 if (cachableUserInfo != null) { 674 return cachableUserInfo; 675 } 676 } 677 678 return null; 679 } 680 681 private String getAnonymousId() throws ServletException { 682 if (anonymous == null) { 683 anonymous = Framework.getService(UserManager.class).getAnonymousUserId(); 684 } 685 return anonymous; 686 } 687 688 protected void doInitIfNeeded() throws ServletException { 689 if (service == null && Framework.getRuntime() != null) { 690 synchronized (this) { 691 if (service != null) { 692 return; 693 } 694 PluggableAuthenticationService svc = (PluggableAuthenticationService) Framework.getRuntime() 695 .getComponent( 696 PluggableAuthenticationService.NAME); 697 new ComponentManager.Listener() { 698 // nullify service field if components are restarting 699 @Override 700 public void beforeStart(ComponentManager mgr, boolean isResume) { 701 service = null; 702 uninstall(); 703 } 704 }.install(); 705 service = svc; 706 } 707 } 708 } 709 710 @Override 711 public void init(FilterConfig config) throws ServletException { 712 String val = config.getInitParameter("byPassAuthenticationLog"); 713 if (val != null && Boolean.parseBoolean(val)) { 714 byPassAuthenticationLog = true; 715 } 716 val = config.getInitParameter("securityDomain"); 717 if (val != null) { 718 securityDomain = val; 719 } 720 721 } 722 723 /** 724 * Save requested URL before redirecting to login form. 725 * <p> 726 * Returns true if target url is a valid startup page. 727 */ 728 public boolean saveRequestedURLBeforeRedirect(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 729 730 final boolean hasRequestedSessionId = !StringUtils.isBlank(httpRequest.getRequestedSessionId()); 731 732 HttpSession session = httpRequest.getSession(false); 733 final boolean isTimeout = session == null && hasRequestedSessionId; 734 735 if (!httpResponse.isCommitted()) { 736 session = httpRequest.getSession(true); 737 } 738 739 if (session == null) { 740 return false; 741 } 742 743 String requestPage; 744 boolean requestPageInParams = false; 745 if (httpRequest.getParameter(REQUESTED_URL) != null) { 746 requestPageInParams = true; 747 requestPage = httpRequest.getParameter(REQUESTED_URL); 748 } else { 749 requestPage = getRequestedUrl(httpRequest); 750 } 751 752 if (requestPage == null) { 753 return false; 754 } 755 756 // add a flag to tell that the Session looks like having timed out 757 if (isTimeout && !requestPage.equals(LoginScreenHelper.getStartupPagePath())) { 758 session.setAttribute(SESSION_TIMEOUT, Boolean.TRUE); 759 } else { 760 session.removeAttribute(SESSION_TIMEOUT); 761 } 762 763 // avoid saving to session is start page is not valid or if it's 764 // already in the request params 765 if (isStartPageValid(requestPage)) { 766 if (!requestPageInParams) { 767 String uri = URIUtils.getURIPath(requestPage); 768 // strip force anonymous login parameter if it exists 769 if (requestPage.contains("?")) { 770 Map<String, String> params = URIUtils.getRequestParameters(requestPage); 771 params.remove(FORCE_ANONYMOUS_LOGIN); 772 if (!params.isEmpty()) { 773 uri += '?' + URIUtils.getURIQuery(params); 774 } 775 } 776 session.setAttribute(START_PAGE_SAVE_KEY, uri); 777 } 778 return true; 779 } 780 781 // avoid redirect if not useful 782 for (String startupPagePath : LoginScreenHelper.getStartupPagePaths()) { 783 if (requestPage.startsWith(startupPagePath) 784 && LoginScreenHelper.getStartupPagePath().equals(startupPagePath)) { 785 return true; 786 } 787 } 788 789 return false; 790 } 791 792 /** 793 * The requested URL is like the requested page BUT is not decoded AND also includes the query string (except 794 * without conversation id). 795 */ 796 public static String getRequestedUrl(HttpServletRequest request) { 797 String path = getRequestedPage(request); 798 // re-encode path, as it's what the caller expects 799 try { 800 path = new URI(null, null, path, null).toASCIIString(); 801 } catch (URISyntaxException e) { 802 // keep path as is 803 } 804 String qs = request.getQueryString(); 805 if (StringUtils.isNotEmpty(qs)) { 806 // strip conversation id 807 if (qs.contains(CONVERSATION_ID)) { 808 List<NameValuePair> list = URLEncodedUtils.parse(qs, UTF_8); 809 if (list.removeIf(pair -> pair.getName().equals(CONVERSATION_ID))) { 810 qs = URLEncodedUtils.format(list, UTF_8); 811 } 812 } 813 if (!qs.isEmpty()) { 814 path = path + '?' + qs; 815 } 816 } 817 return path; 818 } 819 820 protected static String getSavedRequestedURL(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 821 822 HttpSession session = httpRequest.getSession(false); 823 String requestedPage = httpRequest.getParameter(REQUESTED_URL); 824 if (StringUtils.isBlank(requestedPage)) { 825 // retrieve from session 826 if (session != null) { 827 requestedPage = (String) session.getAttribute(START_PAGE_SAVE_KEY); 828 } 829 830 // retrieve from SSO cookies 831 Cookie[] cookies = httpRequest.getCookies(); 832 if (cookies != null) { 833 for (Cookie cookie : cookies) { 834 if (SSO_INITIAL_URL_REQUEST_KEY.equals(cookie.getName())) { 835 requestedPage = cookie.getValue(); 836 cookie.setPath("/"); 837 // enforce cookie removal 838 cookie.setMaxAge(0); 839 httpResponse.addCookie(cookie); 840 } 841 } 842 } 843 } 844 845 if (requestedPage != null) { 846 // retrieve URL fragment from cookie 847 Cookie[] cookies = httpRequest.getCookies(); 848 if (cookies != null) { 849 for (Cookie cookie : cookies) { 850 if (NXAuthConstants.START_PAGE_FRAGMENT_KEY.equals(cookie.getName())) { 851 try { 852 requestedPage = UriBuilder.fromUri(requestedPage) 853 .fragment(URLDecoder.decode(cookie.getValue(), "UTF-8")) 854 .build() 855 .toString(); 856 } catch (UnsupportedEncodingException e) { 857 log.error("Failed to decode start page url fragment", e); 858 } 859 // enforce cookie removal 860 cookie.setMaxAge(0); 861 httpResponse.addCookie(cookie); 862 } 863 } 864 } 865 } 866 867 // clean up session 868 if (session != null) { 869 session.removeAttribute(START_PAGE_SAVE_KEY); 870 } 871 872 return requestedPage; 873 } 874 875 protected boolean isStartPageValid(String startPage) { 876 if (startPage == null) { 877 return false; 878 } 879 try { 880 // Sometimes, the service is not initialized at startup 881 doInitIfNeeded(); 882 } catch (ServletException e) { 883 return false; 884 } 885 for (String prefix : service.getStartURLPatterns()) { 886 if (startPage.startsWith(prefix)) { 887 return true; 888 } 889 } 890 return false; 891 } 892 893 protected boolean handleLogout(ServletRequest request, ServletResponse response, 894 CachableUserIdentificationInfo cachedUserInfo) throws ServletException { 895 logLogout(cachedUserInfo.getUserInfo()); 896 897 request.setAttribute(DISABLE_REDIRECT_REQUEST_KEY, Boolean.TRUE); 898 Map<String, String> parameters = new HashMap<>(); 899 String securityError = request.getParameter(SECURITY_ERROR); 900 if (securityError != null) { 901 parameters.put(SECURITY_ERROR, securityError); 902 } 903 if (cachedUserInfo.getPrincipal().getName().equals(getAnonymousId())) { 904 parameters.put(FORCE_ANONYMOUS_LOGIN, "true"); 905 } 906 String requestedUrl = request.getParameter(REQUESTED_URL); 907 if (requestedUrl != null) { 908 parameters.put(REQUESTED_URL, requestedUrl); 909 } 910 // Reset JSESSIONID Cookie 911 HttpServletResponse httpResponse = (HttpServletResponse) response; 912 Cookie cookie = new Cookie("JSESSIONID", null); 913 cookie.setMaxAge(0); 914 cookie.setPath("/"); 915 httpResponse.addCookie(cookie); 916 917 String pluginName = cachedUserInfo.getUserInfo().getAuthPluginName(); 918 NuxeoAuthenticationPlugin authPlugin = service.getPlugin(pluginName); 919 NuxeoAuthenticationPluginLogoutExtension logoutPlugin = null; 920 921 if (authPlugin instanceof NuxeoAuthenticationPluginLogoutExtension) { 922 logoutPlugin = (NuxeoAuthenticationPluginLogoutExtension) authPlugin; 923 } 924 925 boolean redirected = false; 926 if (logoutPlugin != null) { 927 redirected = Boolean.TRUE.equals( 928 logoutPlugin.handleLogout((HttpServletRequest) request, (HttpServletResponse) response)); 929 } 930 931 // invalidate Session ! 932 service.invalidateSession(request); 933 934 HttpServletRequest httpRequest = (HttpServletRequest) request; 935 if (!redirected && !XMLHTTP_REQUEST_TYPE.equalsIgnoreCase(httpRequest.getHeader("X-Requested-With"))) { 936 String baseURL = service.getBaseURL(request); 937 String callbackURL = request.getParameter(CALLBACK_URL_PARAMETER); 938 try { 939 httpResponse.sendRedirect(getLogoutRedirectURL(callbackURL, baseURL, parameters)); 940 redirected = true; 941 } catch (IOException e) { 942 log.error("Unable to redirect to default start page after logout : " + e.getMessage()); 943 } 944 } 945 946 try { 947 cachedUserInfo.getLoginContext().logout(); 948 } catch (LoginException e) { 949 log.error("Unable to logout " + e.getMessage()); 950 } 951 return redirected; 952 } 953 954 /** 955 * @since 10.3 956 */ 957 protected String getLogoutRedirectURL(String callbackURL, String baseURL, Map<String, String> parameters) { 958 if (isCallbackURLValid(callbackURL, baseURL)) { 959 return callbackURL; 960 } 961 962 String url = baseURL + LoginScreenHelper.getStartupPagePath(); 963 return URIUtils.addParametersToURIQuery(url, parameters); 964 } 965 966 /** 967 * @since 10.3 968 */ 969 protected boolean isCallbackURLValid(String callbackURL, String baseURL) { 970 return StringUtils.isNotBlank(callbackURL) && ((baseURL != null && callbackURL.startsWith(baseURL)) 971 || callbackURL.startsWith(MOBILE_PROTOCOL) || callbackURL.startsWith(DRIVE_PROTOCOL)); 972 } 973 974 // App Server JAAS SPI 975 protected void propagateUserIdentificationInformation(CachableUserIdentificationInfo cachableUserIdent) { 976 service.propagateUserIdentificationInformation(cachableUserIdent); 977 } 978 979 // Plugin API 980 protected void initUnAuthenticatedURLPrefix() { 981 // gather unAuthenticated URLs 982 unAuthenticatedURLPrefix = new ArrayList<>(); 983 for (String pluginName : service.getAuthChain()) { 984 NuxeoAuthenticationPlugin plugin = service.getPlugin(pluginName); 985 if (plugin == null) { 986 throw new NullPointerException("Could not find plugin for name '" + pluginName + "'"); 987 } 988 List<String> prefix = plugin.getUnAuthenticatedURLPrefix(); 989 if (prefix != null && !prefix.isEmpty()) { 990 unAuthenticatedURLPrefix.addAll(prefix); 991 } 992 } 993 } 994 995 protected boolean bypassAuth(HttpServletRequest httpRequest) { 996 if (unAuthenticatedURLPrefix == null) { 997 try { 998 unAuthenticatedURLPrefixLock.writeLock().lock(); 999 // late init to allow plugins registered after this filter init 1000 initUnAuthenticatedURLPrefix(); 1001 } finally { 1002 unAuthenticatedURLPrefixLock.writeLock().unlock(); 1003 } 1004 } 1005 1006 try { 1007 unAuthenticatedURLPrefixLock.readLock().lock(); 1008 String requestPage = getRequestedPage(httpRequest); 1009 for (String prefix : unAuthenticatedURLPrefix) { 1010 if (requestPage.startsWith(prefix)) { 1011 return true; 1012 } 1013 } 1014 } finally { 1015 unAuthenticatedURLPrefixLock.readLock().unlock(); 1016 } 1017 1018 List<OpenUrlDescriptor> openUrls = service.getOpenUrls(); 1019 for (OpenUrlDescriptor openUrl : openUrls) { 1020 if (openUrl.allowByPassAuth(httpRequest)) { 1021 return true; 1022 } 1023 } 1024 1025 return false; 1026 } 1027 1028 public static String getRequestedPage(ServletRequest request) { 1029 if (request instanceof HttpServletRequest) { 1030 HttpServletRequest httpRequest = (HttpServletRequest) request; 1031 return getRequestedPage(httpRequest); 1032 } else { 1033 return null; 1034 } 1035 } 1036 1037 protected static String getRequestedPage(HttpServletRequest httpRequest) { 1038 String path = httpRequest.getServletPath(); // use decoded and normalized servlet path 1039 if (path.endsWith(SLASH_INDEX_JSP)) { 1040 // the welcome file (index.jsp) is present in the servlet path 1041 if (!httpRequest.getRequestURI().contains(SLASH_INDEX_JSP)) { 1042 // remove it if it was not specified explicitly 1043 path = path.substring(0, path.length() - INDEX_JSP.length()); 1044 } 1045 } 1046 String info = httpRequest.getPathInfo(); 1047 if (info != null) { 1048 path = path + info; 1049 } 1050 if (!path.isEmpty()) { 1051 path = path.substring(1); // strip initial / 1052 } 1053 return path; 1054 } 1055 1056 protected boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 1057 1058 // A specific auth chain may prevent the filter to relay to a login prompt. 1059 if (!service.doHandlePrompt(httpRequest)) { 1060 buildUnauthorizedResponse(httpRequest, httpResponse); 1061 return true; 1062 } 1063 1064 return handleLogin(httpRequest, httpResponse); 1065 1066 } 1067 1068 private boolean handleLogin(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 1069 String baseURL = service.getBaseURL(httpRequest); 1070 1071 // go through plugins to get UserIndentity 1072 for (String pluginName : service.getAuthChain(httpRequest)) { 1073 NuxeoAuthenticationPlugin plugin = service.getPlugin(pluginName); 1074 AuthenticationPluginDescriptor descriptor = service.getDescriptor(pluginName); 1075 if (plugin == null) { 1076 throw new NullPointerException("Could not find plugin for name '" + pluginName + "'"); 1077 } 1078 if (Boolean.TRUE.equals(plugin.needLoginPrompt(httpRequest))) { 1079 if (descriptor.getNeedStartingURLSaving()) { 1080 saveRequestedURLBeforeRedirect(httpRequest, httpResponse); 1081 } 1082 1083 HttpServletResponse response = new HttpServletResponseWrapper(httpResponse) { 1084 @Override 1085 public void sendRedirect(String location) throws IOException { 1086 Map<String, String> parameters = URIUtils.getRequestParameters(location); 1087 // failed form authentication, fragment is already stored 1088 if (parameters.containsKey(LOGIN_MISSING) || parameters.containsKey(LOGIN_FAILED)) { 1089 super.sendRedirect(location); 1090 return; 1091 } 1092 HttpServletResponse response = (HttpServletResponse) getResponse(); 1093 StringBuilder sb = new StringBuilder(); 1094 sb.append("<script type=\"text/javascript\">\n"); 1095 sb.append("document.cookie = '" + NXAuthConstants.START_PAGE_FRAGMENT_KEY 1096 + "=' + encodeURIComponent(window.location.hash.substring(1) || '') + '; path=/';\n"); 1097 sb.append("window.location = '" + location + "';\n"); 1098 sb.append("</script>"); 1099 String script = sb.toString(); 1100 1101 response.setStatus(SC_UNAUTHORIZED); 1102 response.setContentType("text/html;charset=UTF-8"); 1103 response.setContentLength(script.length()); 1104 response.getWriter().write(script); 1105 } 1106 }; 1107 return Boolean.TRUE.equals(plugin.handleLoginPrompt(httpRequest, response, baseURL)); 1108 } 1109 } 1110 1111 log.warn("No auth plugin can be found to do the Login Prompt"); 1112 return false; 1113 } 1114 1115 private void buildUnauthorizedResponse(HttpServletRequest req, HttpServletResponse resp) { 1116 1117 try { 1118 String loginUrl = VirtualHostHelper.getBaseURL(req) + LOGIN_PAGE; 1119 resp.addHeader("Location", loginUrl); 1120 resp.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); 1121 resp.getWriter().write("Please log in at: " + loginUrl); 1122 } catch (IOException e) { 1123 log.error("Unable to write login page on unauthorized response", e); 1124 } 1125 } 1126 1127 protected UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest, 1128 HttpServletResponse httpResponse) { 1129 1130 UserIdentificationInfo userIdent = null; 1131 1132 // go through plugins to get UserIdentity 1133 for (String pluginName : service.getAuthChain(httpRequest)) { 1134 NuxeoAuthenticationPlugin plugin = service.getPlugin(pluginName); 1135 if (plugin != null) { 1136 log.debug("Trying to retrieve userIdentification using plugin " + pluginName); 1137 userIdent = plugin.handleRetrieveIdentity(httpRequest, httpResponse); 1138 if (userIdent != null && userIdent.containsValidIdentity()) { 1139 // fill information for the Login module 1140 userIdent.setAuthPluginName(pluginName); 1141 1142 // get the target login module 1143 String loginModulePlugin = service.getDescriptor(pluginName).getLoginModulePlugin(); 1144 userIdent.setLoginPluginName(loginModulePlugin); 1145 1146 // get the additional parameters 1147 Map<String, String> parameters = service.getDescriptor(pluginName).getParameters(); 1148 if (userIdent.getLoginParameters() != null) { 1149 // keep existing parameters set by the auth plugin 1150 if (parameters == null) { 1151 parameters = new HashMap<>(); 1152 } 1153 parameters.putAll(userIdent.getLoginParameters()); 1154 } 1155 userIdent.setLoginParameters(parameters); 1156 1157 break; 1158 } 1159 } else { 1160 log.error("Auth plugin " + pluginName + " can not be retrieved from service"); 1161 } 1162 } 1163 1164 // Fall back to cache (used only when avoidReautenticated=false) 1165 if (userIdent == null || !userIdent.containsValidIdentity()) { 1166 log.debug("user/password not found in request, try into identity cache"); 1167 HttpSession session = httpRequest.getSession(false); 1168 if (session == null) { 1169 // possible we need a new session 1170 if (httpRequest.isRequestedSessionIdValid()) { 1171 session = httpRequest.getSession(true); 1172 } 1173 } 1174 if (session != null) { 1175 CachableUserIdentificationInfo savedUserInfo = retrieveIdentityFromCache(httpRequest); 1176 if (savedUserInfo != null) { 1177 log.debug("Found User identity in cache :" + savedUserInfo.getUserInfo().getUserName()); 1178 userIdent = new UserIdentificationInfo(savedUserInfo.getUserInfo()); 1179 savedUserInfo.setPrincipal(null); 1180 } 1181 } 1182 } else { 1183 log.debug("User/Password found as parameter of the request"); 1184 } 1185 1186 return userIdent; 1187 } 1188 1189 protected boolean needSessionSaving(UserIdentificationInfo userInfo) { 1190 String pluginName = userInfo.getAuthPluginName(); 1191 1192 AuthenticationPluginDescriptor desc = service.getDescriptor(pluginName); 1193 1194 if (desc.getStateful()) { 1195 return true; 1196 } else { 1197 return desc.getNeedStartingURLSaving(); 1198 } 1199 } 1200 1201 /** 1202 * Does a forced login as the given user. Bypasses all authentication checks. 1203 * 1204 * @param username the user name 1205 * @return the login context, which MUST be used for logout in a {@code finally} block 1206 * @throws LoginException 1207 */ 1208 public static LoginContext loginAs(String username) throws LoginException { 1209 UserIdentificationInfo userIdent = new UserIdentificationInfo(username, ""); 1210 userIdent.setLoginPluginName(TrustingLoginPlugin.NAME); 1211 PluggableAuthenticationService authService = (PluggableAuthenticationService) Framework.getRuntime() 1212 .getComponent( 1213 PluggableAuthenticationService.NAME); 1214 CallbackHandler callbackHandler; 1215 if (authService != null) { 1216 callbackHandler = authService.getCallbackHandler(userIdent); 1217 } else { 1218 callbackHandler = new UserIdentificationInfoCallbackHandler(userIdent); 1219 } 1220 LoginContext loginContext = new LoginContext(LOGIN_DOMAIN, callbackHandler); 1221 1222 if (isLoginSynchronized()) { 1223 synchronized (NuxeoAuthenticationFilter.class) { 1224 loginContext.login(); 1225 } 1226 } else { 1227 loginContext.login(); 1228 } 1229 return loginContext; 1230 } 1231 1232}