1 23 24 25 package com.sun.enterprise.security.auth.realm.file; 26 27 import java.lang.*; 28 import java.util.*; 29 import java.util.logging.Logger ; 30 import java.util.logging.Level ; 31 import com.sun.logging.LogDomains; 32 import java.io.*; 33 import java.security.*; 34 import javax.security.auth.login.*; 35 import com.sun.enterprise.security.auth.realm.User; 36 import com.sun.enterprise.security.auth.realm.Realm; 37 import com.sun.enterprise.security.auth.realm.BadRealmException; 38 import com.sun.enterprise.security.auth.realm.NoSuchUserException; 39 import com.sun.enterprise.security.auth.realm.NoSuchRealmException; 40 import com.sun.enterprise.security.auth.realm.AuthenticationHandler; 41 import com.sun.enterprise.security.auth.realm.InvalidOperationException; 42 import com.sun.enterprise.server.*; 43 import com.sun.enterprise.security.RealmConfig; 44 import com.sun.enterprise.security.util.*; 45 import com.sun.enterprise.security.auth.realm.IASRealm; 46 import sun.misc.BASE64Decoder; 47 import sun.misc.BASE64Encoder; 48 49 50 75 76 final public class FileRealm extends IASRealm 77 { 78 public static final String AUTH_TYPE = "filepassword"; 80 81 public static final String PARAM_KEYFILE="file"; 83 84 private static final String FIELD_SEP=";"; 86 private static final String GROUP_SEP=","; 87 private static final String COMMENT="#"; 88 89 public static final String MISC_VALID_CHARS="_-."; 91 92 private static final int SALT_SIZE=8; 94 95 private Map userTable; private Hashtable groupSizeMap; 99 private boolean constructed = false; 100 101 102 126 public FileRealm(String keyfile) 127 throws BadRealmException, NoSuchRealmException 128 { 129 File fp = new File(keyfile); 130 if (!fp.exists()) { 132 FileOutputStream fout = null; 133 try { 134 fout = new FileOutputStream(fp); 135 fout.write("\n".getBytes()); 136 } catch (Exception e) { 137 String msg = sm.getString("filerealm.noaccess", e.toString()); 138 throw new BadRealmException(msg); 139 } finally { 140 if (fout != null) { 141 try { 142 fout.close(); 143 } catch(Exception ex) { 144 } 146 } 147 } 148 } 149 150 constructed = true; 151 Properties p = new Properties(); 152 p.setProperty(PARAM_KEYFILE, keyfile); 153 p.setProperty(IASRealm.JAAS_CONTEXT_PARAM, "ignore"); 154 this.init(p); 155 } 156 157 158 163 public FileRealm() 164 { 165 } 166 167 168 180 protected void init(Properties props) 181 throws BadRealmException, NoSuchRealmException 182 { 183 String file = props.getProperty(PARAM_KEYFILE); 184 if (file == null) { 185 String msg = sm.getString("filerealm.nofile"); 186 throw new BadRealmException(msg); 187 } 188 this.setProperty(PARAM_KEYFILE, file); 189 190 String jaasCtx = props.getProperty(IASRealm.JAAS_CONTEXT_PARAM); 191 if (jaasCtx == null) { 192 String msg = sm.getString("filerealm.nomodule"); 193 throw new BadRealmException(msg); 194 } 195 this.setProperty(IASRealm.JAAS_CONTEXT_PARAM, jaasCtx); 196 197 _logger.fine("FileRealm : "+PARAM_KEYFILE+"="+file); 198 _logger.fine("FileRealm : "+IASRealm.JAAS_CONTEXT_PARAM+"="+ 199 jaasCtx); 200 201 loadKeyFile(); 202 } 203 204 205 212 public String getAuthType() 213 { 214 return AUTH_TYPE; 215 } 216 217 218 224 public Enumeration getUserNames() 225 throws BadRealmException 226 { 227 return (new Vector(userTable.keySet())).elements(); } 229 230 231 239 public User getUser(String name) 240 throws NoSuchUserException 241 { 242 FileRealmUser u = (FileRealmUser)userTable.get(name); 243 if (u == null) { 244 String msg = sm.getString("filerealm.nouser", name); 245 throw new NoSuchUserException(msg); 246 } 247 return u; 248 } 249 250 251 257 public Enumeration getGroupNames() 258 throws BadRealmException 259 { 260 return groupSizeMap.keys(); 261 } 262 263 264 273 public Enumeration getGroupNames(String username) 274 throws NoSuchUserException 275 { 276 FileRealmUser ud = (FileRealmUser)userTable.get(username); 277 if (ud == null) { 278 String msg = sm.getString("filerealm.nouser", username); 279 throw new NoSuchUserException(msg); 280 } 281 282 String [] groups = ud.getGroups(); 283 Vector v = new Vector(); 284 if (groups != null) { 285 for (int i = 0; i < groups.length; i++) { 286 v.add(groups[i]); 287 } 288 } 289 return v.elements(); 290 } 291 292 293 305 public void refresh() 306 throws BadRealmException 307 { 308 _logger.fine("Reloading file realm data."); 309 310 FileRealm newRealm = new FileRealm(); 311 312 try { 313 newRealm.init(getProperties()); 314 Realm.updateInstance(newRealm, this.getName()); 315 } catch (Exception e) { 316 throw new BadRealmException(e.toString()); 317 } 318 } 319 320 321 337 public String [] authenticate(String user, String password) 338 { 339 FileRealmUser ud = (FileRealmUser)userTable.get(user); 340 if (ud == null) { 341 if (_logger.isLoggable(Level.FINE)) { 342 _logger.fine("No such user: [" + user + "]"); 343 } 344 return null; 345 } 346 347 boolean ok = false; 348 try { 349 ok = SSHA.verify(ud.getSalt(), ud.getHash(), password.getBytes()); 350 351 } catch (Exception e) { 352 _logger.fine("File authentication failed: "+e.toString()); 353 return null; 354 } 355 356 if (!ok) { 357 if (_logger.isLoggable(Level.FINE)) { 358 _logger.fine("File authentication failed for: ["+user+"]"); 359 } 360 return null; 361 } 362 363 return ud.getGroups(); 364 } 365 366 367 368 371 372 382 private static boolean isValid(String s, boolean userName) 383 { 384 for (int i=0; i<s.length(); i++) { 385 char c = s.charAt(i); 386 if (!Character.isLetterOrDigit(c) && 387 !Character.isWhitespace(c) && 388 MISC_VALID_CHARS.indexOf(c) == -1) { 389 if (userName && (c == '@')){ 390 continue; 391 } 392 return false; 393 } 394 } 395 return true; 396 } 397 398 399 415 public static void validateUserName(String name) 416 throws IASSecurityException 417 { 418 if (name == null || name.length() == 0) { 419 String msg = sm.getString("filerealm.noname"); 420 throw new IASSecurityException(msg); 421 } 422 423 if (!isValid(name, true)) { 424 String msg = sm.getString("filerealm.badname", name); 425 throw new IASSecurityException(msg); 426 } 427 428 if (!name.equals(name.trim())) { 429 String msg = sm.getString("filerealm.badspaces", name); 430 throw new IASSecurityException(msg); 431 } 432 } 433 434 435 451 public static void validatePassword(String pwd) 452 throws IASSecurityException 453 { 454 if (pwd == null) { 455 String msg = sm.getString("filerealm.emptypwd"); 456 throw new IASSecurityException(msg); 457 } 458 459 if (!pwd.equals(pwd.trim())) { 460 String msg = sm.getString("filerealm.badspacespwd"); 461 throw new IASSecurityException(msg); 462 } 463 } 464 465 466 482 public static void validateGroupName(String group) 483 throws IASSecurityException 484 { 485 if (group == null || group.length() == 0) { 486 String msg = sm.getString("filerealm.nogroup"); 487 throw new IASSecurityException(msg); 488 } 489 490 if (!isValid(group, false)) { 491 String msg = sm.getString("filerealm.badchars", group); 492 throw new IASSecurityException(msg); 493 } 494 495 if (!group.equals(group.trim())) { 496 String msg = sm.getString("filerealm.badspaces", group); 497 throw new IASSecurityException(msg); 498 } 499 } 500 501 502 513 public static void validateGroupList(String [] groupList) 514 throws IASSecurityException 515 { 516 if (groupList == null || groupList.length == 0) { 517 return; } 519 520 for (int i=0; i<groupList.length; i++) { 521 validateGroupName(groupList[i]); 522 } 523 524 } 525 526 527 536 public synchronized void addUser(String name, String password, 537 String [] groupList) 538 throws BadRealmException, IASSecurityException 539 { 540 validateUserName(name); 541 validatePassword(password); 542 validateGroupList(groupList); 543 544 if (userTable.containsKey(name)) { 545 String msg = sm.getString("filerealm.dupuser", name); 546 throw new BadRealmException(msg); 547 } 548 549 addGroupNames(groupList); 550 FileRealmUser ud = createNewUser(name, password, groupList); 551 userTable.put(name, ud); 552 } 553 554 555 562 public synchronized void removeUser(String name) 563 throws NoSuchUserException 564 { 565 if (!userTable.containsKey(name)) { 566 String msg = sm.getString("filerealm.nouser", name); 567 throw new NoSuchUserException(msg); 568 } 569 570 FileRealmUser oldUser = (FileRealmUser)userTable.get(name); 571 userTable.remove(name); 572 reduceGroups(oldUser.getGroups()); 573 } 574 575 576 588 public synchronized void updateUser(String name, String password, 589 String [] groups) 590 throws NoSuchUserException, BadRealmException, 591 IASSecurityException 592 { 593 updateUser(name, name, password, groups); 594 } 595 596 597 612 public synchronized void updateUser(String name, String newName, String password, 613 String [] groups) 614 throws NoSuchUserException, BadRealmException, 615 IASSecurityException 616 { 617 validateUserName(name); 619 if (!userTable.containsKey(name)) { 620 String msg = sm.getString("filerealm.nouser", name); 621 throw new NoSuchUserException(msg); 622 } 623 624 validateUserName(newName); 626 validateGroupList(groups); 627 if (password != null) { validatePassword(password); 629 } 630 631 if (!name.equals(newName) && userTable.containsKey(newName)) { 633 String msg = sm.getString("filerealm.dupuser", name); 634 throw new BadRealmException(msg); 635 } 636 637 638 FileRealmUser oldUser = (FileRealmUser)userTable.get(name); 639 assert (oldUser != null); 640 641 FileRealmUser newUser = new FileRealmUser(newName); 643 644 changeGroups(oldUser.getGroups(), groups); 646 newUser.setGroups(groups); 647 648 if (password==null) { 650 newUser.setSalt(oldUser.getSalt()); 651 newUser.setHash(oldUser.getHash()); 652 653 } else { 654 setPassword(newUser, password); 655 } 656 657 userTable.remove(name); 658 userTable.put(newName, newUser); 659 } 660 661 662 671 public void writeKeyFile(String filename) 672 throws IOException 673 { 674 synchronized(FileRealm.class) { 675 FileOutputStream out = null; 676 try { 677 out = new FileOutputStream(filename); 678 679 Iterator names = userTable.keySet().iterator(); 680 while (names.hasNext()) { 681 682 String name = (String )names.next(); 683 FileRealmUser ud = (FileRealmUser)userTable.get(name); 684 685 String entry = encodeUser(name, ud); 686 out.write(entry.getBytes()); 687 } 688 } catch (IOException e) { 689 throw e; 690 691 } catch (Exception e) { 692 String msg = sm.getString("filerealm.badwrite", e.toString()); 693 throw new IOException(msg); 694 } finally { 695 if (out != null) { 696 out.close(); 697 } 698 } 699 } 700 701 _logger.fine("Done writing "+filename); 702 } 703 704 705 708 709 714 private void addGroupNames(String [] groupList) { 715 if (groupList != null) { 716 for (int i=0; i < groupList.length; i++) { 717 Integer groupSize = (Integer )groupSizeMap.get(groupList[i]); 718 groupSizeMap.put(groupList[i], 719 (groupSize != null) ? 720 new Integer (groupSize.intValue() + 1): new Integer (1)); 721 } 722 } 723 } 724 725 729 private void reduceGroups(String [] groupList) { 730 if (groupList != null) { 731 for (int i=0; i < groupList.length; i++) { 732 Integer groupSize = (Integer )groupSizeMap.get(groupList[i]); 733 if (groupSize != null) { 734 int gpSize = groupSize.intValue() - 1; 735 if (gpSize > 0) { 736 groupSizeMap.put(groupList[i], new Integer (gpSize)); 737 } else { 738 groupSizeMap.remove(groupList[i]); 739 } 740 } 741 } 742 } 743 } 744 745 748 private void changeGroups(String [] oldGroupList, String [] newGroupList) { 749 addGroupNames(newGroupList); 750 reduceGroups(oldGroupList); 751 } 752 753 754 758 private void loadKeyFile() throws BadRealmException 759 { 760 String file = this.getProperty(PARAM_KEYFILE); 761 762 _logger.fine("Reading file realm: "+file); 763 764 userTable = new Hashtable(); 765 groupSizeMap = new Hashtable(); 766 BufferedReader input = null; 767 768 try { 769 input = new BufferedReader(new FileReader(file)); 770 771 while (input.ready()) { 772 773 String line = input.readLine(); 774 if (!line.startsWith(COMMENT) && 775 line.indexOf(FIELD_SEP) > 0) { 776 FileRealmUser ud = decodeUser(line, groupSizeMap); 777 userTable.put(ud.getName(), ud); 778 } 779 } 780 } catch (Exception e) { 781 _logger.log(Level.WARNING, "filerealm.readerror", e); 782 throw new BadRealmException(e.toString()); 783 } finally { 784 if (input != null) { 785 try { 786 input.close(); 787 } catch(Exception ex) { 788 } 789 } 790 } 791 } 792 793 794 803 private static String encodeUser(String name, FileRealmUser ud) 804 { 805 StringBuffer sb = new StringBuffer (); 806 String cryptPwd = null; 807 808 sb.append(name); 809 sb.append(FIELD_SEP); 810 811 String ssha = SSHA.encode(ud.getSalt(), ud.getHash()); 812 813 sb.append(ssha); 814 sb.append(FIELD_SEP); 815 816 String [] groups = ud.getGroups(); 817 if (groups != null) { 818 for (int grp = 0; grp < groups.length; grp++) { 819 if (grp > 0) { 820 sb.append(GROUP_SEP); 821 } 822 sb.append((String )groups[grp]); 823 } 824 } 825 sb.append("\n"); 826 return sb.toString(); 827 } 828 829 830 840 private static FileRealmUser decodeUser(String encodedLine, 841 Map newGroupSizeMap) 842 throws IASSecurityException 843 { 844 StringTokenizer st = new StringTokenizer(encodedLine, FIELD_SEP); 845 846 String user = null; 847 String pwdInfo = null; 848 String groupList = null; 849 850 try { user = st.nextToken(); 852 pwdInfo = st.nextToken(); 853 } catch (Exception e) { 854 String msg = sm.getString("filerealm.syntaxerror", encodedLine); 855 throw new IASSecurityException(msg); 856 } 857 858 if (st.hasMoreTokens()) { groupList = st.nextToken(); 860 } 861 862 byte[] hash = new byte[20]; 863 byte[] salt = SSHA.decode(pwdInfo, hash); 864 865 FileRealmUser ud = new FileRealmUser(user); 866 ud.setHash(hash); 867 ud.setSalt(salt); 868 869 Vector membership = new Vector(); 870 871 if (groupList != null) { 872 StringTokenizer gst = new StringTokenizer(groupList, 873 GROUP_SEP); 874 while (gst.hasMoreTokens()) { 875 String g = gst.nextToken(); 876 membership.add(g); 877 Integer groupSize = (Integer )newGroupSizeMap.get(g); 878 newGroupSizeMap.put(g, (groupSize != null) ? 879 new Integer (groupSize.intValue() + 1) : new Integer (1)); 880 } 881 } 882 ud.setGroups(membership); 883 return ud; 884 } 885 886 887 897 private static FileRealmUser createNewUser(String name, String pwd, 898 String [] groups) 899 throws IASSecurityException 900 { 901 FileRealmUser ud = new FileRealmUser(name); 902 903 if (groups == null) { 904 groups = new String [0]; 905 } 906 ud.setGroups(groups); 907 908 setPassword(ud, pwd); 909 910 return ud; 911 } 912 913 914 920 private static void setPassword(FileRealmUser user, String pwd) 921 throws IASSecurityException 922 { 923 assert (user != null); 924 byte[] pwdBytes = pwd.getBytes(); 925 926 SecureRandom rng=new SecureRandom(); 927 byte[] salt=new byte[SALT_SIZE]; 928 rng.nextBytes(salt); 929 user.setSalt(salt); 930 931 byte[] hash = SSHA.compute(salt, pwdBytes); 932 user.setHash(hash); 933 } 934 935 936 937 941 public static void main(String [] args) 942 { 943 if (args.length==0) { 944 help(); 945 } 946 947 try { 948 if ("-c".equals(args[0])) { 949 String [] groups=new String [0]; 950 if (args.length>3) { 951 groups=new String [args.length-3]; 952 for (int i=3; i<args.length; i++) { 953 groups[i-3]=args[i]; 954 } 955 } 956 FileRealmUser ud = createNewUser(args[1], args[2], groups); 957 String out=encodeUser(args[1], ud); 958 System.out.println(out); 959 960 FileRealmUser u=decodeUser(out, new Hashtable()); 961 System.out.println("verifies: "+ 962 SSHA.verify(u.getSalt(), u.getHash(), 963 args[2].getBytes())); 964 965 } else if ("-v".equals(args[0])) { 966 FileRealmUser u=decodeUser(args[2], new Hashtable()); 967 System.out.println("user: "+u.getName()); 968 System.out.println("verifies: "+ 969 SSHA.verify(u.getSalt(), u.getHash(), 970 args[1].getBytes())); 971 } 972 } catch (Exception e) { 973 e.printStackTrace(System.out); 974 } 975 } 976 980 private static void help() 981 { 982 System.out.println("FileRealm -c <name <pwd [group]*"); 983 System.out.println("FileRealm -v <pwd `output of -c`"); 984 System.exit(1); 985 } 986 987 988 989 } 990 | Popular Tags |