Browse Source

add cr_policy configguide page
add cr_policy config editor "change all" buttons

Jason Rivard 7 years ago
parent
commit
cd7d515a6a

+ 38 - 17
server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java

@@ -24,8 +24,10 @@ package password.pwm.http.servlet.configeditor;
 
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import password.pwm.AppProperty;
+import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmConstants;
+import password.pwm.bean.SessionLabel;
 import password.pwm.bean.SmsItemBean;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.Configuration;
@@ -895,10 +897,39 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             throws IOException, PwmUnrecoverableException
     {
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
-        final PwmSettingTemplateSet template = configManagerBean.getStoredConfiguration().getTemplateSet();
+        final LinkedHashMap<String, Object> returnMap = new LinkedHashMap<>( generateSettingData(
+                pwmRequest.getPwmApplication(),
+                configManagerBean.getStoredConfiguration(),
+                pwmRequest.getSessionLabel(),
+                pwmRequest.getLocale()
+                )
+        );
+
+        if ( pwmRequest.getPwmApplication().getApplicationMode() == PwmApplicationMode.CONFIGURATION && !PwmConstants.TRIAL_MODE )
+        {
+            if ( !configManagerBean.isConfigUnlockedWarningShown() )
+            {
+                returnMap.put( "configUnlocked", true );
+                configManagerBean.setConfigUnlockedWarningShown( true );
+            }
+        }
+
+        final RestResultBean restResultBean = RestResultBean.withData( new LinkedHashMap<>( returnMap ) );
+        pwmRequest.outputJsonResult( restResultBean );
+        return ProcessStatus.Halt;
+    }
+
+    public static Map<String, Object> generateSettingData(
+            final PwmApplication pwmApplication,
+            final StoredConfigurationImpl storedConfiguration,
+            final SessionLabel sessionLabel,
+            final Locale locale
+
+            ) throws PwmUnrecoverableException
+    {
         final LinkedHashMap<String, Object> returnMap = new LinkedHashMap<>();
-        final Locale locale = pwmRequest.getLocale();
-        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmRequest.getPwmApplication(), pwmRequest.getSessionLabel() );
+        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, sessionLabel );
+        final PwmSettingTemplateSet template = storedConfiguration.getTemplateSet();
 
         {
             final LinkedHashMap<String, Object> settingMap = new LinkedHashMap<>();
@@ -931,23 +962,13 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         }
         {
             final LinkedHashMap<String, Object> varMap = new LinkedHashMap<>();
-            varMap.put( "ldapProfileIds", configManagerBean.getStoredConfiguration().readSetting( PwmSetting.LDAP_PROFILE_LIST ).toNativeObject() );
-            varMap.put( "currentTemplate", configManagerBean.getStoredConfiguration().getTemplateSet() );
-            if ( pwmRequest.getPwmApplication().getApplicationMode() == PwmApplicationMode.CONFIGURATION && !PwmConstants.TRIAL_MODE )
-            {
-                if ( !configManagerBean.isConfigUnlockedWarningShown() )
-                {
-                    varMap.put( "configUnlocked", true );
-                    configManagerBean.setConfigUnlockedWarningShown( true );
-                }
-            }
-            varMap.put( "configurationNotes", configManagerBean.getStoredConfiguration().readConfigProperty( ConfigurationProperty.NOTES ) );
+            varMap.put( "ldapProfileIds", storedConfiguration.readSetting( PwmSetting.LDAP_PROFILE_LIST ).toNativeObject() );
+            varMap.put( "currentTemplate", storedConfiguration.getTemplateSet() );
+            varMap.put( "configurationNotes", storedConfiguration.readConfigProperty( ConfigurationProperty.NOTES ) );
             returnMap.put( "var", varMap );
         }
+        return Collections.unmodifiableMap( returnMap );
 
-        final RestResultBean restResultBean = RestResultBean.withData( returnMap );
-        pwmRequest.outputJsonResult( restResultBean );
-        return ProcessStatus.Halt;
     }
 
     @ActionHandler( action = "testMacro" )

+ 10 - 0
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideForm.java

@@ -27,6 +27,7 @@ import password.pwm.config.PwmSettingTemplate;
 import password.pwm.config.StoredValue;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.config.value.BooleanValue;
+import password.pwm.config.value.ChallengeValue;
 import password.pwm.config.value.FileValue;
 import password.pwm.config.value.PasswordValue;
 import password.pwm.config.value.StringArrayValue;
@@ -61,6 +62,7 @@ public class ConfigGuideForm
 
         defaultLdapForm.put( ConfigGuideFormField.PARAM_LDAP_PORT, "636" );
         defaultLdapForm.put( ConfigGuideFormField.PARAM_LDAP_SECURE, "true" );
+        defaultLdapForm.remove( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA );
 
         return Collections.unmodifiableMap( defaultLdapForm );
     }
@@ -205,6 +207,14 @@ public class ConfigGuideForm
             storedConfiguration.writeSetting( PwmSetting.PUBLISH_STATS_SITE_DESCRIPTION, null, new StringValue( siteDescription ), null );
         }
 
+        // cr policy
+        if ( formData.containsKey( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA ) )
+        {
+            final String stringValue = formData.get( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA );
+            final StoredValue challengeValue = ChallengeValue.factory().fromJson( stringValue );
+            storedConfiguration.writeSetting( PwmSetting.CHALLENGE_RANDOM_CHALLENGES, "default", challengeValue, null );
+        }
+
         // set site url
         storedConfiguration.writeSetting( PwmSetting.PWM_SITE_URL, new StringValue( formData.get( ConfigGuideFormField.PARAM_APP_SITEURL ) ), null );
 

+ 2 - 0
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideFormField.java

@@ -51,6 +51,8 @@ public enum ConfigGuideFormField
     PARAM_TELEMETRY_ENABLE( PwmSetting.PUBLISH_STATS_ENABLE ),
     PARAM_TELEMETRY_DESCRIPTION( PwmSetting.PUBLISH_STATS_SITE_DESCRIPTION ),
 
+    CHALLENGE_RESPONSE_DATA( null ),
+
     PARAM_CONFIG_PASSWORD( null ),;
 
     private final PwmSetting pwmSetting;

+ 97 - 1
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideServlet.java

@@ -31,11 +31,13 @@ import password.pwm.PwmConstants;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
+import password.pwm.config.StoredValue;
 import password.pwm.config.function.UserMatchViewerFunction;
 import password.pwm.config.profile.LdapProfile;
 import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.config.value.FileValue;
+import password.pwm.config.value.ValueFactory;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
@@ -57,6 +59,7 @@ import password.pwm.http.PwmURL;
 import password.pwm.http.bean.ConfigGuideBean;
 import password.pwm.http.servlet.AbstractPwmServlet;
 import password.pwm.http.servlet.ControlledPwmServlet;
+import password.pwm.http.servlet.configeditor.ConfigEditorServlet;
 import password.pwm.http.servlet.configeditor.ConfigEditorServletUtils;
 import password.pwm.i18n.Message;
 import password.pwm.ldap.LdapBrowser;
@@ -79,6 +82,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -108,7 +112,11 @@ public class ConfigGuideServlet extends ControlledPwmServlet
         viewAdminMatches( HttpMethod.POST ),
         browseLdap( HttpMethod.POST ),
         uploadJDBCDriver( HttpMethod.POST ),
-        skipGuide( HttpMethod.POST ),;
+        skipGuide( HttpMethod.POST ),
+        readSetting( HttpMethod.POST ),
+        writeSetting( HttpMethod.POST ),
+        settingData( HttpMethod.GET ),;
+
 
         private final HttpMethod method;
 
@@ -573,6 +581,94 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
         return ProcessStatus.Halt;
     }
+
+    @ActionHandler( action = "readSetting" )
+    private ProcessStatus restReadSetting( final PwmRequest pwmRequest ) throws PwmUnrecoverableException, IOException
+    {
+        final String profileID = "default";
+        final ConfigGuideBean configGuideBean = getBean( pwmRequest );
+        final StoredConfigurationImpl storedConfigurationImpl = ConfigGuideForm.generateStoredConfig( configGuideBean );
+
+        final String key = pwmRequest.readParameterAsString( "key" );
+        final LinkedHashMap<String, Object> returnMap = new LinkedHashMap<>();
+        final PwmSetting theSetting = PwmSetting.forKey( key );
+
+        final Object returnValue;
+        returnValue = storedConfigurationImpl.readSetting( theSetting, profileID ).toNativeObject();
+        returnMap.put( "isDefault", storedConfigurationImpl.isDefaultValue( theSetting, profileID ) );
+        returnMap.put( "key", key );
+        returnMap.put( "category", theSetting.getCategory().toString() );
+        returnMap.put( "syntax", theSetting.getSyntax().toString() );
+
+        returnMap.put( "value", returnValue );
+        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap ) );
+
+        return ProcessStatus.Halt;
+    }
+
+    @ActionHandler( action = "writeSetting" )
+    private ProcessStatus restWriteSetting( final PwmRequest pwmRequest )
+            throws PwmUnrecoverableException, IOException
+    {
+        final String profileID = "default";
+        final String key = pwmRequest.readParameterAsString( "key" );
+        final String bodyString = pwmRequest.readRequestBodyAsString();
+        final PwmSetting setting = PwmSetting.forKey( key );
+        final ConfigGuideBean configGuideBean = getBean( pwmRequest );
+        final StoredConfigurationImpl storedConfigurationImpl = ConfigGuideForm.generateStoredConfig( configGuideBean );
+
+
+        final LinkedHashMap<String, Object> returnMap = new LinkedHashMap<>();
+
+        try
+        {
+            final StoredValue storedValue = ValueFactory.fromJson( setting, bodyString );
+            final List<String> errorMsgs = storedValue.validateValue( setting );
+            if ( errorMsgs != null && !errorMsgs.isEmpty() )
+            {
+                returnMap.put( "errorMessage", setting.getLabel( pwmRequest.getLocale() ) + ": " + errorMsgs.get( 0 ) );
+            }
+
+            if ( setting == PwmSetting.CHALLENGE_RANDOM_CHALLENGES )
+            {
+                configGuideBean.getFormData().put( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA, JsonUtil.serialize( (Serializable) storedValue.toNativeObject() ) );
+            }
+        }
+        catch ( Exception e )
+        {
+            final String errorMsg = "error writing default value for setting " + setting.toString() + ", error: " + e.getMessage();
+            LOGGER.error( errorMsg, e );
+            throw new IllegalStateException( errorMsg, e );
+        }
+        returnMap.put( "key", key );
+        returnMap.put( "category", setting.getCategory().toString() );
+        returnMap.put( "syntax", setting.getSyntax().toString() );
+        returnMap.put( "isDefault", storedConfigurationImpl.isDefaultValue( setting, profileID ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap ) );
+
+
+        return ProcessStatus.Halt;
+    }
+
+    @ActionHandler( action = "settingData" )
+    private ProcessStatus restSettingData( final PwmRequest pwmRequest )
+            throws IOException, PwmUnrecoverableException
+    {
+        final ConfigGuideBean configGuideBean = getBean( pwmRequest );
+        final StoredConfigurationImpl storedConfigurationImpl = ConfigGuideForm.generateStoredConfig( configGuideBean );
+
+        final LinkedHashMap<String, Object> returnMap = new LinkedHashMap<>( ConfigEditorServlet.generateSettingData(
+                pwmRequest.getPwmApplication(),
+                storedConfigurationImpl,
+                pwmRequest.getSessionLabel(),
+                pwmRequest.getLocale()
+        )
+        );
+
+        final RestResultBean restResultBean = RestResultBean.withData( new LinkedHashMap<>( returnMap ) );
+        pwmRequest.outputJsonResult( restResultBean );
+        return ProcessStatus.Halt;
+    }
 }
 
 

+ 1 - 0
server/src/main/java/password/pwm/http/servlet/configguide/GuideStep.java

@@ -50,6 +50,7 @@ public enum GuideStep
     DATABASE( DbVisibilityCheck.class ),
     LDAP_PERMISSIONS( LdapSchemeVisibilityCheck.class ),
     LDAP_TESTUSER( null ),
+    CR_POLICY( null ),
     APP( null ),
     PASSWORD( null ),
     END( null ),

+ 2 - 0
server/src/main/resources/password/pwm/i18n/ConfigGuide.properties

@@ -41,3 +41,5 @@ password_title=Configuration Password
 password_title_verify=Verify Configuration Password
 template_description=<p>Begin your configuration by selecting the LDAP directory setting template.  You can change this setting later if you need to.</p><p>Setting this template will establish appropriate default values for many of the application settings.</p>
 title=@PwmAppName@ Configuration Guide
+cr_policy_title=Challenge/Response Questions
+cr_policy_description=<p>@PwmAppName@ includes a default list of challenge/response questions to use.  @PwmAppName@ does not require use of challenge/response questions, but if you do plan on using them you should review and update the questions so that they are appropriate for your organization and user community.  </p><p><b>It is good security practice to use unique security questions for each site. You should change the default questions whenever possible.</b></p><p>You can edit this list as well as set required questions and minimum number of questions in the configuration editor after completing the configuration guide.  The setting location is @PwmSettingReference\:challenge.randomChallenges@.</p>

+ 93 - 0
server/src/main/webapp/WEB-INF/jsp/configguide-cr_policy.jsp

@@ -0,0 +1,93 @@
+<%--
+ ~ Password Management Servlets (PWM)
+ ~ http://www.pwm-project.org
+ ~
+ ~ Copyright (c) 2006-2009 Novell, Inc.
+ ~ Copyright (c) 2009-2018 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
+--%>
+
+<%@ page import="password.pwm.config.value.FileValue" %>
+<%@ page import="password.pwm.http.servlet.configguide.ConfigGuideForm" %>
+<%@ page import="password.pwm.util.java.StringUtil" %>
+<%@ page import="java.util.Locale" %>
+<%@ page import="password.pwm.http.servlet.configguide.ConfigGuideFormField" %>
+
+<% JspUtility.setFlag(pageContext, PwmRequestFlag.HIDE_LOCALE); %>
+<% JspUtility.setFlag(pageContext, PwmRequestFlag.INCLUDE_CONFIG_CSS); %>
+<% final Locale userLocale = JspUtility.locale(request); %>
+<% final ConfigGuideBean configGuideBean = JspUtility.getSessionBean(pageContext, ConfigGuideBean.class);%>
+<!DOCTYPE html>
+<%@ page language="java" session="true" isThreadSafe="true" contentType="text/html" %>
+<%@ taglib uri="pwm" prefix="pwm" %>
+<html lang="<pwm:value name="<%=PwmValue.localeCode%>"/>" dir="<pwm:value name="<%=PwmValue.localeDir%>"/>">
+<%@ include file="fragment/header.jsp" %>
+<body class="nihilo">
+<div id="wrapper">
+    <%@ include file="fragment/configguide-header.jsp"%>
+    <div id="centerbody">
+        <form id="configForm">
+            <%@ include file="/WEB-INF/jsp/fragment/message.jsp" %>
+            <br class="clear"/>
+            <div id="outline_ldap-server" class="setting_outline">
+                <div class="setting_title">
+                    <pwm:display key="cr_policy_title" bundle="ConfigGuide"/>
+
+                </div>
+                <div class="setting_body">
+                    <div class="setting_item">
+                        <div id="titlePane_<%=ConfigGuideFormField.PARAM_DB_CLASSNAME%>" style="padding-left: 5px; padding-top: 5px">
+                            <pwm:display key="cr_policy_description" bundle="ConfigGuide"/>
+                            <br/>
+                            <div id="table_setting_<%=PwmSetting.CHALLENGE_RANDOM_CHALLENGES.getKey()%>">
+                            </div>
+
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+        </form>
+        <br/>
+        <%@ include file="fragment/configguide-buttonbar.jsp" %>
+    </div>
+    <div class="push"></div>
+</div>
+
+configeditor-settings-challenges.js
+<pwm:script>
+    <script type="text/javascript">
+        PWM_GLOBAL['startupFunctions'].push(function(){
+            PWM_MAIN.addEventHandler('button_next','click',function(){PWM_GUIDE.gotoStep('NEXT')});
+            PWM_MAIN.addEventHandler('button_previous','click',function(){PWM_GUIDE.gotoStep('PREVIOUS')});
+
+            initPage();
+        });
+
+        function initPage() {
+            PWM_CFGEDIT.initConfigSettingsDefinition(function(){
+                PWM_VAR['outstandingOperations'] = 0;
+                ChallengeSettingHandler.init('<%=PwmSetting.CHALLENGE_RANDOM_CHALLENGES.getKey()%>');
+            });
+        }
+    </script>
+</pwm:script>
+<pwm:script-ref url="/public/resources/js/configeditor.js"/>
+<pwm:script-ref url="/public/resources/js/configeditor-settings.js"/>
+<pwm:script-ref url="/public/resources/js/configeditor-settings-challenges.js"/>
+<%@ include file="fragment/footer.jsp" %>
+</body>
+</html>

+ 89 - 26
server/src/main/webapp/public/resources/js/configeditor-settings-challenges.js

@@ -31,7 +31,7 @@ ChallengeSettingHandler.init = function(settingKey) {
         PWM_VAR['clientSettingCache'][settingKey] = resultValue;
         if (PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
             var htmlBody = '<button class="btn" id="button-addValue-' + settingKey + '">';
-            htmlBody += '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Value';
+            htmlBody += '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Question';
             htmlBody += '</button>';
 
             var parentDivElement = PWM_MAIN.getObject(parentDiv);
@@ -55,7 +55,7 @@ ChallengeSettingHandler.draw = function(settingKey) {
     var parentDiv = "table_setting_" + settingKey;
     var resultValue = PWM_VAR['clientSettingCache'][settingKey];
     var parentDivElement = PWM_MAIN.getObject(parentDiv);
-    var bodyText = '<div class="footnote">Click on challenge questions to edit questions and policies</div>';
+    var bodyText = '<div class="footnote">Click on challenge questions to edit questions and policy settings.</div>';
     PWM_CFGEDIT.clearDivElements(parentDiv, false);
     for (var localeName in resultValue) {
         (function(localeKey) {
@@ -146,7 +146,6 @@ ChallengeSettingHandler.draw = function(settingKey) {
 
 ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
     var localeDisplay = localeKey === "" ? "Default" : localeKey;
-    var dialogBody = '<div id="challengeLocaleDialogDiv" style="max-height:500px; overflow-x: auto">';
 
     var localeName = localeKey;
 
@@ -154,8 +153,19 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
 
     var multiValues = resultValue[localeName];
 
+    var dialogBody = '';
+    dialogBody += '<div style="width:100%; text-align: center">'
+        + '<span>Toggle All: </span><button class="btn" id="button-toggleWordlist-' + keyName + '-' + localeKey + '">Apply Word List</button>'
+        + '<span>Change All: </span><button class="btn" id="button-changeAll-minLength-' + keyName + '-' + localeKey + '">Min Length</button>'
+        + '<button class="btn" id="button-changeAll-maxLength-' + keyName + '-' + localeKey + '">Max Length</button>'
+        + '<button class="btn" id="button-changeAll-maxQuestionCharsInAnswer-' + keyName + '-' + localeKey + '">Max Question Characters</button>'
+        + '</div>';
+    dialogBody += '<div id="challengeLocaleDialogDiv" style="max-height:500px; overflow-x: auto">';
+
     for (var iteration in multiValues) {
         (function(rowKey) {
+
+
             dialogBody += '<table class="noborder">';
             dialogBody += '<tr><td style="width: 15px" class="noborder">' + (parseInt(iteration) + 1) + '</td><td class="setting_outline">';
             dialogBody += '<table class="noborder" style="margin:0"><tr>';
@@ -171,7 +181,9 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
 
             dialogBody += '<tr><td>';
 
-            dialogBody += '<label class="checkboxWrapper"><input type="checkbox" id="value-adminDefined-' + inputID + '" disabled/>Admin Defined</label>';
+            dialogBody += '<select id="value-adminDefined-' + inputID + '" disabled>'
+                + '<option value="ADMIN">Admin Defined</option><option value="USER">User Defined</option>'
+                + '</select>';
 
             dialogBody += '</td><td>';
 
@@ -208,7 +220,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
     var dialogTitle = PWM_SETTINGS['settings'][keyName]['label'] + ' - ' + localeDisplay + ' Locale';
     PWM_MAIN.showDialog({
         title:dialogTitle,
-        buttonHtml:'<button class="btn" id="button-addValue"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Value</button>',
+        buttonHtml:'<button class="btn" id="button-addValue"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Question</button>',
         text:dialogBody,
         showClose:false,
         dialogClass:'wide',
@@ -216,18 +228,65 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
             PWM_MAIN.addEventHandler('button-addValue','click',function(){
                 ChallengeSettingHandler.addRow(keyName,localeKey);
             });
+
+            var switchAllValues = function(settingType, settingValue) {
+                for (var iteration in multiValues) {
+                    (function(rowKey) {
+                        multiValues[rowKey][settingType] = settingValue;
+                    }(iteration));
+                }
+            };
+
+            var switchAllNumericValue = function(settingType, defaultValue, min, max) {
+                var dialogText = '<div>New Value <input type="number" id="newValue" value="' + defaultValue + '" min="' + min + '" max="' + max + '"></input></div>';
+                PWM_VAR['tempValue'] = defaultValue;
+                var loadFunction = function(){
+                    PWM_MAIN.addEventHandler('newValue','change',function(){
+                        PWM_VAR['tempValue'] = PWM_MAIN.getObject('newValue').value;
+                    })
+                };
+                var okAction = function() {
+                    switchAllValues(settingType,PWM_VAR['tempValue']);
+                    delete 'tempValue' in PWM_VAR;
+                    ChallengeSettingHandler.editLocale(keyName, localeKey);
+                };
+                PWM_MAIN.showConfirmDialog({text:dialogText,loadFunction:loadFunction, okAction:okAction});
+            };
+
+            PWM_MAIN.addEventHandler('button-toggleWordlist-' + keyName + '-' + localeKey,'click',function(){
+                PWM_MAIN.showConfirmDialog({okAction:function(){
+                        var row0value = multiValues[0]['enforceWordlist'];
+                        switchAllValues('enforceWordlist',!row0value);
+                        ChallengeSettingHandler.editLocale(keyName, localeKey);
+                    }
+                });
+            });
+
+            PWM_MAIN.addEventHandler('button-changeAll-minLength-' + keyName + '-' + localeKey,'click',function(){
+                switchAllNumericValue('minLength',4,1,255);
+            });
+            PWM_MAIN.addEventHandler('button-changeAll-maxLength-' + keyName + '-' + localeKey,'click',function(){
+                switchAllNumericValue('maxLength',200,1,255);
+            });
+            PWM_MAIN.addEventHandler('button-changeAll-maxQuestionCharsInAnswer-' + keyName + '-' + localeKey,'click',function(){
+                switchAllNumericValue('maxQuestionCharsInAnswer',3,0,100);
+            });
+
+
+
+
             for (var iteration in multiValues) {
                 (function(rowKey) {
                     var inputID = "value-" + keyName + "-" + localeName + "-" + rowKey;
                     UILibrary.manageNumericInput('button-minLength-' + inputID, function(value){
                         PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['minLength'] = value;
-                    })
+                    });
                     UILibrary.manageNumericInput('button-maxLength-' + inputID, function(value){
                         PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['maxLength'] = value;
-                    })
+                    });
                     UILibrary.manageNumericInput('button-maxQuestionCharsInAnswer-' + inputID, function(value){
                         PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['maxQuestionCharsInAnswer'] = value;
-                    })
+                    });
 
                     // question text
                     var processQuestion = function() {
@@ -237,16 +296,17 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
                     };
                     processQuestion();
                     PWM_MAIN.addEventHandler(inputID, 'input', function () {
-                        //if (!multiValues[rowKey]['adminDefined']) {
-                        PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['text'] = PWM_MAIN.getObject(inputID).value;
-                        //}
+                        if (!multiValues[rowKey]['adminDefined']) {
+                            PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['text'] = PWM_MAIN.getObject(inputID).value;
+                        }
                     });
 
-                    // admin defined checkbox
+                    // admin defined select
                     PWM_MAIN.getObject('value-adminDefined-' + inputID).disabled = false;
-                    PWM_MAIN.getObject('value-adminDefined-' + inputID).checked = multiValues[rowKey]['adminDefined'];
+                    PWM_MAIN.JSLibrary.setValueOfSelectElement('value-adminDefined-' + inputID, multiValues[rowKey]['adminDefined'] ? 'ADMIN' : 'USER');
+
                     PWM_MAIN.addEventHandler('value-adminDefined-' + inputID,'change',function(){
-                        var checked = PWM_MAIN.getObject('value-adminDefined-' + inputID).checked;
+                        var checked = PWM_MAIN.JSLibrary.readValueOfSelectElement('value-adminDefined-' + inputID) === 'ADMIN';
                         multiValues[rowKey]['adminDefined'] = checked;
                         processQuestion();
                     });
@@ -280,12 +340,12 @@ ChallengeSettingHandler.deleteLocale = function(keyName,localeKey) {
         text: 'Are you sure you want to remove all the questions for the <i>' + localeKey + '</i> locale?',
         okAction:function(){
             PWM_MAIN.showWaitDialog({loadFunction:function(){
-                delete PWM_VAR['clientSettingCache'][keyName][localeKey];
-                PWM_CFGEDIT.writeSetting(keyName, PWM_VAR['clientSettingCache'][keyName],function(){
-                    PWM_MAIN.closeWaitDialog();
-                    ChallengeSettingHandler.init(keyName);
-                });
-            }});
+                    delete PWM_VAR['clientSettingCache'][keyName][localeKey];
+                    PWM_CFGEDIT.writeSetting(keyName, PWM_VAR['clientSettingCache'][keyName],function(){
+                        PWM_MAIN.closeWaitDialog();
+                        ChallengeSettingHandler.init(keyName);
+                    });
+                }});
         }
     });
 };
@@ -310,11 +370,11 @@ ChallengeSettingHandler.deleteRow = function(keyName, localeKey, rowName) {
     PWM_MAIN.showConfirmDialog({
         okAction:function(){
             PWM_MAIN.showWaitDialog({loadFunction:function(){
-                delete PWM_VAR['clientSettingCache'][keyName][localeKey][rowName];
-                ChallengeSettingHandler.write(keyName,function(){
-                    ChallengeSettingHandler.editLocale(keyName, localeKey);
-                });
-            }})
+                    delete PWM_VAR['clientSettingCache'][keyName][localeKey][rowName];
+                    ChallengeSettingHandler.write(keyName,function(){
+                        ChallengeSettingHandler.editLocale(keyName, localeKey);
+                    });
+                }})
         }
     });
 };
@@ -325,7 +385,10 @@ ChallengeSettingHandler.addRow = function(keyName, localeKey) {
             var newValues = PWM_MAIN.copyObject(ChallengeSettingHandler.defaultItem);
             PWM_VAR['clientSettingCache'][keyName][localeKey].push(newValues);
             ChallengeSettingHandler.write(keyName,function(){
-                ChallengeSettingHandler.editLocale(keyName, localeKey);
+                PWM_MAIN.showDialog({title:PWM_MAIN.showString('Title_Success'),text:'Added new item to end of existing question list.',okAction:function(){
+                        ChallengeSettingHandler.editLocale(keyName, localeKey);
+                    }}
+                );
             });
         }
     });

+ 135 - 125
server/src/main/webapp/public/resources/js/configeditor.js

@@ -37,7 +37,8 @@ PWM_CFGEDIT.readSetting = function(keyName, valueWriter) {
     var maxLevel = parseInt(PWM_CFGEDIT.readNavigationFilters()['level']);
     PWM_VAR['outstandingOperations']++;
     PWM_CFGEDIT.handleWorkingIcon();
-    var url = "editor?processAction=readSetting&key=" + keyName;
+    var url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction','readSetting');
+    url = PWM_MAIN.addParamToUrl(url, 'key', keyName);
     if (PWM_CFGEDIT.readCurrentProfile()) {
         url = PWM_MAIN.addParamToUrl(url, 'profile', PWM_CFGEDIT.readCurrentProfile());
     }
@@ -100,7 +101,8 @@ PWM_CFGEDIT.updateLastModifiedInfo = function(keyName, data) {
 PWM_CFGEDIT.writeSetting = function(keyName, valueData, nextAction) {
     PWM_VAR['outstandingOperations']++;
     PWM_CFGEDIT.handleWorkingIcon();
-    var url = "editor?processAction=writeSetting&key=" + keyName;
+    var url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction','writeSetting');
+    url = PWM_MAIN.addParamToUrl(url, 'key', keyName);
     if (PWM_CFGEDIT.readCurrentProfile()) {
         url = PWM_MAIN.addParamToUrl(url,'profile',PWM_CFGEDIT.readCurrentProfile());
     }
@@ -171,15 +173,23 @@ PWM_CFGEDIT.updateSettingDisplay = function(keyName, isDefault) {
         }
 
         if (!isDefault) {
-            resetImageButton.style.visibility = 'visible';
-            modifiedIcon.style.display = 'inline';
+            if (resetImageButton) {
+                resetImageButton.style.visibility = 'visible';
+            }
+            if (modifiedIcon) {
+                modifiedIcon.style.display = 'inline';
+            }
             try {
                 dojo.addClass('title_' + keyName,"modified");
                 dojo.addClass('titlePane_' + keyName,"modified");
             } catch (e) { /* noop */ }
         } else {
-            resetImageButton.style.visibility = 'hidden';
-            modifiedIcon.style.display = 'none';
+            if (resetImageButton) {
+                resetImageButton.style.visibility = 'hidden';
+            }
+            if (modifiedIcon) {
+                modifiedIcon.style.display = 'none';
+            }
             try {
                 dojo.removeClass('title_' + keyName,"modified");
                 dojo.removeClass('titlePane_' + keyName,"modified");
@@ -252,13 +262,13 @@ PWM_CFGEDIT.saveConfiguration = function() {
                 } else {
                     console.log('save completed');
                     PWM_MAIN.showWaitDialog({title:'Save complete, restarting application...',loadFunction:function(){
-                        PWM_CONFIG.waitForRestart({location:'/'});
-                    }});
+                            PWM_CONFIG.waitForRestart({location:'/'});
+                        }});
                 }
             };
             PWM_MAIN.showWaitDialog({title:'Saving...',loadFunction:function(){
-                PWM_MAIN.ajaxRequest(url,loadFunction);
-            }});
+                    PWM_MAIN.ajaxRequest(url,loadFunction);
+                }});
         };
         PWM_CFGEDIT.showChangeLog(confirmText,confirmFunction);
     });
@@ -282,8 +292,8 @@ PWM_CFGEDIT.setConfigurationPassword = function(password) {
         };
         PWM_MAIN.clearDijitWidget('dialogPopup');
         PWM_MAIN.showWaitDialog({loadFunction:function(){
-            PWM_MAIN.ajaxRequest(url,loadFunction,{errorFunction:errorFunction,content:{password:password}});
-        }});
+                PWM_MAIN.ajaxRequest(url,loadFunction,{errorFunction:errorFunction,content:{password:password}});
+            }});
         return;
     }
 
@@ -300,10 +310,10 @@ function handleResetClick(settingKey) {
     var titleText = 'Reset ' + label ? label : '';
 
     PWM_MAIN.showConfirmDialog({title:titleText,text:dialogText,okAction:function(){
-        PWM_CFGEDIT.resetSetting(settingKey,function(){
-            PWM_CFGEDIT.loadMainPageBody();
-        });
-    }});
+            PWM_CFGEDIT.resetSetting(settingKey,function(){
+                PWM_CFGEDIT.loadMainPageBody();
+            });
+        }});
 }
 
 PWM_CFGEDIT.initConfigEditor = function(nextFunction) {
@@ -347,8 +357,8 @@ PWM_CFGEDIT.executeSettingFunction = function (setting, name, resultHandler, ext
     resultHandler = resultHandler !== undefined ? resultHandler : function(data) {
         var msgBody = '<div style="max-height: 400px; overflow-y: auto">' + data['successMessage'] + '</div>';
         PWM_MAIN.showDialog({width:700,title: 'Results', text: msgBody, okAction: function () {
-            PWM_CFGEDIT.loadMainPageBody();
-        }});
+                PWM_CFGEDIT.loadMainPageBody();
+            }});
     };
 
     var requestUrl = "editor?processAction=executeSettingFunction";
@@ -357,15 +367,15 @@ PWM_CFGEDIT.executeSettingFunction = function (setting, name, resultHandler, ext
     }
 
     PWM_MAIN.showWaitDialog({loadFunction:function() {
-        var loadFunction = function(data) {
-            if (data['error']) {
-                PWM_MAIN.showErrorDialog(data);
-            } else {
-                resultHandler(data);
-            }
-        };
-        PWM_MAIN.ajaxRequest(requestUrl, loadFunction, {content:jsonSendData});
-    }});
+            var loadFunction = function(data) {
+                if (data['error']) {
+                    PWM_MAIN.showErrorDialog(data);
+                } else {
+                    resultHandler(data);
+                }
+            };
+            PWM_MAIN.ajaxRequest(requestUrl, loadFunction, {content:jsonSendData});
+        }});
 };
 
 PWM_CFGEDIT.showChangeLog=function(confirmText, confirmFunction) {
@@ -400,13 +410,13 @@ PWM_CFGEDIT.showChangeLog=function(confirmText, confirmFunction) {
                 }
             };
 
-                showChangeLogDialog()
+            showChangeLogDialog()
 
         }
     };
     PWM_MAIN.showWaitDialog({loadFunction: function () {
-        PWM_MAIN.ajaxRequest(url, loadFunction);
-    }});
+            PWM_MAIN.ajaxRequest(url, loadFunction);
+        }});
 };
 
 PWM_CFGEDIT.processSettingSearch = function(destinationDiv) {
@@ -595,33 +605,33 @@ PWM_CFGEDIT.setBreadcrumbText = function(text) {
 PWM_CFGEDIT.cancelEditing = function() {
     var url =  "editor?processAction=readChangeLog";
     PWM_MAIN.showWaitDialog({loadFunction:function(){
-        var loadFunction = function(data) {
-            if (data['error']) {
-                PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
-            } else {
-                if (data['data']['modified'] === true) {
-                    var bodyText = '<div class="changeLogViewBox">';
-                    bodyText += data['data']['html'];
-                    bodyText += '</div><br/><div>';
-                    bodyText += PWM_CONFIG.showString('MenuDisplay_CancelConfig');
-                    bodyText += '</div>';
-                    PWM_MAIN.closeWaitDialog();
-                    PWM_MAIN.showConfirmDialog({dialogClass:'wide',showClose:true,allowMove:true,text:bodyText,okAction:
-                        function () {
-                            PWM_MAIN.showWaitDialog({loadFunction: function () {
-                                PWM_MAIN.ajaxRequest('editor?processAction=cancelEditing',function(){
-                                    PWM_MAIN.goto('manager', {addFormID: true});
-                                });
-                            }});
-                        }
-                    });
+            var loadFunction = function(data) {
+                if (data['error']) {
+                    PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
                 } else {
-                    PWM_MAIN.goto('manager', {addFormID: true});
+                    if (data['data']['modified'] === true) {
+                        var bodyText = '<div class="changeLogViewBox">';
+                        bodyText += data['data']['html'];
+                        bodyText += '</div><br/><div>';
+                        bodyText += PWM_CONFIG.showString('MenuDisplay_CancelConfig');
+                        bodyText += '</div>';
+                        PWM_MAIN.closeWaitDialog();
+                        PWM_MAIN.showConfirmDialog({dialogClass:'wide',showClose:true,allowMove:true,text:bodyText,okAction:
+                                function () {
+                                    PWM_MAIN.showWaitDialog({loadFunction: function () {
+                                            PWM_MAIN.ajaxRequest('editor?processAction=cancelEditing',function(){
+                                                PWM_MAIN.goto('manager', {addFormID: true});
+                                            });
+                                        }});
+                                }
+                        });
+                    } else {
+                        PWM_MAIN.goto('manager', {addFormID: true});
+                    }
                 }
-            }
-        };
-        PWM_MAIN.ajaxRequest(url, loadFunction);
-    }});
+            };
+            PWM_MAIN.ajaxRequest(url, loadFunction);
+        }});
 };
 
 PWM_CFGEDIT.showMacroHelp = function() {
@@ -694,55 +704,55 @@ PWM_CFGEDIT.showDateTimeFormatHelp = function() {
 
 PWM_CFGEDIT.ldapHealthCheck = function() {
     PWM_MAIN.showWaitDialog({loadFunction:function() {
-        var url = "editor?processAction=ldapHealthCheck";
-        url = PWM_MAIN.addParamToUrl(url,'profile',PWM_CFGEDIT.readCurrentProfile());
-        var loadFunction = function(data) {
-            PWM_MAIN.closeWaitDialog();
-            if (data['error']) {
-                PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
-            } else {
-                var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
-                var profileName = PWM_CFGEDIT.readCurrentProfile();
-                var titleText = PWM_MAIN.showString('Field_LdapProfile') + ": " + profileName;
-                PWM_MAIN.showDialog({text:bodyText,title:titleText});
-            }
-        };
-        PWM_MAIN.ajaxRequest(url,loadFunction);
-    }});
+            var url = "editor?processAction=ldapHealthCheck";
+            url = PWM_MAIN.addParamToUrl(url,'profile',PWM_CFGEDIT.readCurrentProfile());
+            var loadFunction = function(data) {
+                PWM_MAIN.closeWaitDialog();
+                if (data['error']) {
+                    PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
+                } else {
+                    var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
+                    var profileName = PWM_CFGEDIT.readCurrentProfile();
+                    var titleText = PWM_MAIN.showString('Field_LdapProfile') + ": " + profileName;
+                    PWM_MAIN.showDialog({text:bodyText,title:titleText});
+                }
+            };
+            PWM_MAIN.ajaxRequest(url,loadFunction);
+        }});
 };
 
 PWM_CFGEDIT.databaseHealthCheck = function() {
     PWM_MAIN.showWaitDialog({title:'Checking database connection...',loadFunction:function(){
-        var url =  "editor?processAction=databaseHealthCheck";
-        var loadFunction = function(data) {
-            PWM_MAIN.closeWaitDialog();
-            if (data['error']) {
-                PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
-            } else {
-                var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
-                var titleText = 'Database Connection Status';
-                PWM_MAIN.showDialog({text:bodyText,title:titleText});
-            }
-        };
-        PWM_MAIN.ajaxRequest(url,loadFunction);
-    }});
+            var url =  "editor?processAction=databaseHealthCheck";
+            var loadFunction = function(data) {
+                PWM_MAIN.closeWaitDialog();
+                if (data['error']) {
+                    PWM_MAIN.showDialog({title: PWM_MAIN.showString("Title_Error"), text: data['errorMessage']});
+                } else {
+                    var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
+                    var titleText = 'Database Connection Status';
+                    PWM_MAIN.showDialog({text:bodyText,title:titleText});
+                }
+            };
+            PWM_MAIN.ajaxRequest(url,loadFunction);
+        }});
 };
 
 PWM_CFGEDIT.httpsCertificateView = function() {
     PWM_MAIN.showWaitDialog({title:'Parsing...',loadFunction:function(){
-        var url =  "editor?processAction=httpsCertificateView";
-        var loadFunction = function(data) {
-            PWM_MAIN.closeWaitDialog();
-            if (data['error']) {
-                PWM_MAIN.showErrorDialog(data);
-            } else {
-                var bodyText = '<pre>' + data['data'] + '</pre>';
-                var titleText = 'HTTPS Certificate';
-                PWM_MAIN.showDialog({text:bodyText,title:titleText});
-            }
-        };
-        PWM_MAIN.ajaxRequest(url,loadFunction);
-    }});
+            var url =  "editor?processAction=httpsCertificateView";
+            var loadFunction = function(data) {
+                PWM_MAIN.closeWaitDialog();
+                if (data['error']) {
+                    PWM_MAIN.showErrorDialog(data);
+                } else {
+                    var bodyText = '<pre>' + data['data'] + '</pre>';
+                    var titleText = 'HTTPS Certificate';
+                    PWM_MAIN.showDialog({text:bodyText,title:titleText});
+                }
+            };
+            PWM_MAIN.ajaxRequest(url,loadFunction);
+        }});
 };
 
 PWM_CFGEDIT.smsHealthCheck = function() {
@@ -752,23 +762,23 @@ PWM_CFGEDIT.smsHealthCheck = function() {
         dialogBody += '<tr><td>Message</td><td><input name="message" type="text" value="Test Message"/></td></tr>';
         dialogBody += '</table></form>';
         PWM_MAIN.showDialog({text:dialogBody,showCancel:true,title:'Test SMS connection',closeOnOk:false,okAction:function(){
-            var formElement = PWM_MAIN.getObject("smsCheckParametersForm");
-            var formData = domForm.toObject(formElement);
-            var url =  "editor?processAction=smsHealthCheck";
-            PWM_MAIN.showWaitDialog({loadFunction:function(){
-                var loadFunction = function(data) {
-                    if (data['error']) {
-                        PWM_MAIN.showErrorDialog(data);
-                    } else {
-                        var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
-                        var titleText = 'SMS Send Message Status';
-                        PWM_MAIN.showDialog({text:bodyText,title:titleText,showCancel:true});
-                    }
-
-                };
-                PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});
+                var formElement = PWM_MAIN.getObject("smsCheckParametersForm");
+                var formData = domForm.toObject(formElement);
+                var url =  "editor?processAction=smsHealthCheck";
+                PWM_MAIN.showWaitDialog({loadFunction:function(){
+                        var loadFunction = function(data) {
+                            if (data['error']) {
+                                PWM_MAIN.showErrorDialog(data);
+                            } else {
+                                var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
+                                var titleText = 'SMS Send Message Status';
+                                PWM_MAIN.showDialog({text:bodyText,title:titleText,showCancel:true});
+                            }
+
+                        };
+                        PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});
+                    }});
             }});
-        }});
     });
 };
 
@@ -777,9 +787,9 @@ PWM_CFGEDIT.selectTemplate = function(newTemplate) {
         text: PWM_CONFIG.showString('Warning_ChangeTemplate'),
         okAction: function () {
             PWM_MAIN.showWaitDialog({loadFunction: function () {
-                var url = "editor?processAction=setOption&template=" + newTemplate;
-                PWM_MAIN.ajaxRequest(url, function(){ PWM_MAIN.goto('editor'); });
-            }});
+                    var url = "editor?processAction=setOption&template=" + newTemplate;
+                    PWM_MAIN.ajaxRequest(url, function(){ PWM_MAIN.goto('editor'); });
+                }});
         }
     });
 };
@@ -1184,7 +1194,7 @@ PWM_CFGEDIT.drawDisplayTextPage = function(settingKey, keys) {
 
 
 PWM_CFGEDIT.initConfigSettingsDefinition=function(nextFunction) {
-    var clientConfigUrl = PWM_GLOBAL['url-context'] + "/private/config/editor?processAction=settingData";
+    var clientConfigUrl = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction','settingData');
     var loadFunction = function(data) {
         if (data['error'] === true) {
             console.error('unable to load ' + clientConfigUrl + ', error: ' + data['errorDetail'])
@@ -1256,15 +1266,15 @@ PWM_CFGEDIT.showSettingFilter = function() {
     };
 
     PWM_MAIN.showDialog({title:'Setting Filters',text:dialogBody,loadFunction:function(){
-        //PWM_MAIN.getObject('input-settingFilterText').value = currentValues['text'];
-        PWM_MAIN.addEventHandler('form-settingFilter','change',function(){
-            updateVars();
-        });
-        updateSettingLevelDescription();
-    },okAction:function(){
-        updateIcon();
-        PWM_CFGEDIT.loadMainPageBody();
-    }});
+            //PWM_MAIN.getObject('input-settingFilterText').value = currentValues['text'];
+            PWM_MAIN.addEventHandler('form-settingFilter','change',function(){
+                updateVars();
+            });
+            updateSettingLevelDescription();
+        },okAction:function(){
+            updateIcon();
+            PWM_CFGEDIT.loadMainPageBody();
+        }});
 };