/* * 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.config; import com.novell.ldapchai.util.StringHelper; import password.pwm.AppProperty; import password.pwm.PwmConstants; import password.pwm.bean.EmailItemBean; import password.pwm.bean.PrivateKeyCertificate; import password.pwm.config.option.ADPolicyComplexity; import password.pwm.config.option.DataStorageMethod; import password.pwm.config.option.MessageSendMethod; import password.pwm.config.option.TokenStorageMethod; import password.pwm.config.profile.ChallengeProfile; import password.pwm.config.profile.DeleteAccountProfile; import password.pwm.config.profile.ForgottenPasswordProfile; import password.pwm.config.profile.HelpdeskProfile; import password.pwm.config.profile.LdapProfile; import password.pwm.config.profile.NewUserProfile; import password.pwm.config.profile.Profile; import password.pwm.config.profile.ProfileType; import password.pwm.config.profile.ProfileUtility; import password.pwm.config.profile.PwmPasswordPolicy; import password.pwm.config.profile.PwmPasswordRule; import password.pwm.config.profile.UpdateAttributesProfile; import password.pwm.config.stored.ConfigurationProperty; import password.pwm.config.stored.StoredConfigurationImpl; import password.pwm.config.stored.StoredConfigurationUtil; import password.pwm.config.value.BooleanValue; import password.pwm.config.value.FileValue; import password.pwm.config.value.FormValue; import password.pwm.config.value.LocalizedStringArrayValue; import password.pwm.config.value.LocalizedStringValue; import password.pwm.config.value.NumericValue; import password.pwm.config.value.PasswordValue; import password.pwm.config.value.StringArrayValue; import password.pwm.config.value.StringValue; import password.pwm.config.value.UserPermissionValue; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmUnrecoverableException; import password.pwm.util.LocaleHelper; import password.pwm.util.PasswordData; import password.pwm.util.java.JsonUtil; import password.pwm.util.java.StringUtil; import password.pwm.util.logging.PwmLogLevel; import password.pwm.util.logging.PwmLogger; import password.pwm.util.secure.PwmRandom; import password.pwm.util.secure.PwmSecurityKey; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * @author Jason D. Rivard */ public class Configuration implements Serializable, SettingReader { // ------------------------------ FIELDS ------------------------------ private static final PwmLogger LOGGER = PwmLogger.forClass(Configuration.class); private final StoredConfigurationImpl storedConfiguration; private DataCache dataCache = new DataCache(); // --------------------------- CONSTRUCTORS --------------------------- public Configuration(final StoredConfigurationImpl storedConfiguration) { this.storedConfiguration = storedConfiguration; } public String toDebugString() { final StringBuilder outputText = new StringBuilder(); outputText.append(" "); outputText.append(JsonUtil.serialize(StoredConfigurationUtil.toJsonDebugObject(storedConfiguration), JsonUtil.Flag.PrettyPrint)); return outputText.toString().replaceAll("\n","\n "); } public List<FormConfiguration> readSettingAsForm(final PwmSetting setting) { final StoredValue value = readStoredValue(setting); return JavaTypeConverter.valueToForm(value); } public List<UserPermission> readSettingAsUserPermission(final PwmSetting setting) { final StoredValue value = readStoredValue(setting); return JavaTypeConverter.valueToUserPermissions(value); } public Map<String,LdapProfile> getLdapProfiles() { if (dataCache.ldapProfiles != null) { return dataCache.ldapProfiles; } final List<String> profiles = StoredConfigurationUtil.profilesForSetting(PwmSetting.LDAP_PROFILE_LIST, storedConfiguration); final LinkedHashMap<String,LdapProfile> returnList = new LinkedHashMap<>(); for (final String profileID : profiles) { final LdapProfile ldapProfile = LdapProfile.makeFromStoredConfiguration(this.storedConfiguration, profileID); if (ldapProfile.readSettingAsBoolean(PwmSetting.LDAP_PROFILE_ENABLED)) { returnList.put(profileID, ldapProfile); } } dataCache.ldapProfiles = Collections.unmodifiableMap(returnList); return dataCache.ldapProfiles; } public EmailItemBean readSettingAsEmail(final PwmSetting setting, final Locale locale) { if (PwmSettingSyntax.EMAIL != setting.getSyntax()) { throw new IllegalArgumentException("may not read EMAIL value for setting: " + setting.toString()); } final Map<String, EmailItemBean> storedValues = (Map<String, EmailItemBean>)readStoredValue(setting).toNativeObject(); final Map<Locale, EmailItemBean> availableLocaleMap = new LinkedHashMap<>(); for (final String localeStr : storedValues.keySet()) { availableLocaleMap.put(LocaleHelper.parseLocaleString(localeStr), storedValues.get(localeStr)); } final Locale matchedLocale = LocaleHelper.localeResolver(locale, availableLocaleMap.keySet()); return availableLocaleMap.get(matchedLocale); } public <E extends Enum<E>> E readSettingAsEnum(final PwmSetting setting, final Class<E> enumClass) { final StoredValue value = readStoredValue(setting); return JavaTypeConverter.valueToEnum(setting, value, enumClass); } public <E extends Enum<E>> Set<E> readSettingAsOptionList(final PwmSetting setting, final Class<E> enumClass) { return JavaTypeConverter.valueToOptionList(setting, readStoredValue(setting), enumClass); } public MessageSendMethod readSettingAsTokenSendMethod(final PwmSetting setting) { return readSettingAsEnum(setting,MessageSendMethod.class); } public List<ActionConfiguration> readSettingAsAction(final PwmSetting setting) { return JavaTypeConverter.valueToAction(setting, readStoredValue(setting)); } public List<String> readSettingAsLocalizedStringArray(final PwmSetting setting, final Locale locale) { if (PwmSettingSyntax.LOCALIZED_STRING_ARRAY != setting.getSyntax()) { throw new IllegalArgumentException("may not read LOCALIZED_STRING_ARRAY value for setting: " + setting.toString()); } final StoredValue value = readStoredValue(setting); return JavaTypeConverter.valueToLocalizedStringArray(value, locale); } public String readSettingAsString(final PwmSetting setting) { return JavaTypeConverter.valueToString(readStoredValue(setting)); } public PasswordData readSettingAsPassword(final PwmSetting setting) { return JavaTypeConverter.valueToPassword(readStoredValue(setting)); } public abstract static class JavaTypeConverter { public static long valueToLong(final StoredValue value) { if (!(value instanceof NumericValue)) { throw new IllegalArgumentException("setting value is not readable as number"); } return (long)value.toNativeObject(); } public static String valueToString(final StoredValue value) { if (value == null) { return null; } if ((!(value instanceof StringValue)) && (!(value instanceof BooleanValue))) { throw new IllegalArgumentException("setting value is not readable as string"); } final Object nativeObject = value.toNativeObject(); if (nativeObject == null) { return null; } return nativeObject.toString(); } public static PasswordData valueToPassword(final StoredValue value) { if (value == null) { return null; } if ((!(value instanceof PasswordValue))) { throw new IllegalArgumentException("setting value is not readable as password"); } final Object nativeObject = value.toNativeObject(); if (nativeObject == null) { return null; } return (PasswordData)nativeObject; } public static List<ActionConfiguration> valueToAction(final PwmSetting setting, final StoredValue storedValue) { if (PwmSettingSyntax.ACTION != setting.getSyntax()) { throw new IllegalArgumentException("may not read ACTION value for setting: " + setting.toString()); } return (List<ActionConfiguration>)storedValue.toNativeObject(); } public static List<FormConfiguration> valueToForm(final StoredValue value) { if (value == null) { return null; } if ((!(value instanceof FormValue))) { throw new IllegalArgumentException("setting value is not readable as form"); } return (List<FormConfiguration>)value.toNativeObject(); } public static List<String> valueToStringArray(final StoredValue value) { if (!(value instanceof StringArrayValue)) { throw new IllegalArgumentException("setting value is not readable as string array"); } final List<String> results = new ArrayList<>((List<String>)value.toNativeObject()); for (final Iterator iter = results.iterator(); iter.hasNext(); ) { final Object loopString = iter.next(); if (loopString == null || loopString.toString().length() < 1) { iter.remove(); } } return results; } public static List<UserPermission> valueToUserPermissions(final StoredValue value) { if (value == null) { return Collections.emptyList(); } if (!(value instanceof UserPermissionValue)) { throw new IllegalArgumentException("setting value is not readable as string array"); } final List<UserPermission> results = new ArrayList<>((List<UserPermission>)value.toNativeObject()); for (final Iterator iter = results.iterator(); iter.hasNext(); ) { final Object loopString = iter.next(); if (loopString == null || loopString.toString().length() < 1) { iter.remove(); } } return results; } public static boolean valueToBoolean(final StoredValue value) { if (!(value instanceof BooleanValue)) { throw new IllegalArgumentException("may not read BOOLEAN value for setting"); } return (Boolean)value.toNativeObject(); } public static String valueToLocalizedString(final StoredValue value, final Locale locale) { if (!(value instanceof LocalizedStringValue)) { throw new IllegalArgumentException("may not read LOCALIZED_STRING or LOCALIZED_TEXT_AREA values for setting"); } final Map<String, String> availableValues = (Map<String, String>)value.toNativeObject(); final Map<Locale, String> availableLocaleMap = new LinkedHashMap<>(); for (final String localeStr : availableValues.keySet()) { availableLocaleMap.put(LocaleHelper.parseLocaleString(localeStr), availableValues.get(localeStr)); } final Locale matchedLocale = LocaleHelper.localeResolver(locale, availableLocaleMap.keySet()); return availableLocaleMap.get(matchedLocale); } public static List<String> valueToLocalizedStringArray(final StoredValue value, final Locale locale) { if (!(value instanceof LocalizedStringArrayValue)) { throw new IllegalArgumentException("may not read LOCALIZED_STRING_ARRAY value"); } final Map<String, List<String>> storedValues = (Map<String, List<String>>)value.toNativeObject(); final Map<Locale, List<String>> availableLocaleMap = new LinkedHashMap<>(); for (final String localeStr : storedValues.keySet()) { availableLocaleMap.put(LocaleHelper.parseLocaleString(localeStr), storedValues.get(localeStr)); } final Locale matchedLocale = LocaleHelper.localeResolver(locale, availableLocaleMap.keySet()); return availableLocaleMap.get(matchedLocale); } public static <E extends Enum<E>> E valueToEnum(final PwmSetting setting, final StoredValue value, final Class<E> enumClass) { if (PwmSettingSyntax.SELECT != setting.getSyntax()) { throw new IllegalArgumentException("may not read SELECT enum value for setting: " + setting.toString()); } final String strValue = (String)value.toNativeObject(); try { return (E)enumClass.getMethod("valueOf", String.class).invoke(null, strValue); } catch (InvocationTargetException e1) { if (e1.getCause() instanceof IllegalArgumentException) { LOGGER.error("illegal setting value for option '" + strValue + "' for setting key '" + setting.getKey() + "' is not recognized, will use default"); } } catch (Exception e1) { LOGGER.error("unexpected error", e1); } return null; } public static <E extends Enum<E>> Set<E> valueToOptionList(final PwmSetting setting, final StoredValue value, final Class<E> enumClass) { if (PwmSettingSyntax.OPTIONLIST != setting.getSyntax()) { throw new IllegalArgumentException("may not read optionlist value for setting: " + setting.toString()); } final Set<E> returnSet = new LinkedHashSet<>(); final Set<String> strValues = (Set<String>)value.toNativeObject(); for (final String strValue : strValues) { try { returnSet.add((E)enumClass.getMethod("valueOf", String.class).invoke(null, strValue)); } catch (InvocationTargetException e1) { if (e1.getCause() instanceof IllegalArgumentException) { LOGGER.error("illegal setting value for option '" + strValue + "' is not recognized, will use default"); } } catch (Exception e1) { LOGGER.error("unexpected error", e1); } } return Collections.unmodifiableSet(returnSet); } } public Map<Locale,String> readLocalizedBundle(final String className, final String keyName) { final String key = className + "-" + keyName; if (dataCache.customText.containsKey(key)) { return dataCache.customText.get(key); } final Map<String,String> storedValue = storedConfiguration.readLocaleBundleMap(className,keyName); if (storedValue == null || storedValue.isEmpty()) { dataCache.customText.put(key,null); return null; } final Map<Locale,String> localizedMap = new LinkedHashMap<>(); for (final String localeKey : storedValue.keySet()) { localizedMap.put(LocaleHelper.parseLocaleString(localeKey),storedValue.get(localeKey)); } dataCache.customText.put(key, localizedMap); return localizedMap; } public PwmLogLevel getEventLogLocalDBLevel() { return readSettingAsEnum(PwmSetting.EVENTS_LOCALDB_LOG_LEVEL, PwmLogLevel.class); } public List<String> getChallengeProfileIDs() { return StoredConfigurationUtil.profilesForSetting(PwmSetting.CHALLENGE_PROFILE_LIST, storedConfiguration); } public ChallengeProfile getChallengeProfile(final String profile, final Locale locale) { if (!"".equals(profile) && !getChallengeProfileIDs().contains(profile)) { throw new IllegalArgumentException("unknown challenge profileID specified: " + profile); } // challengeProfile challengeSet's are mutable (question text) and can not be cached. final ChallengeProfile challengeProfile = ChallengeProfile.readChallengeProfileFromConfig(profile, locale, storedConfiguration); return challengeProfile; } public long readSettingAsLong(final PwmSetting setting) { return JavaTypeConverter.valueToLong(readStoredValue(setting)); } public PwmPasswordPolicy getPasswordPolicy(final String profile, final Locale locale) { if (dataCache.cachedPasswordPolicy.containsKey(profile) && dataCache.cachedPasswordPolicy.get(profile).containsKey( locale)) { return dataCache.cachedPasswordPolicy.get(profile).get(locale); } final PwmPasswordPolicy policy = initPasswordPolicy(profile,locale); if (!dataCache.cachedPasswordPolicy.containsKey(profile)) { dataCache.cachedPasswordPolicy.put(profile,new LinkedHashMap<>()); } dataCache.cachedPasswordPolicy.get(profile).put(locale,policy); return policy; } public List<String> getPasswordProfileIDs() { return StoredConfigurationUtil.profilesForSetting(PwmSetting.PASSWORD_PROFILE_LIST, storedConfiguration); } protected PwmPasswordPolicy initPasswordPolicy(final String profile, final Locale locale) { final Map<String, String> passwordPolicySettings = new LinkedHashMap<>(); for (final PwmPasswordRule rule : PwmPasswordRule.values()) { if (rule.getPwmSetting() != null || rule.getAppProperty() != null) { final String value; final PwmSetting pwmSetting = rule.getPwmSetting(); switch (rule) { case DisallowedAttributes: case DisallowedValues: case CharGroupsValues: value = StringHelper.stringCollectionToString( JavaTypeConverter.valueToStringArray(storedConfiguration.readSetting(pwmSetting,profile)), "\n"); break; case RegExMatch: case RegExNoMatch: value = StringHelper.stringCollectionToString( JavaTypeConverter.valueToStringArray(storedConfiguration.readSetting(pwmSetting, profile)), ";;;"); break; case ChangeMessage: value = JavaTypeConverter.valueToLocalizedString( storedConfiguration.readSetting(pwmSetting, profile), locale); break; case ADComplexityLevel: value = JavaTypeConverter.valueToEnum( pwmSetting, storedConfiguration.readSetting(pwmSetting,profile), ADPolicyComplexity.class ).toString(); break; case AllowMacroInRegExSetting: value = readAppProperty(AppProperty.ALLOW_MACRO_IN_REGEX_SETTING); break; default: value = String.valueOf( storedConfiguration.readSetting(pwmSetting, profile).toNativeObject()); } passwordPolicySettings.put(rule.getKey(), value); } } // set case sensitivity final String caseSensitivitySetting = JavaTypeConverter.valueToString(storedConfiguration.readSetting( PwmSetting.PASSWORD_POLICY_CASE_SENSITIVITY)); if (!"read".equals(caseSensitivitySetting)) { passwordPolicySettings.put(PwmPasswordRule.CaseSensitive.getKey(),caseSensitivitySetting); } // set pwm-specific values final PwmPasswordPolicy passwordPolicy = PwmPasswordPolicy.createPwmPasswordPolicy(passwordPolicySettings); passwordPolicy.setProfileID(profile); { final List<UserPermission> queryMatch = (List<UserPermission>)storedConfiguration.readSetting(PwmSetting.PASSWORD_POLICY_QUERY_MATCH,profile).toNativeObject(); passwordPolicy.setUserPermissions(queryMatch); } passwordPolicy.setRuleText(JavaTypeConverter.valueToLocalizedString(storedConfiguration.readSetting(PwmSetting.PASSWORD_POLICY_RULE_TEXT,profile),locale)); return passwordPolicy; } public List<String> readSettingAsStringArray(final PwmSetting setting) { return JavaTypeConverter.valueToStringArray(readStoredValue(setting)); } public String readSettingAsLocalizedString(final PwmSetting setting, final Locale locale) { return JavaTypeConverter.valueToLocalizedString(readStoredValue(setting), locale); } public boolean isDefaultValue(final PwmSetting pwmSetting) { return storedConfiguration.isDefaultValue(pwmSetting); } public Collection<Locale> localesForSetting(final PwmSetting setting) { final Collection<Locale> returnCollection = new ArrayList<>(); switch (setting.getSyntax()) { case LOCALIZED_TEXT_AREA: case LOCALIZED_STRING: for (final String localeStr : ((Map<String, String>)readStoredValue(setting).toNativeObject()).keySet()) { returnCollection.add(LocaleHelper.parseLocaleString(localeStr)); } break; case LOCALIZED_STRING_ARRAY: for (final String localeStr : ((Map<String, List<String>>)readStoredValue(setting).toNativeObject()).keySet()) { returnCollection.add(LocaleHelper.parseLocaleString(localeStr)); } break; default: // ignore other types break; } return returnCollection; } public String readProperty(final ConfigurationProperty key) { return storedConfiguration.readConfigProperty(key); } public boolean readSettingAsBoolean(final PwmSetting setting) { return JavaTypeConverter.valueToBoolean(readStoredValue(setting)); } public Map<FileValue.FileInformation,FileValue.FileContent> readSettingAsFile(final PwmSetting setting) { final FileValue fileValue = (FileValue)storedConfiguration.readSetting(setting); return (Map)fileValue.toNativeObject(); } public X509Certificate[] readSettingAsCertificate(final PwmSetting setting) { if (PwmSettingSyntax.X509CERT != setting.getSyntax()) { throw new IllegalArgumentException("may not read X509CERT value for setting: " + setting.toString()); } if (readStoredValue(setting) == null) { return new X509Certificate[0]; } return (X509Certificate[])readStoredValue(setting).toNativeObject(); } public PrivateKeyCertificate readSettingAsPrivateKey(final PwmSetting setting) { if (PwmSettingSyntax.PRIVATE_KEY != setting.getSyntax()) { throw new IllegalArgumentException("may not read PRIVATE_KEY value for setting: " + setting.toString()); } if (readStoredValue(setting) == null) { return null; } return (PrivateKeyCertificate)readStoredValue(setting).toNativeObject(); } public String getNotes() { return storedConfiguration.readConfigProperty(ConfigurationProperty.NOTES); } private PwmSecurityKey tempInstanceKey = null; public PwmSecurityKey getSecurityKey() throws PwmUnrecoverableException { final PasswordData configValue = readSettingAsPassword(PwmSetting.PWM_SECURITY_KEY); if (configValue == null || configValue.getStringValue().isEmpty()) { final String errorMsg = "Security Key value is not configured,will generate temp value for use by runtime instance"; final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg); LOGGER.warn(errorInfo.toDebugStr()); if (tempInstanceKey == null) { tempInstanceKey = new PwmSecurityKey(PwmRandom.getInstance().alphaNumericString(256)); } return tempInstanceKey; } final int minSecurityKeyLength = Integer.parseInt(readAppProperty(AppProperty.SECURITY_CONFIG_MIN_SECURITY_KEY_LENGTH)); if (configValue.getStringValue().length() < minSecurityKeyLength) { final String errorMsg = "Security Key must be greater than 32 characters in length"; final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg); throw new PwmUnrecoverableException(errorInfo); } try { return new PwmSecurityKey(configValue.getStringValue()); } catch (Exception e) { final String errorMsg = "unexpected error generating Security Key crypto: " + e.getMessage(); final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg); LOGGER.error(errorInfo.toDebugStr(),e); throw new PwmUnrecoverableException(errorInfo); } } public List<DataStorageMethod> getResponseStorageLocations(final PwmSetting setting) { return getGenericStorageLocations(setting); } public List<DataStorageMethod> getOtpSecretStorageLocations(final PwmSetting setting) { return getGenericStorageLocations(setting); } private List<DataStorageMethod> getGenericStorageLocations(final PwmSetting setting) { final String input = readSettingAsString(setting); final List<DataStorageMethod> storageMethods = new ArrayList<>(); for (final String rawValue : input.split("-")) { try { storageMethods.add(DataStorageMethod.valueOf(rawValue)); } catch (IllegalArgumentException e) { LOGGER.error("unknown STORAGE_METHOD found: " + rawValue); } } return storageMethods; } public LdapProfile getDefaultLdapProfile() throws PwmUnrecoverableException { if (getLdapProfiles().isEmpty()) { throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR,null,new String[]{"no ldap profiles are defined"})); } return getLdapProfiles().values().iterator().next(); } public List<Locale> getKnownLocales() { if (dataCache.localeFlagMap == null) { dataCache.localeFlagMap = figureLocaleFlagMap(); } return Collections.unmodifiableList(new ArrayList<>(dataCache.localeFlagMap.keySet())); } public Map<Locale,String> getKnownLocaleFlagMap() { if (dataCache.localeFlagMap == null) { dataCache.localeFlagMap = figureLocaleFlagMap(); } return dataCache.localeFlagMap; } private Map<Locale,String> figureLocaleFlagMap() { final String defaultLocaleAsString = PwmConstants.DEFAULT_LOCALE.toString(); final List<String> inputList = readSettingAsStringArray(PwmSetting.KNOWN_LOCALES); final Map<String,String> inputMap = StringUtil.convertStringListToNameValuePair(inputList, "::"); // Sort the map by display name final Map<String,String> sortedMap = new TreeMap<>(); for (final String localeString : inputMap.keySet()) { final Locale theLocale = LocaleHelper.parseLocaleString(localeString); if (theLocale != null) { sortedMap.put(theLocale.getDisplayName(), localeString); } } final List<String> returnList = new ArrayList<>(); //ensure default is first. returnList.add(defaultLocaleAsString); for (final String localeDisplayString : sortedMap.keySet()) { final String localeString = sortedMap.get(localeDisplayString); if (!defaultLocaleAsString.equals(localeString)) { returnList.add(localeString); } } final Map<Locale,String> localeFlagMap = new LinkedHashMap<>(); for (final String localeString : returnList) { final Locale loopLocale = LocaleHelper.parseLocaleString(localeString); if (loopLocale != null) { final String flagCode = inputMap.containsKey(localeString) ? inputMap.get(localeString) : loopLocale.getCountry(); localeFlagMap.put(loopLocale, flagCode); } } return Collections.unmodifiableMap(localeFlagMap); } public TokenStorageMethod getTokenStorageMethod() { try { return TokenStorageMethod.valueOf(readSettingAsString(PwmSetting.TOKEN_STORAGEMETHOD)); } catch (Exception e) { final String errorMsg = "unknown storage method specified: " + readSettingAsString(PwmSetting.TOKEN_STORAGEMETHOD); final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_INVALID_CONFIG,errorMsg); LOGGER.warn(errorInformation.toDebugStr()); return null; } } public PwmSettingTemplateSet getTemplate() { return storedConfiguration.getTemplateSet(); } public boolean hasDbConfigured() { if (readSettingAsString(PwmSetting.DATABASE_CLASS) == null || readSettingAsString(PwmSetting.DATABASE_CLASS).length() < 1) { return false; } if (readSettingAsString(PwmSetting.DATABASE_URL) == null || readSettingAsString(PwmSetting.DATABASE_URL).length() < 1) { return false; } if (readSettingAsString(PwmSetting.DATABASE_USERNAME) == null || readSettingAsString(PwmSetting.DATABASE_USERNAME).length() < 1) { return false; } if (readSettingAsPassword(PwmSetting.DATABASE_PASSWORD) == null) { return false; } return true; } public String readAppProperty(final AppProperty property) { final Map<String,String> configurationValues = StringUtil.convertStringListToNameValuePair(this.readSettingAsStringArray(PwmSetting.APP_PROPERTY_OVERRIDES),"="); if (configurationValues.containsKey(property.getKey())) { return configurationValues.get(property.getKey()); } return property.getDefaultValue(); } private Convenience helper = new Convenience(); public Convenience helper() { return helper; } public class Convenience { public List<DataStorageMethod> getCrReadPreference() { final List<DataStorageMethod> readPreferences = getResponseStorageLocations(PwmSetting.FORGOTTEN_PASSWORD_READ_PREFERENCE); if (readPreferences.size() == 1 && readPreferences.get(0) == DataStorageMethod.AUTO) { readPreferences.clear(); if (hasDbConfigured()) { readPreferences.add(DataStorageMethod.DB); } else { readPreferences.add(DataStorageMethod.LDAP); } } if (readSettingAsBoolean(PwmSetting.EDIRECTORY_USE_NMAS_RESPONSES)) { readPreferences.add(DataStorageMethod.NMAS); } return readPreferences; } public List<DataStorageMethod> getCrWritePreference() { final List<DataStorageMethod> writeMethods = getResponseStorageLocations(PwmSetting.FORGOTTEN_PASSWORD_WRITE_PREFERENCE); if (writeMethods.size() == 1 && writeMethods.get(0) == DataStorageMethod.AUTO) { writeMethods.clear(); if (hasDbConfigured()) { writeMethods.add(DataStorageMethod.DB); } else { writeMethods.add(DataStorageMethod.LDAP); } } if (readSettingAsBoolean(PwmSetting.EDIRECTORY_STORE_NMAS_RESPONSES)) { writeMethods.add(DataStorageMethod.NMAS); } return writeMethods; } public boolean shouldHaveDbConfigured() { final PwmSetting[] settingsToCheck = new PwmSetting[] { PwmSetting.FORGOTTEN_PASSWORD_READ_PREFERENCE, PwmSetting.FORGOTTEN_PASSWORD_WRITE_PREFERENCE, PwmSetting.INTRUDER_STORAGE_METHOD, PwmSetting.EVENTS_USER_STORAGE_METHOD, }; for (final PwmSetting loopSetting : settingsToCheck) { if (getResponseStorageLocations(loopSetting).contains(DataStorageMethod.DB)) { return true; } } return false; } } private StoredValue readStoredValue(final PwmSetting setting) { if (dataCache.settings.containsKey(setting)) { return dataCache.settings.get(setting); } final StoredValue readValue = storedConfiguration.readSetting(setting); dataCache.settings.put(setting, readValue); return readValue; } private static class DataCache implements Serializable { private final Map<String,Map<Locale,PwmPasswordPolicy>> cachedPasswordPolicy = new LinkedHashMap<>(); private Map<Locale,String> localeFlagMap = null; private Map<String,LdapProfile> ldapProfiles; private final Map<PwmSetting, StoredValue> settings = new EnumMap<>(PwmSetting.class); private final Map<String,Map<Locale,String>> customText = new LinkedHashMap<>(); private final Map<ProfileType,Map<String,Profile>> profileCache = new LinkedHashMap<>(); } public Map<AppProperty,String> readAllNonDefaultAppProperties() { final LinkedHashMap<AppProperty,String> nonDefaultProperties = new LinkedHashMap<>(); for (final AppProperty loopProperty : AppProperty.values()) { final String configuredValue = readAppProperty(loopProperty); final String defaultValue = loopProperty.getDefaultValue(); if (configuredValue != null && !configuredValue.equals(defaultValue)) { nonDefaultProperties.put(loopProperty,configuredValue); } } return nonDefaultProperties; } /* generic profile stuff */ public Map<String,NewUserProfile> getNewUserProfiles() { final Map<String,NewUserProfile> returnMap = new LinkedHashMap<>(); final Map<String,Profile> profileMap = profileMap(ProfileType.NewUser); for (final String profileID : profileMap.keySet()) { returnMap.put(profileID, (NewUserProfile)profileMap.get(profileID)); } return returnMap; } public Map<String,HelpdeskProfile> getHelpdeskProfiles() { final Map<String,HelpdeskProfile> returnMap = new LinkedHashMap<>(); final Map<String,Profile> profileMap = profileMap(ProfileType.Helpdesk); for (final String profileID : profileMap.keySet()) { returnMap.put(profileID, (HelpdeskProfile)profileMap.get(profileID)); } return returnMap; } public Map<String,UpdateAttributesProfile> getUpdateAttributesProfile() { final Map<String,UpdateAttributesProfile> returnMap = new LinkedHashMap<>(); final Map<String,Profile> profileMap = profileMap(ProfileType.UpdateAttributes); for (final String profileID : profileMap.keySet()) { returnMap.put(profileID, (UpdateAttributesProfile)profileMap.get(profileID)); } return returnMap; } public Map<String,ForgottenPasswordProfile> getForgottenPasswordProfiles() { final Map<String,ForgottenPasswordProfile> returnMap = new LinkedHashMap<>(); final Map<String,Profile> profileMap = profileMap(ProfileType.ForgottenPassword); for (final String profileID : profileMap.keySet()) { returnMap.put(profileID, (ForgottenPasswordProfile)profileMap.get(profileID)); } return returnMap; } public Map<String,Profile> profileMap(final ProfileType profileType) { if (!dataCache.profileCache.containsKey(profileType)) { dataCache.profileCache.put(profileType,new LinkedHashMap<>()); for (final String profileID : ProfileUtility.profileIDsForCategory(this, profileType.getCategory())) { final Profile newProfile = newProfileForID(profileType, profileID); dataCache.profileCache.get(profileType).put(profileID, newProfile); } } return dataCache.profileCache.get(profileType); } private Profile newProfileForID(final ProfileType profileType, final String profileID) { final Profile newProfile; switch (profileType) { case Helpdesk: newProfile = HelpdeskProfile.makeFromStoredConfiguration(storedConfiguration, profileID); break; case ForgottenPassword: newProfile = ForgottenPasswordProfile.makeFromStoredConfiguration(storedConfiguration, profileID); break; case NewUser: newProfile = NewUserProfile.makeFromStoredConfiguration(storedConfiguration, profileID); break; case UpdateAttributes: newProfile = UpdateAttributesProfile.makeFromStoredConfiguration(storedConfiguration, profileID); break; case DeleteAccount: newProfile = DeleteAccountProfile.makeFromStoredConfiguration(storedConfiguration, profileID); break; default: throw new IllegalArgumentException("unknown profile type: " + profileType.toString()); } return newProfile; } public StoredConfigurationImpl getStoredConfiguration() throws PwmUnrecoverableException { final StoredConfigurationImpl copiedStoredConfiguration = StoredConfigurationImpl.copy(storedConfiguration); copiedStoredConfiguration.lock(); return copiedStoredConfiguration; } public boolean isDevDebugMode() { return Boolean.parseBoolean(readAppProperty(AppProperty.LOGGING_DEV_OUTPUT)); } public String configurationHash() throws PwmUnrecoverableException { return storedConfiguration.settingChecksum(); } public Set<PwmSetting> nonDefaultSettings() { final Set returnSet = new LinkedHashSet(); for (final StoredConfigurationImpl.SettingValueRecord valueRecord : this.storedConfiguration.modifiedSettings()) { returnSet.add(valueRecord.getSetting()); } return returnSet; } }