1 7 8 package com.sun.security.auth.module; 9 10 import javax.security.auth.*; 11 import javax.security.auth.callback.*; 12 import javax.security.auth.login.*; 13 import javax.security.auth.spi.*; 14 import javax.naming.*; 15 import javax.naming.directory.*; 16 17 import java.io.IOException ; 18 import java.util.Map ; 19 import java.util.LinkedList ; 20 import java.util.ResourceBundle ; 21 22 import com.sun.security.auth.UnixPrincipal; 23 import com.sun.security.auth.UnixNumericUserPrincipal; 24 import com.sun.security.auth.UnixNumericGroupPrincipal; 25 26 import sun.security.util.AuthResources; 27 28 137 public class JndiLoginModule implements LoginModule { 138 139 static final java.util.ResourceBundle rb = 140 java.util.ResourceBundle.getBundle("sun.security.util.AuthResources"); 141 142 143 public final String USER_PROVIDER = "user.provider.url"; 144 public final String GROUP_PROVIDER = "group.provider.url"; 145 146 private boolean debug = false; 148 private boolean strongDebug = false; 149 private String userProvider; 150 private String groupProvider; 151 private boolean useFirstPass = false; 152 private boolean tryFirstPass = false; 153 private boolean storePass = false; 154 private boolean clearPass = false; 155 156 private boolean succeeded = false; 158 private boolean commitSucceeded = false; 159 160 private String username; 162 private char[] password; 163 DirContext ctx; 164 165 private UnixPrincipal userPrincipal; 167 private UnixNumericUserPrincipal UIDPrincipal; 168 private UnixNumericGroupPrincipal GIDPrincipal; 169 private LinkedList supplementaryGroups = new LinkedList (); 170 171 private Subject subject; 173 private CallbackHandler callbackHandler; 174 private Map sharedState; 175 private Map options; 176 177 private static final String CRYPT = "{crypt}"; 178 private static final String USER_PWD = "userPassword"; 179 private static final String USER_UID = "uidNumber"; 180 private static final String USER_GID = "gidNumber"; 181 private static final String GROUP_ID = "gidNumber"; 182 private static final String NAME = "javax.security.auth.login.name"; 183 private static final String PWD = "javax.security.auth.login.password"; 184 185 202 public void initialize(Subject subject, CallbackHandler callbackHandler, 203 Map <String ,?> sharedState, 204 Map <String ,?> options) { 205 206 this.subject = subject; 207 this.callbackHandler = callbackHandler; 208 this.sharedState = sharedState; 209 this.options = options; 210 211 debug = "true".equalsIgnoreCase((String )options.get("debug")); 213 strongDebug = 214 "true".equalsIgnoreCase((String )options.get("strongDebug")); 215 userProvider = (String )options.get(USER_PROVIDER); 216 groupProvider = (String )options.get(GROUP_PROVIDER); 217 tryFirstPass = 218 "true".equalsIgnoreCase((String )options.get("tryFirstPass")); 219 useFirstPass = 220 "true".equalsIgnoreCase((String )options.get("useFirstPass")); 221 storePass = 222 "true".equalsIgnoreCase((String )options.get("storePass")); 223 clearPass = 224 "true".equalsIgnoreCase((String )options.get("clearPass")); 225 } 226 227 241 public boolean login() throws LoginException { 242 243 if (userProvider == null) { 244 throw new LoginException 245 ("Error: Unable to locate JNDI user provider"); 246 } 247 if (groupProvider == null) { 248 throw new LoginException 249 ("Error: Unable to locate JNDI group provider"); 250 } 251 252 if (debug) { 253 System.out.println("\t\t[JndiLoginModule] user provider: " + 254 userProvider); 255 System.out.println("\t\t[JndiLoginModule] group provider: " + 256 groupProvider); 257 } 258 259 if (tryFirstPass) { 261 262 try { 263 attemptAuthentication(true); 266 267 succeeded = true; 269 if (debug) { 270 System.out.println("\t\t[JndiLoginModule] " + 271 "tryFirstPass succeeded"); 272 } 273 return true; 274 } catch (LoginException le) { 275 cleanState(); 277 if (debug) { 278 System.out.println("\t\t[JndiLoginModule] " + 279 "tryFirstPass failed with:" + 280 le.toString()); 281 } 282 } 283 284 } else if (useFirstPass) { 285 286 try { 287 attemptAuthentication(true); 290 291 succeeded = true; 293 if (debug) { 294 System.out.println("\t\t[JndiLoginModule] " + 295 "useFirstPass succeeded"); 296 } 297 return true; 298 } catch (LoginException le) { 299 cleanState(); 301 if (debug) { 302 System.out.println("\t\t[JndiLoginModule] " + 303 "useFirstPass failed"); 304 } 305 throw le; 306 } 307 } 308 309 try { 311 attemptAuthentication(false); 312 313 succeeded = true; 315 if (debug) { 316 System.out.println("\t\t[JndiLoginModule] " + 317 "regular authentication succeeded"); 318 } 319 return true; 320 } catch (LoginException le) { 321 cleanState(); 322 if (debug) { 323 System.out.println("\t\t[JndiLoginModule] " + 324 "regular authentication failed"); 325 } 326 throw le; 327 } 328 } 329 330 354 public boolean commit() throws LoginException { 355 356 if (succeeded == false) { 357 return false; 358 } else { 359 if (subject.isReadOnly()) { 360 cleanState(); 361 throw new LoginException ("Subject is Readonly"); 362 } 363 if (!subject.getPrincipals().contains(userPrincipal)) 365 subject.getPrincipals().add(userPrincipal); 366 if (!subject.getPrincipals().contains(UIDPrincipal)) 367 subject.getPrincipals().add(UIDPrincipal); 368 if (!subject.getPrincipals().contains(GIDPrincipal)) 369 subject.getPrincipals().add(GIDPrincipal); 370 for (int i = 0; i < supplementaryGroups.size(); i++) { 371 if (!subject.getPrincipals().contains 372 ((UnixNumericGroupPrincipal)supplementaryGroups.get(i))) 373 subject.getPrincipals().add((UnixNumericGroupPrincipal) 374 supplementaryGroups.get(i)); 375 } 376 377 if (debug) { 378 System.out.println("\t\t[JndiLoginModule]: " + 379 "added UnixPrincipal,"); 380 System.out.println("\t\t\t\tUnixNumericUserPrincipal,"); 381 System.out.println("\t\t\t\tUnixNumericGroupPrincipal(s),"); 382 System.out.println("\t\t\t to Subject"); 383 } 384 } 385 cleanState(); 387 commitSucceeded = true; 388 return true; 389 } 390 391 409 public boolean abort() throws LoginException { 410 if (debug) 411 System.out.println("\t\t[JndiLoginModule]: " + 412 "aborted authentication failed"); 413 414 if (succeeded == false) { 415 return false; 416 } else if (succeeded == true && commitSucceeded == false) { 417 418 succeeded = false; 420 cleanState(); 421 422 userPrincipal = null; 423 UIDPrincipal = null; 424 GIDPrincipal = null; 425 supplementaryGroups = new LinkedList (); 426 } else { 427 logout(); 430 } 431 return true; 432 } 433 434 447 public boolean logout() throws LoginException { 448 if (subject.isReadOnly()) { 449 cleanState(); 450 throw new LoginException ("Subject is Readonly"); 451 } 452 subject.getPrincipals().remove(userPrincipal); 453 subject.getPrincipals().remove(UIDPrincipal); 454 subject.getPrincipals().remove(GIDPrincipal); 455 for (int i = 0; i < supplementaryGroups.size(); i++) { 456 subject.getPrincipals().remove 457 ((UnixNumericGroupPrincipal)supplementaryGroups.get(i)); 458 } 459 460 461 cleanState(); 463 succeeded = false; 464 commitSucceeded = false; 465 466 userPrincipal = null; 467 UIDPrincipal = null; 468 GIDPrincipal = null; 469 supplementaryGroups = new LinkedList (); 470 471 if (debug) { 472 System.out.println("\t\t[JndiLoginModule]: " + 473 "logged out Subject"); 474 } 475 return true; 476 } 477 478 486 private void attemptAuthentication(boolean getPasswdFromSharedState) 487 throws LoginException { 488 489 String encryptedPassword = null; 490 491 getUsernamePassword(getPasswdFromSharedState); 493 494 try { 495 496 InitialContext iCtx = new InitialContext(); 498 ctx = (DirContext)iCtx.lookup(userProvider); 499 500 509 510 SearchControls controls = new SearchControls(); 511 NamingEnumeration ne = ctx.search("", 512 "(uid=" + username + ")", 513 controls); 514 if (ne.hasMore()) { 515 SearchResult result = (SearchResult)ne.next(); 516 Attributes attributes = result.getAttributes(); 517 518 520 535 Attribute pwd = attributes.get(USER_PWD); 536 String encryptedPwd = new String ((byte[])pwd.get(), "UTF8"); 537 encryptedPassword = encryptedPwd.substring(CRYPT.length()); 538 539 if (verifyPassword 541 (encryptedPassword, new String (password)) == true) { 542 543 if (debug) 545 System.out.println("\t\t[JndiLoginModule] " + 546 "attemptAuthentication() succeeded"); 547 548 } else { 549 if (debug) 551 System.out.println("\t\t[JndiLoginModule] " + 552 "attemptAuthentication() failed"); 553 throw new FailedLoginException("Login incorrect"); 554 } 555 556 if (storePass && 559 !sharedState.containsKey(NAME) && 560 !sharedState.containsKey(PWD)) { 561 sharedState.put(NAME, username); 562 sharedState.put(PWD, password); 563 } 564 565 userPrincipal = new UnixPrincipal(username); 567 568 Attribute uid = attributes.get(USER_UID); 570 String uidNumber = (String )uid.get(); 571 UIDPrincipal = new UnixNumericUserPrincipal(uidNumber); 572 if (debug && uidNumber != null) { 573 System.out.println("\t\t[JndiLoginModule] " + 574 "user: '" + username + "' has UID: " + 575 uidNumber); 576 } 577 578 Attribute gid = attributes.get(USER_GID); 580 String gidNumber = (String )gid.get(); 581 GIDPrincipal = new UnixNumericGroupPrincipal 582 (gidNumber, true); 583 if (debug && gidNumber != null) { 584 System.out.println("\t\t[JndiLoginModule] " + 585 "user: '" + username + "' has GID: " + 586 gidNumber); 587 } 588 589 ctx = (DirContext)iCtx.lookup(groupProvider); 591 ne = ctx.search("", new BasicAttributes("memberUid", username)); 592 593 while (ne.hasMore()) { 594 result = (SearchResult)ne.next(); 595 attributes = result.getAttributes(); 596 597 gid = attributes.get(GROUP_ID); 598 String suppGid = (String )gid.get(); 599 if (!gidNumber.equals(suppGid)) { 600 UnixNumericGroupPrincipal suppPrincipal = 601 new UnixNumericGroupPrincipal(suppGid, false); 602 supplementaryGroups.add(suppPrincipal); 603 if (debug && suppGid != null) { 604 System.out.println("\t\t[JndiLoginModule] " + 605 "user: '" + username + 606 "' has Supplementary Group: " + 607 suppGid); 608 } 609 } 610 } 611 612 } else { 613 if (debug) { 615 System.out.println("\t\t[JndiLoginModule]: User not found"); 616 } 617 throw new FailedLoginException("User not found"); 618 } 619 } catch (NamingException ne) { 620 if (debug) { 622 System.out.println("\t\t[JndiLoginModule]: User not found"); 623 ne.printStackTrace(); 624 } 625 throw new FailedLoginException("User not found"); 626 } catch (java.io.UnsupportedEncodingException uee) { 627 if (debug) { 629 System.out.println("\t\t[JndiLoginModule]: " + 630 "password incorrectly encoded"); 631 uee.printStackTrace(); 632 } 633 throw new LoginException("Login failure due to incorrect " + 634 "password encoding in the password database"); 635 } 636 637 } 639 640 654 private void getUsernamePassword(boolean getPasswdFromSharedState) 655 throws LoginException { 656 657 if (getPasswdFromSharedState) { 658 username = (String )sharedState.get(NAME); 660 password = (char[])sharedState.get(PWD); 661 return; 662 } 663 664 if (callbackHandler == null) 666 throw new LoginException("Error: no CallbackHandler available " + 667 "to garner authentication information from the user"); 668 669 String protocol = userProvider.substring(0, userProvider.indexOf(":")); 670 671 Callback[] callbacks = new Callback[2]; 672 callbacks[0] = new NameCallback(protocol + " " 673 + rb.getString("username: ")); 674 callbacks[1] = new PasswordCallback(protocol + " " + 675 rb.getString("password: "), 676 false); 677 678 try { 679 callbackHandler.handle(callbacks); 680 username = ((NameCallback)callbacks[0]).getName(); 681 char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword(); 682 password = new char[tmpPassword.length]; 683 System.arraycopy(tmpPassword, 0, 684 password, 0, tmpPassword.length); 685 ((PasswordCallback)callbacks[1]).clearPassword(); 686 687 } catch (java.io.IOException ioe) { 688 throw new LoginException(ioe.toString()); 689 } catch (UnsupportedCallbackException uce) { 690 throw new LoginException("Error: " + uce.getCallback().toString() + 691 " not available to garner authentication information " + 692 "from the user"); 693 } 694 695 if (strongDebug) { 697 System.out.println("\t\t[JndiLoginModule] " + 698 "user entered username: " + 699 username); 700 System.out.print("\t\t[JndiLoginModule] " + 701 "user entered password: "); 702 for (int i = 0; i < password.length; i++) 703 System.out.print(password[i]); 704 System.out.println(); 705 } 706 } 707 708 711 private boolean verifyPassword(String encryptedPassword, String password) { 712 713 if (encryptedPassword == null) 714 return false; 715 716 Crypt c = new Crypt(); 717 try { 718 byte oldCrypt[] = encryptedPassword.getBytes("UTF8"); 719 byte newCrypt[] = c.crypt(password.getBytes("UTF8"), 720 oldCrypt); 721 if (newCrypt.length != oldCrypt.length) 722 return false; 723 for (int i = 0; i < newCrypt.length; i++) { 724 if (oldCrypt[i] != newCrypt[i]) 725 return false; 726 } 727 } catch (java.io.UnsupportedEncodingException uee) { 728 return false; 730 } 731 return true; 732 } 733 734 737 private void cleanState() { 738 username = null; 739 if (password != null) { 740 for (int i = 0; i < password.length; i++) 741 password[i] = ' '; 742 password = null; 743 } 744 ctx = null; 745 746 if (clearPass) { 747 sharedState.remove(NAME); 748 sharedState.remove(PWD); 749 } 750 } 751 } 752 | Popular Tags |