Преглед изворни кода

Merge branch 'master' into enh-domainadmin

Jason Rivard пре 3 година
родитељ
комит
06a0313a30
49 измењених фајлова са 1553 додато и 1221 уклоњено
  1. BIN
      .mvn/wrapper/maven-wrapper.jar
  2. 17 1
      .mvn/wrapper/maven-wrapper.properties
  3. 1 1
      data-service/pom.xml
  4. 1 1
      docker/pom.xml
  5. 12 6
      mvnw
  6. 18 12
      mvnw.cmd
  7. 1 1
      onejar/pom.xml
  8. 6 13
      pom.xml
  9. 3 0
      server/src/main/java/password/pwm/PwmConstants.java
  10. 25 16
      server/src/main/java/password/pwm/config/DomainConfig.java
  11. 22 3
      server/src/main/java/password/pwm/config/PwmSettingTemplate.java
  12. 1 1
      server/src/main/java/password/pwm/config/stored/StoredConfigurationModifier.java
  13. 1 1
      server/src/main/java/password/pwm/config/stored/StoredConfigurationUtil.java
  14. 10 7
      server/src/main/java/password/pwm/config/value/AbstractValue.java
  15. 27 28
      server/src/main/java/password/pwm/config/value/ActionValue.java
  16. 4 3
      server/src/main/java/password/pwm/config/value/PrivateKeyValue.java
  17. 8 28
      server/src/main/java/password/pwm/config/value/X509CertificateValue.java
  18. 15 5
      server/src/main/java/password/pwm/error/PwmInternalException.java
  19. 1 9
      server/src/main/java/password/pwm/http/servlet/AbstractPwmServlet.java
  20. 2 1
      server/src/main/java/password/pwm/http/servlet/configeditor/function/ActionCertViewerFunction.java
  21. 2 1
      server/src/main/java/password/pwm/http/servlet/configeditor/function/RemoteWebServiceCertViewerFunction.java
  22. 2 1
      server/src/main/java/password/pwm/http/servlet/configeditor/function/X509CertViewerFunction.java
  23. 2 11
      server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerCertificatesServlet.java
  24. 3 13
      server/src/main/java/password/pwm/svc/wordlist/WordlistConfiguration.java
  25. 2 1
      server/src/main/java/password/pwm/util/cli/commands/LdapSchemaExtendCommand.java
  26. 1 1
      server/src/main/java/password/pwm/util/secure/CertificateReadingTrustManager.java
  27. 1 1
      server/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java
  28. 21 0
      server/src/main/java/password/pwm/util/secure/PwmHashAlgorithm.java
  29. 15 30
      server/src/main/java/password/pwm/util/secure/SecureEngine.java
  30. 96 0
      server/src/main/java/password/pwm/util/secure/X509CertDataParser.java
  31. 111 0
      server/src/main/java/password/pwm/util/secure/X509CertInfo.java
  32. 37 115
      server/src/main/java/password/pwm/util/secure/X509Utils.java
  33. 10 1
      server/src/main/resources/password/pwm/config/PwmSetting.xml
  34. 65 0
      server/src/test/java/password/pwm/config/PwmSettingTemplateTest.java
  35. 102 0
      server/src/test/java/password/pwm/http/ServletTest.java
  36. 2 1
      server/src/test/java/password/pwm/http/servlet/ControlledPwmServletTest.java
  37. 2 1
      server/src/test/java/password/pwm/ws/server/rest/RestServletTest.java
  38. 3 3
      webapp/pom.xml
  39. 79 78
      webapp/src/main/webapp/public/resources/js/configeditor-settings-action.js
  40. 49 65
      webapp/src/main/webapp/public/resources/js/configeditor-settings-challenges.js
  41. 48 47
      webapp/src/main/webapp/public/resources/js/configeditor-settings-customlink.js
  42. 21 21
      webapp/src/main/webapp/public/resources/js/configeditor-settings-email.js
  43. 83 82
      webapp/src/main/webapp/public/resources/js/configeditor-settings-form.js
  44. 32 32
      webapp/src/main/webapp/public/resources/js/configeditor-settings-permissions.js
  45. 65 42
      webapp/src/main/webapp/public/resources/js/configeditor-settings-remotewebservices.js
  46. 49 48
      webapp/src/main/webapp/public/resources/js/configeditor-settings-stringarray.js
  47. 281 292
      webapp/src/main/webapp/public/resources/js/configeditor-settings.js
  48. 185 197
      webapp/src/main/webapp/public/resources/js/configeditor.js
  49. 9 0
      webapp/src/main/webapp/public/resources/js/main.js

BIN
.mvn/wrapper/maven-wrapper.jar


+ 17 - 1
.mvn/wrapper/maven-wrapper.properties

@@ -1,2 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
 distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
-wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

+ 1 - 1
data-service/pom.xml

@@ -99,7 +99,7 @@
             <plugin>
                 <groupId>com.google.cloud.tools</groupId>
                 <artifactId>jib-maven-plugin</artifactId>
-                <version>3.2.0</version>
+                <version>3.2.1</version>
                 <executions>
                     <execution>
                         <id>make-docker-image</id>

+ 1 - 1
docker/pom.xml

@@ -34,7 +34,7 @@
             <plugin>
                 <groupId>com.google.cloud.tools</groupId>
                 <artifactId>jib-maven-plugin</artifactId>
-                <version>3.2.0</version>
+                <version>3.2.1</version>
                 <executions>
                     <execution>
                         <id>make-docker-image</id>

+ 12 - 6
mvnw

@@ -36,6 +36,10 @@
 
 if [ -z "$MAVEN_SKIP_RC" ] ; then
 
+  if [ -f /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
   if [ -f /etc/mavenrc ] ; then
     . /etc/mavenrc
   fi
@@ -145,7 +149,7 @@ if [ -z "$JAVACMD" ] ; then
       JAVACMD="$JAVA_HOME/bin/java"
     fi
   else
-    JAVACMD="`which java`"
+    JAVACMD="`\\unset -f command; \\command -v java`"
   fi
 fi
 
@@ -212,9 +216,9 @@ else
       echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
     fi
     if [ -n "$MVNW_REPOURL" ]; then
-      jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+      jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
     else
-      jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+      jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
     fi
     while IFS="=" read key value; do
       case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
@@ -233,9 +237,9 @@ else
           echo "Found wget ... using wget"
         fi
         if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
-            wget "$jarUrl" -O "$wrapperJarPath"
+            wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
         else
-            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
         fi
     elif command -v curl > /dev/null; then
         if [ "$MVNW_VERBOSE" = true ]; then
@@ -305,6 +309,8 @@ WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
 
 exec "$JAVACMD" \
   $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
   -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
-  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  "-Dmaven.home=${M2_HOME}" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
   ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 18 - 12
mvnw.cmd

@@ -46,8 +46,8 @@ if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
 @REM Execute a user defined script before this one
 if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
 @REM check for pre script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
-if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
 :skipRcPre
 
 @setlocal
@@ -120,9 +120,9 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
 set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
 set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
 
-set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
 
-FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
     IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
 )
 
@@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% (
     )
 ) else (
     if not "%MVNW_REPOURL%" == "" (
-        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
     )
     if "%MVNW_VERBOSE%" == "true" (
         echo Couldn't find %WRAPPER_JAR%, downloading it ...
@@ -158,7 +158,13 @@ if exist %WRAPPER_JAR% (
 @REM work with both Windows and non-Windows executions.
 set MAVEN_CMD_LINE_ARGS=%*
 
-%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+%MAVEN_JAVA_EXE% ^
+  %JVM_CONFIG_MAVEN_PROPS% ^
+  %MAVEN_OPTS% ^
+  %MAVEN_DEBUG_OPTS% ^
+  -classpath %WRAPPER_JAR% ^
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
 if ERRORLEVEL 1 goto error
 goto end
 
@@ -168,15 +174,15 @@ set ERROR_CODE=1
 :end
 @endlocal & set ERROR_CODE=%ERROR_CODE%
 
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
 @REM check for post script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
-if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
 :skipRcPost
 
 @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
-if "%MAVEN_BATCH_PAUSE%" == "on" pause
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
 
-if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
 
-exit /B %ERROR_CODE%
+cmd /C exit /B %ERROR_CODE%

+ 1 - 1
onejar/pom.xml

@@ -16,7 +16,7 @@
     <name>PWM Password Self Service: Executable Server JAR</name>
 
     <properties>
-        <tomcat.version>9.0.59</tomcat.version>
+        <tomcat.version>9.0.62</tomcat.version>
     </properties>
 
     <build>

+ 6 - 13
pom.xml

@@ -29,7 +29,7 @@
         <build.revision>0</build.revision>  <!-- default in case not set on command line -->
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
-        <pwm.minimum.maven.version>3.5</pwm.minimum.maven.version>
+        <pwm.minimum.maven.version>3.6</pwm.minimum.maven.version>
         <timestamp.iso>${maven.build.timestamp}</timestamp.iso>
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
@@ -333,7 +333,7 @@
             <plugin>
                 <groupId>com.github.spotbugs</groupId>
                 <artifactId>spotbugs-maven-plugin</artifactId>
-                <version>4.5.3.0</version>
+                <version>4.6.0.0</version>
                 <dependencies>
                     <dependency>
                         <groupId>com.github.spotbugs</groupId>
@@ -360,7 +360,7 @@
                 </configuration>
                 <executions>
                     <execution>
-                        <phase>test</phase>
+                        <phase>verify</phase>
                         <goals>
                             <goal>check</goal>
                         </goals>
@@ -396,7 +396,7 @@
             <plugin>
                 <groupId>org.owasp</groupId>
                 <artifactId>dependency-check-maven</artifactId>
-                <version>7.0.0</version>
+                <version>7.0.4</version>
                 <executions>
                     <execution>
                         <goals>
@@ -476,15 +476,8 @@
         </dependency>
         <dependency>
             <groupId>com.github.tomakehurst</groupId>
-            <artifactId>wiremock</artifactId>
-            <version>2.27.2</version>
-            <scope>test</scope>
-        </dependency>
-	<!-- older version of jackson databind required by wiremock 2.27.2 -->
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-            <version>2.11.3</version>
+            <artifactId>wiremock-jre8</artifactId>
+            <version>2.32.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>

+ 3 - 0
server/src/main/java/password/pwm/PwmConstants.java

@@ -88,6 +88,9 @@ public abstract class PwmConstants
 
     public static final int XML_OUTPUT_LINE_WRAP_LENGTH = 120;
 
+    public static final Package PWM_BASE_PACKAGE = ClassLoader.getSystemClassLoader()
+            .getDefinedPackage( "password.pwm" );
+
     public static final String LDAP_AD_PASSWORD_POLICY_CONTROL_ASN = "1.2.840.113556.1.4.2066";
     public static final String PROFILE_ID_ALL = "all";
     public static final String PROFILE_ID_DEFAULT = "default";

+ 25 - 16
server/src/main/java/password/pwm/config/DomainConfig.java

@@ -21,6 +21,7 @@
 package password.pwm.config;
 
 import password.pwm.AppProperty;
+import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.bean.PrivateKeyCertificate;
@@ -43,6 +44,7 @@ import password.pwm.config.profile.UpdateProfileProfile;
 import password.pwm.config.stored.StoredConfiguration;
 import password.pwm.config.stored.StoredConfigurationUtil;
 import password.pwm.config.value.FileValue;
+import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.config.value.data.NamedSecretData;
@@ -57,9 +59,8 @@ import password.pwm.util.java.JavaHelper;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.PwmSecurityKey;
-import password.pwm.util.secure.SecureEngine;
 
-import java.io.StringWriter;
+import java.security.MessageDigest;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -114,7 +115,7 @@ public class DomainConfig implements SettingReader
                 ) ) );
 
         this.ldapProfiles = makeLdapProfileMap( this );
-        this.domainSecurityKey = makeDomainSecurityKey( this );
+        this.domainSecurityKey = makeDomainSecurityKey( appConfig, domainID );
     }
 
     public AppConfig getAppConfig()
@@ -412,23 +413,16 @@ public class DomainConfig implements SettingReader
                         Map.Entry::getValue ) ) );
     }
 
-    private static PwmSecurityKey makeDomainSecurityKey( final DomainConfig domainConfig )
-            throws PwmInternalException
+    private static PwmSecurityKey makeDomainSecurityKey(
+            final AppConfig appConfig,
+            final DomainID domainID
+    )
     {
         try
         {
-            final StringWriter keyData = new StringWriter();
-            keyData.append( domainConfig.getDomainID().stringValue() );
-            CollectionUtil.iteratorToStream( domainConfig.getStoredConfiguration().keys() )
-                    .filter( key -> Objects.equals( key.getDomainID(), domainConfig.getDomainID() ) )
-                    .sorted()
-                    .map( s -> domainConfig.getStoredConfiguration().readStoredValue( s ) )
-                    .flatMap( Optional::stream )
-                    .forEach( value -> keyData.append( value.valueHash() ) );
-
-            final String hashedData = SecureEngine.hash( keyData.toString(), PwmHashAlgorithm.SHA512 );
+            final String hashedData = valueHash( appConfig.getStoredConfiguration(), domainID );
             final PwmSecurityKey domainKey = new PwmSecurityKey( hashedData );
-            return domainConfig.getAppConfig().getSecurityKey().add( domainKey );
+            return appConfig.getSecurityKey().add( domainKey );
         }
         catch ( final PwmUnrecoverableException e )
         {
@@ -436,4 +430,19 @@ public class DomainConfig implements SettingReader
         }
     }
 
+
+    private static String valueHash( final StoredConfiguration storedConfiguration, final DomainID domainID )
+    {
+        final MessageDigest messageDigest = PwmHashAlgorithm.SHA512.newMessageDigest();
+        messageDigest.update( domainID.stringValue().getBytes( PwmConstants.DEFAULT_CHARSET ) );
+
+        CollectionUtil.iteratorToStream( storedConfiguration.keys() )
+                .filter( key -> Objects.equals( key.getDomainID(), domainID ) )
+                .map( storedConfiguration::readStoredValue )
+                .flatMap( Optional::stream )
+                .map( StoredValue::valueHash )
+                .forEach( s -> messageDigest.update( s.getBytes( PwmConstants.DEFAULT_CHARSET ) ) );
+
+        return JavaHelper.binaryArrayToHex( messageDigest.digest() );
+    }
 }

+ 22 - 3
server/src/main/java/password/pwm/config/PwmSettingTemplate.java

@@ -26,6 +26,7 @@ import password.pwm.util.java.JavaHelper;
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 
 public enum PwmSettingTemplate
 {
@@ -34,6 +35,7 @@ public enum PwmSettingTemplate
     ORACLE_DS( Type.LDAP_VENDOR ),
     DEFAULT( Type.LDAP_VENDOR ),
     NOVL_IDM( Type.LDAP_VENDOR ),
+    DIRECTORY_SERVER_389( Type.LDAP_VENDOR ),
     OPEN_LDAP( Type.LDAP_VENDOR ),
 
     LOCALDB( Type.STORAGE ),
@@ -78,11 +80,28 @@ public enum PwmSettingTemplate
         return element;
     }
 
+    public static Set<PwmSettingTemplate> valuesForType( final Type type )
+    {
+        return JavaHelper.readEnumsFromPredicate( PwmSettingTemplate.class, t -> t.getType() == type );
+    }
+
     public enum Type
     {
-        LDAP_VENDOR,
-        STORAGE,
-        DB_VENDOR,;
+        LDAP_VENDOR( PwmSetting.TEMPLATE_LDAP ),
+        STORAGE( PwmSetting.TEMPLATE_STORAGE ),
+        DB_VENDOR( PwmSetting.DB_VENDOR_TEMPLATE ),;
+
+        private final PwmSetting pwmSetting;
+
+        Type( final PwmSetting pwmSetting )
+        {
+            this.pwmSetting = pwmSetting;
+        }
+
+        public PwmSetting getPwmSetting()
+        {
+            return pwmSetting;
+        }
 
         // done using map instead of static values to avoid initialization circularity bug
         public PwmSettingTemplate getDefaultValue( )

+ 1 - 1
server/src/main/java/password/pwm/config/stored/StoredConfigurationModifier.java

@@ -187,7 +187,7 @@ public class StoredConfigurationModifier
         } );
     }
 
-    public int modifications()
+    public int modificationCount()
     {
         return modifications.get();
     }

+ 1 - 1
server/src/main/java/password/pwm/config/stored/StoredConfigurationUtil.java

@@ -495,7 +495,7 @@ public abstract class StoredConfigurationUtil
             modifier.writeSetting( key, value, userIdentity );
         }
 
-        LOGGER.trace( () -> "copied " + modifier.modifications() + " domain settings from '" + source + "' to '" + destination + "' domain",
+        LOGGER.trace( () -> "copied " + modifier.modificationCount() + " domain settings from '" + source + "' to '" + destination + "' domain",
                 () -> TimeDuration.fromCurrent( startTime ) );
 
         return modifier.newStoredConfiguration();

+ 10 - 7
server/src/main/java/password/pwm/config/value/AbstractValue.java

@@ -28,17 +28,18 @@ import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.ImmutableByteArray;
+import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.json.JsonProvider;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.PwmSecurityKey;
-import password.pwm.util.secure.SecureEngine;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.Serializable;
+import java.security.DigestOutputStream;
 import java.util.List;
 import java.util.Locale;
 
@@ -121,15 +122,17 @@ public abstract class AbstractValue implements StoredValue
             final List<XmlElement> xmlValues = storedValue.toXmlValues( StoredConfigXmlConstants.XML_ELEMENT_VALUE, xmlOutputProcessData );
             final XmlDocument document = XmlChai.getFactory().newDocument( "root" );
             document.getRootElement().attachElement( xmlValues );
-            final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-            XmlChai.getFactory().output( document, byteArrayOutputStream );
-            final byte[] bytesToHash = byteArrayOutputStream.toByteArray();
-            return SecureEngine.hash( bytesToHash, PwmHashAlgorithm.SHA512 );
 
+            final DigestOutputStream digestOutputStream = new DigestOutputStream(
+                    OutputStream.nullOutputStream(),
+                    PwmHashAlgorithm.SHA512.newMessageDigest() );
+            XmlChai.getFactory().output( document, digestOutputStream );
+            return JavaHelper.binaryArrayToHex( digestOutputStream.getMessageDigest().digest() );
         }
-        catch ( final IOException | PwmUnrecoverableException e )
+        catch ( final IOException e )
         {
             throw new IllegalStateException( e );
         }
     }
+
 }

+ 27 - 28
server/src/main/java/password/pwm/config/value/ActionValue.java

@@ -28,6 +28,7 @@ import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.ActionConfiguration;
+import password.pwm.error.PwmInternalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.MiscUtil;
@@ -35,6 +36,7 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.X509Utils;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -157,30 +159,28 @@ public class ActionValue extends AbstractValue implements StoredValue
                         : webAction.getSuccessStatus();
 
                 // decrypt pw
+                Optional<String> decodedValue = Optional.empty();
                 try
                 {
-                    final Optional<String> decodedValue = StoredValueEncoder.decode(
+                    decodedValue = StoredValueEncoder.decode(
                             webAction.getPassword(),
                             StoredValueEncoder.Mode.ENCODED,
                             pwmSecurityKey );
-                    decodedValue.ifPresent( s ->
-                    {
-                        clonedWebActions.add( webAction.toBuilder()
-                                .password( s )
-                                .successStatus( successStatus )
-                                .build() );
-                    } );
                 }
                 catch ( final PwmOperationalException e )
                 {
                     LOGGER.warn( () -> "error decoding stored pw value on setting '" + pwmSetting.getKey() + "': " + e.getMessage() );
                 }
+
+                final String passwordValue = decodedValue.orElse( "" );
+                clonedWebActions.add( webAction.toBuilder()
+                        .password( passwordValue )
+                        .successStatus( successStatus )
+                        .build() );
             }
 
             return Optional.of( value.toBuilder().webActions( clonedWebActions ).build() );
         }
-
-
     }
 
     @Override
@@ -209,31 +209,26 @@ public class ActionValue extends AbstractValue implements StoredValue
     )
     {
         final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>( webActions.size() );
+
         for ( final ActionConfiguration.WebAction webAction : webActions )
         {
-            if ( StringUtil.notEmpty( webAction.getPassword() ) )
+            try
             {
-                try
-                {
-                    final String encodedValue = StoredValueEncoder.encode(
-                            webAction.getPassword(),
-                            xmlOutputProcessData.getStoredValueEncoderMode(),
-                            xmlOutputProcessData.getPwmSecurityKey() );
-                    clonedWebActions.add( webAction.toBuilder()
-                            .password( encodedValue )
-                            .build() );
-                }
-                catch ( final PwmOperationalException e )
-                {
-                    LOGGER.warn( () -> "error encoding stored pw value: " + e.getMessage() );
-                }
+                final String encodedValue = StringUtil.isEmpty( webAction.getPassword() )
+                        ? ""
+                        : StoredValueEncoder.encode( webAction.getPassword(),
+                                xmlOutputProcessData.getStoredValueEncoderMode(),
+                                xmlOutputProcessData.getPwmSecurityKey() );
+                clonedWebActions.add( webAction.toBuilder()
+                        .password( encodedValue )
+                        .build() );
             }
-            else
+            catch ( final PwmOperationalException e )
             {
-                clonedWebActions.add( webAction.toBuilder().build() );
+                throw new PwmInternalException( "error encoding stored pw value: " + e.getMessage() );
             }
         }
-        return clonedWebActions;
+        return Collections.unmodifiableList( clonedWebActions );
     }
 
     @Override
@@ -323,6 +318,10 @@ public class ActionValue extends AbstractValue implements StoredValue
                 sb.append( "\n   WebServiceAction: " );
                 sb.append( "\n    method=" ).append( webAction.getMethod() );
                 sb.append( "\n    url=" ).append( webAction.getUrl() );
+                if ( !CollectionUtil.isEmpty( webAction.getCertificates() ) )
+                {
+                    sb.append( "\n  certs=" ).append( X509Utils.makeDebugTexts( webAction.getCertificates() ) );
+                }
                 sb.append( "\n    headers=" ).append( JsonFactory.get().serializeMap( webAction.getHeaders() ) );
                 sb.append( "\n    username=" ).append( webAction.getUsername() );
                 sb.append( "\n    password=" ).append(

+ 4 - 3
server/src/main/java/password/pwm/config/value/PrivateKeyValue.java

@@ -31,6 +31,7 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
 import java.io.Serializable;
@@ -211,8 +212,8 @@ public class PrivateKeyValue extends AbstractValue
     {
         if ( privateKeyCertificate != null )
         {
-            return "PrivateKeyCertificate: key=" + JsonFactory.get().serializeMap( X509Utils.makeDebugInfoMap( privateKeyCertificate.getKey() ) )
-                    + ", certificates=" + JsonFactory.get().serializeCollection( X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates() ) );
+            return "PrivateKeyCertificate: key=" + JsonFactory.get().serializeMap( X509CertInfo.makeDebugInfoMap( privateKeyCertificate.getKey() ) )
+                    + ", certificates=" + JsonFactory.get().serializeCollection( X509CertInfo.makeDebugInfoMap( privateKeyCertificate.getCertificates() ) );
         }
         return "";
     }
@@ -230,7 +231,7 @@ public class PrivateKeyValue extends AbstractValue
                 }
                 : null;
         final Map<String, Object> returnMap = new LinkedHashMap<>();
-        returnMap.put( "certificates", X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates(), flags ) );
+        returnMap.put( "certificates", X509CertInfo.makeDebugInfoMap( privateKeyCertificate.getCertificates(), flags ) );
         final Map<String, Object> privateKeyInfo = new LinkedHashMap<>();
         privateKeyInfo.put( "algorithm", privateKeyCertificate.getKey().getAlgorithm() );
         privateKeyInfo.put( "format", privateKeyCertificate.getKey().getFormat() );

+ 8 - 28
server/src/main/java/password/pwm/config/value/X509CertificateValue.java

@@ -26,19 +26,15 @@ import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
-import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.PwmSecurityKey;
-import password.pwm.util.secure.SecureEngine;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
-import java.io.ByteArrayInputStream;
 import java.io.Serializable;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -146,23 +142,11 @@ public class X509CertificateValue extends AbstractValue implements StoredValue
         final int counter = 0;
         for ( final X509Certificate cert : certs.get() )
         {
-            sb.append( "Certificate " ).append( counter ).append( '\n' );
-            sb.append( " Subject: " ).append( cert.getSubjectDN().toString() ).append( '\n' );
-            sb.append( " Serial: " ).append( X509Utils.hexSerial( cert ) ).append( '\n' );
-            sb.append( " Issuer: " ).append( cert.getIssuerDN().toString() ).append( '\n' );
-            sb.append( " IssueDate: " ).append( StringUtil.toIsoDate( cert.getNotBefore().toInstant() ) ).append( '\n' );
-            sb.append( " ExpireDate: " ).append( StringUtil.toIsoDate( cert.getNotAfter().toInstant() ) ).append( '\n' );
-            try
+            sb.append( "Certificate " + counter + "\n" );
+            X509CertInfo.makeDebugInfoMap( cert ).forEach( ( key, value ) ->
             {
-                sb.append( " MD5 Hash: " ).append( SecureEngine.hash( new ByteArrayInputStream( cert.getEncoded() ),
-                        PwmHashAlgorithm.MD5 ) ).append( '\n' );
-                sb.append( " SHA1 Hash: " ).append( SecureEngine.hash( new ByteArrayInputStream( cert.getEncoded() ),
-                        PwmHashAlgorithm.SHA1 ) ).append( '\n' );
-            }
-            catch ( final PwmUnrecoverableException | CertificateEncodingException e )
-            {
-                LOGGER.warn( () -> "error generating hash for certificate: " + e.getMessage() );
-            }
+                sb.append( " " ).append( key ).append( ": " ).append( value ).append( "\n" );
+            } );
         }
         return sb.toString();
     }
@@ -180,14 +164,10 @@ public class X509CertificateValue extends AbstractValue implements StoredValue
             return Collections.emptyList();
         }
 
-        final X509Utils.DebugInfoFlag[] flags = includeDetail
-                ? new X509Utils.DebugInfoFlag[]
-                {
-                        X509Utils.DebugInfoFlag.IncludeCertificateDetail,
-                }
-                : null;
+        return certs.get().stream()
+                .map( cert -> X509CertInfo.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
+                .collect( Collectors.toUnmodifiableList() );
 
-        return certs.get().stream().map( cert -> X509Utils.makeDebugInfoMap( cert, flags ) ).collect( Collectors.toUnmodifiableList() );
     }
 
 }

+ 15 - 5
server/src/main/java/password/pwm/error/PwmInternalException.java

@@ -22,14 +22,29 @@ package password.pwm.error;
 
 public class PwmInternalException extends RuntimeException
 {
+    protected final ErrorInformation errorInformation;
+
+    public PwmInternalException( final ErrorInformation error )
+    {
+        this.errorInformation = error == null ? new ErrorInformation( PwmError.ERROR_INTERNAL ) : error;
+    }
+
+    public PwmInternalException( final Throwable cause )
+    {
+        super( cause );
+        this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "cause: " + cause.getMessage() );
+    }
+
     public PwmInternalException( final String message, final Throwable cause )
     {
         super( message, cause );
+        this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message + ", cause: " + cause.getMessage() );
     }
 
     public PwmInternalException( final String message )
     {
         super( message );
+        this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message );
     }
 
     public static PwmInternalException fromPwmException( final String message, final Exception pwmException )
@@ -41,9 +56,4 @@ public class PwmInternalException extends RuntimeException
     {
         return new PwmInternalException( pwmException );
     }
-
-    public PwmInternalException( final Throwable cause )
-    {
-        super( cause );
-    }
 }

+ 1 - 9
server/src/main/java/password/pwm/http/servlet/AbstractPwmServlet.java

@@ -204,15 +204,7 @@ public abstract class AbstractPwmServlet extends HttpServlet implements PwmServl
             stackTraceText = errorStack.toString();
         }
 
-        String stackTraceHash = "hash";
-        try
-        {
-            stackTraceHash = SecureEngine.hash( stackTraceText, PwmHashAlgorithm.SHA1 );
-        }
-        catch ( final PwmUnrecoverableException e1 )
-        {
-            /* */
-        }
+        final String stackTraceHash = SecureEngine.hash( stackTraceText, PwmHashAlgorithm.SHA1 );
         final String errorMsg = "unexpected error processing request: " + JavaHelper.readHostileExceptionMessage( e ) + " [" + stackTraceHash + "]";
 
         LOGGER.error( pwmRequest, () -> errorMsg, e );

+ 2 - 1
server/src/main/java/password/pwm/http/servlet/configeditor/function/ActionCertViewerFunction.java

@@ -26,6 +26,7 @@ import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.http.PwmRequest;
 import password.pwm.util.json.JsonFactory;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
 import java.io.Serializable;
@@ -71,7 +72,7 @@ public class ActionCertViewerFunction implements SettingUIFunction
         final ActionConfiguration.WebAction webAction = actionConfiguration.getWebActions().get( webActionIter );
 
         return webAction.getCertificates().stream()
-                .map( cert -> X509Utils.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
+                .map( cert -> X509CertInfo.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
                 .collect( Collectors.toUnmodifiableList() );
     }
 }

+ 2 - 1
server/src/main/java/password/pwm/http/servlet/configeditor/function/RemoteWebServiceCertViewerFunction.java

@@ -26,6 +26,7 @@ import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.data.RemoteWebServiceConfiguration;
 import password.pwm.http.PwmRequest;
 import password.pwm.util.json.JsonFactory;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
 import java.io.Serializable;
@@ -68,7 +69,7 @@ public class RemoteWebServiceCertViewerFunction implements SettingUIFunction
         final RemoteWebServiceConfiguration remoteWebServiceConfiguration = values.get( iteration );
 
         return remoteWebServiceConfiguration.getCertificates().stream()
-                .map( cert -> X509Utils.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
+                .map( cert -> X509CertInfo.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
                 .collect( Collectors.toUnmodifiableList() );
     }
 }

+ 2 - 1
server/src/main/java/password/pwm/http/servlet/configeditor/function/X509CertViewerFunction.java

@@ -25,6 +25,7 @@ import password.pwm.config.stored.StoredConfigurationModifier;
 import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.X509CertificateValue;
 import password.pwm.http.PwmRequest;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
 import java.io.Serializable;
@@ -62,7 +63,7 @@ public class X509CertViewerFunction implements SettingUIFunction
         final List<X509Certificate> values = ( ( X509CertificateValue ) storedValue ).asX509Certificates();
 
         return values.stream()
-                .map( cert -> X509Utils.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
+                .map( cert -> X509CertInfo.makeDebugInfoMap( cert, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
                 .collect( Collectors.toUnmodifiableList() );
     }
 }

+ 2 - 11
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerCertificatesServlet.java

@@ -47,7 +47,6 @@ import javax.servlet.ServletException;
 import javax.servlet.annotation.WebServlet;
 import java.io.IOException;
 import java.io.Serializable;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.time.Instant;
 import java.util.ArrayList;
@@ -175,23 +174,15 @@ public class ConfigManagerCertificatesServlet extends AbstractPwmServlet
             final String profileId,
             final X509Certificate certificate
     )
-            throws PwmUnrecoverableException
     {
         final CertificateDebugDataItem.CertificateDebugDataItemBuilder builder = CertificateDebugDataItem.builder();
         builder.menuLocation( setting.toMenuLocationDebug( profileId, PwmConstants.DEFAULT_LOCALE ) );
-        builder.subject( certificate.getSubjectDN().toString() );
+        builder.subject( certificate.getSubjectX500Principal().getName() );
         builder.serial( certificate.getSerialNumber().toString() );
         builder.algorithm( certificate.getSigAlgName() );
         builder.issueDate( certificate.getNotBefore().toInstant() );
         builder.expirationDate( certificate.getNotAfter().toInstant() );
-        try
-        {
-            builder.detail( X509Utils.makeDetailText( certificate ) );
-        }
-        catch ( final CertificateEncodingException e )
-        {
-            LOGGER.error( () -> "unexpected error parsing certificate detail text: " + e.getMessage() );
-        }
+        builder.detail( X509Utils.makeDetailText( certificate ) );
         return builder.build();
     }
 

+ 3 - 13
server/src/main/java/password/pwm/svc/wordlist/WordlistConfiguration.java

@@ -28,13 +28,12 @@ import password.pwm.AppAttribute;
 import password.pwm.AppProperty;
 import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
-import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.MiscUtil;
-import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
+import password.pwm.util.java.MiscUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.SecureEngine;
@@ -165,16 +164,7 @@ public class WordlistConfiguration implements Serializable
 
     @Getter( AccessLevel.PRIVATE )
     private final transient Supplier<String> configHash = new LazySupplier<>( () ->
-    {
-        try
-        {
-            return SecureEngine.hash( JsonFactory.get().serialize( WordlistConfiguration.this ), HASH_ALGORITHM );
-        }
-        catch ( final PwmUnrecoverableException e )
-        {
-            throw new IllegalStateException( "unexpected error generating wordlist-config hash: " + e.getMessage() );
-        }
-    } );
+            SecureEngine.hash( JsonFactory.get().serialize( WordlistConfiguration.this ), HASH_ALGORITHM ) );
 
     public boolean isAutoImportUrlConfigured()
     {

+ 2 - 1
server/src/main/java/password/pwm/util/cli/commands/LdapSchemaExtendCommand.java

@@ -32,6 +32,7 @@ import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.json.JsonProvider;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.secure.PwmTrustManager;
+import password.pwm.util.secure.X509CertInfo;
 import password.pwm.util.secure.X509Utils;
 
 import javax.net.ssl.X509TrustManager;
@@ -128,7 +129,7 @@ public class LdapSchemaExtendCommand extends AbstractCliCommand
         {
             out( "ldaps certificates from: " + url );
             final List<X509Certificate> certificateList = X509Utils.readRemoteCertificates( new URI ( url ), cliEnvironment.getConfig() );
-            out( JsonFactory.get().serializeCollection( X509Utils.makeDebugInfoMap( certificateList ), JsonProvider.Flag.PrettyPrint ) );
+            out( JsonFactory.get().serializeCollection( X509CertInfo.makeDebugInfoMap( certificateList ), JsonProvider.Flag.PrettyPrint ) );
             return certificateList;
         }
         return Collections.emptyList();

+ 1 - 1
server/src/main/java/password/pwm/util/secure/CertificateReadingTrustManager.java

@@ -117,7 +117,7 @@ public class CertificateReadingTrustManager implements X509TrustManager
         }
 
         LOGGER.debug( () -> "ServerCertReader: read self-signed certificates from remote server: "
-                + JsonFactory.get().serialize( new ArrayList<>( X509Utils.makeDebugInfoMap( certificates ) ) ) );
+                + JsonFactory.get().serialize( new ArrayList<>( X509CertInfo.makeDebugInfoMap( certificates ) ) ) );
         return Collections.unmodifiableList( certificates );
     }
 }

+ 1 - 1
server/src/main/java/password/pwm/util/secure/HttpsServerCertificateManager.java

@@ -170,7 +170,7 @@ public class HttpsServerCertificateManager
             final PrivateKey key = entry.getPrivateKey();
             final List<X509Certificate> certificates = Arrays.asList( ( X509Certificate[] ) entry.getCertificateChain() );
 
-            LOGGER.debug( () -> "importing certificate chain: " + JsonFactory.get().serializeCollection( X509Utils.makeDebugInfoMap( certificates ) ) );
+            LOGGER.debug( () -> "importing certificate chain: " + JsonFactory.get().serializeCollection( X509CertInfo.makeDebugInfoMap( certificates ) ) );
             privateKeyCertificate = new PrivateKeyCertificate( certificates, key );
         }
         catch ( final Exception e )

+ 21 - 0
server/src/main/java/password/pwm/util/secure/PwmHashAlgorithm.java

@@ -20,6 +20,13 @@
 
 package password.pwm.util.secure;
 
+import password.pwm.error.ErrorInformation;
+import password.pwm.error.PwmError;
+import password.pwm.error.PwmInternalException;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
 public enum PwmHashAlgorithm
 {
     MD5( "MD5", 32 ),
@@ -46,4 +53,18 @@ public enum PwmHashAlgorithm
     {
         return hexValueLength;
     }
+
+    public MessageDigest newMessageDigest()
+    {
+        try
+        {
+            return MessageDigest.getInstance( getAlgName() );
+        }
+        catch ( final NoSuchAlgorithmException e )
+        {
+            final String errorMsg = "missing hash algorithm: " + e.getMessage();
+            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );
+            throw new PwmInternalException( errorInformation );
+        }
+    }
 }

+ 15 - 30
server/src/main/java/password/pwm/util/secure/SecureEngine.java

@@ -24,6 +24,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
+import password.pwm.error.PwmInternalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.StringUtil;
@@ -313,12 +314,8 @@ public class SecureEngine
             final String input,
             final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
     {
-        if ( input == null || input.length() < 1 )
-        {
-            return null;
-        }
+        Objects.requireNonNull( input );
         return hash( new ByteArrayInputStream( input.getBytes( PwmConstants.DEFAULT_CHARSET ) ), algorithm );
     }
 
@@ -326,7 +323,6 @@ public class SecureEngine
             final InputStream is,
             final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
     {
         return JavaHelper.binaryArrayToHex( computeHashToBytes( is, algorithm ) );
     }
@@ -336,8 +332,8 @@ public class SecureEngine
             final PwmSecurityKey pwmSecurityKey,
             final String input
     )
-            throws PwmUnrecoverableException
     {
+        Objects.requireNonNull( input );
         return JavaHelper.binaryArrayToHex( computeHmacToBytes( hmacAlgorithm, pwmSecurityKey, input.getBytes( PwmConstants.DEFAULT_CHARSET ) ) );
     }
 
@@ -346,8 +342,8 @@ public class SecureEngine
             final PwmSecurityKey pwmSecurityKey,
             final String input
     )
-            throws PwmUnrecoverableException
     {
+        Objects.requireNonNull( input );
         return JavaHelper.binaryArrayToHex( computeHmacToBytes( hmacAlgorithm, pwmSecurityKey, input.getBytes( PwmConstants.DEFAULT_CHARSET ) ) );
     }
 
@@ -356,21 +352,19 @@ public class SecureEngine
             final PwmSecurityKey pwmSecurityKey,
             final byte[] input
     )
-            throws PwmUnrecoverableException
     {
         try
         {
-
             final Mac mac = Mac.getInstance( hmacAlgorithm.getAlgorithmName() );
             final SecretKey secretKey = pwmSecurityKey.getKey( hmacAlgorithm.getKeyType() );
             mac.init( secretKey );
             return mac.doFinal( input );
         }
-        catch ( final GeneralSecurityException e )
+        catch ( final GeneralSecurityException | PwmUnrecoverableException e )
         {
             final String errorMsg = "error during hmac operation: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );
-            throw new PwmUnrecoverableException( errorInformation );
+            throw new PwmInternalException( errorInformation );
         }
     }
 
@@ -379,22 +373,13 @@ public class SecureEngine
             final InputStream is,
             final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
     {
+        Objects.requireNonNull( is );
+        Objects.requireNonNull( algorithm );
 
         final InputStream bis = is instanceof BufferedInputStream ? is : new BufferedInputStream( is );
 
-        final MessageDigest messageDigest;
-        try
-        {
-            messageDigest = MessageDigest.getInstance( algorithm.getAlgName() );
-        }
-        catch ( final NoSuchAlgorithmException e )
-        {
-            final String errorMsg = "missing hash algorithm: " + e.getMessage();
-            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );
-            throw new PwmUnrecoverableException( errorInformation );
-        }
+        final MessageDigest messageDigest = algorithm.newMessageDigest();
 
         try
         {
@@ -417,7 +402,7 @@ public class SecureEngine
         {
             final String errorMsg = "unexpected error during hash operation: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );
-            throw new PwmUnrecoverableException( errorInformation );
+            throw new PwmInternalException( errorInformation );
         }
     }
 
@@ -449,11 +434,11 @@ public class SecureEngine
         NonceGenerator( final int fixedComponentLength, final int counterComponentLength )
         {
             this.fixedComponentLength = fixedComponentLength;
-            value = new byte[ fixedComponentLength + counterComponentLength ];
+            value = new byte[fixedComponentLength + counterComponentLength];
             PwmRandom.getInstance().nextBytes( value );
         }
 
-        public synchronized byte[] nextValue( )
+        public synchronized byte[] nextValue()
         {
             lock.lock();
             try
@@ -469,9 +454,9 @@ public class SecureEngine
 
         private void increment( final int index )
         {
-            if ( value[ index ] == Byte.MAX_VALUE )
+            if ( value[index] == Byte.MAX_VALUE )
             {
-                value[ index ] = 0;
+                value[index] = 0;
                 if ( index > fixedComponentLength )
                 {
                     increment( index - 1 );
@@ -479,7 +464,7 @@ public class SecureEngine
             }
             else
             {
-                value[ index ]++;
+                value[index]++;
             }
         }
     }

+ 96 - 0
server/src/main/java/password/pwm/util/secure/X509CertDataParser.java

@@ -0,0 +1,96 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2021 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.util.secure;
+
+import password.pwm.util.java.CollectionUtil;
+import password.pwm.util.logging.PwmLogger;
+
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+class X509CertDataParser
+{
+    private static final PwmLogger LOGGER = PwmLogger.forClass( X509CertDataParser.class );
+
+    static Optional<String> readCertSubject( final X509Certificate cert )
+    {
+        if ( cert.getSubjectX500Principal() != null )
+        {
+            return Optional.of( cert.getSubjectX500Principal().getName() );
+        }
+        return Optional.empty();
+    }
+
+    static Optional<String> readCertIssuer( final X509Certificate cert )
+    {
+        if ( cert.getIssuerX500Principal() != null )
+        {
+            return Optional.of( cert.getIssuerX500Principal().getName() );
+        }
+        return Optional.empty();
+    }
+
+    static Optional<String> readCertPublicKeyInfo( final X509Certificate cert )
+    {
+        if ( cert.getPublicKey() != null )
+        {
+            final PublicKey publicKey = cert.getPublicKey();
+            final String publicKeyInfo = publicKey.getFormat() + " " + publicKey.getAlgorithm();
+            return Optional.of( publicKeyInfo );
+        }
+
+        return Optional.empty();
+    }
+
+    static Optional<String> readCertSubjectAlternativeNames( final X509Certificate cert )
+    {
+
+        try
+        {
+            if ( !CollectionUtil.isEmpty( cert.getSubjectAlternativeNames() ) )
+            {
+                final String sans = cert.getSubjectAlternativeNames().stream()
+                        .map( Object::toString )
+                        .collect( Collectors.joining( "," ) );
+
+                return Optional.of( sans );
+            }
+        }
+        catch ( final CertificateParsingException e )
+        {
+            LOGGER.trace( () -> "error while examining subject alternate names for certificate: " + e.getMessage() );
+        }
+
+        return Optional.empty();
+    }
+
+    static boolean certIsSigningKey( final X509Certificate certificate )
+    {
+        final int keyCertSignBitPosition = 5;
+        final boolean[] keyUsages = certificate.getKeyUsage();
+        return keyUsages != null
+                && keyUsages.length > keyCertSignBitPosition - 1
+                && keyUsages[keyCertSignBitPosition];
+    }
+}

+ 111 - 0
server/src/main/java/password/pwm/util/secure/X509CertInfo.java

@@ -0,0 +1,111 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2021 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.util.secure;
+
+import password.pwm.PwmConstants;
+import password.pwm.util.i18n.LocaleHelper;
+import password.pwm.util.java.CollectionUtil;
+import password.pwm.util.java.JavaHelper;
+import password.pwm.util.java.StringUtil;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public enum X509CertInfo
+{
+    subject,
+    subjectAlternateNames,
+    publicKeyType,
+    serial,
+    issuer,
+    issueDate,
+    expireDate,
+    md5Hash,
+    sha1Hash,
+    sha256Hash,
+    sha512Hash,
+    isKeySigning,
+    detail,;
+
+    public static List<Map<String, String>> makeDebugInfoMap( final List<X509Certificate> certificates, final X509Utils.DebugInfoFlag... flags )
+    {
+        final List<Map<String, String>> returnList = new ArrayList<>();
+        if ( certificates != null )
+        {
+            for ( final X509Certificate cert : certificates )
+            {
+                returnList.add( makeDebugInfoMap( cert, flags ) );
+            }
+        }
+        return Collections.unmodifiableList( returnList );
+    }
+
+    public static Map<String, String> makeDebugInfoMap( final X509Certificate cert, final X509Utils.DebugInfoFlag... flags )
+    {
+        if ( JavaHelper.enumArrayContainsValue( flags, X509Utils.DebugInfoFlag.IncludeCertificateDetail ) )
+        {
+            final Map<X509CertInfo, String> infoMap = new EnumMap<>( X509CertInfo.class );
+            infoMap.putAll( makeDebugInfoMapImpl( cert ) );
+            infoMap.put( detail, X509Utils.makeDetailText( cert ) );
+            return CollectionUtil.enumMapToStringMap( infoMap );
+        }
+
+        return CollectionUtil.enumMapToStringMap( makeDebugInfoMapImpl( cert ) );
+    }
+
+    static Map<X509CertInfo, String> makeDebugInfoMapImpl( final X509Certificate cert  )
+    {
+
+        final Map<X509CertInfo, String> returnMap = new EnumMap<>( X509CertInfo.class );
+
+        returnMap.put( serial, X509Utils.hexSerial( cert ) );
+        returnMap.put( issueDate, StringUtil.toIsoDate( cert.getNotBefore().toInstant() ) );
+        returnMap.put( expireDate, StringUtil.toIsoDate( cert.getNotAfter().toInstant() ) );
+        returnMap.put( md5Hash, X509Utils.hash( cert, PwmHashAlgorithm.MD5 ) );
+        returnMap.put( sha1Hash, X509Utils.hash( cert, PwmHashAlgorithm.SHA1 ) );
+        returnMap.put( sha256Hash, X509Utils.hash( cert, PwmHashAlgorithm.SHA256 ) );
+        returnMap.put( sha512Hash, X509Utils.hash( cert, PwmHashAlgorithm.SHA512 ) );
+        returnMap.put( isKeySigning, LocaleHelper.valueBoolean( PwmConstants.DEFAULT_LOCALE, X509CertDataParser.certIsSigningKey( cert ) ) );
+
+        X509CertDataParser.readCertSubject( cert ).ifPresent( s -> returnMap.put( subject, s ) );
+        X509CertDataParser.readCertIssuer( cert ).ifPresent( s -> returnMap.put( issuer, s ) );
+
+        X509CertDataParser.readCertPublicKeyInfo( cert ).ifPresent( s -> returnMap.put( publicKeyType, s ) );
+
+        X509CertDataParser.readCertSubjectAlternativeNames( cert ).ifPresent( s -> returnMap.put( subjectAlternateNames, s ) );
+
+        return Collections.unmodifiableMap( returnMap );
+    }
+
+    public static Map<String, String> makeDebugInfoMap( final PrivateKey key )
+    {
+        final Map<String, String> returnMap = new LinkedHashMap<>();
+        returnMap.put( X509Utils.KeyDebugInfoKey.algorithm.toString(), key.getAlgorithm() );
+        returnMap.put( X509Utils.KeyDebugInfoKey.format.toString(), key.getFormat() );
+        return returnMap;
+    }
+}

+ 37 - 115
server/src/main/java/password/pwm/util/secure/X509Utils.java

@@ -28,6 +28,7 @@ import password.pwm.config.option.CertificateMatchingMode;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
+import password.pwm.error.PwmInternalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.HttpMethod;
@@ -56,7 +57,6 @@ import java.security.GeneralSecurityException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
 import java.security.SecureRandom;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
@@ -65,10 +65,8 @@ import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
@@ -82,11 +80,27 @@ public class X509Utils
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( X509Utils.class );
 
-    private X509Utils()
+    public enum ReadCertificateFlag
+    {
+        ReadOnlyRootCA
+    }
+
+    public enum DebugInfoFlag
     {
+        IncludeCertificateDetail
     }
 
 
+    enum KeyDebugInfoKey
+    {
+        algorithm,
+        format,
+    }
+
+    private X509Utils()
+    {
+    }
+
     public static List<X509Certificate> readRemoteCertificates(
             final URI uri,
             final AppConfig appConfig
@@ -269,33 +283,31 @@ public class X509Utils
     }
 
     public static String makeDetailText( final X509Certificate x509Certificate )
-            throws CertificateEncodingException, PwmUnrecoverableException
     {
-        return x509Certificate.toString()
-                + "\nMD5: " + hash( x509Certificate, PwmHashAlgorithm.MD5 )
-                + "\nSHA1: " + hash( x509Certificate, PwmHashAlgorithm.SHA1 )
-                + "\nSHA2-256: " + hash( x509Certificate, PwmHashAlgorithm.SHA256 )
-                + "\nSHA2-512: " + hash( x509Certificate, PwmHashAlgorithm.SHA512 )
-                + "\n:IsRootCA: " + certIsRootCA( x509Certificate );
+        final StringBuilder sb = new StringBuilder();
+        X509CertInfo.makeDebugInfoMapImpl( x509Certificate ).forEach( ( key, value ) ->
+        {
+            sb.append( key );
+            sb.append( ": " );
+            sb.append( value );
+            sb.append( "\n" );
+        } );
+
+        sb.append( x509Certificate );
+        sb.append( "\n" );
+        return sb.toString();
     }
 
     public static String makeDebugTexts( final List<X509Certificate> x509Certificates )
     {
-        final StringBuilder sb = new StringBuilder();
-        sb.append( "Certificates: " );
-        for ( final X509Certificate x509Certificate : x509Certificates )
-        {
-            sb.append( '[' );
-            sb.append( makeDebugText( x509Certificate ) );
-            sb.append( ']' );
-
-        }
-        return sb.toString();
+        return x509Certificates.stream()
+                .map( x509Certificate -> '[' + makeDebugText( x509Certificate ) + ']' )
+                .collect( Collectors.joining( "", "Certificates: ", "" ) );
     }
 
     public static String makeDebugText( final X509Certificate x509Certificate )
     {
-        return "subject=" + x509Certificate.getSubjectDN().getName() + ", serial=" + x509Certificate.getSerialNumber();
+        return "subject=" + X509CertDataParser.readCertSubject( x509Certificate ) + ", serial=" + x509Certificate.getSerialNumber();
     }
 
     public static List<X509Certificate> certificatesFromBase64s( final Collection<String> b64certificates )
@@ -363,80 +375,6 @@ public class X509Utils
         }
     }
 
-    enum CertDebugInfoKey
-    {
-        subject,
-        serial,
-        issuer,
-        issueDate,
-        expireDate,
-        md5Hash,
-        sha1Hash,
-        sha512Hash,
-        detail,
-    }
-
-    public enum ReadCertificateFlag
-    {
-        ReadOnlyRootCA
-    }
-
-    public enum DebugInfoFlag
-    {
-        IncludeCertificateDetail
-    }
-
-    public static List<Map<String, String>> makeDebugInfoMap( final List<X509Certificate> certificates, final DebugInfoFlag... flags )
-    {
-        final List<Map<String, String>> returnList = new ArrayList<>();
-        if ( certificates != null )
-        {
-            for ( final X509Certificate cert : certificates )
-            {
-                returnList.add( makeDebugInfoMap( cert, flags ) );
-            }
-        }
-        return returnList;
-    }
-
-    public static Map<String, String> makeDebugInfoMap( final X509Certificate cert, final DebugInfoFlag... flags )
-    {
-        final Map<String, String> returnMap = new LinkedHashMap<>();
-        returnMap.put( CertDebugInfoKey.subject.toString(), cert.getSubjectDN().toString() );
-        returnMap.put( CertDebugInfoKey.serial.toString(), X509Utils.hexSerial( cert ) );
-        returnMap.put( CertDebugInfoKey.issuer.toString(), cert.getIssuerDN().toString() );
-        returnMap.put( CertDebugInfoKey.issueDate.toString(), StringUtil.toIsoDate( cert.getNotBefore().toInstant() ) );
-        returnMap.put( CertDebugInfoKey.expireDate.toString(), StringUtil.toIsoDate( cert.getNotAfter().toInstant() ) );
-        try
-        {
-            returnMap.put( CertDebugInfoKey.md5Hash.toString(), hash( cert, PwmHashAlgorithm.MD5 ) );
-            returnMap.put( CertDebugInfoKey.sha1Hash.toString(), hash( cert, PwmHashAlgorithm.SHA1 ) );
-            returnMap.put( CertDebugInfoKey.sha512Hash.toString(), hash( cert, PwmHashAlgorithm.SHA512 ) );
-            if ( JavaHelper.enumArrayContainsValue( flags, DebugInfoFlag.IncludeCertificateDetail ) )
-            {
-                returnMap.put( CertDebugInfoKey.detail.toString(), X509Utils.makeDetailText( cert ) );
-            }
-        }
-        catch ( final PwmUnrecoverableException | CertificateEncodingException e )
-        {
-            LOGGER.warn( () -> "error generating hash for certificate: " + e.getMessage() );
-        }
-        return returnMap;
-    }
-
-    enum KeyDebugInfoKey
-    {
-        algorithm,
-        format,
-    }
-
-    public static Map<String, String> makeDebugInfoMap( final PrivateKey key )
-    {
-        final Map<String, String> returnMap = new LinkedHashMap<>();
-        returnMap.put( KeyDebugInfoKey.algorithm.toString(), key.getAlgorithm() );
-        returnMap.put( KeyDebugInfoKey.format.toString(), key.getFormat() );
-        return returnMap;
-    }
 
     public static X509Certificate certificateFromBase64( final String b64encodedStr )
             throws CertificateException, IOException
@@ -462,7 +400,7 @@ public class X509Utils
 
         for ( final X509Certificate certificate : certificates )
         {
-            if ( certIsRootCA( certificate ) )
+            if ( X509CertDataParser.certIsSigningKey( certificate ) )
             {
                 returnList.add( certificate );
             }
@@ -476,21 +414,6 @@ public class X509Utils
         return Optional.empty();
     }
 
-    private static boolean certIsRootCA( final X509Certificate certificate )
-    {
-        final int keyCertSignBitPosition = 5;
-        final boolean[] keyUsages = certificate.getKeyUsage();
-        if ( keyUsages != null && keyUsages.length > keyCertSignBitPosition - 1 )
-        {
-            if ( keyUsages[keyCertSignBitPosition] )
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     public static TrustManager[] getDefaultJavaTrustManager( final AppConfig appConfig )
             throws PwmUnrecoverableException
     {
@@ -509,7 +432,6 @@ public class X509Utils
     }
 
     public static String hash( final X509Certificate certificate, final PwmHashAlgorithm pwmHashAlgorithm )
-            throws PwmUnrecoverableException
     {
         try
         {
@@ -517,7 +439,8 @@ public class X509Utils
         }
         catch ( final CertificateEncodingException e )
         {
-            throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "unexpected error encoding certificate: " + e.getMessage() );
+            throw new PwmInternalException( new ErrorInformation( PwmError.ERROR_INTERNAL,
+                    "unexpected error encoding certificate: " + e.getMessage() ) );
         }
     }
 
@@ -548,5 +471,4 @@ public class X509Utils
         }
         return Collections.unmodifiableSet( resultCertificates );
     }
-
 }

+ 10 - 1
server/src/main/resources/password/pwm/config/PwmSetting.xml

@@ -30,11 +30,12 @@
             <value>DEFAULT</value>
         </default>
         <options>
+            <option value="DIRECTORY_SERVER_389">389 Directory Server</option>
             <option value="AD">Microsoft Active Directory</option>
-            <option value="ORACLE_DS">Oracle Directory Server</option>
             <option value="NOVL">NetIQ eDirectory</option>
             <option value="NOVL_IDM">NetIQ IDM / OAuth Integration</option>
             <option value="OPEN_LDAP">OpenLDAP</option>
+            <option value="ORACLE_DS">Oracle Directory Server</option>
             <option value="DEFAULT">Others</option>
         </options>
         <properties>
@@ -550,6 +551,7 @@
         <example template="AD">CN=@PwmAppName@-Proxy,CN=Users,DC=ad,DC=site,DC=example,DC=com</example>
         <example template="ORACLE_DS">cn=@PwmAppName@-Proxy,cn=Administrators,cn=config</example>
         <example template="OPEN_LDAP">cn=@PwmAppName@-Proxy,dc=example,dc=com</example>
+        <example template="DIRECTORY_SERVER_389">cn=@PwmAppName@-Proxy,dc=example,dc=com</example>
         <default/>
     </setting>
     <setting hidden="false" key="ldap.proxy.password" level="0">
@@ -570,6 +572,7 @@
         <example template="AD">CN=@PwmAppName@-Testuser,CN=Users,DC=ad,DC=site,DC=example,DC=com</example>
         <example template="ORACLE_DS">cn=@PwmAppName@-Testuser,cn=Administrators,cn=config</example>
         <example template="OPEN_LDAP">cn=@PwmAppName@-Testuser,dc=example,dc=com</example>
+        <example template="DIRECTORY_SERVER_389">cn=@PwmAppName@-Testuser,dc=example,dc=com</example>
         <default>
             <value />
         </default>
@@ -640,6 +643,9 @@
         <default template="OPEN_LDAP">
             <value>memberof</value>
         </default>
+        <default template="DIRECTORY_SERVER_389">
+            <value>memberof</value>
+        </default>
     </setting>
     <setting hidden="true" key="ldap.group.label.attribute" level="2">
         <default>
@@ -666,6 +672,9 @@
         <default template="OPEN_LDAP">
             <value><![CDATA[entryuuid]]></value>
         </default>
+        <default template="DIRECTORY_SERVER_389">
+            <value><![CDATA[uidNumber]]></value>
+        </default>
     </setting>
     <setting hidden="false" key="ldap.namingAttribute" level="1" required="true">
         <ldapPermission actor="proxy" access="read"/>

+ 65 - 0
server/src/test/java/password/pwm/config/PwmSettingTemplateTest.java

@@ -0,0 +1,65 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2021 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+import password.pwm.util.java.JavaHelper;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public class PwmSettingTemplateTest
+{
+    @Test
+    public void testPwmSettingTemplateEnums() throws Exception
+    {
+        {
+            for ( final PwmSettingTemplate.Type type : PwmSettingTemplate.Type.values() )
+            {
+                final Set<PwmSettingTemplate> seenTemplatesOfType = EnumSet.noneOf( PwmSettingTemplate.class );
+                final PwmSetting associatedSetting = type.getPwmSetting();
+                final Set<String> xmlValues = associatedSetting.getOptions().keySet();
+                final Set<PwmSettingTemplate> enumValues = PwmSettingTemplate.valuesForType( type );
+
+                for ( final String xmlValue : xmlValues )
+                {
+                    final PwmSettingTemplate pwmSettingTemplate = JavaHelper.readEnumFromString( PwmSettingTemplate.class, xmlValue )
+                            .orElseThrow( () -> new IllegalStateException(
+                                    "PwmSetting.xml has option value '" + xmlValue
+                                            + "' for " + associatedSetting
+                                            + " not declared as PwmSettingTemplate enum value" ) );
+                    seenTemplatesOfType.add( pwmSettingTemplate );
+
+                }
+
+                for ( final PwmSettingTemplate enumValue : enumValues )
+                {
+                    if ( !seenTemplatesOfType.contains( enumValue ) )
+                    {
+                        Assert.fail( "PwmSettingTemplate enum value " + enumValue
+                                + " is missing corresponding option value in setting " + associatedSetting );
+                    }
+                }
+            }
+        }
+    }
+}

+ 102 - 0
server/src/test/java/password/pwm/http/ServletTest.java

@@ -0,0 +1,102 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2021 The PWM Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package password.pwm.http;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import org.reflections.util.ClasspathHelper;
+import org.reflections.util.ConfigurationBuilder;
+import password.pwm.PwmConstants;
+import password.pwm.util.java.StringUtil;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ServletTest
+{
+    @Test
+    public void testDuplicateServletNames()
+    {
+        final var seenServletNames = new HashSet<String>();
+
+        final var servletClasses = getServletClasses();
+
+        for ( final Class<? extends HttpServlet> httpServletClass : servletClasses )
+        {
+            final var webServletAnnotation = httpServletClass.getAnnotation( WebServlet.class );
+            if ( webServletAnnotation != null )
+            {
+                final var name = webServletAnnotation.name();
+                if ( !StringUtil.isEmpty( name ) )
+                {
+                    if ( StringUtil.caseIgnoreContains( seenServletNames, name ) )
+                    {
+                        Assert.fail( httpServletClass.getName() + " servlet class name duplicate (case ignore) detected: " + name );
+                    }
+                    seenServletNames.add( name );
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testDuplicatePatternsNames()
+    {
+        final var seenPatterns = new HashSet<String>();
+
+        final var servletClasses = getServletClasses();
+
+        for ( final Class<? extends HttpServlet> httpServletClass : servletClasses )
+        {
+            final WebServlet webServletAnnotation = httpServletClass.getAnnotation( WebServlet.class );
+            if ( webServletAnnotation != null )
+            {
+                final var names = webServletAnnotation.urlPatterns();
+                for ( final var name : names )
+                {
+                    if ( !StringUtil.isEmpty( name ) )
+                    {
+                        if ( seenPatterns.contains( name ) )
+                        {
+                            Assert.fail( httpServletClass.getName() + " servlet pattern duplicate detected: " + name );
+                        }
+                        seenPatterns.add( name );
+                    }
+                }
+            }
+        }
+    }
+
+
+    private Set<Class<? extends HttpServlet>> getServletClasses()
+    {
+        final var reflections = new Reflections( new ConfigurationBuilder()
+                .setUrls( ClasspathHelper.forPackage( PwmConstants.PWM_BASE_PACKAGE.getName() ) )
+                .setScanners( Scanners.SubTypes ) );
+
+        return Collections.unmodifiableSet( reflections.getSubTypesOf( HttpServlet.class ) );
+    }
+}

+ 2 - 1
server/src/test/java/password/pwm/http/servlet/ControlledPwmServletTest.java

@@ -26,6 +26,7 @@ import org.reflections.Reflections;
 import org.reflections.scanners.Scanners;
 import org.reflections.util.ClasspathHelper;
 import org.reflections.util.ConfigurationBuilder;
+import password.pwm.PwmConstants;
 import password.pwm.http.ProcessStatus;
 import password.pwm.http.PwmRequest;
 import password.pwm.util.java.JavaHelper;
@@ -202,7 +203,7 @@ public class ControlledPwmServletTest
     private Map<Class<? extends ControlledPwmServlet>, Map<String, Method>> getClassAndMethods()
     {
         final Reflections reflections = new Reflections( new ConfigurationBuilder()
-                .setUrls( ClasspathHelper.forPackage( "password.pwm" ) )
+                .setUrls( ClasspathHelper.forPackage( PwmConstants.PWM_BASE_PACKAGE.getName() ) )
                 .setScanners( Scanners.SubTypes,
                         Scanners.TypesAnnotated,
                         Scanners.FieldsAnnotated

+ 2 - 1
server/src/test/java/password/pwm/ws/server/rest/RestServletTest.java

@@ -26,6 +26,7 @@ import org.reflections.Reflections;
 import org.reflections.scanners.Scanners;
 import org.reflections.util.ClasspathHelper;
 import org.reflections.util.ConfigurationBuilder;
+import password.pwm.PwmConstants;
 import password.pwm.http.HttpContentType;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.ws.server.RestMethodHandler;
@@ -141,7 +142,7 @@ public class RestServletTest
     private Set<Class<? extends RestServlet>> getClasses()
     {
         final Reflections reflections = new Reflections( new ConfigurationBuilder()
-                .setUrls( ClasspathHelper.forPackage( "password.pwm" ) )
+                .setUrls( ClasspathHelper.forPackage( PwmConstants.PWM_BASE_PACKAGE.getName() ) )
                 .setScanners( Scanners.SubTypes,
                         Scanners.TypesAnnotated,
                         Scanners.FieldsAnnotated

+ 3 - 3
webapp/pom.xml

@@ -296,17 +296,17 @@
         <dependency>
             <groupId>org.webjars.npm</groupId>
             <artifactId>dojo</artifactId>
-            <version>1.16.4</version>
+            <version>1.17.2</version>
         </dependency>
         <dependency>
             <groupId>org.webjars.npm</groupId>
             <artifactId>dijit</artifactId>
-            <version>1.16.4</version>
+            <version>1.17.2</version>
         </dependency>
         <dependency>
             <groupId>org.webjars.npm</groupId>
             <artifactId>dojox</artifactId>
-            <version>1.16.4</version>
+            <version>1.17.2</version>
         </dependency>
         <dependency>
             <groupId>org.webjars.npm</groupId>

+ 79 - 78
webapp/src/main/webapp/public/resources/js/configeditor-settings-action.js

@@ -58,7 +58,7 @@ ActionHandler.ldapMethodOptions = [
 
 ActionHandler.init = function(keyName, postInitFunction) {
     console.log('ActionHandler init for ' + keyName);
-    var parentDiv = 'table_setting_' + keyName;
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.readSetting(keyName, function(resultValue) {
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
@@ -71,17 +71,17 @@ ActionHandler.init = function(keyName, postInitFunction) {
 
 ActionHandler.redraw = function(keyName) {
     console.log('ActionHandler redraw for ' + keyName);
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
-    var parentDiv = 'table_setting_' + keyName;
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, false);
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
-    var html = '';
+    let html = '';
     if (!PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
         html += '<table class="noborder">';
         html += '<tr><td>Name</td><td></td><td>Description</td></tr>';
 
-        for (var i in resultValue) {
+        for (const i in resultValue) {
             html += ActionHandler.drawRow(keyName, i, resultValue[i]);
         }
 
@@ -91,7 +91,7 @@ ActionHandler.redraw = function(keyName) {
     html += '<br/><button class="btn" id="button-' + keyName + '-addValue"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Action</button>';
     parentDivElement.innerHTML = html;
 
-    for (var i in resultValue) {
+    for (const i in resultValue) {
         html += ActionHandler.addRowHandlers(keyName, i, resultValue[i]);
     }
 
@@ -101,13 +101,13 @@ ActionHandler.redraw = function(keyName) {
 };
 
 ActionHandler.drawRow = function(settingKey, iteration, value) {
-    var inputID = 'value_' + settingKey + '_' + iteration + "_";
-    var optionList = ["webservice","ldap"];
+    const inputID = 'value_' + settingKey + '_' + iteration + "_";
+    const optionList = ["webservice","ldap"];
 
-    var newTableRow = document.createElement("tr");
+    const newTableRow = document.createElement("tr");
     newTableRow.setAttribute("style", "border-width: 0");
 
-    var htmlRow = '<tr>';
+    let htmlRow = '<tr>';
     htmlRow += '<td style="background: #f6f9f8; border:1px solid #dae1e1; width:160px">';
     htmlRow += '<div class="noWrapTextBox" id="display-' + inputID + '-name" ></div>';
     htmlRow += '<td style="width:1px" id="icon-editDescription-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-edit"></span></td>';
@@ -122,7 +122,7 @@ ActionHandler.drawRow = function(settingKey, iteration, value) {
 };
 
 ActionHandler.addRowHandlers = function(settingKey, iteration, value) {
-    var inputID = 'value_' + settingKey + '_' + iteration + "_";
+    const inputID = 'value_' + settingKey + '_' + iteration + "_";
     UILibrary.addTextValueToElement('display-' + inputID + '-name',value['name']);
     UILibrary.addTextValueToElement('display-' + inputID + '-description',value['description']);
 
@@ -130,7 +130,7 @@ ActionHandler.addRowHandlers = function(settingKey, iteration, value) {
         ActionHandler.showActionsDialog(settingKey, iteration);
     });
 
-    var descriptionEditFunction = function() {
+    const descriptionEditFunction = function() {
         UILibrary.stringEditorDialog({
             value: value['description'],
             textarea: true,
@@ -159,7 +159,7 @@ ActionHandler.addRowHandlers = function(settingKey, iteration, value) {
 };
 
 ActionHandler.write = function(settingKey, finishFunction) {
-    var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
+    const cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
@@ -183,8 +183,8 @@ ActionHandler.addRow = function(keyName) {
         instructions: 'Please enter a descriptive name for the action.',
         placeholder:'Name',
         completeFunction:function(newName){
-            var value = PWM_VAR['clientSettingCache'][keyName];
-            var currentSize = PWM_MAIN.JSLibrary.itemCount(value);
+            const value = PWM_VAR['clientSettingCache'][keyName];
+            const currentSize = PWM_MAIN.JSLibrary.itemCount(value);
             value[currentSize] = ActionHandler.defaultValue;
             value[currentSize].name = newName;
             ActionHandler.write(keyName,function(){
@@ -197,16 +197,16 @@ ActionHandler.addRow = function(keyName) {
 };
 
 ActionHandler.showActionsDialog = function(keyName, iteration) {
-    var value = PWM_VAR['clientSettingCache'][keyName][iteration];
-    var titleText = value['name'] + ' actions';
-    var bodyText = '<table class="noborder">';
+    const value = PWM_VAR['clientSettingCache'][keyName][iteration];
+    const titleText = value['name'] + ' actions';
+    let bodyText = '<table class="noborder">';
 
     if (!PWM_MAIN.JSLibrary.isEmpty(value['ldapActions'])) {
         bodyText += '<tr><td></td><td></td><td>LDAP Attribute</td></tr>';
     }
-    for (var iter in value['ldapActions']) {
+    for (const iter in value['ldapActions']) {
         (function (ldapActionsIter) {
-            var inputID = keyName + '_' + iteration + "_ldapActions_"  + ldapActionsIter;
+            const inputID = keyName + '_' + iteration + "_ldapActions_"  + ldapActionsIter;
             bodyText += '<tr id="tableRow-' + inputID + '">'
                 + '<td style="width:1px" id="icon-editLdapAction-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-edit"></span></td>'
                 + '<td>LDAP Action</td>'
@@ -220,9 +220,9 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
     if (!PWM_MAIN.JSLibrary.isEmpty(value['webActions'])) {
         bodyText += '<tr><td></td><td></td><td>URL</td></tr>';
     }
-    for (var iter in value['webActions']) {
+    for (const iter in value['webActions']) {
         (function (webActionIter) {
-            var inputID = keyName + '_' + iteration + "_webActions_"  + webActionIter;
+            const inputID = keyName + '_' + iteration + "_webActions_"  + webActionIter;
             bodyText += '<tr id="tableRow-' + inputID + '">'
                 + '<td style="width:1px" id="icon-editWebAction-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-edit"></span></td>'
                 + '<td>Web Service Action</td>'
@@ -234,7 +234,7 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
 
     bodyText += '</table><br/>';
 
-    var inputID = keyName + '_' + iteration + "_";
+    const inputID = keyName + '_' + iteration + "_";
     bodyText += '<br/><button class="btn" id="button-addLdap-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add LDAP Action</button>';
     bodyText += '<br/><button class="btn" id="button-addWebService-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Web Service Action</button>';
 
@@ -242,10 +242,10 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
         title: titleText,
         text: bodyText,
         loadFunction: function(){
-            for (var iter in value['ldapActions']) {
+            for (const iter in value['ldapActions']) {
                 (function (ldapActionsIter) {
-                    var inputID = keyName + '_' + iteration + "_ldapActions_"  + ldapActionsIter;
-                    PWM_MAIN.addEventHandler('icon-editLdapAction-' + inputID ,'click',function(){
+                    const inputID = keyName + '_' + iteration + "_ldapActions_"  + ldapActionsIter;
+                    PWM_MAIN.addEventHandler('tableRow-' + inputID ,'click',function(){
                         ActionHandler.addOrEditLdapAction(keyName,iteration,ldapActionsIter);
                     });
                     PWM_MAIN.addEventHandler('button-deleteRow-' + inputID ,'click',function(){
@@ -259,14 +259,14 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
                             }
                         });
                     });
-                    var value = PWM_VAR['clientSettingCache'][keyName][iteration]['ldapActions'][ldapActionsIter];
+                    const value = PWM_VAR['clientSettingCache'][keyName][iteration]['ldapActions'][ldapActionsIter];
                     PWM_MAIN.getObject('value-' + inputID).value =  value['attributeName'];
                 }(iter));
             }
-            for (var iter in value['webActions']) {
+            for (const iter in value['webActions']) {
                 (function (webActionIter) {
-                    var inputID = keyName + '_' + iteration + "_webActions_"  + webActionIter;
-                    PWM_MAIN.addEventHandler('icon-editWebAction-' + inputID ,'click',function(){
+                    const inputID = keyName + '_' + iteration + "_webActions_"  + webActionIter;
+                    PWM_MAIN.addEventHandler('tableRow-' + inputID ,'click',function(){
                         ActionHandler.addOrEditWebAction(keyName,iteration,webActionIter);
                     });
                     PWM_MAIN.addEventHandler('button-deleteRow-' + inputID ,'click',function(){
@@ -280,18 +280,17 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
                             }
                         });
                     });
-                    var value = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
+                    const value = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
                     PWM_MAIN.getObject('value-' + inputID).value =  value['url'];
                 }(iter));
             }
 
-            inputID = keyName + '_' + iteration + "_";
             PWM_MAIN.addEventHandler('button-addLdap-' + inputID,'click',function(){
                 UILibrary.stringEditorDialog({
                     textarea: false,
                     title: 'Attribute Name',
                     completeFunction: function (newValue) {
-                        var currentSize = PWM_MAIN.JSLibrary.itemCount(value['ldapActions']);
+                        const currentSize = PWM_MAIN.JSLibrary.itemCount(value['ldapActions']);
                         value['ldapActions'].push(JSON.parse(JSON.stringify(ActionHandler.defaultLdapValue)));
                         value['ldapActions'][currentSize]['attributeName'] = newValue;
                         ActionHandler.write(keyName,function(){
@@ -305,7 +304,7 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
                     textarea: false,
                     title: 'URL',
                     completeFunction: function (newValue) {
-                        var currentSize = PWM_MAIN.JSLibrary.itemCount(value['webActions']);
+                        const currentSize = PWM_MAIN.JSLibrary.itemCount(value['webActions']);
                         value['webActions'].push(JSON.parse(JSON.stringify(ActionHandler.defaultWebValue)));
                         value['webActions'][currentSize]['url'] = newValue;
                         ActionHandler.write(keyName,function(){
@@ -319,11 +318,11 @@ ActionHandler.showActionsDialog = function(keyName, iteration) {
 };
 
 ActionHandler.addOrEditLdapAction = function(keyName, iteration, ldapActionIter) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + ldapActionIter;
-    var value = PWM_VAR['clientSettingCache'][keyName][iteration]['ldapActions'][ldapActionIter];
-    var titleText = 'LDAP options';
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + ldapActionIter;
+    const value = PWM_VAR['clientSettingCache'][keyName][iteration]['ldapActions'][ldapActionIter];
+    const titleText = 'LDAP options';
 
-    var bodyText = '<table class="noborder">';
+    let bodyText = '<table class="noborder">';
     bodyText += '<tr>';
     bodyText += '<td class="key">Attribute Name</td><td><input style="width:300px" class="configStringInput" type="text" id="input-' + inputID + '-attributeName' + '" value="' + value['attributeName'] + '"/></td>';
     bodyText += '</tr><tr>';
@@ -332,10 +331,10 @@ ActionHandler.addOrEditLdapAction = function(keyName, iteration, ldapActionIter)
     bodyText += '<tr>';
     bodyText += '<td class="key">Operation Type</td><td class="noborder"><select id="select-' + inputID + '-ldapMethod' + '">';
 
-    for (var optionItem in ActionHandler.ldapMethodOptions) {
-        var label = ActionHandler.ldapMethodOptions[optionItem]['label'];
-        var optionValue = ActionHandler.ldapMethodOptions[optionItem]['value'];
-        var selected = optionValue === value['ldapMethod'];
+    for (const optionItem in ActionHandler.ldapMethodOptions) {
+        const label = ActionHandler.ldapMethodOptions[optionItem]['label'];
+        const optionValue = ActionHandler.ldapMethodOptions[optionItem]['value'];
+        const selected = optionValue === value['ldapMethod'];
         bodyText += '<option value="' + optionValue + '"' + (selected ? ' selected' : '') + '>' + label + '</option>';
     }
     bodyText += '</td></tr>';
@@ -366,19 +365,19 @@ ActionHandler.addOrEditLdapAction = function(keyName, iteration, ldapActionIter)
 
 
 ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + webActionIter;
-    var value = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
-    var titleText = 'Web Service Options';
-    var showBody = value['method'] !== 'get' && value['method'] !== 'delete';
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + webActionIter;
+    const value = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
+    const titleText = 'Web Service Options';
+    const showBody = value['method'] !== 'get' && value['method'] !== 'delete';
 
-    var bodyText = '<table class="noborder">';
+    let bodyText = '<table class="noborder">';
     bodyText += '<tr>';
     bodyText += '<td class="key">HTTP Method</td><td class="noborder" ><select id="select-' + inputID + '-method">';
 
-    for (var optionItem in ActionHandler.httpMethodOptions) {
-        var label = ActionHandler.httpMethodOptions[optionItem]['label'];
-        var optionValue = ActionHandler.httpMethodOptions[optionItem]['value'];
-        var selected = optionValue === value['method'];
+    for (const optionItem in ActionHandler.httpMethodOptions) {
+        const label = ActionHandler.httpMethodOptions[optionItem]['label'];
+        const optionValue = ActionHandler.httpMethodOptions[optionItem]['value'];
+        const selected = optionValue === value['method'];
         bodyText += '<option value="' + optionValue + '"' + (selected ? ' selected' : '') + '>' + label + '</option>';
     }
     bodyText += '</td>';
@@ -424,7 +423,7 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
                 ActionHandler.showHeadersDialog(keyName,iteration, webActionIter);
             });
             PWM_MAIN.addEventHandler('select-' + inputID + '-method','change',function(){
-                var methodValue = PWM_MAIN.getObject('select-' + inputID + '-method').value;
+                const methodValue = PWM_MAIN.getObject('select-' + inputID + '-method').value;
                 if (methodValue === 'get') {
                     value['body'] = '';
                 }
@@ -455,7 +454,7 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
 
             PWM_MAIN.getObject('input-' + inputID + '-successStatus').value = value['successStatus'] ? value['successStatus'].join() : '';
             PWM_MAIN.addEventHandler('button-' + inputID + '-successStatus', 'click', function(){
-                var options = {};
+                const options = {};
                 options['regex'] = '[0-9]{3}';
                 options['title'] = 'Success Status Codes';
                 options['instructions'] = 'Enter the three digit HTTP status codes that will be considered a success if returned by the remote web service.';
@@ -465,7 +464,7 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
                     ActionHandler.write(keyName);
                     ActionHandler.addOrEditWebAction(keyName, iteration, webActionIter)
                 };
-                var values = 'successStatus' in value ? value['successStatus'] : [];
+                const values = 'successStatus' in value ? value['successStatus'] : [];
                 values.sort();
                 options['value'] = values;
                 UILibrary.stringArrayEditorDialog(options);
@@ -481,7 +480,7 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
             }
             if (value['certificates']) {
                 PWM_MAIN.addEventHandler('button-' + inputID + '-certDetail','click',function(){
-                    var extraData = JSON.stringify({iteration:iteration, webActionIter: webActionIter});
+                    let extraData = JSON.stringify({iteration:iteration, webActionIter: webActionIter, keyName:keyName});
                     PWM_CFGEDIT.executeSettingFunction(keyName, 'password.pwm.http.servlet.configeditor.function.ActionCertViewerFunction',
                         ActionHandler.showCertificateViewerDialog, extraData)
                 });
@@ -495,16 +494,16 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
                 });
             } else {
                 PWM_MAIN.addEventHandler('button-' + inputID + '-importCertificates','click',function() {
-                    var dataHandler = function(data) {
-                        var msgBody = '<div style="max-height: 400px; overflow-y: auto">' + data['successMessage'] + '</div>';
+                    const dataHandler = function(data) {
+                        const 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.readSetting(keyName, function(resultValue) {
                                     PWM_VAR['clientSettingCache'][keyName] = resultValue;
-                                    ActidonHandler.addOrEditWebAction(keyName,iteration,webActionIter)
+                                    ActionHandler.addOrEditWebAction(keyName,iteration,webActionIter)
                                 });
                             }});
                     };
-                    var extraData = {};
+                    const extraData = {};
                     extraData.iteration = iteration;
                     extraData.webActionIter = webActionIter;
                     PWM_CFGEDIT.executeSettingFunction(keyName, 'password.pwm.http.servlet.configeditor.function.ActionCertImportFunction', dataHandler, JSON.stringify(extraData));
@@ -516,17 +515,17 @@ ActionHandler.addOrEditWebAction = function(keyName, iteration, webActionIter) {
 };
 
 ActionHandler.showHeadersDialog = function(keyName, iteration, webActionIter) {
-    var settingValue = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
+    const settingValue = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter];
 
-    var inputID = 'value_' + keyName + '_' + iteration + "_webAction_" + webActionIter +  "_headers_";
+    const inputID = 'value_' + keyName + '_' + iteration + "_webAction_" + webActionIter +  "_headers_";
 
-    var bodyText = '';
+    let bodyText = '';
     bodyText += '<table class="noborder">';
     bodyText += '<tr><td><b>Name</b></td><td><b>Value</b></td></tr>';
-    for (var iter in settingValue['headers']) {
+    for (const iter in settingValue['headers']) {
         (function(headerName) {
-            var value = settingValue['headers'][headerName];
-            var optionID = inputID + headerName;
+            const value = settingValue['headers'][headerName];
+            const optionID = inputID + headerName;
             bodyText += '<tr><td class="border">' + headerName + '</td><td class="border">' + value + '</td>';
             bodyText += '<td style="width:15px;"><span class="delete-row-icon action-icon pwm-icon pwm-icon-times" id="button-' + optionID + '-deleteRow"></span></td>';
             bodyText += '</tr>';
@@ -542,9 +541,9 @@ ActionHandler.showHeadersDialog = function(keyName, iteration, webActionIter) {
             ActionHandler.addOrEditWebAction(keyName,iteration,webActionIter);
         },
         loadFunction: function() {
-            for (var iter in settingValue['headers']) {
+            for (const iter in settingValue['headers']) {
                 (function(headerName) {
-                    var headerID = inputID + headerName;
+                    const headerID = inputID + headerName;
                     PWM_MAIN.addEventHandler('button-' + headerID + '-deleteRow', 'click', function () {
                         delete settingValue['headers'][headerName];
                         ActionHandler.write(keyName);
@@ -560,12 +559,12 @@ ActionHandler.showHeadersDialog = function(keyName, iteration, webActionIter) {
 };
 
 ActionHandler.addHeader = function(keyName, iteration, webActionIter) {
-    var body = '<table class="noborder">';
+    let body = '<table class="noborder">';
     body += '<tr><td>Name</td><td><input class="configStringInput" id="newHeaderName" style="width:300px"/></td></tr>';
     body += '<tr><td>Value</td><td><input class="configStringInput" id="newHeaderValue" style="width:300px"/></td></tr>';
     body += '</table>';
 
-    var updateFunction = function(){
+    const updateFunction = function(){
         PWM_MAIN.getObject('dialog_ok_button').disabled = true;
         PWM_VAR['newHeaderName'] = PWM_MAIN.getObject('newHeaderName').value;
         PWM_VAR['newHeaderValue'] = PWM_MAIN.getObject('newHeaderValue').value;
@@ -587,7 +586,7 @@ ActionHandler.addHeader = function(keyName, iteration, webActionIter) {
             });
             updateFunction();
         },okAction:function(){
-            var headers = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter]['headers'];
+            const headers = PWM_VAR['clientSettingCache'][keyName][iteration]['webActions'][webActionIter]['headers'];
             headers[PWM_VAR['newHeaderName']] = PWM_VAR['newHeaderValue'];
             ActionHandler.write(keyName);
             ActionHandler.showHeadersDialog(keyName, iteration, webActionIter);
@@ -597,15 +596,17 @@ ActionHandler.addHeader = function(keyName, iteration, webActionIter) {
     });
 };
 
-ActionHandler.showCertificateViewerDialog = function(data) {
-    var certInfos = data['data'];
-    var bodyText = '';
-    for (var i in certInfos) {
+ActionHandler.showCertificateViewerDialog = function(data,extraDataJson) {
+    let extraData = JSON.parse(extraDataJson)
+    let keyName = extraData['keyName'];
+    let certInfos = data['data'];
+    let bodyText = '';
+    for (const i in certInfos) {
         bodyText += X509CertificateHandler.certificateToHtml(certInfos[i],keyName,i);
     }
-    var cancelFunction = function(){ ActionHandler.addOrEditWebAction(keyName,iteration); };
-    var loadFunction = function(){
-        for (var i in certInfos) {
+    let cancelFunction = function(){ ActionHandler.addOrEditWebAction(keyName, extraData['iteration'], extraData['webActionIter']); };
+    let loadFunction = function(){
+        for (let i in certInfos) {
             X509CertificateHandler.certHtmlActions(certInfos[i],keyName,i);
         }
     };

+ 49 - 65
webapp/src/main/webapp/public/resources/js/configeditor-settings-challenges.js

@@ -22,17 +22,17 @@ var ChallengeSettingHandler = {};
 ChallengeSettingHandler.defaultItem = {text:'Question',minLength:4,maxLength:200,adminDefined:true,enforceWordlist:true,maxQuestionCharsInAnswer:3};
 
 ChallengeSettingHandler.init = function(settingKey) {
-    var parentDiv = "table_setting_" + settingKey;
+    const parentDiv = "table_setting_" + settingKey;
     console.log('ChallengeSettingHandler init for ' + settingKey);
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.readSetting(settingKey, function(resultValue) {
         PWM_VAR['clientSettingCache'][settingKey] = resultValue;
         if (PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
-            var htmlBody = '<button class="btn" id="button-addValue-' + settingKey + '">';
+            let htmlBody = '<button class="btn" id="button-addValue-' + settingKey + '">';
             htmlBody += '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Question';
             htmlBody += '</button>';
 
-            var parentDivElement = PWM_MAIN.getObject(parentDiv);
+            const parentDivElement = PWM_MAIN.getObject(parentDiv);
             parentDivElement.innerHTML = htmlBody;
 
             PWM_MAIN.addEventHandler('button-addValue-' + settingKey,'click',function(){
@@ -50,19 +50,19 @@ ChallengeSettingHandler.init = function(settingKey) {
 };
 
 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 policy settings.</div>';
+    const parentDiv = "table_setting_" + settingKey;
+    const resultValue = PWM_VAR['clientSettingCache'][settingKey];
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
+    let 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) {
+    for (const localeName in resultValue) {
         (function(localeKey) {
-            var multiValues = resultValue[localeKey];
-            var rowCount = PWM_MAIN.JSLibrary.itemCount(multiValues);
+            const multiValues = resultValue[localeKey];
+            const rowCount = PWM_MAIN.JSLibrary.itemCount(multiValues);
 
             bodyText += '<table class="noborder"><tr><td>';
             bodyText += '<table class="setting-challenge-question-summary">';
-            var localeLabel = localeName === '' ? 'Default Locale' : PWM_GLOBAL['localeInfo'][localeName] + " (" + localeName + ")";
+            const localeLabel = localeName === '' ? 'Default Locale' : PWM_GLOBAL['localeInfo'][localeName] + " (" + localeName + ")";
             if (PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]) > 1) {
                 bodyText += '<tr><td class="title" style="font-size:100%; font-weight:normal">' + localeLabel + '</td></tr>';
             }
@@ -70,8 +70,8 @@ ChallengeSettingHandler.draw = function(settingKey) {
             bodyText += '<tr>';
             bodyText += '<td style="width:100%" id="button-edit-' + settingKey + '-' + localeKey + '">';
             if (rowCount > 0) {
-                for (var iteration in multiValues) {
-                    var id = 'panel-value-' + settingKey + '-' + localeKey + '-' + iteration;
+                for (const iteration in multiValues) {
+                    const id = 'panel-value-' + settingKey + '-' + localeKey + '-' + iteration;
                     bodyText += '<div style="text-overflow:ellipsis; white-space:nowrap; overflow:hidden" id="' + id + '">text</div>';
                     bodyText += '<div style="font-size: 80%; font-style: italic">'
                         + '<span style="padding-left: 10px">Min Length: <span id="' + id + '-minLength"></span></span>'
@@ -94,7 +94,7 @@ ChallengeSettingHandler.draw = function(settingKey) {
     }
     parentDivElement.innerHTML = bodyText;
 
-    var addLocaleFunction = function(localeValue) {
+    const addLocaleFunction = function(localeValue) {
         if (localeValue in PWM_VAR['clientSettingCache'][settingKey]) {
             PWM_MAIN.showDialog({title:PWM_MAIN.showString('Title_Error'),text:'Locale <i>' + localeValue + '</i> is already present.'});
         } else {
@@ -105,26 +105,26 @@ ChallengeSettingHandler.draw = function(settingKey) {
             });
         }
     };
-    var tableElement = document.createElement("div");
+    const tableElement = document.createElement("div");
     parentDivElement.appendChild(tableElement);
 
     UILibrary.addAddLocaleButtonRow(tableElement, settingKey, addLocaleFunction, Object.keys(resultValue));
 
-    for (var localeName in resultValue) {
+    for (const localeName in resultValue) {
         (function(localeKey) {
             PWM_MAIN.addEventHandler('button-edit-' + settingKey + '-' + localeKey,'click',function(){
                 ChallengeSettingHandler.editLocale(settingKey,localeKey);
             });
 
-            var multiValues = resultValue[localeKey];
-            var rowCount = PWM_MAIN.JSLibrary.itemCount(multiValues);
+            const multiValues = resultValue[localeKey];
+            const rowCount = PWM_MAIN.JSLibrary.itemCount(multiValues);
             if (rowCount > 0) {
-                for (var iteration in multiValues) {
+                for (const iteration in multiValues) {
                     (function (rowKey) {
-                        var id = 'panel-value-' + settingKey + '-' + localeKey + '-' + iteration;
-                        var questionText = multiValues[rowKey]['text'];
-                        var adminDefined = multiValues[rowKey]['adminDefined'];
-                        var output = (adminDefined ? questionText : '[User Defined]');
+                        const id = 'panel-value-' + settingKey + '-' + localeKey + '-' + iteration;
+                        const questionText = multiValues[rowKey]['text'];
+                        const adminDefined = multiValues[rowKey]['adminDefined'];
+                        const output = (adminDefined ? questionText : '[User Defined]');
                         UILibrary.addTextValueToElement(id,output);
                         UILibrary.addTextValueToElement(id + '-minLength', multiValues[rowKey]['minLength']);
                         UILibrary.addTextValueToElement(id + '-maxLength', multiValues[rowKey]['maxLength']);
@@ -143,15 +143,15 @@ ChallengeSettingHandler.draw = function(settingKey) {
 };
 
 ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
-    var localeDisplay = localeKey === "" ? "Default" : localeKey;
+    const localeDisplay = localeKey === "" ? "Default" : localeKey;
 
-    var localeName = localeKey;
+    const localeName = localeKey;
 
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
 
-    var multiValues = resultValue[localeName];
+    const multiValues = resultValue[localeName];
 
-    var dialogBody = '';
+    let 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>'
@@ -160,7 +160,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
         + '</div>';
     dialogBody += '<div id="challengeLocaleDialogDiv" style="max-height:500px; overflow-x: auto">';
 
-    for (var iteration in multiValues) {
+    for (const iteration in multiValues) {
         (function(rowKey) {
 
 
@@ -169,7 +169,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
             dialogBody += '<table class="noborder" style="margin:0"><tr>';
             dialogBody += '<td colspan="200" style="border-width: 0;">';
 
-            var inputID = "value-" + keyName + "-" + localeName + "-" + rowKey;
+            const inputID = "value-" + keyName + "-" + localeName + "-" + rowKey;
             PWM_MAIN.clearDijitWidget(inputID);
 
             dialogBody += '<input class="configStringInput" id="' + inputID + '" style="width: 700px" required="required" disabled value="Loading"/>';
@@ -215,7 +215,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
     dialogBody += '</div>';
     dialogBody += '<br/>';
 
-    var dialogTitle = PWM_SETTINGS['settings'][keyName]['label'] + ' - ' + localeDisplay + ' Locale';
+    const 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 Question</button>',
@@ -227,28 +227,28 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
                 ChallengeSettingHandler.addRow(keyName,localeKey);
             });
 
-            var switchAllValues = function(settingType, settingValue) {
-                for (var iteration in multiValues) {
+            const switchAllValues = function(settingType, settingValue) {
+                for (const 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>';
+            const switchAllNumericValue = function(settingType, defaultValue, min, max) {
+                const dialogText = '<div>New Value <input type="number" id="newValue" value="' + defaultValue + '" min="' + min + '" max="' + max + '"></input></div>';
                 PWM_VAR['tempValue'] = defaultValue;
-                var loadFunction = function(){
+                const loadFunction = function(){
                     PWM_MAIN.addEventHandler('newValue','change',function(){
                         PWM_VAR['tempValue'] = PWM_MAIN.getObject('newValue').value;
                     })
                 };
-                var okAction = function() {
+                const okAction = function() {
                     switchAllValues(settingType,PWM_VAR['tempValue']);
                     PWM_MAIN.JSLibrary.removeFromArray(PWM_VAR, 'tempValue');
                     ChallengeSettingHandler.editLocale(keyName, localeKey);
                 };
-                var cancelAction = function() {
+                const cancelAction = function() {
                     ChallengeSettingHandler.editLocale(keyName, localeKey);
                 }
                 PWM_MAIN.showConfirmDialog({text:dialogText,loadFunction:loadFunction, okAction:okAction, cancelAction:cancelAction});
@@ -256,7 +256,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
 
             PWM_MAIN.addEventHandler('button-toggleWordlist-' + keyName + '-' + localeKey,'click',function(){
                 PWM_MAIN.showConfirmDialog({okAction:function(){
-                        var row0value = multiValues[0]['enforceWordlist'];
+                        const row0value = multiValues[0]['enforceWordlist'];
                         switchAllValues('enforceWordlist',!row0value);
                         ChallengeSettingHandler.editLocale(keyName, localeKey);
                     }
@@ -276,9 +276,9 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
 
 
 
-            for (var iteration in multiValues) {
+            for (const iteration in multiValues) {
                 (function(rowKey) {
-                    var inputID = "value-" + keyName + "-" + localeName + "-" + rowKey;
+                    const inputID = "value-" + keyName + "-" + localeName + "-" + rowKey;
                     UILibrary.manageNumericInput('button-minLength-' + inputID, function(value){
                         PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['minLength'] = value;
                     });
@@ -290,8 +290,8 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
                     });
 
                     // question text
-                    var processQuestion = function() {
-                        var isAdminDefined = multiValues[rowKey]['adminDefined'];
+                    const processQuestion = function() {
+                        const isAdminDefined = multiValues[rowKey]['adminDefined'];
                         PWM_MAIN.getObject(inputID).value = isAdminDefined ? multiValues[rowKey]['text'] : '[User Defined]';
                         PWM_MAIN.getObject(inputID).disabled = !isAdminDefined;
                     };
@@ -307,7 +307,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
                     PWM_MAIN.JSLibrary.setValueOfSelectElement('value-adminDefined-' + inputID, multiValues[rowKey]['adminDefined'] ? 'ADMIN' : 'USER');
 
                     PWM_MAIN.addEventHandler('value-adminDefined-' + inputID,'change',function(){
-                        var checked = PWM_MAIN.JSLibrary.readValueOfSelectElement('value-adminDefined-' + inputID) === 'ADMIN';
+                        const checked = PWM_MAIN.JSLibrary.readValueOfSelectElement('value-adminDefined-' + inputID) === 'ADMIN';
                         multiValues[rowKey]['adminDefined'] = checked;
                         processQuestion();
                     });
@@ -316,7 +316,7 @@ ChallengeSettingHandler.editLocale = function(keyName, localeKey) {
                     PWM_MAIN.getObject('value-wordlist-' + inputID).disabled = false;
                     PWM_MAIN.getObject('value-wordlist-' + inputID).checked = multiValues[rowKey]['enforceWordlist'];
                     PWM_MAIN.addEventHandler('value-wordlist-' + inputID,'change',function(){
-                        var checked = PWM_MAIN.getObject('value-wordlist-' + inputID).checked;
+                        const checked = PWM_MAIN.getObject('value-wordlist-' + inputID).checked;
                         multiValues[rowKey]['enforceWordlist'] = checked;
                     });
 
@@ -351,26 +351,10 @@ ChallengeSettingHandler.deleteLocale = function(keyName,localeKey) {
     });
 };
 
-ChallengeSettingHandler.toggleAdminDefinedRow = function(toggleElement,inputID,keyName,localeKey,rowKey) {
-    require(["dojo","dijit/registry"],function(dojo,registry){
-        var currentSetting = toggleElement.checked;
-        PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['adminDefined'] = currentSetting;
-        var inputElement = registry.byId(inputID);
-        if (currentSetting) {
-            inputElement.set('disabled',false);
-            inputElement.set('value','Question');
-        } else {
-            inputElement.set('disabled',true);
-            inputElement.set('value','[User Defined]');
-            PWM_VAR['clientSettingCache'][keyName][localeKey][rowKey]['text'] = '';
-        }
-    });
-};
-
 ChallengeSettingHandler.deleteRow = function(keyName, localeKey, rowName) {
-    var questionText = PWM_VAR['clientSettingCache'][keyName][localeKey][rowName]['text'];
-    var adminDefined = PWM_VAR['clientSettingCache'][keyName][localeKey][rowName]['adminDefined'];
-    var output = (adminDefined ? 'the question "' + questionText + '"': 'the [User Defined] question?');
+    const questionText = PWM_VAR['clientSettingCache'][keyName][localeKey][rowName]['text'];
+    const adminDefined = PWM_VAR['clientSettingCache'][keyName][localeKey][rowName]['adminDefined'];
+    const output = (adminDefined ? 'the question "' + questionText + '"': 'the [User Defined] question?');
     PWM_MAIN.showConfirmDialog({
         text: 'Are you sure you want to remove ' + output,
         okAction:function(){
@@ -387,7 +371,7 @@ ChallengeSettingHandler.deleteRow = function(keyName, localeKey, rowName) {
 ChallengeSettingHandler.addRow = function(keyName, localeKey) {
     PWM_MAIN.showWaitDialog({
         loadFunction:function(){
-            var newValues = PWM_MAIN.copyObject(ChallengeSettingHandler.defaultItem);
+            const newValues = PWM_MAIN.copyObject(ChallengeSettingHandler.defaultItem);
             PWM_VAR['clientSettingCache'][keyName][localeKey].push(newValues);
             ChallengeSettingHandler.write(keyName,function(){
                 PWM_MAIN.showDialog({title:PWM_MAIN.showString('Title_Success'),text:'Added new item to end of existing question list.',okAction:function(){

+ 48 - 47
webapp/src/main/webapp/public/resources/js/configeditor-settings-customlink.js

@@ -29,7 +29,7 @@ CustomLinkHandler.newRowValue = {
 
 CustomLinkHandler.init = function(keyName) {
     console.log('CustomLinkHandler init for ' + keyName);
-    var parentDiv = 'table_setting_' + keyName;
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.readSetting(keyName, function(resultValue) {
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
@@ -38,26 +38,27 @@ CustomLinkHandler.init = function(keyName) {
 };
 
 CustomLinkHandler.redraw = function(keyName) {
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
-    var parentDiv = 'table_setting_' + keyName;
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
-
-    parentDivElement.innerHTML = '<table class="noborder" style="margin-left: 0; width:auto" id="table-top-' + keyName + '"></table>';
-    parentDiv = 'table-top-' + keyName;
-    parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
+    {
+        const parentDiv = 'table_setting_' + keyName;
+        const parentDivElement = PWM_MAIN.getObject(parentDiv);
+        parentDivElement.innerHTML = '<table class="noborder" style="margin-left: 0; width:auto" id="table-top-' + keyName + '"></table>';
+    }
+    const parentDiv = 'table-top-' + keyName;
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
     if (!PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
-        var headerRow = document.createElement("tr");
-        var rowHtml = '<td>Name</td><td></td><td>Label</td>';
+        const headerRow = document.createElement("tr");
+        const rowHtml = '<td>Name</td><td></td><td>Label</td>';
         headerRow.innerHTML = rowHtml;
         parentDivElement.appendChild(headerRow);
     }
 
-    for (var i in resultValue) {
+    for (const i in resultValue) {
         CustomLinkHandler.drawRow(parentDiv, keyName, i, resultValue[i]);
     }
 
-    var buttonRow = document.createElement("tr");
+    const buttonRow = document.createElement("tr");
     buttonRow.setAttribute("colspan","5");
     buttonRow.innerHTML = '<td><button class="btn" id="button-' + keyName + '-addRow"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Item</button></td>';
 
@@ -70,15 +71,15 @@ CustomLinkHandler.redraw = function(keyName) {
 };
 
 CustomLinkHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
-        var itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
-        var inputID = 'value_' + settingKey + '_' + iteration + "_";
-        var options = PWM_SETTINGS['settings'][settingKey]['options'];
-        var properties = PWM_SETTINGS['settings'][settingKey]['properties'];
+        const itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
+        const inputID = 'value_' + settingKey + '_' + iteration + "_";
+        const options = PWM_SETTINGS['settings'][settingKey]['options'];
+        const properties = PWM_SETTINGS['settings'][settingKey]['properties'];
 
-        var newTableRow = document.createElement("tr");
+        const newTableRow = document.createElement("tr");
         newTableRow.setAttribute("style", "border-width: 0");
 
-        var htmlRow = '';
+        let htmlRow = '';
         htmlRow += '<td style="background: #f6f9f8; border:1px solid #dae1e1; width:180px"><div class="noWrapTextBox" id="panel-name-' + inputID + '" ></div></td>';
         htmlRow += '<td style="width:1px" id="icon-editLabel-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-edit"></span></td>';
         htmlRow += '<td style="background: #f6f9f8; border:1px solid #dae1e1; width:170px"><div style="" class="noWrapTextBox " id="' + inputID + 'label"><span>' + value['labels'][''] + '</span></div></td>';
@@ -99,7 +100,7 @@ CustomLinkHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
         htmlRow += '<td style="width:10px"><span class="delete-row-icon action-icon pwm-icon pwm-icon-times" id="' + inputID + '-deleteRowButton"></span></td>';
 
         newTableRow.innerHTML = htmlRow;
-        var parentDivElement = PWM_MAIN.getObject(parentDiv);
+        const parentDivElement = PWM_MAIN.getObject(parentDiv);
         parentDivElement.appendChild(newTableRow);
 
         UILibrary.addTextValueToElement("panel-name-" + inputID,value['name']);
@@ -133,7 +134,7 @@ CustomLinkHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
 };
 
 CustomLinkHandler.write = function(settingKey, finishFunction) {
-    var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
+    const cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
@@ -141,7 +142,7 @@ CustomLinkHandler.removeRow = function(keyName, iteration) {
     PWM_MAIN.showConfirmDialog({
         text:'Are you sure you wish to delete this item?',
         okAction:function(){
-            var currentValues = PWM_VAR['clientSettingCache'][keyName];
+            const currentValues = PWM_VAR['clientSettingCache'][keyName];
             currentValues.splice(iteration,1);
             CustomLinkHandler.write(keyName,function(){
                 CustomLinkHandler.init(keyName);
@@ -151,7 +152,7 @@ CustomLinkHandler.removeRow = function(keyName, iteration) {
 };
 
 CustomLinkHandler.move = function(settingKey, moveUp, iteration) {
-    var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const currentValues = PWM_VAR['clientSettingCache'][settingKey];
     if (moveUp) {
         CustomLinkHandler.arrayMoveUtil(currentValues, iteration, iteration - 1);
     } else {
@@ -162,7 +163,7 @@ CustomLinkHandler.move = function(settingKey, moveUp, iteration) {
 };
 
 CustomLinkHandler.arrayMoveUtil = function(arr, fromIndex, toIndex) {
-    var element = arr[fromIndex];
+    const element = arr[fromIndex];
     arr.splice(fromIndex, 1);
     arr.splice(toIndex, 0, element);
 };
@@ -175,13 +176,13 @@ CustomLinkHandler.addRow = function(keyName) {
         regex:'^[a-zA-Z][a-zA-Z0-9-]*$',
         placeholder:'KeyName',
         completeFunction:function(value){
-            for (var i in PWM_VAR['clientSettingCache'][keyName]) {
+            for (const i in PWM_VAR['clientSettingCache'][keyName]) {
                 if (PWM_VAR['clientSettingCache'][keyName][i]['name'] === value) {
                     alert('key name already exists');
                     return;
                 }
             }
-            var currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
+            const currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1] = CustomLinkHandler.newRowValue;
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1].name = value;
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1].labels = {'':value};
@@ -193,27 +194,27 @@ CustomLinkHandler.addRow = function(keyName) {
 };
 
 CustomLinkHandler.showOptionsDialog = function(keyName, iteration) {
-    var type = PWM_VAR['clientSettingCache'][keyName][iteration]['type'];
-    var settings = PWM_SETTINGS['settings'][keyName];
-    var options = 'options' in PWM_SETTINGS['settings'][keyName] ? PWM_SETTINGS['settings'][keyName]['options'] : {};
+    const type = PWM_VAR['clientSettingCache'][keyName][iteration]['type'];
+    const settings = PWM_SETTINGS['settings'][keyName];
+    const options = 'options' in PWM_SETTINGS['settings'][keyName] ? PWM_SETTINGS['settings'][keyName]['options'] : {};
 
-    var inputID = 'value_' + keyName + '_' + iteration + '_';
-    var bodyText = '<div style="max-height: 500px; overflow-x: auto"><table class="noborder">';
+    const inputID = 'value_' + keyName + '_' + iteration + '_';
+    let bodyText = '<div style="max-height: 500px; overflow-x: auto"><table class="noborder">';
 
     bodyText += '<tr>';
-    var descriptionValue = PWM_VAR['clientSettingCache'][keyName][iteration]['description'][''];
+    const descriptionValue = PWM_VAR['clientSettingCache'][keyName][iteration]['description'][''];
     bodyText += '<td id="' + inputID + '-label-description" class="key" >Description</td><td>';
     bodyText += '<div class="noWrapTextBox" id="' + inputID + 'DescriptionValue"><span class="btn-icon pwm-icon pwm-icon-edit"></span><span>' + descriptionValue + '...</span></div>';
     bodyText += '</td>';
 
     bodyText += '</tr><tr>';
 
-    var customLinkUrl = PWM_VAR['clientSettingCache'][keyName][iteration]['customLinkUrl'];
+    const customLinkUrl = PWM_VAR['clientSettingCache'][keyName][iteration]['customLinkUrl'];
     bodyText += '<td id="' + inputID + '-Site-url" class="key" >Link URL</td><td>' +
         '<input placeholder="https://example.com" style="width: 350px;" type="url" class="key" id="' + inputID + 'SiteURL' + '" value="'+ customLinkUrl +'"/></td>';
     bodyText += '</tr><tr>';
 
-    var checkedValue = PWM_VAR['clientSettingCache'][keyName][iteration]['customLinkNewWindow'];
+    const checkedValue = PWM_VAR['clientSettingCache'][keyName][iteration]['customLinkNewWindow'];
     bodyText += '<td class="key" title="' + PWM_CONFIG.showString('Tooltip_Form_ShowInNewWindow') + '">Open link in new window</td><td><input type="checkbox" id="' + inputID + 'newWindow' + '" ';
     if(checkedValue) {
         bodyText += 'checked'
@@ -224,7 +225,7 @@ CustomLinkHandler.showOptionsDialog = function(keyName, iteration) {
 
     bodyText += '</table></div>';
 
-    var initDialogWidgets = function () {
+    const initDialogWidgets = function () {
 
         PWM_MAIN.addEventHandler(inputID + 'DescriptionValue', 'change', function () {
             CustomLinkHandler.showDescriptionDialog(keyName, iteration);
@@ -257,19 +258,19 @@ CustomLinkHandler.showOptionsDialog = function(keyName, iteration) {
 };
 
 CustomLinkHandler.showLabelDialog = function(keyName, iteration) {
-    var finishAction = function(){ CustomLinkHandler.redraw(keyName); };
-    var title = 'Label for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
+    const finishAction = function(){ CustomLinkHandler.redraw(keyName); };
+    const title = 'Label for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
     CustomLinkHandler.multiLocaleStringDialog(keyName, iteration, 'labels', finishAction, title);
 };
 
 CustomLinkHandler.multiLocaleStringDialog = function(keyName, iteration, settingType, finishAction, titleText) {
     require(["dijit/Dialog","dijit/form/Textarea","dijit/form/CheckBox"],function(){
-        var inputID = 'value_' + keyName + '_' + iteration + "_" + "label_";
-        var bodyText = '<table class="noborder" id="' + inputID + 'table">';
+        const inputID = 'value_' + keyName + '_' + iteration + "_" + "label_";
+        let bodyText = '<table class="noborder" id="' + inputID + 'table">';
         bodyText += '<tr>';
-        for (var localeName in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
-            var value = PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
-            var localeID = inputID + localeName;
+        for (const localeName in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
+            const value = PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
+            const localeID = inputID + localeName;
             bodyText += '<td>' + localeName + '</td>';
             bodyText += '<td><input style="width:420px" class="configStringInput" type="text" value="' + value + '" id="' + localeID + '-input"></input></td>';
             if (localeName !== '') {
@@ -286,12 +287,12 @@ CustomLinkHandler.multiLocaleStringDialog = function(keyName, iteration, setting
                 finishAction();
             },
             loadFunction:function(){
-                for (var iter in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
+                for (const iter in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
                     (function(localeName) {
-                        var localeID = inputID + localeName;
+                        const localeID = inputID + localeName;
                         PWM_MAIN.addEventHandler(localeID + '-input', 'input', function () {
-                            var inputElement = PWM_MAIN.getObject(localeID + '-input');
-                            var value = inputElement.value;
+                            const inputElement = PWM_MAIN.getObject(localeID + '-input');
+                            const value = inputElement.value;
                             PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName] = value;
                             CustomLinkHandler.write(keyName);
                         });
@@ -318,8 +319,8 @@ CustomLinkHandler.multiLocaleStringDialog = function(keyName, iteration, setting
 
 
 CustomLinkHandler.showDescriptionDialog = function(keyName, iteration) {
-    var finishAction = function(){ CustomLinkHandler.showOptionsDialog(keyName, iteration); };
-    var title = 'Description for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
+    const finishAction = function(){ CustomLinkHandler.showOptionsDialog(keyName, iteration); };
+    const title = 'Description for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
     CustomLinkHandler.multiLocaleStringDialog(keyName, iteration, 'description', finishAction, title);
 };
 

+ 21 - 21
webapp/src/main/webapp/public/resources/js/configeditor-settings-email.js

@@ -38,28 +38,28 @@ EmailTableHandler.init = function(keyName) {
 };
 
 EmailTableHandler.draw = function(settingKey) {
-    var resultValue = PWM_VAR['clientSettingCache'][settingKey];
-    var parentDiv = 'table_setting_' + settingKey;
+    const resultValue = PWM_VAR['clientSettingCache'][settingKey];
+    const parentDiv = 'table_setting_' + settingKey;
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.clearDivElements(parentDiv, false);
 
-    var htmlBody = '';
-    for (var localeName in resultValue) {
+    let htmlBody = '';
+    for (const localeName in resultValue) {
         htmlBody += EmailTableHandler.drawRowHtml(settingKey,localeName)
     }
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
     parentDivElement.innerHTML = htmlBody;
 
-    for (var localeName in resultValue) {
+    for (const localeName in resultValue) {
         EmailTableHandler.instrumentRow(settingKey,localeName)
     }
 
     if (PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
-        var htmlBody = '<button class="btn" id="button-addValue-' + settingKey + '">';
+        let htmlBody = '<button class="btn" id="button-addValue-' + settingKey + '">';
         htmlBody += '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Value';
         htmlBody += '</button>';
 
-        var parentDivElement = PWM_MAIN.getObject(parentDiv);
+        const parentDivElement = PWM_MAIN.getObject(parentDiv);
         parentDivElement.innerHTML = htmlBody;
 
         PWM_MAIN.addEventHandler('button-addValue-' + settingKey,'click',function(){
@@ -67,7 +67,7 @@ EmailTableHandler.draw = function(settingKey) {
         });
 
     } else {
-        var addLocaleFunction = function(localeValue) {
+        const addLocaleFunction = function(localeValue) {
             if (!PWM_VAR['clientSettingCache'][settingKey][localeValue]) {
                 PWM_VAR['clientSettingCache'][settingKey][localeValue] = EmailTableHandler.defaultValue;
                 EmailTableHandler.writeSetting(settingKey,true);
@@ -78,15 +78,15 @@ EmailTableHandler.draw = function(settingKey) {
 };
 
 EmailTableHandler.drawRowHtml = function(settingKey, localeName) {
-    var localeLabel = localeName === '' ? 'Default Locale' : PWM_GLOBAL['localeInfo'][localeName] + " (" + localeName + ")";
-    var idPrefix = "setting-" + localeName + "-" + settingKey;
-    var htmlBody = '';
+    const localeLabel = localeName === '' ? 'Default Locale' : PWM_GLOBAL['localeInfo'][localeName] + " (" + localeName + ")";
+    const idPrefix = "setting-" + localeName + "-" + settingKey;
+    let htmlBody = '';
     htmlBody += '<table class="noborder" style=""><tr ><td class="noborder" style="max-width: 440px">';
     htmlBody += '<table>';
     if (PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]) > 1) {
         htmlBody += '<tr><td colspan="5" class="title" style="font-size:100%; font-weight:normal">' + localeLabel + '</td></tr>';
     }
-    var outputFunction = function (labelText, typeText) {
+    const outputFunction = function (labelText, typeText) {
         htmlBody += '<tr><td style="text-align:right; border-width:0;">' + labelText + '</td>';
         htmlBody += '<td id="button-' + typeText + '-' + idPrefix + '" style="border-width:0; width: 15px"><span class="pwm-icon pwm-icon-edit"/></ta>';
         htmlBody += '<td style=""><div class="configStringPanel" id="panel-' + typeText + '-' + idPrefix + '"></div></td>';
@@ -108,7 +108,7 @@ EmailTableHandler.drawRowHtml = function(settingKey, localeName) {
 
 
 EmailTableHandler.instrumentRow = function(settingKey, localeName) {
-    var idPrefix = "setting-" + localeName + "-" + settingKey;
+    const idPrefix = "setting-" + localeName + "-" + settingKey;
 
     UILibrary.addTextValueToElement('panel-to-' + idPrefix,PWM_VAR['clientSettingCache'][settingKey][localeName]['to']);
     PWM_MAIN.addEventHandler('button-to-' + idPrefix,'click',function(){ EmailTableHandler.editor(settingKey,localeName,false,'to',PWM_CONFIG.showString('Instructions_Edit_Email')); });
@@ -139,12 +139,12 @@ EmailTableHandler.instrumentRow = function(settingKey, localeName) {
 };
 
 EmailTableHandler.htmlEditorChoice = function(settingKey,localeName,type) {
-    var  dialogBody = '';
+    let  dialogBody = '';
     dialogBody += '<div>You can use either the HTML or plaintext editor to modify the HTML email body.</div>';
     dialogBody += '<div class="buttonbar"><button class="btn" id="btn-editor-plain">Plain</button>';
     dialogBody += '<button class="btn" id="btn-editor-html">HTML</button></div>';
 
-    var addEventHandlers = function(){
+    const addEventHandlers = function(){
         PWM_MAIN.addEventHandler('btn-editor-plain','click',function(){ EmailTableHandler.editor(settingKey,localeName,true,type); });
         PWM_MAIN.addEventHandler('btn-editor-html','click',function(){ EmailTableHandler.htmlBodyEditor(settingKey,localeName); });
     };
@@ -160,7 +160,7 @@ EmailTableHandler.htmlEditorChoice = function(settingKey,localeName,type) {
 
 
 EmailTableHandler.editor = function(settingKey, localeName, drawTextArea, type, instructions){
-    var settingData = PWM_SETTINGS['settings'][settingKey];
+    const settingData = PWM_SETTINGS['settings'][settingKey];
     UILibrary.stringEditorDialog({
         title:'Edit Value - ' + settingData['label'],
         instructions: instructions ? instructions : '',
@@ -178,9 +178,9 @@ EmailTableHandler.editor = function(settingKey, localeName, drawTextArea, type,
 
 EmailTableHandler.htmlBodyEditor = function(keyName, localeName) {
     // Grab the scope from the angular controller we created on the div element with ID: centerbody-config
-    var $scope = angular.element(document.getElementById("centerbody-config")).scope();
-    var idValue = keyName + "_" + localeName + "_htmlEditor";
-    var toolbarButtons =
+    const $scope = angular.element(document.getElementById("centerbody-config")).scope();
+    const idValue = keyName + "_" + localeName + "_htmlEditor";
+    const toolbarButtons =
         "[" +
         "['h1','h2','h3','h4','h5','h6','p','pre','quote']," +
         "['bold','italics','underline','strikeThrough','ul','ol','undo','redo','clear']," +
@@ -208,7 +208,7 @@ EmailTableHandler.htmlBodyEditor = function(keyName, localeName) {
 
 
 EmailTableHandler.writeSetting = function(settingKey, redraw) {
-    var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const currentValues = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, currentValues, function(){
         if (redraw) {
             EmailTableHandler.init(settingKey);

+ 83 - 82
webapp/src/main/webapp/public/resources/js/configeditor-settings-form.js

@@ -39,7 +39,7 @@ FormTableHandler.newRowValue = {
 
 FormTableHandler.init = function(keyName) {
     console.log('FormTableHandler init for ' + keyName);
-    var parentDiv = 'table_setting_' + keyName;
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.readSetting(keyName, function(resultValue) {
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
@@ -48,26 +48,27 @@ FormTableHandler.init = function(keyName) {
 };
 
 FormTableHandler.redraw = function(keyName) {
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
-    var parentDiv = 'table_setting_' + keyName;
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
-
-    parentDivElement.innerHTML = '<table class="noborder" style="margin-left: 0; width:auto" id="table-top-' + keyName + '"></table>';
-    parentDiv = 'table-top-' + keyName;
-    parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
+    {
+        const parentDiv = 'table_setting_' + keyName;
+        const parentDivElement = PWM_MAIN.getObject(parentDiv);
+        parentDivElement.innerHTML = '<table class="noborder" style="margin-left: 0; width:auto" id="table-top-' + keyName + '"></table>';
+    }
+    const parentDiv = 'table-top-' + keyName;
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
     if (!PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
-        var headerRow = document.createElement("tr");
-        var rowHtml = '<td>Name</td><td></td><td>Label</td>';
+        const headerRow = document.createElement("tr");
+        const rowHtml = '<td>Name</td><td></td><td>Label</td>';
         headerRow.innerHTML = rowHtml;
         parentDivElement.appendChild(headerRow);
     }
 
-    for (var i in resultValue) {
+    for (const i in resultValue) {
         FormTableHandler.drawRow(parentDiv, keyName, i, resultValue[i]);
     }
 
-    var buttonRow = document.createElement("tr");
+    const buttonRow = document.createElement("tr");
     buttonRow.setAttribute("colspan","5");
     buttonRow.innerHTML = '<td><button class="btn" id="button-' + keyName + '-addRow"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Item</button></td>';
 
@@ -80,27 +81,27 @@ FormTableHandler.redraw = function(keyName) {
 };
 
 FormTableHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
-    var itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
-    var inputID = 'value_' + settingKey + '_' + iteration + "_";
-    var options = PWM_SETTINGS['settings'][settingKey]['options'];
-    var properties = PWM_SETTINGS['settings'][settingKey]['properties'];
+    const itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
+    const inputID = 'value_' + settingKey + '_' + iteration + "_";
+    const options = PWM_SETTINGS['settings'][settingKey]['options'];
+    const properties = PWM_SETTINGS['settings'][settingKey]['properties'];
 
-    var newTableRow = document.createElement("tr");
+    const newTableRow = document.createElement("tr");
     newTableRow.setAttribute("style", "border-width: 0");
 
-    var htmlRow = '';
+    let htmlRow = '';
     htmlRow += '<td style="background: #f6f9f8; border:1px solid #dae1e1; width:180px"><div class="noWrapTextBox" id="panel-name-' + inputID + '" ></div></td>';
     htmlRow += '<td style="width:1px" id="icon-editLabel-' + inputID + '"><span class="btn-icon pwm-icon pwm-icon-edit"></span></td>';
     htmlRow += '<td style="background: #f6f9f8; border:1px solid #dae1e1; width:170px"><div style="" class="noWrapTextBox " id="' + inputID + 'label"><span>' + value['labels'][''] + '</span></div></td>';
 
-    var userDNtypeAllowed = options['type-userDN'] === 'show';
+    const userDNtypeAllowed = options['type-userDN'] === 'show';
     if (!PWM_MAIN.JSLibrary.isEmpty(options)) {
         htmlRow += '<td style="width:15px;">';
         htmlRow += '<select id="' + inputID + 'type">';
-        for (var optionItem in options) {
+        for (const optionItem in options) {
             //if (optionList[optionItem] !== 'userDN' || userDNtypeAllowed) {
-            var optionName = options[optionItem];
-            var selected = (optionName === PWM_VAR['clientSettingCache'][settingKey][iteration]['type']);
+            const optionName = options[optionItem];
+            const selected = (optionName === PWM_VAR['clientSettingCache'][settingKey][iteration]['type']);
             htmlRow += '<option value="' + optionName + '"' + (selected ? " selected" : "") + '>' + optionName + '</option>';
             //}
         }
@@ -108,7 +109,7 @@ FormTableHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
         htmlRow += '</td>';
     }
 
-    var hideOptions = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][settingKey]['flags'], 'Form_HideOptions');
+    const hideOptions = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][settingKey]['flags'], 'Form_HideOptions');
     if (!hideOptions) {
         htmlRow += '<td class="noborder" style="min-width:90px;"><button id="' + inputID + 'optionsButton"><span class="btn-icon pwm-icon pwm-icon-sliders"/> Options</button></td>';
     }
@@ -127,7 +128,7 @@ FormTableHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
     htmlRow += '<td style="width:10px"><span class="delete-row-icon action-icon pwm-icon pwm-icon-times" id="' + inputID + '-deleteRowButton"></span></td>';
 
     newTableRow.innerHTML = htmlRow;
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
     parentDivElement.appendChild(newTableRow);
 
     UILibrary.addTextValueToElement("panel-name-" + inputID,value['name']);
@@ -161,7 +162,7 @@ FormTableHandler.drawRow = function(parentDiv, settingKey, iteration, value) {
 };
 
 FormTableHandler.write = function(settingKey, finishFunction) {
-    var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
+    const cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
@@ -169,7 +170,7 @@ FormTableHandler.removeRow = function(keyName, iteration) {
     PWM_MAIN.showConfirmDialog({
         text:'Are you sure you wish to delete this item?',
         okAction:function(){
-            var currentValues = PWM_VAR['clientSettingCache'][keyName];
+            const currentValues = PWM_VAR['clientSettingCache'][keyName];
             currentValues.splice(iteration,1);
             FormTableHandler.write(keyName,function(){
                 FormTableHandler.init(keyName);
@@ -179,7 +180,7 @@ FormTableHandler.removeRow = function(keyName, iteration) {
 };
 
 FormTableHandler.move = function(settingKey, moveUp, iteration) {
-    var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const currentValues = PWM_VAR['clientSettingCache'][settingKey];
     if (moveUp) {
         FormTableHandler.arrayMoveUtil(currentValues, iteration, iteration - 1);
     } else {
@@ -190,7 +191,7 @@ FormTableHandler.move = function(settingKey, moveUp, iteration) {
 };
 
 FormTableHandler.arrayMoveUtil = function(arr, fromIndex, toIndex) {
-    var element = arr[fromIndex];
+    const element = arr[fromIndex];
     arr.splice(fromIndex, 1);
     arr.splice(toIndex, 0, element);
 };
@@ -202,13 +203,13 @@ FormTableHandler.addRow = function(keyName) {
         regex:'^[a-zA-Z][a-zA-Z0-9-]*$',
         placeholder:'FieldName',
         completeFunction:function(value){
-            for (var i in PWM_VAR['clientSettingCache'][keyName]) {
+            for (const i in PWM_VAR['clientSettingCache'][keyName]) {
                 if (PWM_VAR['clientSettingCache'][keyName][i]['name'] === value) {
                     alert('field already exists');
                     return;
                 }
             }
-            var currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
+            const currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1] = FormTableHandler.newRowValue;
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1].name = value;
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1].labels = {'':value};
@@ -220,23 +221,23 @@ FormTableHandler.addRow = function(keyName) {
 };
 
 FormTableHandler.showOptionsDialog = function(keyName, iteration) {
-    var type = PWM_VAR['clientSettingCache'][keyName][iteration]['type'];
-    var settings = PWM_SETTINGS['settings'][keyName];
-    var currentValue = PWM_VAR['clientSettingCache'][keyName][iteration];
-    var options = PWM_SETTINGS['settings'][keyName]['options'];
+    const type = PWM_VAR['clientSettingCache'][keyName][iteration]['type'];
+    const settings = PWM_SETTINGS['settings'][keyName];
+    const currentValue = PWM_VAR['clientSettingCache'][keyName][iteration];
+    const options = PWM_SETTINGS['settings'][keyName]['options'];
 
 
-    var hideStandardOptions = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_HideStandardOptions') || type === 'photo';
-    var showRequired = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowRequiredOption');
-    var showUnique = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowUniqueOption') && type !== 'photo';
-    var showReadOnly = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowReadOnlyOption');
-    var showMultiValue = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowMultiValueOption');
-    var showConfirmation = type !== 'checkbox' && type !== 'select' && type != 'photo' && !hideStandardOptions;
-    var showSource = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowSource');
+    const hideStandardOptions = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_HideStandardOptions') || type === 'photo';
+    const showRequired = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowRequiredOption');
+    const showUnique = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowUniqueOption') && type !== 'photo';
+    const showReadOnly = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowReadOnlyOption');
+    const showMultiValue = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowMultiValueOption');
+    const showConfirmation = type !== 'checkbox' && type !== 'select' && type != 'photo' && !hideStandardOptions;
+    const showSource = PWM_MAIN.JSLibrary.arrayContains(settings['flags'],'Form_ShowSource');
 
 
-    var inputID = 'value_' + keyName + '_' + iteration + "_";
-    var bodyText = '<div style="max-height: 500px; overflow-y: auto"><table class="noborder">';
+    const inputID = 'value_' + keyName + '_' + iteration + "_";
+    let bodyText = '<div style="max-height: 500px; overflow-y: auto"><table class="noborder">';
     if (!hideStandardOptions || type === 'photo') {
         bodyText += '<tr>';
         bodyText += '<td id="' + inputID + '-label-description" class="key" title="' + PWM_CONFIG.showString('Tooltip_FormOptions_Description') + '">Description</td><td>';
@@ -276,7 +277,7 @@ FormTableHandler.showOptionsDialog = function(keyName, iteration) {
             bodyText += '<td id="' + inputID + '-label-regex" class="key" title="' + PWM_CONFIG.showString('Tooltip_FormOptions_Regex') + '">Regular Expression</td><td><input type="text" class="configStringInput" style="width:300px" id="' + inputID + 'regex' + '"/></td>';
             bodyText += '</tr><tr>';
 
-            var regexErrorValue = currentValue['regexErrors'][''];
+            const regexErrorValue = currentValue['regexErrors'][''];
             bodyText += '<td id="' + inputID + '-label-regexError" class="key" title="' + PWM_CONFIG.showString('Tooltip_FormOptions_RegexError') + '">Regular Expression<br/>Error Message</td><td>';
             bodyText += '<div class="noWrapTextBox" id="' + inputID + 'regexErrors"><span class="btn-icon pwm-icon pwm-icon-edit"></span><span>' + regexErrorValue + '...</span></div>';
             bodyText += '</td>';
@@ -311,8 +312,8 @@ FormTableHandler.showOptionsDialog = function(keyName, iteration) {
 
     bodyText += '</table></div>';
 
-    var initFormElements = function() {
-        var currentValue = PWM_VAR['clientSettingCache'][keyName][iteration];
+    const initFormElements = function() {
+        const currentValue = PWM_VAR['clientSettingCache'][keyName][iteration];
 
 
         PWM_MAIN.addEventHandler(inputID + 'editOptionsButton', 'click', function(){
@@ -327,7 +328,7 @@ FormTableHandler.showOptionsDialog = function(keyName, iteration) {
             FormTableHandler.showDescriptionDialog(keyName, iteration);
         });
 
-        var descriptionValue = currentValue['description'][''];
+        const descriptionValue = currentValue['description'][''];
         UILibrary.addTextValueToElement(inputID + '-value', descriptionValue ? descriptionValue : "Edit");
 
         if (showRequired) {
@@ -414,10 +415,10 @@ FormTableHandler.showOptionsDialog = function(keyName, iteration) {
             });
         }
         if (showSource) {
-            var nodeID = inputID + 'source';
+            const nodeID = inputID + 'source';
             PWM_MAIN.JSLibrary.setValueOfSelectElement(nodeID,currentValue['source']);
             PWM_MAIN.addEventHandler(nodeID,'change',function(){
-                var newValue = PWM_MAIN.JSLibrary.readValueOfSelectElement(nodeID);
+                const newValue = PWM_MAIN.JSLibrary.readValueOfSelectElement(nodeID);
                 currentValue['source'] = newValue;
                 FormTableHandler.write(keyName);
             });
@@ -436,17 +437,17 @@ FormTableHandler.showOptionsDialog = function(keyName, iteration) {
 };
 
 FormTableHandler.showLabelDialog = function(keyName, iteration) {
-    var finishAction = function(){ FormTableHandler.redraw(keyName); };
-    var title = 'Label for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
+    const finishAction = function(){ FormTableHandler.redraw(keyName); };
+    const title = 'Label for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
     FormTableHandler.multiLocaleStringDialog(keyName, iteration, 'labels', finishAction, title);
 };
 
 FormTableHandler.multiLocaleStringDialog = function(keyName, iteration, settingType, finishAction, titleText) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + "label_";
-    var bodyText = '<table class="noborder" id="' + inputID + 'table">';
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + "label_";
+    let bodyText = '<table class="noborder" id="' + inputID + 'table">';
     bodyText += '<tr>';
-    for (var localeName in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
-        var localeID = inputID + localeName;
+    for (const localeName in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
+        const localeID = inputID + localeName;
         bodyText += '<td>' + localeName + '</td>';
         bodyText += '<td><input style="width:420px" class="configStringInput" type="text" id="' + localeID + '-input"></input></td>';
         if (localeName !== '') {
@@ -463,14 +464,14 @@ FormTableHandler.multiLocaleStringDialog = function(keyName, iteration, settingT
             finishAction();
         },
         loadFunction:function(){
-            for (var iter in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
+            for (const iter in PWM_VAR['clientSettingCache'][keyName][iteration][settingType]) {
                 (function(localeName) {
-                    var value = PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
-                    var localeID = inputID + localeName;
+                    const value = PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName];
+                    const localeID = inputID + localeName;
                     PWM_MAIN.getObject(localeID + '-input').value = value;
                     PWM_MAIN.addEventHandler(localeID + '-input', 'input', function () {
-                        var inputElement = PWM_MAIN.getObject(localeID + '-input');
-                        var value = inputElement.value;
+                        const inputElement = PWM_MAIN.getObject(localeID + '-input');
+                        const value = inputElement.value;
                         PWM_VAR['clientSettingCache'][keyName][iteration][settingType][localeName] = value;
                         FormTableHandler.write(keyName);
                     });
@@ -496,23 +497,23 @@ FormTableHandler.multiLocaleStringDialog = function(keyName, iteration, settingT
 
 
 FormTableHandler.showRegexErrorsDialog = function(keyName, iteration) {
-    var finishAction = function(){ FormTableHandler.showOptionsDialog(keyName, iteration); };
-    var title = 'Regular Expression Error Message for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
+    const finishAction = function(){ FormTableHandler.showOptionsDialog(keyName, iteration); };
+    const title = 'Regular Expression Error Message for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
     FormTableHandler.multiLocaleStringDialog(keyName, iteration, 'regexErrors', finishAction, title);
 };
 
 
 FormTableHandler.showSelectOptionsDialog = function(keyName, iteration) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + "selectOptions_";
-    var bodyText = '';
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + "selectOptions_";
+    let bodyText = '';
     bodyText += '<table class="noborder" id="' + inputID + 'table"">';
     bodyText += '<tr>';
     bodyText += '<td><b>Value</b></td><td><b>Display Name</b></td>';
     bodyText += '</tr><tr>';
-    for (var optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions']) {
+    for (const optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions']) {
         (function(counter) {
-            var value = PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions'][counter];
-            var optionID = inputID + counter;
+            const value = PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions'][counter];
+            const optionID = inputID + counter;
             bodyText += '<td>' + counter + '</td><td>' + value + '</td>';
             bodyText += '<td class="noborder" style="width:15px">';
             bodyText += '<span id="' + optionID + '-removeButton" class="delete-row-icon action-icon pwm-icon pwm-icon-times"></span>';
@@ -526,10 +527,10 @@ FormTableHandler.showSelectOptionsDialog = function(keyName, iteration) {
     bodyText += '<input class="configStringInput" style="width:200px" type="text" placeholder="Display Name" required id="addSelectOptionValue"/>';
     bodyText += '<button id="addSelectOptionButton"><span class="btn-icon pwm-icon pwm-icon-plus-square"/> Add</button>';
 
-    var initFormFields = function() {
-        for (var optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions']) {
+    const initFormFields = function() {
+        for (const optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['selectOptions']) {
             (function(counter) {
-                var optionID = inputID + counter;
+                const optionID = inputID + counter;
                 PWM_MAIN.addEventHandler(optionID + '-removeButton','click',function(){
                     FormTableHandler.removeSelectOptionsOption(keyName,iteration,counter);
                 });
@@ -537,8 +538,8 @@ FormTableHandler.showSelectOptionsDialog = function(keyName, iteration) {
         }
 
         PWM_MAIN.addEventHandler('addSelectOptionButton','click',function(){
-            var value = PWM_MAIN.getObject('addSelectOptionName').value;
-            var display = PWM_MAIN.getObject('addSelectOptionValue').value;
+            const value = PWM_MAIN.getObject('addSelectOptionName').value;
+            const display = PWM_MAIN.getObject('addSelectOptionValue').value;
             FormTableHandler.addSelectOptionsOption(keyName, iteration, value, display);
         });
     };
@@ -577,21 +578,21 @@ FormTableHandler.removeSelectOptionsOption = function(keyName, iteration, option
 };
 
 FormTableHandler.showDescriptionDialog = function(keyName, iteration) {
-    var finishAction = function(){ FormTableHandler.showOptionsDialog(keyName, iteration); };
-    var title = 'Description for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
+    const finishAction = function(){ FormTableHandler.showOptionsDialog(keyName, iteration); };
+    const title = 'Description for ' + PWM_VAR['clientSettingCache'][keyName][iteration]['name'];
     FormTableHandler.multiLocaleStringDialog(keyName, iteration, 'description', finishAction, title);
 };
 
 FormTableHandler.showMimeTypesDialog = function(keyName, iteration) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + "selectOptions_";
-    var bodyText = '';
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + "selectOptions_";
+    let bodyText = '';
     bodyText += '<table class="noborder" id="' + inputID + 'table"">';
     bodyText += '<tr>';
     bodyText += '</tr><tr>';
-    for (var optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes']) {
+    for (const optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes']) {
         (function(optionName) {
-            var value = PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes'][optionName];
-            var optionID = inputID + optionName;
+            const value = PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes'][optionName];
+            const optionID = inputID + optionName;
             bodyText += '<td><div class="noWrapTextBox">' + value + '</div></td>';
             bodyText += '<td class="noborder" style="">';
             bodyText += '<span id="' + optionID + '-removeButton" class="delete-row-icon action-icon pwm-icon pwm-icon-times"></span>';
@@ -612,9 +613,9 @@ FormTableHandler.showMimeTypesDialog = function(keyName, iteration) {
         }
     });
 
-    for (var optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes']) {
+    for (const optionName in PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes']) {
         (function(optionName) {
-            var optionID = inputID + optionName;
+            const optionID = inputID + optionName;
             PWM_MAIN.addEventHandler(optionID + '-removeButton','click',function(){
                 delete PWM_VAR['clientSettingCache'][keyName][iteration]['mimeTypes'][optionName];
                 FormTableHandler.write(keyName);
@@ -624,7 +625,7 @@ FormTableHandler.showMimeTypesDialog = function(keyName, iteration) {
     }
 
     PWM_MAIN.addEventHandler('addItemButton','click',function(){
-        var value = PWM_MAIN.getObject('addValue').value;
+        const value = PWM_MAIN.getObject('addValue').value;
 
         if (value === null || value.length < 1) {
             alert('Value field is required');

+ 32 - 32
webapp/src/main/webapp/public/resources/js/configeditor-settings-permissions.js

@@ -35,17 +35,17 @@ UserPermissionHandler.init = function(keyName) {
 };
 
 UserPermissionHandler.draw = function(keyName) {
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
-    var parentDiv = 'table_setting_' + keyName;
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
+    const parentDiv = 'table_setting_' + keyName;
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
     while (parentDivElement.firstChild) {
         parentDivElement.removeChild(parentDivElement.firstChild);
     }
 
-    var htmlBody = '';
+    let htmlBody = '';
     if (resultValue.length > 0) {
-        for (var iteration in resultValue) {
+        for (const iteration in resultValue) {
             (function (rowKey) {
                 if (htmlBody.length > 0) {
                     htmlBody += '<br/><br/><div style="clear:both; text-align:center">OR</span></div>'
@@ -60,7 +60,7 @@ UserPermissionHandler.draw = function(keyName) {
     htmlBody += '<button class="btn" id="button-' + keyName + '-addPermission">'
         + '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>' + PWM_CONFIG.showString('Button_AddPermission') + '</button>';
 
-    var hideMatch = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'Permission_HideMatch')
+    const hideMatch = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'Permission_HideMatch')
         || resultValue.length === 0;
     if (!hideMatch) {
         htmlBody += '<button id="button-' + keyName + '-viewMatches" class="btn">'
@@ -69,15 +69,15 @@ UserPermissionHandler.draw = function(keyName) {
 
     parentDivElement.innerHTML = htmlBody;
 
-    for (var iteration in resultValue) {
+    for (const iteration in resultValue) {
         (function(rowKey) {
             UserPermissionHandler.addRowHandlers(resultValue, keyName, rowKey);
         }(iteration));
     }
 
     PWM_MAIN.addEventHandler('button-' + keyName + '-viewMatches','click',function(){
-        var dataHandler = function(data) {
-            var html = PWM_CONFIG.convertListOfIdentitiesToHtml(data['data']);
+        const dataHandler = function(data) {
+            const html = PWM_CONFIG.convertListOfIdentitiesToHtml(data['data']);
             PWM_MAIN.showDialog({title:'Matches',text:html,dialogClass:'wide',showOk:false,showClose:true});
         };
         PWM_CFGEDIT.executeSettingFunction(keyName, 'password.pwm.http.servlet.configeditor.function.UserMatchViewerFunction', dataHandler, null)
@@ -89,11 +89,11 @@ UserPermissionHandler.draw = function(keyName) {
 };
 
 UserPermissionHandler.drawRow = function(keyName, resultValue, rowKey) {
-    var inputID = "value-" + keyName + "-" + rowKey;
-    var type = resultValue[rowKey]['type'];
+    const inputID = "value-" + keyName + "-" + rowKey;
+    const type = resultValue[rowKey]['type'];
 
-    var htmlBody = '<div class="setting_item_value_wrapper" style="float:left; width: 560px;">';
-    var profileLabelKey = (type === 'ldapAllUsers') ? 'Setting_Permission_Profile_AllUsers' : 'Setting_Permission_Profile';
+    let htmlBody = '<div class="setting_item_value_wrapper" style="float:left; width: 560px;">';
+    const profileLabelKey = (type === 'ldapAllUsers') ? 'Setting_Permission_Profile_AllUsers' : 'Setting_Permission_Profile';
 
     htmlBody += '<table class="noborder">'
         + '<tr><td style="width:200px" id="' + inputID + '_profileHeader' + '">' + PWM_CONFIG.showString(profileLabelKey) + '</td>'
@@ -119,7 +119,7 @@ UserPermissionHandler.drawRow = function(keyName, resultValue, rowKey) {
                 + '</tr>';
         }
 
-        var rowLabelKey = (type === 'ldapGroup') ? 'Setting_Permission_Base_Group' :
+        const rowLabelKey = (type === 'ldapGroup') ? 'Setting_Permission_Base_Group' :
             (type === 'ldapUser') ? 'Setting_Permission_Base_User' : 'Setting_Permission_Base'
         htmlBody += '<tr>'
             + '<td><span id="' + inputID + '_BaseHeader' + '">'
@@ -137,20 +137,20 @@ UserPermissionHandler.drawRow = function(keyName, resultValue, rowKey) {
 };
 
 UserPermissionHandler.addRowHandlers = function( resultValue, keyName, rowKey) {
-    var inputID = "value-" + keyName + "-" + rowKey;
+    const inputID = "value-" + keyName + "-" + rowKey;
 
-    var profileDataList = PWM_MAIN.getObject(inputID + "-datalist");
-    var profileIdList = PWM_SETTINGS['var']['ldapProfileIds'];
-    for (var i in profileIdList) {
-        var option = document.createElement('option');
+    const profileDataList = PWM_MAIN.getObject(inputID + "-datalist");
+    const profileIdList = PWM_SETTINGS['var']['ldapProfileIds'];
+    for (const i in profileIdList) {
+        const option = document.createElement('option');
         option.value = profileIdList[i];
         profileDataList.appendChild(option);
     }
 
-    var currentProfile = PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapProfileID'];
+    let currentProfile = PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapProfileID'];
     currentProfile = currentProfile === undefined ? '' : currentProfile;
-    var profileSelectNewValueFunction = function(newValue, writeNewValue) {
-        var allProfilesEnabled = !newValue || newValue === 'all' || newValue === '';
+    const profileSelectNewValueFunction = function(newValue, writeNewValue) {
+        const allProfilesEnabled = !newValue || newValue === 'all' || newValue === '';
         if (allProfilesEnabled) {
             PWM_MAIN.JSLibrary.setValueOfSelectElement(inputID + '-profileSelect', 'all');
             PWM_MAIN.addCssClass( inputID + '-profileWrapper', 'hidden');
@@ -180,7 +180,7 @@ UserPermissionHandler.addRowHandlers = function( resultValue, keyName, rowKey) {
 
     if (resultValue[rowKey]['type'] !== 'ldapGroup') {
         UILibrary.addTextValueToElement(inputID + '-query', PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapQuery']);
-        var queryEditor = function(){
+        const queryEditor = function(){
             UILibrary.stringEditorDialog({
                 value:PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapQuery'],
                 completeFunction:function(value) {
@@ -198,8 +198,8 @@ UserPermissionHandler.addRowHandlers = function( resultValue, keyName, rowKey) {
         });
     }
 
-    var currentBaseValue = ('ldapBase' in resultValue[rowKey]) ? resultValue[rowKey]['ldapBase'] : "";
-    var baseEditor = function(){
+    const currentBaseValue = ('ldapBase' in resultValue[rowKey]) ? resultValue[rowKey]['ldapBase'] : "";
+    const baseEditor = function(){
         UILibrary.editLdapDN(function(value, ldapProfileID) {
             PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapProfileID'] = ldapProfileID;
             PWM_VAR['clientSettingCache'][keyName][rowKey]['ldapBase'] = value;
@@ -216,8 +216,8 @@ UserPermissionHandler.addRowHandlers = function( resultValue, keyName, rowKey) {
         baseEditor();
     });
 
-    var deleteButtonID = 'button-' + inputID + '-deleteRow';
-    var hasID = PWM_MAIN.getObject(deleteButtonID) ? "YES" : "NO";
+    const deleteButtonID = 'button-' + inputID + '-deleteRow';
+    const hasID = PWM_MAIN.getObject(deleteButtonID) ? "YES" : "NO";
     console.log("addEventHandler row: " + deleteButtonID + " rowKey=" + rowKey + " hasID="+hasID);
     PWM_MAIN.addEventHandler(deleteButtonID,'click',function(){
         console.log("delete row: " + inputID + " rowKey=" + rowKey + " hasID="+hasID);
@@ -243,7 +243,7 @@ UserPermissionHandler.addRowHandlers = function( resultValue, keyName, rowKey) {
 }
 
 UserPermissionHandler.write = function(settingKey,redraw) {
-    var nextFunction = function(){
+    const nextFunction = function(){
         if (redraw) {
             UserPermissionHandler.draw(settingKey);
         }
@@ -252,8 +252,8 @@ UserPermissionHandler.write = function(settingKey,redraw) {
 };
 
 UserPermissionHandler.addPermission = function(keyName) {
-    var bodyHtml = '<div><p>' + PWM_CONFIG.showString('MenuDisplay_Permissions') + '</p></div><table class="">'
-    var hideGroup = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'Permission_HideGroups');
+    let bodyHtml = '<div><p>' + PWM_CONFIG.showString('MenuDisplay_Permissions') + '</p></div><table class="">'
+    const hideGroup = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'Permission_HideGroups');
     bodyHtml += '<tr><td><button class="btn" id="button-' + keyName + '-addAllUsersValue">'
         + '<span class="btn-icon pwm-icon pwm-icon-plus-square"></span>' + PWM_CONFIG.showString('MenuItem_Permission_AllUsers')
         + '</button></td><td>' + PWM_CONFIG.showString('MenuDisplay_Permission_AllUsers') + '</td></tr>';
@@ -271,13 +271,13 @@ UserPermissionHandler.addPermission = function(keyName) {
 
     bodyHtml += '</table>';
 
-    var completeAddPermission = function(template) {
+    const completeAddPermission = function(template) {
         PWM_VAR['clientSettingCache'][keyName].push(PWM_MAIN.copyObject(template));
         PWM_MAIN.closeWaitDialog();
         UserPermissionHandler.write(keyName, true);
     }
 
-    var dialogOptions = {};
+    const dialogOptions = {};
     dialogOptions.title = PWM_CONFIG.showString('Button_AddPermission');
     dialogOptions.text = bodyHtml;
     dialogOptions.showCancel = false;

+ 65 - 42
webapp/src/main/webapp/public/resources/js/configeditor-settings-remotewebservices.js

@@ -38,7 +38,7 @@ RemoteWebServiceHandler.httpMethodOptions = [
 
 RemoteWebServiceHandler.init = function(keyName) {
     console.log('RemoteWebServiceHandler init for ' + keyName);
-    var parentDiv = 'table_setting_' + keyName;
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, true);
     PWM_CFGEDIT.readSetting(keyName, function(resultValue) {
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
@@ -48,17 +48,17 @@ RemoteWebServiceHandler.init = function(keyName) {
 
 RemoteWebServiceHandler.redraw = function(keyName) {
     console.log('RemoteWebServiceHandler redraw for ' + keyName);
-    var resultValue = PWM_VAR['clientSettingCache'][keyName];
-    var parentDiv = 'table_setting_' + keyName;
+    const resultValue = PWM_VAR['clientSettingCache'][keyName];
+    const parentDiv = 'table_setting_' + keyName;
     PWM_CFGEDIT.clearDivElements(parentDiv, false);
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
-    var html = '';
+    let html = '';
     if (!PWM_MAIN.JSLibrary.isEmpty(resultValue)) {
         html += '<table class="noborder">';
         html += '<tr><td>Name</td><td>URL</td></tr>';
 
-        for (var loop in resultValue) {
+        for (const loop in resultValue) {
             (function (loop) {
                 html += RemoteWebServiceHandler.drawRow(keyName, loop, resultValue[loop]);
             })(loop);
@@ -67,15 +67,15 @@ RemoteWebServiceHandler.redraw = function(keyName) {
         html += '</table>';
     }
 
-    var rowCount = PWM_MAIN.JSLibrary.itemCount(resultValue);
-    var maxRowCount = PWM_SETTINGS['settings'][keyName]['properties']['Maximum'];
+    const rowCount = PWM_MAIN.JSLibrary.itemCount(resultValue);
+    const maxRowCount = PWM_SETTINGS['settings'][keyName]['properties']['Maximum'];
     if (maxRowCount > 0 && rowCount < maxRowCount) {
         html += '<br/><button class="btn" id="button-' + keyName + '-addValue"><span class="btn-icon pwm-icon pwm-icon-plus-square"></span>Add Service</button>';
     }
 
     parentDivElement.innerHTML = html;
 
-    for (var i in resultValue) {
+    for (const i in resultValue) {
         html += RemoteWebServiceHandler.addRowHandlers(keyName, i, resultValue[i]);
     }
 
@@ -85,12 +85,12 @@ RemoteWebServiceHandler.redraw = function(keyName) {
 };
 
 RemoteWebServiceHandler.drawRow = function(settingKey, iteration) {
-    var inputID = 'value_' + settingKey + '_' + iteration + "_";
+    const inputID = 'value_' + settingKey + '_' + iteration + "_";
 
-    var newTableRow = document.createElement("tr");
+    const newTableRow = document.createElement("tr");
     newTableRow.setAttribute("style", "border-width: 0");
 
-    var htmlRow = '<tr>';
+    let htmlRow = '<tr>';
     htmlRow += '<td class="border">';
     htmlRow += '<div class="noWrapTextBox" style="width:50px" id="display-' + inputID + '-name" ></div>';
     htmlRow += '</td><td>';
@@ -104,7 +104,7 @@ RemoteWebServiceHandler.drawRow = function(settingKey, iteration) {
 };
 
 RemoteWebServiceHandler.addRowHandlers = function(settingKey, iteration, value) {
-    var inputID = 'value_' + settingKey + '_' + iteration + "_";
+    const inputID = 'value_' + settingKey + '_' + iteration + "_";
     UILibrary.addTextValueToElement('display-' + inputID + '-name',value['name']);
     UILibrary.addTextValueToElement('display-' + inputID + '-url',value['url']);
     UILibrary.addTextValueToElement('display-' + inputID + '-description',value['description']);
@@ -118,7 +118,7 @@ RemoteWebServiceHandler.addRowHandlers = function(settingKey, iteration, value)
 };
 
 RemoteWebServiceHandler.write = function(settingKey, finishFunction) {
-    var cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
+    const cachedSetting = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, cachedSetting, finishFunction);
 };
 
@@ -142,7 +142,7 @@ RemoteWebServiceHandler.addRow = function(keyName) {
         instructions:'Please enter a descriptive name for the web service.',
         placeholder:'Name',
         completeFunction:function(value){
-            var currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
+            const currentSize = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][keyName]);
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1] = RemoteWebServiceHandler.defaultValue;
             PWM_VAR['clientSettingCache'][keyName][currentSize + 1].name = value;
 
@@ -159,23 +159,23 @@ RemoteWebServiceHandler.addRow = function(keyName) {
 };
 
 RemoteWebServiceHandler.showOptionsDialog = function(keyName, iteration) {
-    var inputID = 'value_' + keyName + '_' + iteration + "_";
-    var value = PWM_VAR['clientSettingCache'][keyName][iteration];
-    var titleText = 'Web Service options for ' + value['name'];
-    var bodyText = '<table class="noborder">';
+    const inputID = 'value_' + keyName + '_' + iteration + "_";
+    const value = PWM_VAR['clientSettingCache'][keyName][iteration];
+    const titleText = 'Web Service options for ' + value['name'];
+    let bodyText = '<table class="noborder">';
 
-    var hasMethodType = 'MethodType' in PWM_SETTINGS['settings'][keyName]['properties'];
-    var showBody = value['method'] !== 'get' && !(PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'WebService_NoBody'));
+    const hasMethodType = 'MethodType' in PWM_SETTINGS['settings'][keyName]['properties'];
+    const showBody = value['method'] !== 'get' && !(PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][keyName]['flags'], 'WebService_NoBody'));
 
     bodyText += '<tr>';
     bodyText += '<td class="key">HTTP Method</td><td class="noborder" ><select id="select-' + inputID + '-method"'
         + (hasMethodType ? ' disabled' : '')
         + '>';
 
-    for (var optionItem in RemoteWebServiceHandler.httpMethodOptions) {
-        var label = RemoteWebServiceHandler.httpMethodOptions[optionItem]['label'];
-        var optionValue = RemoteWebServiceHandler.httpMethodOptions[optionItem]['value'];
-        var selected = optionValue === value['method'];
+    for (const optionItem in RemoteWebServiceHandler.httpMethodOptions) {
+        const label = RemoteWebServiceHandler.httpMethodOptions[optionItem]['label'];
+        const optionValue = RemoteWebServiceHandler.httpMethodOptions[optionItem]['value'];
+        const selected = optionValue === value['method'];
         bodyText += '<option value="' + optionValue + '"' + (selected ? ' selected' : '') + '>' + label + '</option>';
     }
     bodyText += '</td>';
@@ -220,7 +220,7 @@ RemoteWebServiceHandler.showOptionsDialog = function(keyName, iteration) {
             });
 
             PWM_MAIN.addEventHandler('select-' + inputID + '-method','change',function(){
-                var methodValue = PWM_MAIN.getObject('select-' + inputID + '-method').value;
+                const methodValue = PWM_MAIN.getObject('select-' + inputID + '-method').value;
                 if (methodValue === 'get') {
                     value['body'] = '';
                 }
@@ -254,9 +254,10 @@ RemoteWebServiceHandler.showOptionsDialog = function(keyName, iteration) {
             });
             if (value['certificates']) {
                 PWM_MAIN.addEventHandler('button-' + inputID + '-certDetail','click',function(){
-                    var extraData = JSON.stringify({iteration:iteration});
+                    let extraData = JSON.stringify({iteration:iteration,keyName:keyName});
+                    debugger;
                     PWM_CFGEDIT.executeSettingFunction(keyName, 'password.pwm.http.servlet.configeditor.function.RemoteWebServiceCertViewerFunction',
-                        ActionHandler.showCertificateViewerDialog, extraData)
+                        RemoteWebServiceHandler.showCertificateViewerDialog, extraData)
 
                 });
                 PWM_MAIN.addEventHandler('button-' + inputID + '-clearCertificates','click',function() {
@@ -270,8 +271,8 @@ RemoteWebServiceHandler.showOptionsDialog = function(keyName, iteration) {
                 });
             } else {
                 PWM_MAIN.addEventHandler('button-' + inputID + '-importCertificates','click',function() {
-                    var dataHandler = function(data) {
-                        var msgBody = '<div style="max-height: 400px; overflow-y: auto">' + data['successMessage'] + '</div>';
+                    const dataHandler = function(data) {
+                        const 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.readSetting(keyName, function(resultValue) {
                                 PWM_VAR['clientSettingCache'][keyName] = resultValue;
@@ -290,16 +291,16 @@ RemoteWebServiceHandler.showOptionsDialog = function(keyName, iteration) {
 
 
 RemoteWebServiceHandler.showHeadersDialog = function(keyName, iteration) {
-    var settingValue = PWM_VAR['clientSettingCache'][keyName][iteration];
-    var inputID = 'value_' + keyName + '_' + iteration + "_" + "headers_";
+    const settingValue = PWM_VAR['clientSettingCache'][keyName][iteration];
+    const inputID = 'value_' + keyName + '_' + iteration + "_" + "headers_";
 
-    var bodyText = '';
+    let bodyText = '';
     bodyText += '<table class="noborder">';
     bodyText += '<tr><td><b>Name</b></td><td><b>Value</b></td></tr>';
-    for (var iter in settingValue['headers']) {
+    for (const iter in settingValue['headers']) {
         (function(headerName) {
-            var value = settingValue['headers'][headerName];
-            var optionID = inputID + headerName;
+            const value = settingValue['headers'][headerName];
+            const optionID = inputID + headerName;
             bodyText += '<tr><td class="border">' + headerName + '</td><td class="border">' + value + '</td>';
             bodyText += '<td style="width:15px;"><span class="delete-row-icon action-icon pwm-icon pwm-icon-times" id="button-' + optionID + '-deleteRow"></span></td>';
             bodyText += '</tr>';
@@ -315,9 +316,9 @@ RemoteWebServiceHandler.showHeadersDialog = function(keyName, iteration) {
             RemoteWebServiceHandler.showOptionsDialog(keyName,iteration);
         },
         loadFunction: function() {
-            for (var iter in settingValue['headers']) {
+            for (const iter in settingValue['headers']) {
                 (function(headerName) {
-                    var headerID = inputID + headerName;
+                    const headerID = inputID + headerName;
                     PWM_MAIN.addEventHandler('button-' + headerID + '-deleteRow', 'click', function () {
                         delete settingValue['headers'][headerName];
                         RemoteWebServiceHandler.write(keyName);
@@ -333,12 +334,12 @@ RemoteWebServiceHandler.showHeadersDialog = function(keyName, iteration) {
 };
 
 RemoteWebServiceHandler.addHeader = function(keyName, iteration) {
-    var body = '<table class="noborder">';
+    let body = '<table class="noborder">';
     body += '<tr><td>Name</td><td><input class="configStringInput" id="newHeaderName" style="width:300px"/></td></tr>';
     body += '<tr><td>Value</td><td><input class="configStringInput" id="newHeaderValue" style="width:300px"/></td></tr>';
     body += '</table>';
 
-    var updateFunction = function(){
+    const updateFunction = function(){
         PWM_MAIN.getObject('dialog_ok_button').disabled = true;
         PWM_VAR['newHeaderName'] = PWM_MAIN.getObject('newHeaderName').value;
         PWM_VAR['newHeaderValue'] = PWM_MAIN.getObject('newHeaderValue').value;
@@ -360,7 +361,7 @@ RemoteWebServiceHandler.addHeader = function(keyName, iteration) {
             });
             updateFunction();
         },okAction:function(){
-            var headers = PWM_VAR['clientSettingCache'][keyName][iteration]['headers'];
+            const headers = PWM_VAR['clientSettingCache'][keyName][iteration]['headers'];
             headers[PWM_VAR['newHeaderName']] = PWM_VAR['newHeaderValue'];
             RemoteWebServiceHandler.write(keyName);
             RemoteWebServiceHandler.showHeadersDialog(keyName, iteration);
@@ -368,5 +369,27 @@ RemoteWebServiceHandler.addHeader = function(keyName, iteration) {
             RemoteWebServiceHandler.showHeadersDialog(keyName, iteration);
         }
     });
+};
 
-};
+RemoteWebServiceHandler.showCertificateViewerDialog = function(data,extraDataJson) {
+    let extraData = JSON.parse(extraDataJson)
+    let keyName = extraData['keyName'];
+    let certInfos = data['data'];
+    let bodyText = '';
+    for (let i in certInfos) {
+        bodyText += X509CertificateHandler.certificateToHtml(certInfos[i],keyName,i);
+    }
+    let cancelFunction = function(){ RemoteWebServiceHandler.showOptionsDialog(keyName, extraData['iteration'])};
+    let loadFunction = function(){
+        for (let i in certInfos) {
+            X509CertificateHandler.certHtmlActions(certInfos[i],keyName,i);
+        }
+    };
+    PWM_MAIN.showDialog({
+        title:'Certificate Detail',
+        dialogClass: 'wide',
+        text:bodyText,
+        okAction:cancelFunction,
+        loadFunction:loadFunction
+    });
+};

+ 49 - 48
webapp/src/main/webapp/public/resources/js/configeditor-settings-stringarray.js

@@ -23,9 +23,11 @@ var StringArrayValueHandler = {};
 StringArrayValueHandler.init = function(keyName) {
     console.log('StringArrayValueHandler init for ' + keyName);
 
-    var parentDiv = 'table_setting_' + keyName;
-    PWM_MAIN.getObject(parentDiv).innerHTML = '<div id="tableTop_' + keyName + '">';
-    parentDiv = PWM_MAIN.getObject('tableTop_' + keyName);
+    {
+        const parentDiv = 'table_setting_' + keyName;
+        PWM_MAIN.getObject(parentDiv).innerHTML = '<div id="tableTop_' + keyName + '">';
+    }
+    const parentDiv = PWM_MAIN.getObject('tableTop_' + keyName);
 
     PWM_VAR['clientSettingCache'][keyName + "_options"] = PWM_VAR['clientSettingCache'][keyName + "_options"] || {};
     PWM_VAR['clientSettingCache'][keyName + "_options"]['parentDiv'] = parentDiv;
@@ -34,7 +36,7 @@ StringArrayValueHandler.init = function(keyName) {
         PWM_VAR['clientSettingCache'][keyName] = resultValue;
         StringArrayValueHandler.draw(keyName);
 
-        var syntax = PWM_SETTINGS['settings'][keyName]['syntax'];
+        const syntax = PWM_SETTINGS['settings'][keyName]['syntax'];
         if (syntax === 'PROFILE') {
             PWM_MAIN.getObject("resetButton-" + keyName).style.display = 'none';
             PWM_MAIN.getObject("helpButton-" + keyName).style.display = 'none';
@@ -45,43 +47,43 @@ StringArrayValueHandler.init = function(keyName) {
 
 
 StringArrayValueHandler.draw = function(settingKey) {
-    var parentDiv = PWM_VAR['clientSettingCache'][settingKey + "_options"]['parentDiv'];
-    var parentDivElement = PWM_MAIN.getObject(parentDiv);
+    const parentDiv = PWM_VAR['clientSettingCache'][settingKey + "_options"]['parentDiv'];
+    const parentDivElement = PWM_MAIN.getObject(parentDiv);
 
     PWM_CFGEDIT.clearDivElements(parentDiv, false);
-    var resultValue = PWM_VAR['clientSettingCache'][settingKey];
+    const resultValue = PWM_VAR['clientSettingCache'][settingKey];
 
-    var tableElement = document.createElement("table");
+    const tableElement = document.createElement("table");
     tableElement.setAttribute("style", "border-width: 0;");
 
-    var syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
+    const syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
     if (syntax === 'PROFILE') {
-        var divDescriptionElement = document.createElement("div");
-        var text = PWM_SETTINGS['settings'][settingKey]['description'];
+        const divDescriptionElement = document.createElement("div");
+        let text = PWM_SETTINGS['settings'][settingKey]['description'];
         text += '<br/>' + PWM_CONFIG.showString('Display_ProfileNamingRules');
         divDescriptionElement.innerHTML = text;
         parentDivElement.appendChild(divDescriptionElement);
 
-        var defaultProfileRow = document.createElement("tr");
+        const defaultProfileRow = document.createElement("tr");
         defaultProfileRow.setAttribute("colspan", "5");
     }
 
-    var counter = 0;
-    var itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
+    let counter = 0;
+    const itemCount = PWM_MAIN.JSLibrary.itemCount(PWM_VAR['clientSettingCache'][settingKey]);
     parentDivElement.appendChild(tableElement);
 
-    for (var i in resultValue) {
+    for (const i in resultValue) {
         (function(iteration) {
             StringArrayValueHandler.drawRow(settingKey, iteration, resultValue[iteration], itemCount, tableElement);
             counter++;
         })(i);
     }
 
-    var settingProperties = PWM_SETTINGS['settings'][settingKey]['properties'];
+    const settingProperties = PWM_SETTINGS['settings'][settingKey]['properties'];
     if (settingProperties && 'Maximum' in settingProperties && itemCount >= settingProperties['Maximum']) {
         // item count is already maxed out
     } else {
-        var addItemButton = document.createElement("button");
+        const addItemButton = document.createElement("button");
         addItemButton.setAttribute("type", "button");
         addItemButton.setAttribute("class", "btn");
         addItemButton.setAttribute("id", "button-" + settingKey + "-addItem");
@@ -95,44 +97,43 @@ StringArrayValueHandler.draw = function(settingKey) {
 };
 
 StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCount, parentDivElement) {
-    var settingInfo = PWM_SETTINGS['settings'][settingKey];
-    var settingProperties = PWM_SETTINGS['settings'][settingKey]['properties'];
-    var syntax = settingInfo['syntax'];
+    const settingInfo = PWM_SETTINGS['settings'][settingKey];
+    const settingProperties = PWM_SETTINGS['settings'][settingKey]['properties'];
+    const syntax = settingInfo['syntax'];
 
-    var inputID = 'value-' + settingKey + '-' + iteration;
+    const inputID = 'value-' + settingKey + '-' + iteration;
 
-    var valueRow = document.createElement("tr");
+    const valueRow = document.createElement("tr");
     valueRow.setAttribute("style", "border-width: 0");
     valueRow.setAttribute("id",inputID + "_row");
 
-    var rowHtml = '';
+    let rowHtml = '';
     if (syntax !== 'PROFILE') {
         rowHtml = '<td id="button-' + inputID + '" style="border-width:0; width: 15px"><span class="pwm-icon pwm-icon-edit"/></td>';
     }
     rowHtml += '<td style=""><div class="configStringPanel" id="' + inputID + '"></div></td>';
 
+    const copyButtonID = 'button-' + settingKey + '-' + iteration + '-copy';
     if (syntax === 'PROFILE') {
-        var copyButtonID = 'button-' + settingKey + '-' + iteration + '-copy';
         rowHtml += '<td class="noborder nopadding" style="width:10px" title="Copy">';
         rowHtml += '<span id="' + copyButtonID + '" class="action-icon pwm-icon pwm-icon-copy"></span>';
         rowHtml += '</td>';
     } else if (syntax === 'DOMAIN') {
-        var copyButtonID = 'button-' + settingKey + '-' + iteration + '-copy';
         rowHtml += '<td class="noborder nopadding" style="width:10px" title="Copy">';
         rowHtml += '<span id="' + copyButtonID + '" class="action-icon pwm-icon pwm-icon-copy"></span>';
         rowHtml += '</td>';
     }
 
-    var showMoveButtons = syntax !== 'DOMAIN';
+    const showMoveButtons = syntax !== 'DOMAIN';
+    const downButtonID = 'button-' + settingKey + '-' + iteration + '-moveDown';
+    const upButtonID = 'button-' + settingKey + '-' + iteration + '-moveUp';
     if ( showMoveButtons ) {
-        var downButtonID = 'button-' + settingKey + '-' + iteration + '-moveDown';
         rowHtml += '<td class="noborder nopadding" style="width:10px" title="Move Down">';
         if (itemCount > 1 && iteration !== (itemCount - 1)) {
             rowHtml += '<span id="' + downButtonID + '" class="action-icon pwm-icon pwm-icon-chevron-down"></span>';
         }
         rowHtml += '</td>';
 
-        var upButtonID = 'button-' + settingKey + '-' + iteration + '-moveUp';
         rowHtml += '<td class="noborder nopadding" style="width:10px" title="Move Up">';
         if (itemCount > 1 && iteration !== 0) {
             rowHtml += '<span id="' + upButtonID + '" class="action-icon pwm-icon pwm-icon-chevron-up"></span>';
@@ -140,9 +141,9 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
         rowHtml += '</td>';
     }
 
-    var showDeleteButtons = (itemCount > 1 || (!settingInfo['required'])) && (settingProperties['Minimum'] && itemCount > settingProperties['Minimum'])
+    const showDeleteButtons = (itemCount > 1 || (!settingInfo['required'])) && (settingProperties['Minimum'] && itemCount > settingProperties['Minimum'])
+    const deleteButtonID = 'button-' + settingKey + '-' + iteration + '-delete';
     if (showDeleteButtons) {
-        var deleteButtonID = 'button-' + settingKey + '-' + iteration + '-delete';
         rowHtml += '<td class="noborder nopadding" style="width:10px" title="Delete">';
         rowHtml += '<span id="' + deleteButtonID + '" class="delete-row-icon action-icon pwm-icon pwm-icon-times"></span>';
         rowHtml += '</td>';
@@ -151,22 +152,22 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
     valueRow.innerHTML = rowHtml;
     parentDivElement.appendChild(valueRow);
 
-    var allowEditValue = true;
+    let allowEditValue = true;
     if (syntax === 'PROFILE' || syntax === 'DOMAIN') {
         allowEditValue = false;
         PWM_MAIN.addEventHandler(copyButtonID, 'click', function () {
-            var editorOptions = {};
+            const editorOptions = {};
             editorOptions['title'] = syntax === 'PROFILE' ? 'Copy Profile' : 'Copy Domain';
             editorOptions['instructions'] = syntax === 'PROFILE' ? 'Copy profile and all profile settings from existing "' + value + '" profile to a new profile.' :
                 'Copy domain and all domain settings from existing "' + value + '" domain to a new domain.'
             editorOptions['regex'] = PWM_SETTINGS['settings'][settingKey]['pattern'];
             editorOptions['placeholder'] = PWM_SETTINGS['settings'][settingKey]['placeholder'];
             editorOptions['completeFunction'] = function (newValue) {
-                var options = {};
+                const options = {};
                 options['setting'] = settingKey;
                 options['sourceID'] = value;
                 options['destinationID'] = newValue;
-                var resultFunction = function (data) {
+                const resultFunction = function (data) {
                     if (data['error']) {
                         PWM_MAIN.showErrorDialog(data);
                     } else {
@@ -174,10 +175,10 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
                     }
                 };
 
-                var actionName = syntax === 'PROFILE' ? 'copyProfile' : 'copyDomain';
+                const actionName = syntax === 'PROFILE' ? 'copyProfile' : 'copyDomain';
                 PWM_MAIN.showWaitDialog({
                     loadFunction: function () {
-                        var url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction',actionName);
+                        const url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction',actionName);
                         PWM_MAIN.ajaxRequest(url, resultFunction, {content: options});
                     }
                 });
@@ -211,7 +212,7 @@ StringArrayValueHandler.drawRow = function(settingKey, iteration, value, itemCou
 };
 
 StringArrayValueHandler.valueHandler = function(settingKey, iteration) {
-    var okAction = function(value) {
+    const okAction = function(value) {
         if (iteration > -1) {
             PWM_VAR['clientSettingCache'][settingKey][iteration] = value;
         } else {
@@ -220,14 +221,14 @@ StringArrayValueHandler.valueHandler = function(settingKey, iteration) {
         StringArrayValueHandler.writeSetting(settingKey)
     };
 
-    var editorOptions = {};
+    const editorOptions = {};
     editorOptions['title'] = PWM_SETTINGS['settings'][settingKey]['label'] + " - " + (iteration > -1 ? "Edit" : "Add") + " Value";
     editorOptions['regex'] = PWM_SETTINGS['settings'][settingKey]['pattern'];
     editorOptions['placeholder'] = PWM_SETTINGS['settings'][settingKey]['placeholder'];
     editorOptions['completeFunction'] = okAction;
     editorOptions['value'] = iteration > -1 ? PWM_VAR['clientSettingCache'][settingKey][iteration] : '';
 
-    var isLdapDN = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][settingKey]['flags'],'ldapDNsyntax');
+    const isLdapDN = PWM_MAIN.JSLibrary.arrayContains(PWM_SETTINGS['settings'][settingKey]['flags'],'ldapDNsyntax');
     if (isLdapDN) {
         UILibrary.editLdapDN(okAction,{currentDN: editorOptions['value']});
     } else {
@@ -236,7 +237,7 @@ StringArrayValueHandler.valueHandler = function(settingKey, iteration) {
 };
 
 StringArrayValueHandler.move = function(settingKey, moveUp, iteration) {
-    var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const currentValues = PWM_VAR['clientSettingCache'][settingKey];
     if (moveUp) {
         StringArrayValueHandler.arrayMoveUtil(currentValues, iteration, iteration - 1);
     } else {
@@ -246,16 +247,16 @@ StringArrayValueHandler.move = function(settingKey, moveUp, iteration) {
 };
 
 StringArrayValueHandler.arrayMoveUtil = function(arr, fromIndex, toIndex) {
-    var element = arr[fromIndex];
+    const element = arr[fromIndex];
     arr.splice(fromIndex, 1);
     arr.splice(toIndex, 0, element);
 };
 
 StringArrayValueHandler.removeValue = function(settingKey, iteration) {
-    var syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
-    var profileName = PWM_VAR['clientSettingCache'][settingKey][iteration];
-    var deleteFunction = function() {
-        var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
+    const profileName = PWM_VAR['clientSettingCache'][settingKey][iteration];
+    const deleteFunction = function() {
+        const currentValues = PWM_VAR['clientSettingCache'][settingKey];
         currentValues.splice(iteration,1);
         StringArrayValueHandler.writeSetting(settingKey,false);
     };
@@ -279,8 +280,8 @@ StringArrayValueHandler.removeValue = function(settingKey, iteration) {
 };
 
 StringArrayValueHandler.writeSetting = function(settingKey, reload) {
-    var syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
-    var nextFunction = function() {
+    const syntax = PWM_SETTINGS['settings'][settingKey]['syntax'];
+    const nextFunction = function() {
         if (syntax === 'PROFILE') {
             PWM_MAIN.gotoUrl('editor');
         }
@@ -290,6 +291,6 @@ StringArrayValueHandler.writeSetting = function(settingKey, reload) {
             StringArrayValueHandler.draw(settingKey);
         }
     };
-    var currentValues = PWM_VAR['clientSettingCache'][settingKey];
+    const currentValues = PWM_VAR['clientSettingCache'][settingKey];
     PWM_CFGEDIT.writeSetting(settingKey, currentValues, nextFunction);
 };

Разлика између датотеке није приказан због своје велике величине
+ 281 - 292
webapp/src/main/webapp/public/resources/js/configeditor-settings.js


Разлика између датотеке није приказан због своје велике величине
+ 185 - 197
webapp/src/main/webapp/public/resources/js/configeditor.js


+ 9 - 0
webapp/src/main/webapp/public/resources/js/main.js

@@ -1308,6 +1308,15 @@ PWM_MAIN.JSLibrary.removeFromArray = function(array,element) {
     }
 };
 
+PWM_MAIN.JSLibrary.getParameterByName = function(name, url = window.location.href) {
+    name = name.replace(/[\[\]]/g, '\\$&');
+    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
+        results = regex.exec(url);
+    if (!results) return null;
+    if (!results[2]) return '';
+    return decodeURIComponent(results[2].replace(/\+/g, ' '));
+}
+
 PWM_MAIN.JSLibrary.readValueOfSelectElement = function(nodeID) {
     var element = PWM_MAIN.getObject(nodeID);
     if (element && element.options && element.selectedIndex >= 0) {

Неке датотеке нису приказане због велике количине промена