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