1 28 29 package com.caucho.server.security; 30 31 import com.caucho.log.Log; 32 import com.caucho.security.BasicPrincipal; 33 import com.caucho.server.session.SessionImpl; 34 import com.caucho.server.session.SessionManager; 35 import com.caucho.server.webapp.Application; 36 import com.caucho.util.Alarm; 37 import com.caucho.util.CharBuffer; 38 import com.caucho.util.L10N; 39 import com.caucho.util.LruCache; 40 41 import javax.annotation.PostConstruct; 42 import javax.servlet.ServletContext ; 43 import javax.servlet.ServletException ; 44 import javax.servlet.http.HttpServletRequest ; 45 import javax.servlet.http.HttpServletResponse ; 46 import javax.servlet.http.HttpSession ; 47 import java.lang.ref.SoftReference ; 48 import java.security.MessageDigest ; 49 import java.security.Principal ; 50 import java.util.ArrayList ; 51 import java.util.logging.Level ; 52 import java.util.logging.Logger ; 53 54 62 public class AbstractAuthenticator implements ServletAuthenticator { 63 static final Logger log = Log.open(AbstractAuthenticator.class); 64 static final L10N L = new L10N(AbstractAuthenticator.class); 65 66 public static final String LOGIN_NAME = "com.caucho.servlet.login.name"; 67 68 69 protected int _principalCacheSize = 4096; 70 protected LruCache<String ,PrincipalEntry> _principalCache; 71 72 protected String _passwordDigestAlgorithm = "MD5-base64"; 73 protected String _passwordDigestRealm = "resin"; 74 protected PasswordDigest _passwordDigest; 75 76 private boolean _logoutOnTimeout = true; 77 78 81 public int getPrincipalCacheSize() 82 { 83 return _principalCacheSize; 84 } 85 86 89 public void setPrincipalCacheSize(int size) 90 { 91 _principalCacheSize = size; 92 } 93 94 97 public PasswordDigest getPasswordDigest() 98 { 99 return _passwordDigest; 100 } 101 102 106 public void setPasswordDigest(PasswordDigest digest) 107 { 108 _passwordDigest = digest; 109 } 110 111 114 public String getPasswordDigestAlgorithm() 115 { 116 return _passwordDigestAlgorithm; 117 } 118 119 123 public void setPasswordDigestAlgorithm(String digest) 124 { 125 _passwordDigestAlgorithm = digest; 126 } 127 128 131 public String getPasswordDigestRealm() 132 { 133 return _passwordDigestRealm; 134 } 135 136 139 public void setPasswordDigestRealm(String realm) 140 { 141 _passwordDigestRealm = realm; 142 } 143 144 147 public boolean getLogoutOnSessionTimeout() 148 { 149 return _logoutOnTimeout; 150 } 151 152 155 public void setLogoutOnSessionTimeout(boolean logout) 156 { 157 _logoutOnTimeout = logout; 158 } 159 160 163 public void addRoleMapping(Principal principal, String role) 164 { 165 } 166 167 170 @PostConstruct 171 public void init() 172 throws ServletException 173 { 174 if (_principalCacheSize > 0) 175 _principalCache = new LruCache<String ,PrincipalEntry>(_principalCacheSize); 176 177 if (_passwordDigest != null) { 178 if (_passwordDigest.getAlgorithm() == null || 179 _passwordDigest.getAlgorithm().equals("none")) 180 _passwordDigest = null; 181 } 182 else if (_passwordDigestAlgorithm == null || 183 _passwordDigestAlgorithm.equals("none")) { 184 } 185 else { 186 int p = _passwordDigestAlgorithm.indexOf('-'); 187 188 if (p > 0) { 189 String algorithm = _passwordDigestAlgorithm.substring(0, p); 190 String format = _passwordDigestAlgorithm.substring(p + 1); 191 192 _passwordDigest = new PasswordDigest(); 193 _passwordDigest.setAlgorithm(algorithm); 194 _passwordDigest.setFormat(format); 195 _passwordDigest.setRealm(_passwordDigestRealm); 196 197 _passwordDigest.init(); 198 } 199 } 200 } 201 202 205 public Principal login(HttpServletRequest request, 206 HttpServletResponse response, 207 ServletContext app, 208 String user, String password) 209 throws ServletException 210 { 211 String digestPassword = getPasswordDigest(request, response, app, 212 user, password); 213 214 Principal principal = loginImpl(request, response, app, user, 215 digestPassword); 216 217 if (principal != null) { 218 SessionImpl session = (SessionImpl) request.getSession(); 219 session.setUser(principal); 220 221 if (_principalCache != null) { 222 PrincipalEntry entry = new PrincipalEntry(principal); 223 entry.addSession(session); 224 225 _principalCache.put(session.getId(), entry); 226 } 227 } 228 229 return principal; 230 } 231 232 237 public String getPasswordDigest(HttpServletRequest request, 238 HttpServletResponse response, 239 ServletContext app, 240 String user, String password) 241 throws ServletException 242 { 243 244 if (_passwordDigest != null) 245 return _passwordDigest.getPasswordDigest(request, response, app, 246 user, password); 247 else 248 return password; 249 } 250 251 254 protected Principal loginImpl(HttpServletRequest request, 255 HttpServletResponse response, 256 ServletContext application, 257 String user, String password) 258 throws ServletException 259 { 260 return null; 261 } 262 263 264 294 public Principal loginDigest(HttpServletRequest request, 295 HttpServletResponse response, 296 ServletContext app, 297 String user, String realm, 298 String nonce, String uri, 299 String qop, String nc, String cnonce, 300 byte []clientDigest) 301 throws ServletException 302 { 303 Principal principal = loginDigestImpl(request, response, app, 304 user, realm, nonce, uri, 305 qop, nc, cnonce, 306 clientDigest); 307 308 if (principal != null) { 309 SessionImpl session = (SessionImpl) request.getSession(); 310 session.setUser(principal); 311 312 if (_principalCache != null) { 313 PrincipalEntry entry = new PrincipalEntry(principal); 314 entry.addSession(session); 315 316 _principalCache.put(session.getId(), entry); 317 } 318 } 319 320 return principal; 321 } 322 323 349 public Principal loginDigestImpl(HttpServletRequest request, 350 HttpServletResponse response, 351 ServletContext app, 352 String user, String realm, 353 String nonce, String uri, 354 String qop, String nc, String cnonce, 355 byte []clientDigest) 356 throws ServletException 357 { 358 359 try { 360 if (clientDigest == null) 361 return null; 362 363 MessageDigest digest = MessageDigest.getInstance("MD5"); 364 365 byte []a1 = getDigestSecret(request, response, app, 366 user, realm, "MD5"); 367 368 if (a1 == null) 369 return null; 370 371 digestUpdateHex(digest, a1); 372 373 digest.update((byte) ':'); 374 for (int i = 0; i < nonce.length(); i++) 375 digest.update((byte) nonce.charAt(i)); 376 377 if (qop != null) { 378 digest.update((byte) ':'); 379 for (int i = 0; i < nc.length(); i++) 380 digest.update((byte) nc.charAt(i)); 381 382 digest.update((byte) ':'); 383 384 for (int i = 0; cnonce != null && i < cnonce.length(); i++) 385 digest.update((byte) cnonce.charAt(i)); 386 387 digest.update((byte) ':'); 388 for (int i = 0; qop != null && i < qop.length(); i++) 389 digest.update((byte) qop.charAt(i)); 390 } 391 digest.update((byte) ':'); 392 393 byte []a2 = digest(request.getMethod() + ":" + uri); 394 395 digestUpdateHex(digest, a2); 396 397 byte []serverDigest = digest.digest(); 398 399 if (clientDigest.length != serverDigest.length) 400 return null; 401 402 for (int i = 0; i < clientDigest.length; i++) { 403 if (serverDigest[i] != clientDigest[i]) 404 return null; 405 } 406 407 return new BasicPrincipal(user); 408 } catch (Exception e) { 409 throw new ServletException (e); 410 } 411 } 412 413 private void digestUpdateHex(MessageDigest digest, byte []bytes) 414 { 415 for (int i = 0; i < bytes.length; i++) { 416 int b = bytes[i]; 417 int d1 = (b >> 4) & 0xf; 418 int d2 = b & 0xf; 419 420 if (d1 < 10) 421 digest.update((byte) (d1 + '0')); 422 else 423 digest.update((byte) (d1 + 'a' - 10)); 424 425 if (d2 < 10) 426 digest.update((byte) (d2 + '0')); 427 else 428 digest.update((byte) (d2 + 'a' - 10)); 429 } 430 } 431 432 protected byte []stringToDigest(String digest) 433 { 434 if (digest == null) 435 return null; 436 437 int len = (digest.length() + 1) / 2; 438 byte []clientDigest = new byte[len]; 439 440 for (int i = 0; i + 1 < digest.length(); i += 2) { 441 int ch1 = digest.charAt(i); 442 int ch2 = digest.charAt(i + 1); 443 444 int b = 0; 445 if (ch1 >= '0' && ch1 <= '9') 446 b += ch1 - '0'; 447 else if (ch1 >= 'a' && ch1 <= 'f') 448 b += ch1 - 'a' + 10; 449 450 b *= 16; 451 452 if (ch2 >= '0' && ch2 <= '9') 453 b += ch2 - '0'; 454 else if (ch2 >= 'a' && ch2 <= 'f') 455 b += ch2 - 'a' + 10; 456 457 clientDigest[i / 2] = (byte) b; 458 } 459 460 return clientDigest; 461 } 462 463 private String digestToString(byte []digest) 464 { 465 if (digest == null) 466 return "null"; 467 468 CharBuffer cb = CharBuffer.allocate(); 469 for (int i = 0; i < digest.length; i++) { 470 int ch = digest[i]; 471 472 int d1 = (ch >> 4) & 0xf; 473 int d2 = ch & 0xf; 474 475 if (d1 < 10) 476 cb.append((char) (d1 + '0')); 477 else 478 cb.append((char) (d1 + 'a' - 10)); 479 480 if (d2 < 10) 481 cb.append((char) (d2 + '0')); 482 else 483 cb.append((char) (d2 + 'a' - 10)); 484 } 485 486 return cb.close(); 487 } 488 489 492 protected byte []getDigestSecret(HttpServletRequest request, 493 HttpServletResponse response, 494 ServletContext application, 495 String username, String realm, 496 String algorithm) 497 throws ServletException 498 { 499 String password = getDigestPassword(request, response, application, 500 username, realm); 501 502 if (password == null) 503 return null; 504 505 if (_passwordDigest != null) 506 return _passwordDigest.stringToDigest(password); 507 508 try { 509 MessageDigest digest = MessageDigest.getInstance(algorithm); 510 511 String string = username + ":" + realm + ":" + password; 512 byte []data = string.getBytes("UTF8"); 513 return digest.digest(data); 514 } catch (Exception e) { 515 throw new ServletException (e); 516 } 517 } 518 519 protected byte []digest(String value) 520 throws ServletException 521 { 522 try { 523 MessageDigest digest = MessageDigest.getInstance("MD5"); 524 525 byte []data = value.getBytes("UTF8"); 526 return digest.digest(data); 527 } catch (Exception e) { 528 throw new ServletException (e); 529 } 530 } 531 532 536 protected String getDigestPassword(HttpServletRequest request, 537 HttpServletResponse response, 538 ServletContext application, 539 String username, String realm) 540 throws ServletException 541 { 542 return null; 543 } 544 545 555 public Principal getUserPrincipal(HttpServletRequest request, 556 HttpServletResponse response, 557 ServletContext application) 558 throws ServletException 559 { 560 SessionImpl session = (SessionImpl) request.getSession(false); 561 Principal user = null; 562 563 if (session != null) 564 user = session.getUser(); 565 566 if (user != null) 567 return user; 568 569 PrincipalEntry entry = null; 570 571 if (_principalCache == null) { 572 } 573 else if (session != null) 574 entry = _principalCache.get(session.getId()); 575 else if (request.getRequestedSessionId() != null) 576 entry = _principalCache.get(request.getRequestedSessionId()); 577 578 if (entry != null) { 579 user = entry.getPrincipal(); 580 581 if (session == null) 582 session = (SessionImpl) request.getSession(true); 583 584 session.setUser(user); 585 entry.addSession(session); 586 587 return user; 588 } 589 590 user = getUserPrincipalImpl(request, application); 591 592 if (user == null) { 593 } 594 else if (session != null) { 595 entry = new PrincipalEntry(user); 596 597 session.setUser(user); 598 entry.addSession(session); 599 600 _principalCache.put(session.getId(), entry); 601 } 602 else if (request.getRequestedSessionId() != null) { 603 entry = new PrincipalEntry(user); 604 605 _principalCache.put(request.getRequestedSessionId(), entry); 606 } 607 608 return user; 609 } 610 611 615 protected Principal getUserPrincipalImpl(HttpServletRequest request, 616 ServletContext application) 617 throws ServletException 618 { 619 return null; 620 } 621 622 629 public boolean isUserInRole(HttpServletRequest request, 630 HttpServletResponse response, 631 ServletContext application, 632 Principal user, String role) 633 throws ServletException 634 { 635 return false; 636 } 637 638 645 public void logout(ServletContext application, 646 HttpSession timeoutSession, 647 String sessionId, 648 Principal user) 649 throws ServletException 650 { 651 log.fine("logout " + user); 652 653 if (sessionId != null) { 654 if (_principalCache == null) { 655 } 656 else if (timeoutSession != null) { 657 PrincipalEntry entry = _principalCache.get(sessionId); 658 659 if (entry != null && entry.logout(timeoutSession)) { 660 _principalCache.remove(sessionId); 661 } 662 } 663 else { 664 PrincipalEntry entry = _principalCache.remove(sessionId); 665 666 if (entry != null) 667 entry.logout(); 668 } 669 670 Application app = (Application) application; 671 SessionManager manager = app.getSessionManager(); 672 673 if (manager != null) { 674 SessionImpl session = manager.getSession(sessionId, 675 Alarm.getCurrentTime(), 676 false, true); 677 678 if (session != null) 679 session.logout(); 680 } 681 } 682 } 683 684 690 public void logout(HttpServletRequest request, 691 HttpServletResponse response, 692 ServletContext application, 693 Principal user) 694 throws ServletException 695 { 696 logout(application, null, request.getRequestedSessionId(), user); 697 } 698 699 705 public void logout(ServletContext application, 706 String sessionId, 707 Principal user) 708 throws ServletException 709 { 710 logout(application, null, sessionId, user); 711 } 712 713 static class PrincipalEntry { 714 private Principal _principal; 715 private ArrayList <SoftReference <SessionImpl>> _sessions; 716 717 PrincipalEntry(Principal principal) 718 { 719 _principal = principal; 720 } 721 722 Principal getPrincipal() 723 { 724 return _principal; 725 } 726 727 void addSession(SessionImpl session) 728 { 729 if (_sessions == null) 730 _sessions = new ArrayList <SoftReference <SessionImpl>>(); 731 732 _sessions.add(new SoftReference <SessionImpl>(session)); 733 } 734 735 739 boolean logout(HttpSession timeoutSession) 740 { 741 ArrayList <SoftReference <SessionImpl>> sessions = _sessions; 742 743 if (sessions == null) 744 return true; 745 746 boolean isEmpty = true; 747 for (int i = sessions.size() - 1; i >= 0; i--) { 748 SoftReference <SessionImpl> ref = sessions.get(i); 749 SessionImpl session = ref.get(); 750 751 try { 752 if (session == timeoutSession) { 753 sessions.remove(i); 754 session.logout(); 755 } 756 else if (session == null) 757 sessions.remove(i); 758 else 759 isEmpty = false; 760 } catch (Throwable e) { 761 log.log(Level.WARNING, e.toString(), e); 762 } 763 } 764 765 return isEmpty; 766 } 767 768 void logout() 769 { 770 ArrayList <SoftReference <SessionImpl>> sessions = _sessions; 771 _sessions = null; 772 773 for (int i = 0; sessions != null && i < sessions.size(); i++) { 774 SoftReference <SessionImpl> ref = sessions.get(i); 775 SessionImpl session = ref.get(); 776 777 try { 778 if (session != null) { 779 session.logout(); 780 session.invalidate(); } 782 } catch (Throwable e) { 783 log.log(Level.WARNING, e.toString(), e); 784 } 785 } 786 } 787 } 788 } 789 | Popular Tags |