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: COSManager.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.cos; 031 032import com.iplanet.services.ldap.Attr; 033import com.iplanet.services.ldap.AttrSet; 034import com.iplanet.services.util.I18n; 035import com.iplanet.sso.SSOException; 036import com.iplanet.sso.SSOToken; 037import com.iplanet.sso.SSOTokenManager; 038import com.iplanet.ums.Guid; 039import com.iplanet.ums.IUMSConstants; 040import com.iplanet.ums.PersistentObject; 041import com.iplanet.ums.SchemaManager; 042import com.iplanet.ums.SearchResults; 043import com.iplanet.ums.UMSException; 044import com.iplanet.ums.UMSObject; 045import java.security.Principal; 046import java.util.AbstractCollection; 047import java.util.ArrayList; 048import java.util.Arrays; 049import java.util.Collection; 050import java.util.Enumeration; 051import java.util.HashSet; 052import java.util.StringTokenizer; 053import org.forgerock.opendj.ldap.DN; 054import org.forgerock.opendj.ldap.LdapException; 055import org.forgerock.opendj.ldap.Modification; 056import org.forgerock.opendj.ldap.ModificationType; 057import org.forgerock.opendj.ldap.ResultCode; 058import org.forgerock.opendj.ldap.SearchScope; 059 060/** 061 * This class has the responsibility of adding, removing and replacing COS 062 * definitions. It also provides search capabilities for COS definitions. 063 * @supported.api 064 */ 065public class COSManager { 066 067 /** 068 * This constructor sets the parent Directory entry which identifies the 069 * location of COS definitions which will be managed. It also gets an 070 * instance of a SchemaManager which will be used to update schema entries 071 * for COS assignments. 072 * 073 * @param token Authenticated principal's single sign on token. 074 * @param guid The unique identifier specifying where COS definitions will 075 * be managed. 076 * @throws UMSException if the token authentication fails, or if 077 * the guid for the parent entry is not valid. 078 */ 079 protected COSManager(SSOToken token, Guid guid) throws UMSException { 080 try { 081 SSOTokenManager.getInstance().validateToken(token); 082 } catch (SSOException se) { 083 throw new UMSException(i18n.getString(IUMSConstants.INVALID_TOKEN), 084 se); 085 } 086 _parentObject = UMSObject.getObject(token, guid); 087 try { 088 _schemaManager = SchemaManager.getSchemaManager(token 089 .getPrincipal()); 090 } catch (SSOException se) { 091 throw new UMSException("Bad Authentication Token " 092 + se.getMessage()); 093 } 094 } 095 096 /** 097 * This constructor sets the parent Directory entry which identifies the 098 * location of COS definitions which will be managed. It also gets an 099 * instance of a SchemaManager which will be used to update schema entries 100 * for COS assignments. 101 * 102 * @param principal 103 * Authenticated principal 104 * @param guid 105 * The unique identifier specifying where COS definitions will be 106 * managed. 107 * 108 * @throws UMSException 109 * The exception thrown if there is a problem determining the 110 * parent entry, or getting the SchemaManager instance. 111 */ 112 protected COSManager(Principal principal, Guid guid) throws UMSException { 113 _parentObject = UMSObject.getObject(principal, guid); 114 _schemaManager = SchemaManager.getSchemaManager(principal); 115 } 116 117 /** 118 * This method returns an instance of a COS Manager. 119 * 120 * @param token Authenticated principal's single sign on token. 121 * @param guid COS definitions will be managed under the level identified by 122 * this guid. 123 * @throws UMSException 124 * The exception thrown from the COSManager constructor. 125 * @supported.api 126 */ 127 public static COSManager getCOSManager(SSOToken token, Guid guid) 128 throws UMSException { 129 return new COSManager(token, guid); 130 } 131 132 /** 133 * This method returns an instance of a COS Manager. 134 * 135 * @param principal Authenticated principal. 136 * @param guid COS definitions will be managed under the level identified by 137 * this guid. 138 * @throws UMSException 139 * The exception thrown from the data layer. 140 */ 141 public static COSManager getCOSManager(Principal principal, Guid guid) 142 throws UMSException { 143 return new COSManager(principal, guid); 144 } 145 146 /** 147 * This method adds a COS definition to the persistent store. The definition 148 * is added under the specified "guid" parameter. 149 * 150 * @param cosDef 151 * The COS definition to be added. 152 * 153 * @throws UMSException 154 * The exception thrown from the data layer. 155 * @supported.api 156 */ 157 public void addDefinition(ICOSDefinition cosDef) throws UMSException { 158 if (!(cosDef instanceof DirectCOSDefinition)) { 159 String msg = i18n.getString(IUMSConstants.INVALID_COSDEFINITION); 160 throw new UMSException(msg); 161 } 162 String[] cosAttributes = cosDef.getCOSAttributes(); 163 AbstractCollection aList = (AbstractCollection) Arrays 164 .asList(ICOSDefinition.qualifiers); 165 for (int i = 0; i < cosAttributes.length; i++) { 166 String cosAttribute = null; 167 String qualifier = null; 168 StringTokenizer st = new StringTokenizer(cosAttributes[i]); 169 if (st.hasMoreTokens()) { 170 cosAttribute = st.nextToken(); 171 } 172 if (cosAttribute == null) { 173 String msg = i18n.getString( 174 IUMSConstants.INVALID_COS_ATTRIBUTE_QUALIFIER); 175 throw new UMSException(msg); 176 } 177 if (st.hasMoreTokens()) 178 qualifier = st.nextToken(); 179 if (qualifier == null) { 180 qualifier = ICOSDefinition.qualifiers[ICOSDefinition.DEFAULT]; 181 cosDef.removeCOSAttribute(cosAttribute); 182 cosDef.addCOSAttribute(cosAttribute, ICOSDefinition.DEFAULT); 183 } 184 if (!aList.contains(qualifier)) { 185 String msg = i18n.getString( 186 IUMSConstants.INVALID_COS_ATTRIBUTE_QUALIFIER); 187 throw new UMSException(msg); 188 } 189 } 190 PersistentObject po = (PersistentObject) cosDef; 191 _parentObject.addChild(po); 192 } 193 194 /** 195 * Removes the COS definition. 196 * 197 * @param name 198 * The name of the definition to be removed. 199 * 200 * @throws UMSException 201 * The exception thrown from the data layer. 202 * @supported.api 203 */ 204 public void removeDefinition(String name) throws UMSException { 205 Guid guid = new Guid(ICOSDefinition.DEFAULT_NAMING_ATTR + "=" + name 206 + "," + _parentObject.getGuid().getDn()); 207 _parentObject.removeChild(guid); 208 } 209 210 /** 211 * Updates the contents of a COS definition with the new contents. The COS 212 * definition must already exist in the persistent layer, before its 213 * contents can be replaced. 214 * 215 * @param cosDef 216 * The COS definition containing new contents, which will replace 217 * the same definition in the persistent layer. 218 * 219 * @throws UMSException 220 * The exception thrown from the data layer. 221 * @supported.api 222 */ 223 public void updateDefinition(ICOSDefinition cosDef) throws UMSException { 224 PersistentObject pObject = (PersistentObject) cosDef; 225 if (pObject.getGuid() == null) { 226 String msg = i18n 227 .getString(IUMSConstants.REPLACE_DEFINITION_NOT_PERSISTENT); 228 throw new UMSException(msg); 229 } 230 pObject.save(); 231 } 232 233 /** 234 * Returns COS definition given the name. 235 * 236 * @param name Name of the COS definition. 237 * @return A COS definition with the specified name. 238 * @throws UMSException if exception occurred at the data layer. 239 * @throws COSNotFoundException if the COS object is not found. 240 * @supported.api 241 */ 242 public ICOSDefinition getDefinition(String name) throws UMSException, 243 COSNotFoundException { 244 ICOSDefinition cosDef = null; 245 SearchResults sr = _parentObject.getChildren( 246 ICOSDefinition.COSSUPERDEF_NAME_SEARCH + name + ")", 247 DEF_ATTRIBUTE_NAMES, null); 248 while (sr.hasMoreElements()) { 249 cosDef = (ICOSDefinition) sr.next(); 250 if (cosDef.getName().equals(name)) { 251 break; 252 } else { 253 cosDef = null; 254 } 255 } 256 if (cosDef == null) { 257 String msg = i18n.getString(IUMSConstants.COS_DEFINITION_NOT_FOUND); 258 throw new COSNotFoundException(msg); 259 } 260 sr.abandon(); 261 return cosDef; 262 } 263 264 /** 265 * Retrieves all COS definitions for the current organization. This 266 * COSManager instance applies to an organization. 267 * 268 * @return A collection of COS definition objects. 269 * 270 * @throws UMSException 271 * The exception thrown from the data layer. 272 * @supported.api 273 */ 274 public Collection getDefinitions() throws UMSException { 275 Collection cosDefinitions = new ArrayList(); 276 SearchResults sr = _parentObject.search( 277 ICOSDefinition.COSSUPERDEF_SEARCH, DEF_ATTRIBUTE_NAMES, null); 278 while (sr.hasMoreElements()) { 279 cosDefinitions.add(sr.next()); 280 } 281 return cosDefinitions; 282 } 283 284 /** 285 * Assigns a COS (as defined by a COS definition) to the persistent object. 286 * The COS target persistent object could be a user, group, organization, 287 * organizationalunit, etc. The COS target object must be persistent before 288 * this method can be used. 289 * 290 * @param pObject 291 * The COS target persistent object. 292 * @param cosDef 293 * A COS definition. 294 * @param cosTemplate 295 * A COS template. This only applies for COS and Indirect COS 296 * definitions. For pointer COS definitions, this parameter can 297 * be null. 298 * 299 * @throws UMSException 300 * If a data layer exception occurs. 301 * @supported.api 302 */ 303 public void assignCOSDef(PersistentObject pObject, ICOSDefinition cosDef, 304 COSTemplate cosTemplate) throws UMSException { 305 if (pObject == null || cosDef == null) { 306 String msg = i18n 307 .getString(IUMSConstants.COS_DEF_OR_TARGET_OBJECT_NULL); 308 throw new UMSException(msg); 309 } 310 311 // Do validation.... 312 // 313 if (pObject.getGuid() == null) { 314 String msg = i18n 315 .getString(IUMSConstants.COS_TARGET_OBJECT_NOT_PERSISTENT); 316 throw new UMSException(msg); 317 } 318 319 if (!(cosDef instanceof DirectCOSDefinition)) { 320 String msg = i18n.getString(IUMSConstants.INVALID_COSDEFINITION); 321 throw new UMSException(msg); 322 } 323 324 if (cosDef instanceof DirectCOSDefinition) { 325 assignDirectCOSDef(pObject, (DirectCOSDefinition) cosDef, 326 cosTemplate, _schemaManager); 327 } 328 } 329 330 /** 331 * Removes COS assignment from the persistent object. The COS target 332 * persistent object could be a user, group, organization, 333 * organizationalunit, etc. The COS target object must be persistent before 334 * this method can be used. 335 * 336 * @param pObject 337 * The COS target persistent object. 338 * @param cosDef 339 * A COS definition. 340 * @param cosTemplate 341 * A COS template. 342 * 343 * @throws UMSException 344 * The exception thrown if any of the following occur: o the 345 * target persistent object or COS definition parameter is null. 346 * o the target object is not persistent. o the COS definition 347 * is not one of the valid COS definitions. o an exception is 348 * propagated from any of the "remove" methods. 349 * @supported.api 350 */ 351 public void removeCOSAssignment(PersistentObject pObject, 352 ICOSDefinition cosDef, COSTemplate cosTemplate) throws UMSException 353 { 354 if (pObject == null || cosDef == null) { 355 String msg = i18n 356 .getString(IUMSConstants.COS_DEF_OR_TARGET_OBJECT_NULL); 357 throw new UMSException(msg); 358 } 359 360 // Do validation.... 361 // 362 if (pObject.getGuid() == null) { 363 String msg = i18n 364 .getString(IUMSConstants.COS_TARGET_OBJECT_NOT_PERSISTENT); 365 throw new UMSException(msg); 366 } 367 368 if (!(cosDef instanceof DirectCOSDefinition)) { 369 String msg = i18n.getString(IUMSConstants.INVALID_COSDEFINITION); 370 throw new UMSException(msg); 371 } 372 373 if (cosDef instanceof DirectCOSDefinition) { 374 removeDirectCOSAssignment(pObject, (DirectCOSDefinition) cosDef, 375 cosTemplate, _schemaManager); 376 } 377 } 378 379 /** 380 * Removes a Direct COS assignment from a target persistent object. The COS 381 * target persistent object could be a user, group, organization, 382 * organizationalunit, etc. The COS target object must be persistent before 383 * this method can be used. 384 * 385 * @param pObject 386 * The COS target persistent object. 387 * @param cosDef 388 * A COS definition. 389 * @param sMgr 390 * A SchemaManager object, which is used to determine object 391 * classes for attributes. 392 * 393 * @throws UMSException 394 * The exception thrown if any of the following occur: o an 395 * exception occurs determining the object class for the COS 396 * specifier. o an exception occurs determining the object class 397 * for the COS attributes. o there is an exception thrown rom 398 * the data layer. 399 */ 400 private void removeDirectCOSAssignment(PersistentObject pObject, 401 DirectCOSDefinition cosDef, COSTemplate cosTemplate, 402 SchemaManager sMgr) throws UMSException { 403 ArrayList aList; 404 AttrSet attrSet = new AttrSet(); 405 406 try { 407 // Include the attribute (whose name is the cosSpecifier) 408 // in the attribute set for removal (only if it exists). 409 // 410 if (pObject.getAttribute(cosDef.getCOSSpecifier()) != null) 411 attrSet.add(new Attr(cosDef.getCOSSpecifier(), cosTemplate 412 .getName())); 413 414 // Get cosSpecifier object class - should only be one. 415 // Include the cosSpecifier object class in the attribute 416 // set for removal (only if itt exists). 417 // 418 aList = (ArrayList) sMgr.getObjectClasses(cosDef.getCOSSpecifier()); 419 String cosSpecObjectClass = (String) aList.get(0); 420 if (objectClassExists(cosSpecObjectClass, pObject)) { 421 attrSet.add(new Attr("objectclass", cosSpecObjectClass)); 422 } 423 424 // Get the cos attributes from the definition (ex. mailquota). 425 // For each of the attributes, get the objectclass. Include the 426 // object classes in the attribute set for removal (if they exist). 427 // 428 String[] cosAttributes = cosDef.getCOSAttributes(); 429 String cosAttribute = null; 430 for (int i = 0; i < cosAttributes.length; i++) { 431 // Only get the attribute - not the qualifier 432 // 433 StringTokenizer st = new StringTokenizer(cosAttributes[i]); 434 cosAttribute = st.nextToken(); 435 aList = (ArrayList) sMgr.getObjectClasses(cosAttribute); 436 String cosAttributeObjectClass = (String) aList.get(0); 437 if (objectClassExists(cosAttributeObjectClass, pObject)) { 438 attrSet 439 .add(new Attr("objectclass", 440 cosAttributeObjectClass)); 441 } 442 } 443 444 if (attrSet.size() > 0) { 445 pObject.modify(toModifications(ModificationType.DELETE, attrSet)); 446 pObject.save(); 447 } 448 } catch (UMSException e) { 449 LdapException le = (LdapException) e.getRootCause(); 450 // Ignore anything that is not a COS generated attribute's object class 451 if (!ResultCode.OBJECTCLASS_VIOLATION.equals(le.getResult().getResultCode())) { 452 throw e; 453 } 454 } 455 } 456 457 /** 458 * Assigns a direct (Classic) COS definition to a persistent object. 459 * 460 * @param pObject 461 * The target persistent object. 462 * @param cosDef 463 * The direct (Classic) COS definition. 464 * @param cosTemplate 465 * A COS template belonging to the definition. 466 * @param sMgr 467 * A SchemaManager instance. 468 * 469 * @throws UMSException 470 * if an exception occurs 471 */ 472 private void assignDirectCOSDef(PersistentObject pObject, 473 DirectCOSDefinition cosDef, COSTemplate cosTemplate, 474 SchemaManager sMgr) throws UMSException { 475 476 // Do validation.... 477 // 478 if (cosDef.getGuid() == null) { 479 String msg = i18n 480 .getString(IUMSConstants.COS_DEFINITION_NOT_PERSISTENT); 481 throw new UMSException(msg); 482 } 483 484 // Make sure target entry is in same tree as COS Def parent. 485 // 486 DN targetDN = DN.valueOf(pObject.getGuid().getDn()); 487 DN cosParentDN = DN.valueOf(cosDef.getParentGuid().getDn()); 488 if (!(targetDN.isInScopeOf(cosParentDN, SearchScope.SUBORDINATES))) { 489 String msg = i18n 490 .getString(IUMSConstants.COS_TARGET_OBJECT_DIFFERENT_TREE); 491 throw new UMSException(msg); 492 } 493 494 // If cosSpecifier is "nsRole", then we don't need to go 495 // any further (we don't need to update target entries). 496 // 497 if (cosDef.getCOSSpecifier().equalsIgnoreCase("nsrole")) 498 return; 499 500 ArrayList aList; 501 AttrSet attrSet = new AttrSet(); 502 503 // Get cosSpecifier object class - should only be one. 504 // Update the target entry with cosSpecifier object class. 505 // Only add it if it doesn't already exist. 506 // 507 aList = (ArrayList) sMgr.getObjectClasses(cosDef.getCOSSpecifier()); 508 String cosSpecObjectClass = (String) aList.get(0); 509 if (!objectClassExists(cosSpecObjectClass, pObject)) { 510 attrSet.add(new Attr("objectclass", cosSpecObjectClass)); 511 } 512 513 // Get the cos attributes from the definition (ex. mailquota). 514 // For each of the attributes, get the objectclass. These 515 // will be used to attach to the target entry. This is only 516 // done if the cos attribute qualifier is not "operational" 517 // (you don't need to add cos attribute object classes for 518 // "operational" cos attribute qualifier. 519 // 520 String[] cosAttributes = cosDef.getCOSAttributes(); 521 String qualifier = null; 522 Arrays.asList(ICOSDefinition.qualifiers); 523 Attr attr = cosTemplate.getAttribute("objectclass"); 524 String[] cosTempObjClasses = attr.getStringValues(); 525 526 for (int i = 0; i < cosAttributes.length; i++) { 527 StringTokenizer st = new StringTokenizer(cosAttributes[i]); 528 st.nextToken(); 529 qualifier = st.nextToken(); 530 if ((!qualifier.equals( 531 ICOSDefinition.qualifiers[ICOSDefinition.OPERATIONAL]))) { 532 for (int j = 0; j < cosTempObjClasses.length; j++) { 533 if (!cosTempObjClasses[j].equalsIgnoreCase("top") 534 && !cosTempObjClasses[j].equalsIgnoreCase("costemplate") 535 && !objectClassExists(cosTempObjClasses[j], pObject)) 536 { 537 if (!attrSet.contains("objectclass", 538 cosTempObjClasses[j])) { 539 attrSet.add(new Attr("objectclass", 540 cosTempObjClasses[j])); 541 } 542 } 543 } 544 } 545 } 546 547 // Add the attribute name (cosSpecifier value) and attribute 548 // value (cosTemplate name) only if it doesn't exist. 549 // 550 if (pObject.getAttribute(cosDef.getCOSSpecifier()) == null) 551 attrSet.add(new Attr(cosDef.getCOSSpecifier(), cosTemplate 552 .getName())); 553 554 if (attrSet.size() > 0) { 555 pObject.modify(toModifications(ModificationType.ADD, attrSet)); 556 pObject.save(); 557 } 558 } 559 560 private Collection<Modification> toModifications(ModificationType type, AttrSet attrSet) { 561 Collection<Modification> modifications = new HashSet<>(); 562 Enumeration<Attr> attributes = attrSet.getAttributes(); 563 while (attributes.hasMoreElements()) { 564 modifications.add(new Modification(type, attributes.nextElement().toLDAPAttribute())); 565 } 566 return modifications; 567 } 568 569 /** 570 * Utility method to check if an object class exists in a persistent object. 571 * 572 * @param objectClass 573 * The object class. 574 * @param pObject 575 * The persistent object. 576 */ 577 private boolean objectClassExists(String objectClass, 578 PersistentObject pObject) { 579 Attr attr = pObject.getAttribute("objectclass"); 580 String[] vals = attr.getStringValues(); 581 for (int i = 0; i < vals.length; i++) { 582 if (objectClass.equalsIgnoreCase(vals[i])) { 583 return true; 584 } 585 } 586 return false; 587 } 588 589 // 590 // Definition Search Attributes 591 // 592 private static final String[] DEF_ATTRIBUTE_NAMES = { "objectclass", 593 ICOSDefinition.DEFAULT_NAMING_ATTR, ICOSDefinition.COSTEMPLATEDN, 594 ICOSDefinition.COSSPECIFIER, ICOSDefinition.COSATTRIBUTE, 595 ICOSDefinition.ICOSSPECIFIER }; 596 597 private PersistentObject _parentObject; 598 599 private SchemaManager _schemaManager; 600 601 private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 602}