/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm; import com.novell.ldapchai.ChaiFactory; import com.novell.ldapchai.ChaiUser; import com.novell.ldapchai.exception.ChaiUnavailableException; import com.novell.ldapchai.provider.ChaiProvider; import password.pwm.bean.SmsItemBean; import password.pwm.bean.UserIdentity; import password.pwm.config.Configuration; import password.pwm.config.PwmSetting; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmException; import password.pwm.error.PwmUnrecoverableException; import password.pwm.health.HealthMonitor; import password.pwm.http.servlet.resource.ResourceServletService; import password.pwm.http.state.SessionStateService; import password.pwm.ldap.LdapConnectionService; import password.pwm.ldap.search.UserSearchEngine; import password.pwm.svc.PwmService; import password.pwm.svc.PwmServiceManager; import password.pwm.svc.cache.CacheService; import password.pwm.svc.event.AuditEvent; import password.pwm.svc.event.AuditRecordFactory; import password.pwm.svc.event.AuditService; import password.pwm.svc.event.SystemAuditRecord; import password.pwm.svc.intruder.IntruderManager; import password.pwm.svc.intruder.RecordType; import password.pwm.svc.report.ReportService; import password.pwm.svc.sessiontrack.SessionTrackService; import password.pwm.svc.shorturl.UrlShortenerService; import password.pwm.svc.stats.Statistic; import password.pwm.svc.stats.StatisticsManager; import password.pwm.svc.token.TokenService; import password.pwm.svc.wordlist.SeedlistManager; import password.pwm.svc.wordlist.SharedHistoryManager; import password.pwm.svc.wordlist.WordlistManager; import password.pwm.util.PasswordData; import password.pwm.util.VersionChecker; import password.pwm.util.cli.commands.ExportHttpsTomcatConfigCommand; import password.pwm.util.db.DatabaseAccessor; import password.pwm.util.db.DatabaseAccessorImpl; import password.pwm.util.java.FileSystemUtility; import password.pwm.util.java.JavaHelper; import password.pwm.util.java.JsonUtil; import password.pwm.util.java.TimeDuration; import password.pwm.util.localdb.LocalDB; import password.pwm.util.localdb.LocalDBFactory; import password.pwm.util.logging.LocalDBLogger; import password.pwm.util.logging.PwmLogLevel; import password.pwm.util.logging.PwmLogManager; import password.pwm.util.logging.PwmLogger; import password.pwm.util.macro.MacroMachine; import password.pwm.util.operations.CrService; import password.pwm.util.operations.OtpService; import password.pwm.util.queue.EmailQueueManager; import password.pwm.util.queue.SmsQueueManager; import password.pwm.util.secure.HttpsServerCertificateManager; import password.pwm.util.secure.PwmRandom; import password.pwm.util.secure.SecureService; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.security.KeyStore; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * A repository for objects common to the servlet context. A singleton * of this object is stored in the servlet context. * * @author Jason D. Rivard */ public class PwmApplication { // ------------------------------ FIELDS ------------------------------ // ----------------------------- CONSTANTS ---------------------------- private static final PwmLogger LOGGER = PwmLogger.forClass(PwmApplication.class); private static final String DEFAULT_INSTANCE_ID = "-1"; public enum AppAttribute { INSTANCE_ID("context_instanceID"), INSTALL_DATE("DB_KEY_INSTALL_DATE"), CONFIG_HASH("configurationSettingHash"), LAST_LDAP_ERROR("lastLdapError"), TOKEN_COUNTER("tokenCounter"), REPORT_STATUS("reporting.status"), // REPORT_CLEAN_FLAG("reporting.cleanFlag"), deprecated SMS_ITEM_COUNTER("smsQueue.itemCount"), EMAIL_ITEM_COUNTER("itemQueue.itemCount"), LOCALDB_IMPORT_STATUS("localDB.import.status"), WORDLIST_METADATA("wordlist.metadata"), SEEDLIST_METADATA("seedlist.metadata"), HTTPS_SELF_CERT("https.selfCert"), CONFIG_LOGIN_HISTORY("config.loginHistory"), LOCALDB_LOGGER_STORAGE_FORMAT("localdb.logger.storage.format"), ; private final String key; AppAttribute(final String key) { this.key = key; } public String getKey() { return key; } } private String instanceID = DEFAULT_INSTANCE_ID; private String instanceNonce = PwmRandom.getInstance().randomUUID().toString(); private LocalDB localDB; private LocalDBLogger localDBLogger; private final Instant startupTime = Instant.now(); private Instant installTime = Instant.now(); private ErrorInformation lastLocalDBFailure; private final PwmEnvironment pwmEnvironment; private final PwmServiceManager pwmServiceManager = new PwmServiceManager(this); public PwmApplication(final PwmEnvironment pwmEnvironment) throws PwmUnrecoverableException { pwmEnvironment.verifyIfApplicationPathIsSetProperly(); this.pwmEnvironment = pwmEnvironment; try { initialize(); } catch (PwmUnrecoverableException e) { LOGGER.fatal(e.getMessage()); throw e; } } private void initialize() throws PwmUnrecoverableException { final Instant startTime = Instant.now(); // initialize log4j if (!pwmEnvironment.isInternalRuntimeInstance() && !pwmEnvironment.getFlags().contains(PwmEnvironment.ApplicationFlag.CommandLineInstance)) { final String log4jFileName = pwmEnvironment.getConfig().readSettingAsString(PwmSetting.EVENTS_JAVA_LOG4JCONFIG_FILE); final File log4jFile = FileSystemUtility.figureFilepath(log4jFileName, pwmEnvironment.getApplicationPath()); final String consoleLevel; final String fileLevel; switch (getApplicationMode()) { case ERROR: case NEW: consoleLevel = PwmLogLevel.TRACE.toString(); fileLevel = PwmLogLevel.TRACE.toString(); break; default: consoleLevel = pwmEnvironment.getConfig().readSettingAsString(PwmSetting.EVENTS_JAVA_STDOUT_LEVEL); fileLevel = pwmEnvironment.getConfig().readSettingAsString(PwmSetting.EVENTS_FILE_LEVEL); break; } PwmLogManager.initializeLogger(this, pwmEnvironment.getConfig(), log4jFile, consoleLevel, pwmEnvironment.getApplicationPath(), fileLevel); switch (getApplicationMode()) { case RUNNING: break; case ERROR: LOGGER.fatal("starting up in ERROR mode! Check log or health check information for cause"); break; default: LOGGER.trace("setting log level to TRACE because application mode is " + getApplicationMode()); break; } } // get file lock if (!pwmEnvironment.isInternalRuntimeInstance()) { pwmEnvironment.waitForFileLock(); } // clear temp dir if (!pwmEnvironment.isInternalRuntimeInstance()) { final File tempFileDirectory = getTempDirectory(); try { FileSystemUtility.deleteDirectoryContents(tempFileDirectory); } catch (Exception e) { throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_STARTUP_ERROR, "unable to clear temp file directory '"+ tempFileDirectory.getAbsolutePath() + "', error: " + e.getMessage() )); } } LOGGER.info("initializing, application mode=" + getApplicationMode() + ", applicationPath=" + (pwmEnvironment.getApplicationPath() == null ? "null" : pwmEnvironment.getApplicationPath().getAbsolutePath()) + ", configFile=" + (pwmEnvironment.getConfigurationFile() == null ? "null" : pwmEnvironment.getConfigurationFile().getAbsolutePath()) ); if (!pwmEnvironment.isInternalRuntimeInstance()) { if (getApplicationMode() == PwmApplicationMode.ERROR || getApplicationMode() == PwmApplicationMode.NEW) { LOGGER.warn("skipping LocalDB open due to application mode " + getApplicationMode()); } else { this.localDB = Initializer.initializeLocalDB(this); } } this.localDBLogger = PwmLogManager.initializeLocalDBLogger(this); // log the loaded configuration LOGGER.info("configuration load completed"); // read the pwm servlet instance id instanceID = fetchInstanceID(localDB, this); LOGGER.info("using '" + getInstanceID() + "' for instance's ID (instanceID)"); // read the pwm installation date installTime = fetchInstallDate(startupTime); LOGGER.debug("this application instance first installed on " + JavaHelper.toIsoDate(installTime)); LOGGER.debug("application environment flags: " + JsonUtil.serializeCollection(pwmEnvironment.getFlags())); LOGGER.debug("application environment parameters: " + JsonUtil.serializeMap(pwmEnvironment.getParameters())); pwmServiceManager.initAllServices(); final boolean skipPostInit = pwmEnvironment.isInternalRuntimeInstance() || pwmEnvironment.getFlags().contains(PwmEnvironment.ApplicationFlag.CommandLineInstance); if (!skipPostInit) { final TimeDuration totalTime = TimeDuration.fromCurrent(startTime); LOGGER.info(PwmConstants.PWM_APP_NAME + " " + PwmConstants.SERVLET_VERSION + " open for bidness! (" + totalTime.asCompactString() + ")"); StatisticsManager.incrementStat(this, Statistic.PWM_STARTUPS); LOGGER.debug("buildTime=" + PwmConstants.BUILD_TIME + ", javaLocale=" + Locale.getDefault() + ", DefaultLocale=" + PwmConstants.DEFAULT_LOCALE); final Thread postInitThread = new Thread(() -> postInitTasks()); postInitThread.setDaemon(true); postInitThread.setName(JavaHelper.makeThreadName(this, PwmApplication.class)); postInitThread.start(); } } private void postInitTasks() { final Instant startTime = Instant.now(); LOGGER.debug("loaded configuration: " + pwmEnvironment.getConfig().toDebugString()); // detect if config has been modified since previous startup try { final String previousHash = readAppAttribute(AppAttribute.CONFIG_HASH, String.class); final String currentHash = pwmEnvironment.getConfig().configurationHash(); if (previousHash == null || !previousHash.equals(currentHash)) { writeAppAttribute(AppAttribute.CONFIG_HASH, currentHash); LOGGER.warn("configuration checksum does not match previously seen checksum, configuration has been modified since last startup"); if (this.getAuditManager() != null) { final String modifyMessage = "configuration was modified directly (not using ConfigEditor UI)"; this.getAuditManager().submit(new AuditRecordFactory(this).createUserAuditRecord( AuditEvent.MODIFY_CONFIGURATION, null, null, modifyMessage )); } } } catch (Exception e) { LOGGER.debug("unable to detect if configuration has been modified since previous startup: " + e.getMessage()); } if (this.getConfig() != null) { final Map<AppProperty,String> nonDefaultProperties = getConfig().readAllNonDefaultAppProperties(); if (nonDefaultProperties != null && !nonDefaultProperties.isEmpty()) { final Map<String,String> tempMap = new LinkedHashMap<>(); for (final AppProperty loopProperty : nonDefaultProperties.keySet()) { tempMap.put(loopProperty.getKey(), nonDefaultProperties.get(loopProperty)); } LOGGER.trace("non-default app properties read from configuration: " + JsonUtil.serializeMap(tempMap)); } else { LOGGER.trace("no non-default app properties in configuration"); } } // send system audit event try { final SystemAuditRecord auditRecord = new AuditRecordFactory(this).createSystemAuditRecord( AuditEvent.STARTUP, null ); getAuditManager().submit(auditRecord); } catch (PwmException e) { LOGGER.warn("unable to submit start alert event " + e.getMessage()); } try { final Map<PwmAboutProperty,String> infoMap = PwmAboutProperty.makeInfoBean(this); LOGGER.trace("application info: " + JsonUtil.serializeMap(infoMap)); } catch (Exception e) { LOGGER.error("error generating about application bean: " + e.getMessage(), e); } try { this.getIntruderManager().clear(RecordType.USERNAME, PwmConstants.CONFIGMANAGER_INTRUDER_USERNAME); } catch (Exception e) { LOGGER.warn("error while clearing configmanager-intruder-username from intruder table: " + e.getMessage()); } if (!pwmEnvironment.isInternalRuntimeInstance()) { try { outputKeystore(this); } catch (Exception e) { LOGGER.debug("error while generating keystore output: " + e.getMessage()); } try { outputTomcatConf(this); } catch (Exception e) { LOGGER.debug("error while generating tomcat conf output: " + e.getMessage()); } } LOGGER.trace("completed post init tasks in " + TimeDuration.fromCurrent(startTime).asCompactString()); } private static void outputKeystore(final PwmApplication pwmApplication) throws Exception { final Map<PwmEnvironment.ApplicationParameter, String> applicationParams = pwmApplication.getPwmEnvironment().getParameters(); final String keystoreFileString = applicationParams.get(PwmEnvironment.ApplicationParameter.AutoExportHttpsKeyStoreFile); if (keystoreFileString != null && !keystoreFileString.isEmpty()) { LOGGER.trace("attempting to output keystore as configured by environment parameters to " + keystoreFileString); final File keyStoreFile = new File(keystoreFileString); final String password = applicationParams.get(PwmEnvironment.ApplicationParameter.AutoExportHttpsKeyStorePassword); final String alias = applicationParams.get(PwmEnvironment.ApplicationParameter.AutoExportHttpsKeyStoreAlias); final KeyStore keyStore = HttpsServerCertificateManager.keyStoreForApplication(pwmApplication, new PasswordData(password), alias); final ByteArrayOutputStream outputContents = new ByteArrayOutputStream(); keyStore.store(outputContents, password.toCharArray()); if (keyStoreFile.exists()) { LOGGER.trace("deleting existing keystore file " + keyStoreFile.getAbsolutePath()); if (keyStoreFile.delete()) { LOGGER.trace("deleted existing keystore file: " + keyStoreFile.getAbsolutePath()); } } new FileOutputStream(keyStoreFile).write(outputContents.toByteArray()); LOGGER.info("successfully exported application https key to keystore file " + keyStoreFile.getAbsolutePath()); } } private static void outputTomcatConf(final PwmApplication pwmApplication) throws IOException { final Map<PwmEnvironment.ApplicationParameter, String> applicationParams = pwmApplication.getPwmEnvironment().getParameters(); final String tomcatOutputFileStr = applicationParams.get(PwmEnvironment.ApplicationParameter.AutoWriteTomcatConfOutputFile); if (tomcatOutputFileStr != null && !tomcatOutputFileStr.isEmpty()) { LOGGER.trace("attempting to output tomcat configuration file as configured by environment parameters to " + tomcatOutputFileStr); final File tomcatOutputFile = new File(tomcatOutputFileStr); final File tomcatSourceFile; { final String tomcatSourceFileStr = applicationParams.get(PwmEnvironment.ApplicationParameter.AutoWriteTomcatConfSourceFile); if (tomcatSourceFileStr != null && !tomcatSourceFileStr.isEmpty()) { tomcatSourceFile = new File(tomcatSourceFileStr); if (!tomcatSourceFile.exists()) { LOGGER.error("can not output tomcat configuration file, source file does not exist: " + tomcatSourceFile.getAbsolutePath()); return; } } else { LOGGER.error("can not output tomcat configuration file, source file parameter '" + PwmEnvironment.ApplicationParameter.AutoWriteTomcatConfSourceFile.toString() + "' is not specified."); return; } } final ByteArrayOutputStream outputContents = new ByteArrayOutputStream(); ExportHttpsTomcatConfigCommand.TomcatConfigWriter.writeOutputFile( pwmApplication.getConfig(), new FileInputStream(tomcatSourceFile), outputContents ); if (tomcatOutputFile.exists()) { LOGGER.trace("deleting existing tomcat configuration file " + tomcatOutputFile.getAbsolutePath()); if (tomcatOutputFile.delete()) { LOGGER.trace("deleted existing tomcat configuration file: " + tomcatOutputFile.getAbsolutePath()); } } new FileOutputStream(tomcatOutputFile).write(outputContents.toByteArray()); LOGGER.info("successfully wrote tomcat configuration to file " + tomcatOutputFile.getAbsolutePath()); } } public String getInstanceID() { return instanceID; } public SharedHistoryManager getSharedHistoryManager() { return (SharedHistoryManager)pwmServiceManager.getService(SharedHistoryManager.class); } public IntruderManager getIntruderManager() { return (IntruderManager)pwmServiceManager.getService(IntruderManager.class); } public ChaiUser getProxiedChaiUser(final UserIdentity userIdentity) throws PwmUnrecoverableException { try { final ChaiProvider proxiedProvider = getProxyChaiProvider(userIdentity.getLdapProfileID()); return ChaiFactory.createChaiUser(userIdentity.getUserDN(), proxiedProvider); } catch (ChaiUnavailableException e) { throw PwmUnrecoverableException.fromChaiException(e); } } public ChaiProvider getProxyChaiProvider(final String identifier) throws PwmUnrecoverableException { return getLdapConnectionService().getProxyChaiProvider(identifier); } public LocalDBLogger getLocalDBLogger() { return localDBLogger; } public HealthMonitor getHealthMonitor() { return (HealthMonitor)pwmServiceManager.getService(HealthMonitor.class); } public List<PwmService> getPwmServices() { final List<PwmService> pwmServices = new ArrayList<>(); pwmServices.add(this.localDBLogger); pwmServices.addAll(this.pwmServiceManager.getRunningServices()); pwmServices.remove(null); return Collections.unmodifiableList(pwmServices); } public WordlistManager getWordlistManager() { return (WordlistManager)pwmServiceManager.getService(WordlistManager.class); } public SeedlistManager getSeedlistManager() { return (SeedlistManager)pwmServiceManager.getService(SeedlistManager.class); } public ReportService getReportService() { return (ReportService)pwmServiceManager.getService(ReportService.class); } public EmailQueueManager getEmailQueue() { return (EmailQueueManager)pwmServiceManager.getService(EmailQueueManager.class); } public AuditService getAuditManager() { return (AuditService)pwmServiceManager.getService(AuditService.class); } public SmsQueueManager getSmsQueue() { return (SmsQueueManager)pwmServiceManager.getService(SmsQueueManager.class); } public UrlShortenerService getUrlShortener() { return (UrlShortenerService)pwmServiceManager.getService(UrlShortenerService.class); } public UserSearchEngine getUserSearchEngine() { return (UserSearchEngine)pwmServiceManager.getService(UserSearchEngine.class); } public VersionChecker getVersionChecker() { return (VersionChecker)pwmServiceManager.getService(VersionChecker.class); } public ErrorInformation getLastLocalDBFailure() { return lastLocalDBFailure; } public TokenService getTokenService() { return (TokenService)pwmServiceManager.getService(TokenService.class); } public LdapConnectionService getLdapConnectionService() { return (LdapConnectionService)pwmServiceManager.getService(LdapConnectionService.class); } public SessionTrackService getSessionTrackService() { return (SessionTrackService)pwmServiceManager.getService(SessionTrackService.class); } public ResourceServletService getResourceServletService() { return (ResourceServletService)pwmServiceManager.getService(ResourceServletService.class); } public Configuration getConfig() { return pwmEnvironment.getConfig(); } public PwmApplicationMode getApplicationMode() { return pwmEnvironment.getApplicationMode(); } public synchronized DatabaseAccessor getDatabaseAccessor() { return (DatabaseAccessorImpl)pwmServiceManager.getService(DatabaseAccessorImpl.class); } private Instant fetchInstallDate(final Instant startupTime) { if (localDB != null) { try { final String storedDateStr = readAppAttribute(AppAttribute.INSTALL_DATE,String.class); if (storedDateStr == null || storedDateStr.length() < 1) { writeAppAttribute(AppAttribute.INSTALL_DATE, String.valueOf(startupTime.toEpochMilli())); } else { return Instant.ofEpochMilli(Long.parseLong(storedDateStr)); } } catch (Exception e) { LOGGER.error("error retrieving installation date from localDB: " + e.getMessage()); } } return Instant.now(); } private String fetchInstanceID(final LocalDB localDB, final PwmApplication pwmApplication) { String newInstanceID = pwmApplication.getConfig().readSettingAsString(PwmSetting.PWM_INSTANCE_NAME); if (newInstanceID != null && newInstanceID.trim().length() > 0) { return newInstanceID; } newInstanceID = readAppAttribute(AppAttribute.INSTANCE_ID, String.class); if (newInstanceID == null || newInstanceID.length() < 1) { newInstanceID = Long.toHexString(PwmRandom.getInstance().nextLong()).toUpperCase(); LOGGER.info("generated new random instanceID " + newInstanceID); if (localDB != null) { writeAppAttribute(AppAttribute.INSTANCE_ID, newInstanceID); } } else { LOGGER.trace("retrieved instanceID " + newInstanceID + "" + " from localDB"); } if (newInstanceID.length() < 1) { newInstanceID = DEFAULT_INSTANCE_ID; } return newInstanceID; } public StatisticsManager getStatisticsManager() { return (StatisticsManager)pwmServiceManager.getService(StatisticsManager.class); } public OtpService getOtpService() { return (OtpService)pwmServiceManager.getService(OtpService.class); } public CrService getCrService() { return (CrService)pwmServiceManager.getService(CrService.class); } public SessionStateService getSessionStateService() { return (SessionStateService)pwmServiceManager.getService(SessionStateService.class); } public CacheService getCacheService() { return (CacheService)pwmServiceManager.getService(CacheService.class); } public SecureService getSecureService() { return (SecureService)pwmServiceManager.getService(SecureService.class); } public void sendSmsUsingQueue( final SmsItemBean smsItem, final MacroMachine macroMachine ) { final SmsQueueManager smsQueue = getSmsQueue(); if (smsQueue == null) { LOGGER.error("SMS queue is unavailable, unable to send SMS: " + smsItem.toString()); return; } final SmsItemBean rewrittenSmsItem = new SmsItemBean( macroMachine.expandMacros(smsItem.getTo()), macroMachine.expandMacros(smsItem.getMessage()) ); try { smsQueue.addSmsToQueue(rewrittenSmsItem); } catch (PwmUnrecoverableException e) { LOGGER.warn("unable to add sms to queue: " + e.getMessage()); } } public void shutdown() { LOGGER.warn("shutting down"); { // send system audit event try { final SystemAuditRecord auditRecord = new AuditRecordFactory(this).createSystemAuditRecord( AuditEvent.SHUTDOWN, null ); if (getAuditManager() != null) { getAuditManager().submit(auditRecord); } } catch (PwmException e) { LOGGER.warn("unable to submit shutdown alert event " + e.getMessage()); } } pwmServiceManager.shutdownAllServices(); if (localDBLogger != null) { try { localDBLogger.close(); } catch (Exception e) { LOGGER.error("error closing localDBLogger: " + e.getMessage(),e); } localDBLogger = null; } if (localDB != null) { try { LOGGER.trace("beginning close of LocalDB"); localDB.close(); } catch (Exception e) { LOGGER.fatal("error closing localDB: " + e, e); } localDB = null; } pwmEnvironment.releaseFileLock(); LOGGER.info(PwmConstants.PWM_APP_NAME + " " + PwmConstants.SERVLET_VERSION + " closed for bidness, cya!"); } public Instant getStartupTime() { return startupTime; } public Instant getInstallTime() { return installTime; } public LocalDB getLocalDB() { return localDB; } // -------------------------- INNER CLASSES -------------------------- private static class Initializer { public static LocalDB initializeLocalDB(final PwmApplication pwmApplication) throws PwmUnrecoverableException { final File databaseDirectory; // see if META-INF isn't already there, then use WEB-INF. try { final String localDBLocationSetting = pwmApplication.getConfig().readSettingAsString(PwmSetting.PWMDB_LOCATION); databaseDirectory = FileSystemUtility.figureFilepath(localDBLocationSetting, pwmApplication.pwmEnvironment.getApplicationPath()); } catch (Exception e) { pwmApplication.lastLocalDBFailure = new ErrorInformation(PwmError.ERROR_LOCALDB_UNAVAILABLE,"error locating configured LocalDB directory: " + e.getMessage()); LOGGER.warn(pwmApplication.lastLocalDBFailure.toDebugStr()); throw new PwmUnrecoverableException(pwmApplication.lastLocalDBFailure); } LOGGER.debug("using localDB path " + databaseDirectory); // initialize the localDB try { final boolean readOnly = pwmApplication.getApplicationMode() == PwmApplicationMode.READ_ONLY; return LocalDBFactory.getInstance(databaseDirectory, readOnly, pwmApplication, pwmApplication.getConfig()); } catch (Exception e) { pwmApplication.lastLocalDBFailure = new ErrorInformation(PwmError.ERROR_LOCALDB_UNAVAILABLE,"unable to initialize LocalDB: " + e.getMessage()); LOGGER.warn(pwmApplication.lastLocalDBFailure.toDebugStr()); throw new PwmUnrecoverableException(pwmApplication.lastLocalDBFailure); } } } public PwmEnvironment getPwmEnvironment() { return pwmEnvironment; } public String getInstanceNonce() { return instanceNonce; } public <T extends Serializable> T readAppAttribute(final AppAttribute appAttribute, final Class<T> returnClass) { if (localDB == null || localDB.status() != LocalDB.Status.OPEN) { LOGGER.error("error retrieving key '" + appAttribute.getKey() + "', localDB unavailable: "); return null; } if (appAttribute == null) { return null; } try { final String strValue = localDB.get(LocalDB.DB.PWM_META, appAttribute.getKey()); return JsonUtil.deserialize(strValue, returnClass); } catch (Exception e) { LOGGER.error("error retrieving key '" + appAttribute.getKey() + "' value from localDB: " + e.getMessage()); } return null; } public void writeAppAttribute(final AppAttribute appAttribute, final Serializable value) { if (localDB == null || localDB.status() != LocalDB.Status.OPEN) { LOGGER.error("error writing key '" + appAttribute.getKey() + "', localDB unavailable: "); return; } if (appAttribute == null) { return; } try { if (value == null) { localDB.remove(LocalDB.DB.PWM_META, appAttribute.getKey()); } else { final String jsonValue = JsonUtil.serialize(value); localDB.put(LocalDB.DB.PWM_META, appAttribute.getKey(), jsonValue); } } catch (Exception e) { LOGGER.error("error retrieving key '" + appAttribute.getKey() + "' installation date from localDB: " + e.getMessage()); try { localDB.remove(LocalDB.DB.PWM_META, appAttribute.getKey()); } catch (Exception e2) { LOGGER.error("error removing bogus appAttribute value for key " + appAttribute.getKey() + ", error: " + localDB); } } } public File getTempDirectory() throws PwmUnrecoverableException { if (pwmEnvironment.getApplicationPath() == null) { final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_STARTUP_ERROR, "unable to establish temp work directory: application path unavailable" ); throw new PwmUnrecoverableException(errorInformation); } final File tempDirectory = new File(pwmEnvironment.getApplicationPath() + File.separator + "temp"); if (!tempDirectory.exists()) { LOGGER.trace("preparing to create temporary directory " + tempDirectory.getAbsolutePath()); if (tempDirectory.mkdir()) { LOGGER.debug("created " + tempDirectory.getAbsolutePath()); } else { LOGGER.debug("unable to create temporary directory " + tempDirectory.getAbsolutePath()); final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_STARTUP_ERROR, "unable to establish create temp work directory " + tempDirectory.getAbsolutePath() ); throw new PwmUnrecoverableException(errorInformation); } } return tempDirectory; } public boolean determineIfDetailErrorMsgShown() { final PwmApplicationMode mode = this.getApplicationMode(); if (mode == PwmApplicationMode.CONFIGURATION || mode == PwmApplicationMode.NEW) { return true; } if (mode == PwmApplicationMode.RUNNING) { if (this.getConfig() != null) { if (this.getConfig().readSettingAsBoolean(PwmSetting.DISPLAY_SHOW_DETAILED_ERRORS)) { return true; } } } return false; } }