1 16 package org.jboss.web.tomcat.tc6.sso; 17 18 19 import org.jboss.web.tomcat.tc6.session.JBossManager; 20 21 import java.io.IOException ; 22 import java.security.Principal ; 23 import java.util.Collections ; 24 import java.util.HashSet ; 25 import java.util.Set ; 26 27 import javax.management.ObjectName ; 28 import javax.servlet.ServletException ; 29 import javax.servlet.http.Cookie ; 30 31 import org.apache.catalina.Lifecycle; 32 import org.apache.catalina.LifecycleEvent; 33 import org.apache.catalina.LifecycleException; 34 import org.apache.catalina.LifecycleListener; 35 import org.apache.catalina.Manager; 36 import org.apache.catalina.Session; 37 import org.apache.catalina.Realm; 38 import org.apache.catalina.SessionEvent; 39 import org.apache.catalina.authenticator.Constants; 40 import org.apache.catalina.connector.Request; 41 import org.apache.catalina.connector.Response; 42 import org.apache.catalina.session.ManagerBase; 43 44 45 65 public class ClusteredSingleSignOn 66 extends org.apache.catalina.authenticator.SingleSignOn 67 implements LifecycleListener 68 { 69 70 static 72 { 73 info = ClusteredSingleSignOn.class.getName(); 74 } 75 76 78 79 84 private String clusterManagerClass = 85 TreeCacheSSOClusterManager.class.getName(); 86 87 90 private SSOClusterManager ssoClusterManager = null; 91 92 97 private String treeCacheName = "jboss.cache:service=TomcatClusteringCache"; 98 99 private Set activeManagers = Collections.synchronizedSet(new HashSet ()); 100 101 103 109 public SSOClusterManager getClusterManager() 110 { 111 return this.ssoClusterManager; 112 } 113 114 115 122 public void setClusterManager(SSOClusterManager clusterManager) 123 { 124 if (started && (clusterManager != ssoClusterManager)) 125 { 126 throw new IllegalStateException ("already started -- cannot set a " + 127 "new SSOClusterManager"); 128 } 129 130 this.ssoClusterManager = clusterManager; 131 132 if (clusterManager != null) 133 { 134 clusterManagerClass = clusterManager.getClass().getName(); 135 } 136 } 137 138 139 149 public String getClusterManagerClass() 150 { 151 return clusterManagerClass; 152 } 153 154 155 168 public void setClusterManagerClass(String managerClass) 169 { 170 if (!started) 171 { 172 clusterManagerClass = managerClass; 173 } 174 else if (ssoClusterManager == null) 175 { 176 try 177 { 178 createClusterManager(managerClass); 179 } 180 catch (LifecycleException e) 181 { 182 getContainer().getLogger().error("Exception creating SSOClusterManager " + 183 managerClass, e); 184 } 185 } 186 else 187 { 188 getContainer().getLogger().error("Cannot set clusterManagerClass to " + managerClass + 189 "; already started using " + clusterManagerClass); 190 } 191 } 192 193 198 public String getTreeCacheName() 199 { 200 return treeCacheName; 201 } 202 203 208 public void setTreeCacheName(String cacheName) 209 throws Exception 210 { 211 this.treeCacheName = cacheName; 212 if (ssoClusterManager != null 213 && ssoClusterManager instanceof TreeCacheSSOClusterManager) 214 { 215 ((TreeCacheSSOClusterManager) ssoClusterManager).setCacheName(cacheName); 216 } 217 } 218 219 220 222 223 231 public void start() throws LifecycleException 232 { 233 if (started) 235 { 236 throw new LifecycleException 237 (sm.getString("authenticator.alreadyStarted")); 238 } 239 240 createClusterManager(getClusterManagerClass()); 242 243 lifecycle.fireLifecycleEvent(START_EVENT, null); 244 started = true; 245 246 if (ssoClusterManager != null) 247 { 248 ssoClusterManager.start(); 249 } 250 251 } 252 253 254 262 public void stop() throws LifecycleException 263 { 264 if (!started) 266 { 267 throw new LifecycleException 268 (sm.getString("authenticator.notStarted")); 269 } 270 271 if (ssoClusterManager != null) 272 { 273 ssoClusterManager.stop(); 274 } 275 276 lifecycle.fireLifecycleEvent(STOP_EVENT, null); 277 started = false; 278 279 } 280 281 282 284 285 297 public void sessionEvent(SessionEvent event) 298 { 299 if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())) 301 return; 302 303 Session session = event.getSession(); 305 if (getContainer().getLogger().isDebugEnabled()) 306 getContainer().getLogger().debug("Process session destroyed on " + session); 307 308 String ssoId = null; 309 synchronized (reverse) 310 { 311 ssoId = (String ) reverse.get(session); 312 } 313 if (ssoId == null) 314 return; 315 316 if (isSessionTimedOut(session) || isManagerStopped(session)) 322 { 323 removeSession(ssoId, session); 324 } 325 else 326 { 327 logout(ssoId); 329 } 330 331 } 332 333 private boolean isSessionTimedOut(Session session) 334 { 335 return (session.getMaxInactiveInterval() > 0) 336 && (System.currentTimeMillis() - session.getLastAccessedTime() >= 337 session.getMaxInactiveInterval() * 1000); 338 } 339 340 private boolean isManagerStopped(Session session) 341 { 342 boolean stopped = false; 343 344 Manager manager = session.getManager(); 345 346 if (manager instanceof ManagerBase) 347 { 348 ObjectName mgrName = ((ManagerBase)manager).getObjectName(); 349 stopped = (!activeManagers.contains(mgrName)); 350 } 351 else if (manager instanceof JBossManager) 352 { 353 ObjectName mgrName = ((JBossManager)manager).getObjectName(); 354 stopped = (!activeManagers.contains(mgrName)); 355 } 356 else if (manager instanceof Lifecycle) 357 { 358 stopped = (!activeManagers.contains(manager)); 359 } 360 362 return stopped; 363 } 364 365 367 368 public void lifecycleEvent(LifecycleEvent event) 369 { 370 String type = event.getType(); 371 if (Lifecycle.BEFORE_STOP_EVENT.equals(type) 372 || Lifecycle.STOP_EVENT.equals(type) 373 || Lifecycle.AFTER_STOP_EVENT.equals(type)) 374 { 375 Lifecycle source = event.getLifecycle(); 376 boolean removed; 377 if (source instanceof ManagerBase) 378 { 379 removed = activeManagers.remove(((ManagerBase)source).getObjectName()); 380 } 381 else if (source instanceof JBossManager) 382 { 383 removed = activeManagers.remove(((JBossManager)source).getObjectName()); 384 } 385 else 386 { 387 removed = activeManagers.remove(source); 388 } 389 390 if (removed) 391 { 392 source.removeLifecycleListener(this); 393 394 if (getContainer().getLogger().isDebugEnabled()) 395 { 396 getContainer().getLogger().debug("ClusteredSSO: removed " + 397 "stopped manager " + source.toString()); 398 } 399 } 400 401 404 } 405 } 406 407 408 410 411 426 public void invoke(Request request, Response response) 427 throws IOException , ServletException 428 { 429 request.removeNote(Constants.REQ_SSOID_NOTE); 430 431 if (getContainer().getLogger().isDebugEnabled()) 433 getContainer().getLogger().debug("Process request for '" + request.getRequestURI() + "'"); 434 if (request.getUserPrincipal() != null) 435 { 436 if (getContainer().getLogger().isDebugEnabled()) 437 getContainer().getLogger().debug(" Principal '" + request.getUserPrincipal().getName() + 438 "' has already been authenticated"); 439 getNext().invoke(request, response); 440 return; 441 } 442 443 Cookie cookie = null; 445 Cookie cookies[] = request.getCookies(); 446 if (cookies == null) 447 cookies = new Cookie [0]; 448 for (int i = 0; i < cookies.length; i++) 449 { 450 if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) 451 { 452 cookie = cookies[i]; 453 break; 454 } 455 } 456 if (cookie == null) 457 { 458 if (getContainer().getLogger().isDebugEnabled()) 459 getContainer().getLogger().debug(" SSO cookie is not present"); 460 getNext().invoke(request, response); 461 return; 462 } 463 464 if (getContainer().getLogger().isDebugEnabled()) 466 getContainer().getLogger().debug(" Checking for cached principal for " + cookie.getValue()); 467 SingleSignOnEntry entry = getSingleSignOnEntry(cookie.getValue()); 468 if (entry != null) 469 { 470 Principal ssoPrinc = entry.getPrincipal(); 471 if (getContainer().getLogger().isDebugEnabled()) 475 { 476 getContainer().getLogger().debug(" Found cached principal '" + 477 (ssoPrinc == null ? "NULL" : ssoPrinc.getName()) + 478 "' with auth type '" + entry.getAuthType() + "'"); 479 } 480 request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); 481 if (!getRequireReauthentication() && ssoPrinc != null) 484 { 485 request.setAuthType(entry.getAuthType()); 486 request.setUserPrincipal(ssoPrinc); 487 } 488 } 489 else 490 { 491 if (getContainer().getLogger().isDebugEnabled()) 492 getContainer().getLogger().debug(" No cached principal found, erasing SSO cookie"); 493 cookie.setMaxAge(0); 494 response.addCookie(cookie); 495 } 496 497 getNext().invoke(request, response); 499 } 500 501 502 504 505 515 protected void associate(String ssoId, Session session) 516 { 517 if (getContainer().getLogger().isDebugEnabled()) 518 getContainer().getLogger().debug("Associate sso id " + ssoId + " with session " + session); 519 520 SingleSignOnEntry sso = getSingleSignOnEntry(ssoId); 521 boolean added = false; 522 if (sso != null) 523 added = sso.addSession(this, session); 524 525 synchronized (reverse) 526 { 527 reverse.put(session, ssoId); 528 } 529 530 if (added) 532 { 533 Manager manager = session.getManager(); 534 535 Object mgrKey = null; 538 if (manager instanceof ManagerBase) 539 { 540 mgrKey = ((ManagerBase)manager).getObjectName(); 541 } 542 else if (manager instanceof JBossManager) 543 { 544 mgrKey = ((JBossManager)manager).getObjectName(); 545 } 546 else if (manager instanceof Lifecycle) 547 { 548 mgrKey = manager; 549 } 550 else { 551 getContainer().getLogger().warn("Manager for session " + 552 session.getIdInternal() + 553 " does not implement Lifecycle; web app shutdown may " + 554 " lead to incorrect SSO invalidations"); 555 } 556 557 if (mgrKey != null) 558 { 559 synchronized (activeManagers) 560 { 561 if (!activeManagers.contains(mgrKey)) 562 { 563 activeManagers.add(mgrKey); 564 ((Lifecycle) manager).addLifecycleListener(this); 565 } 566 } 567 } 568 569 if (ssoClusterManager != null) 570 ssoClusterManager.addSession(ssoId, session); 571 } 572 } 573 574 575 585 protected void deregister(String ssoId, Session session) 586 { 587 synchronized (reverse) 588 { 589 reverse.remove(session); 590 } 591 592 SingleSignOnEntry sso = getSingleSignOnEntry(ssoId); 593 if (sso == null) 594 return; 595 596 boolean removed = sso.removeSession(session); 597 if (removed && ssoClusterManager != null) 599 { 600 ssoClusterManager.removeSession(ssoId, session); 601 } 602 603 if (sso.getSessionCount() == 0) 606 { 607 synchronized (cache) 608 { 609 sso = (SingleSignOnEntry) cache.remove(ssoId); 610 } 611 } 612 } 613 614 615 621 protected void deregister(String ssoId) 622 { 623 if (getContainer().getLogger().isDebugEnabled()) 624 getContainer().getLogger().debug("Deregistering sso id '" + ssoId + "'"); 625 626 SingleSignOnEntry sso = null; 628 synchronized (cache) 629 { 630 sso = (SingleSignOnEntry) cache.remove(ssoId); 631 } 632 633 if (sso == null) 634 return; 635 636 Session sessions[] = sso.findSessions(); 638 for (int i = 0; i < sessions.length; i++) 639 { 640 if (getContainer().getLogger().isTraceEnabled()) 641 getContainer().getLogger().trace(" Invalidating session " + sessions[i]); 642 synchronized (reverse) 644 { 645 reverse.remove(sessions[i]); 646 } 647 sessions[i].expire(); 649 } 650 651 } 655 656 657 663 protected void logout(String ssoId) 664 { 665 deregister(ssoId); 666 if (ssoClusterManager != null) 668 ssoClusterManager.logout(ssoId); 669 } 670 671 672 678 protected SingleSignOnEntry getSingleSignOnEntry(String ssoId) 679 { 680 SingleSignOnEntry sso = localLookup(ssoId); 681 if (sso == null && ssoClusterManager != null) 684 { 685 sso = ssoClusterManager.lookup(ssoId); 686 if (sso != null) 687 { 688 synchronized (cache) 690 { 691 cache.put(ssoId, sso); 692 } 693 } 694 } 695 696 return sso; 697 } 698 699 700 720 protected boolean reauthenticate(String ssoId, Realm realm, 721 Request request) 722 { 723 if (ssoId == null || realm == null) 724 return false; 725 726 boolean reauthenticated = false; 727 728 SingleSignOnEntry entry = getSingleSignOnEntry(ssoId); 729 if (entry != null && entry.getCanReauthenticate()) 730 { 731 732 String username = entry.getUsername(); 733 if (username != null) 734 { 735 Principal reauthPrincipal = 736 realm.authenticate(username, entry.getPassword()); 737 if (reauthPrincipal != null) 738 { 739 reauthenticated = true; 740 request.setAuthType(entry.getAuthType()); 742 request.setUserPrincipal(reauthPrincipal); 743 entry.setPrincipal(reauthPrincipal); 745 } 746 } 747 } 748 749 return reauthenticated; 750 } 751 752 753 767 protected void register(String ssoId, Principal principal, String authType, 768 String username, String password) 769 { 770 registerLocal(ssoId, principal, authType, username, password); 771 772 if (ssoClusterManager != null) 774 ssoClusterManager.register(ssoId, authType, username, password); 775 } 776 777 778 788 protected void removeSession(String ssoId, Session session) 789 { 790 if (getContainer().getLogger().isDebugEnabled()) 791 getContainer().getLogger().debug("Removing session " + session.toString() + 792 " from sso id " + ssoId); 793 794 SingleSignOnEntry entry = getSingleSignOnEntry(ssoId); 796 if (entry == null) 797 return; 798 799 boolean removed = entry.removeSession(session); 801 if (removed && ssoClusterManager != null) 803 { 804 ssoClusterManager.removeSession(ssoId, session); 805 } 806 807 synchronized (reverse) 809 { 810 reverse.remove(session); 811 } 812 813 if (entry.getSessionCount() == 0) 816 { 817 deregister(ssoId); 818 } 819 } 820 821 822 850 protected void update(String ssoId, Principal principal, String authType, 851 String username, String password) 852 { 853 boolean needToBroadcast = updateLocal(ssoId, principal, authType, 854 username, password); 855 856 if (needToBroadcast && ssoClusterManager != null) 858 { 859 ssoClusterManager.updateCredentials(ssoId, authType, 860 username, password); 861 } 862 } 863 864 866 873 SingleSignOnEntry localLookup(String ssoId) 874 { 875 synchronized (cache) 876 { 877 return ((SingleSignOnEntry) cache.get(ssoId)); 878 } 879 880 } 881 882 894 void registerLocal(String ssoId, Principal principal, String authType, 895 String username, String password) 896 { 897 if (getContainer().getLogger().isDebugEnabled()) 898 { 899 getContainer().getLogger().debug("Registering sso id '" + ssoId + "' for user '" + 900 principal.getName() + "' with auth type '" + authType + "'"); 901 } 902 903 synchronized (cache) 904 { 905 cache.put(ssoId, new SingleSignOnEntry(principal, authType, 906 username, password)); 907 } 908 } 909 910 924 boolean updateLocal(String ssoId, Principal principal, String authType, 925 String username, String password) 926 { 927 boolean shouldBroadcast = false; 928 929 SingleSignOnEntry sso = getSingleSignOnEntry(ssoId); 930 if (sso != null) 932 { 933 if (sso.getCanReauthenticate() == false) 934 { 935 if (getContainer().getLogger().isDebugEnabled()) 936 getContainer().getLogger().debug("Update sso id " + ssoId + " to auth type " + authType); 937 938 synchronized (sso) 939 { 940 shouldBroadcast = sso.updateCredentials(principal, authType, 941 username, password); 942 } 943 } 944 else if (sso.getPrincipal() == null && principal != null) 945 { 946 if (getContainer().getLogger().isDebugEnabled()) 947 getContainer().getLogger().debug("Update sso id " + ssoId + " with principal " + 948 principal.getName()); 949 950 synchronized (sso) 951 { 952 sso.setPrincipal(principal); 953 } 955 } 956 957 } 958 959 return shouldBroadcast; 960 961 } 962 963 void remoteUpdate(String ssoId, String authType, 964 String username, String password) 965 { 966 SingleSignOnEntry sso = getSingleSignOnEntry(ssoId); 967 if (sso != null && sso.getCanReauthenticate() == false) 969 { 970 if (getContainer().getLogger().isDebugEnabled()) 971 getContainer().getLogger().debug("Update sso id " + ssoId + " to auth type " + authType); 972 973 synchronized (sso) 974 { 975 Principal p = sso.getPrincipal(); 977 sso.updateCredentials(p, authType, username, password); 978 } 979 } 980 981 } 982 983 984 986 987 1001 private void createClusterManager(String className) 1002 throws LifecycleException 1003 { 1004 if (ssoClusterManager != null) 1005 return; 1006 1007 if (className != null) 1008 { 1009 SSOClusterManager mgr = null; 1010 try 1011 { 1012 ClassLoader tcl = 1013 Thread.currentThread().getContextClassLoader(); 1014 Class clazz = tcl.loadClass(className); 1015 mgr = (SSOClusterManager) clazz.newInstance(); 1016 mgr.setSingleSignOnValve(this); 1017 if (mgr instanceof TreeCacheSSOClusterManager) 1018 { 1019 ((TreeCacheSSOClusterManager) mgr).setCacheName(getTreeCacheName()); 1020 } 1021 ssoClusterManager = mgr; 1022 clusterManagerClass = className; 1023 } 1024 catch (Throwable t) 1025 { 1026 throw new LifecycleException("Cannot create " + 1027 "SSOClusterManager using " + 1028 className, t); 1029 } 1030 1031 if (started) 1032 { 1033 ssoClusterManager.start(); 1034 } 1035 } 1036 } 1037 1038} 1039 | Popular Tags |