/** * Build a list of realm that can be traversed to obtain credentials from the initiating realm * cRealm for a service in the target realm sRealm. * * @param cRealm the initiating realm * @param sRealm the target realm, not the same as cRealm * @returns array of realms including cRealm as the first element */ private static String[] parseHierarchy(String cRealm, String sRealm) { String[] cComponents = cRealm.split("\\."); String[] sComponents = sRealm.split("\\."); int cPos = cComponents.length; int sPos = sComponents.length; boolean hasCommon = false; for (sPos--, cPos--; sPos >= 0 && cPos >= 0 && sComponents[sPos].equals(cComponents[cPos]); sPos--, cPos--) { hasCommon = true; } // For those with common components: // length pos // SITES1.SALES.EXAMPLE.COM 4 1 // EVERYWHERE.EXAMPLE.COM 3 0 // For those without common components: // length pos // DEVEL.EXAMPLE.COM 3 2 // PROD.EXAMPLE.ORG 3 2 LinkedList<String> path = new LinkedList<>(); // Un-common ones for client side for (int i = 0; i <= cPos; i++) { path.addLast(subStringFrom(cComponents, i)); } // Common one if (hasCommon) { path.addLast(subStringFrom(cComponents, cPos + 1)); } // Un-common ones for server side for (int i = sPos; i >= 0; i--) { path.addLast(subStringFrom(sComponents, i)); } // Remove sRealm from path. Note that it might be added at last loop // or as a common component, if sRealm is a parent of cRealm path.removeLast(); return path.toArray(new String[path.size()]); }
/** * Parses the [capaths] stanza of the configuration file for a list of realms to traverse to * obtain credentials from the initiating realm cRealm to the target realm sRealm. * * <p>For a given client realm C there is a tag C in [capaths] whose subtag S has a value which is * a (possibly partial) path from C to S. When the path is partial, it contains only the tail of * the full path. Values of other subtags will be used to build the full path. The value "." means * a direct path from C to S. If realm S does not appear as a subtag, there is no path defined * here. * * <p>The implementation ignores all values which equals to C or S, or a "." in multiple values, * or any duplicated realm names. * * <p>When a path value has more than two realms, they can be specified with multiple key-value * pairs each having a single value, but the order must not change. * * <p>For example: * * <p>[capaths] TIVOLI.COM = { IBM.COM = IBM_LDAPCENTRAL.COM MOONLITE.ORG IBM_LDAPCENTRAL.COM = * LDAPCENTRAL.NET LDAPCENTRAL.NET = . } * * <p>TIVOLI.COM has a direct path to LDAPCENTRAL.NET, which has a direct path to * IBM_LDAPCENTRAL.COM. It also has a partial path to IBM.COM being "IBM_LDAPCENTRAL.COM * MOONLITE.ORG". Merging these info together, a full path from TIVOLI.COM to IBM.COM will be * * <p>TIVOLI.COM -> LDAPCENTRAL.NET -> IBM_LDAPCENTRAL.COM -> IBM_LDAPCENTRAL.COM -> MOONLITE.ORG * * <p>Please note the sRealm IBM.COM does not appear in the path. * * @param cRealm the initiating realm * @param sRealm the target realm, not the same as cRealm * @returns array of realms including at least cRealm as the first element * @throws KrbException if the config does not contain a sub-stanza for cRealm in [capaths] or the * sub-stanza does not contain sRealm as a tag */ private static String[] parseCapaths(String cRealm, String sRealm) throws KrbException { // This line could throw a KrbException Config cfg = Config.getInstance(); if (!cfg.exists("capaths", cRealm, sRealm)) { throw new KrbException("No conf"); } LinkedList<String> path = new LinkedList<>(); String head = sRealm; while (true) { String value = cfg.getAll("capaths", cRealm, head); if (value == null) { break; } String[] more = value.split("\\s+"); boolean changed = false; for (int i = more.length - 1; i >= 0; i--) { if (path.contains(more[i]) || more[i].equals(".") || more[i].equals(cRealm) || more[i].equals(sRealm) || more[i].equals(head)) { // Ignore invalid values continue; } changed = true; path.addFirst(more[i]); } if (!changed) break; head = path.getFirst(); } path.addFirst(cRealm); return path.toArray(new String[path.size()]); }