/** * 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 * 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: AgentConfiguration.java,v 1.39 2009/04/02 00:02:11 leiming Exp $ * */ /* * Portions Copyrighted 2010-2013 ForgeRock AS. */ package com.sun.identity.agents.arch; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Properties; import java.util.Vector; import com.iplanet.am.util.SystemProperties; import com.iplanet.services.comm.client.AlreadyRegisteredException; import com.iplanet.services.comm.client.PLLClient; import com.iplanet.services.naming.URLNotFoundException; import com.iplanet.services.naming.WebtopNaming; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.iplanet.sso.SSOTokenManager; import com.sun.identity.agents.common.CommonFactory; import com.sun.identity.agents.common.IApplicationSSOTokenProvider; import com.sun.identity.agents.util.AgentRemoteConfigUtils; import com.sun.identity.agents.util.ResourceReader; import com.sun.identity.common.DebugPropertiesObserver; import com.sun.identity.common.GeneralTaskRunnable; import com.sun.identity.common.SystemTimer; import com.sun.identity.shared.Constants; import com.sun.identity.shared.debug.Debug; import com.sun.identity.install.tools.util.FileUtils; import org.forgerock.openam.util.Version; /** *

* Provides access to the configuration as set in the system. *

* It uses the agent bootstrap configuration file called * OpenSSOAgentBootstrap.properties to get the agent startup configuration that * includes the OpenSSO (OpenSSO) server information and the * agent user credential. It uses these information to authenticate to * the OpenSSO server. The OpenSSO Authentication service completes the agent * authentication and sends a SSO token back to the agent. Using the SSO * token, the agent calls the OpenSSO Attribute service to fetch its * configuration. The OpenSSO Attribute service sends the agent configuration * back to the agent. The agent configuration returned contains the agent * configuration repository location. If the location is "centralized", * then agent will use the agent configuration just returned. If the * location is "local" or not present, then the agent knows that its * configuration is at the local. It reads the rest of its configuration * from the local configuration file OpenSSOAgentConfiguration.properties. *

* Most of the agent configuration properties are hot swappable. The * changes to these properties are effective without having to restart * the agent container. The property changes are updated at the agent * in two ways. The agent configuration change notification and agent * configuration change polling. *

* The agent configuration change notification is available in the case * of the agent configuration is centralized. Anytime one or more agent * properties are changed in the OpenSSO, a notification is sent to the agent. * Upon receiving the notification, the affected agent will refetch its * from the OpenSSO server and updates its configuration using the new values. *

* Configuration polling updates are available if the configuration setting * com.sun.identity.agents.j2ee.config.load.interval has been set * to a non-zero positive value indicating the number of seconds after which * the system will poll to identify configuration changes. If this value is set * to zero, the configuration reloads will be disabled. Every time a * configuration reload occurs, the value of the configuration setting that * governs the reload interval is also recalculated, thereby making it possible * to dynamically disable reloads by setting the value to zero when reloads are * active. Note that in the event of a reload, only the configuration keys that * are designated for Agent operation are reloaded. These keys begin with the * com.sun.identity.agents.config prefix. The keys that do * not match this criteria are kept unchanged and reflect the values that were * present during system initialization. Certain keys which meet this crieteria * would still not be reloaded due to potential security concerns associated * with the swapping of the associated values. *

* General access methods in this class are package protected and thus cannot * be directly invoked by classes that are not within the same package. It is * expected and required that all configuration access be done via a designated * Manager of the subsystem which in turn acts as an intermediate * caching point for configuration values. Public methods are available for * configuration settings that are considered core settings. *

* * @see com.sun.identity.agents.arch.Manager * @see com.sun.identity.agents.arch.IConfigurationListener */ public class AgentConfiguration implements IAgentConfigurationConstants, IConfigurationKeyConstants, IClientConfigurationKeyConstants, IConfigurationDefaultValueConstants { /** * A constant value used to identify the default web application context * for configuration settings that are application specific. */ public static final String DEFAULT_WEB_APPLICATION_NAME = "DefaultWebApp"; private static final String ATTRIBUTE_SERVICE_NAME = "idsvcs-rest"; private static final String AGENT_CONFIG_CENTRALIZED = "centralized"; private static final String AGENT_CONFIG_LOCAL = "local"; /** * Returns a header name that contains the client IP address. If no header * name is specified in the configuration file, this method will return * null. * * @return a header name that contains client IP address or null * if no header name is specified. */ public static String getClientIPAddressHeader() { return _clientIPAddressHeader; } /** * Returns a header name that contains the client hostname. If no header * name is specified in the configuration file, this method will return * null. * * @return a header name that contains client hostname or null * if no header name is specified. */ public static String getClientHostNameHeader() { return _clientHostNameHeader; } /** * Returns the name of the organization that can be used for authenticating * the Agent services. This value represents the organization name or the * realm name to which the Agent profile belongs. * * @return the organization or realm name to which the Agent profile belongs. */ public static String getOrganizationName() { return _organizationName; } public static String getServerHost() { return getProperty("com.iplanet.am.server.host"); } public static String getServerPort() { return getProperty("com.iplanet.am.server.port"); } public static String getServerProtocol() { return getProperty("com.iplanet.am.server.protocol"); } public static String getPolicyAdmLocation() { return _policyAdminLoc; } /** * Returns a boolean indicating if the notifications for Policy changes * have been set as enabled. * @return true if notifications for Policy are enabled, * false otherwise. */ public static boolean isPolicyNotificationEnabled() { return _policyNotificationEnabledFlag; } /** * Returns the URL that will be used by the Server to send all * notifications to agents. This will include policy, session, and agent * configuration change notifications. * @return the client notification URL. */ public static String getClientNotificationURL() { return _clientNotificationURL; } /** * Returns a boolean indicating if the notificatiosn for Sessino changes have * been set as enabled. * * @return true if notifications for Session are enabled, * false otherwise. */ public static boolean isSessionNotificationEnabled() { return _sessionNotificationEnabledFlag; } /** * Returns the name of the OpenSSO Session property that is used by * the Agent runtime to identify the user-id of the current user. * * @return the Session property name that identifies the user-id of the * current user. */ public static String getUserIdPropertyName() { return _userIdPropertyName; } /** * A method that ensures that any class that directly depends * upon Client SDK can first initialize the AgentConfiguration. * Failing to initialize the AgentConfiguration can result * in the malfunction of the Client SDK due to configuration dependancies. */ public static void initialize() { // No processing requried } /** * Returns the name of the cookie or URI parameter that holds the users * SSO token. * * @return the SSO token cookie or parameter name. */ public static synchronized String getSSOTokenName() { return _ssoTokenCookieName; } /** * Returns the ServiceResolver instance associated with the * Agent runtime. * @return the configured ServiceResolver. */ public static ServiceResolver getServiceResolver() { return _serviceResolver; } /** * Returns the UserMapingMode configured in the system. This * setting is not hot-swappable and is initialized during system * initialization and never changed thereafter. * * @return the configured UserMappingMode. */ public static UserMappingMode getUserMappingMode() { return _userMappingMode; } /** * Returns the AuditLogMode configured in the system. This * setting is not hot-swappable and is initialized during system * initialization and never changed thereafeter. * * @return the configured AuditLogMode. */ public static AuditLogMode getAuditLogMode() { return _auditLogMode; } /** * Returns the user attribute value configured in the system. This setting * is not hot-swappable and is initialized during system initialization and * never changed thereafter. * * @return the configured user attribute value. */ public static String getUserAttributeName() { return _userAttributeName; } /** * Returns true if the runtime is configured to use the user's * DN instead of the regular userid for * identification purposes. This setting is not hot-swappable and is * initialized during system initialization and never changed thereafter. * * @return true if the system is configured to use the user's * DN for identification purposes, false otherwise. */ public static boolean isUserPrincipalEnabled() { return _userPrincipalEnabled; } /** * Allows other parts of the subsystem to register for configuration * change events by registering the specified * IConfigurationListener. * * @param listener the IConfigurationListener to be registered. */ public static void addConfigurationListener( IConfigurationListener listener) { if(isLogMessageEnabled()) { logMessage("AgentConfiguration: Adding listener for : " + listener.getName()); } Vector configurationListeners = getModuleConfigurationListeners(); synchronized(configurationListeners) { configurationListeners.add(listener); } } /** * Returns the application user name to be used to identify the Agent * runtime. * * @return the application user name. */ public static String getApplicationUser() { return _applicationUser; } /** * Returns the application password to be used to identify the Agent * runtime. * * @return the application password. */ public static String getApplicationPassword() { return _applicationPassword; } /** * Would be called by agent configuration notification handler when the * agent housekeeping app receives configuration update notifications from * the OpenSSO server */ public static void updatePropertiesUponNotification() { if(isAgentConfigurationRemote()) { hotSwapAgentConfiguration(true); if (isLogMessageEnabled()) { logMessage( "AgentConfiguration.updatePropertiesUponNotification():" + " updating configuration from a notification while" + " in centralized mode."); } } else { if (isLogMessageEnabled()) { logMessage( "AgentConfiguration.updatePropertiesUponNotification():" + " caller trying to update configuration from a" + " notification while in local mode." + " Should only be called when in centralized mode."); } } } /** * Returns the configuration value corresponding to the specified * id or the supplied defaultValue if not * present. * * @param id the configuration key to be looked up. * @param defaultValue the default value to be used in case no configuration * is specified for the given id. * * @return the associated configuration value with the specified * id or the defaultValue if no value is specified * in the configuration. */ static String getProperty(String id, String defaultValue) { String value = getProperty(id); if (value == null) { value = defaultValue; } return value; } /** * Returns the configuration value corresponding to the specified * id or null if no value is present. * * @param id the configuration key to be looked up. * * @return the associated configuration value with the specified * id or null if no value is specified in the * configuration. */ static String getProperty(String id) { String result = null; String value = SystemProperties.get(id); if (value == null) { value = getPropertyInternal(id); } if (value != null && value.trim().length() > 0) { result = value.trim(); } return result; } /** * Returns a Properties instance that holds all the available * configuration as available in the system. * * @return the configuration as a Properties instance. */ static Properties getAll() { Properties result = getAllInternal(); Iterator it = SystemProperties.getProperties().keySet().iterator(); while (it.hasNext()) { String nextKey = (String) it.next(); result.put(nextKey, SystemProperties.get(nextKey)); } return result; } private synchronized static String getPropertyInternal(String id) { return getProperties().getProperty(id); } private synchronized static Properties getAllInternal() { Properties properties = new Properties(); properties.putAll(getProperties()); return properties; } /* * This method will check for the JVM option: * * openam.agents.bootstrap.dir * * before falling back to trying to load the file from the CLASSPATH */ private static synchronized void setConfigurationFilePath() { if (!isInitialized()) { String bootstrapDir = System.getProperty(CONFIG_JVM_OPTION_NAME); // try to load the bootstrap from the JVM option if (bootstrapDir != null) { String configFile = bootstrapDir + System.getProperty("file.separator") + CONFIG_FILE_NAME; String localConfigFile = bootstrapDir + System.getProperty("file.separator") + LOCAL_CONFIG_FILE_NAME; if (isFileValid(configFile) && isFileValid(localConfigFile)) { setConfigFilePath(configFile); setLocalConfigFilePath(localConfigFile); return; } } // fallback to loading the bootstrap file from the classpath String result = null; URL resUrl = ClassLoader.getSystemResource(CONFIG_FILE_NAME); if(resUrl == null) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if(cl != null) { resUrl = cl.getResource(CONFIG_FILE_NAME); } } if (resUrl == null) { throw new RuntimeException( "Failed to get configuration file:" + CONFIG_FILE_NAME); } result = resUrl.getPath(); try { if (System.getProperty("file.separator").equals("\\") && result.startsWith("/")) { result = resUrl.toURI().getPath().substring(1); } } catch (Exception ex) { throw new RuntimeException( "Failed to get absolute file path:" + CONFIG_FILE_NAME); } if (result == null) { throw new RuntimeException( "Failed to get configuration file:" + CONFIG_FILE_NAME); } setConfigFilePath(result); int index = result.lastIndexOf(CONFIG_FILE_NAME); if (index < 0) { throw new RuntimeException( "Failed to find the agent bootstrap file:" + CONFIG_FILE_NAME); } String pathDir = result.substring(0, index); setLocalConfigFilePath(pathDir + LOCAL_CONFIG_FILE_NAME); } } /* * Is file valid @param filename * * @return boolean */ private static boolean isFileValid(String filename) { boolean result = false; if ((filename != null) && (filename.length() > 0)) { File file = new File(filename); if (file.exists() && file.isFile() && file.canRead()) { result = true; } } return result; } /** * Load from OpenSSOAgentBootstrap.properties for start up properties. * This method should only be called once at start up time * since bootstrap properties are not hot swappable by editing the * properties file without a restart. * If it is called more than once(already initialized, then it will just * return the bootstrap properties that were read and saved at start * up time. **/ private static Properties getPropertiesFromConfigFile() throws Exception { Properties result = new Properties(); if (!isInitialized()) { BufferedInputStream instream = null; try { instream = new BufferedInputStream( new FileInputStream(getConfigFilePath())); result.load(instream); setBootstrapProperties(result); } catch (Exception ex) { throw ex; } finally { if (instream != null) { try { instream.close(); } catch (Exception ex) { // No handling required } } } } else { //already initialized //this is to enforce that coders do not accidently try to re-read //the agents bootstrap configuration file. If already initialized //then will return the original set of bootstrap properties result = getBootstrapProperties(); } return result; } private static Properties getPropertiesFromRemote(Vector urls) throws AgentException { Properties result = new Properties(); String tokenId = getAppSSOToken().getTokenID().toString(); result = AgentRemoteConfigUtils.getAgentProperties( urls, tokenId, getProfileName(), getOrganizationName()); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Centralized agent properties =" + result); } return result; } private static Properties getPropertiesFromLocal() throws AgentException { Properties result = new Properties(); BufferedInputStream instream = null; try { instream = new BufferedInputStream( new FileInputStream(getLocalConfigFilePath())); result.load(instream); } catch (Exception ex) { throw new AgentException(ex); } finally { if (instream != null) { try { instream.close(); } catch (Exception ex) { // No handling required } } } if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Local config properties =" + result); } return result; } private static void setAppSSOToken() throws AgentException { CommonFactory cf = new CommonFactory(BaseModule.getModule()); IApplicationSSOTokenProvider provider = cf.newApplicationSSOTokenProvider(); _appSSOToken = provider.getApplicationSSOToken(true); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: appSSOToken =" + _appSSOToken); } } public static synchronized SSOToken getAppSSOToken() throws AgentException { if (_appSSOToken != null) { try { // check if token is still valid with the session server. // This refreshSession call throws a SSOException if the token // is not valid any more. SSOTokenManager.getInstance().refreshSession(_appSSOToken); } catch (SSOException se) { if (isLogMessageEnabled()) { logMessage("AgentConfiguration.getAppSSOToken: " + "The app SSO token is invalid, indicating openam " + "server may have restarted, so need to " + "reauthenticate to get a new app SSO token"); } setAppSSOToken(); } } else { setAppSSOToken(); } return _appSSOToken; } private static Vector getAttributeServiceURLs() throws AgentException { if (_attributeServiceURLs == null) { try { _attributeServiceURLs = WebtopNaming.getServiceAllURLs( ATTRIBUTE_SERVICE_NAME); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: attribute service urls" + _attributeServiceURLs); } } catch (URLNotFoundException ue) { throw new AgentException(ue); } } return _attributeServiceURLs; } /** * Collect all configuration info. Store all config properties, including * OpenSSOAgentBootstrap.properties bootstrap small set of props and also * agent config props (from OpenSSO server or if local config file * OpenSSOAgentConfiguration.properties) and store ALL the properties in a * class field for later use, plus set a few fields on this class for some * props that are used throughout agent code and accessed from this class. * Also, for any clientsdk properties, push them into the JVM system * properties so they can be accessed by clientsdk. * All non-system properties start with AGENT_CONFIG_PREFIX and this is how * we distinguish between agent properties and clientsdk properties. * Note, a few clientsdk props (like notification url and notification * enable flags) are ALSO stored by this class in fields since * they are also use throughout agent code as well as by clientsdk. */ private static synchronized void bootStrapClientConfiguration() { if (!isInitialized()) { HashMap sysPropertyMap = null; setConfigurationFilePath(); try { sysPropertyMap = new HashMap(); Properties properties = getProperties(); properties.clear(); properties.putAll(getPropertiesFromConfigFile()); //debug level can optionally be set in OpenSSOAgentBootstrap.properties //but by default is not set, so we provide default if no value //This debug level(either default or prop in OpenSSOAgentBootstrap.properties) //file is only used for bootup time logging. //Real runtime debug level value is later retrieved with rest of //agent config from OpenSSO server String initialDebugLevel = properties.getProperty( Constants.SERVICES_DEBUG_LEVEL); if ((initialDebugLevel == null) || (initialDebugLevel.trim().length() == 0)) { properties.setProperty( Constants.SERVICES_DEBUG_LEVEL, Debug.STR_MESSAGE); } //push the bootstrap properties to JVM system properties Iterator iter = properties.keySet().iterator(); while (iter.hasNext()) { String nextKey = (String) iter.next(); if (!nextKey.startsWith(AGENT_CONFIG_PREFIX)) { String nextValue = getProperties().getProperty(nextKey); SystemProperties.initializeProperties(nextKey, nextValue); //save in sysPropertyMap for upcoming log messages sysPropertyMap.put(nextKey, nextValue); } } //app sso token provider plugin property and value are not //exposed to users so not in bootstrap property file SystemProperties.initializeProperties( ClientSDKAppSSOProvider.CLIENT_SDK_ADMIN_TOKEN_PROPERTY, ClientSDKAppSSOProvider.APP_SSO_PROVIDER_PLUGIN); setDebug(Debug.getInstance(IBaseModuleConstants.BASE_RESOURCE)); setOrganizationName(); setServiceResolver(); setApplicationUser(); setApplicationPassword(); setPolicyAdminLoc(); setAppSSOToken(); setLockConfig(); setProfileName(); // instantiate the instance of DebugPropertiesObserver debugObserver = DebugPropertiesObserver.getInstance(); Vector attrServiceURLs = getAttributeServiceURLs(); //if OpenSSO server 8.0 if (attrServiceURLs != null) { Properties propsFromOpenSSOserver = getPropertiesFromRemote(attrServiceURLs); String agentConfigLocation = propsFromOpenSSOserver.getProperty(CONFIG_REPOSITORY_LOCATION); //if agent profile on OpenSSO server is 2.2 style(null or //blank value)-maybe to help agent upgrade use case) //OR agent profile is 3.0 style(common case) with local //config flag set if ((agentConfigLocation == null) || (agentConfigLocation.trim().equals("")) || (agentConfigLocation.equalsIgnoreCase( AGENT_CONFIG_LOCAL))) { properties.putAll(getPropertiesFromLocal()); } else if (agentConfigLocation.equalsIgnoreCase( AGENT_CONFIG_CENTRALIZED)) { markAgentConfigurationRemote(); properties.putAll(propsFromOpenSSOserver); } else { throw new AgentException("Invalid agent config" + "location: does not specify local or centralized"); } } else { //else if Access Manager 7.1/7.0 server // Need to read the rest of agent config from its local // configuration file properties.putAll(getPropertiesFromLocal()); } Iterator it = properties.keySet().iterator(); while (it.hasNext()) { String nextKey = (String) it.next(); if (!nextKey.startsWith(AGENT_CONFIG_PREFIX)) { String nextValue = getProperties().getProperty(nextKey); SystemProperties.initializeProperties(nextKey, nextValue); //save in sysPropertyMap for upcoming log messages sysPropertyMap.put(nextKey, nextValue); } } // notify possible debug level change if (debugObserver != null) { debugObserver.notifyChanges(); } //used by agentsdk and clientsdk, not hot swappable setClientNotificationURL(); String modIntervalString = getProperty(CONFIG_LOAD_INTERVAL); try { long modInterval = Long.parseLong(modIntervalString); setModInterval(modInterval * 1000L); } catch (NumberFormatException nfex) { System.err.println( "AgentConfiguration: Exception while reading " + "new mod interval: \"" + modIntervalString + "\""); } markCurrent(); } catch (Exception ex) { ex.printStackTrace(System.err); throw new RuntimeException("Failed to load configuration: " + ex.getMessage()); } if (isLogMessageEnabled()) { if (sysPropertyMap != null) { logMessage( "AgentConfiguration: The following properties " + "were added to system: " + sysPropertyMap); } else { logMessage( "AgentConfiguration: No properties were added " + " to system."); } logMessage("AgentConfiguration: Mod Interval is set to: " + getModInterval() + " ms."); } //Start the Configuration Monitor if necessary if (!getLockConfig()) { GeneralTaskRunnable monitorRunnable = new ConfigurationMonitor(); SystemTimer.getTimer().schedule(monitorRunnable, new Date(( System.currentTimeMillis() / 1000) * 1000)); } } } /** * Registers the agent config notification handler with PLLClient. The * handler is registered once and exists for continuous hot swaps if an * agent is configured to enable agent configuration updates from the OpenSSO * server. The handler is used by notification filter task handler when * the filter receives agent configuration XML notifications. This method * only needs to be called once when the agent boots up and initializes. */ private static void registerAgentNotificationHandler () { AgentConfigNotificationHandler handler = new AgentConfigNotificationHandler(); try { PLLClient.addNotificationHandler( AgentConfigNotificationHandler.AGENT_CONFIG_SERVICE, handler); if (isLogMessageEnabled()) { logMessage( "AgentConfiguration.registerAgentNotificationHandler():" + " registered handler for accepting agent configuration" + " notifications while in centralized mode."); } } catch (AlreadyRegisteredException arex) { //should only be one handler per VM since static & global //so probably will never happen if(isLogWarningEnabled()){ logWarning("AgentConfiguration.registerAgentNotificationHandler" + " Tried to register the AgentConfigNotificationHandler" + " with PLL Client but PLL client already has it" + " registered." , arex ); } } } private static synchronized void setServiceResolver() { if (!isInitialized()) { String serviceResolverClassName = getProperty(CONFIG_SERVICE_RESOLVER); try { if (isLogMessageEnabled()) { logMessage( "AgentConfiguration: service resolver set to: " + serviceResolverClassName); } _serviceResolver = (ServiceResolver) Class.forName( serviceResolverClassName).newInstance(); if (isLogMessageEnabled()) { logMessage( "AgentConfiguration: service resolver reports " + "EJBContext available: " + _serviceResolver.isEJBContextAvailable()); } } catch (Exception ex) { logError( "AgentConfiguration: Failed to set Service Resolver: " + serviceResolverClassName, ex); throw new RuntimeException( "Failed to set Service Resolver: " + serviceResolverClassName + ": " + ex.getMessage()); } } } private static synchronized void setOrganizationName() { if (!isInitialized()) { _organizationName = getProperty(CONFIG_ORG_NAME); if (_organizationName == null || _organizationName.trim().length() == 0) { _organizationName = DEFAULT_ORG_NAME; if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setOrganizationName:" + " organization name for realm is not set in the" + " agent bootstrap file, so using the default" + " root realm = " + _organizationName); } } else { if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setOrganizationName:" + " organization name for realm is set to: " + _organizationName); } } } } private static synchronized void setUserMappingMode() { UserMappingMode mode = UserMappingMode.get( getProperty(CONFIG_USER_MAPPING_MODE)); if (mode == null) { throw new RuntimeException("Unknown User Mapping Mode: " + getProperty(CONFIG_USER_MAPPING_MODE)); } _userMappingMode = mode; if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setUserMappingMode: User Mapping" + " mode set to: " + _userMappingMode); } } private static synchronized void setAuditLogMode() { AuditLogMode mode = AuditLogMode.get( getProperty(CONFIG_AUDIT_LOG_MODE)); if (mode == null) { throw new RuntimeException("Unknown Audit Log Mode: " + getProperty(CONFIG_AUDIT_LOG_MODE)); } _auditLogMode = mode; if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setAuditLogMode: Audit Log mode" + " set to: " + _auditLogMode); } } private static synchronized void setUserAttributeName() { String userAttributeName = getProperty(CONFIG_USER_ATTRIBUTE_NAME); if (userAttributeName == null || userAttributeName.trim().length() == 0) { userAttributeName = DEFAULT_USER_ATTRIBUTE_NAME; logError("AgentConfiguation.setUserAttributeName: Unable to load" + " user attribute name. Using default value: " + userAttributeName); } _userAttributeName = userAttributeName; if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setUserAttributeName: User" + " attribute name set to: " + _userAttributeName); } } private static synchronized void setUserPrincipalEnabledFlag() { String userPrinsipalFlagString = getProperty(CONFIG_USER_PRINCIPAL); if (userPrinsipalFlagString == null || userPrinsipalFlagString.trim().length() == 0) { userPrinsipalFlagString = DEFAULT_USE_DN; } _userPrincipalEnabled = Boolean.valueOf( userPrinsipalFlagString).booleanValue(); if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setUserPrincipalEnabledFlag: use-DN" + " User Principal Enabled Flag is set to: " + _userPrincipalEnabled); } } private static synchronized void setSSOTokenName() { if (!isInitialized()) { _ssoTokenCookieName = getProperty(SDKPROP_SSO_COOKIE_NAME); if (_ssoTokenCookieName == null || _ssoTokenCookieName.trim().length() == 0) { throw new RuntimeException("Invalid SSO Cookie name set"); } if (isLogMessageEnabled()) { logMessage("AgentConfiguration: SSO Token name set to: " + _ssoTokenCookieName); } } } private static synchronized void setPolicyAdminLoc() { if (!isInitialized()) { _policyAdminLoc = getProperty("com.sun.identity.agent.policyadmin.location"); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Policy Admin Location: " + _policyAdminLoc); } } } private static synchronized void setApplicationUser() { if (!isInitialized()) { _applicationUser = getProperty(SDKPROP_APP_USERNAME); if (_applicationUser == null || _applicationUser.trim().length()==0) { throw new RuntimeException( "Invalid application user specified"); } if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Application User: " + _applicationUser); } } } private static synchronized void setApplicationPassword() { if (!isInitialized()) { try { _crypt = ServiceFactory.getCryptProvider(); if(_crypt != null) { String encodedPass = getProperty(SDKPROP_APP_PASSWORD); _applicationPassword = _crypt.decrypt(encodedPass); } } catch (Exception ex) { logError("AgentConfiguration: Unable to create new instance of " + "Crypt class with exception ", ex); } if (_applicationPassword == null || _applicationPassword.trim().length() == 0) { throw new RuntimeException( "Invalid application password specified"); } } } private static synchronized void setProfileName() { if (!isInitialized()) { _profileName = getProperty(CONFIG_PROFILE_NAME); if ((_profileName == null) ||(_profileName.trim().length() == 0)) { _profileName = getApplicationUser(); } if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Profile Name: " + _profileName); } } } private static synchronized void setUserIdPropertyName() { String propertyName = getProperty(CONFIG_USER_ID_PROPERTY); if (propertyName == null || propertyName.trim().length() == 0) { propertyName = DEFAULT_USER_ID_PROPERTY; if (isLogWarningEnabled()) { logWarning("AgentConfiguration.setUserIdPropertyName: No value" + " specified for user id property name. Using default: " + propertyName); } } _userIdPropertyName = propertyName; if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setUserIdPropertyName: User id" + " property name set to: " + _userIdPropertyName); } } //this property is a hot swappable ClientSDK property private static synchronized void setSessionNotificationEnabledFlag() { _sessionNotificationEnabledFlag = true; boolean pollingEnabled = false; String flag = getProperty(SDKPROP_SESSION_POLLING_ENABLE); if (flag != null && flag.trim().length() > 0) { pollingEnabled = Boolean.valueOf(flag).booleanValue(); } _sessionNotificationEnabledFlag = !pollingEnabled; if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Session notification enable: " + _sessionNotificationEnabledFlag); } } //this property is used by both the agentsdk code and also the clientsdk private static synchronized void setClientNotificationURL() { if (!isInitialized()) { String url = getProperty(SDKPROP_CLIENT_NOTIFICATION_URL); if (url != null && url.trim().length() > 0) { _clientNotificationURL = url; } else { if (isLogWarningEnabled()) { logWarning( "AgentConfiguration: No client notification URL set"); } } if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Client notification URL: " + _clientNotificationURL); } } } //this property is a hot swappable ClientSDK property private static synchronized void setPolicyNotificationEnabledFlag() { boolean enable = false; String flag = getProperty(SDKPROP_POLICY_NOTIFICATION_ENABLE); if (flag != null && flag.trim().length() > 0) { enable = Boolean.valueOf(flag).booleanValue(); } _policyNotificationEnabledFlag = enable; if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Policy notification enable: " + _policyNotificationEnabledFlag); } } private static synchronized void setClientIPAddressHeader() { _clientIPAddressHeader = getProperty(CONFIG_CLIENT_IP_HEADER); if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setClientIPAddressHeader:" + " Client IP Address Header: " + _clientIPAddressHeader); } } private static synchronized void setClientHostNameHeader() { _clientHostNameHeader = getProperty(CONFIG_CLIENT_HOSTNAME_HEADER); if (isLogMessageEnabled()) { logMessage("AgentConfiguration.setClientHostNameHeader: Client" + " Hostname Header: " + _clientHostNameHeader); } } private static synchronized void initializeConfiguration() { if (!isInitialized()) { //read in all properties, save all props & values in map to use //later and push some to system for clientsdk bootStrapClientConfiguration(); registerAgentNotificationHandler(); //now set some class fields with property values setHotSwappableConfigProps(); //set fields as some clientsdk props also used by agent code setSSOTokenName(); setHotSwappableClientSDKProps(); logAgentVersion(); logServerVersion(); logAgentEnv(); markInitialized(); } } /** * Logs the version information for the running agent. */ private static void logAgentVersion() { logError(Version.getVersion()); } /** * Logs some of the system env information for the running agent. */ private static void logAgentEnv() { if (isLogMessageEnabled()) { logMessage("Agent Env information:"); logMessage("Java version=" + System.getProperty("java.version")); logMessage("Java vendor=" + System.getProperty("java.vendor")); logMessage("OS arch info=" + System.getProperty("os.arch")); logMessage("OS name=" + System.getProperty("os.name")); logMessage("OS version=" + System.getProperty("os.version")); } } /** * Logs the version of OpenSSO Server. */ private static void logServerVersion() { String version = null; try { Vector attrServiceURLs = getAttributeServiceURLs(); version = AgentRemoteConfigUtils.getServerVersion(attrServiceURLs, getDebug()); if (version == null || version.length() == 0) { version = "Access Manager 7.x Server"; } } catch (AgentException ex) { version = "Unknown Server Version due to: " + ex.getMessage(); } if (isLogMessageEnabled()) { logMessage("AgentConfiguration.logServerVersion() - \n\n" + "------------------------------------------------\n" + "OpenAM Server Version:" + version + "\n" + "------------------------------------------------\n"); } } /** * Some properties managed by this class are hotswappable and should be * set on initialization and reload of configuration property values */ private static void setHotSwappableConfigProps() { setAuditLogMode(); setUserMappingMode(); setUserAttributeName(); setUserPrincipalEnabledFlag(); setUserIdPropertyName(); setClientIPAddressHeader(); setClientHostNameHeader(); } /** * some of clientSDK props are hot-swappable and are used by clientSDK thru * SystemProperties helper class and are ALSO used by agent code and hence * we store their current values in some fields. */ private static void setHotSwappableClientSDKProps() { setSessionNotificationEnabledFlag(); setPolicyNotificationEnabledFlag(); } private static void logMessage(String msg) { getDebug().message(msg); } private static void logMessage(String msg, Throwable th) { getDebug().message(msg, th); } private static void logWarning(String msg) { getDebug().warning(msg); } private static void logWarning(String msg, Throwable th) { getDebug().warning(msg, th); } private static void logError(String msg) { getDebug().error(msg); } private static void logError(String msg, Throwable th) { getDebug().error(msg, th); } private static boolean isLogWarningEnabled() { return getDebug().warningEnabled(); } private static boolean isLogMessageEnabled() { return getDebug().messageEnabled(); } private static void updatePropertiesUponPolling() { if (needToRefresh()) { if (!isAgentConfigurationRemote()) { File configFile = new File(getLocalConfigFilePath()); if (!configFile.exists()) { configFile = new File(getConfigFilePath()); } if(getLastLoadTime() > configFile.lastModified()) { markCurrent(); return; } } hotSwapAgentConfiguration(false); } } private static void hotSwapAgentConfiguration(boolean fromNotification) { // if lock config is enabled, there will be no config change. if (getLockConfig()) { if (isLogMessageEnabled()) { logMessage("AgentConfiguration.hotSwapAgentConfiguration() - " + "Agent config is locked, there's no config update."); } return; } if (loadProperties(fromNotification)) { notifyModuleConfigurationListeners(); // notify possible debug level change if (debugObserver != null) { debugObserver.notifyChanges(); } } } private static void notifyModuleConfigurationListeners() { Vector configurationListeners = getModuleConfigurationListeners(); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: Notifying all listeners"); } synchronized(configurationListeners) { for(int i = 0; i < configurationListeners.size(); i++) { IConfigurationListener nextListener = (IConfigurationListener) configurationListeners.get(i); nextListener.configurationChanged(); if(isLogMessageEnabled()) { logMessage("AgentConfiguration: Notified listener for " + nextListener.getName()); } } } } private synchronized static boolean loadProperties( boolean fromNotification) { boolean result = false; try { Properties properties = new Properties(); properties.clear(); //add in bootstrap properties which were saved on //agent initial start up properties.putAll(getBootstrapProperties()); Properties tempProperties; if (!isAgentConfigurationRemote()) { tempProperties = getPropertiesFromLocal(); } else { tempProperties = getPropertiesFromRemote( getAttributeServiceURLs()); } // check and return if notification.enabled is false. String notificationEnabled = tempProperties.getProperty( CONFIG_CENTRALIZED_NOTIFICATION_ENABLE, DEFAULT_CENTRALIZED_NOTIFICATION_ENABLE); if (fromNotification && !notificationEnabled.equalsIgnoreCase("true")) { if (isLogMessageEnabled()) { logMessage("AgentConfiguration: received config " + "notification, but no update " + "since notification enabled is false"); } return false; } String modIntervalString = tempProperties.getProperty( CONFIG_LOAD_INTERVAL); if (isLogMessageEnabled()) { logMessage("AgentConfiguration: interval=" + modIntervalString); } if (modIntervalString != null && modIntervalString.trim().length()>0) { modIntervalString = modIntervalString.trim(); } else { logWarning("AgentConfiguration: No mod interval setting found"); modIntervalString = "0"; } long modInterval = 0L; try { modInterval = Long.parseLong(modIntervalString); } catch (NumberFormatException nfex) { logWarning("AgentConfiguration: Exception while reading " + "new mod interval: \"" + modIntervalString + "\""); } if (!fromNotification && modInterval == 0) { setModInterval(modInterval); return false; } properties.putAll(tempProperties); setModInterval(modInterval*1000L); getProperties().clear(); getProperties().putAll(properties); markCurrent(); Iterator it = properties.keySet().iterator(); while (it.hasNext()) { String nextKey = (String) it.next(); if (!nextKey.startsWith(AGENT_CONFIG_PREFIX)) { String nextValue = getProperties().getProperty(nextKey); SystemProperties.initializeProperties(nextKey, nextValue); } } //set local copies of config property values stored by this class setHotSwappableConfigProps(); //set local copies of some clientsdk property values we store setHotSwappableClientSDKProps(); result = true; if (isLogMessageEnabled()) { logMessage("AgentConfiguration: loaded new configuration."); } } catch (Exception ex) { result = false; logError("AgentConfiguration: Exception during reload:", ex); logError("AgentConfiguration: Setting reload interval to 0"); setModInterval(0L); } return result; } private static boolean needToRefresh() { return((System.currentTimeMillis() - getLastLoadTime()) >= getModInterval()); } private static class ConfigurationMonitor extends GeneralTaskRunnable { public ConfigurationMonitor() { if(isLogMessageEnabled()) { logMessage("AgentConfiguration: Monitor initialized"); } } public boolean isEmpty() { return true; } public boolean addElement(Object obj) { return false; } public boolean removeElement(Object obj) { return false; } public long getRunPeriod() { long interval = getModInterval(); if (interval == 0L) { interval = 3600000L; } // 1 hour. return interval; } public void run() { if(isLogMessageEnabled()) { logMessage("AgentConfiguration: Monitor started"); } updatePropertiesUponPolling(); } } private static boolean isInitialized() { return _initialized; } private static void markInitialized() { if (!isInitialized()) { _initialized = true; if (isLogMessageEnabled()) { logMessage("AgentConfiguration: initialized."); } } } private static boolean isAgentConfigurationRemote() { return _isAgentConfigurationRemote; } private static void markAgentConfigurationRemote() { _isAgentConfigurationRemote = true; } private static String getConfigFilePath() { return _configFilePath; } private static void setConfigFilePath(String configFilePath) { _configFilePath = configFilePath; } private static String getLocalConfigFilePath() { return _localConfigFilePath; } private static void setLocalConfigFilePath(String localConfigFilePath) { _localConfigFilePath = localConfigFilePath; } private static Properties getProperties() { return _properties; } private static void setDebug(Debug debug) { _debug = debug; } private static Debug getDebug() { return _debug; } private static void setModInterval(long modInterval) { _modInterval = modInterval; } private static long getModInterval() { return _modInterval; } private static long getLastLoadTime() { return _lastLoadTime; } private static void markCurrent() { _lastLoadTime = System.currentTimeMillis(); } private static Vector getModuleConfigurationListeners() { return _moduleConfigListeners; } private static void setBootstrapProperties(Properties bootstrapProperties){ //ensure its only set once at start up, not on configuration reloads if (!isInitialized()) { _bootstrapProperties.putAll(bootstrapProperties); } } private static Properties getBootstrapProperties() { return _bootstrapProperties; } private static boolean getLockConfig() { return _lockConfig; } private static String getProfileName() { return _profileName; } private static void setLockConfig() { if (!isInitialized()) { String lockConfig = getProperty(CONFIG_LOCK_ENABLE); if (lockConfig != null && lockConfig.equalsIgnoreCase("true")) { _lockConfig = true; } } } private static boolean _isAgentConfigurationRemote = false; private static boolean _initialized; private static String _configFilePath; private static String _localConfigFilePath; private static Properties _properties = new Properties(); private static Properties _bootstrapProperties = new Properties(); private static Debug _debug; private static long _modInterval = 0L; private static long _lastLoadTime = 0L; private static Vector _moduleConfigListeners = new Vector(); private static ServiceResolver _serviceResolver; private static String _organizationName = DEFAULT_ORG_NAME; private static UserMappingMode _userMappingMode = UserMappingMode.MODE_USER_ID; private static String _userAttributeName; private static boolean _userPrincipalEnabled; private static String _ssoTokenCookieName; private static String _applicationUser; private static String _applicationPassword; private static String _policyAdminLoc; private static String _userIdPropertyName; private static AuditLogMode _auditLogMode = AuditLogMode.MODE_BOTH; private static String _clientNotificationURL; private static boolean _policyNotificationEnabledFlag; private static boolean _sessionNotificationEnabledFlag; private static String _clientIPAddressHeader; private static String _clientHostNameHeader; private static ICrypt _crypt; private static SSOToken _appSSOToken = null; private static Vector _attributeServiceURLs = null; private static DebugPropertiesObserver debugObserver; private static boolean _lockConfig = false; private static String _profileName; static { initializeConfiguration(); } }