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