浏览代码

configeditor bug fixes

jrivard 10 年之前
父节点
当前提交
215ec45c8a

+ 0 - 3
pwm/servlet/src/password/pwm/AppProperty.java

@@ -133,9 +133,6 @@ public enum AppProperty {
     NMAS_THREADS_MIN_SECONDS                        ("nmas.threads.minSeconds"),
     NMAS_THREADS_MAX_SECONDS                        ("nmas.threads.maxSeconds"),
     NMAS_THREADS_WATCHDOG_FREQUENCY                 ("nmas.threads.watchdogFrequencyMs"),
-    NMAS_CR_MIN_RANDOM_DURING_SETUP                 ("nmas.cr.minRandomDuringSetup"),
-    NMAS_CR_APPLY_WORDLIST                          ("nmas.cr.applyWordlist"),
-    NMAS_CR_MAX_QUESTION_CHARS_IN__ANSWER           ("nmas.cr.maxQuestionCharsInAnswer"),
     OAUTH_ID_REQUEST_TYPE                           ("oauth.id.requestType"),
     OAUTH_ID_ACCESS_GRANT_TYPE                      ("oauth.id.accessGrantType"),
     OAUTH_ID_REFRESH_GRANT_TYPE                     ("oauth.id.refreshGrantType"),

+ 0 - 3
pwm/servlet/src/password/pwm/AppProperty.properties

@@ -123,9 +123,6 @@ nmas.threads.maxCount=120
 nmas.threads.minSeconds=1800
 nmas.threads.maxSeconds=3000
 nmas.threads.watchdogFrequencyMs=1000
-nmas.cr.minRandomDuringSetup=0
-nmas.cr.applyWordlist=false
-nmas.cr.maxQuestionCharsInAnswer=0
 oauth.id.accessGrantType=authorization_code
 oauth.id.refreshGrantType=refresh_token
 oauth.id.requestType=code

+ 18 - 8
pwm/servlet/src/password/pwm/config/PwmSetting.java

@@ -30,6 +30,8 @@ import password.pwm.config.value.PasswordValue;
 import password.pwm.config.value.ValueFactory;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.i18n.Config;
+import password.pwm.i18n.LocaleHelper;
 import password.pwm.util.logging.PwmLogger;
 
 import java.util.*;
@@ -811,17 +813,25 @@ public enum PwmSetting {
 
     // edirectory settings
     EDIRECTORY_ENABLE_NMAS(
-            "ldap.edirectory.enableNmas", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIRECTORY, Template.NOVL),
+            "ldap.edirectory.enableNmas", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_SETTINGS, Template.NOVL),
     EDIRECTORY_STORE_NMAS_RESPONSES(
-            "ldap.edirectory.storeNmasResponses", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIRECTORY, Template.NOVL),
+            "ldap.edirectory.storeNmasResponses", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_SETTINGS, Template.NOVL),
     EDIRECTORY_USE_NMAS_RESPONSES(
-            "ldap.edirectory.useNmasResponses", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIRECTORY, Template.NOVL),
+            "ldap.edirectory.useNmasResponses", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_SETTINGS, Template.NOVL),
     EDIRECTORY_READ_USER_PWD(
-            "ldap.edirectory.readUserPwd", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIRECTORY, Template.NOVL),
-    EDIRECTORY_READ_CHALLENGE_SET(
-            "ldap.edirectory.readChallengeSets", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIRECTORY, Template.NOVL),
+            "ldap.edirectory.readUserPwd", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_SETTINGS, Template.NOVL),
     EDIRECTORY_PWD_MGT_WEBSERVICE_URL(
-            "ldap.edirectory.ws.pwdMgtURL", PwmSettingSyntax.STRING, PwmSettingCategory.EDIRECTORY, Template.NOVL),
+            "ldap.edirectory.ws.pwdMgtURL", PwmSettingSyntax.STRING, PwmSettingCategory.EDIR_SETTINGS, Template.NOVL),
+
+    EDIRECTORY_READ_CHALLENGE_SET(
+            "ldap.edirectory.readChallengeSets", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_CR_SETTINGS, Template.NOVL),
+    EDIRECTORY_CR_MIN_RANDOM_DURING_SETUP(
+            "ldap.edirectory.cr.minRandomDuringSetup", PwmSettingSyntax.NUMERIC, PwmSettingCategory.EDIR_CR_SETTINGS, Template.NOVL),
+    EDIRECTORY_CR_APPLY_WORDLIST(
+            "ldap.edirectory.cr.applyWordlist", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.EDIR_CR_SETTINGS, Template.NOVL),
+    EDIRECTORY_CR_MAX_QUESTION_CHARS_IN__ANSWER(
+            "ldap.edirectory.cr.maxQuestionCharsInAnswer", PwmSettingSyntax.NUMERIC, PwmSettingCategory.EDIR_CR_SETTINGS, Template.NOVL),
+
 
     // active directory
     AD_USE_PROXY_FOR_FORGOTTEN(
@@ -1235,7 +1245,7 @@ public enum PwmSetting {
             final String profileID,
             final Locale locale
     ) {
-        final String SEPARATOR = " -> ";
+        final String SEPARATOR = LocaleHelper.getLocalizedMessage(locale, Config.Display_SettingNavigationSeparator, null);
         final StringBuilder sb = new StringBuilder();
         sb.append(this.getCategory().toMenuLocationDebug(profileID, locale));
 

+ 30 - 1
pwm/servlet/src/password/pwm/config/PwmSetting.xml

@@ -3105,6 +3105,27 @@
             <value />
         </default>
     </setting>
+    <setting key="ldap.edirectory.cr.minRandomDuringSetup" level="1" required="true">
+        <label>eDir CR Minimum Randoms During Setup</label>
+        <description><![CDATA[]]></description>
+        <default>
+            <value>0</value>
+        </default>
+    </setting>
+    <setting key="ldap.edirectory.cr.applyWordlist" level="1" required="true">
+        <label>eDir CR Apply Wordlist</label>
+        <description><![CDATA[]]></description>
+        <default>
+            <value>false</value>
+        </default>
+    </setting>
+    <setting key="ldap.edirectory.cr.maxQuestionCharsInAnswer" level="1" required="true">
+        <label>eDir CR Maximum Question Chars In Answer</label>
+        <description><![CDATA[]]></description>
+        <default>
+            <value>0</value>
+        </default>
+    </setting>
     <setting key="ldap.ad.proxyForgotten" level="1" required="true">
         <label>Use Proxy When Password Forgotten</label>
         <description><![CDATA[If true, when the user's password is forgotten, the system will use the ldap proxy account for ldap work.  This is because an ldap connection is not possible to AD without the user's password.  When authenticated in this condition, the user will be forced to change password immediately.]]></description>
@@ -4105,7 +4126,15 @@
     </category>
     <category key="EDIRECTORY">
         <label>NetIQ eDirectory</label>
-        <description><![CDATA[NetIQ eDirectory specifc settings.]]></description>
+        <description><![CDATA[NetIQ eDirectory specific settings.]]></description>
+    </category>
+    <category key="EDIR_SETTINGS">
+        <label>eDirectory Settings</label>
+        <description><![CDATA[NetIQ eDirectory specific settings.]]></description>
+    </category>
+    <category key="EDIR_CR_SETTINGS">
+        <label>eDirectory CR Settings</label>
+        <description><![CDATA[NetIQ eDirectory CR specific settings.]]></description>
     </category>
     <category key="ACTIVE_DIRECTORY">
         <label>Active Directory</label>

+ 17 - 5
pwm/servlet/src/password/pwm/config/PwmSettingCategory.java

@@ -24,6 +24,8 @@ package password.pwm.config;
 
 import org.jdom2.Attribute;
 import org.jdom2.Element;
+import password.pwm.i18n.Config;
+import password.pwm.i18n.LocaleHelper;
 
 import java.util.*;
 
@@ -36,7 +38,11 @@ public enum PwmSettingCategory {
 
     LDAP_PROFILE                (LDAP),
     LDAP_GLOBAL                 (LDAP),
+
     EDIRECTORY                  (LDAP),
+    EDIR_SETTINGS               (EDIRECTORY),
+    EDIR_CR_SETTINGS            (EDIRECTORY),
+
     ACTIVE_DIRECTORY            (LDAP),
     ORACLE_DS                   (LDAP),
 
@@ -117,6 +123,7 @@ public enum PwmSettingCategory {
 
     private final PwmSettingCategory parent;
     private static final Map<PwmSettingCategory,PwmSetting> CACHE_PROFILE_SETTING = new HashMap<>();
+    private static List<PwmSettingCategory> cached_sortedSettings;
 
     PwmSettingCategory(PwmSettingCategory parent) {
         this.parent = parent;
@@ -234,7 +241,7 @@ public enum PwmSettingCategory {
             final String profileID,
             final Locale locale
     ) {
-        final String SEPARATOR = " -> ";
+        final String SEPARATOR = LocaleHelper.getLocalizedMessage(locale, Config.Display_SettingNavigationSeparator, null);
         final StringBuilder sb = new StringBuilder();
 
         PwmSettingCategory nextCategory = this;
@@ -256,10 +263,15 @@ public enum PwmSettingCategory {
     }
 
     public static List<PwmSettingCategory> sortedValues(final Locale locale) {
-        final Map<String,PwmSettingCategory> sortedCategories = new TreeMap<String,PwmSettingCategory>();
-        for (final PwmSettingCategory category : PwmSettingCategory.values()) {
-            sortedCategories.put(category.toMenuLocationDebug(null,locale),category);
+        if (cached_sortedSettings == null) {
+            int counter = 0; // prevents dupes from being eliminated;
+            final Map<String, PwmSettingCategory> sortedCategories = new TreeMap<String, PwmSettingCategory>();
+            for (final PwmSettingCategory category : PwmSettingCategory.values()) {
+                final String sortValue = category.toMenuLocationDebug(null, locale) + (counter++);
+                sortedCategories.put(sortValue, category);
+            }
+            cached_sortedSettings = Collections.unmodifiableList(new ArrayList<>(sortedCategories.values()));
         }
-        return Collections.unmodifiableList(new ArrayList<>(sortedCategories.values()));
+        return cached_sortedSettings;
     }
 }

+ 5 - 1
pwm/servlet/src/password/pwm/config/StoredConfiguration.java

@@ -34,6 +34,8 @@ import password.pwm.config.value.StringArrayValue;
 import password.pwm.config.value.StringValue;
 import password.pwm.config.value.ValueFactory;
 import password.pwm.error.*;
+import password.pwm.i18n.Config;
+import password.pwm.i18n.LocaleHelper;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.util.*;
 import password.pwm.util.logging.PwmLogger;
@@ -1204,6 +1206,8 @@ public class StoredConfiguration implements Serializable {
 
         public String changeLogAsDebugString(final Locale locale, boolean asHtml) {
             final Map<String,String> outputMap = new TreeMap<>();
+            final String SEPARATOR = LocaleHelper.getLocalizedMessage(locale, Config.Display_SettingNavigationSeparator, null);
+
             for (final ConfigRecordID configRecordID : changeLog.keySet()) {
                 switch (configRecordID.recordType) {
                     case SETTING: {
@@ -1221,7 +1225,7 @@ public class StoredConfiguration implements Serializable {
                         final String keys = key.split("!")[1];
                         final Map<String,String> currentValue = readLocaleBundleMap(bundleName,keys);
                         final String debugValue = JsonUtil.serializeMap(currentValue, JsonUtil.Flag.PrettyPrint);
-                        outputMap.put("LocaleBundle" + " -> " + bundleName + " " + keys,debugValue);
+                        outputMap.put("LocaleBundle" + SEPARATOR + bundleName + " " + keys,debugValue);
                     }
                     break;
                 }

+ 15 - 8
pwm/servlet/src/password/pwm/config/option/RecoveryVerificationMethod.java

@@ -23,26 +23,29 @@
 package password.pwm.config.option;
 
 import password.pwm.config.Configuration;
+import password.pwm.i18n.Config;
 import password.pwm.i18n.Display;
 
 import java.util.Locale;
 
 public enum RecoveryVerificationMethod implements ConfigurationOption {
-    PREVIOUS_AUTH(      false,  Display.Field_VerificationMethodPreviousAuth),
-    ATTRIBUTES(         true,   Display.Field_VerificationMethodAttributes),
-    CHALLENGE_RESPONSES(true,   Display.Field_VerificationMethodChallengeResponses),
-    TOKEN(              true,   Display.Field_VerificationMethodToken),
-    OTP(                true,   Display.Field_VerificationMethodOTP),
-    REMOTE_RESPONSES(   false,  Display.Field_VerificationMethodRemoteResponses),
+    PREVIOUS_AUTH(      false,  Display.Field_VerificationMethodPreviousAuth,       Config.Field_VerificationMethodPreviousAuth),
+    ATTRIBUTES(         true,   Display.Field_VerificationMethodAttributes,         Config.Field_VerificationMethodAttributes),
+    CHALLENGE_RESPONSES(true,   Display.Field_VerificationMethodChallengeResponses, Config.Field_VerificationMethodChallengeResponses),
+    TOKEN(              true,   Display.Field_VerificationMethodToken,              Config.Field_VerificationMethodToken),
+    OTP(                true,   Display.Field_VerificationMethodOTP,                Config.Field_VerificationMethodOTP),
+    REMOTE_RESPONSES(   false,  Display.Field_VerificationMethodRemoteResponses,    Config.Field_VerificationMethodRemoteResponses),
 
     ;
     
     private final boolean userSelectable;
     private final Display displayKey;
+    private final Config configDisplayKey;
 
-    RecoveryVerificationMethod(boolean userSelectable, Display displayKey) {
+    RecoveryVerificationMethod(boolean userSelectable, Display displayKey, Config configDisplayKey) {
         this.userSelectable = userSelectable;
         this.displayKey = displayKey;
+        this.configDisplayKey = configDisplayKey;
     }
 
     public boolean isUserSelectable() {
@@ -52,7 +55,11 @@ public enum RecoveryVerificationMethod implements ConfigurationOption {
     public Display getDisplayKey() {
         return displayKey;
     }
-    
+
+    public Config getConfigDisplayKey() {
+        return configDisplayKey;
+    }
+
     public String getLabel(final Configuration configuration, final Locale locale) {
         return Display.getLocalizedMessage(locale, this.getDisplayKey(), configuration);
     }

+ 4 - 1
pwm/servlet/src/password/pwm/health/ConfigurationChecker.java

@@ -34,6 +34,8 @@ import password.pwm.config.profile.NewUserProfile;
 import password.pwm.config.profile.Profile;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.i18n.Config;
+import password.pwm.i18n.LocaleHelper;
 import password.pwm.util.PasswordData;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.operations.PasswordUtility;
@@ -65,6 +67,7 @@ public class ConfigurationChecker implements HealthChecker {
         }
 
         final String siteUrl = config.readSettingAsString(PwmSetting.PWM_SITE_URL);
+        final String SEPARATOR = LocaleHelper.getLocalizedMessage(PwmConstants.DEFAULT_LOCALE, Config.Display_SettingNavigationSeparator, null);
         try {
             if (siteUrl == null || siteUrl.isEmpty() || siteUrl.equals(
                     PwmSetting.PWM_SITE_URL.getDefaultValue(config.getTemplate()).toNativeObject())) {
@@ -84,7 +87,7 @@ public class ConfigurationChecker implements HealthChecker {
         }
 
         if (Boolean.parseBoolean(config.readAppProperty(AppProperty.LDAP_PROMISCUOUS_ENABLE))) {
-            final String appPropertyKey = "AppProperty -> " + AppProperty.LDAP_PROMISCUOUS_ENABLE.getKey();
+            final String appPropertyKey = "AppProperty" +  SEPARATOR + AppProperty.LDAP_PROMISCUOUS_ENABLE.getKey();
             records.add(HealthRecord.forMessage(HealthMessage.Config_PromiscuousLDAP, appPropertyKey));
         }
 

+ 6 - 2
pwm/servlet/src/password/pwm/http/servlet/ConfigEditorServlet.java

@@ -137,7 +137,7 @@ public class ConfigEditorServlet extends PwmServlet {
             return null;
         }
     }
-    
+
 
 // -------------------------- OTHER METHODS --------------------------
 
@@ -953,7 +953,11 @@ public class ConfigEditorServlet extends PwmServlet {
         {
             final LinkedHashMap<String, Object> verificationMethodMap = new LinkedHashMap<>();
             for (final RecoveryVerificationMethod recoveryVerificationMethod : RecoveryVerificationMethod.values()) {
-                verificationMethodMap.put(recoveryVerificationMethod.toString(), recoveryVerificationMethod.getLabel(pwmRequest.getConfig(), pwmRequest.getLocale()));
+                final String displayLabel = LocaleHelper.getLocalizedMessage(
+                        pwmRequest.getLocale(),
+                        recoveryVerificationMethod.getConfigDisplayKey(),
+                        pwmRequest.getConfig());
+                verificationMethodMap.put(recoveryVerificationMethod.toString(),displayLabel);
             }
             returnMap.put("verificationMethods",verificationMethodMap);
         }

+ 103 - 91
pwm/servlet/src/password/pwm/i18n/Config.java

@@ -27,103 +27,115 @@ import password.pwm.config.Configuration;
 import java.util.Locale;
 
 public enum Config implements PwmDisplayBundle {
-    Button_Next,
-    Button_Previous,
-    Button_CheckSettings,
-    Button_ShowAdvanced,
-    Button_HideAdvanced,
-    Confirm_LockConfig,
-    Confirm_SkipGuide,
-    Confirm_UploadConfig,
-    Confirm_UploadLocalDB,
-    Confirm_SSLDisable,
-    Display_AboutTemplates,
-    Display_ConfigEditorLocales,
-    Display_ConfigGuideNotSecureLDAP,
-    Display_ConfigGuideSelectTemplate,
-    Display_ConfigGuideSelectCrStorage,
-    Display_ConfigGuideLdapSchema,
-    Display_ConfigGuideLdapSchema2,
-    Display_ConfigManagerConfiguration,
-    Display_ConfigManagerNew,
-    Display_ConfigManagerRunning,
-    Display_ConfigManagerRunningEditor,
-    Display_ConfigOpenInfo,
-    MenuDisplay_AlternateNewConfig,
-    MenuDisplay_AlternateUnlockConfig,
-    MenuDisplay_AlternateUpload,
-    MenuDisplay_CancelEdits,
-    MenuDisplay_ConfigEditor,
-    MenuDisplay_DownloadConfig,
-    MenuDisplay_DownloadConfigRunning,
-    MenuDisplay_DownloadBundle,
-    MenuDisplay_LockConfig,
-    MenuDisplay_UnlockConfig,
-    MenuDisplay_ExportLocalDB,
-    MenuDisplay_MainMenu,
-    MenuDisplay_ManualConfig,
-    MenuDisplay_ReturnToEditor,
-    MenuDisplay_SaveConfig,
-    MenuDisplay_CancelConfig,
-    MenuDisplay_StartConfigGuide,
-    MenuDisplay_UploadConfig,
-    MenuDisplay_ViewLog,
-    MenuItem_AlternateNewConfig,
-    MenuItem_AlternateUnlockConfig,
-    MenuItem_CancelEdits,
-    MenuItem_DownloadConfig,
-    MenuItem_DownloadBundle,
-    MenuItem_LockConfig,
-    MenuItem_ExportLocalDB,
-    MenuItem_MainMenu,
-    MenuItem_ManualConfig,
-    MenuItem_ReturnToEditor,
-    MenuItem_StartConfigGuide,
-    MenuItem_UploadConfig,
-    MenuItem_UnlockConfig,
-    MenuItem_ViewLog,
-    MenuItem_Home,
-    Setting_Permission_Profile,
-    Setting_Permission_Filter,
-    Setting_Permission_Base,
-    Setting_Permission_Base_Group,
-    Title_ConfigGuide,
-    Title_ConfigGuide_app,
-    Title_ConfigGuide_ldap,
-    Title_ConfigGuide_ldapcert,
-    Title_ConfigGuide_ldap_schema,
-    Title_ConfigGuide_start,
-    Title_ConfigGuide_template,
-    Title_ConfigGuide_crStorage,
-    Title_ConfigManager,
-    Warning_ChangeTemplate,
-    Warning_ResetSetting,
-    Warning_ShowAdvanced,
-    Warning_ShowDescription,
-    Warning_ShowNotes,
-    Warning_HeaderVisibility,
-    Warning_ConfigMustBeClosed,
-    Warning_MakeSupportZipNoTrace,
-    Warning_DownloadSupportZip,
-    Warning_DownloadConfiguration,
-    Warning_DownloadLocal,
-    Warning_InvalidFormat,
-    Warning_UploadIE9,
-    Tooltip_ResetButton,
-    Tooltip_HelpButton,
-    Tooltip_Setting_Permission_Profile,
-    Tooltip_Setting_Permission_Filter,
-    Tooltip_Setting_Permission_Base,
-    
-    ;
+
+Button_Next,
+Button_Previous,
+Button_CheckSettings,
+Button_ShowAdvanced,
+Button_HideAdvanced,
+Confirm_LockConfig,
+Confirm_SkipGuide,
+Confirm_UploadConfig,
+Confirm_UploadLocalDB,
+Confirm_SSLDisable,
+Display_AboutTemplates,
+Display_ConfigEditorLocales,
+Display_ConfigGuideNotSecureLDAP,
+Display_ConfigGuideSelectTemplate,
+Display_ConfigGuideSelectCrStorage,
+Display_ConfigGuideLdapSchema,
+Display_ConfigGuideLdapSchema2,
+Display_ConfigManagerConfiguration,
+Display_ConfigManagerNew,
+Display_ConfigManagerRunning,
+Display_ConfigManagerRunningEditor,
+Display_ConfigOpenInfo,
+Display_SettingFilter_Level_0,
+Display_SettingFilter_Level_1,
+Display_SettingFilter_Level_2,
+Display_SettingNavigationSeparator,
+Field_VerificationMethodPreviousAuth,
+Field_VerificationMethodToken,
+Field_VerificationMethodOTP,
+Field_VerificationMethodChallengeResponses,
+Field_VerificationMethodAttributes,
+Field_VerificationMethodRemoteResponses,
+Field_VerificationMethod,
+MenuDisplay_AlternateNewConfig,
+MenuDisplay_AlternateUnlockConfig,
+MenuDisplay_AlternateUpload,
+MenuDisplay_CancelEdits,
+MenuDisplay_ConfigEditor,
+MenuDisplay_DownloadConfig,
+MenuDisplay_DownloadConfigRunning,
+MenuDisplay_DownloadBundle,
+MenuDisplay_LockConfig,
+MenuDisplay_UnlockConfig,
+MenuDisplay_ExportLocalDB,
+MenuDisplay_MainMenu,
+MenuDisplay_ManualConfig,
+MenuDisplay_ReturnToEditor,
+MenuDisplay_SaveConfig,
+MenuDisplay_CancelConfig,
+MenuDisplay_StartConfigGuide,
+MenuDisplay_UploadConfig,
+MenuDisplay_ViewLog,
+MenuItem_AlternateNewConfig,
+MenuItem_AlternateUnlockConfig,
+MenuItem_CancelEdits,
+MenuItem_DownloadConfig,
+MenuItem_DownloadBundle,
+MenuItem_LockConfig,
+MenuItem_ExportLocalDB,
+MenuItem_MainMenu,
+MenuItem_ManualConfig,
+MenuItem_ReturnToEditor,
+MenuItem_StartConfigGuide,
+MenuItem_UploadConfig,
+MenuItem_UnlockConfig,
+MenuItem_ViewLog,
+MenuItem_Home,
+Setting_Permission_Profile,
+Setting_Permission_Filter,
+Setting_Permission_Base,
+Setting_Permission_Base_Group,
+Title_ConfigGuide,
+Title_ConfigGuide_app,
+Title_ConfigGuide_ldap,
+Title_ConfigGuide_ldapcert,
+Title_ConfigGuide_ldap_schema,
+Title_ConfigGuide_start,
+Title_ConfigGuide_template,
+Title_ConfigGuide_crStorage,
+Title_ConfigManager,
+Warning_ChangeTemplate,
+Warning_ResetSetting,
+Warning_ShowAdvanced,
+Warning_ShowDescription,
+Warning_ShowNotes,
+Warning_HeaderVisibility,
+Warning_ConfigMustBeClosed,
+Warning_MakeSupportZipNoTrace,
+Warning_DownloadSupportZip,
+Warning_DownloadConfiguration,
+Warning_DownloadLocal,
+Warning_InvalidFormat,
+Warning_UploadIE9,
+Tooltip_ResetButton,
+Tooltip_HelpButton,
+Tooltip_Setting_Permission_Profile,
+Tooltip_Setting_Permission_Filter,
+Tooltip_Setting_Permission_Base,
+
+;
 
     public static String getLocalizedMessage(final Locale locale, final Config key, final Configuration config) {
         return LocaleHelper.getLocalizedMessage(locale, key.toString(), config, Config.class);
     }
-    
+
     @Override
     public String getKey() {
         return this.toString();
-        
+
     }
 }

+ 8 - 1
pwm/servlet/src/password/pwm/i18n/Config.properties

@@ -43,10 +43,17 @@ Display_ConfigManagerConfiguration=<p>Welcome to the Configuration Manager. This
 Display_ConfigManagerNew=<p><b>Welcome to %1%.</b>  We hope you enjoy using this software.</p><p>%1% was not able to detect a pre-existing configuration and is now in new configuration mode.</p>
 Display_ConfigManagerRunning=<p><b>The configuration for this server has been closed.  However you can still edit the configuration.</b></p><p>For security reasons, to edit the configuration, you must upload (and then download) the <em>%1%</em> file.</p>
 Display_ConfigManagerRunningEditor=Your modified configuration is currently in memory, but has not yet been saved.  Please choose an option below to continue.
+Display_ConfigOpenInfo=<p>While the configuration status is <i>open</i> any user can access this configuration without authenticating to LDAP.</p><p>Please close the configuration using the <a id="link-configManager">ConfigurationManager</a> when the configuration is completed enough to authenticate administrative users.</p>
 Display_SettingFilter_Level_0=Required
 Display_SettingFilter_Level_1=Standard / Common
 Display_SettingFilter_Level_2=Advanced
-Display_ConfigOpenInfo=<p>While the configuration status is <i>open</i> any user can access this configuration without authenticating to LDAP.</p><p>Please close the configuration using the <a id="link-configManager">ConfigurationManager</a> when the configuration is completed enough to authenticate administrative users.</p>
+Display_SettingNavigationSeparator=\u0020\u21e8\u0020
+Field_VerificationMethodPreviousAuth=Previous Authentication
+Field_VerificationMethodToken=SMS/Email Token Verification
+Field_VerificationMethodOTP=OTP (Mobile Device) Verification
+Field_VerificationMethodChallengeResponses=Challenge/Response Answers
+Field_VerificationMethodAttributes=LDAP Attributes
+Field_VerificationMethodRemoteResponses=External Responses
 MenuDisplay_AlternateNewConfig=Edit a new configuration in memory by selecting a new configuration template. After editing the configuration, you can download the <em>%1%</em> file.  This option will not modify the running configuration.
 MenuDisplay_AlternateUnlockConfig=The closing of the <em>%1%</em> file is controlled by the property "configIsEditable" within the file.  Set this property to "true" to return to the online configuration mode. Be aware that while this property is set to true anyone accessing this site can make modifications to the live configuration without authentication.
 MenuDisplay_AlternateUpload=Alternatively, you may upload a previously saved configuration file. The uploaded file will be saved as the new configuration.

+ 4 - 5
pwm/servlet/src/password/pwm/util/operations/CrService.java

@@ -29,7 +29,6 @@ import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.exception.ChaiValidationException;
 import com.novell.ldapchai.impl.edir.NmasCrFactory;
 import com.novell.ldapchai.provider.ChaiProvider;
-import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmService;
 import password.pwm.bean.ResponseInfoBean;
@@ -131,7 +130,7 @@ public class CrService implements PwmService {
                                 locale,
                                 applyPwmPolicyToNmasChallenges(returnSet, config),
                                 null,
-                                Integer.parseInt(config.readAppProperty(AppProperty.NMAS_CR_MIN_RANDOM_DURING_SETUP)),
+                                (int)config.readSettingAsLong(PwmSetting.EDIRECTORY_CR_MIN_RANDOM_DURING_SETUP),
                                 0
                         );
 
@@ -146,7 +145,7 @@ public class CrService implements PwmService {
             }
         }
 
-        // use PWM policies if PWM is configured and either its all that is configured OR the NMAS policy read was not successfull
+        // use PWM policies if PWM is configured and either its all that is configured OR the NMAS policy read was not successful
         final String challengeProfileID = determineChallengeProfileForUser(pwmApplication, sessionLabel, userIdentity, locale);
         final ChallengeProfile challengeProfile = config.getChallengeProfile(challengeProfileID, locale);
 
@@ -157,8 +156,8 @@ public class CrService implements PwmService {
 
     private static ChallengeSet applyPwmPolicyToNmasChallenges(final ChallengeSet challengeSet, final Configuration configuration) throws PwmUnrecoverableException {
         final List<Challenge> newChallenges = new ArrayList<>();
-        final boolean applyWordlist = Boolean.parseBoolean(configuration.readAppProperty(AppProperty.NMAS_CR_APPLY_WORDLIST));
-        final int questionsInAnswer = Integer.parseInt(configuration.readAppProperty(AppProperty.NMAS_CR_MAX_QUESTION_CHARS_IN__ANSWER));
+        final boolean applyWordlist = configuration.readSettingAsBoolean(PwmSetting.EDIRECTORY_CR_APPLY_WORDLIST);
+        final int questionsInAnswer = (int)configuration.readSettingAsLong(PwmSetting.EDIRECTORY_CR_MAX_QUESTION_CHARS_IN__ANSWER);
         for (final Challenge challenge : challengeSet.getChallenges()) {
             newChallenges.add(new ChaiChallenge(
                     challenge.isRequired(),

+ 4 - 4
pwm/servlet/web/public/resources/configStyle.css

@@ -492,14 +492,14 @@ input[type=range]:focus::-ms-fill-upper {
     background: #ccc;
 }
 
+
 button {
-    border-style:none;
-    padding: 4px 12px;
-    margin: 9px 7px;
     text-decoration: none;
     color: #3e374c;
     background: white;
     cursor: pointer;
+    border: 1px solid #9e9e9e;
+    border-radius: 2px;
 }.button:disabled {
      color: #9e9e9e;
- }
+ }

+ 134 - 49
pwm/servlet/web/public/resources/js/configeditor-settings.js

@@ -79,9 +79,9 @@ LocalizedStringValueHandler.draw = function(settingKey) {
         for (var localeKey in resultValue) {
             LocalizedStringValueHandler.drawRow(parentDiv, settingKey, localeKey, resultValue[localeKey])
         }
-        PWM_CFGEDIT.addAddLocaleButtonRow(parentDiv, settingKey, function(localeKey) {
+        UILibrary.addAddLocaleButtonRow(parentDiv, settingKey, function(localeKey) {
             LocalizedStringValueHandler.addLocaleSetting(settingKey, localeKey);
-        });
+        }, Object.keys(resultValue));
     }
 
     PWM_VAR['clientSettingCache'][settingKey] = resultValue;
@@ -258,7 +258,8 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
     valueRow.setAttribute("style", "border-width: 0");
     valueRow.setAttribute("id",inputID + "_row");
 
-    var rowHtml = '<td style=""><div class="configStringPanel" id="' + inputID + '"></div></td>';
+    var rowHtml = '<td id="button-' + inputID + '" style="border-width:0; width: 15px"><span class="fa fa-edit"/></ta>';
+    rowHtml += '<td style=""><div class="configStringPanel" id="' + inputID + '"></div></td>';
 
     var downButtonID = 'button-' + settingKey + '-' + iteration + '-moveDown';
     rowHtml += '<td style="border:0">';
@@ -290,6 +291,9 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
         PWM_MAIN.addEventHandler(inputID,'click',function(){
             StringArrayValueHandler.valueHandler(settingKey,iteration);
         });
+        PWM_MAIN.addEventHandler('button-' + inputID,'click',function(){
+            StringArrayValueHandler.valueHandler(settingKey,iteration);
+        });
     }
 
     if (itemCount > 1 && iteration != (itemCount -1)) {
@@ -506,7 +510,7 @@ MultiLocaleTableHandler.draw = function(keyName) {
             });
         };
 
-        PWM_CFGEDIT.addAddLocaleButtonRow(parentDiv, keyName, addLocaleFunction);
+        UILibrary.addAddLocaleButtonRow(parentDiv, keyName, addLocaleFunction, Object.keys(resultValue));
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
         dojoParser.parse(parentDiv);
     });
@@ -949,7 +953,7 @@ FormTableHandler.multiLocaleStringDialog = function(keyName, iteration, settingT
             var value = PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
             var localeID = inputID + localeName;
             bodyText += '<td>' + localeName + '</td>';
-            bodyText += '<td><input style="width:445px" class="configStringInput" type="text" value="' + value + '" id="' + localeID + '-input"></input></td>';
+            bodyText += '<td><input style="width:420px" class="configStringInput" type="text" value="' + value + '" id="' + localeID + '-input"></input></td>';
             if (localeName != '') {
                 bodyText += '<td><span class="delete-row-icon action-icon fa fa-times" id="' + localeID + '-removeLocaleButton"></span></td>';
             }
@@ -974,17 +978,21 @@ FormTableHandler.multiLocaleStringDialog = function(keyName, iteration, settingT
                             FormTableHandler.writeFormSetting(keyName);
                         });
                         PWM_MAIN.addEventHandler(localeID + '-removeLocaleButton', 'click', function () {
-                            delete PWM_VAR['clientSettingCache'][keyName][iteration]['labels'][localeName];
+                            delete PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
                             FormTableHandler.writeFormSetting(keyName);
                             FormTableHandler.multiLocaleStringDialog(keyName, iteration, settingType, finishAction, titleText);
                         });
                     }(iter));
                 }
-                PWM_CFGEDIT.addAddLocaleButtonRow(inputID + 'table', inputID, function(localeName){
-                    PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName] = '';
-                    FormTableHandler.writeFormSetting(keyName);
-                    FormTableHandler.multiLocaleStringDialog(keyName, iteration, settingType, finishAction, titleText);
-                });
+                UILibrary.addAddLocaleButtonRow(inputID + 'table', inputID, function(localeName){
+                    if (localeName in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
+                        alert('Locale is already present');
+                    } else {
+                        PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName] = '';
+                        FormTableHandler.writeFormSetting(keyName);
+                        FormTableHandler.multiLocaleStringDialog(keyName, iteration, settingType, finishAction, titleText);
+                    }
+                }, Object.keys(PWM_VAR['clientSettingCache'][keyName][iteration][settingType]));
             }
         });
     });
@@ -1717,7 +1725,7 @@ EmailTableHandler.draw = function(keyName) {
                         EmailTableHandler.writeSetting(keyName,true);
                     }
                 };
-                PWM_CFGEDIT.addAddLocaleButtonRow(parentDiv, keyName, addLocaleFunction);
+                UILibrary.addAddLocaleButtonRow(parentDiv, keyName, addLocaleFunction, Object.keys(PWM_VAR['clientSettingCache'][keyName]));
             }
             dojoParser.parse(parentDiv);
         });
@@ -1932,23 +1940,16 @@ ChallengeSettingHandler.draw = function(keyName) {
             bodyText += '</td>';
 
             bodyText += '<td onclick="' + editJsText + '"> ';
-            bodyText += '<div style="text-overflow:ellipsis; white-space:nowrap; overflow:hidden">';
             if (rowCount > 0) {
                 for (var iteration in multiValues) {
                     (function (rowKey) {
-                        var questionText = multiValues[rowKey]['text'];
-                        var adminDefined = multiValues[rowKey]['adminDefined'];
-                        bodyText += '<div>' + (adminDefined ? questionText : '[User Defined]') + '</div>';
+                        var id = 'panel-value-' + keyName + '-' + localeKey + '-' + iteration;
+                        bodyText += '<div style="text-overflow:ellipsis; white-space:nowrap; overflow:hidden" id="' + id + '">text</div>';
                     }(iteration));
                 }
             } else {
                 bodyText += '[No Questions]';
             }
-            bodyText += '</div>';
-            //bodyText += '</td><td style="border:0; vertical-align: top">';
-            //if (!isDefaultLocale) {
-            //    bodyText += '<span id="button-' + keyName + '-' + localeKey + '-deleteRow" style="top:0" class="delete-row-icon action-icon fa fa-times"/>';
-            //}
             bodyText += '</td></tr>';
             bodyText += '<tr><td>&nbsp;</td></tr>';
 
@@ -1973,7 +1974,26 @@ ChallengeSettingHandler.draw = function(keyName) {
     };
     var tableElement = document.createElement("table");
     parentDivElement.appendChild(tableElement);
-    PWM_CFGEDIT.addAddLocaleButtonRow(tableElement, keyName, addLocaleFunction);
+    UILibrary.addAddLocaleButtonRow(tableElement, keyName, addLocaleFunction, Object.keys(resultValue));
+
+    for (var localeName in resultValue) {
+        (function(localeKey) {
+            var multiValues = resultValue[localeKey];
+            var rowCount = PWM_MAIN.itemCount(multiValues);
+            if (rowCount > 0) {
+                for (var iteration in multiValues) {
+                    (function (rowKey) {
+                        var id = 'panel-value-' + keyName + '-' + localeKey + '-' + iteration;
+                        var questionText = multiValues[rowKey]['text'];
+                        var adminDefined = multiValues[rowKey]['adminDefined'];
+                        var output = (adminDefined ? questionText : '[User Defined]');
+                        UILibrary.addTextValueToElement(id,output);
+                    }(iteration));
+                }
+            }
+        }(localeName));
+    }
+
 };
 
 ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
@@ -2427,47 +2447,75 @@ DurationValueHandler.init = function(settingKey) {
 // -------------------------- string value handler ------------------------------------
 
 var StringValueHandler = {};
+
 StringValueHandler.init = function(settingKey) {
     var parentDiv = 'table_setting_' + settingKey;
     var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    var settingData = PWM_SETTINGS['settings'][settingKey];
+    PWM_CFGEDIT.readSetting(settingKey,function(data) {
+        var inputID = settingKey;
+        var bodyHtml = '';
+        var value = data;
+        if (value && value.length > 0) {
+            bodyHtml += '<table style="border-width: 0">';
+            bodyHtml += '<td id="button-' + inputID + '" style="border-width:0; width: 15px"><span class="fa fa-edit"/></ta>';
+            bodyHtml += '<td style=""><div class="configStringPanel" id="panel-' + inputID + '"></div></td>';
+            if (!settingData['required']) {
+                bodyHtml += '<td style="border-width: 0"><span id="button-' + inputID + '-delete" class="delete-row-icon action-icon fa fa-times"></span></td>';
+            }
 
-    parentDivElement.innerHTML = '<input class="configStringInput" id="value_' + settingKey + '" name="setting_' + settingKey + '" disabled/>'
-    + '&nbsp;<span id="icon-' + settingKey + '-warning" style="visibility:hidden; color:orange" class="btn-icon fa fa-warning"></span>';
-    PWM_CFGEDIT.readSetting(settingKey,function(data){
-        var inputElement = PWM_MAIN.getObject("value_" + settingKey);
-        inputElement.value = data;
-        if (PWM_SETTINGS['settings'][settingKey]['required']) {
-            inputElement.required = true;
+            bodyHtml += '</table>';
+        } else {
+            bodyHtml += '<button class="btn" id="button-add-' + inputID + '">';
+            bodyHtml += '<span class="btn-icon fa fa-plus-square"></span>Add Value';
+            bodyHtml += '</button>';
         }
-        if (PWM_SETTINGS['settings'][settingKey]['pattern']) {
-            inputElement.pattern = PWM_SETTINGS['settings'][settingKey]['pattern'];
-            inputElement.title = PWM_CONFIG.showString('Warning_InvalidFormat');
-            var validateValue = function() {
-                var re = new RegExp(PWM_SETTINGS['settings'][settingKey]['pattern']);
-                var matches = re.test(inputElement.value);
-                PWM_MAIN.getObject('icon-' + settingKey + '-warning').style.visibility = matches ?  'hidden' : 'visible';
-            };
-            PWM_MAIN.addEventHandler("value_" + settingKey,"keyup",function(){
-                validateValue();
+
+        parentDivElement.innerHTML = bodyHtml;
+        UILibrary.addTextValueToElement('panel-' + inputID, value);
+
+        PWM_MAIN.addEventHandler('button-' + inputID + '-delete','click',function(){
+            PWM_CFGEDIT.writeSetting(settingKey,'',function(){
+                StringValueHandler.init(settingKey);
             });
-            validateValue();
-            PWM_MAIN.showTooltip({id:'icon-'+settingKey+'-warning',text:PWM_CONFIG.showString('Warning_InvalidFormat')});
+        });
 
-        }
-        if (PWM_SETTINGS['settings'][settingKey]['placeholder']) {
-            inputElement.placeholder = PWM_SETTINGS['settings'][settingKey]['placeholder'];
-        }
-        inputElement.disabled = false;
-        PWM_MAIN.addEventHandler("value_" + settingKey,"input,change",function(){
-            PWM_CFGEDIT.writeSetting(settingKey,inputElement.value);
+        var editor = function(){
+            UILibrary.stringEditorDialog({
+                title:'Edit Value - ' + settingData['label'],
+                textarea:('TEXT_AREA' == settingData['syntax']),
+                regex:'pattern' in settingData ? settingData['pattern'] : '.+',
+                placeholder:settingData['placeholder'],
+                value:value,
+                completeFunction:function(value){
+                    PWM_CFGEDIT.writeSetting(settingKey,value,function(){
+                        StringValueHandler.init(settingKey);
+                    });
+                }
+            });
+        };
+
+        PWM_MAIN.addEventHandler('button-' + settingKey,'click',function(){
+            editor();
+        });
+        PWM_MAIN.addEventHandler('button-add-' + settingKey,'click',function(){
+            editor();
+        });
+        PWM_MAIN.addEventHandler('panel-' + settingKey,'click',function(){
+            editor();
         });
     });
 };
 
+
 // -------------------------- text area handler ------------------------------------
 
 var TextAreaValueHandler = {};
 TextAreaValueHandler.init = function(settingKey) {
+    StringValueHandler.init(settingKey);
+};
+
+TextAreaValueHandler.init2 = function(settingKey) {
     var parentDiv = 'table_setting_' + settingKey;
     var parentDivElement = PWM_MAIN.getObject(parentDiv);
 
@@ -2866,4 +2914,41 @@ UILibrary.addTextValueToElement = function(elementID, input) {
         element.innerHTML = '';
         element.appendChild(document.createTextNode(input));
     }
-};
+};
+
+UILibrary.addAddLocaleButtonRow = function(parentDiv, keyName, addFunction, existingLocales) {
+    var availableLocales = PWM_GLOBAL['localeInfo'];
+
+    var tableRowElement = document.createElement('tr');
+    tableRowElement.setAttribute("style","border-width: 0");
+
+    var bodyHtml = '';
+    bodyHtml += '<td style="border-width: 0" colspan="5">';
+    bodyHtml += '<select id="' + keyName + '-addLocaleValue">';
+
+    var localesAdded = 0;
+    for (var localeIter in availableLocales) {
+        if (localeIter != PWM_GLOBAL['defaultLocale']) {
+            if (!existingLocales || (existingLocales.indexOf(localeIter) == -1)) {
+                localesAdded++;
+                var labelText = availableLocales[localeIter] + " (" + localeIter + ")";
+                bodyHtml += '<option value="' + localeIter + '">' + labelText + '</option>';
+            }
+        }
+    }
+    bodyHtml += '</select>';
+
+    bodyHtml += '<button type="button" class="btn" id="' + keyName + '-addLocaleButton"><span class="btn-icon fa fa-plus-square"></span>Add Locale</button>'
+
+    bodyHtml += '</td>';
+    if (localesAdded == 0) {
+        bodyHtml = '<td style="border-width: 0" colspan="5"><span class="footnote">All locales present</span></td>';
+    }
+    tableRowElement.innerHTML = bodyHtml;
+    PWM_MAIN.getObject(parentDiv).appendChild(tableRowElement);
+
+    PWM_MAIN.addEventHandler(keyName + '-addLocaleButton','click',function(){
+        var value = PWM_MAIN.getObject(keyName + "-addLocaleValue").value;
+        addFunction(value);
+    });
+};

+ 1 - 31
pwm/servlet/web/public/resources/js/configeditor.js

@@ -224,7 +224,7 @@ PWM_CFGEDIT.addValueButtonRow = function(parentDiv, keyName, addFunction) {
     var addItemButton = document.createElement("button");
     addItemButton.setAttribute("type", "button");
     addItemButton.setAttribute("id", buttonId);
-    addItemButton.setAttribute("class", "btn")
+    addItemButton.setAttribute("class", "btn");
     addItemButton.onclick = addFunction;
     addItemButton.innerHTML = "Add Value";
     newTableData.appendChild(addItemButton);
@@ -234,36 +234,6 @@ PWM_CFGEDIT.addValueButtonRow = function(parentDiv, keyName, addFunction) {
     newTableRow.appendChild(newTableData);
 };
 
-PWM_CFGEDIT.addAddLocaleButtonRow = function(parentDiv, keyName, addFunction) {
-    var availableLocales = PWM_GLOBAL['localeInfo'];
-
-    var tableRowElement = document.createElement('tr');
-    tableRowElement.setAttribute("style","border-width: 0");
-
-    var bodyHtml = '';
-    bodyHtml += '<td style="border-width: 0" colspan="5">';
-    bodyHtml += '<select id="' + keyName + '-addLocaleValue">';
-    for (var localeIter in availableLocales) {
-        if (localeIter != PWM_GLOBAL['defaultLocale']) {
-            var labelText = availableLocales[localeIter] + " (" + localeIter + ")";
-            bodyHtml += '<option value="' + localeIter + '">' + labelText + '</option>';
-        }
-    }
-    bodyHtml += '</select>';
-
-    bodyHtml += '<button type="button" class="btn" id="' + keyName + '-addLocaleButton"><span class="btn-icon fa fa-plus-square"></span>Add Locale</button>'
-
-    bodyHtml += '</td>';
-    tableRowElement.innerHTML = bodyHtml;
-    PWM_MAIN.getObject(parentDiv).appendChild(tableRowElement);
-
-    PWM_MAIN.addEventHandler(keyName + '-addLocaleButton','click',function(){
-        var value = PWM_MAIN.getObject(keyName + "-addLocaleValue").value;
-        addFunction(value);
-    });
-
-};
-
 PWM_CFGEDIT.readInitialTextBasedValue = function(key) {
     require(["dijit/registry"],function(registry){
         PWM_CFGEDIT.readSetting(key, function(dataValue) {

+ 2 - 0
pwm/servlet/web/public/resources/style.css

@@ -790,6 +790,8 @@ dialog .titleBar {
 
 dialog .body {
     padding:5px;
+    max-height: 98vh;
+    overflow-x: auto;
 }
 
 dialog .closeIcon {