1 17 18 19 package org.apache.catalina.authenticator; 20 21 22 import java.io.IOException ; 23 import java.security.MessageDigest ; 24 import java.security.NoSuchAlgorithmException ; 25 import java.security.Principal ; 26 import java.text.SimpleDateFormat ; 27 import java.util.Date ; 28 import java.util.Locale ; 29 import java.util.Random ; 30 31 import javax.servlet.ServletException ; 32 import javax.servlet.http.Cookie ; 33 34 import org.apache.catalina.Authenticator; 35 import org.apache.catalina.Container; 36 import org.apache.catalina.Context; 37 import org.apache.catalina.Lifecycle; 38 import org.apache.catalina.LifecycleException; 39 import org.apache.catalina.LifecycleListener; 40 import org.apache.catalina.Pipeline; 41 import org.apache.catalina.Realm; 42 import org.apache.catalina.Session; 43 import org.apache.catalina.Valve; 44 import org.apache.catalina.connector.Request; 45 import org.apache.catalina.connector.Response; 46 import org.apache.catalina.deploy.LoginConfig; 47 import org.apache.catalina.deploy.SecurityConstraint; 48 import org.apache.catalina.util.DateTool; 49 import org.apache.catalina.util.LifecycleSupport; 50 import org.apache.catalina.util.StringManager; 51 import org.apache.catalina.valves.ValveBase; 52 import org.apache.commons.logging.Log; 53 import org.apache.commons.logging.LogFactory; 54 55 56 75 76 77 public abstract class AuthenticatorBase 78 extends ValveBase 79 implements Authenticator, Lifecycle { 80 private static Log log = LogFactory.getLog(AuthenticatorBase.class); 81 82 83 85 86 90 protected static final String DEFAULT_ALGORITHM = "MD5"; 91 92 93 97 protected static final int SESSION_ID_BYTES = 16; 98 99 100 105 protected String algorithm = DEFAULT_ALGORITHM; 106 107 108 112 protected boolean cache = true; 113 114 115 118 protected Context context = null; 119 120 121 125 protected MessageDigest digest = null; 126 127 128 132 protected String entropy = null; 133 134 135 138 protected static final String info = 139 "org.apache.catalina.authenticator.AuthenticatorBase/1.0"; 140 141 145 protected boolean disableProxyCaching = true; 146 147 151 protected boolean securePagesWithPragma = true; 152 153 156 protected LifecycleSupport lifecycle = new LifecycleSupport(this); 157 158 159 162 protected Random random = null; 163 164 165 169 protected String randomClass = "java.security.SecureRandom"; 170 171 172 175 protected static final StringManager sm = 176 StringManager.getManager(Constants.Package); 177 178 179 183 protected SingleSignOn sso = null; 184 185 186 189 protected boolean started = false; 190 191 192 195 private static final String DATE_ONE = 196 (new SimpleDateFormat (DateTool.HTTP_RESPONSE_DATE_HEADER, 197 Locale.US)).format(new Date (1)); 198 199 200 202 203 206 public String getAlgorithm() { 207 208 return (this.algorithm); 209 210 } 211 212 213 218 public void setAlgorithm(String algorithm) { 219 220 this.algorithm = algorithm; 221 222 } 223 224 225 228 public boolean getCache() { 229 230 return (this.cache); 231 232 } 233 234 235 240 public void setCache(boolean cache) { 241 242 this.cache = cache; 243 244 } 245 246 247 250 public Container getContainer() { 251 252 return (this.context); 253 254 } 255 256 257 262 public void setContainer(Container container) { 263 264 if (!(container instanceof Context)) 265 throw new IllegalArgumentException 266 (sm.getString("authenticator.notContext")); 267 268 super.setContainer(container); 269 this.context = (Context) container; 270 271 } 272 273 274 278 public String getEntropy() { 279 280 if (this.entropy == null) 282 setEntropy(this.toString()); 283 284 return (this.entropy); 285 286 } 287 288 289 294 public void setEntropy(String entropy) { 295 296 this.entropy = entropy; 297 298 } 299 300 301 304 public String getInfo() { 305 306 return (info); 307 308 } 309 310 311 314 public String getRandomClass() { 315 316 return (this.randomClass); 317 318 } 319 320 321 326 public void setRandomClass(String randomClass) { 327 328 this.randomClass = randomClass; 329 330 } 331 332 336 public boolean getDisableProxyCaching() { 337 return disableProxyCaching; 338 } 339 340 346 public void setDisableProxyCaching(boolean nocache) { 347 disableProxyCaching = nocache; 348 } 349 350 354 public boolean getSecurePagesWithPragma() { 355 return securePagesWithPragma; 356 } 357 358 365 public void setSecurePagesWithPragma(boolean securePagesWithPragma) { 366 this.securePagesWithPragma = securePagesWithPragma; 367 } 368 369 371 372 382 public void invoke(Request request, Response response) 383 throws IOException , ServletException { 384 385 if (log.isDebugEnabled()) 386 log.debug("Security checking request " + 387 request.getMethod() + " " + request.getRequestURI()); 388 LoginConfig config = this.context.getLoginConfig(); 389 390 if (cache) { 392 Principal principal = request.getUserPrincipal(); 393 if (principal == null) { 394 Session session = request.getSessionInternal(false); 395 if (session != null) { 396 principal = session.getPrincipal(); 397 if (principal != null) { 398 if (log.isDebugEnabled()) 399 log.debug("We have cached auth type " + 400 session.getAuthType() + 401 " for principal " + 402 session.getPrincipal()); 403 request.setAuthType(session.getAuthType()); 404 request.setUserPrincipal(principal); 405 } 406 } 407 } 408 } 409 410 String contextPath = this.context.getPath(); 414 String requestURI = request.getDecodedRequestURI(); 415 if (requestURI.startsWith(contextPath) && 416 requestURI.endsWith(Constants.FORM_ACTION)) { 417 if (!authenticate(request, response, config)) { 418 if (log.isDebugEnabled()) 419 log.debug(" Failed authenticate() test ??" + requestURI ); 420 return; 421 } 422 } 423 424 Realm realm = this.context.getRealm(); 425 SecurityConstraint [] constraints 427 = realm.findSecurityConstraints(request, this.context); 428 429 if ((constraints == null) ) { 431 if (log.isDebugEnabled()) 432 log.debug(" Not subject to any constraint"); 433 getNext().invoke(request, response); 434 return; 435 } 436 437 if (disableProxyCaching && 440 !"POST".equalsIgnoreCase(request.getMethod())) { 444 if (securePagesWithPragma) { 445 response.setHeader("Pragma", "No-cache"); 449 response.setHeader("Cache-Control", "no-cache"); 450 } else { 451 response.setHeader("Cache-Control", "private"); 452 } 453 response.setHeader("Expires", DATE_ONE); 454 } 455 456 int i; 457 if (log.isDebugEnabled()) { 459 log.debug(" Calling hasUserDataPermission()"); 460 } 461 if (!realm.hasUserDataPermission(request, response, 462 constraints)) { 463 if (log.isDebugEnabled()) { 464 log.debug(" Failed hasUserDataPermission() test"); 465 } 466 470 return; 471 } 472 473 boolean authRequired = true; 476 for(i=0; i < constraints.length && authRequired; i++) { 477 if(!constraints[i].getAuthConstraint()) { 478 authRequired = false; 479 } else if(!constraints[i].getAllRoles()) { 480 String [] roles = constraints[i].findAuthRoles(); 481 if(roles == null || roles.length == 0) { 482 authRequired = false; 483 } 484 } 485 } 486 487 if(authRequired) { 488 if (log.isDebugEnabled()) { 489 log.debug(" Calling authenticate()"); 490 } 491 if (!authenticate(request, response, config)) { 492 if (log.isDebugEnabled()) { 493 log.debug(" Failed authenticate() test"); 494 } 495 500 return; 501 } 502 } 503 504 if (log.isDebugEnabled()) { 505 log.debug(" Calling accessControl()"); 506 } 507 if (!realm.hasResourcePermission(request, response, 508 constraints, 509 this.context)) { 510 if (log.isDebugEnabled()) { 511 log.debug(" Failed accessControl() test"); 512 } 513 518 return; 519 } 520 521 if (log.isDebugEnabled()) { 523 log.debug(" Successfully passed all security constraints"); 524 } 525 getNext().invoke(request, response); 526 527 } 528 529 530 532 533 534 535 542 protected void associate(String ssoId, Session session) { 543 544 if (sso == null) 545 return; 546 sso.associate(ssoId, session); 547 548 } 549 550 551 564 protected abstract boolean authenticate(Request request, 565 Response response, 566 LoginConfig config) 567 throws IOException ; 568 569 570 574 protected synchronized String generateSessionId() { 575 576 byte bytes[] = new byte[SESSION_ID_BYTES]; 578 getRandom().nextBytes(bytes); 579 bytes = getDigest().digest(bytes); 580 581 StringBuffer result = new StringBuffer (); 583 for (int i = 0; i < bytes.length; i++) { 584 byte b1 = (byte) ((bytes[i] & 0xf0) >> 4); 585 byte b2 = (byte) (bytes[i] & 0x0f); 586 if (b1 < 10) 587 result.append((char) ('0' + b1)); 588 else 589 result.append((char) ('A' + (b1 - 10))); 590 if (b2 < 10) 591 result.append((char) ('0' + b2)); 592 else 593 result.append((char) ('A' + (b2 - 10))); 594 } 595 return (result.toString()); 596 597 } 598 599 600 605 protected synchronized MessageDigest getDigest() { 606 607 if (this.digest == null) { 608 try { 609 this.digest = MessageDigest.getInstance(algorithm); 610 } catch (NoSuchAlgorithmException e) { 611 try { 612 this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); 613 } catch (NoSuchAlgorithmException f) { 614 this.digest = null; 615 } 616 } 617 } 618 619 return (this.digest); 620 621 } 622 623 624 629 protected synchronized Random getRandom() { 630 631 if (this.random == null) { 632 try { 633 Class clazz = Class.forName(randomClass); 634 this.random = (Random ) clazz.newInstance(); 635 long seed = System.currentTimeMillis(); 636 char entropy[] = getEntropy().toCharArray(); 637 for (int i = 0; i < entropy.length; i++) { 638 long update = ((byte) entropy[i]) << ((i % 8) * 8); 639 seed ^= update; 640 } 641 this.random.setSeed(seed); 642 } catch (Exception e) { 643 this.random = new java.util.Random (); 644 } 645 } 646 647 return (this.random); 648 649 } 650 651 652 660 protected boolean reauthenticateFromSSO(String ssoId, Request request) { 661 662 if (sso == null || ssoId == null) 663 return false; 664 665 boolean reauthenticated = false; 666 667 Container parent = getContainer(); 668 if (parent != null) { 669 Realm realm = parent.getRealm(); 670 if (realm != null) { 671 reauthenticated = sso.reauthenticate(ssoId, realm, request); 672 } 673 } 674 675 if (reauthenticated) { 676 associate(ssoId, request.getSessionInternal(true)); 677 678 if (log.isDebugEnabled()) { 679 log.debug(" Reauthenticated cached principal '" + 680 request.getUserPrincipal().getName() + 681 "' with auth type '" + request.getAuthType() + "'"); 682 } 683 } 684 685 return reauthenticated; 686 } 687 688 689 702 protected void register(Request request, Response response, 703 Principal principal, String authType, 704 String username, String password) { 705 706 if (log.isDebugEnabled()) 707 log.debug("Authenticated '" + principal.getName() + "' with type '" 708 + authType + "'"); 709 710 request.setAuthType(authType); 712 request.setUserPrincipal(principal); 713 714 Session session = request.getSessionInternal(false); 715 if (cache) { 717 if (session != null) { 718 session.setAuthType(authType); 719 session.setPrincipal(principal); 720 if (username != null) 721 session.setNote(Constants.SESS_USERNAME_NOTE, username); 722 else 723 session.removeNote(Constants.SESS_USERNAME_NOTE); 724 if (password != null) 725 session.setNote(Constants.SESS_PASSWORD_NOTE, password); 726 else 727 session.removeNote(Constants.SESS_PASSWORD_NOTE); 728 } 729 } 730 731 if (sso == null) 733 return; 734 735 String ssoId = (String ) request.getNote(Constants.REQ_SSOID_NOTE); 739 if (ssoId == null) { 740 ssoId = generateSessionId(); 742 Cookie cookie = new Cookie (Constants.SINGLE_SIGN_ON_COOKIE, ssoId); 743 cookie.setMaxAge(-1); 744 cookie.setPath("/"); 745 746 String ssoDomain = sso.getCookieDomain(); 748 if(ssoDomain != null) { 749 cookie.setDomain(ssoDomain); 750 } 751 752 response.addCookie(cookie); 753 754 sso.register(ssoId, principal, authType, username, password); 756 request.setNote(Constants.REQ_SSOID_NOTE, ssoId); 757 758 } else { 759 sso.update(ssoId, principal, authType, username, password); 761 } 762 763 if (session == null) 770 session = request.getSessionInternal(true); 771 sso.associate(ssoId, session); 772 773 } 774 775 776 778 779 784 public void addLifecycleListener(LifecycleListener listener) { 785 786 lifecycle.addLifecycleListener(listener); 787 788 } 789 790 791 795 public LifecycleListener[] findLifecycleListeners() { 796 797 return lifecycle.findLifecycleListeners(); 798 799 } 800 801 802 807 public void removeLifecycleListener(LifecycleListener listener) { 808 809 lifecycle.removeLifecycleListener(listener); 810 811 } 812 813 814 822 public void start() throws LifecycleException { 823 824 if (started) 826 throw new LifecycleException 827 (sm.getString("authenticator.alreadyStarted")); 828 lifecycle.fireLifecycleEvent(START_EVENT, null); 829 started = true; 830 831 Container parent = context.getParent(); 834 while ((sso == null) && (parent != null)) { 835 if (!(parent instanceof Pipeline)) { 836 parent = parent.getParent(); 837 continue; 838 } 839 Valve valves[] = ((Pipeline) parent).getValves(); 840 for (int i = 0; i < valves.length; i++) { 841 if (valves[i] instanceof SingleSignOn) { 842 sso = (SingleSignOn) valves[i]; 843 break; 844 } 845 } 846 if (sso == null) 847 parent = parent.getParent(); 848 } 849 if (log.isDebugEnabled()) { 850 if (sso != null) 851 log.debug("Found SingleSignOn Valve at " + sso); 852 else 853 log.debug("No SingleSignOn Valve is present"); 854 } 855 856 } 857 858 859 867 public void stop() throws LifecycleException { 868 869 if (!started) 871 throw new LifecycleException 872 (sm.getString("authenticator.notStarted")); 873 lifecycle.fireLifecycleEvent(STOP_EVENT, null); 874 started = false; 875 876 sso = null; 877 878 } 879 880 881 } 882 | Popular Tags |