001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2007-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2012-2015 ForgeRock AS 026 */ 027package org.opends.admin.ads; 028 029import static org.forgerock.util.Utils.*; 030import static org.opends.messages.QuickSetupMessages.*; 031 032import java.io.File; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.LinkedHashSet; 036import java.util.LinkedList; 037import java.util.Map; 038import java.util.Set; 039import java.util.SortedSet; 040import java.util.TreeSet; 041 042import javax.naming.CompositeName; 043import javax.naming.InvalidNameException; 044import javax.naming.NameAlreadyBoundException; 045import javax.naming.NameNotFoundException; 046import javax.naming.NamingEnumeration; 047import javax.naming.NamingException; 048import javax.naming.NoPermissionException; 049import javax.naming.NotContextException; 050import javax.naming.directory.Attribute; 051import javax.naming.directory.Attributes; 052import javax.naming.directory.BasicAttribute; 053import javax.naming.directory.BasicAttributes; 054import javax.naming.directory.DirContext; 055import javax.naming.directory.SearchControls; 056import javax.naming.directory.SearchResult; 057import javax.naming.ldap.Control; 058import javax.naming.ldap.InitialLdapContext; 059import javax.naming.ldap.LdapContext; 060import javax.naming.ldap.LdapName; 061import javax.naming.ldap.Rdn; 062 063import org.forgerock.i18n.LocalizableMessage; 064import org.forgerock.i18n.slf4j.LocalizedLogger; 065import org.opends.admin.ads.ADSContextException.ErrorType; 066import org.opends.admin.ads.util.ConnectionUtils; 067import org.opends.quicksetup.Constants; 068import org.opends.server.schema.SchemaConstants; 069 070/** Class used to update and read the contents of the Administration Data. */ 071public class ADSContext 072{ 073 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 074 075 /** 076 * Enumeration containing the different server properties syntaxes that could 077 * be stored in the ADS. 078 */ 079 public enum ADSPropertySyntax 080 { 081 /** String syntax. */ 082 STRING, 083 /** Integer syntax. */ 084 INTEGER, 085 /** Boolean syntax. */ 086 BOOLEAN, 087 /** Certificate;binary syntax. */ 088 CERTIFICATE_BINARY 089 } 090 091 /** Enumeration containing the different server properties that are stored in the ADS. */ 092 public enum ServerProperty 093 { 094 /** The ID used to identify the server. */ 095 ID("id",ADSPropertySyntax.STRING), 096 /** The host name of the server. */ 097 HOST_NAME("hostname",ADSPropertySyntax.STRING), 098 /** The LDAP port of the server. */ 099 LDAP_PORT("ldapport",ADSPropertySyntax.INTEGER), 100 /** The JMX port of the server. */ 101 JMX_PORT("jmxport",ADSPropertySyntax.INTEGER), 102 /** The JMX secure port of the server. */ 103 JMXS_PORT("jmxsport",ADSPropertySyntax.INTEGER), 104 /** The LDAPS port of the server. */ 105 LDAPS_PORT("ldapsport",ADSPropertySyntax.INTEGER), 106 /** The administration connector port of the server. */ 107 ADMIN_PORT("adminport",ADSPropertySyntax.INTEGER), 108 /** The certificate used by the server. */ 109 CERTIFICATE("certificate",ADSPropertySyntax.STRING), 110 /** The path where the server is installed. */ 111 INSTANCE_PATH("instancepath",ADSPropertySyntax.STRING), 112 /** The description of the server. */ 113 DESCRIPTION("description",ADSPropertySyntax.STRING), 114 /** The OS of the machine where the server is installed. */ 115 HOST_OS("os",ADSPropertySyntax.STRING), 116 /** Whether LDAP is enabled or not. */ 117 LDAP_ENABLED("ldapEnabled",ADSPropertySyntax.BOOLEAN), 118 /** Whether LDAPS is enabled or not. */ 119 LDAPS_ENABLED("ldapsEnabled",ADSPropertySyntax.BOOLEAN), 120 /** Whether ADMIN is enabled or not. */ 121 ADMIN_ENABLED("adminEnabled",ADSPropertySyntax.BOOLEAN), 122 /** Whether StartTLS is enabled or not. */ 123 STARTTLS_ENABLED("startTLSEnabled",ADSPropertySyntax.BOOLEAN), 124 /** Whether JMX is enabled or not. */ 125 JMX_ENABLED("jmxEnabled",ADSPropertySyntax.BOOLEAN), 126 /** Whether JMX is enabled or not. */ 127 JMXS_ENABLED("jmxsEnabled",ADSPropertySyntax.BOOLEAN), 128 /** The location of the server. */ 129 LOCATION("location",ADSPropertySyntax.STRING), 130 /** The groups to which this server belongs. */ 131 GROUPS("memberofgroups",ADSPropertySyntax.STRING), 132 /** The unique name of the instance key public-key certificate. */ 133 INSTANCE_KEY_ID("ds-cfg-key-id",ADSPropertySyntax.STRING), 134 /** 135 * The instance key-pair public-key certificate. Note: This attribute 136 * belongs to an instance key entry, separate from the server entry and 137 * named by the ds-cfg-key-id attribute from the server entry. 138 */ 139 INSTANCE_PUBLIC_KEY_CERTIFICATE("ds-cfg-public-key-certificate", ADSPropertySyntax.CERTIFICATE_BINARY); 140 141 private String attrName; 142 private ADSPropertySyntax attSyntax; 143 144 /** 145 * Private constructor. 146 * 147 * @param n 148 * the name of the attribute. 149 * @param s 150 * the name of the syntax. 151 */ 152 private ServerProperty(String n, ADSPropertySyntax s) 153 { 154 attrName = n; 155 attSyntax = s; 156 } 157 158 /** 159 * Returns the attribute name. 160 * 161 * @return the attribute name. 162 */ 163 public String getAttributeName() 164 { 165 return attrName; 166 } 167 168 /** 169 * Returns the attribute syntax. 170 * 171 * @return the attribute syntax. 172 */ 173 public ADSPropertySyntax getAttributeSyntax() 174 { 175 return attSyntax; 176 } 177 } 178 179 /** Default global admin UID. */ 180 public static final String GLOBAL_ADMIN_UID = "admin"; 181 182 private static Map<String, ServerProperty> NAME_TO_SERVER_PROPERTY; 183 184 /** 185 * Get a ServerProperty associated to a name. 186 * 187 * @param name 188 * The name of the property to retrieve. 189 * @return The corresponding ServerProperty or null if name doesn't match with 190 * an existing property. 191 */ 192 public static ServerProperty getServerPropFromName(String name) 193 { 194 if (NAME_TO_SERVER_PROPERTY == null) 195 { 196 NAME_TO_SERVER_PROPERTY = new HashMap<>(); 197 for (ServerProperty s : ServerProperty.values()) 198 { 199 NAME_TO_SERVER_PROPERTY.put(s.getAttributeName(), s); 200 } 201 } 202 return NAME_TO_SERVER_PROPERTY.get(name); 203 } 204 205 /** The list of server properties that are multivalued. */ 206 private static final Set<ServerProperty> MULTIVALUED_SERVER_PROPERTIES = new HashSet<>(); 207 static 208 { 209 MULTIVALUED_SERVER_PROPERTIES.add(ServerProperty.GROUPS); 210 } 211 212 /** The default server group which will contain all registered servers. */ 213 public static final String ALL_SERVERGROUP_NAME = "all-servers"; 214 215 /** Enumeration containing the different server group properties that are stored in the ADS. */ 216 public enum ServerGroupProperty 217 { 218 /** The UID of the server group. */ 219 UID("cn"), 220 /** The description of the server group. */ 221 DESCRIPTION("description"), 222 /** The members of the server group. */ 223 MEMBERS("uniqueMember"); 224 225 private String attrName; 226 227 /** 228 * Private constructor. 229 * 230 * @param n 231 * the attribute name. 232 */ 233 private ServerGroupProperty(String n) 234 { 235 attrName = n; 236 } 237 238 /** 239 * Returns the attribute name. 240 * 241 * @return the attribute name. 242 */ 243 public String getAttributeName() 244 { 245 return attrName; 246 } 247 } 248 249 /** The list of server group properties that are multivalued. */ 250 private static final Set<ServerGroupProperty> MULTIVALUED_SERVER_GROUP_PROPERTIES = new HashSet<>(); 251 static 252 { 253 MULTIVALUED_SERVER_GROUP_PROPERTIES.add(ServerGroupProperty.MEMBERS); 254 } 255 256 /** The enumeration containing the different Administrator properties. */ 257 public enum AdministratorProperty 258 { 259 /** The UID of the administrator. */ 260 UID("id", ADSPropertySyntax.STRING), 261 /** The password of the administrator. */ 262 PASSWORD("password", ADSPropertySyntax.STRING), 263 /** The description of the administrator. */ 264 DESCRIPTION("description", ADSPropertySyntax.STRING), 265 /** The DN of the administrator. */ 266 ADMINISTRATOR_DN("administrator dn", ADSPropertySyntax.STRING), 267 /** The administrator privilege. */ 268 PRIVILEGE("privilege", ADSPropertySyntax.STRING); 269 270 private String attrName; 271 private ADSPropertySyntax attrSyntax; 272 273 /** 274 * Private constructor. 275 * 276 * @param n 277 * the name of the attribute. 278 * @param s 279 * the name of the syntax. 280 */ 281 private AdministratorProperty(String n, ADSPropertySyntax s) 282 { 283 attrName = n; 284 attrSyntax = s; 285 } 286 287 /** 288 * Returns the attribute name. 289 * 290 * @return the attribute name. 291 */ 292 public String getAttributeName() 293 { 294 return attrName; 295 } 296 297 /** 298 * Returns the attribute syntax. 299 * 300 * @return the attribute syntax. 301 */ 302 public ADSPropertySyntax getAttributeSyntax() 303 { 304 return attrSyntax; 305 } 306 } 307 308 private static HashMap<String, AdministratorProperty> nameToAdminUserProperty; 309 310 /** 311 * Get a AdministratorProperty associated to a name. 312 * 313 * @param name 314 * The name of the property to retrieve. 315 * @return The corresponding AdministratorProperty or null if name doesn't 316 * match with an existing property. 317 */ 318 public static AdministratorProperty getAdminUserPropFromName(String name) 319 { 320 if (nameToAdminUserProperty == null) 321 { 322 nameToAdminUserProperty = new HashMap<>(); 323 for (AdministratorProperty u : AdministratorProperty.values()) 324 { 325 nameToAdminUserProperty.put(u.getAttributeName(), u); 326 } 327 } 328 return nameToAdminUserProperty.get(name); 329 } 330 331 /** The context used to retrieve information. */ 332 private final InitialLdapContext dirContext; 333 334 /** 335 * Constructor of the ADSContext. 336 * 337 * @param dirContext 338 * the DirContext that must be used to retrieve information. 339 */ 340 public ADSContext(InitialLdapContext dirContext) 341 { 342 this.dirContext = dirContext; 343 } 344 345 /** 346 * Returns the DirContext used to retrieve information by this ADSContext. 347 * 348 * @return the DirContext used to retrieve information by this ADSContext. 349 */ 350 public InitialLdapContext getDirContext() 351 { 352 return dirContext; 353 } 354 355 /** 356 * Method called to register a server in the ADS. 357 * 358 * @param serverProperties 359 * the properties of the server. 360 * @throws ADSContextException 361 * if the server could not be registered. 362 */ 363 public void registerServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 364 { 365 LdapName dn = makeDNFromServerProperties(serverProperties); 366 BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, true); 367 try 368 { 369 // This check is required because by default the server container entry 370 // does not exist. 371 if (!isExistingEntry(nameFromDN(getServerContainerDN()))) 372 { 373 createContainerEntry(getServerContainerDN()); 374 } 375 dirContext.createSubcontext(dn, attrs).close(); 376 if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) 377 { 378 registerInstanceKeyCertificate(serverProperties, dn); 379 } 380 381 // register this server into "all" groups 382 Map<ServerGroupProperty, Object> serverGroupProperties = new HashMap<>(); 383 Set<String> memberList = getServerGroupMemberList(ALL_SERVERGROUP_NAME); 384 if (memberList == null) 385 { 386 memberList = new HashSet<>(); 387 } 388 String newMember = "cn=" + Rdn.escapeValue(serverProperties.get(ServerProperty.ID)); 389 390 memberList.add(newMember); 391 serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList); 392 393 updateServerGroup(ALL_SERVERGROUP_NAME, serverGroupProperties); 394 395 // Update the server property "GROUPS" 396 Set<?> rawGroupList = (Set<?>) serverProperties.get(ServerProperty.GROUPS); 397 Set<String> groupList = new HashSet<>(); 398 if (rawGroupList != null) 399 { 400 for (Object elm : rawGroupList) 401 { 402 groupList.add(elm.toString()); 403 } 404 } 405 groupList.add(ALL_SERVERGROUP_NAME); 406 serverProperties.put(ServerProperty.GROUPS, groupList); 407 updateServer(serverProperties, null); 408 } 409 catch (ADSContextException ace) 410 { 411 throw ace; 412 } 413 catch (NameAlreadyBoundException x) 414 { 415 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 416 } 417 catch (Exception x) 418 { 419 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 420 } 421 } 422 423 /** 424 * Method called to update the properties of a server in the ADS. 425 * 426 * @param serverProperties 427 * the new properties of the server. 428 * @param newServerId 429 * The new server Identifier, or null. 430 * @throws ADSContextException 431 * if the server could not be registered. 432 */ 433 public void updateServer(Map<ServerProperty, Object> serverProperties, String newServerId) throws ADSContextException 434 { 435 LdapName dn = makeDNFromServerProperties(serverProperties); 436 437 try 438 { 439 if (newServerId != null) 440 { 441 Map<ServerProperty, Object> newServerProps = new HashMap<>(serverProperties); 442 newServerProps.put(ServerProperty.ID, newServerId); 443 LdapName newDn = makeDNFromServerProperties(newServerProps); 444 dirContext.rename(dn, newDn); 445 dn = newDn; 446 serverProperties.put(ServerProperty.ID, newServerId); 447 } 448 BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, false); 449 dirContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); 450 if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) 451 { 452 registerInstanceKeyCertificate(serverProperties, dn); 453 } 454 } 455 catch (ADSContextException ace) 456 { 457 throw ace; 458 } 459 catch (NameNotFoundException x) 460 { 461 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 462 } 463 catch (Exception x) 464 { 465 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 466 } 467 } 468 469 /** 470 * Method called to unregister a server in the ADS. Note that the server's 471 * instance key-pair public-key certificate entry (created in 472 * <tt>registerServer()</tt>) is left untouched. 473 * 474 * @param serverProperties 475 * the properties of the server. 476 * @throws ADSContextException 477 * if the server could not be unregistered. 478 */ 479 public void unregisterServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 480 { 481 LdapName dn = makeDNFromServerProperties(serverProperties); 482 try 483 { 484 // Unregister the server from the server groups. 485 String member = "cn=" + Rdn.escapeValue(serverProperties.get(ServerProperty.ID)); 486 Set<Map<ServerGroupProperty, Object>> serverGroups = readServerGroupRegistry(); 487 for (Map<ServerGroupProperty, Object> serverGroup : serverGroups) 488 { 489 Set<?> memberList = (Set<?>) serverGroup.get(ServerGroupProperty.MEMBERS); 490 if (memberList != null && memberList.remove(member)) 491 { 492 Map<ServerGroupProperty, Object> serverGroupProperties = new HashMap<>(); 493 serverGroupProperties.put(ServerGroupProperty.MEMBERS, memberList); 494 String groupName = (String) serverGroup.get(ServerGroupProperty.UID); 495 updateServerGroup(groupName, serverGroupProperties); 496 } 497 } 498 499 dirContext.destroySubcontext(dn); 500 } 501 catch (NameNotFoundException x) 502 { 503 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 504 } 505 catch (NamingException x) 506 { 507 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 508 } 509 510 // Unregister the server in server groups 511 NamingEnumeration<SearchResult> ne = null; 512 try 513 { 514 SearchControls sc = new SearchControls(); 515 516 String serverID = getServerID(serverProperties); 517 if (serverID != null) 518 { 519 String memberAttrName = ServerGroupProperty.MEMBERS.getAttributeName(); 520 String filter = "(" + memberAttrName + "=cn=" + serverID + ")"; 521 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 522 ne = dirContext.search(getServerGroupContainerDN(), filter, sc); 523 while (ne.hasMore()) 524 { 525 SearchResult sr = ne.next(); 526 String groupDn = sr.getNameInNamespace(); 527 BasicAttribute newAttr = new BasicAttribute(memberAttrName); 528 NamingEnumeration<? extends Attribute> attrs = sr.getAttributes().getAll(); 529 try 530 { 531 while (attrs.hasMore()) 532 { 533 Attribute attr = attrs.next(); 534 String attrID = attr.getID(); 535 536 if (attrID.equalsIgnoreCase(memberAttrName)) 537 { 538 NamingEnumeration<?> ae = attr.getAll(); 539 try 540 { 541 while (ae.hasMore()) 542 { 543 String value = (String) ae.next(); 544 if (!value.equalsIgnoreCase("cn=" + serverID)) 545 { 546 newAttr.add(value); 547 } 548 } 549 } 550 finally 551 { 552 handleCloseNamingEnumeration(ae); 553 } 554 } 555 } 556 } 557 finally 558 { 559 handleCloseNamingEnumeration(attrs); 560 } 561 BasicAttributes newAttrs = new BasicAttributes(); 562 newAttrs.put(newAttr); 563 if (newAttr.size() > 0) 564 { 565 dirContext.modifyAttributes(groupDn, DirContext.REPLACE_ATTRIBUTE, newAttrs); 566 } 567 else 568 { 569 dirContext.modifyAttributes(groupDn, DirContext.REMOVE_ATTRIBUTE, newAttrs); 570 } 571 } 572 } 573 } 574 catch (NameNotFoundException x) 575 { 576 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 577 } 578 catch (NoPermissionException x) 579 { 580 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 581 } 582 catch (NamingException x) 583 { 584 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 585 } 586 finally 587 { 588 handleCloseNamingEnumeration(ne); 589 } 590 } 591 592 /** 593 * Returns whether a given server is already registered or not. 594 * 595 * @param serverProperties 596 * the server properties. 597 * @return <CODE>true</CODE> if the server was registered and 598 * <CODE>false</CODE> otherwise. 599 * @throws ADSContextException 600 * if something went wrong. 601 */ 602 public boolean isServerAlreadyRegistered(Map<ServerProperty, Object> serverProperties) throws ADSContextException 603 { 604 return isExistingEntry(makeDNFromServerProperties(serverProperties)); 605 } 606 607 /** 608 * Returns whether a given administrator is already registered or not. 609 * 610 * @param uid 611 * the administrator UID. 612 * @return <CODE>true</CODE> if the administrator was registered and 613 * <CODE>false</CODE> otherwise. 614 * @throws ADSContextException 615 * if something went wrong. 616 */ 617 public boolean isAdministratorAlreadyRegistered(String uid) throws ADSContextException 618 { 619 return isExistingEntry(makeDNFromAdministratorProperties(uid)); 620 } 621 622 /** 623 * A convenience method that takes some server properties as parameter and if 624 * there is no server registered associated with those properties, registers 625 * it and if it is already registered, updates it. 626 * 627 * @param serverProperties 628 * the server properties. 629 * @return 0 if the server was registered; 1 if updated (i.e., the server 630 * entry was already in ADS). 631 * @throws ADSContextException 632 * if something goes wrong. 633 */ 634 public int registerOrUpdateServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException 635 { 636 try 637 { 638 registerServer(serverProperties); 639 return 0; 640 } 641 catch (ADSContextException x) 642 { 643 if (x.getError() == ErrorType.ALREADY_REGISTERED) 644 { 645 updateServer(serverProperties, null); 646 return 1; 647 } 648 649 throw x; 650 } 651 } 652 653 /** 654 * Returns the member list of a group of server. 655 * 656 * @param serverGroupId 657 * The group name. 658 * @return the member list of a group of server. 659 * @throws ADSContextException 660 * if something goes wrong. 661 */ 662 public Set<String> getServerGroupMemberList(String serverGroupId) throws ADSContextException 663 { 664 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); 665 666 Set<String> result = new HashSet<>(); 667 NamingEnumeration<SearchResult> srs = null; 668 NamingEnumeration<? extends Attribute> ne = null; 669 try 670 { 671 SearchControls sc = new SearchControls(); 672 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 673 srs = getDirContext().search(dn, "(objectclass=*)", sc); 674 675 if (!srs.hasMore()) 676 { 677 return result; 678 } 679 Attributes attrs = srs.next().getAttributes(); 680 ne = attrs.getAll(); 681 while (ne.hasMore()) 682 { 683 Attribute attr = ne.next(); 684 String attrID = attr.getID(); 685 686 if (!attrID.toLowerCase().equals(ServerGroupProperty.MEMBERS.getAttributeName().toLowerCase())) 687 { 688 continue; 689 } 690 691 // We have the members list 692 NamingEnumeration<?> ae = attr.getAll(); 693 try 694 { 695 while (ae.hasMore()) 696 { 697 result.add((String) ae.next()); 698 } 699 } 700 finally 701 { 702 handleCloseNamingEnumeration(ae); 703 } 704 break; 705 } 706 } 707 catch (NameNotFoundException x) 708 { 709 result = new HashSet<>(); 710 } 711 catch (NoPermissionException x) 712 { 713 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 714 } 715 catch (NamingException x) 716 { 717 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 718 } 719 finally 720 { 721 handleCloseNamingEnumeration(srs); 722 handleCloseNamingEnumeration(ne); 723 } 724 return result; 725 } 726 727 /** 728 * Returns a set containing the servers that are registered in the ADS. 729 * 730 * @return a set containing the servers that are registered in the ADS. 731 * @throws ADSContextException 732 * if something goes wrong. 733 */ 734 public Set<Map<ServerProperty, Object>> readServerRegistry() throws ADSContextException 735 { 736 Set<Map<ServerProperty, Object>> result = new HashSet<>(); 737 NamingEnumeration<SearchResult> ne = null; 738 try 739 { 740 SearchControls sc = new SearchControls(); 741 742 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 743 ne = dirContext.search(getServerContainerDN(), "(objectclass=*)", sc); 744 while (ne.hasMore()) 745 { 746 SearchResult sr = ne.next(); 747 Map<ServerProperty, Object> properties = makePropertiesFromServerAttrs(sr.getAttributes()); 748 Object keyId = properties.get(ServerProperty.INSTANCE_KEY_ID); 749 if (keyId != null) 750 { 751 NamingEnumeration<SearchResult> ne2 = null; 752 try 753 { 754 SearchControls sc1 = new SearchControls(); 755 sc1.setSearchScope(SearchControls.ONELEVEL_SCOPE); 756 final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" }; 757 sc1.setReturningAttributes(attrIDs); 758 759 ne2 = dirContext.search(getInstanceKeysContainerDN(), "(ds-cfg-key-id=" + keyId + ")", sc); 760 boolean found = false; 761 while (ne2.hasMore()) 762 { 763 SearchResult certEntry = ne2.next(); 764 Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]); 765 properties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, certAttr.get()); 766 found = true; 767 } 768 if (!found) 769 { 770 logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); 771 } 772 } 773 catch (NameNotFoundException x) 774 { 775 logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); 776 } 777 finally 778 { 779 handleCloseNamingEnumeration(ne2); 780 } 781 } 782 result.add(properties); 783 } 784 } 785 catch (NameNotFoundException x) 786 { 787 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 788 } 789 catch (NoPermissionException x) 790 { 791 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 792 } 793 catch (NamingException x) 794 { 795 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 796 } 797 finally 798 { 799 handleCloseNamingEnumeration(ne); 800 } 801 802 return result; 803 } 804 805 /** 806 * Creates a Server Group in the ADS. 807 * 808 * @param serverGroupProperties 809 * the properties of the server group to be created. 810 * @throws ADSContextException 811 * if something goes wrong. 812 */ 813 public void createServerGroup(Map<ServerGroupProperty, Object> serverGroupProperties) throws ADSContextException 814 { 815 LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties); 816 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 817 // Add the objectclass attribute value 818 Attribute oc = new BasicAttribute("objectclass"); 819 oc.add("top"); 820 oc.add("groupOfUniqueNames"); 821 attrs.put(oc); 822 try 823 { 824 DirContext ctx = dirContext.createSubcontext(dn, attrs); 825 ctx.close(); 826 } 827 catch (NameAlreadyBoundException x) 828 { 829 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 830 } 831 catch (NamingException x) 832 { 833 throw new ADSContextException(ErrorType.BROKEN_INSTALL, x); 834 } 835 } 836 837 /** 838 * Updates the properties of a Server Group in the ADS. 839 * 840 * @param serverGroupProperties 841 * the new properties of the server group to be updated. 842 * @param groupID 843 * The group name. 844 * @throws ADSContextException 845 * if something goes wrong. 846 */ 847 public void updateServerGroup(String groupID, Map<ServerGroupProperty, Object> serverGroupProperties) 848 throws ADSContextException 849 { 850 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN()); 851 try 852 { 853 // Entry renaming ? 854 if (serverGroupProperties.containsKey(ServerGroupProperty.UID)) 855 { 856 String newGroupId = serverGroupProperties.get(ServerGroupProperty.UID).toString(); 857 if (!newGroupId.equals(groupID)) 858 { 859 // Rename to entry 860 LdapName newDN = nameFromDN("cn=" + Rdn.escapeValue(newGroupId) + "," + getServerGroupContainerDN()); 861 dirContext.rename(dn, newDN); 862 dn = newDN; 863 } 864 865 // In any case, we remove the "cn" attribute. 866 serverGroupProperties.remove(ServerGroupProperty.UID); 867 } 868 if (serverGroupProperties.isEmpty()) 869 { 870 return; 871 } 872 873 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 874 // attribute modification 875 dirContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); 876 } 877 catch (NameNotFoundException x) 878 { 879 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 880 } 881 catch (NameAlreadyBoundException x) 882 { 883 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 884 } 885 catch (NamingException x) 886 { 887 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 888 } 889 } 890 891 /** 892 * Updates the properties of a Server Group in the ADS. 893 * 894 * @param serverGroupProperties 895 * the new properties of the server group to be updated. 896 * @param groupID 897 * The group name. 898 * @throws ADSContextException 899 * if something goes wrong. 900 */ 901 public void removeServerGroupProp(String groupID, Set<ServerGroupProperty> serverGroupProperties) 902 throws ADSContextException 903 { 904 LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN()); 905 BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); 906 try 907 { 908 dirContext.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, attrs); 909 } 910 catch (NameAlreadyBoundException x) 911 { 912 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 913 } 914 catch (NamingException x) 915 { 916 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 917 } 918 } 919 920 /** 921 * Deletes a Server Group in the ADS. 922 * 923 * @param serverGroupProperties 924 * the properties of the server group to be deleted. 925 * @throws ADSContextException 926 * if something goes wrong. 927 */ 928 public void deleteServerGroup(Map<ServerGroupProperty, Object> serverGroupProperties) throws ADSContextException 929 { 930 LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties); 931 try 932 { 933 dirContext.destroySubcontext(dn); 934 } 935 catch (NamingException x) 936 { 937 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 938 } 939 } 940 941 /** 942 * Returns a set containing the server groups that are defined in the ADS. 943 * 944 * @return a set containing the server groups that are defined in the ADS. 945 * @throws ADSContextException 946 * if something goes wrong. 947 */ 948 public Set<Map<ServerGroupProperty, Object>> readServerGroupRegistry() throws ADSContextException 949 { 950 Set<Map<ServerGroupProperty, Object>> result = new HashSet<>(); 951 NamingEnumeration<SearchResult> ne = null; 952 try 953 { 954 SearchControls sc = new SearchControls(); 955 956 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 957 ne = dirContext.search(getServerGroupContainerDN(), "(objectclass=*)", sc); 958 while (ne.hasMore()) 959 { 960 SearchResult sr = ne.next(); 961 Map<ServerGroupProperty, Object> properties = makePropertiesFromServerGroupAttrs(sr.getAttributes()); 962 result.add(properties); 963 } 964 } 965 catch (NameNotFoundException x) 966 { 967 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 968 } 969 catch (NoPermissionException x) 970 { 971 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 972 } 973 catch (NamingException x) 974 { 975 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 976 } 977 finally 978 { 979 handleCloseNamingEnumeration(ne); 980 } 981 return result; 982 } 983 984 /** 985 * Returns a set containing the administrators that are defined in the ADS. 986 * 987 * @return a set containing the administrators that are defined in the ADS. 988 * @throws ADSContextException 989 * if something goes wrong. 990 */ 991 public Set<Map<AdministratorProperty, Object>> readAdministratorRegistry() throws ADSContextException 992 { 993 Set<Map<AdministratorProperty, Object>> result = new HashSet<>(); 994 NamingEnumeration<SearchResult> ne = null; 995 try 996 { 997 SearchControls sc = new SearchControls(); 998 999 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); 1000 String[] attList = { "cn", "userpassword", "ds-privilege-name", "description" }; 1001 sc.setReturningAttributes(attList); 1002 ne = dirContext.search(getAdministratorContainerDN(), "(objectclass=*)", sc); 1003 while (ne.hasMore()) 1004 { 1005 SearchResult sr = ne.next(); 1006 Map<AdministratorProperty, Object> properties = 1007 makePropertiesFromAdministratorAttrs(getRdn(sr.getName()), sr.getAttributes()); 1008 result.add(properties); 1009 } 1010 } 1011 catch (NameNotFoundException x) 1012 { 1013 throw new ADSContextException(ErrorType.BROKEN_INSTALL); 1014 } 1015 catch (NoPermissionException x) 1016 { 1017 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1018 } 1019 catch (NamingException x) 1020 { 1021 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1022 } 1023 finally 1024 { 1025 handleCloseNamingEnumeration(ne); 1026 } 1027 1028 return result; 1029 } 1030 1031 /** 1032 * Creates the Administration Data in the server. The call to this method 1033 * assumes that OpenDS.jar has already been loaded. So this should not be 1034 * called by the Java Web Start before being sure that this jar is loaded. 1035 * 1036 * @param backendName 1037 * the backend name which will handle admin information. 1038 * <CODE>null</CODE> to use the default backend name for the admin 1039 * information. 1040 * @throws ADSContextException 1041 * if something goes wrong. 1042 */ 1043 public void createAdminData(String backendName) throws ADSContextException 1044 { 1045 // Add the administration suffix 1046 createAdministrationSuffix(backendName); 1047 createAdminDataContainers(); 1048 } 1049 1050 /** Create container entries. */ 1051 private void createAdminDataContainers() throws ADSContextException 1052 { 1053 // Create the DIT below the administration suffix 1054 if (!isExistingEntry(nameFromDN(getAdministrationSuffixDN()))) 1055 { 1056 createTopContainerEntry(); 1057 } 1058 if (!isExistingEntry(nameFromDN(getAdministratorContainerDN()))) 1059 { 1060 createAdministratorContainerEntry(); 1061 } 1062 if (!isExistingEntry(nameFromDN(getServerContainerDN()))) 1063 { 1064 createContainerEntry(getServerContainerDN()); 1065 } 1066 if (!isExistingEntry(nameFromDN(getServerGroupContainerDN()))) 1067 { 1068 createContainerEntry(getServerGroupContainerDN()); 1069 } 1070 1071 // Add the default "all-servers" group 1072 if (!isExistingEntry(nameFromDN(getAllServerGroupDN()))) 1073 { 1074 Map<ServerGroupProperty, Object> allServersGroupsMap = new HashMap<>(); 1075 allServersGroupsMap.put(ServerGroupProperty.UID, ALL_SERVERGROUP_NAME); 1076 createServerGroup(allServersGroupsMap); 1077 } 1078 1079 // Create the CryptoManager instance key DIT below the administration suffix 1080 if (!isExistingEntry(nameFromDN(getInstanceKeysContainerDN()))) 1081 { 1082 createContainerEntry(getInstanceKeysContainerDN()); 1083 } 1084 1085 // Create the CryptoManager secret key DIT below the administration suffix 1086 if (!isExistingEntry(nameFromDN(getSecretKeysContainerDN()))) 1087 { 1088 createContainerEntry(getSecretKeysContainerDN()); 1089 } 1090 } 1091 1092 /** 1093 * Removes the administration data. 1094 * 1095 * @param removeAdministrators 1096 * {@code true} if administrators should be removed. It may not be 1097 * possible to remove administrators if the operation is being 1098 * performed by one of the administrators because it will cause the 1099 * administrator to be disconnected. 1100 * @throws ADSContextException 1101 * if something goes wrong. 1102 */ 1103 public void removeAdminData(boolean removeAdministrators) throws ADSContextException 1104 { 1105 String[] dns = { getServerContainerDN(), getServerGroupContainerDN(), 1106 removeAdministrators ? getAdministratorContainerDN() : null }; 1107 try 1108 { 1109 Control[] controls = new Control[] { new SubtreeDeleteControl() }; 1110 LdapContext tmpContext = dirContext.newInstance(controls); 1111 try 1112 { 1113 for (String dn : dns) 1114 { 1115 if (dn != null) 1116 { 1117 LdapName ldapName = nameFromDN(dn); 1118 if (isExistingEntry(ldapName)) 1119 { 1120 tmpContext.destroySubcontext(dn); 1121 } 1122 } 1123 } 1124 } 1125 finally 1126 { 1127 try 1128 { 1129 tmpContext.close(); 1130 } 1131 catch (Exception ex) 1132 { 1133 logger.warn(LocalizableMessage.raw("Error while closing LDAP connection after removing admin data", ex)); 1134 } 1135 } 1136 // Recreate the container entries: 1137 createAdminDataContainers(); 1138 } 1139 catch (NamingException x) 1140 { 1141 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1142 } 1143 } 1144 1145 /** 1146 * Returns <CODE>true</CODE> if the server contains Administration Data and 1147 * <CODE>false</CODE> otherwise. 1148 * 1149 * @return <CODE>true</CODE> if the server contains Administration Data and 1150 * <CODE>false</CODE> otherwise. 1151 * @throws ADSContextException 1152 * if something goes wrong. 1153 */ 1154 public boolean hasAdminData() throws ADSContextException 1155 { 1156 String[] dns = { getAdministratorContainerDN(), getAllServerGroupDN(), getServerContainerDN(), 1157 getInstanceKeysContainerDN(), getSecretKeysContainerDN() }; 1158 boolean hasAdminData = true; 1159 for (int i = 0; i < dns.length && hasAdminData; i++) 1160 { 1161 hasAdminData = isExistingEntry(nameFromDN(dns[i])); 1162 } 1163 return hasAdminData; 1164 } 1165 1166 /** 1167 * Returns the DN of the administrator for a given UID. 1168 * 1169 * @param uid 1170 * the UID to be used to generate the DN. 1171 * @return the DN of the administrator for the given UID: 1172 */ 1173 public static String getAdministratorDN(String uid) 1174 { 1175 return "cn=" + Rdn.escapeValue(uid) + "," + getAdministratorContainerDN(); 1176 } 1177 1178 /** 1179 * Creates an Administrator in the ADS. 1180 * 1181 * @param adminProperties 1182 * the properties of the administrator to be created. 1183 * @throws ADSContextException 1184 * if something goes wrong. 1185 */ 1186 public void createAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException 1187 { 1188 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1189 BasicAttributes attrs = makeAttrsFromAdministratorProperties(adminProperties, true, null); 1190 1191 try 1192 { 1193 DirContext ctx = dirContext.createSubcontext(dnCentralAdmin, attrs); 1194 ctx.close(); 1195 } 1196 catch (NameAlreadyBoundException x) 1197 { 1198 throw new ADSContextException(ErrorType.ALREADY_REGISTERED); 1199 } 1200 catch (NoPermissionException x) 1201 { 1202 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1203 } 1204 catch (NamingException x) 1205 { 1206 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1207 } 1208 } 1209 1210 /** 1211 * Deletes the administrator in the ADS. 1212 * 1213 * @param adminProperties 1214 * the properties of the administrator to be deleted. 1215 * @throws ADSContextException 1216 * if something goes wrong. 1217 */ 1218 public void deleteAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException 1219 { 1220 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1221 1222 try 1223 { 1224 dirContext.destroySubcontext(dnCentralAdmin); 1225 } 1226 catch (NameNotFoundException | NotContextException x) 1227 { 1228 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 1229 } 1230 catch (NoPermissionException x) 1231 { 1232 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1233 } 1234 catch (NamingException x) 1235 { 1236 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1237 } 1238 } 1239 1240 /** 1241 * Updates and administrator registered in the ADS. 1242 * 1243 * @param adminProperties 1244 * the new properties of the administrator. 1245 * @param newAdminUserId 1246 * The new admin user Identifier, or null. 1247 * @throws ADSContextException 1248 * if something goes wrong. 1249 */ 1250 public void updateAdministrator(Map<AdministratorProperty, Object> adminProperties, String newAdminUserId) 1251 throws ADSContextException 1252 { 1253 LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); 1254 1255 boolean updatePassword = adminProperties.containsKey(AdministratorProperty.PASSWORD); 1256 1257 NamingEnumeration<?> currentPrivileges = null; 1258 try 1259 { 1260 // Entry renaming 1261 if (newAdminUserId != null) 1262 { 1263 Map<AdministratorProperty, Object> newAdminUserProps = new HashMap<>(adminProperties); 1264 newAdminUserProps.put(AdministratorProperty.UID, newAdminUserId); 1265 LdapName newDn = makeDNFromAdministratorProperties(newAdminUserProps); 1266 dirContext.rename(dnCentralAdmin, newDn); 1267 dnCentralAdmin = newDn; 1268 adminProperties.put(AdministratorProperty.UID, newAdminUserId); 1269 } 1270 1271 // if modification includes 'privilege', we have to get first the 1272 // current privileges list. 1273 if (adminProperties.containsKey(AdministratorProperty.PRIVILEGE)) 1274 { 1275 SearchControls sc = new SearchControls(); 1276 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 1277 String[] attList = { "ds-privilege-name" }; 1278 sc.setReturningAttributes(attList); 1279 NamingEnumeration<SearchResult> ne = dirContext.search(dnCentralAdmin, "(objectclass=*)", sc); 1280 try 1281 { 1282 while (ne.hasMore()) 1283 { 1284 currentPrivileges = ne.next().getAttributes().get("ds-privilege-name").getAll(); 1285 } 1286 } 1287 finally 1288 { 1289 handleCloseNamingEnumeration(ne); 1290 } 1291 } 1292 1293 // Replace properties, if needed. 1294 if (adminProperties.size() > 1) 1295 { 1296 BasicAttributes attrs = 1297 makeAttrsFromAdministratorProperties(adminProperties, updatePassword, currentPrivileges); 1298 dirContext.modifyAttributes(dnCentralAdmin, DirContext.REPLACE_ATTRIBUTE, attrs); 1299 } 1300 } 1301 catch (NameNotFoundException x) 1302 { 1303 throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); 1304 } 1305 catch (NoPermissionException x) 1306 { 1307 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 1308 } 1309 catch (NamingException x) 1310 { 1311 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1312 } 1313 finally 1314 { 1315 handleCloseNamingEnumeration(currentPrivileges); 1316 } 1317 } 1318 1319 /** 1320 * Returns the DN of the suffix that contains the administration data. 1321 * 1322 * @return the DN of the suffix that contains the administration data. 1323 */ 1324 public static String getAdministrationSuffixDN() 1325 { 1326 return "cn=admin data"; 1327 } 1328 1329 /** 1330 * This method returns the DN of the entry that corresponds to the given host 1331 * name and installation path. 1332 * 1333 * @param hostname 1334 * the host name. 1335 * @param ipath 1336 * the installation path. 1337 * @return the DN of the entry that corresponds to the given host name and 1338 * installation path. 1339 * @throws ADSContextException 1340 * if something goes wrong. 1341 */ 1342 private static LdapName makeDNFromHostnameAndPath(String hostname, String ipath) throws ADSContextException 1343 { 1344 return nameFromDN("cn=" + Rdn.escapeValue(hostname + "@" + ipath) + "," + getServerContainerDN()); 1345 } 1346 1347 /** 1348 * This method returns the DN of the entry that corresponds to the given host 1349 * name port representation. 1350 * 1351 * @param serverUniqueId 1352 * the host name and port. 1353 * @return the DN of the entry that corresponds to the given host name and 1354 * port. 1355 * @throws ADSContextException 1356 * if something goes wrong. 1357 */ 1358 private static LdapName makeDNFromServerUniqueId(String serverUniqueId) throws ADSContextException 1359 { 1360 return nameFromDN("cn=" + Rdn.escapeValue(serverUniqueId) + "," + getServerContainerDN()); 1361 } 1362 1363 /** 1364 * This method returns the DN of the entry that corresponds to the given 1365 * server group properties. 1366 * 1367 * @param serverGroupProperties 1368 * the server group properties 1369 * @return the DN of the entry that corresponds to the given server group 1370 * properties. 1371 * @throws ADSContextException 1372 * if something goes wrong. 1373 */ 1374 private static LdapName makeDNFromServerGroupProperties(Map<ServerGroupProperty, Object> serverGroupProperties) 1375 throws ADSContextException 1376 { 1377 String serverGroupId = (String) serverGroupProperties.get(ServerGroupProperty.UID); 1378 if (serverGroupId == null) 1379 { 1380 throw new ADSContextException(ErrorType.MISSING_NAME); 1381 } 1382 return nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); 1383 } 1384 1385 /** 1386 * This method returns the DN of the entry that corresponds to the given 1387 * server properties. 1388 * 1389 * @param serverProperties 1390 * the server properties. 1391 * @return the DN of the entry that corresponds to the given server 1392 * properties. 1393 * @throws ADSContextException 1394 * if something goes wrong. 1395 */ 1396 private static LdapName makeDNFromServerProperties(Map<ServerProperty, Object> serverProperties) 1397 throws ADSContextException 1398 { 1399 String serverID = getServerID(serverProperties); 1400 if (serverID != null) 1401 { 1402 return makeDNFromServerUniqueId(serverID); 1403 } 1404 1405 String hostname = getHostname(serverProperties); 1406 try 1407 { 1408 String ipath = getInstallPath(serverProperties); 1409 return makeDNFromHostnameAndPath(hostname, ipath); 1410 } 1411 catch (ADSContextException ace) 1412 { 1413 ServerDescriptor s = ServerDescriptor.createStandalone(serverProperties); 1414 return makeDNFromServerUniqueId(s.getHostPort(true)); 1415 } 1416 } 1417 1418 /** 1419 * This method returns the DN of the entry that corresponds to the given 1420 * server properties. 1421 * 1422 * @param serverProperties 1423 * the server properties. 1424 * @return the DN of the entry that corresponds to the given server 1425 * properties. 1426 * @throws ADSContextException 1427 * if something goes wrong. 1428 */ 1429 public static String getServerIdFromServerProperties(Map<ServerProperty, Object> serverProperties) 1430 throws ADSContextException 1431 { 1432 LdapName ldapName = makeDNFromServerProperties(serverProperties); 1433 String rdn = ldapName.get(ldapName.size() - 1); 1434 int pos = rdn.indexOf("="); 1435 return rdn.substring(pos + 1); 1436 } 1437 1438 /** 1439 * This method returns the DN of the entry that corresponds to the given 1440 * administrator properties. 1441 * 1442 * @param adminProperties 1443 * the administrator properties. 1444 * @return the DN of the entry that corresponds to the given administrator 1445 * properties. 1446 * @throws ADSContextException 1447 * if something goes wrong. 1448 */ 1449 private static LdapName makeDNFromAdministratorProperties(Map<AdministratorProperty, Object> adminProperties) 1450 throws ADSContextException 1451 { 1452 return makeDNFromAdministratorProperties(getAdministratorUID(adminProperties)); 1453 } 1454 1455 /** 1456 * This method returns the DN of the entry that corresponds to the given 1457 * administrator properties. 1458 * 1459 * @param adminUid 1460 * the administrator uid. 1461 * @return the DN of the entry that corresponds to the given administrator 1462 * properties. 1463 * @throws ADSContextException 1464 * if something goes wrong. 1465 */ 1466 private static LdapName makeDNFromAdministratorProperties(String adminUid) throws ADSContextException 1467 { 1468 return nameFromDN(getAdministratorDN(adminUid)); 1469 } 1470 1471 /** 1472 * Returns the attributes for some administrator properties. 1473 * 1474 * @param adminProperties 1475 * the administrator properties. 1476 * @param passwordRequired 1477 * Indicates if the properties should include the password. 1478 * @param currentPrivileges 1479 * The current privilege list or null. 1480 * @return the attributes for the given administrator properties. 1481 * @throws ADSContextException 1482 * if something goes wrong. 1483 */ 1484 private static BasicAttributes makeAttrsFromAdministratorProperties( 1485 Map<AdministratorProperty, Object> adminProperties, boolean passwordRequired, 1486 NamingEnumeration<?> currentPrivileges) throws ADSContextException 1487 { 1488 BasicAttributes attrs = new BasicAttributes(); 1489 Attribute oc = new BasicAttribute("objectclass"); 1490 if (passwordRequired) 1491 { 1492 attrs.put("userPassword", getAdministratorPassword(adminProperties)); 1493 } 1494 oc.add("top"); 1495 oc.add("person"); 1496 attrs.put(oc); 1497 attrs.put("sn", GLOBAL_ADMIN_UID); 1498 if (adminProperties.containsKey(AdministratorProperty.DESCRIPTION)) 1499 { 1500 attrs.put("description", adminProperties.get(AdministratorProperty.DESCRIPTION)); 1501 } 1502 Attribute privilegeAtt; 1503 if (adminProperties.containsKey(AdministratorProperty.PRIVILEGE)) 1504 { 1505 // We assume that privilege strings provided in 1506 // AdministratorProperty.PRIVILEGE 1507 // are valid privileges represented as a LinkedList of string. 1508 privilegeAtt = new BasicAttribute("ds-privilege-name"); 1509 if (currentPrivileges != null) 1510 { 1511 while (currentPrivileges.hasMoreElements()) 1512 { 1513 privilegeAtt.add(currentPrivileges.nextElement().toString()); 1514 } 1515 } 1516 1517 LinkedList<?> privileges = (LinkedList<?>) adminProperties.get(AdministratorProperty.PRIVILEGE); 1518 for (Object o : privileges) 1519 { 1520 String p = o.toString(); 1521 if (p.startsWith("-")) 1522 { 1523 privilegeAtt.remove(p.substring(1)); 1524 } 1525 else 1526 { 1527 privilegeAtt.add(p); 1528 } 1529 } 1530 } 1531 else 1532 { 1533 privilegeAtt = addRootPrivileges(); 1534 } 1535 attrs.put(privilegeAtt); 1536 1537 // Add the RootDNs Password policy so the password do not expire. 1538 attrs.put("ds-pwp-password-policy-dn", "cn=Root Password Policy,cn=Password Policies,cn=config"); 1539 1540 return attrs; 1541 } 1542 1543 /** 1544 * Builds an attribute which contains 'root' privileges. 1545 * 1546 * @return The attribute which contains 'root' privileges. 1547 */ 1548 private static Attribute addRootPrivileges() 1549 { 1550 Attribute privilege = new BasicAttribute("ds-privilege-name"); 1551 privilege.add("bypass-acl"); 1552 privilege.add("modify-acl"); 1553 privilege.add("config-read"); 1554 privilege.add("config-write"); 1555 privilege.add("ldif-import"); 1556 privilege.add("ldif-export"); 1557 privilege.add("backend-backup"); 1558 privilege.add("backend-restore"); 1559 privilege.add("server-shutdown"); 1560 privilege.add("server-restart"); 1561 privilege.add("disconnect-client"); 1562 privilege.add("cancel-request"); 1563 privilege.add("password-reset"); 1564 privilege.add("update-schema"); 1565 privilege.add("privilege-change"); 1566 privilege.add("unindexed-search"); 1567 privilege.add("subentry-write"); 1568 privilege.add("changelog-read"); 1569 return privilege; 1570 } 1571 1572 /** 1573 * Returns the attributes for some server properties. 1574 * 1575 * @param serverProperties 1576 * the server properties. 1577 * @param addObjectClass 1578 * Indicates if the object class has to be added. 1579 * @return the attributes for the given server properties. 1580 */ 1581 private static BasicAttributes makeAttrsFromServerProperties(Map<ServerProperty, Object> serverProperties, 1582 boolean addObjectClass) 1583 { 1584 BasicAttributes result = new BasicAttributes(); 1585 1586 // Transform 'properties' into 'attributes' 1587 for (ServerProperty prop : serverProperties.keySet()) 1588 { 1589 Attribute attr = makeAttrFromServerProperty(prop, serverProperties.get(prop)); 1590 if (attr != null) 1591 { 1592 result.put(attr); 1593 } 1594 } 1595 if (addObjectClass) 1596 { 1597 // Add the objectclass attribute value 1598 // TODO: use another structural objectclass 1599 Attribute oc = new BasicAttribute("objectclass"); 1600 oc.add("top"); 1601 oc.add("ds-cfg-branch"); 1602 oc.add("extensibleobject"); 1603 result.put(oc); 1604 } 1605 return result; 1606 } 1607 1608 /** 1609 * Returns the attribute for a given server property. 1610 * 1611 * @param property 1612 * the server property. 1613 * @param value 1614 * the value. 1615 * @return the attribute for a given server property. 1616 */ 1617 private static Attribute makeAttrFromServerProperty(ServerProperty property, Object value) 1618 { 1619 Attribute result; 1620 1621 switch (property) 1622 { 1623 case INSTANCE_PUBLIC_KEY_CERTIFICATE: 1624 result = null; // used in separate instance key entry 1625 break; 1626 case GROUPS: 1627 result = new BasicAttribute(ServerProperty.GROUPS.getAttributeName()); 1628 for (Object o : ((Set<?>) value)) 1629 { 1630 result.add(o); 1631 } 1632 break; 1633 default: 1634 result = new BasicAttribute(property.getAttributeName(), value); 1635 } 1636 return result; 1637 } 1638 1639 /** 1640 * Returns the attributes for some server group properties. 1641 * 1642 * @param serverGroupProperties 1643 * the server group properties. 1644 * @return the attributes for the given server group properties. 1645 */ 1646 private static BasicAttributes makeAttrsFromServerGroupProperties( 1647 Map<ServerGroupProperty, Object> serverGroupProperties) 1648 { 1649 BasicAttributes result = new BasicAttributes(); 1650 1651 // Transform 'properties' into 'attributes' 1652 for (ServerGroupProperty prop : serverGroupProperties.keySet()) 1653 { 1654 Attribute attr = makeAttrFromServerGroupProperty(prop, serverGroupProperties.get(prop)); 1655 if (attr != null) 1656 { 1657 result.put(attr); 1658 } 1659 } 1660 return result; 1661 } 1662 1663 /** 1664 * Returns the attributes for some server group properties. 1665 * 1666 * @param serverGroupProperties 1667 * the server group properties. 1668 * @return the attributes for the given server group properties. 1669 */ 1670 private static BasicAttributes makeAttrsFromServerGroupProperties(Set<ServerGroupProperty> serverGroupProperties) 1671 { 1672 BasicAttributes result = new BasicAttributes(); 1673 1674 // Transform 'properties' into 'attributes' 1675 for (ServerGroupProperty prop : serverGroupProperties) 1676 { 1677 Attribute attr = makeAttrFromServerGroupProperty(prop, null); 1678 if (attr != null) 1679 { 1680 result.put(attr); 1681 } 1682 } 1683 return result; 1684 } 1685 1686 /** 1687 * Returns the attribute for a given server group property. 1688 * 1689 * @param property 1690 * the server group property. 1691 * @param value 1692 * the value. 1693 * @return the attribute for a given server group property. 1694 */ 1695 private static Attribute makeAttrFromServerGroupProperty(ServerGroupProperty property, Object value) 1696 { 1697 switch (property) 1698 { 1699 case MEMBERS: 1700 Attribute result = new BasicAttribute(ServerGroupProperty.MEMBERS.getAttributeName()); 1701 for (Object o : ((Set<?>) value)) 1702 { 1703 result.add(o); 1704 } 1705 return result; 1706 default: 1707 return new BasicAttribute(property.getAttributeName(), value); 1708 } 1709 } 1710 1711 /** 1712 * Returns the properties of a server group for some LDAP attributes. 1713 * 1714 * @param attrs 1715 * the LDAP attributes. 1716 * @return the properties of a server group for some LDAP attributes. 1717 * @throws ADSContextException 1718 * if something goes wrong. 1719 */ 1720 private Map<ServerGroupProperty, Object> makePropertiesFromServerGroupAttrs(Attributes attrs) 1721 throws ADSContextException 1722 { 1723 Map<ServerGroupProperty, Object> result = new HashMap<>(); 1724 try 1725 { 1726 for (ServerGroupProperty prop : ServerGroupProperty.values()) 1727 { 1728 Attribute attr = attrs.get(prop.getAttributeName()); 1729 if (attr == null) 1730 { 1731 continue; 1732 } 1733 Object value; 1734 1735 if (attr.size() >= 1 && MULTIVALUED_SERVER_GROUP_PROPERTIES.contains(prop)) 1736 { 1737 Set<String> set = new HashSet<>(); 1738 NamingEnumeration<?> ae = attr.getAll(); 1739 try 1740 { 1741 while (ae.hasMore()) 1742 { 1743 set.add((String) ae.next()); 1744 } 1745 } 1746 finally 1747 { 1748 ae.close(); 1749 } 1750 value = set; 1751 } 1752 else 1753 { 1754 value = attr.get(0); 1755 } 1756 1757 result.put(prop, value); 1758 } 1759 } 1760 catch (NamingException x) 1761 { 1762 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1763 } 1764 return result; 1765 } 1766 1767 /** 1768 * Returns the properties of a server for some LDAP attributes. 1769 * 1770 * @param attrs 1771 * the LDAP attributes. 1772 * @return the properties of a server for some LDAP attributes. 1773 * @throws ADSContextException 1774 * if something goes wrong. 1775 */ 1776 private Map<ServerProperty, Object> makePropertiesFromServerAttrs(Attributes attrs) throws ADSContextException 1777 { 1778 Map<ServerProperty, Object> result = new HashMap<>(); 1779 try 1780 { 1781 NamingEnumeration<? extends Attribute> ne = attrs.getAll(); 1782 while (ne.hasMore()) 1783 { 1784 Attribute attr = ne.next(); 1785 String attrID = attr.getID(); 1786 Object value; 1787 1788 if (attrID.endsWith(";binary")) 1789 { 1790 attrID = attrID.substring(0, attrID.lastIndexOf(";binary")); 1791 } 1792 1793 ServerProperty prop = null; 1794 ServerProperty[] props = ServerProperty.values(); 1795 for (int i = 0; i < props.length && prop == null; i++) 1796 { 1797 String v = props[i].getAttributeName(); 1798 if (attrID.equalsIgnoreCase(v)) 1799 { 1800 prop = props[i]; 1801 } 1802 } 1803 if (prop == null) 1804 { 1805 // Do not handle it 1806 } 1807 else 1808 { 1809 if (attr.size() >= 1 && MULTIVALUED_SERVER_PROPERTIES.contains(prop)) 1810 { 1811 Set<String> set = new HashSet<>(); 1812 NamingEnumeration<?> ae = attr.getAll(); 1813 try 1814 { 1815 while (ae.hasMore()) 1816 { 1817 set.add((String) ae.next()); 1818 } 1819 } 1820 finally 1821 { 1822 ae.close(); 1823 } 1824 value = set; 1825 } 1826 else 1827 { 1828 value = attr.get(0); 1829 } 1830 1831 result.put(prop, value); 1832 } 1833 } 1834 } 1835 catch (NamingException x) 1836 { 1837 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1838 } 1839 return result; 1840 } 1841 1842 /** 1843 * Returns the properties of an administrator for some rdn and LDAP 1844 * attributes. 1845 * 1846 * @param rdn 1847 * the RDN. 1848 * @param attrs 1849 * the LDAP attributes. 1850 * @return the properties of an administrator for the given rdn and LDAP 1851 * attributes. 1852 * @throws ADSContextException 1853 * if something goes wrong. 1854 */ 1855 private Map<AdministratorProperty, Object> makePropertiesFromAdministratorAttrs(String rdn, Attributes attrs) 1856 throws ADSContextException 1857 { 1858 Map<AdministratorProperty, Object> result = new HashMap<>(); 1859 LdapName nameObj; 1860 nameObj = nameFromDN(rdn); 1861 String dn = nameObj + "," + getAdministratorContainerDN(); 1862 result.put(AdministratorProperty.ADMINISTRATOR_DN, dn); 1863 NamingEnumeration<? extends Attribute> ne = null; 1864 try 1865 { 1866 ne = attrs.getAll(); 1867 while (ne.hasMore()) 1868 { 1869 Attribute attr = ne.next(); 1870 String attrID = attr.getID(); 1871 Object value; 1872 1873 if ("cn".equalsIgnoreCase(attrID)) 1874 { 1875 value = attr.get(0); 1876 result.put(AdministratorProperty.UID, value); 1877 } 1878 else if ("userpassword".equalsIgnoreCase(attrID)) 1879 { 1880 value = new String((byte[]) attr.get()); 1881 result.put(AdministratorProperty.PASSWORD, value); 1882 } 1883 else if ("description".equalsIgnoreCase(attrID)) 1884 { 1885 value = attr.get(0); 1886 result.put(AdministratorProperty.DESCRIPTION, value); 1887 } 1888 else if ("ds-privilege-name".equalsIgnoreCase(attrID)) 1889 { 1890 LinkedHashSet<String> privileges = new LinkedHashSet<>(); 1891 NamingEnumeration<?> attValueList = attr.getAll(); 1892 while (attValueList.hasMoreElements()) 1893 { 1894 privileges.add(attValueList.next().toString()); 1895 } 1896 result.put(AdministratorProperty.PRIVILEGE, privileges); 1897 } 1898 } 1899 } 1900 catch (NamingException x) 1901 { 1902 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 1903 } 1904 finally 1905 { 1906 handleCloseNamingEnumeration(ne); 1907 } 1908 1909 return result; 1910 } 1911 1912 /** 1913 * Returns the parent entry of the server entries. 1914 * 1915 * @return the parent entry of the server entries. 1916 */ 1917 public static String getServerContainerDN() 1918 { 1919 return "cn=Servers," + getAdministrationSuffixDN(); 1920 } 1921 1922 /** 1923 * Returns the parent entry of the administrator entries. 1924 * 1925 * @return the parent entry of the administrator entries. 1926 */ 1927 public static String getAdministratorContainerDN() 1928 { 1929 return "cn=Administrators," + getAdministrationSuffixDN(); 1930 } 1931 1932 /** 1933 * Returns the parent entry of the server group entries. 1934 * 1935 * @return the parent entry of the server group entries. 1936 */ 1937 public static String getServerGroupContainerDN() 1938 { 1939 return "cn=Server Groups," + getAdministrationSuffixDN(); 1940 } 1941 1942 /** 1943 * Returns the all server group entry DN. 1944 * 1945 * @return the all server group entry DN. 1946 */ 1947 private static String getAllServerGroupDN() 1948 { 1949 return "cn=" + Rdn.escapeValue(ALL_SERVERGROUP_NAME) + "," + getServerGroupContainerDN(); 1950 } 1951 1952 /** 1953 * Returns the host name for the given properties. 1954 * 1955 * @param serverProperties 1956 * the server properties. 1957 * @return the host name for the given properties. 1958 * @throws ADSContextException 1959 * if the host name could not be found or its value is not valid. 1960 */ 1961 private static String getHostname(Map<ServerProperty, Object> serverProperties) throws ADSContextException 1962 { 1963 String result = (String) serverProperties.get(ServerProperty.HOST_NAME); 1964 if (result == null) 1965 { 1966 throw new ADSContextException(ErrorType.MISSING_HOSTNAME); 1967 } 1968 else if (result.length() == 0) 1969 { 1970 throw new ADSContextException(ErrorType.NOVALID_HOSTNAME); 1971 } 1972 return result; 1973 } 1974 1975 /** 1976 * Returns the Server ID for the given properties. 1977 * 1978 * @param serverProperties 1979 * the server properties. 1980 * @return the server ID for the given properties or null. 1981 */ 1982 private static String getServerID(Map<ServerProperty, Object> serverProperties) 1983 { 1984 String result = (String) serverProperties.get(ServerProperty.ID); 1985 if (result != null && result.length() == 0) 1986 { 1987 result = null; 1988 } 1989 return result; 1990 } 1991 1992 /** 1993 * Returns the install path for the given properties. 1994 * 1995 * @param serverProperties 1996 * the server properties. 1997 * @return the install path for the given properties. 1998 * @throws ADSContextException 1999 * if the install path could not be found or its value is not valid. 2000 */ 2001 private static String getInstallPath(Map<ServerProperty, Object> serverProperties) throws ADSContextException 2002 { 2003 String result = (String) serverProperties.get(ServerProperty.INSTANCE_PATH); 2004 if (result == null) 2005 { 2006 throw new ADSContextException(ErrorType.MISSING_IPATH); 2007 } 2008 else if (result.length() == 0) 2009 { 2010 throw new ADSContextException(ErrorType.NOVALID_IPATH); 2011 } 2012 return result; 2013 } 2014 2015 /** 2016 * Returns the Administrator UID for the given properties. 2017 * 2018 * @param adminProperties 2019 * the server properties. 2020 * @return the Administrator UID for the given properties. 2021 * @throws ADSContextException 2022 * if the administrator UID could not be found. 2023 */ 2024 private static String getAdministratorUID(Map<AdministratorProperty, Object> adminProperties) 2025 throws ADSContextException 2026 { 2027 String result = (String) adminProperties.get(AdministratorProperty.UID); 2028 if (result == null) 2029 { 2030 throw new ADSContextException(ErrorType.MISSING_ADMIN_UID); 2031 } 2032 return result; 2033 } 2034 2035 /** 2036 * Returns the Administrator password for the given properties. 2037 * 2038 * @param adminProperties 2039 * the server properties. 2040 * @return the Administrator password for the given properties. 2041 * @throws ADSContextException 2042 * if the administrator password could not be found. 2043 */ 2044 private static String getAdministratorPassword(Map<AdministratorProperty, Object> adminProperties) 2045 throws ADSContextException 2046 { 2047 String result = (String) adminProperties.get(AdministratorProperty.PASSWORD); 2048 if (result == null) 2049 { 2050 throw new ADSContextException(ErrorType.MISSING_ADMIN_PASSWORD); 2051 } 2052 return result; 2053 } 2054 2055 // LDAP utilities 2056 /** 2057 * Returns the LdapName object for the given dn. 2058 * 2059 * @param dn 2060 * the DN. 2061 * @return the LdapName object for the given dn. 2062 * @throws ADSContextException 2063 * if a valid LdapName could not be retrieved for the given dn. 2064 */ 2065 private static LdapName nameFromDN(String dn) throws ADSContextException 2066 { 2067 try 2068 { 2069 return new LdapName(dn); 2070 } 2071 catch (InvalidNameException x) 2072 { 2073 logger.error(LocalizableMessage.raw("Error parsing dn " + dn, x)); 2074 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2075 } 2076 } 2077 2078 /** 2079 * Returns the String rdn for the given search result name. 2080 * 2081 * @param rdnName 2082 * the search result name. 2083 * @return the String rdn for the given search result name. 2084 * @throws ADSContextException 2085 * if a valid String rdn could not be retrieved for the given result 2086 * name. 2087 */ 2088 private static String getRdn(String rdnName) throws ADSContextException 2089 { 2090 // Transform the JNDI name into a RDN string 2091 try 2092 { 2093 return new CompositeName(rdnName).get(0); 2094 } 2095 catch (InvalidNameException x) 2096 { 2097 logger.error(LocalizableMessage.raw("Error parsing rdn " + rdnName, x)); 2098 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2099 } 2100 } 2101 2102 /** 2103 * Tells whether an entry with the provided DN exists. 2104 * 2105 * @param dn 2106 * the DN to check. 2107 * @return <CODE>true</CODE> if the entry exists and <CODE>false</CODE> if it 2108 * does not. 2109 * @throws ADSContextException 2110 * if an error occurred while checking if the entry exists or not. 2111 */ 2112 private boolean isExistingEntry(LdapName dn) throws ADSContextException 2113 { 2114 try 2115 { 2116 SearchControls sc = new SearchControls(); 2117 2118 sc.setSearchScope(SearchControls.OBJECT_SCOPE); 2119 sc.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); 2120 NamingEnumeration<SearchResult> sr = getDirContext().search(dn, "(objectclass=*)", sc); 2121 boolean result = false; 2122 try 2123 { 2124 while (sr.hasMore()) 2125 { 2126 sr.next(); 2127 result = true; 2128 } 2129 } 2130 finally 2131 { 2132 sr.close(); 2133 } 2134 return result; 2135 } 2136 catch (NameNotFoundException x) 2137 { 2138 return false; 2139 } 2140 catch (NoPermissionException x) 2141 { 2142 throw new ADSContextException(ErrorType.ACCESS_PERMISSION); 2143 } 2144 catch (javax.naming.NamingException x) 2145 { 2146 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2147 } 2148 } 2149 2150 /** 2151 * Creates a container entry with the given dn. 2152 * 2153 * @param dn 2154 * the entry of the new entry to be created. 2155 * @throws ADSContextException 2156 * if the entry could not be created. 2157 */ 2158 private void createContainerEntry(String dn) throws ADSContextException 2159 { 2160 BasicAttributes attrs = new BasicAttributes(); 2161 Attribute oc = new BasicAttribute("objectclass"); 2162 oc.add("top"); 2163 oc.add("ds-cfg-branch"); 2164 attrs.put(oc); 2165 createEntry(dn, attrs); 2166 } 2167 2168 /** 2169 * Creates the administrator container entry. 2170 * 2171 * @throws ADSContextException 2172 * if the entry could not be created. 2173 */ 2174 private void createAdministratorContainerEntry() throws ADSContextException 2175 { 2176 BasicAttributes attrs = new BasicAttributes(); 2177 Attribute oc = new BasicAttribute("objectclass"); 2178 oc.add("groupofurls"); 2179 attrs.put(oc); 2180 attrs.put("memberURL", "ldap:///" + getAdministratorContainerDN() + "??one?(objectclass=*)"); 2181 attrs.put("description", "Group of identities which have full access."); 2182 createEntry(getAdministratorContainerDN(), attrs); 2183 } 2184 2185 /** 2186 * Creates the top container entry. 2187 * 2188 * @throws ADSContextException 2189 * if the entry could not be created. 2190 */ 2191 private void createTopContainerEntry() throws ADSContextException 2192 { 2193 BasicAttributes attrs = new BasicAttributes(); 2194 Attribute oc = new BasicAttribute("objectclass"); 2195 oc.add("top"); 2196 oc.add("ds-cfg-branch"); 2197 attrs.put(oc); 2198 createEntry(getAdministrationSuffixDN(), attrs); 2199 } 2200 2201 /** 2202 * Creates an entry with the provided dn and attributes. 2203 * 2204 * @param dn 2205 * the dn of the entry. 2206 * @param attrs 2207 * the attributes of the entry. 2208 * @throws ADSContextException 2209 * if the entry could not be created. 2210 */ 2211 private void createEntry(String dn, Attributes attrs) throws ADSContextException 2212 { 2213 try 2214 { 2215 DirContext ctx = getDirContext().createSubcontext(nameFromDN(dn), attrs); 2216 ctx.close(); 2217 } 2218 catch (NamingException x) 2219 { 2220 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2221 } 2222 } 2223 2224 /** 2225 * Creates the Administration Suffix. 2226 * 2227 * @param backendName 2228 * the backend name to be used for the Administration Suffix. If this 2229 * value is null the default backendName for the Administration 2230 * Suffix will be used. 2231 * @throws ADSContextException 2232 * if something goes wrong. 2233 */ 2234 public void createAdministrationSuffix(String backendName) throws ADSContextException 2235 { 2236 ADSContextHelper helper = new ADSContextHelper(); 2237 String ben = backendName; 2238 if (backendName == null) 2239 { 2240 ben = getDefaultBackendName(); 2241 } 2242 helper.createAdministrationSuffix(getDirContext(), ben); 2243 } 2244 2245 /** 2246 * Returns the default backend name of the administration data. 2247 * 2248 * @return the default backend name of the administration data. 2249 */ 2250 public static String getDefaultBackendName() 2251 { 2252 return "adminRoot"; 2253 } 2254 2255 /** 2256 * Returns the LDIF file of the administration data. 2257 * 2258 * @return the LDIF file of the administration data. 2259 */ 2260 public static String getAdminLDIFFile() 2261 { 2262 return "config" + File.separator + "admin-backend.ldif"; 2263 } 2264 2265 /** CryptoManager related types, fields, and methods. */ 2266 2267 /** 2268 * Returns the parent entry of the server key entries in ADS. 2269 * 2270 * @return the parent entry of the server key entries in ADS. 2271 */ 2272 public static String getInstanceKeysContainerDN() 2273 { 2274 return "cn=instance keys," + getAdministrationSuffixDN(); 2275 } 2276 2277 /** 2278 * Returns the parent entry of the secret key entries in ADS. 2279 * 2280 * @return the parent entry of the secret key entries in ADS. 2281 */ 2282 public static String getSecretKeysContainerDN() 2283 { 2284 return "cn=secret keys," + getAdministrationSuffixDN(); 2285 } 2286 2287 /** 2288 * Tells whether the provided server is registered in the registry. 2289 * 2290 * @param server 2291 * the server. 2292 * @param registry 2293 * the registry. 2294 * @return <CODE>true</CODE> if the server is registered in the registry and 2295 * <CODE>false</CODE> otherwise. 2296 */ 2297 public static boolean isRegistered(ServerDescriptor server, Set<Map<ADSContext.ServerProperty, Object>> registry) 2298 { 2299 for (Map<ADSContext.ServerProperty, Object> s : registry) 2300 { 2301 ServerDescriptor servInRegistry = ServerDescriptor.createStandalone(s); 2302 if (servInRegistry.getId().equals(server.getId())) 2303 { 2304 return true; 2305 } 2306 } 2307 return false; 2308 } 2309 2310 /** 2311 * Register instance key-pair public-key certificate provided in 2312 * serverProperties: generate a key-id attribute if one is not provided (as 2313 * expected); add an instance key public-key certificate entry for the key 2314 * certificate; and associate the certificate entry with the server entry via 2315 * the key ID attribute. 2316 * 2317 * @param serverProperties 2318 * Properties of the server being registered to which the instance 2319 * key entry belongs. 2320 * @param serverEntryDn 2321 * The server's ADS entry DN. 2322 * @throws NamingException 2323 * In case some JNDI operation fails. 2324 * @throws CryptoManager.CryptoManagerException 2325 * In case there is a problem getting the instance public key 2326 * certificate ID. 2327 */ 2328 private void registerInstanceKeyCertificate(Map<ServerProperty, Object> serverProperties, LdapName serverEntryDn) 2329 throws ADSContextException 2330 { 2331 ADSContextHelper helper = new ADSContextHelper(); 2332 helper.registerInstanceKeyCertificate(dirContext, serverProperties, serverEntryDn); 2333 } 2334 2335 /** 2336 * Return the set of valid (i.e., not tagged as compromised) instance key-pair 2337 * public-key certificate entries in ADS. NOTE: calling this method assumes 2338 * that all the jar files are present in the classpath. 2339 * 2340 * @return The set of valid (i.e., not tagged as compromised) instance 2341 * key-pair public-key certificate entries in ADS represented as a Map 2342 * from ds-cfg-key-id value to ds-cfg-public-key-certificate;binary 2343 * value. Note that the collection might be empty. 2344 * @throws ADSContextException 2345 * in case of problems with the entry search. 2346 * @see org.opends.server.crypto.CryptoManagerImpl#getTrustedCertificates 2347 */ 2348 public Map<String, byte[]> getTrustedCertificates() throws ADSContextException 2349 { 2350 final Map<String, byte[]> certificateMap = new HashMap<>(); 2351 final String baseDNStr = getInstanceKeysContainerDN(); 2352 try 2353 { 2354 ADSContextHelper helper = new ADSContextHelper(); 2355 final LdapName baseDN = new LdapName(baseDNStr); 2356 final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + helper.getOcCryptoInstanceKey() + ")"; 2357 final String FILTER_NOT_COMPROMISED = "(!(" + helper.getAttrCryptoKeyCompromisedTime() + "=*))"; 2358 final String searchFilter = "(&" + FILTER_OC_INSTANCE_KEY + FILTER_NOT_COMPROMISED + ")"; 2359 final SearchControls searchControls = new SearchControls(); 2360 searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); 2361 final String attrIDs[] = 2362 { ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(), 2363 ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName() + ";binary" }; 2364 searchControls.setReturningAttributes(attrIDs); 2365 NamingEnumeration<SearchResult> keyEntries = dirContext.search(baseDN, searchFilter, searchControls); 2366 try 2367 { 2368 while (keyEntries.hasMore()) 2369 { 2370 final SearchResult entry = keyEntries.next(); 2371 final Attributes attrs = entry.getAttributes(); 2372 final Attribute keyIDAttr = attrs.get(attrIDs[0]); 2373 final Attribute keyCertAttr = attrs.get(attrIDs[1]); 2374 if (null == keyIDAttr || null == keyCertAttr) 2375 { 2376 continue;// schema viol. 2377 } 2378 certificateMap.put((String) keyIDAttr.get(), (byte[]) keyCertAttr.get()); 2379 } 2380 } 2381 finally 2382 { 2383 try 2384 { 2385 keyEntries.close(); 2386 } 2387 catch (Exception ex) 2388 { 2389 logger.warn(LocalizableMessage.raw("Unexpected error closing enumeration on ADS key pairs", ex)); 2390 } 2391 } 2392 } 2393 catch (NamingException x) 2394 { 2395 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); 2396 } 2397 return certificateMap; 2398 } 2399 2400 /** 2401 * Merge the contents of this ADSContext with the contents of the provided 2402 * ADSContext. Note that only the contents of this ADSContext will be updated. 2403 * 2404 * @param adsCtx 2405 * the other ADSContext to merge the contents with. 2406 * @throws ADSContextException 2407 * if there was an error during the merge. 2408 */ 2409 public void mergeWithRegistry(ADSContext adsCtx) throws ADSContextException 2410 { 2411 try 2412 { 2413 mergeAdministrators(adsCtx); 2414 mergeServerGroups(adsCtx); 2415 mergeServers(adsCtx); 2416 } 2417 catch (ADSContextException adce) 2418 { 2419 LocalizableMessage msg = ERR_ADS_MERGE.get(ConnectionUtils.getHostPort(getDirContext()), 2420 ConnectionUtils.getHostPort(adsCtx.getDirContext()), adce.getMessageObject()); 2421 throw new ADSContextException(ErrorType.ERROR_MERGING, msg, adce); 2422 } 2423 } 2424 2425 /** 2426 * Merge the administrator contents of this ADSContext with the contents of 2427 * the provided ADSContext. Note that only the contents of this ADSContext 2428 * will be updated. 2429 * 2430 * @param adsCtx 2431 * the other ADSContext to merge the contents with. 2432 * @throws ADSContextException 2433 * if there was an error during the merge. 2434 */ 2435 private void mergeAdministrators(ADSContext adsCtx) throws ADSContextException 2436 { 2437 Set<Map<AdministratorProperty, Object>> admins2 = adsCtx.readAdministratorRegistry(); 2438 SortedSet<String> notDefinedAdmins = new TreeSet<>(); 2439 for (Map<AdministratorProperty, Object> admin2 : admins2) 2440 { 2441 String uid = (String) admin2.get(AdministratorProperty.UID); 2442 if (!isAdministratorAlreadyRegistered(uid)) 2443 { 2444 notDefinedAdmins.add(uid); 2445 } 2446 } 2447 if (!notDefinedAdmins.isEmpty()) 2448 { 2449 LocalizableMessage msg = ERR_ADS_ADMINISTRATOR_MERGE.get( 2450 ConnectionUtils.getHostPort(adsCtx.getDirContext()), ConnectionUtils.getHostPort(getDirContext()), 2451 joinAsString(Constants.LINE_SEPARATOR, notDefinedAdmins), ConnectionUtils.getHostPort(getDirContext())); 2452 throw new ADSContextException(ErrorType.ERROR_MERGING, msg, null); 2453 } 2454 } 2455 2456 /** 2457 * Merge the groups contents of this ADSContext with the contents of the 2458 * provided ADSContext. Note that only the contents of this ADSContext will be 2459 * updated. 2460 * 2461 * @param adsCtx 2462 * the other ADSContext to merge the contents with. 2463 * @throws ADSContextException 2464 * if there was an error during the merge. 2465 */ 2466 private void mergeServerGroups(ADSContext adsCtx) throws ADSContextException 2467 { 2468 Set<Map<ServerGroupProperty, Object>> serverGroups1 = readServerGroupRegistry(); 2469 Set<Map<ServerGroupProperty, Object>> serverGroups2 = adsCtx.readServerGroupRegistry(); 2470 2471 for (Map<ServerGroupProperty, Object> group2 : serverGroups2) 2472 { 2473 Map<ServerGroupProperty, Object> group1 = null; 2474 String uid2 = (String) group2.get(ServerGroupProperty.UID); 2475 for (Map<ServerGroupProperty, Object> gr : serverGroups1) 2476 { 2477 String uid1 = (String) gr.get(ServerGroupProperty.UID); 2478 if (uid1.equalsIgnoreCase(uid2)) 2479 { 2480 group1 = gr; 2481 break; 2482 } 2483 } 2484 2485 if (group1 != null) 2486 { 2487 // Merge the members, keep the description on this ADS. 2488 Set<String> member1List = getServerGroupMemberList(uid2); 2489 if (member1List == null) 2490 { 2491 member1List = new HashSet<>(); 2492 } 2493 Set<String> member2List = adsCtx.getServerGroupMemberList(uid2); 2494 if (member2List != null && !member2List.isEmpty()) 2495 { 2496 member1List.addAll(member2List); 2497 Map<ServerGroupProperty, Object> newProperties = new HashMap<>(); 2498 newProperties.put(ServerGroupProperty.MEMBERS, member1List); 2499 updateServerGroup(uid2, newProperties); 2500 } 2501 } 2502 else 2503 { 2504 createServerGroup(group2); 2505 } 2506 } 2507 } 2508 2509 /** 2510 * Merge the server contents of this ADSContext with the contents of the 2511 * provided ADSContext. Note that only the contents of this ADSContext will be 2512 * updated. 2513 * 2514 * @param adsCtx 2515 * the other ADSContext to merge the contents with. 2516 * @throws ADSContextException 2517 * if there was an error during the merge. 2518 */ 2519 private void mergeServers(ADSContext adsCtx) throws ADSContextException 2520 { 2521 for (Map<ServerProperty, Object> server2 : adsCtx.readServerRegistry()) 2522 { 2523 if (!isServerAlreadyRegistered(server2)) 2524 { 2525 registerServer(server2); 2526 } 2527 } 2528 } 2529 2530 private void handleCloseNamingEnumeration(NamingEnumeration<?> ne) throws ADSContextException 2531 { 2532 if (ne != null) 2533 { 2534 try 2535 { 2536 ne.close(); 2537 } 2538 catch (NamingException ex) 2539 { 2540 throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, ex); 2541 } 2542 } 2543 } 2544}