AMSetupServlet.java revision fa46e507c99bcee6a200809f37e91a34e345eea4
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 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
* 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: AMSetupServlet.java,v 1.117 2010/01/20 17:01:35 veiming Exp $
*
* Portions Copyrighted 2010-2015 ForgeRock AS.
*/
/**
* This class is the first class to get loaded by the Servlet container.
*
* It has helper methods to determine the status of OpenAM configuration when deployed as a single
* web-application. If OpenAM is not deployed as single web-application then the configured status
* returned is always true.
*/
public class AMSetupServlet extends HttpServlet {
private static boolean isConfiguredFlag = false;
private static boolean isVersionNewer = false;
private static boolean upgradeCompleted = false;
private static boolean isOpenDJUpgraded = false;
static {
}
/*
* Initializes the servlet.
*/
if (servletCtx == null ) {
}
if (isConfiguredFlag) {
// this will sync up bootstrap file will serverconfig.xml
// due startup; and also register the observer.
// Syncup embedded opends replication with current server instances.
if (!syncServerInfoWithRelication()) {
.error("AMSetupServlet.init: embedded replication sync failed.");
}
}
final String[] licenseFilePaths =
if (licenseFilePaths == null) {
throw new ServletException("Could not get license file paths.");
}
}
private static LicenseLocator licenseLocator;
public static LicenseLocator getLicenseLocator() {
return licenseLocator;
}
/*
* Flag indicating if OpenAM is configured with the latest valid config
*/
static public boolean isCurrentConfigurationValid() {
if (isConfiguredFlag) {
}
}
static public boolean isConfigured() {
return isConfiguredFlag;
}
/**
* Used this method to check if the version is newer; called post upgrade
*/
private static void isVersionNewer() {
if (isConfiguredFlag) {
}
}
public static void upgradeCompleted() {
upgradeCompleted = true;
}
public static boolean isUpgradeCompleted() {
return upgradeCompleted;
}
public static boolean isOpenDJUpgraded() {
return isOpenDJUpgraded;
}
public static void enableDebug() {
for (Debug d : debugInstances) {
}
}
/**
* Checks if the embedded directory (if present) needs to be upgraded
*/
private static void checkOpenDJUpgrade() throws ServletException {
// check for embedded directory
if (!isEmbeddedDS()) {
return;
}
// check if upgrade is required
if (!upgrader.isUpgradeRequired()) {
return;
}
// backup embedded directory
// initiate upgrade
try {
}
isOpenDJUpgraded = true;
}
private static void createOpenDJBackup() {
try {
} catch (UpgradeException ue) {
return;
}
if (backupFile.exists()) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("Upgrade cannot continue as backup file exists! "
+ backupFile.getName());
return;
}
try {
// Compress the files
}
} catch (IOException ioe) {
} finally {
try {
} catch (IOException ioe) {
// do nothing
}
}
}
}
}
try {
}
if (!filename.isDirectory()) {
zOut.putNextEntry(new ZipEntry((dirName + filename.getName()).replace('\\','/').substring(stripLen)));
}
zOut.closeEntry();
} else {
zOut.closeEntry();
}
}
}
}
/**
* Checks if the product is already configured. This is required
* when the container on which WAR is deployed is restarted. If
* product is configured the flag is set true. Also the flag is
* set to true in case of non-single war deployment.
*/
private static void checkConfigProperties() {
try {
if (bootstrapFile != null) {
} else {
}
}
} catch (ConfiguratorException e) {
//ignore, WAR may not be configured yet.
} catch (Exception e) {
}
}
}
boolean loaded = false;
try {
loaded = true;
} finally {
try {
} catch (IOException e) {
//ignore
}
}
}
}
return loaded;
}
/**
* Invoked from the filter to decide which page needs to be
* displayed.
* @param servletctx is the Servlet Context
* @return true if AM is already configured, false otherwise
*/
return isConfiguredFlag;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException,
// Only continue if we are not already configured
if (isConfigured()) {
return;
}
if (loadBalancerHost != null) {
// site configuration is passed as a map of the site
// information
}
if (userStoreType != null) {
// site configuration is passed as a map of the site information
try {
}
} catch (NamingException nex) {
} catch (IOException ioex) {
}
}
} else {
}
}
} else {
}
}
if (!result) {
} else {
}
}
// Only continue if we are not already configured
if (isConfigured()) {
return true;
}
/*
* This logic needs refactoring later. setServiceConfigValues()
* attempts to check if directory is up and makes a call
* back to this class. The implementation'd
* be cleaner if classes&methods are named better and separated than
* intertwined together.
*/
// set debug directory
SystemProperties.initializeProperties(Constants.SERVICES_DEBUG_DIRECTORY, basedir + uri + "/debug");
// used for site configuration later
Map<String, Object> siteMap = (Map<String, Object>) map.remove(SetupConstants.CONFIG_VAR_SITE_CONFIGURATION);
try {
// Check for click-through license acceptance before processing the request.
if (!isLicenseAccepted(request)) {
return false;
}
/*
* As we have got this far then the user must have accepted the license, so we log this implicitly.
*/
}
if (isConfiguredFlag) {
//postInitialize was called at the end of configure????
}
if (isConfiguredFlag) {
if (fileBootstrap != null) {
}
// this will write bootstrap file after configuration is
// done; and also register the observer.
// register our other observers
if (fileBootstrap == null) {
} else {
}
// this is to store the bootstrap location
// store the ds admin port if we are running in embedded mode
}
// setup site configuration information
/*
* If primary url is null that means we are adding
* to an existing site. we don't need to create it
* first.
*/
}
}
}
}
// Setup Replication port in SMS for each server
}
}
} catch (Exception e) {
} finally {
}
}
}
installLog.close();
}
} else {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("WebtopNaming.configMonitoring returned error.");
}
return isConfiguredFlag;
}
// The list of constants, passwords for example, that should be hashed out if logged.
};
// Used to provide a lookup list of items that should be hashed out.
/**
* Iterate over the supplied properties (sorted by property name) and write them out to the passed install log.
* Property values that are in the CONFIG_ITEMS_TO_HASH_LIST will have their value masked.
* @param installLog The log to write the properties into
* @param properties A non-null set of properties to iterate over and write out to the log
*/
private static void dumpConfigurationProperties(InstallLog installLog, Map<String, Object> properties) {
SortedMap<String, Object> sortedProperties = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
} else {
}
}
}
/**
* Verify that the user has accepted the terms of all required licenses. This is indicated by the presence of a
* request parameter {@code licenseAccepted=true}.
*
* @param request the servlet request.
* @return true if the license acceptance parameter is present and correct, otherwise false.
*/
try {
return Boolean.parseBoolean(request.getParameterMap().get(SetupConstants.ACCEPT_LICENSE_PARAM).toString());
} catch (NullPointerException ex) {
return false;
}
}
throws IOException {
} else {
}
} else {
}
}
}
}
}
}
if (!baseDirectory.exists()) {
} else {
+ " cannot be used - has preexisting config data.");
}
}
}
// (i) install, configure and start an embedded instance.
// or
// (ii) install, configure, and replicate embedded instance
private static boolean setupEmbeddedDS(Map<String, Object> map, String dataStore) throws Exception {
boolean ditLoaded = false;
// wait for at most 10 seconds for OpenDS to come up
int sleepTime = 10;
// sleep one second a time
}
if (!dsConfig.isDServerUp()) {
throw new ConfigurationException("OpenDJ cannot be started.");
}
// Determine if DITLoaded flag needs to be set: multi instance
// Replication
// TOFIX: Temporary fix until OpenDS auto-loads schema
// Get the remote host name from the SERVER URL
// entered in the 'Add to existing instance' and place
// it in the map. This is for console configurator.
// For cli configurator, the "DS_EMB_REPL_HOST2" would
// be entered in the config. file itself.
if (existingInstance != null) {
}
}
}
ditLoaded = true;
}
return ditLoaded;
}
}
if (!isDITLoaded) {
}
return isDITLoaded;
}
try {
if (!isDITLoaded) {
}
if (!isDITLoaded || !ServerConfiguration.isServerInstanceExist(adminSSOToken, serverInstanceName)) {
}
} catch (UnknownPropertyNameException ex) {
// ignore, property names are valid because they are
// gotten from template.
}
}
private static boolean configure(IHttpServletRequest request, Map<String, Object> map, Map<String, Object> userRepo)
throws Exception {
boolean configured;
boolean existingConfiguration = false;
try {
// do this here since initializeConfigProperties needs the dir
String strAMConfigProperties = (String) mapFileNameToConfig.get(SetupConstants.AMCONFIG_PROPERTIES);
// Set the install property since reInitConfigProperties
// initializes SMS which inturn initializes EventService
// SystemProperties gets reinitialized and installTime property
// has to set again
if (!isDITLoaded) {
}
// Set installTime to false, to avoid in-memory notification from
// SMS in cases where not needed, and to denote that service
// registration got completed during configuration phase and it
// has passed installtime.
configureServerInstance(adminSSOToken, serverInstanceName, strAMConfigProperties, isDITLoaded, basedir,
// Embedded :get our serverid and configure embedded idRepo
// Ensure this service are initialized before continuing
if (embedded) {
try {
throw ex;
}
}
// Construct the SMSEntry for the node to check to
// see if this is an existing configuration store,
// or new store.
if (entry.isNewEntry()) {
} else {
existingConfiguration = true;
}
}
}
/*
* Requiring the keystore.jks file in OpenAM workspace.
* The createIdentitiesForWSSecurity is for the
*/
if (!isDITLoaded) {
}
if (!existingConfiguration) {
}
}
isConfiguredFlag = true;
configured = true;
} catch (Exception e) {
// catch all because we want all exception to be logged
errorMessage = e.getMessage();
throw e;
}
return configured;
}
/**
* Creates a SubConfiguration in the Session service that should enable/disable SFO based on the provided values.
*
* @param adminToken The admin token to use when adding the SubConfiguration.
* @param siteName The name of the site that has been provided for the configurator.
* @param values Valid values for the session subconfiguration containing the SFO settings.
* @throws SMSException If there was an error while creating the new SubConfiguration.
* @throws SSOException If the provided admin token wasn't valid.
*/
private static void createSFOSubConfig(SSOToken adminToken, String siteName, Map<String, Set<String>> values)
throws SMSException, SSOException {
throw new SMSException("Global config does not exist for iPlanetAMSessionService");
}
//if the subconfig already exists, then we shouldn't try to create it for the second time
if (existingSubConfig == null) {
}
}
public static String getErrorMessage() {
}
}
}
svcMgr.clearCache();
}
private static void handlePostPlugins(SSOToken adminSSOToken) throws IllegalAccessException, InstantiationException,
if (servletCtx == null) {
return;
}
}
}
try {
if (strPlugins != null) {
while (st.hasMoreTokens()) {
}
}
} catch (IllegalAccessException e) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("AMSetupServlet.getConfigPluginClasses: error", e);
throw e;
} catch (InstantiationException e) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("AMSetupServlet.getConfigPluginClasses: error", e);
throw e;
} catch (ClassNotFoundException e) {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("AMSetupServlet.getConfigPluginClasses: error", e);
throw e;
} catch (MissingResourceException e) {
//ignore if there are no configurator plugins.
}
return plugins;
}
private static void reInitConfigProperties(String serverName, Properties prop, String strServerConfigXML)
}
}
try {
} catch (MissingResourceException e) {
//ignored because bootstrap properties file maybe absent.
}
}
} else {
throw new ConfiguratorException("cannot get configuration path");
}
}
return configDir;
}
/**
* Returns location of the bootstrap file.
*
* @return Location of the bootstrap file. Returns null if the file
* cannot be located
* @throws ConfiguratorException if servlet context is null or deployment
* application real path cannot be determined.
*/
} else {
try {
} catch (IOException e) {
//ignore
} finally {
try {
} catch (IOException e) {
//ignore
}
}
}
}
}
}
return bootstrap;
}
// this is the file which contains the base dir.
// this file is not created if configuration directory is
// preset in bootstrap.properties
return null;
}
if (servletCtx != null) {
String fullOldPath = oldPath.getPath() + "/" + SetupConstants.CONFIG_VAR_BOOTSTRAP_BASE_PREFIX + path;
String fullNewPath = newPath.getPath() + "/" + SetupConstants.CONFIG_VAR_BOOTSTRAP_BASE_PREFIX + path;
// Simple case where just the old path exists.
if (debug.messageEnabled()) {
}
// There is a chance that both new and old path locations exist when newer installations have been done
// from scratch but the instance to consider is in the old path, double check for an old config before
// returning the new path when finding both.
// Test if we have a config file in the old path
if (testOldPath.exists()) {
if (debug.messageEnabled()) {
+ "config in the old path, returning old " + bootstrapLocatorResult);
}
} else {
if (debug.messageEnabled()) {
+ "not find a config in old path, returning new " + bootstrapLocatorResult);
}
}
} else {
if (debug.messageEnabled()) {
}
}
return bootstrapLocatorResult;
} else {
throw new ConfiguratorException(
"Cannot read the bootstrap path");
}
} else {
return null;
}
}
return configDir;
}
if (servletCtx != null) {
return null;
}
try {
} catch (IOException e) {
throw new ConfiguratorException(e.getMessage());
} finally {
try {
} catch (IOException e) {
//ignore
}
}
}
} else {
throw new ConfiguratorException("Cannot read the bootstrap path");
}
} else {
throw new ConfiguratorException("Servlet Context is null");
}
}
if (servletCtx != null) {
} else {
}
if (idx != -1) {
}
}
}
return path;
}
/**
* Returns URL of the default resource.
*
* @return URL of the default resource. Returns null of servlet context is
* null.
*/
if (servletCtx != null) {
try {
} catch (MalformedURLException mue) {
}
} else {
Debug.getInstance(SetupConstants.DEBUG_NAME).error("AMSetupServlet.getAppResource: Context is null");
}
return null;
}
/**
* This method takes the name of XML file, process each
* request object one by one immediately after parsing.
*
* @param xmlBaseDir is the location of request xml files
* @throws SMSException if error occurs in the service management space.
* @throws SSOException if administrator single sign on is not valid.
* @throws IOException if error accessing the configuration files.
* @throws PolicyException if policy cannot be loaded.
*/
private static void processDataRequests(String xmlBaseDir) throws SMSException, SSOException, IOException,
try {
} catch (SMSException e) {
throw e;
} catch (SSOException e) {
throw e;
} catch (IOException e) {
throw e;
}
}
/**
* Helper method to return Admin token
* @return Admin Token
*/
private static SSOToken getAdminSSOToken() {
if (adminToken == null) {
}
return adminToken;
}
/**
* Initialize AMConfig.properties with host specific values
*/
try {
} catch (SecurityException e) {
throw e;
}
// this is for the servicetag-registry.xml stuff, a bit later
/*
* if the file's not there, just skip it
* usually will be about a file included with OpenAM,
* so it's informational, rather than a "real" error.
*/
try {
} catch (IOException ioex) {
break;
}
boolean dbSunDS;
boolean dbMsAD = false;
if (embedded) {
dbSunDS = true;
} else { // Keep old behavior for now.
}
if (idx1 != -1) {
}
}
}
} else {
}
}
return mapFileNameToContent;
}
}
}
}
/**
* Returns schema file names.
*
* @param dataStore Name of data store configuration data.
* @throws MissingResourceException if the bundle cannot be found.
*/
if (embedded) {
} else {
}
while (st.hasMoreTokens()) {
}
return fileNames;
}
while (st.hasMoreTokens()) {
}
return fileNames;
}
/**
* Tag swaps strings in schema files.
*
* @param basedir the configuration base directory.
* @param schemaFiles List of schema files to be loaded.
* @throws IOException if data files cannot be written.
*/
private static void writeSchemaFiles(String basedir, List<String> schemaFiles, Map map, String dataStore)
throws Exception {
try {
} catch (IOException ioex) {
+ "Exception in writing schema files:" , ioex);
throw ioex;
} finally {
try {
//No handling requried
}
}
}
}
if (ret != 0) {
+ "Unable to rebuild indexes in OpenDJ: " + ret);
}
}
}
}
/**
* Create the storepass and keypass files
*
* @param basedir the configuration base directory.
* @param deployuri the deployment URI.
* @throws IOException if password files cannot be written.
*/
}
/**
* Helper method to create the storepass and keypass files
*
* @param fName is the name of the file to create.
* @param content is the password to write in the file.
*/
try {
} catch (IOException ioex) {
throw ioex;
} finally {
try {
//No handling requried
}
}
}
}
/**
* Update Embedded Idrepo instance with new embedded opends isntance.
*/
private static void updateEmbeddedIdRepo(String orgName, String configName, String entry) throws SMSException,
}
}
}
/**
* Update platform server list and Organization alias
*/
private static void updatePlatformServerList(String serverURL, String hostName) throws SMSException, SSOException {
// Update Organization Aliases
}
}
}
int maxNumber = 1;
if (index1 != -1) {
try {
if (n > maxNumber) {
maxNumber = n;
}
} catch (NumberFormatException nfe) {
// Ignore and continue
}
}
}
}
return instanceName;
}
boolean found = false;
if (idx != -1) {
}
}
return found;
}
try {
return true;
} catch (SSOException ex) {
return false;
} catch (SMSException ex) {
return false;
}
}
private static void createDemoUser()
throws IdRepoException, SSOException {
try {
} catch (IdRepoException e) {
throw e;
} catch (SSOException e) {
throw e;
}
}
/**
* Creates Identities for WS Security
*
* @param serverURL URL at which OpenAM is configured.
*/
private static void createIdentitiesForWSSecurity(String serverURL, String deployuri) throws IdRepoException,
if (!isAgentServiceLoad(token)) {
return;
}
// Add WSC configuration
// Add WSP configuration
+ "urn:sun:wss:security:null:SAML2Token-HK," + "urn:sun:wss:security:null:SAML2Token-SV,"
+ "urn:sun:wss:security:null:X509Token");
// Add STS Client configuration
// Add Agent Authenticator configuration
}
private static void createAgent(SSOToken adminToken, AMIdentityRepository idrepo, String name, String password,
while (st.hasMoreTokens()) {
}
} else {
}
}
}
}
/*
* make sure the basedir + "/" + deployuri + "/lib/registration"
* directory exists, and then create the monitoring auth file
* there.
*/
try {
// Check for Existing File
}
} catch (IOException ex) {
.error("AMSetupServlet.createMonitoringAuthFile:failed to create monitoring authentication file");
}
}
/**
*/
if (!dataAceDir.mkdirs()) {
.error("AMSetupServlet.setupSecurIDDirs: failed to create SecurID data directory");
}
}
/*
* not rsa_api.properties, as it's tagged swapped and
*
* if file isn't copied, it's probably because this is
* an OpenSSO deployment, rather than OpenSSO, so it would
* just be informational, but at the debug error level.
* additionally, before some point, the debug stuff can't
* be invoked.
*/
try {
} catch (IOException ioex) {
}
}
private static boolean copyCtxFile (String srcDir, String file, String destDir) throws IOException {
byte[] b = new byte[2000];
int len;
}
} else {
return false;
}
return true;
}
try {
} finally {
try {
} catch (IOException e) {
//ignore
}
}
}
}
.append("\n");
}
}
private static String determineOS() {
return SetupConstants.WINDOWS;
} else {
return SetupConstants.X86SOLARIS;
} else {
return SetupConstants.LINUX;
}
}
} else {
return SetupConstants.SOLARIS;
}
}
} else {
} else {
}
}
}
}
private static boolean isEmbeddedDS() {
}
/**
* Synchronizes embedded replication state with current server list.
* @return boolean true is sync succeeds else false.
*/
private static boolean syncServerInfoWithRelication() {
// We need to execute syn only if we are in Embedded mode
if (!isEmbeddedDS()) {
return true;
}
try {
if (getAdminSSOToken() == null) {
+ "Could not sync servers with embedded replication:no admin token");
return false;
}
// Determine which server this is
// See if we need to execute sync
// Check if we are already replication with other servers
return true;
}
// Get server list
return true;
}
}
boolean stats = EmbeddedOpenDS.syncReplicatedServers(currServerSet, dsAdminPort, getSMSPassword(sGroup));
boolean statd = EmbeddedOpenDS.syncReplicatedDomains(currServerSet, dsAdminPort, getSMSPassword(sGroup));
boolean statl = EmbeddedOpenDS.syncReplicatedServerList(currServerDSAdminPortsSet, getSMSPort(sGroup),
+ "Could not sync servers with embedded replication:", ex);
return false;
}
}
/**
* Gets <code>ServerGroup</code> for SMS for specified server
* @param sname servername of groupo to find.
* @return <code>ServerGroup</code> instance
*/
return scc.getSMSServerGroup() ;
}
/**
* Gets clear password of SMS datastore
* @param ssg <code>ServerGroup</code> instance representing SMS
* or Configuration datastore.
* @return clear password
*/
}
/**
* Gets port number of SMS datastore
* @param ssg <code>ServerGroup</code> instance representing SMS
* or Configuration datastore.
* @return port
*/
}
try {
// Update this instance first...
// Update remote instance
// Update remote instance ...
+ "could not add replication port info to SM", ex);
}
}
// Method to convert the domain name to the root suffix.
// eg., Domain Name amqa.test.com is converted to root suffix
// DC=amqa,DC=test,DC=com
continue;
} else {
}
}
}
// Method to get hostname and port number with the
// provided Domain Name for Active Directory user data store.
domainName+='.';
}
// Check if domain name is a valid one.
// The resource record type A is defined in RFC 1035.
try {
throw new NamingException();
}
} catch (NamingException e) {
// Failed to resolve domainName to A record.
// throw exception.
throw e;
}
// then look for the LDAP server
try {
// Attempting to resolve ldapServer to SRV record.
// This is a mechanism defined in MSDN, querying
// SRV records for _ldap._tcp.DOMAINNAME.
// and get host and port from domain.
throw new NamingException();
}
} catch (NamingException e) {
// Failed to resolve ldapServer to SRV record.
// throw exception.
throw e;
}
// try to connect to LDAP port to make sure this machine
// has LDAP service
try {
} catch (IOException e) {
throw e;
}
return hostAndPort;
}
private static void registerListeners() {
if (isCurrentConfigurationValid()) {
for (SetupListener p : listeners) {
p.setupComplete();
}
}
}
}