1 23 24 package com.sun.enterprise.security.web; 25 26 import java.io.IOException ; 27 import java.security.Principal ; 28 import java.util.HashMap ; 29 import java.util.Iterator ; 30 import java.util.ArrayList ; 31 import java.util.logging.Logger ; 32 import java.util.logging.Level ; 33 34 import javax.servlet.ServletException ; 35 import javax.servlet.http.Cookie ; 36 import javax.servlet.http.HttpServletRequest ; 37 import javax.servlet.http.HttpServletResponse ; 38 39 import org.apache.catalina.Container; 40 import org.apache.catalina.HttpRequest; 41 import org.apache.catalina.HttpResponse; 42 import org.apache.catalina.Lifecycle; 43 import org.apache.catalina.LifecycleException; 44 import org.apache.catalina.Request; 45 import org.apache.catalina.Response; 46 import org.apache.catalina.Session; 47 import org.apache.catalina.SessionEvent; 48 import org.apache.catalina.SessionListener; 49 import org.apache.catalina.authenticator.Constants; 50 import org.apache.catalina.Realm; 51 52 import com.sun.enterprise.web.logging.pwc.LogDomains; 53 import java.util.concurrent.atomic.AtomicInteger ; 54 55 64 public class SingleSignOn 65 extends org.apache.catalina.authenticator.SingleSignOn 66 implements Lifecycle, SessionListener, Runnable , SingleSignOnMBean { 67 68 70 73 Logger logger = LogDomains.getLogger(LogDomains.PWC_LOGGER); 74 75 78 private Thread thread = null; 79 80 83 private boolean threadDone = false; 84 85 88 private int ssoReapInterval = 60; 89 90 96 private int ssoMaxInactive = 300; 97 98 100 103 private AtomicInteger hitCount = new AtomicInteger (0); 104 105 108 private AtomicInteger missCount = new AtomicInteger (0); 109 110 112 113 116 public int getReapInterval() { 117 118 return this.ssoReapInterval; 119 120 } 121 122 123 126 public void setReapInterval(int t) { 127 128 this.ssoReapInterval = t; 129 130 } 131 132 133 136 public int getMaxInactive() { 137 138 return this.ssoMaxInactive; 139 140 } 141 142 145 public void setMaxInactive(int t) { 146 147 this.ssoMaxInactive = t; 148 149 } 150 151 152 154 155 163 public void start() throws LifecycleException { 164 165 super.start(); 166 threadStart(); 168 169 } 170 171 172 180 public void stop() throws LifecycleException { 181 182 super.stop(); 183 threadStop(); 185 } 186 187 188 190 191 196 public void sessionEvent(SessionEvent event) { 197 198 if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())) 200 return; 201 202 Session session = event.getSession(); 204 if (logger.isLoggable(Level.FINE)) { 206 logger.fine("Process session destroyed on " + session); 207 } 208 String ssoId = null; 210 synchronized (reverse) { 211 ssoId = (String ) reverse.get(session); 212 } 213 if (ssoId == null) { 214 return; 215 } 216 217 if (session.hasExpired()) { 222 removeSession(ssoId, session); 223 } else { 224 deregister(ssoId); 228 } 229 } 230 231 232 234 235 246 251 public int invoke(Request request, Response response) 253 throws IOException , ServletException { 254 256 267 HttpServletRequest hreq = (HttpServletRequest ) request.getRequest(); 268 HttpServletResponse hres = 269 (HttpServletResponse ) response.getResponse(); 270 request.removeNote(Constants.REQ_SSOID_NOTE); 271 272 if (logger.isLoggable(Level.FINE)) { 275 logger.fine("Process request for '" + hreq.getRequestURI() + "'"); 276 } 277 if (hreq.getUserPrincipal() != null) { 278 if (logger.isLoggable(Level.FINE)) { 280 logger.fine(" Principal '" + hreq.getUserPrincipal().getName() 281 + "' has already been authenticated"); 282 } 283 return INVOKE_NEXT; 287 } 289 290 if (logger.isLoggable(Level.FINE)) { 293 logger.fine(" Checking for SSO cookie"); 294 } 295 Cookie cookie = null; 296 Cookie cookies[] = hreq.getCookies(); 297 if (cookies == null) 298 cookies = new Cookie [0]; 299 for (int i = 0; i < cookies.length; i++) { 300 if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) { 301 cookie = cookies[i]; 302 break; 303 } 304 } 305 if (cookie == null) { 306 if (logger.isLoggable(Level.FINE)) { 308 logger.fine(" SSO cookie is not present"); 309 } 310 return INVOKE_NEXT; 315 } 317 318 Realm realm = request.getContext().getRealm(); 321 if (realm == null) { 322 if (logger.isLoggable(Level.FINE)) { 324 logger.fine(" No realm configured for this application, SSO " 325 + "does not apply."); 326 } 327 return INVOKE_NEXT; 332 } 334 335 String realmName = realm.getRealmName(); 336 if (realmName == null) { 337 if (logger.isLoggable(Level.FINE)) { 339 logger.fine(" No realm configured for this application, SSO " 340 + "does not apply."); 341 } 342 return INVOKE_NEXT; 347 } 349 350 if (debug >= 1) { 351 if (logger.isLoggable(Level.FINE)) { 353 logger.fine("This application uses realm '" + realmName + "'"); 354 } 355 } 356 358 if (logger.isLoggable(Level.FINE)) { 361 logger.fine(" Checking for cached principal for " 362 + cookie.getValue()); 363 } 364 SingleSignOnEntry entry = lookupEntry(cookie.getValue()); 365 if (entry != null) { 366 if (logger.isLoggable(Level.FINE)) { 367 logger.fine(" Found cached principal '" 368 + entry.principal.getName() 369 + "' with auth type '" + entry.authType 370 + "' in realm '" + entry.realmName + "'"); 371 } 372 374 if (entry.realmName.equals(realmName)) { 376 request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); 377 ((HttpRequest) request).setAuthType(entry.authType); 378 ((HttpRequest) request).setUserPrincipal(entry.principal); 379 entry.lastAccessTime = System.currentTimeMillis(); 381 hitCount.incrementAndGet(); 383 } else { 384 if (logger.isLoggable(Level.FINE)) { 386 logger.fine(" Ignoring SSO entry which does not match " 387 + "application realm '" + realmName + "'"); 388 } 389 missCount.incrementAndGet(); 391 } 392 } else { 393 if (logger.isLoggable(Level.FINE)) { 394 logger.fine(" No cached principal found, erasing SSO cookie"); 395 } 396 cookie.setMaxAge(0); 397 hres.addCookie(cookie); 398 missCount.incrementAndGet(); 400 } 401 return INVOKE_NEXT; 407 409 } 410 411 412 414 415 422 protected void associate(String ssoId, Session session) { 423 424 if (logger.isLoggable(Level.FINE)) { 426 logger.fine("Associate sso id " + ssoId + " with session " 427 + session); 428 } 429 SingleSignOnEntry sso = lookupEntry(ssoId); 431 if (sso != null) 432 sso.addSession(this, session); 433 synchronized (reverse) { 434 reverse.put(session, ssoId); 435 } 436 437 } 438 439 446 protected void deregister(String ssoId, Session session) { 447 448 synchronized (reverse) { 449 reverse.remove(session); 450 } 451 452 SingleSignOnEntry sso = lookupEntry(ssoId); 453 if ( sso == null ) 454 return; 455 456 sso.removeSession( session ); 457 458 Session sessions[] = sso.findSessions(); 460 if ( sessions == null || sessions.length == 0 ) { 461 synchronized (cache) { 462 sso = (SingleSignOnEntry) cache.remove(ssoId); 463 } 464 } 465 466 } 467 468 469 475 protected void deregister(String ssoId) { 476 477 if (logger.isLoggable(Level.FINE)) { 479 logger.fine("Deregistering sso id '" + ssoId + "'"); 480 } 481 SingleSignOnEntry sso = null; 484 synchronized (cache) { 485 sso = (SingleSignOnEntry) cache.remove(ssoId); 486 } 487 488 if (sso == null) 489 return; 490 491 Session sessions[] = sso.findSessions(); 493 for (int i = 0; i < sessions.length; i++) { 494 if (logger.isLoggable(Level.FINE)) { 495 logger.fine(" Invalidating session " + sessions[i]); 496 } 497 synchronized (reverse) { 499 reverse.remove(sessions[i]); 500 } 501 sessions[i].expire(); 503 } 504 505 } 509 510 511 522 protected void register(String ssoId, Principal principal, String authType, 523 String username, String password, 524 String realmName) { 525 526 if (logger.isLoggable(Level.FINE)) { 528 logger.fine("Registering sso id '" + ssoId + "' for user '" 529 + principal.getName() + " in realm " + realmName 530 + "' with auth type '" + authType + "'"); 531 } 532 synchronized (cache) { 534 cache.put(ssoId, new SingleSignOnEntry(principal, 535 authType, 536 username, 537 password, 538 realmName)); 539 } 540 } 541 542 543 545 546 552 protected SingleSignOnEntry lookupEntry(String ssoId) { 553 554 synchronized (cache) { 555 return ((SingleSignOnEntry) cache.get(ssoId)); 556 } 557 558 } 559 560 561 564 private void processExpires() { 565 566 if (ssoMaxInactive < 0) { 567 return; 569 } 570 571 long tooOld = System.currentTimeMillis() - ssoMaxInactive * 1000; 572 if (logger.isLoggable(Level.FINE)) { 574 logger.fine("SSO expiration started. Current entries: " 575 + cache.size()); 576 } 577 ArrayList removals = new ArrayList (cache.size()/2); 579 580 582 587 try { 588 synchronized (cache) { 589 590 Iterator it = cache.keySet().iterator(); 591 while (it.hasNext()) { 592 String key = (String ) it.next(); 593 SingleSignOnEntry sso = (SingleSignOnEntry) cache.get(key); 594 if (sso.sessions.length == 0 && 595 sso.lastAccessTime < tooOld) { 596 removals.add(key); 597 } 598 } 599 } 600 601 int removalCount = removals.size(); 602 if (logger.isLoggable(Level.FINE)) { 604 logger.fine("SSO cache will expire " + removalCount 605 + " entries."); 606 } 607 for (int i=0; i < removalCount; i++) { 610 if (logger.isLoggable(Level.FINE)) { 612 logger.fine("SSO expiration removing entry: " 613 + removals.get(i)); 614 } 615 deregister((String )removals.get(i)); 616 } 617 } catch (Throwable e) { logger.warning("Caught exception during SingleSignOn expiration: " 620 + e); 621 } 622 } 623 624 625 629 private void threadSleep() { 630 631 try { 632 Thread.sleep(ssoReapInterval * 1000L); 633 } catch (InterruptedException e) { 634 ; 635 } 636 637 } 638 639 640 644 private void threadStart() { 645 646 if (thread != null) 647 return; 648 649 threadDone = false; 650 String threadName = "SingleSignOnExpiration"; 651 thread = new Thread (this, threadName); 652 thread.setDaemon(true); 653 thread.start(); 654 655 } 656 657 658 662 private void threadStop() { 663 664 if (thread == null) 665 return; 666 667 threadDone = true; 668 thread.interrupt(); 669 try { 670 thread.join(); 671 } catch (InterruptedException e) { 672 ; 673 } 674 675 thread = null; 676 677 } 678 679 680 682 683 686 public void run() { 687 688 while (!threadDone) { 690 threadSleep(); 691 processExpires(); 692 } 693 694 } 695 696 703 protected void removeSession(String ssoId, Session session) { 704 705 if (logger.isLoggable(Level.FINE)) { 706 logger.fine("Removing session " + session.toString() 707 + " from sso id " + ssoId ); 708 } 709 710 SingleSignOnEntry entry = lookupEntry(ssoId); 712 if (entry == null) 713 return; 714 715 entry.removeSession(session); 717 718 synchronized(reverse) { 720 reverse.remove(session); 721 } 722 723 if (entry.findSessions().length == 0) { 726 deregister(ssoId); 727 } 728 } 729 730 732 737 public int getActiveSessionCount() { 738 return cache.size(); 739 } 740 741 742 747 public int getHitCount() { 748 return hitCount.intValue(); 749 } 750 751 752 757 public int getMissCount() { 758 return missCount.intValue(); 759 } 760 761 } 762 763 764 | Popular Tags |