EmbeddedOpenDS.java revision bee2440354b4bc8796e1de0b6cbd60e1f68deba0
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: EmbeddedOpenDS.java,v 1.27 2010/01/15 01:22:39 goodearth Exp $
*
* Portions Copyrighted 2010-2015 ForgeRock AS.
*/
package com.sun.identity.setup;
import com.iplanet.am.util.SystemProperties;
import com.sun.identity.common.ShutdownManager;
import com.sun.identity.shared.Constants;
import com.sun.identity.shared.debug.Debug;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.ServletContext;
import org.forgerock.openam.utils.IOUtils;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.Attributes;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.Connections;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.LDAPOptions;
import org.forgerock.opendj.ldap.Modification;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.util.thread.listener.ShutdownListener;
import org.forgerock.util.thread.listener.ShutdownPriority;
import org.opends.messages.Message;
import org.opends.server.core.DirectoryServer;
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.extensions.SaltedSHA512PasswordStorageScheme;
import org.opends.server.tools.InstallDS;
import org.opends.server.tools.RebuildIndex;
import org.opends.server.tools.dsconfig.DSConfig;
import org.opends.server.tools.dsreplication.ReplicationCliMain;
import org.opends.server.types.DirectoryEnvironmentConfig;
import org.opends.server.util.EmbeddedUtils;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.TimeThread;
// OpenDS, now OpenDJ, does not have APIs to install and setup replication yet
/**
* This class encapsulates all <code>OpenDJ</code> dependencies.
* All the interfaces are invoked from <code>AMSetupServlet</code> class
* at different points : initial installation, normal startup and
* normal shutdown of the embedded <code>OpenDJ</code> instance.
*/
public class EmbeddedOpenDS {
private static final String OPENDS_1x_VER = "5097";
private static final String OPENDS_230B2_VER = "6500";
private static final String OPENDS_UPGRADE_DIR = "/config/upgrade/";
private static final String OPENDS_CONFIG_LDIF = "config.ldif";
private static boolean serverStarted = false;
private static ConnectionFactory factory;
/**
* Returns <code>true</code> if the server has already been started.
*
* @return <code>true</code> if the server has already been started.
*/
public static boolean isStarted() {
return serverStarted;
}
/**
* Sets up embedded OpenDJ during initial installation :
* <ul>
* <li>lays out the filesystem directory structure needed by OpenDJ
* <li>sets up port numbers for ldap and replication
* <li>invokes <code>EmbeddedUtils</code> to start the embedded server.
* </ul>
*
* @param map Map of properties collected by the configurator.
* @param servletCtx Servlet Context to read deployed war contents.
* @throws Exception on encountering errors.
*/
public static void setup(Map map, ServletContext servletCtx)
throws Exception {
// Determine Cipher to be used
SetupProgress.reportStart("emb.installingemb.null", null);
String xform = getSupportedTransformation();
if (xform == null) {
SetupProgress.reportEnd("emb.noxform", null);
throw new Exception("No transformation found");
} else {
map.put(OPENDS_TRANSFORMATION, xform);
Object[] params = {xform};
SetupProgress.reportEnd("emb.success.param", params);
}
String basedir = (String) map.get(SetupConstants.CONFIG_VAR_BASE_DIR);
String odsRoot = getOpenDJBaseDir(map);
new File(basedir).mkdir();
new File(odsRoot).mkdir();
SetupProgress.reportStart("emb.opends.start", null);
String zipFileName = "/WEB-INF/template/opendj/opendj.zip";
BufferedInputStream bin = new BufferedInputStream(
AMSetupUtils.getResourceAsStream(servletCtx, zipFileName), 10000);
BufferedOutputStream bout = new BufferedOutputStream(
new FileOutputStream(odsRoot + "/opendj.zip"), 10000);
try {
while (bin.available() > 0) {
bout.write(bin.read());
}
} catch (IOException ioe) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setup(): Error copying zip file", ioe);
throw ioe;
} finally {
IOUtils.closeIfNotNull(bin);
IOUtils.closeIfNotNull(bout);
}
ZipFile opendsZip = new ZipFile(odsRoot + "/opendj.zip");
Enumeration files = opendsZip.entries();
// Process the OpenDJ Archive File.
while (files.hasMoreElements()) {
ZipEntry file = (ZipEntry) files.nextElement();
File f = new File(odsRoot + "/" + file.getName());
if (file.isDirectory()) {
f.mkdir();
continue;
}
BufferedInputStream is =
new BufferedInputStream(opendsZip.getInputStream(file), 10000);
BufferedOutputStream fos =
new BufferedOutputStream(new java.io.FileOutputStream(f), 10000);
try {
while (is.available() > 0) {
fos.write(is.read());
}
} catch (IOException ioe) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setup(): Error loading ldifs", ioe);
throw ioe;
} finally {
IOUtils.closeIfNotNull(is);
IOUtils.closeIfNotNull(fos);
} // End of Inner Finally.
if (file.getName().endsWith("sh") || file.getName().startsWith("bin")) {
f.setExecutable(true);
}
} // End of File Elements from Zip for OpenDJ.
// create tag swapped files
String[] tagSwapFiles = {
"template/ldif/openam_suffix.ldif.template"
};
for (int i = 0; i < tagSwapFiles.length; i++) {
String fileIn = odsRoot + "/" + tagSwapFiles[i];
FileReader fin = new FileReader(fileIn);
StringBuilder sbuf = new StringBuilder();
char[] cbuf = new char[1024];
int len;
while ((len = fin.read(cbuf)) > 0) {
sbuf.append(cbuf, 0, len);
}
FileWriter fout = null;
try {
fout = new FileWriter(odsRoot + "/" +
tagSwapFiles[i].substring(0, tagSwapFiles[i].indexOf(".template")));
String inpStr = sbuf.toString();
fout.write(ServicesDefaultValues.tagSwap(inpStr));
} catch (IOException e) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setup(): Error tag swapping files", e);
throw e;
} finally {
IOUtils.closeIfNotNull(fin);
IOUtils.closeIfNotNull(fout);
}
}
// remove zip
File toDelete = new File(odsRoot + "/opendj.zip");
if (!toDelete.delete()) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setup(): Unable to delete zip file:" +toDelete.getAbsolutePath());
}
SetupProgress.reportEnd("emb.opends.stop", null);
// now setup OpenDJ
System.setProperty("org.opends.quicksetup.Root", odsRoot);
System.setProperty(ServerConstants.PROPERTY_SERVER_ROOT, odsRoot);
System.setProperty(ServerConstants.PROPERTY_INSTANCE_ROOT, odsRoot);
EmbeddedOpenDS.setupOpenDS(map);
Object[] params = {odsRoot};
SetupProgress.reportStart("emb.installingemb", params);
EmbeddedOpenDS.startServer(odsRoot);
// Check: If adding a new server to a existing cluster
if (!isMultiServer(map)) {
// Default: single / first server.
SetupProgress.reportStart("emb.creatingfamsuffix", null);
int ret = EmbeddedOpenDS.loadLDIF(map, odsRoot, odsRoot + "/ldif/openam_suffix.ldif");
if (ret == 0) {
SetupProgress.reportEnd("emb.creatingfamsuffix.success", null);
} else {
Object[] error = {Integer.toString(ret)};
SetupProgress.reportEnd("emb.creatingfamsuffix.failure", error);
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setupOpenDS. Error loading OpenAM suffix");
throw new ConfiguratorException(
"emb.creatingfamsuffix.failure");
}
} // End of single / first server check.
}
/**
* Helper Method to Copy from one Byte Channel to another.
* @param from
* @param to
* @throws IOException
*/
protected static void channelCopy(ReadableByteChannel from, WritableByteChannel to)
throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
try {
// Read
while (from.read(buffer) != -1) {
buffer.flip();
to.write(buffer);
buffer.compact();
}
// Flip the Buffer
buffer.flip();
// Write
while (buffer.hasRemaining()) {
to.write(buffer);
} // End of While Loop
} finally {
// Handle In Channel Closure
if (from != null) {
try {
from.close();
} catch (Exception ex) {
//No handling required
}
}
// Handle Out Channel Closure
if (to != null) {
try {
to.close();
} catch (Exception ex) {
//No handling required
}
}
} // End of Finally
}
/**
* Preferred transforms
*/
final static String[] preferredTransforms =
{
"RSA/ECB/OAEPWithSHA1AndMGF1Padding", // Sun JCE
"RSA/ /OAEPPADDINGSHA-1", // IBMJCE
"RSA/ECB/OAEPWithSHA-1AndMGF-1Padding", // BouncyCastle
"RSA/ECB/PKCS1Padding" // Fallback
};
final static String OPENDS_TRANSFORMATION = "OPENDS_TRANSFORMATION";
/**
* Traverses <code>preferredTransforms</code> list in order to
* find a Cipher supported by underlying JCE providers.`
*
* @returns transformation available.
*/
private static String getSupportedTransformation() {
for (int i = 0; i < preferredTransforms.length; i++) {
try {
Cipher.getInstance(preferredTransforms[i]);
return preferredTransforms[i];
} catch (NoSuchAlgorithmException ex) {
} catch (NoSuchPaddingException ex) {
}
}
return null;
}
/**
* Runs the OpenDJ setup command to create our instance
*
* @param map The map of configuration options
* @throws Exception upon encountering errors.
*/
public static void setupOpenDS(Map map)
throws Exception {
SetupProgress.reportStart("emb.setupopends", null);
int ret = runOpenDSSetup(map);
if (ret == 0) {
SetupProgress.reportEnd("emb.setupopends.success", null);
Debug.getInstance(SetupConstants.DEBUG_NAME).message(
"EmbeddedOpenDS.setupOpenDS: OpenDS setup succeeded.");
} else {
Object[] params = {Integer.toString(ret)};
SetupProgress.reportEnd("emb.setupopends.failed.param", params);
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setupOpenDS. Error setting up OpenDS");
throw new ConfiguratorException(
"configurator.embsetupopendsfailed");
}
}
/**
* Runs the OpenDJ setup command like this:
* $ ./setup --cli --adminConnectorPort 4444
* --baseDN dc=openam,dc=forgerock,dc=org --rootUserDN "cn=directory manager"
* --doNotStart --ldapPort 50389 --skipPortCheck --rootUserPassword xxxxxxx
* --jmxPort 1689 --no-prompt
*
* @param map Map of properties collected by the configurator.
* @return status : 0 == success, !0 == failure
*/
public static int runOpenDSSetup(Map map) {
String[] setupCmd = {
"--cli", // 0
"--adminConnectorPort", // 1
"4444", // 2
"--baseDN", // 3
Constants.DEFAULT_ROOT_SUFFIX, // 4
"--rootUserDN", // 5
"cn=Directory Manager", // 6
"--ldapPort", // 7
"50389", // 8
"--skipPortCheck", // 9
"--rootUserPassword", // 10
"xxxxxxx", // 11
"--jmxPort", // 12
"1689", // 13
"--no-prompt", // 14
"--doNotStart", // 15
"--hostname", // 16
"hostname", // 17
"--noPropertiesFile" // 18
};
setupCmd[2] = (String) map.get(SetupConstants.CONFIG_VAR_DIRECTORY_ADMIN_SERVER_PORT);
setupCmd[4] = (String) map.get(SetupConstants.CONFIG_VAR_ROOT_SUFFIX);
setupCmd[6] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_DN);
setupCmd[8] = (String) map.get(SetupConstants.CONFIG_VAR_DIRECTORY_SERVER_PORT);
setupCmd[13] = (String) map.get(SetupConstants.CONFIG_VAR_DIRECTORY_JMX_SERVER_PORT);
setupCmd[17] = getOpenDJHostName(map);
Object[] params = {concat(setupCmd)};
SetupProgress.reportStart("emb.setupcommand", params);
setupCmd[11] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
int ret = InstallDS.mainCLI(
setupCmd,
SetupProgress.getOutputStream(),
SetupProgress.getOutputStream(),
null);
if (ret == 0) {
SetupProgress.reportEnd("emb.success", null);
} else {
SetupProgress.reportEnd("emb.failed", null);
}
return ret;
}
/**
* Starts the embedded <code>OpenDJ</code> instance.
*
* @param odsRoot File system directory where <code>OpenDJ</code>
* is installed.
* @throws Exception upon encountering errors.
*/
public static void startServer(String odsRoot) throws Exception {
if (isStarted()) {
return;
}
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
debug.message("EmbeddedOpenDS.startServer(" + odsRoot + ")");
DirectoryEnvironmentConfig config = new DirectoryEnvironmentConfig();
config.setServerRoot(new File(odsRoot));
config.setForceDaemonThreads(true);
config.setConfigClass(ConfigFileHandler.class);
config.setConfigFile(new File(odsRoot + "/config", "config.ldif"));
debug.message("EmbeddedOpenDS.startServer:starting DS Server...");
EmbeddedUtils.startServer(config);
debug.message("...EmbeddedOpenDS.startServer:DS Server started.");
int sleepcount = 0;
while (!EmbeddedUtils.isRunning() && (sleepcount < 60)) {
sleepcount++;
SetupProgress.reportStart("emb.waitingforstarted", null);
Thread.sleep(1000);
}
if (EmbeddedUtils.isRunning()) {
SetupProgress.reportEnd("emb.success", null);
} else {
SetupProgress.reportEnd("emb.failed", null);
}
serverStarted = true;
ShutdownManager shutdownMan = com.sun.identity.common.ShutdownManager.getInstance();
shutdownMan.addShutdownListener(new ShutdownListener() {
public void shutdown() {
try {
shutdownServer("Graceful Shutdown");
} catch (Exception ex) {
Debug debug = Debug.getInstance(
SetupConstants.DEBUG_NAME);
debug.error("EmbeddedOpenDS:shutdown hook failed",
ex);
}
}
}, ShutdownPriority.LOWEST);
}
/**
* Gracefully shuts down the embedded OpenDJ instance.
*
* @param reason string representing reason why shutdown was called.
* @throws Exception on encountering errors.
*/
public static void shutdownServer(String reason) throws Exception {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
if (isStarted()) {
debug.message("EmbeddedOpenDS.shutdown server...");
DirectoryServer.shutDown(
"com.sun.identity.setup.EmbeddedOpenDS",
Message.EMPTY);
int sleepcount = 0;
while (DirectoryServer.isRunning() && (sleepcount < 60)) {
sleepcount++;
Thread.sleep(1000);
}
serverStarted = false;
debug.message("EmbeddedOpenDS.shutdown server success.");
}
}
public static void setupReplication(Map map) throws Exception {
// Setup replication
SetupProgress.reportStart("emb.creatingreplica", null);
int ret = setupReplicationEnable(map);
if (ret == 0) {
ret = setupReplicationInitialize(map);
SetupProgress.reportEnd("emb.success", null);
Debug.getInstance(SetupConstants.DEBUG_NAME).message(
"EmbeddedOpenDS.setupReplication: replication setup succeeded.");
} else {
Object[] params = {Integer.toString(ret)};
SetupProgress.reportEnd("emb.failed.param", params);
Debug.getInstance(SetupConstants.DEBUG_NAME).error(
"EmbeddedOpenDS.setupReplication. Error setting up replication");
throw new ConfiguratorException(
"configurator.embreplfailed");
}
}
/**
* Setups replication between two OpenDJ sms and user stores.
* $ dsreplication enable
* --no-prompt
* --host1 host1 --port1 1389 --bindDN1 "cn=Directory Manager"
* --bindPassword1 password --replicationPort1 8989
* --host2 host2 --port2 2389 --bindDN2 "cn=Directory Manager"
* --bindPassword2 password --replicationPort2 8990
* --adminUID admin --adminPassword password
* --baseDN "dc=example,dc=com"
*
* @param map Map of properties collected by the configurator.
* @return status : 0 == success, !0 == failure
*/
public static int setupReplicationEnable(Map map) {
String[] enableCmd = {
"enable", // 0
"--no-prompt", // 1
"--host1", // 2
"host1val", // 3
"--port1", // 4
"port1ival", // 5
"--bindDN1", // 6
"cn=Directory Manager", // 7
"--bindPassword1", // 8
"xxxxxxxx", // 9
"--replicationPort1", // 10
"8989", // 11
"--host2", // 12
"host2val", // 13
"--port2", // 14
"port2ival", // 15
"--bindDN2", // 16
"cn=Directory Manager", // 17
"--bindPassword2", // 18
"xxxxxxxx", // 19
"--replicationPort2", // 20
"8989", // 21
"--adminUID", // 22
"admin", // 23
"--adminPassword", // 24
"xxxxxxxx", // 25
"--baseDN", // 26
"dc=example,dc=com", // 27
"--trustAll", // 28
"--configFile", // 29
"path/to/config.ldif", // 30
"--noPropertiesFile" // 31
};
enableCmd[3] = (String) map.get(SetupConstants.DS_EMB_REPL_HOST2);
enableCmd[5] = (String) map.get(SetupConstants.DS_EMB_REPL_ADMINPORT2);
enableCmd[11] = (String) map.get(SetupConstants.DS_EMB_REPL_REPLPORT2);
enableCmd[13] = getOpenDJHostName(map);
enableCmd[15] = (String) map.get(SetupConstants.CONFIG_VAR_DIRECTORY_ADMIN_SERVER_PORT);
enableCmd[21] = (String) map.get(SetupConstants.DS_EMB_REPL_REPLPORT1);
enableCmd[27] = (String) map.get(SetupConstants.CONFIG_VAR_ROOT_SUFFIX);
enableCmd[30] = getOpenDJConfigFile(map);
Object[] params = {concat(enableCmd)};
SetupProgress.reportStart("emb.replcommand", params);
enableCmd[9] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
enableCmd[19] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
enableCmd[25] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS.setupReplicationEnable: " +
"Host 1 " + enableCmd[3]);
debug.message("EmbeddedOpenDS.setupReplicationEnable: " +
"Host 2 " + enableCmd[13]);
debug.message("EmbeddedOpenDS.setupReplicationEnable: " +
"Port 1 " + enableCmd[5]);
debug.message("EmbeddedOpenDS.setupReplicationEnable: " +
"Port 2 " + enableCmd[15]);
}
int ret = ReplicationCliMain.mainCLI(
enableCmd, false,
SetupProgress.getOutputStream(),
SetupProgress.getOutputStream(),
null);
if (ret == 0) {
SetupProgress.reportEnd("emb.success", null);
} else {
SetupProgress.reportEnd("emb.failed", null);
}
return ret;
}
/**
* Syncs replication data between two OpenDJ sms and user stores.
* $ dsreplication initialize
* --baseDN "dc=example,dc=com" --adminUID admin --adminPassword pass
* --hostSource host1 --portSource 1389
* --hostDestination host2 --portDestination 2389
* --trustAll
*
* @param map Map of properties collected by the configurator.
* @return status : 0 == success, !0 == failure
*/
public static int setupReplicationInitialize(Map map) {
String[] initializeCmd = {
"initialize", // 0
"--no-prompt", // 1
"--baseDN", // 2
Constants.DEFAULT_ROOT_SUFFIX,// 3 Placeholder
"--adminUID", // 4
"admin", // 5
"--adminPassword", // 6
"xxxxxxxx", // 7
"--hostSource", // 8
"localhost", // 9
"--portSource", // 10
"50389", // 11
"--hostDestination", // 12
"localhost", // 13
"--portDestination", // 14
"51389", // 15
"--trustAll", // 16
"--configFile", // 17
"path/to/config.ldif", // 18
"--noPropertiesFile" // 19
};
initializeCmd[3] = (String) map.get(SetupConstants.CONFIG_VAR_ROOT_SUFFIX);
initializeCmd[9] = (String) map.get(SetupConstants.DS_EMB_REPL_HOST2);
initializeCmd[11] = (String) map.get(SetupConstants.DS_EMB_REPL_ADMINPORT2);
initializeCmd[13] = getOpenDJHostName(map);
initializeCmd[15] = (String) map.get(
SetupConstants.CONFIG_VAR_DIRECTORY_ADMIN_SERVER_PORT);
initializeCmd[18] = getOpenDJConfigFile(map);
Object[] params = {concat(initializeCmd)};
SetupProgress.reportStart("emb.replcommand", params);
initializeCmd[7] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
int ret = ReplicationCliMain.mainCLI(initializeCmd, false,
SetupProgress.getOutputStream(), SetupProgress.getOutputStream(),
null);
if (ret == 0) {
SetupProgress.reportEnd("emb.success", null);
} else {
SetupProgress.reportEnd("emb.failed", null);
}
return ret;
}
/**
* Returns Replication Status by invoking OpenDJ <code>dsreplication</code>
* CLI
*
* @param port LDAP port number of embedded OpenDJ
* @param passwd Directory Manager password
* @param oo Standard output
* @param err : Standard error
* @return <code>dsreplication</code> CLI exit code.
*/
public static int getReplicationStatus(String port, String passwd,
OutputStream oo, OutputStream err) {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
String baseDir = SystemProperties.get(SystemProperties.CONFIG_PATH);
String[] statusCmd = {
"status", "--no-prompt",
"-h", "localhost",
"-p", port,
"--adminUID", "admin",
"--adminPassword", passwd,
"-s",
"--configFile",
baseDir + "/opends/config/config.ldif",
"--noPropertiesFile"
};
if (debug.messageEnabled()) {
String dbgcmd = concat(statusCmd).replaceAll(passwd, "****");
debug.message("EmbeddedOpenDS:getReplicationStatus:exec dsreplication :"
+ dbgcmd);
}
int ret = ReplicationCliMain.mainCLI(statusCmd, false, oo, err, null);
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:getReplicationStatus:dsreplication ret:"
+ ret);
}
return ret;
}
/**
* @return true if multi server option is selected in the configurator.
*/
public static boolean isMultiServer(Map map) {
String replFlag = (String) map.get(SetupConstants.DS_EMB_REPL_FLAG);
if (replFlag != null && replFlag.startsWith(
SetupConstants.DS_EMP_REPL_FLAG_VAL)) {
return true;
}
return false;
}
private static String concat(String[] args) {
String ret = "";
for (int i = 0; i < args.length; i++)
ret += args[i] + " ";
return ret;
}
/**
* Utility function to preload data in the embedded instance.
* Must be called when the directory instance is shutdown.
*
* @param odsRoot Local directory where <code>OpenDJ</code> is installed.
* @param ldif Full path of the ldif file to be loaded.
*/
public static int loadLDIF(Map map, String odsRoot, String ldif) {
int ret = 0;
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
File ldifFile = new File(ldif);
if (!ldifFile.exists()) {
debug.error("LDIF File:" + ldifFile.getAbsolutePath() + " does not exist, unable to load!");
return -1;
}
try {
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:loadLDIF(" + ldif + ")");
}
String[] args1 =
{
"-C", // 0
"org.opends.server.extensions.ConfigFileHandler", // 1
"-f", // 2
odsRoot + "/config/config.ldif", // 3
"-n", // 4
"userRoot", // 5
"-l", // 6
ldif, // 7
"--trustAll", // 8
"-D", // 9
"cn=Directory Manager", // 10
"-w", // 11
"password", // 12
"--noPropertiesFile" // 13
};
args1[10] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_DN);
args1[12] = (String) map.get(SetupConstants.CONFIG_VAR_DS_MGR_PWD);
ret = org.opends.server.tools.ImportLDIF.mainImportLDIF(args1, false,
SetupProgress.getOutputStream(), SetupProgress.getOutputStream());
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:loadLDIF Success");
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS:loadLDIF:ex=", ex);
}
return ret;
}
/**
* Returns a one-way hash for passwd using SSHA512 scheme.
*
* @param p Clear password string
* @return hash value
*/
public static String hash(String p) {
String str = null;
try {
byte[] bb = p.getBytes();
str = SaltedSHA512PasswordStorageScheme.encodeOffline(bb);
} catch (Exception ex) {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
debug.error("EmbeddedOpenDS.hash failed : ex=" + ex);
}
return str;
}
/**
* Get replication port
*
* @param username
* @param password
* @param hostname
* @param port
* @return port number if replication is setup, null if not or on error.
*/
public static String getReplicationPort(
String username,
String password,
String hostname,
String port
) {
final String replDN =
"cn=replication server,cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config";
final String[] attrs = {"ds-cfg-replication-port"};
String replPort = null;
Connection ld = null;
username = "cn=Directory Manager";
try (Connection conn = getLDAPConnection(hostname, port, username, password)) {
// We'll use Directory Manager
if (conn != null) {
SearchResultEntry le = conn.readEntry(replDN, attrs);
if (le != null) {
Attribute la = le.getAttribute(attrs[0]);
if (la != null) {
replPort = la.firstValueAsString();
}
}
}
} catch (Exception ex) {
Debug.getInstance(SetupConstants.DEBUG_NAME)
.error("EmbeddedOpenDS.getReplicationPort(). Error getting replication port:", ex);
}
return replPort;
}
/**
* Get admin port of the OpenDJ server
*
* @param username The username of the directory admin
* @param password The password of the directory admin
* @param hostname The hostname of the directory server
* @param port The port of the directory server
* @return The admin port
*/
public static String getAdminPort(
String username,
String password,
String hostname,
String port
) {
final String adminConnectorDN = "cn=Administration Connector,cn=config";
final String[] attrs = {"ds-cfg-listen-port"};
String adminPort = null;
Connection ld = null;
try (Connection conn = getLDAPConnection(hostname, port, username, password)) {
if (conn != null) {
SearchResultEntry le = conn.readEntry(adminConnectorDN, attrs);
if (le != null) {
Attribute la = le.getAttribute(attrs[0]);
if (la != null) {
adminPort = la.firstValueAsString();
}
}
}
} catch (Exception ex) {
Debug.getInstance(SetupConstants.DEBUG_NAME)
.error("EmbeddedOpenDS.getAdminPort(). Error getting admin port:", ex);
}
return adminPort;
}
/**
* Synchronizes replication server info with current list of OpenAM servers.
*/
public static boolean syncReplicatedServers(
Set currServerSet, String port, String passwd) {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
debug.message("EmbeddedOPenDS:syncReplication:start processing.");
String[] args = {
"-p", port, // 1 : ds port num
"-h", "localhost",
"-D", "cn=directory manager",
"-w", passwd, // 7 : password
"list-replication-server",
"--provider-name", "Multimaster Synchronization",
"--property", "replication-server",
"--property", "replication-port", "--no-prompt", "--trustAll",
"--noPropertiesFile"
};
if (debug.messageEnabled()) {
String dbgcmd = concat(args).replaceAll(passwd, "****");
debug.message("EmbeddedOpenDS:syncReplication:exec dsconfig:"
+ dbgcmd);
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayOutputStream boe = new ByteArrayOutputStream();
DSConfig.main(args, false, bos, boe);
String str = bos.toString();
String stre = boe.toString();
if (stre.length() > 0 &&
!stre.contains("Unable to continue since there are no Replication Server currently")) {
debug.error("EmbeddedOpenDS:syncReplication: stderr is not empty:"
+ stre);
return false;
} else {
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:syncReplication: stderr is not empty:"
+ stre);
}
}
/*
v2.6 output example
Replication Server : replication-server : replication-port
-------------------:----------------------------------------------:-----------------
replication-server : dj1.example.com:58989, dj2.example.com:50889 : 50889
*/
BufferedReader brd = new BufferedReader(new StringReader(str));
String line = null;
try {
line = brd.readLine(); // 1st line
line = brd.readLine(); // 2nd line
line = brd.readLine(); // 3rd line
} catch (Exception ex) {
debug.error("EmbeddedOpenDS:syncReplication:Failed:", ex);
}
if (line == null) {
debug.error("EmbeddedOpenDS:syncReplication:cmd failed" + str);
return false;
}
try {
int lastcolon = line.lastIndexOf(':');
int stcolon = line.indexOf(':');
String replservers = line.substring(stcolon + 1, lastcolon);
StringTokenizer stok = new StringTokenizer(replservers, ",");
// Check if this server is part of server list
List cmdlist = new ArrayList();
cmdlist.add("-p");
cmdlist.add(port);
cmdlist.add("-h");
cmdlist.add("localhost");
cmdlist.add("-D");
cmdlist.add("cn=directory manager");
cmdlist.add("-w");
cmdlist.add(passwd);
cmdlist.add("--no-prompt");
cmdlist.add("--trustAll");
cmdlist.add("set-replication-server-prop");
cmdlist.add("--provider-name");
cmdlist.add("Multimaster Synchronization");
cmdlist.add("--noPropertiesFile");
int numremoved = 0;
while (stok.hasMoreTokens()) {
String tok = stok.nextToken().trim();
if (!currServerSet.contains(tok)) {
cmdlist.add("--remove");
cmdlist.add("replication-server:" + tok);
numremoved++;
}
}
if (numremoved > 0) {
String[] args1 =
(String[]) cmdlist.toArray(new String[cmdlist.size()]);
if (debug.messageEnabled()) {
String dbgcmd1 = concat(args1).replaceAll(passwd, "****");
debug.message("EmbeddedOpenDS:syncReplication:Execute:" +
dbgcmd1);
}
bos = new ByteArrayOutputStream();
boe = new ByteArrayOutputStream();
DSConfig.main(args1, false, bos, boe);
str = bos.toString();
stre = boe.toString();
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:syncReplication:Result:" +
str);
}
if (stre.length() != 0) {
debug.error("EmbeddedOpenDS:syncReplication:cmd stderr:"
+ stre);
}
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS:syncReplication:Failed:", ex);
return false;
}
return true;
}
/**
* Synchronizes replication domain info with current list of OpenAM servers.
*/
public static boolean syncReplicatedDomains(
Set currServerSet, String port, String passwd) {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
debug.message("EmbeddedOpenDS:syncReplication:Domains:started");
String[] args = {
"-p", port, // 1 : ds port num
"-h", "localhost",
"-D", "cn=directory manager",
"-w", passwd, // 7 : password
"list-replication-domains",
"--provider-name", "Multimaster Synchronization",
"--property", "replication-server",
"--no-prompt",
"--trustAll",
"--noPropertiesFile"
};
if (debug.messageEnabled()) {
String dbgcmd = concat(args).replaceAll(passwd, "****");
debug.message("EmbeddedOpenDS:syncReplication:exec dsconfig:"
+ dbgcmd);
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayOutputStream boe = new ByteArrayOutputStream();
DSConfig.main(args, false, bos, boe);
String str = bos.toString();
String stre = boe.toString();
if (stre.length() != 0) {
debug.error("EmbeddedOpenDS:syncReplication:stderr:" + stre);
}
/*
v2.6 output example
Replication Domain : replication-server
------------------------------:---------------------------------------------
cn=admin data : dj1.example.com:58989, dj2.example.com:50889
cn=schema : dj1.example.com:58989, dj2.example.com:50889
dc=openam,dc=forgerock,dc=org : dj1.example.com:58989, dj2.example.com:50889
*/
BufferedReader brd = new BufferedReader(new StringReader(str));
String line = null;
try {
line = brd.readLine(); // 1st line
line = brd.readLine(); // 2nd line
while ((line = brd.readLine()) != null) {
try {
int dcolon = line.indexOf(':');
String domainname = line.substring(0, dcolon).trim();
int stcolon = dcolon + 1;
String replservers = line.substring(stcolon + 1);
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:syncRepl:domain=" +
domainname + " replservers=" + replservers);
}
StringTokenizer stok = new StringTokenizer(replservers, ",");
// Check if this server is part of server list
List cmdlist = new ArrayList();
cmdlist.add("-p");
cmdlist.add(port);
cmdlist.add("-h");
cmdlist.add("localhost");
cmdlist.add("-D");
cmdlist.add("cn=directory manager");
cmdlist.add("-w");
cmdlist.add(passwd);
cmdlist.add("--no-prompt");
cmdlist.add("--trustAll");
cmdlist.add("set-replication-domain-prop");
cmdlist.add("--provider-name");
cmdlist.add("Multimaster Synchronization");
cmdlist.add("--domain-name");
cmdlist.add(domainname);
cmdlist.add("--noPropertiesFile");
int numremoved = 0;
while (stok.hasMoreTokens()) {
String tok = stok.nextToken().trim();
if (!currServerSet.contains(tok)) {
cmdlist.add("--remove");
cmdlist.add("replication-server:" + tok);
numremoved++;
}
}
if (numremoved > 0) {
String[] args1 =
(String[]) cmdlist.toArray(new String[cmdlist.size()]);
if (debug.messageEnabled()) {
String dbgcmd1 =
concat(args1).replaceAll(passwd, "****");
debug.message("EmbeddedOpenDS:syncReplication:Execute:" +
dbgcmd1);
}
bos = new ByteArrayOutputStream();
boe = new ByteArrayOutputStream();
DSConfig.main(args1, false, bos, boe);
str = bos.toString();
stre = boe.toString();
if (stre.length() != 0) {
debug.error("EmbeddedOpenDS:syncRepl:stderr=" + stre);
}
if (debug.messageEnabled()) {
debug.message("EmbeddedOpenDS:syncReplication:Result:" +
str);
}
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS:syncReplication:Failed:", ex);
return false;
}
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS:syncReplication:Failed:", ex);
return false;
}
return true;
}
/**
* Synchronizes replication domain info with current list of OpenAM servers.
*/
public static boolean syncReplicatedServerList(
Set currServerSet, String port, String passwd) {
try (Connection conn = getLDAPConnection("localhost", port, "cn=Directory Manager", passwd)) {
Set<String> dsServers = getServerSet(conn);
if (dsServers == null) {
return false;
}
for (String tok : dsServers) {
if (!currServerSet.contains(tok)) {
delOpenDSServer(conn, tok);
}
}
} catch (Exception ex) {
return false;
}
return true;
}
/**
* Helper method to return Ldap connection to a embedded OpenDJ
* server.
*
* @return Ldap connection
*/
private static Connection getLDAPConnection(String dsHostName, String dsPort, String dsManager,
String dsAdminPwd) {
try {
return getLDAPConnectionFactory(dsHostName, dsPort, dsManager, dsAdminPwd).getConnection();
} catch (ErrorResultException ex) {
Debug.getInstance(SetupConstants.DEBUG_NAME)
.error("EmbeddedOpenDS.setup(). Error getting LDAPConnection:", ex);
}
return null;
}
private static synchronized ConnectionFactory getLDAPConnectionFactory(String dsHostName, String dsPort,
String dsManager, String dsAdminPwd) {
if (factory == null) {
factory = Connections.newAuthenticatedConnectionFactory(
new LDAPConnectionFactory(dsHostName, Integer.parseInt(dsPort),
new LDAPOptions().setConnectTimeout(300, TimeUnit.SECONDS)),
Requests.newSimpleBindRequest(dsManager, dsAdminPwd.toCharArray()));
ShutdownManager.getInstance().addShutdownListener(new ShutdownListener() {
@Override
public void shutdown() {
if (factory != null) {
factory.close();
}
}
});
}
return factory;
}
static final String replDN = "cn=all-servers,cn=Server Groups,cn=admin data";
/**
* Removes host:port from OpenDJ replication
*/
public static void delOpenDSServer(Connection lc, String delServer) {
String replServerDN =
"cn=" + delServer + ",cn=Servers,cn=admin data";
final String[] attrs = {"ds-cfg-key-id"};
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
if (lc == null) {
debug.error("EmbeddedOpenDS:syncOpenDSServer():" +
"Could not connect to local OpenDJ instance." + replServerDN);
return;
}
String trustKey = null;
try {
SearchResultEntry le = lc.readEntry(replServerDN, attrs);
if (le != null) {
Attribute la = le.getAttribute(attrs[0]);
if (la != null) {
trustKey = la.firstValueAsString();
}
String keyDN = "ds-cfg-key-id=" + trustKey +
",cn=instance keys,cn=admin data";
lc.delete(keyDN);
} else {
debug.error("EmbeddedOpenDS:syncOpenDSServer():" +
"Could not find trustkey for:" + replServerDN);
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS.syncOpenDSServer()." +
" Error getting replication key:", ex);
}
try {
lc.delete(replServerDN);
} catch (Exception ex) {
debug.error("EmbeddedOpenDS.syncOpenDSServer()." +
" Error getting deleting server entry:" + replServerDN, ex);
}
try {
ModifyRequest modifyRequest = Requests.newModifyRequest(replDN)
.addModification(new Modification(ModificationType.DELETE,
Attributes.singletonAttribute("uniqueMember", "cn=" + delServer)));
lc.modify(modifyRequest);
} catch (Exception ex) {
debug.error("EmbeddedOpenDS.syncOpenDSServer()." +
" Error getting removing :" + replDN, ex);
}
}
/**
* Gets list of replicated servers from local OpenDJ directory.
*/
public static Set getServerSet(Connection lc) {
final String[] attrs = {"uniqueMember"};
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
try {
if (lc != null) {
SearchResultEntry le = lc.readEntry(replDN, attrs);
if (le != null) {
Set hostSet = new HashSet();
Attribute la = le.getAttribute(attrs[0]);
if (la != null) {
for (ByteString value : la) {
hostSet.add(value.toString().substring(3, value.length()));
}
}
return hostSet;
} else {
debug.error("EmbeddedOpenDS:syncOpenDSServer():" +
"Could not find trustkey for:" + replDN);
}
} else {
debug.error("EmbeddedOpenDS:syncOpenDSServer():" +
"Could not connect to local opends instance.");
}
} catch (Exception ex) {
debug.error("EmbeddedOpenDS.syncOpenDSServer()." +
" Error getting replication key:", ex);
}
return null;
}
// Programmatic way of rebuilding indexes in OpenDJ.
// This method simulates the OpenDJ cli command rebuild-index.
// eg., rebuild-index -b dc=example,dc=com -i uid -i mail
public static int rebuildIndex(Map map) throws Exception {
int ret = 0;
shutdownServer("Rebuild index");
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
String[] args = {
"--configClass",
"org.opends.server.extensions.ConfigFileHandler",
"--configFile",
getOpenDJConfigFile(map),
"--baseDN",
(String) map.get(SetupConstants.CONFIG_VAR_ROOT_SUFFIX),
"--rebuildAll",
"--noPropertiesFile"};
OutputStream bos = new ByteArrayOutputStream();
OutputStream boe = new ByteArrayOutputStream();
TimeThread.start();
ret = RebuildIndex.mainRebuildIndex(args, true, bos, boe);
TimeThread.stop();
String outStr = bos.toString();
String errStr = boe.toString();
if (errStr.length() != 0) {
debug.error("EmbeddedOpenDS:rebuildIndex:stderr=" +
errStr);
}
if (debug.messageEnabled()) {
String msg = "msg=Rebuild complete.";
int idx = outStr.indexOf(msg);
if (idx >= 0) {
debug.message("EmbeddedOpenDS:rebuildIndex: " +
"Rebuild Status: " + outStr.substring(idx));
}
debug.message("EmbeddedOpenDS:rebuildIndex:Result:" +
outStr);
}
startServer(getOpenDJBaseDir(map));
return ret;
}
/**
* @return true if installed OpenDS is version 1.0.2
*/
public static boolean isOpenDSVer1Installed() {
boolean openDSVer1x = false;
if (getOpenDSVersion().equals(OPENDS_1x_VER)) {
openDSVer1x = true;
}
return openDSVer1x;
}
/**
* @return true if installed OpenDS is version 2.3.0BACKPORT2
*/
public static boolean isOpenDSVer230Installed() {
boolean openDSVer230b2 = false;
if (getOpenDSVersion().equals(OPENDS_230B2_VER)) {
openDSVer230b2 = true;
}
return openDSVer230b2;
}
public static String getOpenDSVersion() {
Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
String odsRoot = AMSetupServlet.getBaseDir() + "/" + SetupConstants.SMS_OPENDS_DATASTORE;
String version = "unknown";
File configLdif = new File(odsRoot + OPENDS_UPGRADE_DIR);
File buildInfo = new File(odsRoot + "/" + "config" + "/" + SetupConstants.OPENDJ_BUILDINFO);
if (configLdif.exists() && configLdif.isDirectory()) {
String[] configFile = configLdif.list(new FilenameFilter() {
//@Override -- Not Allowed Here.
public boolean accept(File dir, String name) {
return name.startsWith(OPENDS_CONFIG_LDIF);
}
});
if (configFile.length != 0) {
version = configFile[0].substring(configFile[0].lastIndexOf('.') + 1);
} else {
debug.error("Unable to determine OpenDJ version");
}
} else if (buildInfo.exists() && buildInfo.canRead() && buildInfo.isFile()) {
String buildInfoVersionText = getOpenDJBuildInfo(buildInfo);
if ( (buildInfoVersionText != null) && (!buildInfoVersionText.isEmpty()) ) {
version = buildInfoVersionText.trim();
} else {
debug.error("Unable to determine OpenDJ version");
}
} else {
if (debug.warningEnabled()) {
debug.warning("Unable to determine OpenDJ version; could be pre-config");
}
}
if (debug.messageEnabled()) {
debug.message("Found OpenDJ version: " + version);
}
return version;
}
/**
* Initialises OpenDJ for client use, used by the CLI tools
*/
public static void initializeForClientUse() {
EmbeddedUtils.initializeForClientUse();
}
// Returns the installation directory for the embedded OpenDJ.
private static String getOpenDJBaseDir(Map configProperties) {
String basedir = (String) configProperties
.get(SetupConstants.CONFIG_VAR_BASE_DIR);
return basedir + "/" + SetupConstants.SMS_OPENDS_DATASTORE;
}
// Returns the configuration file name for the embedded OpenDJ.
private static String getOpenDJConfigFile(Map configProperties) {
return getOpenDJBaseDir(configProperties) + "/config/config.ldif";
}
// Returns the host name for the embedded OpenDJ.
private static String getOpenDJHostName(Map configProperties) {
String dirHost = (String) configProperties
.get(SetupConstants.CONFIG_VAR_DIRECTORY_SERVER_HOST);
if (dirHost.equals("localhost")) {
dirHost = (String) configProperties
.get(SetupConstants.CONFIG_VAR_SERVER_HOST);
}
return dirHost;
}
// Helper Method to return the first line of the OpenDJ buildInfo file.
private static String getOpenDJBuildInfo(File buildInfo) {
try {
Scanner scan = new Scanner(buildInfo);
while (scan.hasNextLine()) {
return scan.nextLine();
}
} catch (FileNotFoundException e) {
// Simply Ignore this Exception and Allow UpStream to Handle Null.
}
return null;
}
}