001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: DomainComponentTree.java,v 1.5 2009/01/28 05:34:51 ww203982 Exp $ 026 * 027 */ 028 029package com.iplanet.ums.dctree; 030 031import java.util.Hashtable; 032import java.util.StringTokenizer; 033 034import com.sun.identity.shared.ldap.LDAPDN; 035 036import com.iplanet.services.util.I18n; 037import com.iplanet.sso.SSOException; 038import com.iplanet.sso.SSOToken; 039import com.iplanet.sso.SSOTokenManager; 040import com.iplanet.ums.EntryNotFoundException; 041import com.iplanet.ums.Guid; 042import com.iplanet.ums.IUMSConstants; 043import com.iplanet.ums.PersistentObject; 044import com.iplanet.ums.SearchResults; 045import com.iplanet.ums.UMSException; 046import com.iplanet.ums.UMSObject; 047import com.iplanet.ums.User; 048 049/** 050 * Represents the domain component index tree (dctree). A domain component tree 051 * is used to represent virtual domains as used in DNS. DCTree composes of a 052 * hiearchical tree of domain components (dc) and each dc node may/maynot 053 * associate with a organizational DIT (convergence tree as noted in nortel 054 * spec). Sample of a dctree that starts at dcroot of "o=internet" will look 055 * like this 056 * <p> 057 * 058 * <pre> 059 * o=internet 060 * | 061 * ------------------------------ 062 * | | | 063 * dc=com dc=net dc=edu 064 * | 065 * --------- 066 * | | 067 * dc=sun dc=iplanet 068 * | | 069 * dc=eng dc=red 070 * </pre> 071 * 072 * DomainComponentTree allows the user to create a dc tree capturing virtual 073 * domain names in a network (hosted or enterprise) environment with each low 074 * level dc node being mapped to an organizational DIT. 075 * 076 * @see DomainComponent 077 * @supported.api 078 */ 079public class DomainComponentTree { 080 081 private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 082 083 /** 084 * Default constructor 085 */ 086 public DomainComponentTree() { 087 } 088 089 /** 090 * Constructs a <code>DomainComponentTree</code> with an authenticated 091 * prinicipal and an identification of the root of the dc index tree. 092 * 093 * @param token Single sign on token of authenticated principal with 094 * priviledge for accessing the domain component index tree (dctree). 095 * @param dcRoot Identification of root, a DN, of the dc tree such as 096 * <code>o=internet</code>. 097 * @throws InvalidDCRootException if invalid root specification. 098 * @throws UMSException if other read error occurred. 099 * @supported.api 100 */ 101 public DomainComponentTree(SSOToken token, Guid dcRoot) 102 throws InvalidDCRootException, UMSException { 103 if (token == null) 104 throw new IllegalArgumentException(i18n 105 .getString(IUMSConstants.NULL_TOKEN)); 106 try { 107 SSOTokenManager.getInstance().validateToken(token); 108 } catch (SSOException se) { 109 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 110 se); 111 } 112 113 setSSOToken(token); 114 115 try { 116 setDCRoot(dcRoot); 117 } catch (EntryNotFoundException e) { 118 throw new InvalidDCRootException(dcRoot.getDn(), e.getRootCause()); 119 } 120 121 } 122 123 /** 124 * Sets the authenticated principal used for access to directory server 125 * 126 * @param ssotoken 127 * SSO token for authenticated user 128 */ 129 void setSSOToken(SSOToken token) throws UMSException { 130 try { 131 SSOTokenManager.getInstance().validateToken(token); 132 } catch (SSOException se) { 133 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 134 se); 135 } 136 m_token = token; 137 } 138 139 /** 140 * Gets the authenticated Principal used to contruct the dctree instance 141 * 142 * @return authenticated principal that is associated with dctree 143 * construction 144 * 145 * java.security.Principal getPrincipal() { if (token) return 146 * token.getPrincipal(); else return null; } 147 */ 148 149 /** 150 * Gets the SSOToken used to contruct the dctree instance 151 * 152 * @return SSOToken that is associated with dctree construction 153 */ 154 SSOToken getSSOToken() { 155 return m_token; 156 } 157 158 /** 159 * Sets the root of the domain component tree (dc 160 * tree). Needs an established authenticated principal before setting 161 * dcroot. 162 * 163 * @param root 164 * Identification of the root of the tree such as o=internet 165 * @supported.api 166 */ 167 public void setDCRoot(Guid root) throws UMSException { 168 SSOToken token = getSSOToken(); 169 try { 170 SSOTokenManager.getInstance().validateToken(token); 171 } catch (SSOException se) { 172 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 173 se); 174 } 175 176 if (token != null) { 177 m_dcRoot = UMSObject.getObject(token, root); 178 } 179 } 180 181 /** 182 * Gets the root of the domain component tree (dc 183 * tree) 184 * 185 * @return PersistentObject representing the dctree root in the dctree DIT 186 * @supported.api 187 */ 188 public PersistentObject getDCRoot() { 189 return m_dcRoot; 190 } 191 192 /** 193 * Add a virtual domain into the domain component 194 * tree. 195 * 196 * @param domain 197 * Fully qualified domain name 198 * @return Domain Componet entry just added to the dctree 199 * @throws InvalidDCRootException 200 * if dcroot is not defined 201 * @throws UMSException 202 * for write problem in adding domain to dctree 203 * @supported.api 204 */ 205 public DomainComponent addDomain(String domain) throws UMSException { 206 if (domain == null || domain.length() == 0) { 207 throw new IllegalArgumentException(); 208 } 209 210 if (m_dcRoot == null) { 211 throw new InvalidDCRootException(); 212 } 213 214 StringTokenizer st = new StringTokenizer(domain, "."); 215 216 int nDoms = st.countTokens(); 217 String[] doms = new String[nDoms]; 218 219 int i = 0; 220 while (st.hasMoreElements()) { 221 doms[i++] = st.nextToken(); 222 } 223 224 PersistentObject parent = UMSObject.getObject(getSSOToken(), m_dcRoot 225 .getGuid()); 226 227 // Going from right to left on the virtual domain name 228 // to go through all the domain components (dc). Make sure that 229 // all dc entries are created in the dctree 230 // e.g. adding a domain for eng.sun.com with dcRoot being o=internet 231 // will yield 232 // <pre> 233 // o=internet (assmumed to exist) 234 // dc=com,o=internet (created) 235 // dc=sun,dc=com,o=ineternet (created) 236 // dc=eng,dc=sun,dc=com,o=internet (created) 237 // </pre> 238 // in the domain component tree 239 // 240 DomainComponent dc = null; 241 for (i = 0; i < nDoms; i++) { 242 243 SearchResults results = parent.getChildren("dc=" 244 + doms[nDoms - i - 1], null); 245 246 try { 247 dc = (DomainComponent) results.assertOneEntry(); 248 } catch (EntryNotFoundException e) { 249 dc = new DomainComponent(getSSOToken(), doms[nDoms - i - 1]); 250 parent.addChild(dc); 251 } 252 253 parent = UMSObject.getObject(getSSOToken(), dc.getGuid()); 254 } 255 256 return dc; 257 } 258 259 /** 260 * Remove a virtual domain in the dctree 261 * 262 * @param domain 263 * Virtual domain name to be removed 264 * @throws UMSException 265 * upon failure to remove the corresponding dc entry in the 266 * dctree 267 * 268 * @supported.api 269 */ 270 public void removeDomain(String domain) throws UMSException { 271 if (m_dcRoot == null) 272 return; 273 274 DomainComponent dc = getDomainComponent(domain); 275 m_dcRoot.removeChild(dc); 276 } 277 278 /** 279 * Set the domain mapping so that the dc entry maps to 280 * an organization in the the organization DIT hosting user data (the 281 * convergence tree in Nortel spec) 282 * 283 * @param domain 284 * Fully qualified domain name 285 * @param org 286 * Organization entry to be mapped from dctree to organization 287 * DIT (the convergence tree in nortel spec) 288 * @throws DomainNotFoundException 289 * if domain id not defined 290 * @throws UMSException 291 * upon write failure 292 * @supported.api 293 */ 294 public void setDomainMapping(String domain, PersistentObject org) 295 throws UMSException { 296 setDomainMapping(domain, org.getGuid()); 297 } 298 299 /** 300 * Set the domain mapping so that the dc entry maps to 301 * an organization in the convergence tree. 302 * 303 * @param domain Virtual domain name. 304 * @param orgGuid Identifiication of Organization entry to be mapped from 305 * dctree to organization DIT (the convergence tree in nortel spec). 306 * @throws UMSException if write failed. 307 * @supported.api 308 */ 309 public void setDomainMapping(String domain, Guid orgGuid) 310 throws UMSException { 311 DomainComponent dc = getDomainComponent(domain); 312 dc.setAssociatedOrganization(orgGuid); 313 } 314 315 /** 316 * Sets the domain status for a given virtual domain 317 * 318 * @param domain 319 * Virtual domain name 320 * @param status 321 * Domain status to be set 322 * @throws DomainNotFoundException 323 * if domain is not found in dctree 324 * @throws UMSException 325 * upon write failure 326 * 327 * @supported.api 328 */ 329 public void setDomainStatus(String domain, String status) 330 throws DomainNotFoundException, UMSException { 331 DomainComponent dc = getDomainComponent(domain); 332 dc.setDomainStatus(status); 333 } 334 335 /** 336 * Gets the domain status of a given virtual domain 337 * 338 * @param domain 339 * Virtual domain name 340 * @return Domain status for the given domain 341 * @throws DomainNotFoundException 342 * if domain not found in dctree 343 * @throws UMSException 344 * upon read failure 345 * @supported.api 346 */ 347 public String getDomainStatus(String domain) 348 throws DomainNotFoundException, UMSException { 349 DomainComponent dc = getDomainComponent(domain); 350 return dc.getDomainStatus(); 351 } 352 353 /** 354 * Given a fully qualified domain name, maps it to the 355 * corresponding DN in the DCtree 356 * 357 * @param domain 358 * Fully qualified domain name 359 * @return String representation of the Distinguished Name in the DC Tree 360 * @supported.api 361 */ 362 public String mapDomainToDN(String domain) { 363 StringTokenizer st = new StringTokenizer(domain, "."); 364 String dn = new String(); 365 366 while (st.hasMoreElements()) { 367 dn = dn + "dc=" + st.nextToken() + ","; 368 } 369 370 dn = dn + getDCRoot().getDN(); 371 return dn; 372 } 373 374 /** 375 * Given a virtual domain name such as 376 * "javasoft.sun.com", returns the domain component entry in the dc index 377 * tree. This entry lives under dc index tree and one can use the dc entry 378 * to get to the organization assoicated with the dc tree 379 * 380 * @param domain 381 * Virtual domain name such as "javasoft.sun.com" 382 * @return Domain componet entry representing the virtual domain in the 383 * domain component tree 384 * @throws DomainNotFoundException 385 * if given domain is not found in the dctree 386 * @throws UMSException 387 * upon read error 388 * @supported.api 389 */ 390 public DomainComponent getDomainComponent(String domain) 391 throws DomainNotFoundException, UMSException { 392 393 String dn = mapDomainToDN(domain); 394 395 try { 396 DomainComponent dc = (DomainComponent) UMSObject.getObject( 397 getSSOToken(), new Guid(dn)); 398 dc.setSSOToken(getSSOToken()); 399 return dc; 400 } catch (EntryNotFoundException e) { 401 throw new DomainNotFoundException(domain, e.getRootCause()); 402 } 403 404 } 405 406 /** 407 * Given a virtual domain name such as 408 * "javasoft.sun.com", return the organization, organizationalunit or any 409 * DIT entry that is assoicated from the domain compoent tree (dctree) to 410 * the customer oranization DIT (the convergence tree as outlined in nortel 411 * spec) 412 * 413 * @param domain 414 * Fully qualified virtual domain name 415 * @return Entry referred in the dc tree. 416 * @throws DomainNotFoundException 417 * if domain is not found 418 * @throws UMSException 419 * for reading problem in instantiating the mapped organization 420 * @supported.api 421 */ 422 public PersistentObject getOrganization(String domain) 423 throws DomainNotFoundException, UMSException { 424 DomainComponent dc = getDomainComponent(domain); 425 return dc.getOrganization(); 426 } 427 428 /** 429 * Given a uid for a user, lookup the user under a 430 * specified virtual domain name. For example, 431 * 432 * <pre> 433 * DomainComponentTree dctree = new DomainComponentTree(ctx, 434 * "red.iplanet.com"); 435 * 436 * User user = dctree.getUser("hman", 437 * "red.iplanet.com"); 438 * </pre> 439 * 440 * @param uid 441 * User id for the entry to be searched 442 * @param domain 443 * Fully qualified domain name such as "red.iplanet.com" 444 * @return User object found 445 * @throws DomainNotFoundException 446 * if domain is not found 447 * @throws UMSException 448 * upon failure in instantiating the user object 449 * @supported.api 450 */ 451 public User getUser(String uid, String domain) 452 throws DomainNotFoundException, UMSException { 453 return getUser("uid", uid, domain); 454 } 455 456 /** 457 * Given identification of a user with a naming 458 * attribute and value, lookup the user under a virtual domain specified. 459 * For example, 460 * 461 * <pre> 462 * DomainComponentTree dctree = new DomainComponentTree(ctx, 463 * "red.iplanet.com"); 464 * 465 * User user = dctree.getUser("cn", "Hin Man", 466 * "red.iplanet.com"); 467 * </pre> 468 * 469 * @param namingAttribute 470 * Naming attribute for the user object such as "uid" or "mail". 471 * The naming attribute has to provide a unique identifier for 472 * the user. 473 * @param value 474 * attribute value for the naming attribute 475 * @param domain 476 * Fully qualified domain name such as "red.iplanet.com" 477 * @return User object if found 478 * @throws DomainNotFoundException 479 * if domain is not found 480 * @throws UMSException 481 * upon failure in instantiating the user object 482 * @supported.api 483 */ 484 public User getUser(String namingAttribute, String value, String domain) 485 throws DomainNotFoundException, UMSException { 486 PersistentObject orgEntry = getOrganization(domain); 487 488 SearchResults result = orgEntry.search(namingAttribute + "=" + value, 489 null); 490 491 return (User) result.assertOneEntry(); 492 } 493 494 /** 495 * Given a domain componet in a dctree, maps it to a 496 * virtual domain name 497 * 498 * @param dc 499 * A domain component that lives in the dctree 500 * @return Fully qualified domain name 501 * @supported.api 502 */ 503 public String mapDCToDomainName(DomainComponent dc) { 504 505 if (m_dcRoot == null) 506 return null; 507 508 String rootDN = LDAPDN.normalize(m_dcRoot.getDN()); 509 String dcDN = LDAPDN.normalize(dc.getDN()); 510 511 // Skip the dcRoot part of the DN for the given domain component. 512 // Find the position of the rootDN in dcDN 513 // 514 int end = dcDN.indexOf("," + rootDN); 515 516 // TODO: Kind of kludgy, need to revisit 517 // 518 dcDN = dcDN.substring(0, end); 519 520 String[] doms = LDAPDN.explodeDN(dcDN, true); 521 String domainName = doms[0]; 522 523 // Compose the fully qualified domain name with the "." character 524 // 525 for (int i = 1; i < doms.length; i++) { 526 domainName = domainName + "." + doms[i]; 527 } 528 529 return domainName; 530 } 531 532 /** 533 * Get all virtual domains present in the dctree. 534 * Construct a hashtable of the found domain names and their associated 535 * organization in the customer organizational DIT (the convergence tree) 536 * <p> 537 * 538 * This function can be used as a cache function for the complete DCTree. 539 * The returning hastable provides all the virtual domain name as keys that 540 * maps to organization mapping linked in the domain component dc nodes 541 * <p> 542 * 543 * @return Hashtable of domain names and associated organizations. Each 544 * domain name is associated with one organization but muliple 545 * domain names can map to the same organization in the customer 546 * DIT. 547 * @throws UMSException 548 * upon failure in searching all mapped domains 549 * @supported.api 550 */ 551 public Hashtable getChildDomainIDs() throws UMSException { 552 553 if (m_dcRoot == null) { 554 return null; 555 } 556 557 // Search in DCTree that have a link to a mapped organization 558 // 559 SearchResults results = m_dcRoot.search( 560 "(&(objectclass=inetDomain)(inetDomainBaseDN=*))", null); 561 562 Hashtable domains = new Hashtable(); 563 564 // For each domain found, recapture the domain name from the DC hiearchy 565 // such as 566 // dc=red,dc=iplanet,dc=com -> red.iplanet.com 567 // dc=eng,dc=sun,dc=com -> eng.sun.com 568 // and put in the hashtable the corresponding organization mapped from 569 // dctree to customer organization DIT (the convergence tree in nortel 570 // spec) 571 // 572 while (results.hasMoreElements()) { 573 DomainComponent dc = (DomainComponent) results.next(); 574 String domainName = mapDCToDomainName(dc); 575 domains.put(domainName, dc.getAssociatedOrganizationGuid().getDn()); 576 } 577 578 return domains; 579 } 580 581 private PersistentObject m_dcRoot = null; 582 583 private SSOToken m_token = null; 584}