浏览代码

pom updates
ldap cert auto-import

Jason Rivard 6 年之前
父节点
当前提交
6619460e88
共有 22 个文件被更改,包括 237 次插入93 次删除
  1. 1 1
      docker/pom.xml
  2. 1 1
      onejar/pom.xml
  3. 6 6
      pom.xml
  4. 5 1
      pwm-cr/src/main/java/password/pwm/cr/ChaiXmlResponseSetSerializer.java
  5. 1 1
      server/pom.xml
  6. 1 0
      server/src/main/java/password/pwm/bean/SessionLabel.java
  7. 7 31
      server/src/main/java/password/pwm/config/function/LdapCertImportFunction.java
  8. 6 0
      server/src/main/java/password/pwm/config/profile/LdapProfile.java
  9. 2 1
      server/src/main/java/password/pwm/config/stored/ConfigurationProperty.java
  10. 1 1
      server/src/main/java/password/pwm/health/ConfigurationChecker.java
  11. 6 2
      server/src/main/java/password/pwm/health/LDAPHealthChecker.java
  12. 120 27
      server/src/main/java/password/pwm/http/ContextManager.java
  13. 3 1
      server/src/main/java/password/pwm/http/filter/ApplicationModeFilter.java
  14. 9 3
      server/src/main/java/password/pwm/http/servlet/resource/ResourceFileServlet.java
  15. 9 3
      server/src/main/java/password/pwm/http/tag/DisplayTag.java
  16. 3 1
      server/src/main/java/password/pwm/http/tag/ErrorMessageTag.java
  17. 3 1
      server/src/main/java/password/pwm/http/tag/url/PwmUrlTag.java
  18. 3 1
      server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java
  19. 4 1
      server/src/main/java/password/pwm/svc/intruder/DataStoreRecordStore.java
  20. 12 9
      server/src/main/java/password/pwm/util/PropertyConfigurationImporter.java
  21. 3 1
      server/src/main/java/password/pwm/util/java/JsonUtil.java
  22. 31 0
      server/src/main/java/password/pwm/util/secure/X509Utils.java

+ 1 - 1
docker/pom.xml

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

+ 1 - 1
onejar/pom.xml

@@ -17,7 +17,7 @@
 
     <properties>
         <project.root.basedir>${project.basedir}/..</project.root.basedir>
-        <tomcat.version>9.0.19</tomcat.version>
+        <tomcat.version>9.0.20</tomcat.version>
     </properties>
 
     <build>

+ 6 - 6
pom.xml

@@ -167,12 +167,12 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-checkstyle-plugin</artifactId>
-                <version>3.0.0</version>
+                <version>3.1.0</version>
                 <dependencies>
                     <dependency>
                         <groupId>com.puppycrawl.tools</groupId>
                         <artifactId>checkstyle</artifactId>
-                        <version>8.19</version>
+                        <version>8.20</version>
                     </dependency>
                 </dependencies>
                 <executions>
@@ -247,7 +247,7 @@
                     <dependency>
                         <groupId>com.github.spotbugs</groupId>
                         <artifactId>spotbugs</artifactId>
-                        <version>4.0.0-beta1</version>
+                        <version>4.0.0-beta2</version>
                     </dependency>
                 </dependencies>
                 <configuration>
@@ -268,7 +268,7 @@
             <plugin> <!-- checks owsp vulnerability database -->
                 <groupId>org.owasp</groupId>
                 <artifactId>dependency-check-maven</artifactId>
-                <version>5.0.0-M2</version>
+                <version>5.0.0-M3</version>
                 <executions>
                     <execution>
                         <goals>
@@ -285,13 +285,13 @@
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
-            <version>1.18.6</version>
+            <version>1.18.8</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.github.spotbugs</groupId>
             <artifactId>spotbugs-annotations</artifactId>
-            <version>4.0.0-beta1</version>
+            <version>4.0.0-beta2</version>
             <scope>provided</scope>
         </dependency>
 

+ 5 - 1
pwm-cr/src/main/java/password/pwm/cr/ChaiXmlResponseSetSerializer.java

@@ -276,12 +276,16 @@ public class ChaiXmlResponseSetSerializer
         final String salt = element.getAttribute( XML_ATTRIBUTE_SALT ) == null ? "" : element.getAttribute( XML_ATTRIBUTE_SALT ).getValue();
         final String hashCount = element.getAttribute( XML_ATTRIBUTE_HASH_COUNT ) == null ? "1" : element.getAttribute( XML_ATTRIBUTE_HASH_COUNT ).getValue();
         int saltCount = 1;
+
         try
         {
             saltCount = Integer.parseInt( hashCount );
         }
         catch ( NumberFormatException e )
-        { /* noop */ }
+        {
+            /* noop */
+        }
+
         final String formatStr = element.getAttributeValue( XML_ATTRIBUTE_CONTENT_FORMAT ) == null ? "" : element.getAttributeValue( XML_ATTRIBUTE_CONTENT_FORMAT );
 
         return StoredResponseItem.builder()

+ 1 - 1
server/pom.xml

@@ -292,7 +292,7 @@
         <dependency>
             <groupId>com.blueconic</groupId>
             <artifactId>browscap-java</artifactId>
-            <version>1.2.8</version>
+            <version>1.2.9</version>
         </dependency>
         <dependency>
             <groupId>org.jetbrains.xodus</groupId>

+ 1 - 0
server/src/main/java/password/pwm/bean/SessionLabel.java

@@ -41,6 +41,7 @@ public class SessionLabel implements Serializable
     public static final SessionLabel AUDITING_SESSION_LABEL = new SessionLabel( SESSION_LABEL_SESSION_ID, null, "auditing", null, null );
     public static final SessionLabel TELEMETRY_SESSION_LABEL = new SessionLabel( SESSION_LABEL_SESSION_ID, null, "telemetry", null, null );
     public static final SessionLabel PWNOTIFY_SESSION_LABEL = new SessionLabel( SESSION_LABEL_SESSION_ID, null, "pwnotify", null, null );
+    public static final SessionLabel CONTEXT_SESSION_LABEL = new SessionLabel( SESSION_LABEL_SESSION_ID, null, "context", null, null );
 
     private final String sessionID;
     private final UserIdentity userIdentity;

+ 7 - 31
server/src/main/java/password/pwm/config/function/LdapCertImportFunction.java

@@ -29,17 +29,12 @@ import password.pwm.config.SettingUIFunction;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.config.value.StringArrayValue;
 import password.pwm.config.value.X509CertificateValue;
-import password.pwm.error.ErrorInformation;
-import password.pwm.error.PwmError;
-import password.pwm.error.PwmException;
-import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmSession;
 import password.pwm.i18n.Message;
 import password.pwm.util.secure.X509Utils;
 
-import java.net.URI;
 import java.security.cert.X509Certificate;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -47,49 +42,30 @@ import java.util.Set;
 
 public class LdapCertImportFunction implements SettingUIFunction
 {
-
     @Override
     public String provideFunction(
             final PwmRequest pwmRequest,
             final StoredConfigurationImpl storedConfiguration,
             final PwmSetting setting,
             final String profile,
-            final String extraData )
-            throws PwmOperationalException, PwmUnrecoverableException
+            final String extraData
+    )
+            throws PwmUnrecoverableException
     {
         final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
         final PwmSession pwmSession = pwmRequest.getPwmSession();
 
         final StringArrayValue ldapUrlsValue = ( StringArrayValue ) storedConfiguration.readSetting( PwmSetting.LDAP_SERVER_URLS, profile );
         final Set<X509Certificate> resultCertificates = new LinkedHashSet<>();
-        try
-        {
-            if ( ldapUrlsValue != null && ldapUrlsValue.toNativeObject() != null )
-            {
-                final List<String> ldapUrlStrings = ldapUrlsValue.toNativeObject();
-                for ( final String ldapUrlString : ldapUrlStrings )
-                {
-                    final URI ldapURI = new URI( ldapUrlString );
-                    final List<X509Certificate> certs = X509Utils.readRemoteCertificates( ldapURI, pwmApplication.getConfig() );
-                    if ( certs != null )
-                    {
-                        resultCertificates.addAll( certs );
-                    }
-                }
-            }
-        }
-        catch ( Exception e )
+        if ( ldapUrlsValue != null && ldapUrlsValue.toNativeObject() != null )
         {
-            if ( e instanceof PwmException )
-            {
-                throw new PwmOperationalException( ( ( PwmException ) e ).getErrorInformation() );
-            }
-            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "error importing certificates: " + e.getMessage() );
-            throw new PwmOperationalException( errorInformation );
+            final List<String> ldapUrlStrings = ldapUrlsValue.toNativeObject();
+            resultCertificates.addAll( X509Utils.readCertsForListOfLdapUrls( ldapUrlStrings, pwmRequest.getConfig() ) );
         }
 
         final UserIdentity userIdentity = pwmSession.isAuthenticated() ? pwmSession.getUserInfo().getUserIdentity() : null;
         storedConfiguration.writeSetting( setting, profile, new X509CertificateValue( resultCertificates ), userIdentity );
         return Message.getLocalizedMessage( pwmSession.getSessionStateBean().getLocale(), Message.Success_Unknown, pwmApplication.getConfig() );
     }
+
 }

+ 6 - 0
server/src/main/java/password/pwm/config/profile/LdapProfile.java

@@ -96,6 +96,12 @@ public class LdapProfile extends AbstractProfile implements Profile
         return Collections.unmodifiableList( canonicalValues );
     }
 
+    public List<String> getLdapUrls(
+    )
+    {
+        return readSettingAsStringArray( PwmSetting.LDAP_SERVER_URLS );
+    }
+
     @Override
     public String getDisplayName( final Locale locale )
     {

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

@@ -30,7 +30,8 @@ public enum ConfigurationProperty
     NOTES( "notes" ),
     PASSWORD_HASH( "configPasswordHash" ),
     CONFIG_ON_START( "saveConfigOnStart" ),
-    MODIFIFICATION_TIMESTAMP( "modificationTimestamp" ),;
+    MODIFIFICATION_TIMESTAMP( "modificationTimestamp" ),
+    IMPORT_LDAP_CERTIFICATES( "importLdapCertificates" ),;
 
     private final String key;
 

+ 1 - 1
server/src/main/java/password/pwm/health/ConfigurationChecker.java

@@ -152,7 +152,7 @@ public class ConfigurationChecker implements HealthChecker
 
         for ( final LdapProfile ldapProfile : config.getLdapProfiles().values() )
         {
-            final List<String> ldapServerURLs = ldapProfile.readSettingAsStringArray( PwmSetting.LDAP_SERVER_URLS );
+            final List<String> ldapServerURLs = ldapProfile.getLdapUrls();
             if ( ldapServerURLs != null && !ldapServerURLs.isEmpty() )
             {
                 for ( final String urlStringValue : ldapServerURLs )

+ 6 - 2
server/src/main/java/password/pwm/health/LDAPHealthChecker.java

@@ -455,7 +455,9 @@ public class LDAPHealthChecker implements HealthChecker
                         chaiProvider.close();
                     }
                     catch ( Exception e )
-                    { /* ignore */ }
+                    {
+                        /* ignore */
+                    }
                 }
             }
         }
@@ -582,7 +584,9 @@ public class LDAPHealthChecker implements HealthChecker
                     chaiProvider.close();
                 }
                 catch ( Exception e )
-                { /* ignore */ }
+                {
+                    /* ignore */
+                }
             }
         }
 

+ 120 - 27
server/src/main/java/password/pwm/http/ContextManager.java

@@ -27,19 +27,26 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmConstants;
 import password.pwm.PwmEnvironment;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.Configuration;
+import password.pwm.config.PwmSetting;
+import password.pwm.config.StoredValue;
+import password.pwm.config.profile.LdapProfile;
 import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.ConfigurationReader;
 import password.pwm.config.stored.StoredConfigurationImpl;
+import password.pwm.config.value.X509CertificateValue;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
+import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.PropertyConfigurationImporter;
 import password.pwm.util.PwmScheduler;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.X509Utils;
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
@@ -51,11 +58,14 @@ import java.io.InputStream;
 import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.security.cert.X509Certificate;
 import java.time.Instant;
 import java.util.Collection;
 import java.util.Date;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -64,8 +74,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 public class ContextManager implements Serializable
 {
-
     private static final PwmLogger LOGGER = PwmLogger.forClass( ContextManager.class );
+    private static final SessionLabel SESSION_LABEL = SessionLabel.CONTEXT_SESSION_LABEL;
 
     private transient ServletContext servletContext;
     private transient ScheduledExecutorService taskMaster;
@@ -101,8 +111,6 @@ public class ContextManager implements Serializable
         final PwmApplication pwmApplication = getPwmApplication( request.getServletContext() );
         request.setAttribute( PwmConstants.REQUEST_ATTR_PWM_APPLICATION, pwmApplication );
         return pwmApplication;
-
-
     }
 
     public static PwmApplication getPwmApplication( final HttpSession session ) throws PwmUnrecoverableException
@@ -241,7 +249,7 @@ public class ContextManager implements Serializable
 
         {
             final String filename = configurationFile == null ? "null" : configurationFile.getAbsoluteFile().getAbsolutePath();
-            LOGGER.debug( () -> "configuration file was loaded from " + ( filename ) );
+            LOGGER.debug( SESSION_LABEL, () -> "configuration file was loaded from " + ( filename ) );
         }
 
         final Collection<PwmEnvironment.ApplicationFlag> applicationFlags = parameterReader.readApplicationFlags();
@@ -288,6 +296,8 @@ public class ContextManager implements Serializable
             }
 
             checkConfigForSaveOnRestart( configReader, pwmApplication );
+
+            checkConfigForAutoImportLdapCerts( configReader );
         }
 
         if ( pwmApplication == null || pwmApplication.getApplicationMode() == PwmApplicationMode.NEW )
@@ -295,7 +305,7 @@ public class ContextManager implements Serializable
             taskMaster.scheduleWithFixedDelay( new SilentPropertiesFileWatcher(), fileScanFrequencyMs, fileScanFrequencyMs, TimeUnit.MILLISECONDS );
         }
 
-        LOGGER.trace( () -> "initialization complete (" + TimeDuration.compactFromCurrent( startTime ) + ")" );
+        LOGGER.trace( SESSION_LABEL, () -> "initialization complete (" + TimeDuration.compactFromCurrent( startTime ) + ")" );
     }
 
     private void checkConfigForSaveOnRestart(
@@ -308,29 +318,48 @@ public class ContextManager implements Serializable
             return;
         }
 
-        final String saveConfigOnRestartStrValue = configReader.getStoredConfiguration().readConfigProperty(
-                ConfigurationProperty.CONFIG_ON_START );
-
-        if ( saveConfigOnRestartStrValue == null || !Boolean.parseBoolean( saveConfigOnRestartStrValue ) )
+        if ( !Boolean.parseBoolean( configReader.getStoredConfiguration().readConfigProperty( ConfigurationProperty.CONFIG_ON_START ) ) )
         {
             return;
         }
 
-        LOGGER.warn( "configuration file contains property \"" + ConfigurationProperty.CONFIG_ON_START + "\"=true, will save configuration and set property to false." );
+        LOGGER.warn( SESSION_LABEL, "configuration file contains property \""
+                + ConfigurationProperty.CONFIG_ON_START.getKey() + "\"=true, will save configuration and set property to false." );
 
         try
         {
             final StoredConfigurationImpl newConfig = StoredConfigurationImpl.copy( configReader.getStoredConfiguration() );
             newConfig.writeConfigProperty( ConfigurationProperty.CONFIG_ON_START, "false" );
-            configReader.saveConfiguration( newConfig, pwmApplication, null );
+            configReader.saveConfiguration( newConfig, pwmApplication, SESSION_LABEL );
             requestPwmApplicationRestart();
         }
         catch ( Exception e )
         {
-            LOGGER.error( "error while saving configuration file commanded by property \"" + ConfigurationProperty.CONFIG_ON_START + "\"=true, error: " + e.getMessage() );
+            LOGGER.error( SESSION_LABEL, "error while saving configuration file commanded by property \""
+                    + ConfigurationProperty.CONFIG_ON_START + "\"=true, error: " + e.getMessage() );
         }
     }
 
+    private void checkConfigForAutoImportLdapCerts(
+            final ConfigurationReader configReader
+    )
+    {
+        if ( configReader == null || configReader.getStoredConfiguration() == null )
+        {
+            return;
+        }
+
+        if ( !Boolean.parseBoolean( configReader.getStoredConfiguration().readConfigProperty( ConfigurationProperty.IMPORT_LDAP_CERTIFICATES ) ) )
+        {
+            return;
+        }
+
+        LOGGER.info( SESSION_LABEL, () -> "configuration file contains property \"" + ConfigurationProperty.IMPORT_LDAP_CERTIFICATES.getKey()
+                + "\"=true, will import attempt ldap certificate import every 5 seconds until successful" );
+        final long secondsDelay = 5;
+        taskMaster.scheduleWithFixedDelay( new AutoImportLdapCertJob(), secondsDelay, secondsDelay, TimeUnit.SECONDS );
+    }
+
     private void handleStartupError( final String msgPrefix, final Throwable throwable )
     {
         final String errorMsg;
@@ -352,7 +381,7 @@ public class ContextManager implements Serializable
 
         try
         {
-            LOGGER.fatal( startupErrorInformation.getDetailedErrorMsg() );
+            LOGGER.fatal( SESSION_LABEL, startupErrorInformation.getDetailedErrorMsg() );
         }
         catch ( Exception e2 )
         {
@@ -404,7 +433,7 @@ public class ContextManager implements Serializable
             {
                 if ( configReader.modifiedSinceLoad() )
                 {
-                    LOGGER.info( () -> "configuration file modification has been detected" );
+                    LOGGER.info( SESSION_LABEL, () -> "configuration file modification has been detected" );
                     requestPwmApplicationRestart();
                 }
             }
@@ -428,19 +457,19 @@ public class ContextManager implements Serializable
                 if ( silentPropertiesFile.exists() )
                 {
                     boolean success = false;
-                    LOGGER.info( () -> "file " + silentPropertiesFile.getAbsolutePath() + " has appeared, will import as configuration" );
+                    LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile.getAbsolutePath() + " has appeared, will import as configuration" );
                     try
                     {
                         final PropertyConfigurationImporter importer = new PropertyConfigurationImporter();
                         final StoredConfigurationImpl storedConfiguration = importer.readConfiguration( new FileInputStream( silentPropertiesFile ) );
-                        configReader.saveConfiguration( storedConfiguration, pwmApplication, null );
-                        LOGGER.info( () -> "file " + silentPropertiesFile.getAbsolutePath() + " has been successfully imported and saved as configuration file" );
+                        configReader.saveConfiguration( storedConfiguration, pwmApplication, SESSION_LABEL );
+                        LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile.getAbsolutePath() + " has been successfully imported and saved as configuration file" );
                         requestPwmApplicationRestart();
                         success = true;
                     }
                     catch ( Exception e )
                     {
-                        LOGGER.error( "error importing " + silentPropertiesFile.getAbsolutePath() + ", error: " + e.getMessage() );
+                        LOGGER.error( SESSION_LABEL, "error importing " + silentPropertiesFile.getAbsolutePath() + ", error: " + e.getMessage() );
                     }
 
                     final String appendValue = success ? ".imported" : ".error";
@@ -450,11 +479,11 @@ public class ContextManager implements Serializable
                     try
                     {
                         Files.move( source, dest );
-                        LOGGER.info( () -> "file " + source.toString() + " has been renamed to " + dest.toString() );
+                        LOGGER.info( SESSION_LABEL, () -> "file " + source.toString() + " has been renamed to " + dest.toString() );
                     }
                     catch ( IOException e )
                     {
-                        LOGGER.error( "error renaming file " + source.toString() + " to " + dest.toString() + ", error: " + e.getMessage() );
+                        LOGGER.error( SESSION_LABEL, "error renaming file " + source.toString() + " to " + dest.toString() + ", error: " + e.getMessage() );
                     }
                 }
             }
@@ -481,7 +510,7 @@ public class ContextManager implements Serializable
             if ( configReader != null && configReader.isSaveInProgress() )
             {
                 final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
-                LOGGER.info( () -> "delaying restart request due to in progress file save (" + timeDuration.asCompactString() + ")" );
+                LOGGER.info( SESSION_LABEL, () -> "delaying restart request due to in progress file save (" + timeDuration.asCompactString() + ")" );
                 taskMaster.schedule( new RestartFlagWatcher(), 1, TimeUnit.SECONDS );
                 return;
             }
@@ -497,7 +526,7 @@ public class ContextManager implements Serializable
 
                 {
                     final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
-                    LOGGER.info( () -> "beginning application restart (" + timeDuration.asCompactString() + "), restart count=" + restartCount.incrementAndGet() );
+                    LOGGER.info( SESSION_LABEL, () -> "beginning application restart (" + timeDuration.asCompactString() + "), restart count=" + restartCount.incrementAndGet() );
                 }
 
                 final Instant shutdownStartTime = Instant.now();
@@ -512,7 +541,7 @@ public class ContextManager implements Serializable
                     }
                     catch ( Exception e )
                     {
-                        LOGGER.error( "unexpected error attempting to close application: " + e.getMessage() );
+                        LOGGER.error( SESSION_LABEL, "unexpected error attempting to close application: " + e.getMessage() );
                     }
                 }
                 catch ( Exception e )
@@ -523,7 +552,7 @@ public class ContextManager implements Serializable
                 {
                     final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
                     final TimeDuration shutdownDuration = TimeDuration.fromCurrent( shutdownStartTime );
-                    LOGGER.info( () -> "application restart; shutdown completed, ("
+                    LOGGER.info( SESSION_LABEL, () -> "application restart; shutdown completed, ("
                             + shutdownDuration.asCompactString()
                             + ") now starting new application instance ("
                             + timeDuration.asCompactString() + ")" );
@@ -532,7 +561,7 @@ public class ContextManager implements Serializable
 
                 {
                     final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
-                    LOGGER.info( () -> "application restart completed (" + timeDuration.asCompactString() + ")" );
+                    LOGGER.info( SESSION_LABEL, () -> "application restart completed (" + timeDuration.asCompactString() + ")" );
                 }
             }
             finally
@@ -554,14 +583,14 @@ public class ContextManager implements Serializable
                 return;
             }
 
-            LOGGER.trace( () -> "waiting up to " + maxRequestWaitTime.asCompactString()
+            LOGGER.trace( SESSION_LABEL, () -> "waiting up to " + maxRequestWaitTime.asCompactString()
                     + " for " + startingRequestInProgress  + " requests to complete." );
             maxRequestWaitTime.pause( TimeDuration.of( 10, TimeDuration.Unit.MILLISECONDS ), () -> pwmApplication.getInprogressRequests().get() == 0
             );
 
             final int requestsInProgress = pwmApplication.getInprogressRequests().get();
             final TimeDuration waitTime = TimeDuration.fromCurrent( startTime  );
-            LOGGER.trace( () -> "after " + waitTime.asCompactString() + ", " + requestsInProgress
+            LOGGER.trace( SESSION_LABEL, () -> "after " + waitTime.asCompactString() + ", " + requestsInProgress
                     + " requests in progress, proceeding with restart" );
         }
     }
@@ -686,4 +715,68 @@ public class ContextManager implements Serializable
     {
         return contextPath;
     }
+
+
+
+    private class AutoImportLdapCertJob implements Runnable
+    {
+        @Override
+        public void run()
+        {
+            try
+            {
+                importLdapCert();
+            }
+            catch ( Exception e )
+            {
+                LOGGER.error( SESSION_LABEL, "error trying to auto-import certs: " + e.getMessage() );
+            }
+        }
+
+        private void importLdapCert() throws PwmUnrecoverableException, IOException, PwmOperationalException
+        {
+            LOGGER.trace( SESSION_LABEL, () -> "beginning auto-import ldap cert due to config property '"
+                    + ConfigurationProperty.IMPORT_LDAP_CERTIFICATES.getKey() + "'" );
+            final Configuration configuration = new Configuration( configReader.getStoredConfiguration() );
+            final StoredConfigurationImpl newStoredConfig = StoredConfigurationImpl.copy( configReader.getStoredConfiguration() );
+
+            int importedCerts = 0;
+            for ( final LdapProfile ldapProfile : configuration.getLdapProfiles().values() )
+            {
+                final List<String> ldapUrls = ldapProfile.getLdapUrls();
+                if ( !JavaHelper.isEmpty( ldapUrls ) )
+                {
+                    final Set<X509Certificate> certs = X509Utils.readCertsForListOfLdapUrls( ldapUrls, configuration );
+                    if ( !JavaHelper.isEmpty( certs ) )
+                    {
+                        importedCerts += certs.size();
+                        for ( final X509Certificate cert : certs )
+                        {
+                            LOGGER.trace( SESSION_LABEL, () -> "imported cert: " + X509Utils.makeDebugText( cert ) );
+                        }
+                        final StoredValue storedValue = new X509CertificateValue( certs );
+                        newStoredConfig.writeSetting( PwmSetting.LDAP_SERVER_CERTS, ldapProfile.getIdentifier(), storedValue, null );
+                    }
+
+                }
+            }
+
+            if ( importedCerts > 0 )
+            {
+                final int totalImportedCerts = importedCerts;
+                LOGGER.trace( SESSION_LABEL, () -> "completed auto-import ldap cert due to config property '"
+                        + ConfigurationProperty.IMPORT_LDAP_CERTIFICATES.getKey() + "'"
+                        + ", imported " + totalImportedCerts + " certificates" );
+                newStoredConfig.writeConfigProperty( ConfigurationProperty.IMPORT_LDAP_CERTIFICATES, "false" );
+                configReader.saveConfiguration( newStoredConfig, pwmApplication, SESSION_LABEL );
+                requestPwmApplicationRestart();
+            }
+            else
+            {
+                LOGGER.trace( SESSION_LABEL, () -> "unable to completed auto-import ldap cert due to config property '"
+                        + ConfigurationProperty.IMPORT_LDAP_CERTIFICATES.getKey() + "'"
+                        + ", no LDAP urls are configured" );
+            }
+        }
+    }
 }

+ 3 - 1
server/src/main/java/password/pwm/http/filter/ApplicationModeFilter.java

@@ -72,7 +72,9 @@ public class ApplicationModeFilter extends AbstractPwmFilter
                         LOGGER.error( e.getMessage() );
                     }
                     catch ( Exception ignore )
-                    { /* noop */ }
+                    {
+                        /* noop */
+                    }
                 }
                 pwmRequest.respondWithError( e.getErrorInformation(), true );
                 return;

+ 9 - 3
server/src/main/java/password/pwm/http/servlet/resource/ResourceFileServlet.java

@@ -160,7 +160,9 @@ public class ResourceFileServlet extends HttpServlet implements PwmServlet
                 pwmRequest.debugHttpRequestToLog( "returning HTTP 500 status" );
             }
             catch ( PwmUnrecoverableException e2 )
-            { /* noop */ }
+            {
+                /* noop */
+            }
             return;
         }
 
@@ -172,7 +174,9 @@ public class ResourceFileServlet extends HttpServlet implements PwmServlet
                 pwmRequest.debugHttpRequestToLog( "returning HTTP 404 status" );
             }
             catch ( PwmUnrecoverableException e )
-            { /* noop */ }
+            {
+                /* noop */
+            }
             return;
         }
 
@@ -373,7 +377,9 @@ public class ResourceFileServlet extends HttpServlet implements PwmServlet
                 pwmRequest.debugHttpRequestToLog( "returning HTTP 304 status" );
             }
             catch ( PwmUnrecoverableException e2 )
-            { /* noop */ }
+            {
+                /* noop */
+            }
             return true;
         }
 

+ 9 - 3
server/src/main/java/password/pwm/http/tag/DisplayTag.java

@@ -123,7 +123,9 @@ public class DisplayTag extends PwmAbstractTag
                 pwmRequest = PwmRequest.forRequest( ( HttpServletRequest ) pageContext.getRequest(), ( HttpServletResponse ) pageContext.getResponse() );
             }
             catch ( PwmException e )
-            { /* noop */ }
+            {
+                /* noop */
+            }
 
             final Locale locale = pwmRequest == null ? PwmConstants.DEFAULT_LOCALE : pwmRequest.getLocale();
 
@@ -165,14 +167,18 @@ public class DisplayTag extends PwmAbstractTag
             return Class.forName( bundle );
         }
         catch ( ClassNotFoundException e )
-        { /* no op */ }
+        {
+            /* no op */
+        }
 
         try
         {
             return Class.forName( Display.class.getPackage().getName() + "." + bundle );
         }
         catch ( ClassNotFoundException e )
-        { /* no op */ }
+        {
+            /* no op */
+        }
 
         return Display.class;
     }

+ 3 - 1
server/src/main/java/password/pwm/http/tag/ErrorMessageTag.java

@@ -58,7 +58,9 @@ public class ErrorMessageTag extends PwmAbstractTag
                 pwmApplication = ContextManager.getPwmApplication( pageContext.getRequest() );
             }
             catch ( PwmException e )
-            { /* noop */ }
+            {
+                /* noop */
+            }
 
             if ( pwmRequest == null || pwmApplication == null )
             {

+ 3 - 1
server/src/main/java/password/pwm/http/tag/url/PwmUrlTag.java

@@ -69,7 +69,9 @@ public class PwmUrlTag extends PwmAbstractTag
             pwmRequest = PwmRequest.forRequest( ( HttpServletRequest ) pageContext.getRequest(), ( HttpServletResponse ) pageContext.getResponse() );
         }
         catch ( PwmException e )
-        { /* noop */ }
+        {
+            /* noop */
+        }
 
         String workingUrl = url;
 

+ 3 - 1
server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java

@@ -155,7 +155,9 @@ public class UserSearchEngine implements PwmService
                 inputIdentity = UserIdentity.fromKey( username, pwmApplication );
             }
             catch ( PwmException e )
-            { /* input is not a userIdentity */ }
+            {
+                /* input is not a userIdentity */
+            }
 
             if ( inputIdentity != null )
             {

+ 4 - 1
server/src/main/java/password/pwm/svc/intruder/DataStoreRecordStore.java

@@ -98,7 +98,10 @@ class DataStoreRecordStore implements RecordStore
             dataStore.remove( key );
         }
         catch ( PwmDataStoreException e )
-        { /*noop*/ }
+        {
+            /*noop*/
+        }
+
         return null;
     }
 

+ 12 - 9
server/src/main/java/password/pwm/util/PropertyConfigurationImporter.java

@@ -66,9 +66,12 @@ public class PropertyConfigurationImporter
         ID_VAULT_LDAPS_PORT,
         ID_VAULT_ADMIN_LDAP,
         ID_VAULT_PASSWORD,
-        USER_CONTAINER,
+        UA_SERVER_HOST,
         UA_ADMIN,
 
+        SSPR_SERVER_HOST,
+        SSPR_SERVER_PORT,
+        USER_CONTAINER,
         SSO_SERVER_HOST,
         SSO_SERVER_SSL_PORT,
         SSO_SERVICE_PWD,
@@ -102,9 +105,11 @@ public class PropertyConfigurationImporter
         final StoredConfigurationImpl storedConfiguration = StoredConfigurationImpl.newStoredConfiguration( );
         storedConfiguration.initNewRandomSecurityKey( );
         storedConfiguration.writeConfigProperty( 
-                ConfigurationProperty.CONFIG_IS_EDITABLE, Boolean.toString( true ) );
+                ConfigurationProperty.CONFIG_IS_EDITABLE, Boolean.toString( false ) );
         storedConfiguration.writeConfigProperty( 
                 ConfigurationProperty.CONFIG_EPOCH, String.valueOf( 0 ) );
+        storedConfiguration.writeConfigProperty(
+                ConfigurationProperty.IMPORT_LDAP_CERTIFICATES, Boolean.toString( true ) );
 
         // static values
         storedConfiguration.writeSetting( PwmSetting.TEMPLATE_LDAP, new StringValue( 
@@ -131,7 +136,7 @@ public class PropertyConfigurationImporter
         // ldap server
         storedConfiguration.writeSetting( PwmSetting.LDAP_SERVER_URLS, LDAP_PROFILE, makeLdapServerUrlValue( ), null );
         storedConfiguration.writeSetting( PwmSetting.LDAP_PROXY_USER_DN, LDAP_PROFILE,
-                new PasswordValue( PasswordData.forStringValue( inputMap.get( PropertyKey.ID_VAULT_ADMIN_LDAP.name( ) ) ) ), null );
+                new StringValue( inputMap.get( PropertyKey.ID_VAULT_ADMIN_LDAP.name( ) ) ), null );
         storedConfiguration.writeSetting( PwmSetting.LDAP_PROXY_USER_PASSWORD, LDAP_PROFILE,
                 new PasswordValue( PasswordData.forStringValue( inputMap.get( PropertyKey.ID_VAULT_PASSWORD.name( ) ) ) ), null );
         storedConfiguration.writeSetting( PwmSetting.LDAP_CONTEXTLESS_ROOT, LDAP_PROFILE,
@@ -185,7 +190,7 @@ public class PropertyConfigurationImporter
 
     private String makeOAuthBaseUrl( )
     {
-        return "https://" + inputMap.get( PropertyKey.SSO_SERVER_HOST.name( ) )
+        return "https://" + inputMap.get( PropertyKey.UA_SERVER_HOST.name( ) )
                 + ":" + inputMap.get( PropertyKey.SSO_SERVER_SSL_PORT.name( ) )
                 + "/osp/a/idm/auth/oauth2";
     }
@@ -199,22 +204,20 @@ public class PropertyConfigurationImporter
     private StoredValue makeSelfUrl( )
     {
         return new StringValue( "https://" + inputMap.get( PropertyKey.SSO_SERVER_HOST.name( ) )
-                + ":" + inputMap.get( PropertyKey.SSO_SERVER_SSL_PORT.name( ) )
+                + ":" + inputMap.getOrDefault( PropertyKey.SSPR_SERVER_PORT.name( ), "9443" )
                 + "/sspr" );
     }
 
     private StoredValue makeForwardUrl( )
     {
-        return new StringValue( "https://" + inputMap.get( PropertyKey.SSO_SERVER_HOST.name( ) )
+        return new StringValue( "https://" + inputMap.get( PropertyKey.SSPR_SERVER_HOST.name( ) )
                 + ":" + inputMap.get( PropertyKey.SSO_SERVER_SSL_PORT.name( ) )
                 + "/idmdash/#/landing" );
     }
 
     private StoredValue makeLogoutUrl( )
     {
-        final String targetValue = "https://" + inputMap.get( PropertyKey.SSO_SERVER_HOST.name( ) )
-                + ":" + inputMap.get( PropertyKey.SSO_SERVER_SSL_PORT.name( ) )
-                + "/sspr";
+        final String targetValue = makeSelfUrl().toNativeObject().toString();
 
         return new StringValue( "https://" + inputMap.get( PropertyKey.SSO_SERVER_HOST.name( ) )
                 + ":" + inputMap.get( PropertyKey.SSO_SERVER_SSL_PORT.name( ) )

+ 3 - 1
server/src/main/java/password/pwm/util/java/JsonUtil.java

@@ -220,7 +220,9 @@ public class JsonUtil
                 return ISO_DATE_FORMAT.parse( jsonElement.getAsString() );
             }
             catch ( ParseException e )
-            { /* noop */ }
+            {
+                /* noop */
+            }
 
             // for backwards compatibility
             try

+ 31 - 0
server/src/main/java/password/pwm/util/secure/X509Utils.java

@@ -65,8 +65,10 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public abstract class X509Utils
 {
@@ -570,4 +572,33 @@ public abstract class X509Utils
             throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "unexpected error encoding certificate: " + e.getMessage() );
         }
     }
+
+    public static Set<X509Certificate> readCertsForListOfLdapUrls( final List<String> ldapUrls, final Configuration configuration )
+            throws PwmUnrecoverableException
+    {
+        final Set<X509Certificate> resultCertificates = new LinkedHashSet<>();
+        try
+        {
+            for ( final String ldapUrlString : ldapUrls )
+            {
+                final URI ldapURI = new URI( ldapUrlString );
+                final List<X509Certificate> certs = X509Utils.readRemoteCertificates( ldapURI, configuration );
+                if ( certs != null )
+                {
+                    resultCertificates.addAll( certs );
+                }
+            }
+        }
+        catch ( Exception e )
+        {
+            if ( e instanceof PwmException )
+            {
+                throw new PwmUnrecoverableException( ( ( PwmException ) e ).getErrorInformation() );
+            }
+            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "error importing certificates: " + e.getMessage() );
+            throw new PwmUnrecoverableException( errorInformation );
+        }
+        return Collections.unmodifiableSet( resultCertificates );
+    }
+
 }