1 package com.ca.directory.jxplorer.broker; 2 3 import javax.naming.*; 4 import javax.naming.directory.*; 5 6 7 import java.util.*; 8 import java.util.logging.Logger ; 9 import java.util.logging.Level ; 10 import java.io.*; 11 12 import com.ca.directory.jxplorer.*; 13 import com.ca.commons.naming.*; 14 import com.ca.commons.cbutil.*; 15 import com.ca.commons.jndi.*; 16 17 18 19 20 29 30 public class JNDIBroker extends Broker 31 { 32 private static final int SEARCHLIMIT = 0; 34 private static final int SEARCHTIMEOUT = 0; 35 36 40 41 public static final int SEARCH_BASE_OBJECT = 0; 42 43 47 48 public static final int SEARCH_ONE_LEVEL = 1; 49 50 54 55 public static final int SEARCH_SUB_TREE = 2; 56 57 private DirContext ctx; 58 private boolean tracing = false; 61 private boolean connectionError = true; 62 63 64 private Hashtable attributeNames; 65 66 private boolean quietMode = false; private boolean errorWhileQuietFlag = false; 69 int limit = SEARCHLIMIT; int timeout = SEARCHTIMEOUT; 72 static int threadID = 1; static final boolean DEBUGTHREADS = false; 75 private CBGraphicsOps dirOps = null; private SchemaOps schemaOps; 78 private HashSet specialObjectClasses; 80 private final static Logger log = Logger.getLogger(JNDIBroker.class.getName()); 81 82 88 89 public class DataConnectionQuery extends DataQuery 90 { 91 public final ConnectionData conData; 92 93 94 98 99 public DataConnectionQuery(ConnectionData cData) 100 { 101 super(DataQuery.EXTENDED); 102 103 conData = cData; 104 105 setExtendedData("version", String.valueOf(conData.version)); 106 setExtendedData("url", conData.getURL()); 107 } 108 109 110 111 114 115 public String getTypeString() 116 { 117 return super.getTypeString() + " Connection Request"; 118 } 119 } 120 121 122 123 127 128 public JNDIBroker() 129 { 130 initSpecialObjectClasses(); 131 } 132 133 134 135 142 143 public JNDIBroker(JNDIBroker cloneMe) 144 { 145 registerDirectoryConnection(cloneMe); 146 } 147 148 149 150 156 157 public void registerDirectoryConnection(JNDIBroker cloneMe) 158 { 159 ctx = cloneMe.ctx; 160 tracing = cloneMe.tracing; 162 connectionError = cloneMe.connectionError; 163 attributeNames = cloneMe.attributeNames; 164 165 limit = cloneMe.limit; 166 timeout = cloneMe.timeout; 167 168 dirOps = cloneMe.dirOps; 169 schemaOps = cloneMe.schemaOps; 170 171 specialObjectClasses = cloneMe.specialObjectClasses; } 173 174 175 176 179 180 protected void initSpecialObjectClasses() 181 { 182 String fileName = System.getProperty("user.dir") + File.separator + "specialocs.txt"; 183 if (new File(fileName).exists()) 184 { 185 try 186 { 187 String text = CBUtility.readTextFile(new File(fileName)); 188 StringTokenizer st = new StringTokenizer(text); 189 specialObjectClasses = new HashSet(10); 190 while (st.hasMoreTokens()) 191 { 192 String oc = st.nextToken(); 193 specialObjectClasses.add(oc); 194 } 195 } 196 catch (Exception e) 197 { 198 log.info("unable to obtain special object classes list:\n " + e.toString()); 199 specialObjectClasses = null; 200 } 201 } 202 } 203 204 205 206 212 213 public void setGUIQuiet(boolean status) 214 { 215 quietMode = status; 216 dirOps.setQuietMode(status); 217 218 if (quietMode == false) 219 setQuietError(false); } 221 222 223 224 228 229 public void setQuietError(boolean status) 230 { 231 errorWhileQuietFlag = status; 232 } 233 234 235 236 243 244 public boolean getQuietError() 245 { 246 return (errorWhileQuietFlag || dirOps.errorWhileQuietFlag); 247 } 248 249 250 257 258 public void setTracing(boolean traceStatus) 259 { 260 tracing = traceStatus; 261 } 262 263 270 271 public boolean getTracing() { return tracing; } 272 273 297 298 300 public DataQuery connect(String baseDN, int version, String host, 301 int port, String userDN, char[] pwd, 302 String referralType, String aliasType, boolean useSSL, 303 String cacerts, String clientcerts, 304 char[] caKeystorePwd, char[] clientKeystorePwd) 305 { 306 ConnectionData cData = new ConnectionData(); 307 cData.setURL(host,port); 308 309 cData.baseDN = baseDN; 310 cData.version = version; 311 cData.setURL(host, port); 312 cData.userDN = userDN; 313 cData.pwd = pwd; 314 cData.referralType = referralType; 315 cData.aliasType = aliasType; 316 cData.useSSL = useSSL; 317 cData.cacerts = cacerts; 318 cData.clientcerts = clientcerts; 319 cData.caKeystorePwd = caKeystorePwd; 320 cData.clientKeystorePwd = clientKeystorePwd; 321 cData.tracing = getTracing(); 322 return connect(cData); 323 } 324 325 326 327 337 338 public DataQuery connect(ConnectionData cData) 339 { 340 cData.caKeystoreType = JXplorer.getProperty("keystoreType.cacerts", "JKS"); 341 cData.clientKeystoreType = JXplorer.getProperty("keystoreType.clientcerts", "JKS"); 342 343 DataQuery openCon = new DataConnectionQuery(cData); 344 345 return push(openCon); 346 } 347 348 349 350 354 355 protected void processRequest(DataQuery request) 356 { 357 try 358 { 359 if (request instanceof DataConnectionQuery) 360 openConnection((DataConnectionQuery) request); 361 else 362 super.processRequest(request); 363 } 364 catch (Exception e) 365 { 366 request.setException(e); 367 e.printStackTrace(); 368 } 369 } 370 371 372 373 378 379 protected DataQuery openConnection(DataConnectionQuery request) 380 { 381 disconnect(); 383 ConnectionData cData = request.conData; 384 385 String url = cData.url; 386 387 connectionError = false; 388 389 ctx = null; 391 393 try 394 { 395 dirOps = new CBGraphicsOps(cData); ctx = dirOps.getContext(); 397 398 if (ctx == null) 399 throw new NamingException("unable to open connection: unknown condition, no error returned."); 400 401 405 String base = (request.conData.baseDN==null)?"":request.conData.baseDN; 406 407 if (dirOps.exists(base) == false) 410 cData.baseDN = getActualDN(cData.baseDN); 412 } 414 catch (Exception ne) { log.warning("initial receipt of exception by jndi broker " + ne.getMessage()); 418 ne.printStackTrace(); 419 request.setException(ne); 420 request.setStatus(false); 421 request.finish(); 422 return request; 423 } 424 425 try 426 { 427 schemaOps = new SchemaOps(ctx); 428 } catch (NamingException e) 430 { 431 log.log(Level.WARNING, "unable to init schemaOps Ops ", e); 432 schemaOps = null; 433 } 434 435 if (schemaOps != null && (cData.protocol == ConnectionData.DSML || cData.version > 2)) { 437 try 438 { 439 String binaries = schemaOps.getNewBinaryAttributes(); 440 if (binaries.trim() != "") 441 ctx.addToEnvironment("java.naming.ldap.attributes.binary", binaries); 442 initAttributeNamesHash(); 443 } 444 catch (NamingException e) { 446 log.log(Level.WARNING, "Failed to connect to schemaOps: " + url, e); 447 } 448 } 449 else 450 { 451 log.info("skipped schemaOps stuff : " + cData.protocol); 452 } 453 454 if (cData.protocol.equalsIgnoreCase("dsml")) log.info("Successfully connected to " + url + " using " + cData.protocol + " version 2"); 456 else 457 log.info("Successfully connected to " + url + " using " + cData.protocol + " version " + cData.version); 458 459 request.setStatus(true); request.finish(); 461 return request; 462 } 463 464 465 466 480 public String getActualDN(String dn) 482 { 483 if(true) 484 return dn; 485 486 try 487 { 488 NamingEnumeration en = dirOps.searchBaseEntry(new DN(dn), "objectClass=*",0,0, null); 489 String temp = ""; 490 while (en.hasMoreElements()) 491 { 492 temp = (en.nextElement()).toString(); 493 temp = temp.substring(0, temp.indexOf(":")); 494 } 495 return temp; 496 } 497 catch(Exception e) 498 { 499 return dn; 500 } 501 } 502 503 504 505 510 511 protected void initAttributeNamesHash() 514 { 515 attributeNames = new Hashtable(100); 516 517 521 try 522 { 523 Attribute attDefs = schemaOps.getAttributeTypes(); 524 if (attDefs==null) 525 { 526 log.warning("unable to read schema attributes in JNDIBroker:initAttributeNamesHash"); 527 return; 528 } 529 StringTokenizer tokenizer; 530 for (int i=0; i<attDefs.size(); i++) 531 { 532 String parseMe = attDefs.get(i).toString(); int namePos = parseMe.indexOf("NAME"); 534 if (namePos == -1) 535 throw new NamingException("unable to parse ldap syntax '" + parseMe + "'"); 536 String oid = parseMe.substring(1, namePos).trim(); 537 String names = ""; 538 if (parseMe.indexOf("SYNTAX")>-1) 539 names = parseMe.substring(parseMe.indexOf("'", namePos), parseMe.indexOf("SYNTAX")-2); 541 tokenizer = new StringTokenizer(names, "'"); 542 while (tokenizer.hasMoreElements()) 543 { 544 String name = tokenizer.nextToken().trim(); 545 if (name.length() > 0) 546 { 547 attributeNames.put(oid, name); 548 } 549 } 550 551 } 552 } 553 catch (NamingException e) 554 { 555 log.warning("unable to parse schemaOps at JndiBroker:initAttributeNamesHash " + e + "\n"); 556 } 557 catch (Exception e2) 558 { 559 log.warning("Unexpected exception parsing schemaOps at JndiBroker:initAttributeNamesHash " + e2 + "\n"); 560 e2.printStackTrace(); 561 } 562 563 } 564 565 566 567 573 574 public String getAttributeDescription(String attributeoid) 575 { 576 if (attributeNames == null) return "(schemaOps not correctly read)"; 577 String attributeName = (String )attributeNames.get(attributeoid); 578 if (attributeName == null) attributeName = "(attribute not listed in schemaOps)"; 579 return attributeName; 580 } 581 582 583 587 588 public int getVersion() 589 { 590 return dirOps.getLdapVersion(); 591 } 592 593 594 595 603 604 public void printContextList(Context C, DN dn, String message) 605 { 606 System.out.println("******* " + message + " ******\nPrinting context '" + dn + "'"); 607 try 608 { 609 NamingEnumeration debug = C.list(dn); 610 while (debug.hasMore()) 611 { 612 System.out.println(((NameClassPair)(debug.next())).getName()); 613 } 614 } 615 catch (NamingException e) 616 { 617 System.out.println("error printing context " + dn + "( " + message + " )" +e); 618 } 619 } 620 621 622 623 627 628 public void disconnect() 629 { 630 attributeNames = null; 631 ctx = null; 632 schemaOps = null; 633 634 if (dirOps == null) 635 return; try 637 { 638 dirOps.close(); } 640 catch (NamingException e) 641 { 642 e.printStackTrace(); } 644 dirOps = null; 645 646 Runtime.getRuntime().gc(); 647 Runtime.getRuntime().runFinalization(); 648 } 649 650 651 652 656 657 public void setLimit(int maxResponses) { limit = maxResponses; } 658 659 660 661 666 667 public void setTimeout(int maxTime) { timeout = maxTime; } 668 669 670 671 677 678 public DXNamingEnumeration unthreadedList(DN searchbase) 679 { 680 SetContextToBrowsingAliases(); 681 682 try 683 { 684 return new DXNamingEnumeration(dirOps.list(searchbase)); 685 } 686 catch (NamingException e) 687 { 688 error("unable to list " + searchbase, e); 689 return new DXNamingEnumeration(); } 691 } 692 693 694 695 704 705 public DXNamingEnumeration unthreadedSearch(DN dn, String filter, int search_level, String [] returnAttributes) 706 { 707 SetContextToSearchingAliases(); 708 709 DXNamingEnumeration ret; 710 711 713 try 714 { 715 if (search_level == SEARCH_BASE_OBJECT) 716 ret = new DXNamingEnumeration(dirOps.searchBaseEntry(dn, filter, limit, timeout, returnAttributes)); 717 else if (search_level == SEARCH_ONE_LEVEL) 718 ret = new DXNamingEnumeration(dirOps.searchOneLevel(dn, filter, limit, timeout, returnAttributes)); 719 else if (search_level == SEARCH_SUB_TREE) 720 ret = new DXNamingEnumeration(dirOps.searchSubTree(dn, filter, limit, timeout, returnAttributes)); 721 else 722 return null; 723 } 724 catch (NamingException e) 725 { 726 error("unable to search " + dn, e); 727 return new DXNamingEnumeration(); 728 } 729 730 SetContextToBrowsingAliases(); 731 732 return ret; 733 } 734 735 736 737 744 745 public synchronized Attributes read(DN dn) 746 { 747 Attributes atts = null; 748 try 749 { 750 atts = dirOps.read(dn); 751 } 752 catch (NamingException e) 753 { 754 error("unable to read " + dn, e); 755 756 } 757 return new DXAttributes(atts); 758 } 759 760 761 762 766 767 public void deleteTree(DN nodeDN) 768 throws NamingException 769 { 770 dirOps.deleteTree(nodeDN); 771 } 772 773 774 775 783 784 public void moveTree(DN oldNodeDN, DN newNodeDN) throws NamingException 786 { 787 dirOps.moveTree(oldNodeDN, newNodeDN); 788 } 789 790 791 792 799 800 public void unthreadedCopy(DN oldNodeDN, DN newNodeDN) throws NamingException 802 { 803 dirOps.copyTree(oldNodeDN, newNodeDN); 804 } 805 806 807 808 813 814 public boolean unthreadedExists(DN checkMe) 815 throws NamingException 816 { 817 return dirOps.exists(checkMe); 818 } 819 820 821 822 825 826 public boolean processQueue() 827 { 828 if (dirOps != null) dirOps.setQuietMode(true); 829 boolean ret = super.processQueue(); 830 831 832 if (ret == false) return false; 840 841 if (dirOps != null) dirOps.setQuietMode(false); 842 return true; 843 } 844 845 846 850 851 public Exception getException() 852 { 853 return dirOps.quietException; 854 } 855 856 857 858 862 863 public void clearException() 864 { 865 dirOps.quietException = null; 866 } 867 868 869 870 874 875 protected DataQuery finish(DataQuery request) 876 { 877 request.setException(dirOps.quietException); request.finish(); 879 return request; 880 } 881 882 883 887 888 public boolean isActive() { return (ctx != null); } 889 890 891 892 896 897 public boolean hasConnectionError() { return ((ctx==null)||(connectionError)); } 898 899 900 901 908 909 public DXEntry unthreadedReadEntry(DN entryDN, String [] returnAttributes) 910 throws NamingException 911 { 912 DXAttributes atts = new DXAttributes(dirOps.read(entryDN, returnAttributes)); 913 return new DXEntry(atts, entryDN); 914 } 915 916 917 918 922 923 public void addEntry(DXEntry newEntry) 924 throws NamingException 925 { 926 if (newEntry.getDN() == null) 928 throw new NamingException("Internal Error: Entry with null DN passed to JNDIBroker addEntry(). Modify Request Cancelled."); 929 930 dirOps.addEntry(newEntry.getDN(), newEntry); 931 } 932 933 934 935 946 947 protected int loadMods(ModificationItem[] mods, NamingEnumeration atts, int TYPE, int index) 948 throws NamingException 949 { 950 while (atts.hasMore()) 951 { 952 Attribute temp = (Attribute)atts.next(); 953 mods[index++] = new ModificationItem(TYPE,temp); 954 } 955 return index; 956 } 957 958 959 960 965 966 public void unthreadedModify(DXEntry oldEntry, DXEntry newEntry) 967 throws NamingException 968 { 969 if (useSpecialWriteAllAttsMode()) doSpecialWriteAllAttsHandling(oldEntry, newEntry); 971 else 972 dirOps.modifyEntry(oldEntry, newEntry); 973 } 974 975 private void doSpecialWriteAllAttsHandling(DXEntry oldEntry, DXEntry newEntry) 976 throws NamingException 977 { 978 if ( (newEntry == null) || (oldEntry == null && newEntry.getStatus() == DXEntry.NEW) ) 980 { 981 dirOps.modifyEntry(oldEntry, newEntry); 982 } 983 984 if (oldEntry.getDN().toString().equals(newEntry.getDN().toString()) == false) 986 { 987 moveTree(oldEntry.getDN(), newEntry.getDN()); 988 } 989 990 if (DXAttributes.attributesEqual(oldEntry,newEntry)) 991 { 992 return; } 994 995 DN nodeDN = newEntry.getDN(); 996 RDN newRDN = nodeDN.getLowestRDN(); 997 998 DXAttributes adds = null; DXAttributes reps = null; DXAttributes dels = null; 1002 try 1003 { 1004 if (hasVerboseObjectClass(newEntry)) reps = Special.getReplacementSet(newRDN, oldEntry, newEntry); 1006 else 1007 reps = new DXAttributes(); 1008 1009 dels = Special.getDeletionSet(newRDN, oldEntry, newEntry); 1010 adds = Special.getAdditionSet(newRDN, oldEntry, newEntry); 1011 1012 log.fine("updateNode: " + nodeDN); 1013 1014 ModificationItem[] mods; 1015 1016 mods = new ModificationItem[dels.size() + reps.size() + adds.size()]; 1017 1018 int modIndex = 0; 1019 modIndex = loadMods(mods, dels.getAll(), DirContext.REMOVE_ATTRIBUTE, modIndex); 1020 modIndex = loadMods(mods, adds.getAll(), DirContext.ADD_ATTRIBUTE, modIndex); 1021 modIndex = loadMods(mods, reps.getAll(), DirContext.REPLACE_ATTRIBUTE, modIndex); 1022 1023 dirOps.modifyAttributes(nodeDN, mods); 1024 } 1025 catch (Exception e) 1026 { 1027 NamingException os390 = new NamingException("SPECIAL OS390 MODE ERROR: Unexpected Error updating node " + oldEntry.getDN() + "! " + e.toString()); 1028 os390.initCause(e); 1029 throw os390; 1030 } 1031 } 1032 1033 1034 1035 1036 1044 1056 1057 protected boolean useSpecialWriteAllAttsMode() 1058 { 1059 1063 return (specialObjectClasses != null); } 1065 1066 1074 1075 protected boolean hasVerboseObjectClass(Attributes atts) 1076 { 1077 if (specialObjectClasses == null) return false; 1079 try 1080 { 1081 Attribute oc; 1082 if (atts instanceof DXAttributes == false) 1083 oc = atts.get("objectClass"); else oc = ((DXAttributes)atts).getAllObjectClasses(); 1086 1087 NamingEnumeration ocs = oc.getAll(); 1088 while (ocs.hasMore()) 1089 { 1090 Object test = ocs.next(); 1091 if (specialObjectClasses.contains(test)) 1092 { 1093 return true; 1094 } 1095 } 1096 return false; 1097 } 1098 catch (NamingException e) 1099 { 1100 log.warning("error getting object classes in jndibroker " + e); 1101 return false; 1102 } 1103 } 1104 1105 1106 1107 1116 1117 public boolean isModifiable() 1118 { 1119 return true; 1120 } 1121 1122 1123 1124 1126 1127 1128 1129 1133 1134 public String getSchemaRoot() 1135 { 1136 if (ctx==null) 1137 return ""; 1138 1139 String fnord = ""; 1140 try 1142 { 1143 fnord = ctx.getSchema("").toString(); 1144 return fnord; 1145 } 1146 catch (NamingException e) 1147 { log.warning("error reading schemaOps\n" + e);} 1148 1149 1150 return "cn=schemaOps"; } 1152 1153 1154 1155 1162 public ArrayList unthreadedGetRecOCs(DN dn) 1163 { 1164 return schemaOps.getRecommendedObjectClasses(dn.toString()); 1165 } 1166 1167 1172 1173 public void modifyAttributes(DN dn, ModificationItem[] mods) 1174 throws AttributeModificationException, NamingException 1175 { 1176 if (ctx == null) 1177 throw new NamingException("no directory context to work with"); 1178 1179 ctx.modifyAttributes(dn, mods); 1180 } 1181 1182 1188 1189 public void error(String msg, Exception e) 1190 { 1191 if (quietMode == false) 1192 { 1193 CBUtility.error(msg, e); 1194 } 1195 else 1196 { 1197 errorWhileQuietFlag = true; 1198 log.warning(msg + "\n (details) " + e.toString()); 1199 } 1200 } 1201 1202 1203 1204 1207 1208 public CBGraphicsOps getDirOp() { return dirOps; } 1209 1210 1211 1212 1215 1216 public DirContext getDirContext() { return (dirOps==null)?null:dirOps.getContext(); } 1217 1218 1219 1220 1228 1229 public DN[] readFallbackRoot() 1230 { 1231 log.finer("reading fallback root DN..."); 1232 try 1233 { 1234 Attributes a = unthreadedReadEntry(new DN(""), new String [] {"namingContexts"}); 1235 1236 if (a==null) return null; 1238 log.finer("...Got root DSE data..."); 1239 1240 1241 1243 Attribute rootDNC; 1244 rootDNC = a.get("namingcontexts"); 1245 if (rootDNC == null) 1246 rootDNC = a.get("namingContexts"); 1248 if (rootDNC == null || rootDNC.size()==0) return new DN[] {new DN()}; 1250 if (rootDNC.size() == 1) 1251 { 1252 String rootDNString = rootDNC.get().toString(); 1253 1254 log.info("read fallback root DN as: " + rootDNString); 1255 return new DN[] {new DN(rootDNString)}; 1256 } 1257 1258 1260 DN contexts[] = new DN[rootDNC.size()]; 1261 1262 int index=0; 1263 Enumeration roots = rootDNC.getAll(); 1264 while (roots.hasMoreElements()) 1265 { 1266 String dn = roots.nextElement().toString(); 1267 contexts[index++] = new DN(dn); 1268 } 1269 return contexts; 1270 } 1271 catch (NamingException e) 1272 { 1273 log.log(Level.WARNING, "Error reading fallback root: ",e); 1274 return null; 1275 } 1276 } 1277 1278 1279 1280 1285 1286 public void SetContextToSearchingAliases() 1287 { 1288 1289 try 1290 { 1291 if (ctx != null) ctx.addToEnvironment("java.naming.ldap.derefAliases", JXplorer.getProperty("option.ldap.searchAliasBehaviour")); 1292 } 1293 catch( Exception e) 1294 { 1295 log.warning("Unexpected exception setting search alias handling behaviour in context to " + JXplorer.getProperty("option.ldap.searchAliasBehaviour") + "\n " + e); 1296 } 1297 } 1298 1299 1300 1301 1306 1307 public void SetContextToBrowsingAliases() 1308 { 1309 try 1310 { 1311 if (ctx != null) ctx.addToEnvironment("java.naming.ldap.derefAliases", JXplorer.getProperty("option.ldap.browseAliasBehaviour")); 1312 } 1313 catch( Exception e) 1314 { 1315 log.warning("Unexpected exception setting browse alias handling behaviour in context to " + JXplorer.getProperty("option.ldap.browseAliasBehaviour") + "\n " + e); 1316 } 1317 } 1318 1319 1323 public SchemaOps getSchemaOps() 1324 { 1325 return schemaOps; 1326 } 1327 1328} | Popular Tags |