浏览代码

log message improvements

Jason Rivard 3 年之前
父节点
当前提交
a13d39d173
共有 100 个文件被更改,包括 735 次插入557 次删除
  1. 1 1
      pom.xml
  2. 3 3
      server/src/main/java/password/pwm/PwmAboutProperty.java
  3. 1 1
      server/src/main/java/password/pwm/PwmApplication.java
  4. 3 3
      server/src/main/java/password/pwm/PwmDomain.java
  5. 3 3
      server/src/main/java/password/pwm/PwmDomainUtil.java
  6. 9 8
      server/src/main/java/password/pwm/PwmEnvironment.java
  7. 2 0
      server/src/main/java/password/pwm/bean/SessionLabel.java
  8. 21 1
      server/src/main/java/password/pwm/config/AppConfig.java
  9. 2 1
      server/src/main/java/password/pwm/config/StoredSettingReader.java
  10. 11 10
      server/src/main/java/password/pwm/config/stored/ConfigurationCleaner.java
  11. 18 17
      server/src/main/java/password/pwm/config/stored/ConfigurationFileManager.java
  12. 5 4
      server/src/main/java/password/pwm/config/value/data/ShortcutItem.java
  13. 22 11
      server/src/main/java/password/pwm/health/HealthService.java
  14. 1 1
      server/src/main/java/password/pwm/health/LDAPHealthChecker.java
  15. 3 3
      server/src/main/java/password/pwm/http/ContextManager.java
  16. 3 4
      server/src/main/java/password/pwm/http/PwmRequest.java
  17. 1 0
      server/src/main/java/password/pwm/http/PwmSession.java
  18. 1 1
      server/src/main/java/password/pwm/http/auth/HttpAuthenticationUtilities.java
  19. 3 3
      server/src/main/java/password/pwm/http/filter/SessionFilter.java
  20. 1 1
      server/src/main/java/password/pwm/http/servlet/ClientApiServlet.java
  21. 1 1
      server/src/main/java/password/pwm/http/servlet/GuestRegistrationServlet.java
  22. 2 2
      server/src/main/java/password/pwm/http/servlet/ShortcutServlet.java
  23. 2 2
      server/src/main/java/password/pwm/http/servlet/admin/AppDashboardData.java
  24. 1 1
      server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java
  25. 2 2
      server/src/main/java/password/pwm/http/servlet/command/CommandServlet.java
  26. 4 4
      server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java
  27. 1 1
      server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServletUtils.java
  28. 1 1
      server/src/main/java/password/pwm/http/servlet/configeditor/function/SmtpCertImportFunction.java
  29. 1 1
      server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideServlet.java
  30. 4 4
      server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideUtils.java
  31. 1 2
      server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerServlet.java
  32. 2 2
      server/src/main/java/password/pwm/http/servlet/forgottenpw/RemoteVerificationMethod.java
  33. 1 1
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationOptionsBean.java
  34. 2 1
      server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java
  35. 2 2
      server/src/main/java/password/pwm/http/servlet/oauth/OAuthMachine.java
  36. 3 3
      server/src/main/java/password/pwm/http/servlet/peoplesearch/PhotoDataReader.java
  37. 1 1
      server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileUtil.java
  38. 1 1
      server/src/main/java/password/pwm/http/state/SessionStateService.java
  39. 4 4
      server/src/main/java/password/pwm/http/tag/DisplayTag.java
  40. 8 8
      server/src/main/java/password/pwm/ldap/LdapDomainService.java
  41. 138 112
      server/src/main/java/password/pwm/ldap/LdapOperationsHelper.java
  42. 1 2
      server/src/main/java/password/pwm/ldap/LdapPermissionCalculator.java
  43. 2 2
      server/src/main/java/password/pwm/ldap/LdapUserInfoReader.java
  44. 2 2
      server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java
  45. 2 2
      server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java
  46. 3 2
      server/src/main/java/password/pwm/svc/PwmServiceEnum.java
  47. 15 7
      server/src/main/java/password/pwm/svc/PwmServiceManager.java
  48. 1 1
      server/src/main/java/password/pwm/svc/cache/CacheService.java
  49. 26 6
      server/src/main/java/password/pwm/svc/cr/CrService.java
  50. 84 57
      server/src/main/java/password/pwm/svc/cr/NMASCrOperator.java
  51. 1 1
      server/src/main/java/password/pwm/svc/db/DatabaseUtil.java
  52. 17 9
      server/src/main/java/password/pwm/svc/email/EmailConnectionPool.java
  53. 33 14
      server/src/main/java/password/pwm/svc/email/EmailServerUtil.java
  54. 34 29
      server/src/main/java/password/pwm/svc/email/EmailService.java
  55. 1 1
      server/src/main/java/password/pwm/svc/event/AuditRecordFactory.java
  56. 2 2
      server/src/main/java/password/pwm/svc/event/AuditService.java
  57. 1 1
      server/src/main/java/password/pwm/svc/event/SyslogAuditService.java
  58. 10 8
      server/src/main/java/password/pwm/svc/httpclient/ApachePwmHttpClient.java
  59. 5 4
      server/src/main/java/password/pwm/svc/httpclient/HttpClientService.java
  60. 7 5
      server/src/main/java/password/pwm/svc/httpclient/JavaPwmHttpClient.java
  61. 1 5
      server/src/main/java/password/pwm/svc/httpclient/PwmHttpClient.java
  62. 7 1
      server/src/main/java/password/pwm/svc/httpclient/PwmHttpClientProvider.java
  63. 2 2
      server/src/main/java/password/pwm/svc/intruder/IntruderDomainService.java
  64. 1 1
      server/src/main/java/password/pwm/svc/sessiontrack/SessionTrackService.java
  65. 2 1
      server/src/main/java/password/pwm/svc/shorturl/AbstractUrlShortener.java
  66. 2 1
      server/src/main/java/password/pwm/svc/shorturl/BasicUrlShortener.java
  67. 4 3
      server/src/main/java/password/pwm/svc/shorturl/TinyUrlShortener.java
  68. 6 4
      server/src/main/java/password/pwm/svc/shorturl/UrlShortenerService.java
  69. 32 44
      server/src/main/java/password/pwm/svc/sms/SmsQueueService.java
  70. 1 1
      server/src/main/java/password/pwm/svc/stats/StatisticsService.java
  71. 2 2
      server/src/main/java/password/pwm/svc/telemetry/HttpTelemetrySender.java
  72. 1 1
      server/src/main/java/password/pwm/svc/userhistory/LdapXmlUserHistory.java
  73. 2 2
      server/src/main/java/password/pwm/svc/wordlist/SharedHistoryService.java
  74. 4 1
      server/src/main/java/password/pwm/svc/wordlist/WordlistImporter.java
  75. 3 3
      server/src/main/java/password/pwm/svc/wordlist/WordlistSource.java
  76. 3 3
      server/src/main/java/password/pwm/util/CaptchaUtility.java
  77. 2 1
      server/src/main/java/password/pwm/util/OnejarHelper.java
  78. 3 2
      server/src/main/java/password/pwm/util/cli/MainClass.java
  79. 1 2
      server/src/main/java/password/pwm/util/cli/commands/ConfigLockCommand.java
  80. 2 2
      server/src/main/java/password/pwm/util/cli/commands/ConfigResetHttpsCommand.java
  81. 1 2
      server/src/main/java/password/pwm/util/cli/commands/ConfigSetPasswordCommand.java
  82. 1 2
      server/src/main/java/password/pwm/util/cli/commands/ConfigUnlockCommand.java
  83. 2 2
      server/src/main/java/password/pwm/util/cli/commands/ImportHttpsKeyStoreCommand.java
  84. 2 2
      server/src/main/java/password/pwm/util/debug/LdapConnectionsDebugItemGenerator.java
  85. 1 1
      server/src/main/java/password/pwm/util/form/FormUtility.java
  86. 23 25
      server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java
  87. 29 7
      server/src/main/java/password/pwm/util/logging/LocalDBLogger.java
  88. 9 9
      server/src/main/java/password/pwm/util/logging/PwmLogger.java
  89. 4 1
      server/src/main/java/password/pwm/util/macro/ExternalRestMacro.java
  90. 3 3
      server/src/main/java/password/pwm/util/operations/ActionExecutor.java
  91. 3 3
      server/src/main/java/password/pwm/util/password/PasswordUtility.java
  92. 6 6
      server/src/main/java/password/pwm/util/password/PwmPasswordRuleValidator.java
  93. 2 2
      server/src/main/java/password/pwm/util/secure/X509Utils.java
  94. 3 2
      server/src/main/java/password/pwm/ws/client/rest/RestClientHelper.java
  95. 1 1
      server/src/main/java/password/pwm/ws/client/rest/RestTokenDataClient.java
  96. 5 3
      server/src/main/java/password/pwm/ws/client/rest/form/RestFormDataClient.java
  97. 1 1
      server/src/main/java/password/pwm/ws/server/RestServlet.java
  98. 2 2
      server/src/main/java/password/pwm/ws/server/rest/RestSetPasswordServer.java
  99. 11 10
      server/src/test/java/password/pwm/http/client/PwmHttpClientTest.java
  100. 2 4
      server/src/test/java/password/pwm/svc/sms/EmailQueueManagerTest.java

+ 1 - 1
pom.xml

@@ -334,7 +334,7 @@
             <plugin>
                 <groupId>com.github.spotbugs</groupId>
                 <artifactId>spotbugs-maven-plugin</artifactId>
-                <version>4.6.0.0</version>
+                <version>4.7.0.0</version>
                 <dependencies>
                     <dependency>
                         <groupId>com.github.spotbugs</groupId>

+ 3 - 3
server/src/main/java/password/pwm/PwmAboutProperty.java

@@ -23,7 +23,7 @@ package password.pwm;
 import lombok.Value;
 import password.pwm.config.PwmSetting;
 import password.pwm.i18n.Display;
-import password.pwm.ldap.LdapConnectionService;
+import password.pwm.ldap.LdapDomainService;
 import password.pwm.svc.db.DatabaseService;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.FileSystemUtility;
@@ -77,8 +77,8 @@ public enum PwmAboutProperty
     app_configurationRestartCounter( null, pwmApplication -> Integer.toString( pwmApplication.getPwmEnvironment().getContextManager().getRestartCount() ) ),
     app_secureBlockAlgorithm( null, pwmApplication -> pwmApplication.getSecureService().getDefaultBlockAlgorithm().getLabel() ),
     app_secureHashAlgorithm( null, pwmApplication -> pwmApplication.getSecureService().getDefaultHashAlgorithm().toString() ),
-    app_ldapProfileCount( null, pwmApplication -> Integer.toString( LdapConnectionService.totalLdapProfileCount( pwmApplication ) ) ),
-    app_ldapConnectionCount( null, pwmApplication -> Long.toString( LdapConnectionService.totalLdapConnectionCount( pwmApplication ) ) ),
+    app_ldapProfileCount( null, pwmApplication -> Integer.toString( LdapDomainService.totalLdapProfileCount( pwmApplication ) ) ),
+    app_ldapConnectionCount( null, pwmApplication -> Long.toString( LdapDomainService.totalLdapConnectionCount( pwmApplication ) ) ),
     app_activeSessionCount( "App Active Session Count", pwmApplication -> Integer.toString( pwmApplication.getSessionTrackService().sessionCount() ) ),
     app_activeRequestCount( "App Active Request Count", pwmApplication -> Integer.toString( pwmApplication.getActiveServletRequests().get() ) ),
     app_definedDomainCount( "App Defined Domain Count", pwmApplication -> Integer.toString( pwmApplication.domains().size() ) ),

+ 1 - 1
server/src/main/java/password/pwm/PwmApplication.java

@@ -256,7 +256,7 @@ public class PwmApplication
         }
         else
         {
-            LOGGER.debug( sessionLabel, () -> "no system-level settings have been changed, restart of system services is not required");
+            LOGGER.debug( sessionLabel, () -> "no system-level settings have been changed, restart of system services is not required" );
         }
 
         domains = PwmDomainUtil.reInitDomains( this, newConfig, oldConfig );

+ 3 - 3
server/src/main/java/password/pwm/PwmDomain.java

@@ -32,7 +32,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.servlet.peoplesearch.PeopleSearchService;
 import password.pwm.http.servlet.resource.ResourceServletService;
 import password.pwm.http.state.SessionStateService;
-import password.pwm.ldap.LdapConnectionService;
+import password.pwm.ldap.LdapDomainService;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.PwmServiceEnum;
@@ -154,9 +154,9 @@ public class PwmDomain
         return pwmApplication.determineIfDetailErrorMsgShown();
     }
 
-    public LdapConnectionService getLdapConnectionService( )
+    public LdapDomainService getLdapConnectionService( )
     {
-        return ( LdapConnectionService ) pwmServiceManager.getService( PwmServiceEnum.LdapConnectionService );
+        return ( LdapDomainService ) pwmServiceManager.getService( PwmServiceEnum.LdapConnectionService );
     }
 
     public AuditService getAuditService()

+ 3 - 3
server/src/main/java/password/pwm/PwmDomainUtil.java

@@ -76,7 +76,7 @@ class PwmDomainUtil
             throws PwmUnrecoverableException
     {
         final Instant domainInitStartTime = Instant.now();
-        LOGGER.trace( () -> "beginning domain initializations" );
+        LOGGER.trace( pwmApplication.getSessionLabel(), () -> "beginning domain initializations" );
 
         final List<Callable<Optional<PwmUnrecoverableException>>> callables = domains.stream()
                 .map( DomainInitializingCallable::new )
@@ -95,7 +95,7 @@ class PwmDomainUtil
             throw domainStartupException.get();
         }
 
-        LOGGER.trace( () -> "completed domain initialization for domains", TimeDuration.fromCurrent( domainInitStartTime ) );
+        LOGGER.trace( pwmApplication.getSessionLabel(), () -> "completed domain initialization for domains", TimeDuration.fromCurrent( domainInitStartTime ) );
     }
 
     private static class DomainInitializingCallable implements Callable<Optional<PwmUnrecoverableException>>
@@ -153,7 +153,7 @@ class PwmDomainUtil
 
         if ( newDomains.isEmpty() && deletedDomains.isEmpty() )
         {
-            LOGGER.debug( pwmApplication.getSessionLabel(), () -> "no domain-level settings have been changed, restart of domain services is not required");
+            LOGGER.debug( pwmApplication.getSessionLabel(), () -> "no domain-level settings have been changed, restart of domain services is not required" );
         }
 
         if ( !newDomains.isEmpty() )

+ 9 - 8
server/src/main/java/password/pwm/PwmEnvironment.java

@@ -23,6 +23,7 @@ package password.pwm;
 import lombok.Builder;
 import lombok.Singular;
 import lombok.Value;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
@@ -168,7 +169,7 @@ public class PwmEnvironment
         }
         if ( applicationPathIsWebInfPath )
         {
-            LOGGER.trace( () -> "applicationPath appears to be servlet /WEB-INF directory" );
+            LOGGER.trace( SessionLabel.SYSTEM_LABEL, () -> "applicationPath appears to be servlet /WEB-INF directory" );
         }
     }
 
@@ -196,7 +197,7 @@ public class PwmEnvironment
             );
         }
 
-        LOGGER.trace( () -> "examining applicationPath of " + applicationPath.getAbsolutePath() + "" );
+        LOGGER.trace( SessionLabel.SYSTEM_LABEL, () -> "examining applicationPath of " + applicationPath.getAbsolutePath() + "" );
 
         if ( !applicationPath.exists() )
         {
@@ -223,7 +224,7 @@ public class PwmEnvironment
         }
 
         final File infoFile = new File( applicationPath.getAbsolutePath() + File.separator + PwmConstants.APPLICATION_PATH_INFO_FILE );
-        LOGGER.trace( () -> "checking " + infoFile.getAbsolutePath() + " status" );
+        LOGGER.trace( SessionLabel.SYSTEM_LABEL, () -> "checking " + infoFile.getAbsolutePath() + " status" );
         if ( infoFile.exists() )
         {
             final String errorMsg = "The file " + infoFile.getAbsolutePath() + " exists, and an applicationPath was not explicitly specified."
@@ -310,7 +311,7 @@ public class PwmEnvironment
                 }
                 else
                 {
-                    LOGGER.warn( () -> "unknown " + EnvironmentParameter.applicationFlags + " value: " + input );
+                    LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "unknown " + EnvironmentParameter.applicationFlags + " value: " + input );
                 }
             }
             return returnFlags;
@@ -330,7 +331,7 @@ public class PwmEnvironment
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "error reading properties file '" + input + "' specified by environment setting "
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "error reading properties file '" + input + "' specified by environment setting "
                         + EnvironmentParameter.applicationParamFile + ", error: " + e.getMessage() );
             }
 
@@ -347,14 +348,14 @@ public class PwmEnvironment
                     }
                     else
                     {
-                        LOGGER.warn( () -> "unknown " + EnvironmentParameter.applicationParamFile + " value: " + input );
+                        LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "unknown " + EnvironmentParameter.applicationParamFile + " value: " + input );
                     }
                 }
                 return Collections.unmodifiableMap( returnParams );
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "unable to parse jason value of " + EnvironmentParameter.applicationParamFile + ", error: " + e.getMessage() );
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "unable to parse jason value of " + EnvironmentParameter.applicationParamFile + ", error: " + e.getMessage() );
             }
 
             return Collections.emptyMap();
@@ -365,7 +366,7 @@ public class PwmEnvironment
     {
         if ( PwmConstants.TRIAL_MODE && mode == PwmApplicationMode.RUNNING )
         {
-            LOGGER.info( () -> "application is in trial mode" );
+            LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "application is in trial mode" );
             return PwmApplicationMode.CONFIGURATION;
         }
 

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

@@ -40,6 +40,8 @@ public class SessionLabel implements Serializable
     public static final SessionLabel TEST_SESSION_LABEL = SessionLabel.builder().sessionID( SYSTEM_LABEL_SESSION_ID ).username( "test" ).build();
     public static final SessionLabel CLI_SESSION_LABEL = SessionLabel.builder().sessionID( SYSTEM_LABEL_SESSION_ID ).username( "cli" ).build();
     public static final SessionLabel CONTEXT_SESSION_LABEL = SessionLabel.builder().sessionID( SYSTEM_LABEL_SESSION_ID ).username( "context" ).build();
+    public static final SessionLabel ONEJAR_LABEL = SessionLabel.builder().sessionID( SYSTEM_LABEL_SESSION_ID ).username( "onejar" ).build();
+
 
     private final String sessionID;
     private final String requestID;

+ 21 - 1
server/src/main/java/password/pwm/config/AppConfig.java

@@ -24,6 +24,7 @@ import password.pwm.AppProperty;
 import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
 import password.pwm.bean.PrivateKeyCertificate;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.option.CertificateMatchingMode;
 import password.pwm.config.option.DataStorageMethod;
 import password.pwm.config.profile.EmailServerProfile;
@@ -358,6 +359,25 @@ public class AppConfig implements SettingReader
         return Collections.unmodifiableMap( appPropertyMap );
     }
 
+    public boolean isSmsConfigured()
+    {
+        final String gatewayUrl = readSettingAsString( PwmSetting.SMS_GATEWAY_URL );
+        final String gatewayUser = readSettingAsString( PwmSetting.SMS_GATEWAY_USER );
+        final PasswordData gatewayPass = readSettingAsPassword( PwmSetting.SMS_GATEWAY_PASSWORD );
+        if ( gatewayUrl == null || gatewayUrl.length() < 1 )
+        {
+            return false;
+        }
+
+        if ( gatewayUser != null && gatewayUser.length() > 0 && ( gatewayPass == null ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
     private static PwmSecurityKey makeAppSecurityKey( final AppConfig appConfig )
     {
         try
@@ -368,7 +388,7 @@ public class AppConfig implements SettingReader
             {
                 final String errorMsg = "Security Key value is not configured, will generate temp value for use by runtime instance";
                 final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg );
-                LOGGER.warn( errorInfo::toDebugStr );
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, errorInfo::toDebugStr );
                 return new PwmSecurityKey( PwmRandom.getInstance().alphaNumericString( 1024 ) );
             }
             else

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

@@ -24,6 +24,7 @@ import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.bean.PrivateKeyCertificate;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.option.DataStorageMethod;
 import password.pwm.config.profile.Profile;
 import password.pwm.config.profile.ProfileDefinition;
@@ -321,7 +322,7 @@ public class StoredSettingReader implements SettingReader
 
         if ( setting.getFlags().contains( PwmSettingFlag.Deprecated ) )
         {
-            LOGGER.warn( () -> "attempt to read deprecated config setting: " + setting.toMenuLocationDebug( profileID, null ) );
+            LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "attempt to read deprecated config setting: " + setting.toMenuLocationDebug( profileID, null ) );
         }
 
         if ( StringUtil.isEmpty( profileID ) )

+ 11 - 10
server/src/main/java/password/pwm/config/stored/ConfigurationCleaner.java

@@ -22,6 +22,7 @@ package password.pwm.config.stored;
 
 import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
+import password.pwm.bean.SessionLabel;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingTemplateSet;
@@ -112,7 +113,7 @@ public class ConfigurationCleaner
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.error( () -> "error converting deprecated AD password policy setting: " + key + ", error: " + e.getMessage() );
+                LOGGER.error( SessionLabel.SYSTEM_LABEL, () -> "error converting deprecated AD password policy setting: " + key + ", error: " + e.getMessage() );
             }
         }
     }
@@ -138,7 +139,7 @@ public class ConfigurationCleaner
                                 : new StringValue( RecoveryMinLifetimeOption.ALLOW.name() );
                         final Optional<ValueMetaData> existingData = oldConfig.readSettingMetadata( key );
                         final UserIdentity newActor = existingData.map( ValueMetaData::getUserIdentity ).orElse( null );
-                        LOGGER.info( () -> "converting deprecated non-default setting "
+                        LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "converting deprecated non-default setting "
                                 + PwmSetting.RECOVERY_ENFORCE_MINIMUM_PASSWORD_LIFETIME.toMenuLocationDebug( profileID, PwmConstants.DEFAULT_LOCALE ) + "/" + profileID
                                 + " to replacement setting " + PwmSetting.RECOVERY_MINIMUM_PASSWORD_LIFETIME_OPTIONS.toMenuLocationDebug( profileID, PwmConstants.DEFAULT_LOCALE )
                                 + ", value="
@@ -164,7 +165,7 @@ public class ConfigurationCleaner
                 final StoredConfigKey existingPubWebservicesKey = StoredConfigKey.forSetting( PwmSetting.PUBLIC_HEALTH_STATS_WEBSERVICES, null, domainID );
                 if ( oldConfig.readStoredValue( existingPubWebservicesKey ).isPresent() )
                 {
-                    LOGGER.info( () -> "converting deprecated non-default setting "
+                    LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "converting deprecated non-default setting "
                             + PwmSetting.PUBLIC_HEALTH_STATS_WEBSERVICES.toMenuLocationDebug( null, PwmConstants.DEFAULT_LOCALE )
                             + " to replacement setting " + PwmSetting.WEBSERVICES_PUBLIC_ENABLE.toMenuLocationDebug( null, PwmConstants.DEFAULT_LOCALE ) );
                     final StoredConfigKey existingPubEnableKey = StoredConfigKey.forSetting( PwmSetting.WEBSERVICES_PUBLIC_ENABLE, null, domainID );
@@ -221,7 +222,7 @@ public class ConfigurationCleaner
                     }
                     catch ( final PwmUnrecoverableException e )
                     {
-                        LOGGER.warn( () -> "error moving setting " + pwmSetting.getKey() + " without profile attribute to profile \"" + destProfile
+                        LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "error moving setting " + pwmSetting.getKey() + " without profile attribute to profile \"" + destProfile
                                 + "\", error: " + e.getMessage() );
                     }
                 }
@@ -229,12 +230,12 @@ public class ConfigurationCleaner
 
             try
             {
-                LOGGER.info( () -> "removing setting " + key + " without profile" );
+                LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "removing setting " + key + " without profile" );
                 modifier.deleteKey( key );
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.warn( () -> "error deleting setting " + pwmSetting.getKey() + " after adding profile settings: " + e.getMessage() );
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "error deleting setting " + pwmSetting.getKey() + " after adding profile settings: " + e.getMessage() );
             }
         }
     }
@@ -265,12 +266,12 @@ public class ConfigurationCleaner
         {
             try
             {
-                LOGGER.info( () -> "removing setting " + key.toString() + " with non-existing profileID" );
+                LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "removing setting " + key.toString() + " with non-existing profileID" );
                 modifier.deleteKey( key );
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.warn( () -> "error deleting setting " + key.toString() + " with non-existing profileID: " + e.getMessage() );
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "error deleting setting " + key.toString() + " with non-existing profileID: " + e.getMessage() );
             }
         }
     }
@@ -301,12 +302,12 @@ public class ConfigurationCleaner
             try
             {
                 final StoredValue value = inputConfig.readStoredValue( key ).orElseThrow();
-                LOGGER.info( () -> "removing setting " + key.toString() + " with default value: " + value.toDebugString( PwmConstants.DEFAULT_LOCALE ) );
+                LOGGER.info( SessionLabel.SYSTEM_LABEL, () -> "removing setting " + key.toString() + " with default value: " + value.toDebugString( PwmConstants.DEFAULT_LOCALE ) );
                 modifier.deleteKey( key );
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.warn( () -> "error deleting setting " + key.toString() + " with default value: " + e.getMessage() );
+                LOGGER.warn( SessionLabel.SYSTEM_LABEL, () -> "error deleting setting " + key.toString() + " with default value: " + e.getMessage() );
             }
         }
     }

+ 18 - 17
server/src/main/java/password/pwm/config/stored/ConfigurationFileManager.java

@@ -67,6 +67,8 @@ public class ConfigurationFileManager
 
     private final File configFile;
     private final String configFileChecksum;
+    private final SessionLabel sessionLabel;
+
     private AppConfig domainConfig;
     private StoredConfiguration storedConfiguration;
     private ErrorInformation configFileError;
@@ -75,9 +77,11 @@ public class ConfigurationFileManager
 
     private volatile boolean saveInProgress;
 
-    public ConfigurationFileManager( final File configFile ) throws PwmUnrecoverableException
+    public ConfigurationFileManager( final File configFile, final SessionLabel sessionLabel )
+            throws PwmUnrecoverableException
     {
         this.configFile = configFile;
+        this.sessionLabel = sessionLabel;
 
         this.configFileChecksum = readFileChecksum( configFile );
         try
@@ -88,7 +92,7 @@ public class ConfigurationFileManager
         catch ( final PwmUnrecoverableException e )
         {
             this.configFileError = e.getErrorInformation();
-            LOGGER.warn( () -> "error reading configuration file: " + e.getMessage() );
+            LOGGER.warn( sessionLabel, () -> "error reading configuration file: " + e.getMessage() );
         }
 
         if ( storedConfiguration == null )
@@ -96,7 +100,7 @@ public class ConfigurationFileManager
             this.storedConfiguration = StoredConfigurationFactory.newConfig();
         }
 
-        LOGGER.debug( () -> "configuration mode: " + configMode );
+        LOGGER.debug( sessionLabel, () -> "configuration mode: " + configMode );
     }
 
     public PwmApplicationMode getConfigMode( )
@@ -123,11 +127,11 @@ public class ConfigurationFileManager
 
     private StoredConfiguration readStoredConfig( ) throws PwmUnrecoverableException
     {
-        LOGGER.debug( () -> "loading configuration file: " + configFile );
+        LOGGER.debug( sessionLabel, () -> "loading configuration file: " + configFile );
 
         if ( !configFile.exists() )
         {
-            LOGGER.warn( () -> "configuration file '" + configFile.getAbsolutePath() + "' does not exist" );
+            LOGGER.warn( sessionLabel, () -> "configuration file '" + configFile.getAbsolutePath() + "' does not exist" );
             return null;
         }
 
@@ -180,7 +184,7 @@ public class ConfigurationFileManager
         }
 
         final String fileSize = StringUtil.formatDiskSize( configFile.length() );
-        LOGGER.debug( () -> "configuration reading/parsing of " + fileSize + " complete", TimeDuration.fromCurrent( startTime ) );
+        LOGGER.debug( sessionLabel, () -> "configuration reading/parsing of " + fileSize + " complete", TimeDuration.fromCurrent( startTime ) );
 
 
         final Optional<String> configIsEditable = storedConfiguration.readConfigProperty( ConfigurationProperty.CONFIG_IS_EDITABLE );
@@ -198,8 +202,7 @@ public class ConfigurationFileManager
 
     public void saveConfiguration(
             final StoredConfiguration storedConfiguration,
-            final PwmApplication pwmApplication,
-            final SessionLabel sessionLabel
+            final PwmApplication pwmApplication
     )
             throws IOException, PwmUnrecoverableException, PwmOperationalException
     {
@@ -248,12 +251,12 @@ public class ConfigurationFileManager
 
         if ( pwmApplication != null && pwmApplication.getAuditService() != null )
         {
-            auditModifiedSettings( pwmApplication, storedConfiguration, sessionLabel );
+            auditModifiedSettings( pwmApplication, storedConfiguration );
         }
 
         try
         {
-            outputConfigurationFile( storedConfiguration, pwmApplication, sessionLabel, backupRotations, backupDirectory );
+            outputConfigurationFile( storedConfiguration, pwmApplication, backupRotations, backupDirectory );
         }
         finally
         {
@@ -261,8 +264,7 @@ public class ConfigurationFileManager
         }
     }
 
-    private static void auditModifiedSettings( final PwmApplication pwmApplication, final StoredConfiguration newConfig, final SessionLabel sessionLabel )
-            throws PwmUnrecoverableException
+    private void auditModifiedSettings( final PwmApplication pwmApplication, final StoredConfiguration newConfig )
     {
         final Instant startTime = Instant.now();
 
@@ -286,7 +288,7 @@ public class ConfigurationFileManager
                     .orElse( "removed" );
 
             final String finalMsg = modifyMessage;
-            LOGGER.trace( () -> "sending audit notice: " + finalMsg );
+            LOGGER.trace( sessionLabel, () -> "sending audit notice: " + finalMsg );
 
             AuditServiceClient.submit( pwmApplication, sessionLabel, AuditRecordFactory.make( sessionLabel, pwmApplication ).createUserAuditRecord(
                     AuditEvent.MODIFY_CONFIGURATION,
@@ -298,13 +300,12 @@ public class ConfigurationFileManager
         }
 
         final int finalChangeCount = changeCount;
-        LOGGER.debug( () -> "sent " + finalChangeCount + " audit notifications about changed settings", TimeDuration.fromCurrent( startTime ) );
+        LOGGER.debug( sessionLabel, () -> "sent " + finalChangeCount + " audit notifications about changed settings", TimeDuration.fromCurrent( startTime ) );
     }
 
     private void outputConfigurationFile(
             final StoredConfiguration storedConfiguration,
             final PwmApplication pwmApplication,
-            final SessionLabel sessionLabel,
             final int backupRotations,
             final File backupDirectory
     )
@@ -322,14 +323,14 @@ public class ConfigurationFileManager
             StoredConfigurationFactory.output( storedConfiguration, fileOutputStream );
         }
 
-        LOGGER.info( () -> "saved configuration", TimeDuration.fromCurrent( saveFileStartTime ) );
+        LOGGER.info( sessionLabel, () -> "saved configuration", TimeDuration.fromCurrent( saveFileStartTime ) );
         if ( pwmApplication != null )
         {
             final String actualChecksum = StoredConfigurationUtil.valueHash( storedConfiguration );
             pwmApplication.writeAppAttribute( AppAttribute.CONFIG_HASH, actualChecksum );
         }
 
-        LOGGER.trace( () -> "renaming file " + tempWriteFile.getAbsolutePath() + " to " + configFile.getAbsolutePath() );
+        LOGGER.trace( sessionLabel, () -> "renaming file " + tempWriteFile.getAbsolutePath() + " to " + configFile.getAbsolutePath() );
         try
         {
             Files.move( tempWriteFile.toPath(), configFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );

+ 5 - 4
server/src/main/java/password/pwm/config/value/data/ShortcutItem.java

@@ -21,6 +21,7 @@
 package password.pwm.config.value.data;
 
 import lombok.Value;
+import password.pwm.bean.SessionLabel;
 import password.pwm.util.logging.PwmLogger;
 
 import java.io.Serializable;
@@ -36,7 +37,7 @@ public class ShortcutItem implements Serializable
     private final String ldapQuery;
     private final String description;
 
-    public static ShortcutItem parsePwmConfigInput( final String input )
+    public static ShortcutItem parsePwmConfigInput( final String input, final SessionLabel sessionLabel )
     {
         if ( input != null && input.length() > 0 )
         {
@@ -52,14 +53,14 @@ public class ShortcutItem implements Serializable
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "malformed ShortcutItem configuration value of '" + input + "', " + e.getMessage() );
+                LOGGER.warn( sessionLabel, () -> "malformed ShortcutItem configuration value of '" + input + "', " + e.getMessage() );
             }
         }
         throw new IllegalArgumentException( "malformed ShortcutItem configuration value of '" + input + "'" );
     }
 
 
-    public static ShortcutItem parseHeaderInput( final String input )
+    public static ShortcutItem parseHeaderInput( final String input, final SessionLabel sessionLabel )
     {
         if ( input != null && input.length() > 0 )
         {
@@ -75,7 +76,7 @@ public class ShortcutItem implements Serializable
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "malformed ShortcutItem configuration value of '" + input + "', " + e.getMessage() );
+                LOGGER.warn( sessionLabel, () -> "malformed ShortcutItem configuration value of '" + input + "', " + e.getMessage() );
             }
         }
         throw new IllegalArgumentException( "malformed ShortcutItem configuration value of '" + input + "'" );

+ 22 - 11
server/src/main/java/password/pwm/health/HealthService.java

@@ -127,7 +127,11 @@ public class HealthService extends AbstractPwmService implements PwmService
 
         if ( settings.getThreadDumpInterval().as( TimeDuration.Unit.SECONDS ) > 0 )
         {
-            pwmApplication.getPwmScheduler().scheduleFixedRateJob( new ThreadDumpLogger(), executorService, TimeDuration.SECOND, settings.getThreadDumpInterval() );
+            pwmApplication.getPwmScheduler().scheduleFixedRateJob(
+                    new ThreadDumpLogger( getSessionLabel() ),
+                    executorService,
+                    TimeDuration.SECOND,
+                    settings.getThreadDumpInterval() );
         }
 
         return STATUS.OPEN;
@@ -163,13 +167,13 @@ public class HealthService extends AbstractPwmService implements PwmService
         if ( healthData.recordsAreOutdated() )
         {
             final Instant startTime = Instant.now();
-            LOGGER.trace( () ->  "begin force immediate check" );
+            LOGGER.trace( getSessionLabel(), () -> "begin force immediate check" );
             final Future<?> future = getPwmApplication().getPwmScheduler().scheduleJob( new ImmediateJob(), executorService, TimeDuration.ZERO );
             settings.getMaximumForceCheckWait().pause( future::isDone );
             final TimeDuration checkDuration = TimeDuration.fromCurrent( startTime );
             averageStats.update( AverageStatKey.checkProcessTime, checkDuration.asDuration() );
             counterStats.increment( CounterStatKey.checks );
-            LOGGER.trace( () ->  "exit force immediate check, done=" + future.isDone(), checkDuration );
+            LOGGER.trace( getSessionLabel(), () -> "exit force immediate check, done=" + future.isDone(), checkDuration );
         }
 
         getPwmApplication().getPwmScheduler().scheduleJob( new UpdateJob(), executorService, settings.getNominalCheckInterval() );
@@ -221,7 +225,7 @@ public class HealthService extends AbstractPwmService implements PwmService
         }
 
         final Instant startTime = Instant.now();
-        LOGGER.trace( () -> "beginning health check execution #" + counter  );
+        LOGGER.trace( getSessionLabel(), () -> "beginning health check execution #" + counter  );
         final List<HealthRecord> tempResults = new ArrayList<>();
 
         for ( final Supplier<List<HealthRecord>> loopSupplier : gatherSuppliers( getPwmApplication(), getSessionLabel() ) )
@@ -238,16 +242,16 @@ public class HealthService extends AbstractPwmService implements PwmService
             {
                 if ( status() == STATUS.OPEN )
                 {
-                    LOGGER.warn( () -> "unexpected error during healthCheck: " + e.getMessage(), e );
+                    LOGGER.warn( getSessionLabel(), () -> "unexpected error during healthCheck: " + e.getMessage(), e );
                 }
             }
         }
 
         healthData = new HealthData( Collections.unmodifiableSet( new TreeSet<>( tempResults ) ), Instant.now() );
-        LOGGER.trace( () -> "completed health check execution #" + counter, TimeDuration.fromCurrent( startTime ) );
+        LOGGER.trace( getSessionLabel(), () -> "completed health check execution #" + counter, TimeDuration.fromCurrent( startTime ) );
     }
 
-    private static List<Supplier<List<HealthRecord>>> gatherSuppliers(
+    private List<Supplier<List<HealthRecord>>> gatherSuppliers(
             final PwmApplication pwmApplication,
             final SessionLabel sessionLabel
     )
@@ -269,7 +273,7 @@ public class HealthService extends AbstractPwmService implements PwmService
                 }
                 catch ( final Exception e )
                 {
-                    LOGGER.warn( () -> "unexpected error during healthCheck: " + e.getMessage(), e );
+                    LOGGER.warn( getSessionLabel(), () -> "unexpected error during healthCheck: " + e.getMessage(), e );
                 }
             }
         }
@@ -319,11 +323,11 @@ public class HealthService extends AbstractPwmService implements PwmService
             {
                 final Instant startTime = Instant.now();
                 doHealthChecks();
-                LOGGER.trace( () -> "completed health check dredge", TimeDuration.fromCurrent( startTime ) );
+                LOGGER.trace( getSessionLabel(), () -> "completed health check dredge", TimeDuration.fromCurrent( startTime ) );
             }
             catch ( final Throwable e )
             {
-                LOGGER.error( () -> "error during health check execution: " + e.getMessage(), e );
+                LOGGER.error( getSessionLabel(), () -> "error during health check execution: " + e.getMessage(), e );
             }
         }
     }
@@ -417,6 +421,13 @@ public class HealthService extends AbstractPwmService implements PwmService
         private static final PwmLogger LOGGER = PwmLogger.forClass( ThreadDumpLogger.class );
         private static final AtomicLoopIntIncrementer COUNTER = new AtomicLoopIntIncrementer();
 
+        private final SessionLabel sessionLabel;
+
+        ThreadDumpLogger( final SessionLabel sessionLabel )
+        {
+            this.sessionLabel = sessionLabel;
+        }
+
         @Override
         public void run()
         {
@@ -448,7 +459,7 @@ public class HealthService extends AbstractPwmService implements PwmService
 
         private void output( final CharSequence output )
         {
-            LOGGER.trace( () -> output );
+            LOGGER.trace( sessionLabel, () -> output );
         }
     }
 }

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

@@ -850,7 +850,7 @@ public class LDAPHealthChecker implements HealthSupplier
         {
             errorReachingServer = true;
             LOGGER.error( sessionLabel,
-                    () ->  "error during ad api password policy (asn " + PwmConstants.LDAP_AD_PASSWORD_POLICY_CONTROL_ASN + ") check: " + e.getMessage() );
+                    () -> "error during ad api password policy (asn " + PwmConstants.LDAP_AD_PASSWORD_POLICY_CONTROL_ASN + ") check: " + e.getMessage() );
         }
 
         if ( !errorReachingServer && pwmDomain.getPwmApplication().getHealthMonitor() != null )

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

@@ -246,7 +246,7 @@ public class ContextManager implements Serializable
         {
             configurationFile = locateConfigurationFile( applicationPath, PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
 
-            configReader = new ConfigurationFileManager( configurationFile );
+            configReader = new ConfigurationFileManager( configurationFile, SESSION_LABEL );
             appConfig = configReader.getConfiguration();
 
             mode = startupErrorInformation == null ? configReader.getConfigMode() : PwmApplicationMode.ERROR;
@@ -467,7 +467,7 @@ public class ContextManager implements Serializable
                             storedConfiguration = importer.readConfiguration( fileInputStream );
                         }
 
-                        configReader.saveConfiguration( storedConfiguration, pwmApplication, SESSION_LABEL );
+                        configReader.saveConfiguration( storedConfiguration, pwmApplication );
                         LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile.getAbsolutePath() + " has been successfully imported and saved as configuration file" );
                         requestPwmApplicationRestart();
                         success = true;
@@ -768,7 +768,7 @@ public class ContextManager implements Serializable
                         + ConfigurationProperty.IMPORT_LDAP_CERTIFICATES.getKey() + "'"
                         + ", imported " + totalImportedCerts + " certificates" );
                 modifiedConfig.writeConfigProperty( ConfigurationProperty.IMPORT_LDAP_CERTIFICATES, "false" );
-                configReader.saveConfiguration( modifiedConfig.newStoredConfiguration(), pwmApplication, SESSION_LABEL );
+                configReader.saveConfiguration( modifiedConfig.newStoredConfiguration(), pwmApplication );
                 requestPwmApplicationRestart();
             }
             else

+ 3 - 4
server/src/main/java/password/pwm/http/PwmRequest.java

@@ -58,7 +58,6 @@ import password.pwm.user.UserInfo;
 import password.pwm.util.Validator;
 import password.pwm.data.ImmutableByteArray;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogLevel;
@@ -85,7 +84,6 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Supplier;
 
 public class PwmRequest extends PwmHttpRequestWrapper
 {
@@ -96,7 +94,7 @@ public class PwmRequest extends PwmHttpRequestWrapper
     private final PwmRequestID pwmRequestID;
 
     private final transient PwmApplication pwmApplication;
-    private final transient Supplier<SessionLabel> sessionLabelLazySupplier = new LazySupplier<>( this::makeSessionLabel );
+    private final SessionLabel sessionLabel;
 
     private final Set<PwmRequestFlag> flags = EnumSet.noneOf( PwmRequestFlag.class );
     private final Instant requestStartTime = Instant.now();
@@ -144,6 +142,7 @@ public class PwmRequest extends PwmHttpRequestWrapper
         this.pwmApplication = pwmApplication;
         this.pwmURL = PwmURL.create( this.getHttpServletRequest() );
         this.domainID = PwmHttpRequestWrapper.readDomainIdFromRequest( httpServletRequest );
+        this.sessionLabel = makeSessionLabel();
     }
 
     public PwmDomain getPwmDomain( )
@@ -158,7 +157,7 @@ public class PwmRequest extends PwmHttpRequestWrapper
 
     public SessionLabel getLabel( )
     {
-        return sessionLabelLazySupplier.get();
+        return sessionLabel;
     }
 
     private SessionLabel makeSessionLabel( )

+ 1 - 0
server/src/main/java/password/pwm/http/PwmSession.java

@@ -202,6 +202,7 @@ public class PwmSession implements Serializable
 
     public SessionLabel getLabel( )
     {
+        System.out.println();
         final LocalSessionStateBean ssBean = this.getSessionStateBean();
 
         UserIdentity userIdentity = null;

+ 1 - 1
server/src/main/java/password/pwm/http/auth/HttpAuthenticationUtilities.java

@@ -62,7 +62,7 @@ public abstract class HttpAuthenticationUtilities
             }
             catch ( final Throwable e )
             {
-                LOGGER.trace( () -> "could not load authentication class '" + method + "', will ignore (error: " + e.getMessage() + ")" );
+                LOGGER.error( () -> "could not load authentication class '" + method + "', will ignore (error: " + e.getMessage() + ")" );
             }
         }
         return Collections.unmodifiableMap( methods );

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

@@ -346,12 +346,12 @@ public class SessionFilter extends AbstractPwmFilter
                         }
                         else
                         {
-                            LOGGER.debug( () -> "dropping non-query string (body?) parameter '" + paramName + "' during redirect validation)" );
+                            LOGGER.debug( pwmRequest, () -> "dropping non-query string (body?) parameter '" + paramName + "' during redirect validation)" );
                         }
                     }
                     catch ( final IOException e )
                     {
-                        LOGGER.trace( () -> "error decoding cookie value '" + paramName
+                        LOGGER.trace( pwmRequest, () -> "error decoding cookie value '" + paramName
                                 + "', error: " + e.getMessage() );
                     }
                 }
@@ -549,7 +549,7 @@ public class SessionFilter extends AbstractPwmFilter
                 return ProcessStatus.Continue;
             }
 
-            LOGGER.warn( () -> "invalidating session due to dirty page leave time greater then configured timeout" );
+            LOGGER.warn( pwmRequest, () -> "invalidating session due to dirty page leave time greater then configured timeout" );
             pwmRequest.invalidateSession();
             pwmRequest.getPwmResponse().sendRedirect( pwmRequest.getHttpServletRequest().getRequestURI() );
             return ProcessStatus.Halt;

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

@@ -507,7 +507,7 @@ public class ClientApiServlet extends ControlledPwmServlet
         }
 
         final String body = pwmRequest.readRequestBodyAsString();
-        LOGGER.trace( () -> body );
+        LOGGER.trace( pwmRequest, () -> body );
         return ProcessStatus.Halt;
     }
 

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

@@ -235,7 +235,7 @@ public class GuestRegistrationServlet extends ControlledPwmServlet
             final Instant expirationDate = readExpirationFromRequest( pwmRequest );
 
             // Update user attributes
-            LdapOperationsHelper.writeFormValuesToLdap( theGuest, formValues, pwmSession.getSessionManager().getMacroMachine( ), false );
+            LdapOperationsHelper.writeFormValuesToLdap( pwmSession.getLabel(), theGuest, formValues, pwmSession.getSessionManager().getMacroMachine( ), false );
 
             // Write expirationDate
             if ( expirationDate != null )

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/ShortcutServlet.java

@@ -195,7 +195,7 @@ public class ShortcutServlet extends ControlledPwmServlet
 
         final Collection<String> configValues = pwmRequest.getDomainConfig().readSettingAsLocalizedStringArray( PwmSetting.SHORTCUT_ITEMS, pwmRequest.getLocale() );
         final List<ShortcutItem> configuredItems = configValues.stream()
-                .map( ShortcutItem::parsePwmConfigInput )
+                .map( ( String input ) -> ShortcutItem.parsePwmConfigInput( input, pwmRequest.getLabel() ) )
                 .collect( Collectors.toUnmodifiableList() );
 
 
@@ -218,7 +218,7 @@ public class ShortcutServlet extends ControlledPwmServlet
     {
         if ( StringUtil.caseIgnoreContains( labelsFromHeader, item.getLabel() ) )
         {
-            LOGGER.trace( () -> "adding the shortcut item '" + item.getLabel() + "' due to presence of configured headers in request" );
+            LOGGER.trace( pwmRequest, () -> "adding the shortcut item '" + item.getLabel() + "' due to presence of configured headers in request" );
             return true;
         }
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/admin/AppDashboardData.java

@@ -35,7 +35,7 @@ import password.pwm.http.ContextManager;
 import password.pwm.http.bean.DisplayElement;
 import password.pwm.i18n.Admin;
 import password.pwm.i18n.Display;
-import password.pwm.ldap.LdapConnectionService;
+import password.pwm.ldap.LdapDomainService;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.node.NodeInfo;
 import password.pwm.svc.node.NodeService;
@@ -207,7 +207,7 @@ public class AppDashboardData implements Serializable
             }
         }
 
-        builder.ldapConnectionCount( LdapConnectionService.totalLdapConnectionCount( pwmDomain.getPwmApplication() ) );
+        builder.ldapConnectionCount( LdapDomainService.totalLdapConnectionCount( pwmDomain.getPwmApplication() ) );
         builder.sessionCount( pwmDomain.getSessionTrackService().sessionCount() );
         builder.requestsInProgress( pwmDomain.getPwmApplication().getActiveServletRequests().get() );
 

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java

@@ -212,7 +212,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
             final PwmPasswordRuleValidator pwmPasswordRuleValidator = PwmPasswordRuleValidator.create(
                     pwmRequest.getLabel(), pwmRequest.getPwmDomain(), userInfo.getPasswordPolicy() );
             final PasswordData oldPassword = pwmRequest.getPwmSession().getLoginInfoBean().getUserCurrentPassword();
-            pwmPasswordRuleValidator.testPassword( password1, oldPassword, userInfo, theUser );
+            pwmPasswordRuleValidator.testPassword( pwmRequest.getLabel(), password1, oldPassword, userInfo, theUser );
         }
         catch ( final PwmDataValidationException e )
         {

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/command/CommandServlet.java

@@ -101,11 +101,11 @@ public abstract class CommandServlet extends ControlledPwmServlet
         final String body = pwmRequest.readRequestBodyAsString();
         try
         {
-            LOGGER.trace( () -> "CSP Report: " + body );
+            LOGGER.trace( pwmRequest, () -> "CSP Report: " + body );
         }
         catch ( final Exception e )
         {
-            LOGGER.error( () -> "error processing csp report: " + e.getMessage() + ", body=" + body );
+            LOGGER.error( pwmRequest, () -> "error processing csp report: " + e.getMessage() + ", body=" + body );
         }
         return ProcessStatus.Halt;
     }

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

@@ -496,12 +496,12 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 {
                     final PwmSettingTemplate template = PwmSettingTemplate.valueOf( requestedTemplate );
                     modifier.writeConfigProperty( ConfigurationProperty.LDAP_TEMPLATE, template.toString() );
-                    LOGGER.trace( () -> "setting template to: " + requestedTemplate );
+                    LOGGER.trace( pwmRequest, () -> "setting template to: " + requestedTemplate );
                 }
                 catch ( final IllegalArgumentException e )
                 {
                     modifier.writeConfigProperty( ConfigurationProperty.LDAP_TEMPLATE, PwmSettingTemplate.DEFAULT.toString() );
-                    LOGGER.error( () -> "unknown template set request: " + requestedTemplate );
+                    LOGGER.error( pwmRequest, () -> "unknown template set request: " + requestedTemplate );
                 }
             }
         }
@@ -645,7 +645,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         final StringBuilder output = new StringBuilder();
         output.append( "beginning SMS send process:\n" );
 
-        if ( !SmsQueueService.smsIsConfigured( config.getAppConfig() ) )
+        if ( !config.getAppConfig().isSmsConfigured() )
         {
             output.append( "SMS not configured." );
         }
@@ -711,7 +711,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
 
                 try
                 {
-                    EmailService.sendEmailSynchronous( emailServer.get(), testDomainConfig, testEmailItem, macroRequest );
+                    EmailService.sendEmailSynchronous( emailServer.get(), testDomainConfig, testEmailItem, macroRequest, pwmRequest.getLabel() );
                     output.append( "message delivered" );
                 }
                 catch ( final PwmException e )

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServletUtils.java

@@ -151,7 +151,7 @@ public class ConfigEditorServletUtils
                                     record.getDomainID(), k -> new ArrayList<>() )
                             .add( record.getDetail( locale, pwmRequest.getAppConfig() ) ) );
 
-            LOGGER.debug( () -> "config health check done in ", TimeDuration.fromCurrent( startTime ) );
+            LOGGER.debug( pwmRequest.getLabel(), () -> "config health check done in ", TimeDuration.fromCurrent( startTime ) );
 
             return Collections.unmodifiableMap( returnData );
         }

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

@@ -48,7 +48,7 @@ public class SmtpCertImportFunction implements SettingUIFunction
         final PwmSession pwmSession = pwmRequest.getPwmSession();
         final String profile = key.getProfileID();
 
-        final List<X509Certificate> certs = EmailServerUtil.readCertificates( pwmRequest.getAppConfig(), profile );
+        final List<X509Certificate> certs = EmailServerUtil.readCertificates( pwmRequest.getAppConfig(), profile, pwmRequest.getLabel() );
         if ( !CollectionUtil.isEmpty( certs ) )
         {
             final UserIdentity userIdentity = pwmSession.isAuthenticated() ? pwmSession.getUserInfo().getUserIdentity() : null;

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

@@ -479,7 +479,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
             {
                 final GuideStep finalStep = step;
-                LOGGER.trace( () -> "setting current step to: " + finalStep );
+                LOGGER.trace( pwmRequest, () -> "setting current step to: " + finalStep );
             }
         }
 

+ 4 - 4
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideUtils.java

@@ -31,9 +31,8 @@ import password.pwm.PwmDomain;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
-import password.pwm.http.servlet.configeditor.function.UserMatchViewerFunction;
-import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.ConfigurationFileManager;
+import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.StoredConfigKey;
 import password.pwm.config.stored.StoredConfiguration;
 import password.pwm.config.stored.StoredConfigurationFactory;
@@ -50,10 +49,11 @@ import password.pwm.http.ContextManager;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequestAttribute;
 import password.pwm.http.bean.ConfigGuideBean;
+import password.pwm.http.servlet.configeditor.function.UserMatchViewerFunction;
 import password.pwm.i18n.Message;
+import password.pwm.ldap.LdapPermissionCalculator;
 import password.pwm.ldap.schema.SchemaManager;
 import password.pwm.ldap.schema.SchemaOperationResult;
-import password.pwm.ldap.LdapPermissionCalculator;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.Percent;
 import password.pwm.util.logging.PwmLogger;
@@ -115,7 +115,7 @@ public class ConfigGuideUtils
             // add a random security key
             StoredConfigurationUtil.initNewRandomSecurityKey( modifier );
 
-            configReader.saveConfiguration( modifier.newStoredConfiguration(), pwmApplication, null );
+            configReader.saveConfiguration( modifier.newStoredConfiguration(), pwmApplication );
 
             contextManager.requestPwmApplicationRestart();
         }

+ 1 - 2
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerServlet.java

@@ -319,8 +319,7 @@ public class ConfigManagerServlet extends AbstractPwmServlet
             final ContextManager contextManager = ContextManager.getContextManager( pwmRequest.getHttpServletRequest().getSession().getServletContext() );
             contextManager.getConfigReader().saveConfiguration(
                     storedConfiguration,
-                    pwmRequest.getPwmApplication(),
-                    pwmRequest.getLabel()
+                    pwmRequest.getPwmApplication()
             );
 
             contextManager.requestPwmApplicationRestart();

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/forgottenpw/RemoteVerificationMethod.java

@@ -114,7 +114,7 @@ public class RemoteVerificationMethod implements VerificationMethodSystem
     public void init( final PwmDomain pwmDomain, final UserInfo userInfo, final SessionLabel sessionLabel, final Locale locale )
             throws PwmUnrecoverableException
     {
-        pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( );
+        pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( sessionLabel );
         this.remoteSessionID = pwmDomain.getSecureService().pwmRandom().randomUUID().toString();
         this.userInfo = userInfo;
         this.sessionLabel = sessionLabel;
@@ -159,7 +159,7 @@ public class RemoteVerificationMethod implements VerificationMethodSystem
 
         try
         {
-            final PwmHttpClientResponse response = pwmHttpClient.makeRequest( pwmHttpClientRequest, this.sessionLabel );
+            final PwmHttpClientResponse response = pwmHttpClient.makeRequest( pwmHttpClientRequest );
             final String responseBodyStr = response.getBody();
             this.lastResponse = JsonFactory.get().deserialize( responseBodyStr, RemoteVerificationResponseBean.class );
         }

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationOptionsBean.java

@@ -118,7 +118,7 @@ public class HelpdeskVerificationOptionsBean implements Serializable
                 }
                 catch ( final PwmUnrecoverableException e )
                 {
-                    LOGGER.trace( () -> "error while calculating available token methods: " + e.getMessage() );
+                    LOGGER.trace( pwmRequest, () -> "error while calculating available token methods: " + e.getMessage() );
                 }
             }
             tokenDestinations = Collections.unmodifiableList( TokenDestinationItem.stripValues( returnList ) );

+ 2 - 1
server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java

@@ -162,7 +162,8 @@ public class NewUserServlet extends ControlledPwmServlet
         if ( StringUtil.notEmpty( signedFormData ) )
         {
             final Map<String, String> jsonForm = RestFormSigningServer.readSignedFormValue( pwmDomain, signedFormData );
-            LOGGER.trace( () -> "detected signedForm parameter in request, will read and place in bean; keys=" + JsonFactory.get().serializeCollection( jsonForm.keySet() ) );
+            LOGGER.trace( pwmRequest, () -> "detected signedForm parameter in request, will read and place in bean; keys="
+                    + JsonFactory.get().serializeCollection( jsonForm.keySet() ) );
             newUserBean.setRemoteInputData( jsonForm );
         }
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/oauth/OAuthMachine.java

@@ -289,8 +289,8 @@ public class OAuthMachine
                     .certificates( CollectionUtil.isEmpty( certs ) ? null : certs )
                     .maskBodyDebugOutput( true )
                     .build();
-            final PwmHttpClient pwmHttpClient = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient( config );
-            pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest, pwmRequest.getLabel() );
+            final PwmHttpClient pwmHttpClient = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient( config, pwmRequest.getLabel() );
+            pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest );
         }
         catch ( final PwmException e )
         {

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/peoplesearch/PhotoDataReader.java

@@ -227,7 +227,7 @@ public class PhotoDataReader
             throws PwmUnrecoverableException, PwmOperationalException
     {
         final Optional<String> overrideURL = getPhotoUrlOverride( userIdentity );
-        if ( !overrideURL.isPresent() )
+        if ( overrideURL.isEmpty() )
         {
             return Optional.empty();
         }
@@ -237,12 +237,12 @@ public class PhotoDataReader
             final PwmHttpClientConfiguration configuration = PwmHttpClientConfiguration.builder()
                     .trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous )
                     .build();
-            final PwmHttpClient pwmHttpClient = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient( configuration );
+            final PwmHttpClient pwmHttpClient = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient( configuration, pwmRequest.getLabel() );
             final PwmHttpClientRequest clientRequest = PwmHttpClientRequest.builder()
                     .method( HttpMethod.GET )
                     .url( overrideURL.get() )
                     .build();
-            final PwmHttpClientResponse response = pwmHttpClient.makeRequest( clientRequest, pwmRequest.getLabel() );
+            final PwmHttpClientResponse response = pwmHttpClient.makeRequest( clientRequest );
             if ( response != null )
             {
                 final ImmutableByteArray bodyContents = response.getBinaryBody();

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileUtil.java

@@ -367,7 +367,7 @@ public class UpdateProfileUtil
         // write values.
         LOGGER.info( sessionLabel, () -> "updating profile for " + userInfo.getUserIdentity() );
 
-        LdapOperationsHelper.writeFormValuesToLdap( theUser, formMap, macroRequest, false );
+        LdapOperationsHelper.writeFormValuesToLdap( sessionLabel, theUser, formMap, macroRequest, false );
 
         postUpdateActionsAndEmail( pwmDomain, sessionLabel, locale, userInfo.getUserIdentity(), updateProfileProfile );
 

+ 1 - 1
server/src/main/java/password/pwm/http/state/SessionStateService.java

@@ -198,7 +198,7 @@ public class SessionStateService extends AbstractPwmService implements PwmServic
         }
         catch ( final ReflectiveOperationException e )
         {
-            LOGGER.warn( () -> "unexpected reflective error reading session bean: " + e.getMessage(), e );
+            LOGGER.warn( getSessionLabel(), () -> "unexpected reflective error reading session bean: " + e.getMessage(), e );
         }
         return false;
     }

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

@@ -115,9 +115,9 @@ public class DisplayTag extends PwmAbstractTag
     public int doEndTag( )
             throws javax.servlet.jsp.JspTagException
     {
+        PwmRequest pwmRequest = null;
         try
         {
-            PwmRequest pwmRequest = null;
             try
             {
                 pwmRequest = PwmRequest.forRequest( ( HttpServletRequest ) pageContext.getRequest(), ( HttpServletResponse ) pageContext.getResponse() );
@@ -143,19 +143,19 @@ public class DisplayTag extends PwmAbstractTag
         catch ( final PwmUnrecoverableException e )
         {
             {
-                LOGGER.debug( () -> "error while executing jsp display tag: " + e.getMessage() );
+                LOGGER.debug( pwmRequest, () -> "error while executing jsp display tag: " + e.getMessage() );
                 return EVAL_PAGE;
             }
         }
         catch ( final Exception e )
         {
-            LOGGER.debug( () -> "error while executing jsp display tag: " + e.getMessage(), e );
+            LOGGER.debug( pwmRequest, () -> "error while executing jsp display tag: " + e.getMessage(), e );
             throw new JspTagException( e.getMessage(), e );
         }
         return EVAL_PAGE;
     }
 
-    private Class readBundle( )
+    private Class<?> readBundle( )
     {
         if ( bundle == null || bundle.length() < 1 )
         {

+ 8 - 8
server/src/main/java/password/pwm/ldap/LdapConnectionService.java → server/src/main/java/password/pwm/ldap/LdapDomainService.java

@@ -66,9 +66,9 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 
-public class LdapConnectionService extends AbstractPwmService implements PwmService
+public class LdapDomainService extends AbstractPwmService implements PwmService
 {
-    private static final PwmLogger LOGGER = PwmLogger.forClass( LdapConnectionService.class );
+    private static final PwmLogger LOGGER = PwmLogger.forClass( LdapDomainService.class );
 
     private final Map<String, ErrorInformation> lastLdapErrors = new ConcurrentHashMap<>();
     private final ThreadLocal<ThreadLocalContainer> threadLocalProvider = new ThreadLocal<>();
@@ -91,7 +91,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
     {
         return pwmApplication.domains().values().stream()
                 .map( PwmDomain::getLdapConnectionService )
-                .map( LdapConnectionService::connectionCount )
+                .map( LdapDomainService::connectionCount )
                 .map( Long::valueOf )
                 .reduce( 0L, Long::sum );
     }
@@ -142,13 +142,13 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
         this.chaiProviderFactory = ChaiProviderFactory.newProviderFactory();
 
         useThreadLocal = Boolean.parseBoolean( pwmDomain.getConfig().readAppProperty( AppProperty.LDAP_PROXY_USE_THREAD_LOCAL ) );
-        LOGGER.trace( () -> "threadLocal enabled: " + useThreadLocal );
+        LOGGER.trace( getSessionLabel(), () -> "threadLocal enabled: " + useThreadLocal );
 
         // read the lastLoginTime
         this.lastLdapErrors.putAll( pwmApplication.readLastLdapFailure( getDomainID() ) );
 
         final int connectionsPerProfile = maxSlotsPerProfile( pwmDomain );
-        LOGGER.trace( () -> "allocating " + connectionsPerProfile + " ldap proxy connections per profile" );
+        LOGGER.trace( getSessionLabel(), () -> "allocating " + connectionsPerProfile + " ldap proxy connections per profile" );
         slotIncrementer = AtomicLoopIntIncrementer.builder().ceiling( connectionsPerProfile ).build();
 
         for ( final LdapProfile ldapProfile : pwmDomain.getConfig().getLdapProfiles().values() )
@@ -164,7 +164,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
     {
         setStatus( STATUS.CLOSED );
         logDebugInfo();
-        LOGGER.trace( () -> "closing ldap proxy connections" );
+        LOGGER.trace( getSessionLabel(), () -> "closing ldap proxy connections" );
 
         try
         {
@@ -172,7 +172,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
         }
         catch ( final Exception e )
         {
-            LOGGER.error( () -> "error closing ldap proxy connection: " + e.getMessage(), e );
+            LOGGER.error( getSessionLabel(), () -> "error closing ldap proxy connection: " + e.getMessage(), e );
         }
 
         proxyChaiProviders.clear();
@@ -456,7 +456,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
                 {
                     for ( final ChaiProvider chaiProvider : container.getProviderMap().values() )
                     {
-                        LOGGER.trace( () -> "discarding idled connection id=" + chaiProvider.toString() + " from orphaned threadLocal, age="
+                        LOGGER.trace( getSessionLabel(), () -> "discarding idled connection id=" + chaiProvider.toString() + " from orphaned threadLocal, age="
                                 + age.asCompactString() + ", thread=" + container.getThreadName() );
                         stats.increment( StatKey.clearedThreadLocals );
                     }

+ 138 - 112
server/src/main/java/password/pwm/ldap/LdapOperationsHelper.java

@@ -243,7 +243,7 @@ public class LdapOperationsHelper
             {
                 if ( ldapProfile.readSettingAsBoolean( PwmSetting.LDAP_GUID_AUTO_ADD ) )
                 {
-                    LOGGER.trace( () -> "assigning new GUID to user " + userIdentity );
+                    LOGGER.trace( sessionLabel, () -> "assigning new GUID to user " + userIdentity );
                     return GuidReaderUtil.assignGuidToUser( pwmDomain, sessionLabel, userIdentity, guidAttributeName );
                 }
             }
@@ -275,9 +275,10 @@ public class LdapOperationsHelper
      * @param macroRequest used to resolve macros before values are written.
      * @param expandMacros a boolean to indicate if value macros should be expanded.
      * @throws ChaiUnavailableException if the directory is unavailable
-     * @throws PwmUnrecoverableException if their is an unexpected ldap problem
+     * @throws PwmUnrecoverableException if there is an unexpected ldap problem
      */
     public static void writeFormValuesToLdap(
+            final SessionLabel sessionLabel,
             final ChaiUser theUser,
             final Map<FormConfiguration, String> valueMap,
             final MacroRequest macroRequest,
@@ -287,73 +288,78 @@ public class LdapOperationsHelper
     {
         for ( final Map.Entry<FormConfiguration, String> entry : valueMap.entrySet() )
         {
-            final FormConfiguration formItem = entry.getKey();
-            if ( !formItem.isReadonly() )
+            writeFormValueToLdap( sessionLabel, theUser, entry.getKey(), entry.getValue(), macroRequest, expandMacros );
+        }
+    }
+
+    private static void writeFormValueToLdap(
+            final SessionLabel sessionLabel,
+            final ChaiUser theUser,
+            final FormConfiguration formItem,
+            final String value,
+            final MacroRequest macroRequest,
+            final boolean expandMacros
+    )
+            throws PwmUnrecoverableException, ChaiUnavailableException
+    {
+        if ( formItem.isReadonly() )
+        {
+            return;
+        }
+
+        final String attrName = formItem.getName();
+        if ( formItem.getType() == FormConfiguration.Type.photo )
+        {
+            writePhotoFormValue( sessionLabel, formItem, theUser, value );
+        }
+        else
+        {
+            String attrValue = value != null
+                    ? value
+                    : "";
+
+            if ( expandMacros )
+            {
+                attrValue = macroRequest.expandMacros( attrValue );
+            }
+
+            final String currentValue;
+            try
+            {
+                currentValue = theUser.readStringAttribute( attrName );
+            }
+            catch ( final ChaiOperationException e )
             {
-                final String attrName = formItem.getName();
-                if ( formItem.getType() == FormConfiguration.Type.photo )
+                final String errorMsg = "error reading existing values on user " + theUser.getEntryDN() + " prior to replacing values, error: " + e.getMessage();
+                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
+                throw new PwmUnrecoverableException( errorInformation );
+            }
+
+            if ( !attrValue.equals( currentValue ) )
+            {
+                if ( attrValue.length() > 0 )
                 {
-                    final String sValue = entry.getValue();
-                    final byte[] newBytes;
                     try
                     {
-                        newBytes = StringUtil.base64Decode( sValue );
+                        theUser.writeStringAttribute( attrName, attrValue );
+                        final String finalAttrValue = attrValue;
+                        LOGGER.info( sessionLabel, () -> "set attribute on user " + theUser.getEntryDN() + " (" + attrName + "=" + finalAttrValue + ")" );
                     }
-                    catch ( final IOException e )
-                    {
-                        throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "error processing binary form value: " + e.getMessage() );
-                    }
-
-                    final byte[] existingBytes;
-                    {
-                        final byte[][] existingMultiByte;
-                        try
-                        {
-                            existingMultiByte = theUser.readMultiByteAttribute( attrName );
-                            if ( existingMultiByte != null && existingMultiByte.length > 0 )
-                            {
-                                existingBytes = existingMultiByte[ 0 ];
-                            }
-                            else
-                            {
-                                existingBytes = null;
-                            }
-                        }
-                        catch ( final ChaiOperationException e )
-                        {
-                            final String errorMsg = "error reading existing values on user " + theUser.getEntryDN()
-                                    + " prior to replacing values, error: " + e.getMessage();
-                            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
-                            throw new PwmUnrecoverableException( errorInformation );
-                        }
-                    }
-
-                    if ( StringUtil.notEmpty( sValue ) )
+                    catch ( final ChaiOperationException e )
                     {
-                        if ( !Arrays.equals( existingBytes, newBytes ) )
-                        {
-                            if ( newBytes.length > 0 )
-                            {
-                                try
-                                {
-                                    theUser.writeBinaryAttribute( attrName, newBytes );
-                                }
-                                catch ( final ChaiOperationException e )
-                                {
-                                    final String errorMsg = "error setting '" + attrName + "' attribute on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
-                                    final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
-                                    throw new PwmUnrecoverableException( errorInformation );
-                                }
-                                LOGGER.info( () -> "set attribute on user " + theUser.getEntryDN() + " (" + formItem + "=[base64]" + sValue + ")" );
-                            }
-                        }
+                        final String errorMsg = "error setting '" + attrName + "' attribute on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
+                        final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
+                        throw new PwmUnrecoverableException( errorInformation );
                     }
-                    else if ( existingBytes != null && existingBytes.length > 0 )
+                }
+                else
+                {
+                    if ( currentValue != null && currentValue.length() > 0 )
                     {
                         try
                         {
                             theUser.deleteAttribute( attrName, null );
-                            LOGGER.info( () -> "deleted binary attribute value on user " + theUser.getEntryDN() + " (" + attrName + ")" );
+                            LOGGER.info( sessionLabel, () -> "deleted attribute value on user " + theUser.getEntryDN() + " (" + attrName + ")" );
                         }
                         catch ( final ChaiOperationException e )
                         {
@@ -363,74 +369,94 @@ public class LdapOperationsHelper
                         }
                     }
                 }
+            }
+            else
+            {
+                LOGGER.debug( sessionLabel, () -> "skipping attribute modify for attribute '" + attrName + "', no change in value" );
+            }
+        }
+    }
+
+    private static void writePhotoFormValue(
+            final SessionLabel sessionLabel,
+            final FormConfiguration formItem,
+            final ChaiUser theUser,
+            final String value
+    )
+            throws PwmUnrecoverableException, ChaiUnavailableException
+    {
+        final byte[] newBytes;
+        try
+        {
+            newBytes = StringUtil.base64Decode( value );
+        }
+        catch ( final IOException e )
+        {
+            throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "error processing binary form value: " + e.getMessage() );
+        }
+
+        final String attrName = formItem.getName();
+        final byte[] existingBytes;
+        {
+            final byte[][] existingMultiByte;
+            try
+            {
+                existingMultiByte = theUser.readMultiByteAttribute( attrName );
+                if ( existingMultiByte != null && existingMultiByte.length > 0 )
+                {
+                    existingBytes = existingMultiByte[ 0 ];
+                }
                 else
                 {
-                    final String value = entry.getValue();
-                    String attrValue = value != null
-                            ? value
-                            : "";
-
-                    if ( expandMacros )
-                    {
-                        attrValue = macroRequest.expandMacros( attrValue );
-                    }
+                    existingBytes = null;
+                }
+            }
+            catch ( final ChaiOperationException e )
+            {
+                final String errorMsg = "error reading existing values on user " + theUser.getEntryDN()
+                        + " prior to replacing values, error: " + e.getMessage();
+                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
+                throw new PwmUnrecoverableException( errorInformation );
+            }
+        }
 
-                    final String currentValue;
+        if ( StringUtil.notEmpty( value ) )
+        {
+            if ( !Arrays.equals( existingBytes, newBytes ) )
+            {
+                if ( newBytes.length > 0 )
+                {
                     try
                     {
-                        currentValue = theUser.readStringAttribute( attrName );
+                        theUser.writeBinaryAttribute( attrName, newBytes );
                     }
                     catch ( final ChaiOperationException e )
                     {
-                        final String errorMsg = "error reading existing values on user " + theUser.getEntryDN() + " prior to replacing values, error: " + e.getMessage();
+                        final String errorMsg = "error setting '" + attrName + "' attribute on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
                         final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
                         throw new PwmUnrecoverableException( errorInformation );
                     }
-
-                    if ( !attrValue.equals( currentValue ) )
-                    {
-                        if ( attrValue.length() > 0 )
-                        {
-                            try
-                            {
-                                theUser.writeStringAttribute( attrName, attrValue );
-                                final String finalAttrValue = attrValue;
-                                LOGGER.info( () -> "set attribute on user " + theUser.getEntryDN() + " (" + attrName + "=" + finalAttrValue + ")" );
-                            }
-                            catch ( final ChaiOperationException e )
-                            {
-                                final String errorMsg = "error setting '" + attrName + "' attribute on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
-                                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
-                                throw new PwmUnrecoverableException( errorInformation );
-                            }
-                        }
-                        else
-                        {
-                            if ( currentValue != null && currentValue.length() > 0 )
-                            {
-                                try
-                                {
-                                    theUser.deleteAttribute( attrName, null );
-                                    LOGGER.info( () -> "deleted attribute value on user " + theUser.getEntryDN() + " (" + attrName + ")" );
-                                }
-                                catch ( final ChaiOperationException e )
-                                {
-                                    final String errorMsg = "error removing '" + attrName + "' attribute value on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
-                                    final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
-                                    throw new PwmUnrecoverableException( errorInformation );
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        LOGGER.debug( () -> "skipping attribute modify for attribute '" + attrName + "', no change in value" );
-                    }
+                    LOGGER.info( sessionLabel, () -> "set attribute on user " + theUser.getEntryDN() + " (" + formItem + "=[base64]" + value + ")" );
                 }
             }
         }
+        else if ( existingBytes != null && existingBytes.length > 0 )
+        {
+            try
+            {
+                theUser.deleteAttribute( attrName, null );
+                LOGGER.info( sessionLabel, () -> "deleted binary attribute value on user " + theUser.getEntryDN() + " (" + attrName + ")" );
+            }
+            catch ( final ChaiOperationException e )
+            {
+                final String errorMsg = "error removing '" + attrName + "' attribute value on user " + theUser.getEntryDN() + ", error: " + e.getMessage();
+                final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, errorMsg );
+                throw new PwmUnrecoverableException( errorInformation );
+            }
+        }
     }
 
+
     private static class GuidReaderUtil
     {
         private static String readExistingGuidValue(
@@ -452,10 +478,10 @@ public class LdapOperationsHelper
 
             if ( guidMode == AbstractProfile.GuidMode.VENDORGUID )
             {
-               return readVendorGuid( theUser, sessionLabel, throwExceptionOnError );
+                return readVendorGuid( theUser, sessionLabel, throwExceptionOnError );
             }
 
-           return readAttributeGuid( ldapProfile, userIdentity, theUser, throwExceptionOnError );
+            return readAttributeGuid( ldapProfile, userIdentity, theUser, throwExceptionOnError );
         }
 
         private static String readAttributeGuid(

+ 1 - 2
server/src/main/java/password/pwm/ldap/LdapPermissionCalculator.java

@@ -44,7 +44,6 @@ import password.pwm.i18n.Config;
 import password.pwm.ldap.permission.UserPermissionType;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.svc.sms.SmsQueueService;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -367,7 +366,7 @@ public class LdapPermissionCalculator implements Serializable
 
             case SMS_USER_PHONE_ATTRIBUTE:
             {
-                if ( !SmsQueueService.smsIsConfigured( domainConfig.getAppConfig() ) )
+                if ( !domainConfig.getAppConfig().isSmsConfigured() )
                 {
                     return Collections.emptyList();
                 }

+ 2 - 2
server/src/main/java/password/pwm/ldap/LdapUserInfoReader.java

@@ -233,7 +233,7 @@ public class LdapUserInfoReader implements UserInfo
                 try
                 {
                     final PwmPasswordRuleValidator passwordRuleValidator = PwmPasswordRuleValidator.create( sessionLabel, pwmDomain, passwordPolicy );
-                    passwordRuleValidator.testPassword( currentPassword, null, selfCachedReference, chaiUser );
+                    passwordRuleValidator.testPassword( sessionLabel, currentPassword, null, selfCachedReference, chaiUser );
                 }
                 catch ( final PwmDataValidationException | PwmUnrecoverableException e )
                 {
@@ -429,7 +429,7 @@ public class LdapUserInfoReader implements UserInfo
     @Override
     public boolean isRequiresOtpConfig( ) throws PwmUnrecoverableException
     {
-        LOGGER.trace( sessionLabel, () ->  "checkOtp: beginning process to check if user OTP setup is required" );
+        LOGGER.trace( sessionLabel, () -> "checkOtp: beginning process to check if user OTP setup is required" );
 
         SetupOtpProfile setupOtpProfile = null;
         final Map<ProfileDefinition, String> profileIDs = selfCachedReference.getProfileIDs();

+ 2 - 2
server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java

@@ -319,7 +319,7 @@ public class PasswordChangeProgressChecker
                     pwmSession, userIdentity );
             if ( checkResults.size() <= 1 )
             {
-                LOGGER.trace( () -> "only one replica returned data, marking as complete" );
+                LOGGER.trace( pwmSession, () -> "only one replica returned data, marking as complete" );
                 return Optional.of( completedReplicationRecord );
             }
             else
@@ -339,7 +339,7 @@ public class PasswordChangeProgressChecker
                 }
                 final Percent pctComplete = Percent.of( duplicateValues + 1, checkResults.size() );
                 final ProgressRecord progressRecord = makeReplicaProgressRecord( pctComplete );
-                LOGGER.trace( () -> "read password replication sync status as: " + JsonFactory.get().serialize( progressRecord ) );
+                LOGGER.trace( pwmSession, () -> "read password replication sync status as: " + JsonFactory.get().serialize( progressRecord ) );
                 return Optional.of( progressRecord );
             }
         }

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

@@ -765,7 +765,7 @@ public class UserSearchEngine extends AbstractPwmService implements PwmService
 
     private void periodicDebugOutput( )
     {
-        LOGGER.trace( () -> "periodic debug status: " + StringUtil.mapToString( debugProperties() ) );
+        LOGGER.trace( getSessionLabel(), () -> "periodic debug status: " + StringUtil.mapToString( debugProperties() ) );
     }
 
     void log( final PwmLogLevel level, final SessionLabel sessionLabel, final int searchID, final int jobID, final String message )
@@ -812,7 +812,7 @@ public class UserSearchEngine extends AbstractPwmService implements PwmService
             final int threads = Math.min( maxThreads, ( endPoints ) * factor );
             final int minThreads = JavaHelper.rangeCheck( 1, 10, endPoints );
 
-            LOGGER.trace( () -> "initialized with threads min=" + minThreads + " max=" + threads );
+            LOGGER.trace( getSessionLabel(), () -> "initialized with threads min=" + minThreads + " max=" + threads );
 
             return PwmScheduler.makeMultiThreadExecutor( threads, getPwmApplication(), getSessionLabel(), UserSearchEngine.class );
         }

+ 3 - 2
server/src/main/java/password/pwm/svc/PwmServiceEnum.java

@@ -23,6 +23,7 @@ package password.pwm.svc;
 import password.pwm.bean.DomainID;
 import password.pwm.config.PwmSettingScope;
 import password.pwm.health.HealthService;
+import password.pwm.ldap.LdapDomainService;
 import password.pwm.svc.email.EmailService;
 import password.pwm.svc.intruder.IntruderDomainService;
 import password.pwm.svc.intruder.IntruderSystemService;
@@ -52,7 +53,7 @@ public enum PwmServiceEnum
     WordlistService( WordlistService.class, PwmSettingScope.SYSTEM, Flag.StartDuringRuntimeInstance ),
     SeedlistService( SeedlistService.class, PwmSettingScope.SYSTEM ),
     IntruderSystemService( IntruderSystemService.class, PwmSettingScope.SYSTEM ),
-    EmailService( EmailService.class, PwmSettingScope.SYSTEM, Flag.StartDuringRuntimeInstance ),
+    EmailService( EmailService.class, PwmSettingScope.SYSTEM ),
     SmsQueueManager( SmsQueueService.class, PwmSettingScope.SYSTEM ),
     UrlShortenerService( password.pwm.svc.shorturl.UrlShortenerService.class, PwmSettingScope.SYSTEM ),
     CacheService( password.pwm.svc.cache.CacheService.class, PwmSettingScope.SYSTEM, Flag.StartDuringRuntimeInstance ),
@@ -66,7 +67,7 @@ public enum PwmServiceEnum
     NodeService( NodeService.class, PwmSettingScope.SYSTEM ),
 
     DomainSecureService( password.pwm.svc.secure.DomainSecureService.class, PwmSettingScope.DOMAIN, Flag.StartDuringRuntimeInstance ),
-    LdapConnectionService( password.pwm.ldap.LdapConnectionService.class, PwmSettingScope.DOMAIN, Flag.StartDuringRuntimeInstance ),
+    LdapConnectionService( LdapDomainService.class, PwmSettingScope.DOMAIN, Flag.StartDuringRuntimeInstance ),
     CrService( password.pwm.svc.cr.CrService.class, PwmSettingScope.DOMAIN, Flag.StartDuringRuntimeInstance ),
     OtpService( password.pwm.svc.otp.OtpService.class, PwmSettingScope.DOMAIN ),
     IntruderDomainService( IntruderDomainService.class, PwmSettingScope.DOMAIN ),

+ 15 - 7
server/src/main/java/password/pwm/svc/PwmServiceManager.java

@@ -127,6 +127,11 @@ public class PwmServiceManager
         LOGGER.trace( sessionLabel, () -> logVerb + "ed services, " + statCounter.debugStats(), TimeDuration.fromCurrent( startTime ) );
     }
 
+    private String debugSvcType()
+    {
+        return ( domainID.isSystem() ? "system" : "domain" ) + " service";
+    }
+
     private PwmService initService( final PwmServiceEnum pwmServiceEnum )
             throws PwmUnrecoverableException
     {
@@ -134,6 +139,7 @@ public class PwmServiceManager
         final PwmService newServiceInstance;
 
         final String serviceName = pwmServiceEnum.serviceName( domainID );
+
         try
         {
             final Class<? extends PwmService> serviceClass = pwmServiceEnum.getPwmServiceClass();
@@ -141,7 +147,7 @@ public class PwmServiceManager
         }
         catch ( final Exception e )
         {
-            final String errorMsg = "unexpected error instantiating service class '" + serviceName + "', error: " + e;
+            final String errorMsg = "unexpected error instantiating " + debugSvcType() + " class '" + serviceName + "', error: " + e;
             LOGGER.fatal( () -> errorMsg, e );
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_STARTUP_ERROR, errorMsg ) );
         }
@@ -151,16 +157,17 @@ public class PwmServiceManager
             LOGGER.trace( sessionLabel, () -> "initializing service " + serviceName );
             newServiceInstance.init( pwmApplication, domainID );
             final TimeDuration startupDuration = TimeDuration.fromCurrent( startTime );
-            LOGGER.debug( sessionLabel, () -> "completed initialization of service " + serviceName + " in " + startupDuration.asCompactString()
+            LOGGER.debug( sessionLabel, () -> "completed initialization of " + debugSvcType()
+                    + " " + serviceName + " in " + startupDuration.asCompactString()
                     + ", status=" + newServiceInstance.status() );
         }
         catch ( final PwmException e )
         {
-            LOGGER.warn( () -> "error instantiating service class '" + serviceName + "', service will remain unavailable, error: " + e.getMessage() );
+            LOGGER.warn( sessionLabel, () -> "error instantiating " + debugSvcType() + " class '" + serviceName + "', service will remain unavailable, error: " + e.getMessage() );
         }
         catch ( final Exception e )
         {
-            String errorMsg = "unexpected error instantiating service class '" + serviceName + "', cannot load, error: " + e.getMessage();
+            String errorMsg = "unexpected error instantiating " + debugSvcType() + " class '" + serviceName + "', cannot load, error: " + e.getMessage();
             if ( e.getCause() != null )
             {
                 errorMsg += ", cause: " + e.getCause();
@@ -200,18 +207,19 @@ public class PwmServiceManager
     private void shutDownService( final PwmServiceEnum pwmServiceEnum, final PwmService serviceInstance )
     {
 
-        LOGGER.trace( sessionLabel, () -> "closing service " + pwmServiceEnum.serviceName( domainID ) );
+        LOGGER.trace( sessionLabel, () -> "closing " + debugSvcType() + " " + pwmServiceEnum.serviceName( domainID ) );
 
         try
         {
             final Instant startTime = Instant.now();
             serviceInstance.shutdown();
             final TimeDuration timeDuration = TimeDuration.fromCurrent( startTime );
-            LOGGER.trace( () -> "successfully closed service " + pwmServiceEnum.serviceName( domainID ) + " (" + timeDuration.asCompactString() + ")" );
+            LOGGER.trace( sessionLabel, () -> "successfully closed " + debugSvcType() + " " + pwmServiceEnum.serviceName( domainID )
+                    + " (" + timeDuration.asCompactString() + ")" );
         }
         catch ( final Exception e )
         {
-            LOGGER.error( sessionLabel, () -> "error closing " + pwmServiceEnum.serviceName( domainID ) + ": " + e.getMessage(), e );
+            LOGGER.error( sessionLabel, () -> "error closing " + debugSvcType() + " " + pwmServiceEnum.serviceName( domainID ) + ": " + e.getMessage(), e );
         }
     }
 

+ 1 - 1
server/src/main/java/password/pwm/svc/cache/CacheService.java

@@ -186,6 +186,6 @@ public class CacheService extends AbstractPwmService implements PwmService
             traceOutput.append( ", histogram=" );
             traceOutput.append( JsonFactory.get().serializeMap( memoryCacheStore.storedClassHistogram( "" ) ) );
         }
-        LOGGER.trace( () -> traceOutput );
+        LOGGER.trace( getSessionLabel(), () -> traceOutput );
     }
 }

+ 26 - 6
server/src/main/java/password/pwm/svc/cr/CrService.java

@@ -156,9 +156,6 @@ public class CrService extends AbstractPwmService implements PwmService
                     }
                     else
                     {
-                        final ChallengeSet finalReturnSet = returnSet;
-                        LOGGER.debug( sessionLabel, () -> "using nmas c/r policy for user " + theUser.getEntryDN() + ": " + finalReturnSet );
-
                         final String challengeID = "nmasPolicy-" + userIdentity.toDelimitedKey();
 
                         final ChallengeProfile challengeProfile = ChallengeProfile.createChallengeProfile(
@@ -170,9 +167,32 @@ public class CrService extends AbstractPwmService implements PwmService
                                 0
                         );
 
-                        LOGGER.debug( sessionLabel, () -> "using ldap c/r policy for user " + theUser.getEntryDN() + ": "
-                                + finalReturnSet );
-                        LOGGER.trace( sessionLabel, () -> "readUserChallengeProfile completed, result=" + JsonFactory.get().serialize( challengeProfile ),
+                        {
+                            final Optional<ChallengeSet> challengeSet = challengeProfile.getChallengeSet();
+                            if ( challengeSet.isPresent() )
+                            {
+                                LOGGER.debug( sessionLabel, () -> "using nmas ldap c/r policy for user " + theUser.getEntryDN() + ": "
+                                        + JsonFactory.get().serialize( challengeSet.get().asChallengeSetBean() ) );
+                            }
+                            else
+                            {
+                                LOGGER.debug( sessionLabel, () -> "nmas ldap c/r policy for user is empty" );
+                            }
+                        }
+                        {
+                            final Optional<ChallengeSet> challengeSet = challengeProfile.getHelpdeskChallengeSet();
+                            if ( challengeSet.isPresent() )
+                            {
+                                LOGGER.debug( sessionLabel, () -> "using nmas ldap c/r helpdesk policy for user " + theUser.getEntryDN() + ": "
+                                        + JsonFactory.get().serialize( challengeSet.get().asChallengeSetBean() ) );
+                            }
+                            else
+                            {
+                                LOGGER.debug( sessionLabel, () -> "nmas ldap c/r helpdesk policy for user is empty" );
+                            }
+                        }
+
+                        LOGGER.trace( sessionLabel, () -> "readUserChallengeProfile completed",
                                 TimeDuration.fromCurrent( methodStartTime ) );
 
                         return challengeProfile;

+ 84 - 57
server/src/main/java/password/pwm/svc/cr/NMASCrOperator.java

@@ -77,9 +77,10 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.ldap.LdapOperationsHelper;
 import password.pwm.svc.intruder.IntruderServiceClient;
 import password.pwm.util.PasswordData;
+import password.pwm.util.PwmScheduler;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
-import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 
 import javax.security.auth.callback.Callback;
@@ -109,9 +110,9 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.TreeMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 public class NMASCrOperator implements CrOperator
 {
@@ -124,14 +125,14 @@ public class NMASCrOperator implements CrOperator
     private final int maxThreadCount;
 
 
-    private volatile Timer timer;
+    private volatile ScheduledExecutorService executorService;
 
     private Provider saslProvider;
 
     private static final Map<String, Object> CR_OPTIONS_MAP = Map.of(
-                "com.novell.security.sasl.client.pkgs", "com.novell.sasl.client",
-                "javax.security.sasl.client.pkgs", "com.novell.sasl.client",
-                "LoginSequence", "Challenge Response" );
+            "com.novell.security.sasl.client.pkgs", "com.novell.sasl.client",
+            "javax.security.sasl.client.pkgs", "com.novell.sasl.client",
+            "LoginSequence", "Challenge Response" );
 
     public NMASCrOperator( final PwmDomain pwmDomain )
     {
@@ -162,18 +163,20 @@ public class NMASCrOperator implements CrOperator
         {
             if ( forceRegistration )
             {
-                LOGGER.warn( () -> "SASL provider '" + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME + "' is already defined, however forcing registration due to app property "
+                LOGGER.warn( pwmDomain.getSessionLabel(), () -> "SASL provider '" + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME
+                        + "' is already defined, however forcing registration due to app property "
                         + AppProperty.NMAS_FORCE_SASL_FACTORY_REGISTRATION.getKey() + " value" );
             }
             else
             {
-                LOGGER.warn( () -> "SASL provider '" + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME + "' is already defined, skipping SASL factory registration" );
+                LOGGER.warn( pwmDomain.getSessionLabel(), () -> "SASL provider '" + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME
+                        + "' is already defined, skipping SASL factory registration" );
                 return;
             }
         }
         else
         {
-            LOGGER.trace( () -> "pre-existing SASL provider for " + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME + " has not been detected" );
+            LOGGER.trace( pwmDomain.getSessionLabel(), () -> "pre-existing SASL provider for " + NMASCrPwmSaslProvider.SASL_PROVIDER_NAME + " has not been detected" );
         }
 
         final boolean useLocalProvider = Boolean.parseBoolean( pwmDomain.getConfig().readAppProperty( AppProperty.NMAS_USE_LOCAL_SASL_FACTORY ) );
@@ -182,19 +185,19 @@ public class NMASCrOperator implements CrOperator
         {
             if ( useLocalProvider )
             {
-                LOGGER.trace( () -> "registering built-in local SASL provider" );
+                LOGGER.trace( pwmDomain.getSessionLabel(), () -> "registering built-in local SASL provider" );
                 saslProvider = new NMASCrPwmSaslProvider();
             }
             else
             {
-                LOGGER.trace( () -> "registering NMAS library SASL provider" );
+                LOGGER.trace( pwmDomain.getSessionLabel(), () -> "registering NMAS library SASL provider" );
                 saslProvider = new com.novell.sasl.client.NovellSaslProvider();
             }
-            LOGGER.trace( () -> "initialized security provider " + saslProvider.getClass().getName() );
+            LOGGER.trace( pwmDomain.getSessionLabel(), () -> "initialized security provider " + saslProvider.getClass().getName() );
         }
         catch ( final Throwable t )
         {
-            LOGGER.warn( () -> "unable to create SASL provider, error: " + t.getMessage(), t );
+            LOGGER.warn( pwmDomain.getSessionLabel(), () -> "unable to create SASL provider, error: " + t.getMessage(), t );
         }
 
         if ( saslProvider != null )
@@ -205,7 +208,7 @@ public class NMASCrOperator implements CrOperator
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "error registering security provider" );
+                LOGGER.warn( pwmDomain.getSessionLabel(), () -> "error registering security provider" );
             }
         }
     }
@@ -232,23 +235,26 @@ public class NMASCrOperator implements CrOperator
         {
             if ( sessionMonitorThreads.isEmpty() )
             {
-                final Timer localTimer = timer;
+                final ScheduledExecutorService localTimer = executorService;
                 if ( localTimer != null )
                 {
-                    LOGGER.debug( () -> "discontinuing NMASCrOperator watchdog timer, no active threads" );
-                    localTimer.cancel();
-                    timer = null;
+                    LOGGER.debug( pwmDomain.getSessionLabel(), () -> "discontinuing NMASCrOperator watchdog timer, no active threads" );
+                    localTimer.shutdown();
+                    executorService = null;
                 }
             }
             else
             {
-                if ( timer == null )
+                if ( executorService == null )
                 {
-                    LOGGER.debug( () -> "starting NMASCrOperator watchdog timer, maxIdleThreadTime=" + maxThreadIdleTime.asCompactString() );
-                    timer = new Timer( PwmConstants.PWM_APP_NAME + "-NMASCrOperator watchdog timer", true );
+                    LOGGER.debug( pwmDomain.getSessionLabel(), () -> "starting NMASCrOperator watchdog timer, maxIdleThreadTime=" + maxThreadIdleTime.asCompactString() );
+                    executorService = PwmScheduler.makeBackgroundServiceExecutor(
+                            pwmDomain.getPwmApplication(),
+                            pwmDomain.getSessionLabel(),
+                            NMASCrOperator.class, "watchdog-timer" );
                     final long frequency = Long.parseLong( pwmDomain.getConfig().readAppProperty( AppProperty.NMAS_THREADS_WATCHDOG_FREQUENCY ) );
                     final boolean debugOutput = Boolean.parseBoolean( pwmDomain.getConfig().readAppProperty( AppProperty.NMAS_THREADS_WATCHDOG_DEBUG ) );
-                    timer.schedule( new ThreadWatchdogTask( debugOutput ), frequency, frequency );
+                    executorService.scheduleAtFixedRate( new ThreadWatchdogTask( debugOutput ), frequency, frequency, TimeUnit.MILLISECONDS );
                 }
             }
         }
@@ -285,7 +291,7 @@ public class NMASCrOperator implements CrOperator
                 return Optional.empty();
             }
 
-            final ResponseSet responseSet = new NMASCRResponseSet( pwmDomain, userIdentity );
+            final ResponseSet responseSet = new NMASCRResponseSet( pwmDomain, userIdentity, sessionLabel );
             if ( responseSet.getChallengeSet() == null )
             {
                 return Optional.empty();
@@ -441,17 +447,23 @@ public class NMASCrOperator implements CrOperator
     {
         private final PwmDomain pwmDomain;
         private final UserIdentity userIdentity;
+        private final SessionLabel sessionLabel;
 
         private final ChaiConfiguration chaiConfiguration;
         private ChallengeSet challengeSet;
         private transient NMASResponseSession ldapChallengeSession;
         boolean passed;
 
-        private NMASCRResponseSet( final PwmDomain pwmDomain, final UserIdentity userIdentity )
+        private NMASCRResponseSet(
+                final PwmDomain pwmDomain,
+                final UserIdentity userIdentity,
+                final SessionLabel sessionLabel
+        )
                 throws Exception
         {
             this.pwmDomain = pwmDomain;
             this.userIdentity = userIdentity;
+            this.sessionLabel = sessionLabel;
 
             final LdapProfile ldapProfile = pwmDomain.getConfig().getLdapProfiles().get( userIdentity.getLdapProfileID() );
 
@@ -477,7 +489,7 @@ public class NMASCrOperator implements CrOperator
                 ldapChallengeSession = null;
             }
             final LDAPConnection ldapConnection = makeLdapConnection();
-            ldapChallengeSession = new NMASResponseSession( userIdentity.getUserDN(), ldapConnection );
+            ldapChallengeSession = new NMASResponseSession( userIdentity.getUserDN(), ldapConnection, sessionLabel );
             final List<String> questions = ldapChallengeSession.getQuestions();
             challengeSet = questionsToChallengeSet( questions );
         }
@@ -491,7 +503,7 @@ public class NMASCrOperator implements CrOperator
             {
                 if ( theUser.isPasswordLocked() )
                 {
-                    LOGGER.trace( () -> "user " + theUser.getEntryDN() + " appears to be intruder locked, aborting nmas ResponseSet loading" );
+                    LOGGER.trace( sessionLabel, () -> "user " + theUser.getEntryDN() + " appears to be intruder locked, aborting nmas ResponseSet loading" );
                     throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INTRUDER_LDAP, "nmas account is intruder locked-out" ) );
                 }
                 else if ( !theUser.isAccountEnabled() )
@@ -527,7 +539,7 @@ public class NMASCrOperator implements CrOperator
         {
             if ( challengeSet.getRequiredChallenges().size() > this.getChallengeSet().getRequiredChallenges().size() )
             {
-                LOGGER.debug( () -> "failed meetsChallengeSetRequirements, not enough required challenge" );
+                LOGGER.debug( sessionLabel, () -> "failed meetsChallengeSetRequirements, not enough required challenge" );
                 return false;
             }
 
@@ -537,7 +549,7 @@ public class NMASCrOperator implements CrOperator
                 {
                     if ( !this.getChallengeSet().getChallengeTexts().contains( loopChallenge.getChallengeText() ) )
                     {
-                        LOGGER.debug( () -> "failed meetsChallengeSetRequirements, missing required challenge text: '" + loopChallenge.getChallengeText() + "'" );
+                        LOGGER.debug( sessionLabel, () -> "failed meetsChallengeSetRequirements, missing required challenge text: '" + loopChallenge.getChallengeText() + "'" );
                         return false;
                     }
                 }
@@ -548,7 +560,7 @@ public class NMASCrOperator implements CrOperator
                 if ( this.getChallengeSet().getChallenges().size() < challengeSet.getMinRandomRequired() )
                 {
                     final int challengesInSet = challengeSet.getChallenges().size();
-                    LOGGER.debug( () -> "failed meetsChallengeSetRequirements, not enough questions to meet minrandom; minRandomRequired="
+                    LOGGER.debug( sessionLabel, () -> "failed meetsChallengeSetRequirements, not enough questions to meet minrandom; minRandomRequired="
                             + challengeSet.getMinRandomRequired() + ", ChallengesInSet=" + challengesInSet );
                     return false;
                 }
@@ -589,7 +601,7 @@ public class NMASCrOperator implements CrOperator
             }
             catch ( final Exception e )
             {
-                LOGGER.error( () -> "error testing responses: " + e.getMessage() );
+                LOGGER.error( sessionLabel, () -> "error testing responses: " + e.getMessage() );
             }
             if ( !passed )
             {
@@ -606,7 +618,7 @@ public class NMASCrOperator implements CrOperator
                 catch ( final PwmException e )
                 {
                     final String errorMsg = "error reading next challenges after testing responses: " + e.getMessage();
-                    LOGGER.error( () -> "error reading next challenges after testing responses: " + e.getMessage() );
+                    LOGGER.error( sessionLabel, () -> "error reading next challenges after testing responses: " + e.getMessage() );
                     final ChaiUnavailableException chaiUnavailableException = new ChaiUnavailableException( errorMsg, ChaiError.UNKNOWN );
                     chaiUnavailableException.initCause( e );
                     throw chaiUnavailableException;
@@ -614,7 +626,7 @@ public class NMASCrOperator implements CrOperator
                 catch ( final Exception e )
                 {
                     final String errorMsg = "error reading next challenges after testing responses: " + e.getMessage();
-                    LOGGER.error( () -> "error reading next challenges after testing responses: " + e.getMessage() );
+                    LOGGER.error( sessionLabel, () -> "error reading next challenges after testing responses: " + e.getMessage() );
                     throw new ChaiUnavailableException( errorMsg, ChaiError.UNKNOWN );
                 }
             }
@@ -658,20 +670,28 @@ public class NMASCrOperator implements CrOperator
 
     private class NMASResponseSession
     {
+        private static final boolean COMPLETE_ON_UNSUPPORTED_FAILURE = false;
 
         private LDAPConnection ldapConnection;
         private final GenLcmUI lcmEnv;
-        private NMASSessionThread nmasSessionThread;
-        private boolean completeOnUnsupportedFailure = false;
+        private final NMASSessionThread nmasSessionThread;
+        private final SessionLabel sessionLabel;
 
-        NMASResponseSession( final String userDN, final LDAPConnection ldapConnection ) throws LCMRegistryException, PwmUnrecoverableException
+        NMASResponseSession(
+                final String userDN,
+                final LDAPConnection ldapConnection,
+                final SessionLabel sessionLabel
+        )
+                throws LCMRegistryException, PwmUnrecoverableException
         {
             this.ldapConnection = ldapConnection;
+            this.sessionLabel = sessionLabel;
+
             lcmEnv = new GenLcmUI();
             final GenLCMRegistry lcmRegistry = new GenLCMRegistry();
             lcmRegistry.registerLcm( "com.novell.security.nmas.lcm.chalresp.XmlChalRespLCM" );
 
-            nmasSessionThread = new NMASSessionThread( this );
+            nmasSessionThread = new NMASSessionThread( this, sessionLabel );
             final ChalRespCallbackHandler cbh = new ChalRespCallbackHandler( lcmEnv, lcmRegistry );
             nmasSessionThread.startLogin( userDN, ldapConnection, cbh );
         }
@@ -717,7 +737,7 @@ public class NMASCrOperator implements CrOperator
                 }
                 catch ( final LDAPException e )
                 {
-                    LOGGER.error( () -> "error closing ldap connection: " + e.getMessage(), e );
+                    LOGGER.error( sessionLabel, () -> "error closing ldap connection: " + e.getMessage(), e );
                 }
                 this.ldapConnection = null;
             }
@@ -745,36 +765,36 @@ public class NMASCrOperator implements CrOperator
                     // note in some cases instanceof check fails due to classloader issues, using getName string comparison instead
                     if ( NMASCompletionCallback.class.getName().equals( callbackClassname ) )
                     {
-                        LOGGER.trace( () -> "received NMASCompletionCallback, ignoring" );
+                        LOGGER.trace( sessionLabel, () -> "received NMASCompletionCallback, ignoring" );
                     }
                     else if ( NMASCallback.class.getName().equals( callbackClassname ) )
                     {
-                        LOGGER.trace( () -> "callback is instance of NMASCompletionCallback, calling handleNMASCallback()" );
+                        LOGGER.trace( sessionLabel, () -> "callback is instance of NMASCompletionCallback, calling handleNMASCallback()" );
                         try
                         {
                             handleNMASCallback( ( NMASCallback ) callback );
                         }
                         catch ( final com.novell.security.nmas.client.InvalidNMASCallbackException e )
                         {
-                            LOGGER.error( () -> "error processing NMASCallback: " + e.getMessage(), e );
+                            LOGGER.error( sessionLabel, () -> "error processing NMASCallback: " + e.getMessage(), e );
                         }
                     }
                     else if ( LCMUserPromptCallback.class.getName().equals( callbackClassname ) )
                     {
-                        LOGGER.trace( () -> "callback is instance of LCMUserPromptCallback, calling handleLCMUserPromptCallback()" );
+                        LOGGER.trace( sessionLabel, () -> "callback is instance of LCMUserPromptCallback, calling handleLCMUserPromptCallback()" );
                         try
                         {
                             handleLCMUserPromptCallback( ( LCMUserPromptCallback ) callback );
                         }
                         catch ( final LCMUserPromptException e )
                         {
-                            LOGGER.error( () -> "error processing LCMUserPromptCallback: " + e.getMessage(), e );
+                            LOGGER.error( sessionLabel, () -> "error processing LCMUserPromptCallback: " + e.getMessage(), e );
                         }
                     }
                     else
                     {
                         unsupportedCallbackHasOccurred = true;
-                        LOGGER.trace( () -> "throwing UnsupportedCallbackException for " + callback + ", class=" + callback.getClass().getName() );
+                        LOGGER.trace( sessionLabel, () -> "throwing UnsupportedCallbackException for " + callback + ", class=" + callback.getClass().getName() );
                         throw new UnsupportedCallbackException( callback );
                     }
                 }
@@ -787,9 +807,9 @@ public class NMASCrOperator implements CrOperator
                 Instant lastLogTime = Instant.now();
                 while ( !done && TimeDuration.fromCurrent( startTime ).isShorterThan( maxThreadIdleTime ) )
                 {
-                    LOGGER.trace( () -> "attempt to read return code, but isNmasDone=false, will await completion" );
+                    LOGGER.trace( sessionLabel, () -> "attempt to read return code, but isNmasDone=false, will await completion" );
                     TimeDuration.of( 10, TimeDuration.Unit.SECONDS ).pause();
-                    if ( completeOnUnsupportedFailure )
+                    if ( COMPLETE_ON_UNSUPPORTED_FAILURE )
                     {
                         done = unsupportedCallbackHasOccurred || this.isNmasDone();
                     }
@@ -799,12 +819,12 @@ public class NMASCrOperator implements CrOperator
                     }
                     if ( TimeDuration.SECOND.isLongerThan( TimeDuration.fromCurrent( lastLogTime ) ) )
                     {
-                        LOGGER.trace( () -> "waiting for return code: " + TimeDuration.fromCurrent( startTime ).asCompactString()
+                        LOGGER.trace( sessionLabel, () -> "waiting for return code: " + TimeDuration.fromCurrent( startTime ).asCompactString()
                                 + " unsupportedCallbackHasOccurred=" + unsupportedCallbackHasOccurred );
                         lastLogTime = Instant.now();
                     }
                 }
-                LOGGER.debug( () -> "read return code in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
+                LOGGER.debug( sessionLabel, () -> "read return code in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
                 return this.getNmasRetCode();
             }
         }
@@ -825,13 +845,20 @@ public class NMASCrOperator implements CrOperator
         private volatile NMASResponseSession.ChalRespCallbackHandler callbackHandler = null;
         private volatile LDAPConnection ldapConn = null;
         private volatile String loginDN = null;
+
         private final NMASResponseSession nmasResponseSession;
+        private final SessionLabel sessionLabel;
 
         private final int threadID;
 
-        NMASSessionThread( final NMASResponseSession nmasResponseSession )
+        NMASSessionThread(
+                final NMASResponseSession nmasResponseSession,
+                final SessionLabel sessionLabel
+                )
         {
             this.nmasResponseSession = nmasResponseSession;
+            this.sessionLabel = sessionLabel;
+
             this.threadID = threadCounter.next();
             setLoginState( NMASThreadState.NEW );
         }
@@ -905,7 +932,7 @@ public class NMASCrOperator implements CrOperator
         {
             try
             {
-                LOGGER.trace( () -> "starting NMASSessionThread, activeCount=" + sessionMonitorThreads.size() + ", " + this.toDebugString() );
+                LOGGER.trace( sessionLabel, () -> "starting NMASSessionThread, activeCount=" + sessionMonitorThreads.size() + ", " + this.toDebugString() );
                 sessionMonitorThreads.add( this );
                 controlWatchdogThread();
                 doLoginSequence();
@@ -914,7 +941,7 @@ public class NMASCrOperator implements CrOperator
             {
                 sessionMonitorThreads.remove( this );
                 controlWatchdogThread();
-                LOGGER.trace( () -> "exiting NMASSessionThread, activeCount=" + sessionMonitorThreads.size() + ", " + this.toDebugString() );
+                LOGGER.trace( sessionLabel, () -> "exiting NMASSessionThread, activeCount=" + sessionMonitorThreads.size() + ", " + this.toDebugString() );
             }
         }
 
@@ -953,7 +980,7 @@ public class NMASCrOperator implements CrOperator
                 }
                 catch ( final NullPointerException e )
                 {
-                    LOGGER.error( () -> "NullPointer error during CallBackHandler-NMASCR-bind; "
+                    LOGGER.error( sessionLabel, () -> "NullPointer error during CallBackHandler-NMASCR-bind; "
                             + "this is usually the result of an ldap disconnection, thread=" + this.toDebugString() );
                     this.setLoginState( NMASThreadState.ABORTED );
                     return;
@@ -979,11 +1006,11 @@ public class NMASCrOperator implements CrOperator
                 final String ldapErrorMessage = e.getLDAPErrorMessage();
                 if ( ldapErrorMessage != null )
                 {
-                    LOGGER.error( () -> "NMASLoginMonitor: LDAP error (" + ldapErrorMessage + ")" );
+                    LOGGER.error( sessionLabel, () -> "NMASLoginMonitor: LDAP error (" + ldapErrorMessage + ")" );
                 }
                 else
                 {
-                    LOGGER.error( () -> "NMASLoginMonitor: LDAPException " + e );
+                    LOGGER.error( sessionLabel, () -> "NMASLoginMonitor: LDAPException " + e );
                 }
                 setLoginState( NMASThreadState.COMPLETED );
                 final com.novell.security.nmas.client.NMASLoginResult localNMASLoginResult
@@ -1013,7 +1040,7 @@ public class NMASCrOperator implements CrOperator
             }
             catch ( final Exception e )
             {
-                LOGGER.trace( () -> "error during NMASResponseSession abort: " + e.getMessage() );
+                LOGGER.trace( sessionLabel, () -> "error during NMASResponseSession abort: " + e.getMessage() );
             }
         }
 
@@ -1030,7 +1057,7 @@ public class NMASCrOperator implements CrOperator
         }
     }
 
-    private class ThreadWatchdogTask extends TimerTask
+    private class ThreadWatchdogTask implements Runnable
     {
 
         private final boolean debugOutput;
@@ -1156,7 +1183,7 @@ public class NMASCrOperator implements CrOperator
         {
             final String className = "com.novell.sasl.client.ClientFactory";
             final ClassLoader threadLocalClassLoader = Thread.currentThread().getContextClassLoader();
-            final Class threadLocalClass = threadLocalClassLoader.loadClass( className );
+            final Class<?> threadLocalClass = threadLocalClassLoader.loadClass( className );
             return ( SaslClientFactory ) threadLocalClass.getDeclaredConstructor().newInstance();
         }
 

+ 1 - 1
server/src/main/java/password/pwm/svc/db/DatabaseUtil.java

@@ -145,7 +145,7 @@ class DatabaseUtil
                     + "  " + DatabaseService.VALUE_COLUMN + " " + dbConfiguration.getColumnTypeValue() + " " + "\n"
                     + ")" + "\n";
 
-            LOGGER.trace( () ->  "attempting to execute the following sql statement:\n " + sqlString );
+            LOGGER.trace( () -> "attempting to execute the following sql statement:\n " + sqlString );
 
             Statement statement = null;
             try

+ 17 - 9
server/src/main/java/password/pwm/svc/email/EmailConnectionPool.java

@@ -21,6 +21,7 @@
 package password.pwm.svc.email;
 
 import jakarta.mail.Transport;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
@@ -47,6 +48,7 @@ public class EmailConnectionPool
     private final Lock lock = new ReentrantLock();
 
     private final EmailServiceSettings settings;
+    private final SessionLabel sessionLabel;
     private final List<EmailServer> servers;
 
     private final AtomicInteger activeConnectionCounter = new AtomicInteger();
@@ -55,16 +57,19 @@ public class EmailConnectionPool
 
     public static EmailConnectionPool emptyConnectionPool()
     {
-        return new EmailConnectionPool( Collections.emptyList(), EmailServiceSettings.builder().build() );
+        return new EmailConnectionPool( Collections.emptyList(), EmailServiceSettings.builder().build(), null );
     }
 
     public EmailConnectionPool(
             final List<EmailServer> servers,
-            final EmailServiceSettings settings )
+            final EmailServiceSettings settings,
+            final SessionLabel sessionLabel
+    )
     {
         this.servers = List.copyOf( servers );
-        this.serverIncrementer = AtomicLoopIntIncrementer.builder().ceiling( servers.size() ).build();
         this.settings = settings;
+        this.sessionLabel = sessionLabel;
+        this.serverIncrementer = AtomicLoopIntIncrementer.builder().ceiling( servers.size() ).build();
     }
 
     public int idleConnectionCount()
@@ -106,7 +111,7 @@ public class EmailConnectionPool
             }
             final Instant startTime = Instant.now();
             final EmailConnection emailConnection = getSmtpTransport();
-            LOGGER.trace( () -> "created new email connection " + emailConnection.getId()
+            LOGGER.trace( sessionLabel, () -> "created new email connection " + emailConnection.getId()
                             + " to " + emailConnection.getEmailServer().getId(),
                     TimeDuration.fromCurrent( startTime ) );
             activeConnectionCounter.incrementAndGet();
@@ -130,7 +135,7 @@ public class EmailConnectionPool
             }
             else
             {
-                LOGGER.warn( () -> "connection " + emailConnection.getId() + "returned but was already in oool" );
+                LOGGER.warn( sessionLabel, () -> "connection " + emailConnection.getId() + "returned but was already in oool" );
             }
         }
         finally
@@ -143,20 +148,23 @@ public class EmailConnectionPool
     {
         if ( emailConnection.getSentItems() >= settings.getConnectionSendItemLimit() )
         {
-            LOGGER.trace( () -> "email connection " + emailConnection.getId() + " has sent " + emailConnection.getSentItems() + " and will be retired" );
+            LOGGER.trace( sessionLabel, () -> "email connection " + emailConnection.getId()
+                    + " has sent " + emailConnection.getSentItems() + " and will be retired" );
             return false;
         }
 
         final TimeDuration connectionAge = TimeDuration.fromCurrent( emailConnection.getStartTime() );
         if ( connectionAge.isLongerThan( settings.getConnectionSendItemDuration() ) )
         {
-            LOGGER.trace( () -> "email connection " + emailConnection.getId() + " has lived " + connectionAge.asCompactString() + " and will be retired" );
+            LOGGER.trace( sessionLabel, () -> "email connection " + emailConnection.getId()
+                    + " has lived " + connectionAge.asCompactString() + " and will be retired" );
             return false;
         }
 
         if ( !emailConnection.getTransport().isConnected() )
         {
-            LOGGER.trace( () -> "email connection " + emailConnection.getId() + " is no longer connected " + connectionAge.asCompactString() + " and will be retired" );
+            LOGGER.trace( sessionLabel, () -> "email connection " + emailConnection.getId()
+                    + " is no longer connected " + connectionAge.asCompactString() + " and will be retired" );
             return false;
 
         }
@@ -182,7 +190,7 @@ public class EmailConnectionPool
             final EmailServer server = servers.get( nextSlot );
             try
             {
-                final Transport transport = EmailServerUtil.makeSmtpTransport( server );
+                final Transport transport = EmailServerUtil.makeSmtpTransport( server, sessionLabel );
                 server.getConnectionStats().increment( EmailServer.ServerStat.newConnections );
                 return new EmailConnection( server, transport );
             }

+ 33 - 14
server/src/main/java/password/pwm/svc/email/EmailServerUtil.java

@@ -35,6 +35,7 @@ import password.pwm.AppProperty;
 import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
 import password.pwm.bean.EmailItemBean;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.option.SmtpServerType;
@@ -214,7 +215,10 @@ public class EmailServerUtil
         return properties;
     }
 
-    private static Optional<InternetAddress> makeInternetAddress( final String input )
+    private static Optional<InternetAddress> makeInternetAddress(
+            final String input,
+            final SessionLabel sessionLabel
+    )
             throws AddressException
     {
         if ( input == null )
@@ -239,7 +243,7 @@ public class EmailServerUtil
             }
             catch ( final UnsupportedEncodingException e )
             {
-                LOGGER.error( () -> "unsupported encoding error while parsing internet address '" + input + "', error: " + e.getMessage() );
+                LOGGER.error( sessionLabel, () -> "unsupported encoding error while parsing internet address '" + input + "', error: " + e.getMessage() );
             }
             return Optional.of( address );
         }
@@ -268,7 +272,11 @@ public class EmailServerUtil
         );
     }
 
-    static boolean examineSendFailure( final Exception e, final Set<Integer> retyableStatusCodes )
+    static boolean examineSendFailure(
+            final Exception e,
+            final Set<Integer> retyableStatusCodes,
+            final SessionLabel sessionLabel
+    )
     {
         if ( e != null )
         {
@@ -276,7 +284,7 @@ public class EmailServerUtil
                 final Optional<IOException> optionalIoException = JavaHelper.extractNestedExceptionType( e, IOException.class );
                 if ( optionalIoException.isPresent() )
                 {
-                    LOGGER.trace( () -> "message send failure cause is due to an I/O error: " + optionalIoException.get().getMessage() );
+                    LOGGER.trace( sessionLabel, () -> "message send failure cause is due to an I/O error: " + optionalIoException.get().getMessage() );
                     return true;
                 }
             }
@@ -287,7 +295,7 @@ public class EmailServerUtil
                 {
                     final SMTPSendFailedException smtpSendFailedException = optionalSmtpSendFailedException.get();
                     final int returnCode = smtpSendFailedException.getReturnCode();
-                    LOGGER.trace( () -> "message send failure cause is due to server response code: " + returnCode );
+                    LOGGER.trace( sessionLabel, () -> "message send failure cause is due to server response code: " + returnCode );
                     if ( retyableStatusCodes.contains( returnCode ) )
                     {
                         return true;
@@ -306,7 +314,8 @@ public class EmailServerUtil
     public static List<Message> convertEmailItemToMessages(
             final EmailItemBean emailItemBean,
             final AppConfig config,
-            final EmailServer emailServer
+            final EmailServer emailServer,
+            final SessionLabel sessionLabel
     )
             throws MessagingException
     {
@@ -324,7 +333,7 @@ public class EmailServerUtil
             {
                 final MimeMessage message = new MimeMessage( emailServer.getSession() );
 
-                final Optional<InternetAddress> fromAddress = makeInternetAddress( emailItemBean.getFrom() );
+                final Optional<InternetAddress> fromAddress = makeInternetAddress( emailItemBean.getFrom(), sessionLabel );
                 if ( fromAddress.isPresent() )
                 {
                     message.setFrom( fromAddress.get() );
@@ -370,7 +379,10 @@ public class EmailServerUtil
         return messages;
     }
 
-    static Transport makeSmtpTransport( final EmailServer server )
+    static Transport makeSmtpTransport(
+            final EmailServer server,
+            final SessionLabel sessionLabel
+    )
             throws MessagingException, PwmUnrecoverableException
     {
         final Instant startTime = Instant.now();
@@ -394,14 +406,18 @@ public class EmailServerUtil
             transport.connect();
         }
 
-        LOGGER.debug( () -> "connected to " + server.toDebugString() + " " + ( authenticated ? "(authenticated)" : "(unauthenticated)" ),
+        LOGGER.debug( sessionLabel, () -> "connected to " + server.toDebugString() + " " + ( authenticated ? "(authenticated)" : "(unauthenticated)" ),
                 TimeDuration.fromCurrent( startTime ) );
 
         return transport;
     }
 
 
-    public static List<X509Certificate> readCertificates( final AppConfig appConfig, final String profile )
+    public static List<X509Certificate> readCertificates(
+            final AppConfig appConfig,
+            final String profile,
+            final SessionLabel sessionLabel
+    )
             throws PwmUnrecoverableException
     {
         final EmailServerProfile emailServerProfile = appConfig.getEmailServerProfiles().get( profile );
@@ -415,7 +431,7 @@ public class EmailServerUtil
         final Optional<EmailServer> emailServer = makeEmailServer( appConfig, emailServerProfile, trustManagers );
         if ( emailServer.isPresent() )
         {
-            try ( Transport transport = makeSmtpTransport( emailServer.get() ) )
+            try ( Transport transport = makeSmtpTransport( emailServer.get(), sessionLabel ) )
             {
                 return certReaderTm.getCertificates();
             }
@@ -423,7 +439,7 @@ public class EmailServerUtil
             {
                 final String exceptionMessage = JavaHelper.readHostileExceptionMessage( e );
                 final String errorMsg = "error connecting to secure server while reading SMTP certificates: " + exceptionMessage;
-                LOGGER.debug( () -> errorMsg );
+                LOGGER.debug( sessionLabel, () -> errorMsg );
                 throw new PwmUnrecoverableException( PwmError.ERROR_SERVICE_UNREACHABLE, errorMsg );
             }
         }
@@ -431,14 +447,17 @@ public class EmailServerUtil
         return Collections.emptyList();
     }
 
-    static List<HealthRecord> checkAllConfiguredServers( final List<EmailServer> emailServers )
+    static List<HealthRecord> checkAllConfiguredServers(
+            final List<EmailServer> emailServers,
+            final SessionLabel sessionLabel
+    )
     {
         final List<HealthRecord> records = new ArrayList<>();
         for ( final EmailServer emailServer : emailServers )
         {
             try
             {
-                final Transport transport = EmailServerUtil.makeSmtpTransport( emailServer );
+                final Transport transport = EmailServerUtil.makeSmtpTransport( emailServer, sessionLabel );
                 if ( !transport.isConnected() )
                 {
                     records.add( HealthRecord.forMessage(

+ 34 - 29
server/src/main/java/password/pwm/svc/email/EmailService.java

@@ -27,6 +27,7 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.bean.DomainID;
 import password.pwm.bean.EmailItemBean;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.config.option.DataStorageMethod;
 import password.pwm.error.ErrorInformation;
@@ -92,7 +93,14 @@ public class EmailService extends AbstractPwmService implements PwmService
             throws PwmException
     {
         this.emailServiceSettings = EmailServiceSettings.fromConfiguration( this.getPwmApplication().getConfig() );
-        LOGGER.trace( () -> "initializing with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
+
+        if ( this.getPwmApplication().getLocalDB() == null || this.getPwmApplication().getLocalDB().status() != LocalDB.Status.OPEN )
+        {
+            LOGGER.debug( getSessionLabel(), () -> "localDB is not open, EmailService will remain closed" );
+            return STATUS.CLOSED;
+        }
+
+        LOGGER.trace( getSessionLabel(), () -> "initializing with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
 
         final List<EmailServer> servers;
         try
@@ -102,24 +110,17 @@ public class EmailService extends AbstractPwmService implements PwmService
         catch ( final PwmUnrecoverableException e )
         {
             setStartupError( e.getErrorInformation() );
-            LOGGER.error( () -> "unable to startup email service: " + e.getMessage() );
+            LOGGER.error( getSessionLabel(), () -> "unable to startup email service: " + e.getMessage() );
             return STATUS.CLOSED;
         }
 
         if ( servers.isEmpty() )
         {
-            LOGGER.debug( () -> "no email servers configured, will remain closed" );
+            LOGGER.debug( getSessionLabel(), () -> "no email servers configured, will remain closed" );
             return STATUS.CLOSED;
         }
 
-        if ( this.getPwmApplication().getLocalDB() == null || this.getPwmApplication().getLocalDB().status() != LocalDB.Status.OPEN )
-        {
-            LOGGER.debug( () -> "localDB is not open, EmailService will remain closed" );
-            return STATUS.CLOSED;
-
-        }
-
-        LOGGER.debug( () -> "starting with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
+        LOGGER.debug( getSessionLabel(), () -> "starting with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
                 .maxEvents( emailServiceSettings.getQueueMaxItems() )
@@ -132,7 +133,7 @@ public class EmailService extends AbstractPwmService implements PwmService
 
         workQueueProcessor = new WorkQueueProcessor<>( this.getPwmApplication(), this.getSessionLabel(), localDBStoredQueue, settings, new EmailItemProcessor(), this.getClass() );
 
-        connectionPool = new EmailConnectionPool( servers, emailServiceSettings );
+        connectionPool = new EmailConnectionPool( servers, emailServiceSettings, getSessionLabel() );
 
         statsLogger.conditionallyExecuteTask();
 
@@ -196,7 +197,7 @@ public class EmailService extends AbstractPwmService implements PwmService
             }
         }
 
-        records.addAll( EmailServerUtil.checkAllConfiguredServers( connectionPool.getServers() ) );
+        records.addAll( EmailServerUtil.checkAllConfiguredServers( connectionPool.getServers(), getSessionLabel() ) );
 
         return Collections.unmodifiableList( records );
     }
@@ -248,7 +249,7 @@ public class EmailService extends AbstractPwmService implements PwmService
 
     private void logStats()
     {
-        LOGGER.trace( () -> "stats: " + StringUtil.mapToString( stats() ) );
+        LOGGER.trace( getSessionLabel(), () -> "stats: " + StringUtil.mapToString( stats() ) );
     }
 
 
@@ -290,7 +291,7 @@ public class EmailService extends AbstractPwmService implements PwmService
     {
         if ( status() != STATUS.OPEN )
         {
-            LOGGER.debug( () -> "discarding email send event, no service is not running" );
+            LOGGER.debug( getSessionLabel(), () -> "discarding email send event, no service is not running" );
             return false;
         }
 
@@ -301,7 +302,7 @@ public class EmailService extends AbstractPwmService implements PwmService
         }
         catch ( final PwmOperationalException e )
         {
-            LOGGER.debug( () -> "discarding email send event: " + e.getMessage() );
+            LOGGER.debug( getSessionLabel(), () -> "discarding email send event: " + e.getMessage() );
         }
         return false;
     }
@@ -371,7 +372,7 @@ public class EmailService extends AbstractPwmService implements PwmService
 
         if ( status() != STATUS.OPEN )
         {
-            LOGGER.trace( () -> "email service is closed, discarding email job: " + emailItem.toDebugString() );
+            LOGGER.trace( getSessionLabel(), () -> "email service is closed, discarding email job: " + emailItem.toDebugString() );
             return;
         }
 
@@ -394,7 +395,7 @@ public class EmailService extends AbstractPwmService implements PwmService
 
                 if ( StringUtil.isEmpty( workingItemBean.getTo() ) )
                 {
-                    LOGGER.error( () -> "no destination address available for email, skipping; email: " + emailItem.toDebugString() );
+                    LOGGER.error( getSessionLabel(), () -> "no destination address available for email, skipping; email: " + emailItem.toDebugString() );
                 }
 
                 if ( !determineIfItemCanBeDelivered( emailItem ) )
@@ -417,7 +418,7 @@ public class EmailService extends AbstractPwmService implements PwmService
             }
             catch ( final PwmOperationalException e )
             {
-                LOGGER.warn( () -> "unable to add email to queue: " + e.getMessage() );
+                LOGGER.warn( getSessionLabel(), () -> "unable to add email to queue: " + e.getMessage() );
             }
         }
         finally
@@ -433,10 +434,10 @@ public class EmailService extends AbstractPwmService implements PwmService
             final EmailServer emailServer,
             final AppConfig domainConfig,
             final EmailItemBean emailItem,
-            final MacroRequest macroRequest
+            final MacroRequest macroRequest,
+            final SessionLabel sessionLabel
     )
             throws PwmOperationalException, PwmUnrecoverableException
-
     {
         try
         {
@@ -446,11 +447,12 @@ public class EmailService extends AbstractPwmService implements PwmService
             {
                 workingItemBean = EmailServerUtil.applyMacrosToEmail( workingItemBean, macroRequest );
             }
-            final Transport transport = EmailServerUtil.makeSmtpTransport( emailServer );
+            final Transport transport = EmailServerUtil.makeSmtpTransport( emailServer, sessionLabel );
             final List<Message> messages = EmailServerUtil.convertEmailItemToMessages(
                     workingItemBean,
                     domainConfig,
-                    emailServer
+                    emailServer,
+                    sessionLabel
             );
 
             for ( final Message message : messages )
@@ -477,15 +479,17 @@ public class EmailService extends AbstractPwmService implements PwmService
         }
         catch ( final MessagingException | PwmException e )
         {
-            if ( EmailServerUtil.examineSendFailure( e, emailServiceSettings.getRetryableStatusResponses() ) )
+            if ( EmailServerUtil.examineSendFailure( e, emailServiceSettings.getRetryableStatusResponses(), getSessionLabel() ) )
             {
-                LOGGER.error( () -> "error sending email (" + e.getMessage() + ") " + emailItemBean.toDebugString() + ", will retry" );
+                LOGGER.error( getSessionLabel(), () -> "error sending email (" + e.getMessage() + ") "
+                        + emailItemBean.toDebugString() + ", will retry" );
                 StatisticsClient.incrementStat( getPwmApplication(), Statistic.EMAIL_SEND_FAILURES );
                 return WorkQueueProcessor.ProcessResult.RETRY;
             }
             else
             {
-                LOGGER.error( () -> "error sending email (" + e.getMessage() + ") " + emailItemBean.toDebugString() + ", permanent failure, discarding message" );
+                LOGGER.error( getSessionLabel(), () -> "error sending email (" + e.getMessage() + ") "
+                        + emailItemBean.toDebugString() + ", permanent failure, discarding message" );
                 StatisticsClient.incrementStat( getPwmApplication(), Statistic.EMAIL_SEND_DISCARDS );
                 return WorkQueueProcessor.ProcessResult.FAILED;
             }
@@ -506,7 +510,8 @@ public class EmailService extends AbstractPwmService implements PwmService
             final List<Message> messages = EmailServerUtil.convertEmailItemToMessages(
                     emailItemBean,
                     this.getPwmApplication().getConfig(),
-                    emailConnection.getEmailServer()
+                    emailConnection.getEmailServer(),
+                    getSessionLabel()
             );
 
             for ( final Message message : messages )
@@ -521,7 +526,7 @@ public class EmailService extends AbstractPwmService implements PwmService
             emailConnection.getEmailServer().getAverageSendTime().update( sendTime.asMillis() );
             lastSendError.set( null );
 
-            LOGGER.debug( () -> "sent email: " + emailItemBean.toDebugString(), sendTime );
+            LOGGER.debug( getSessionLabel(), () -> "sent email: " + emailItemBean.toDebugString(), sendTime );
             StatisticsClient.incrementStat( getPwmApplication(), Statistic.EMAIL_SEND_SUCCESSES );
         }
         catch ( final MessagingException | PwmException e )
@@ -540,7 +545,7 @@ public class EmailService extends AbstractPwmService implements PwmService
                         new String[] {
                                 emailItemBean.toDebugString(),
                                 JavaHelper.readHostileExceptionMessage( e ),
-                                }
+                        }
                 );
             }
 

+ 1 - 1
server/src/main/java/password/pwm/svc/event/AuditRecordFactory.java

@@ -306,7 +306,7 @@ public class AuditRecordFactory
             }
             catch ( final Exception e )
             {
-                LOGGER.warn( () -> "unable to read userID for " + userIdentity + ", error: " + e.getMessage() );
+                LOGGER.warn( sessionLabel, () -> "unable to read userID for " + userIdentity + ", error: " + e.getMessage() );
             }
         }
 

+ 2 - 2
server/src/main/java/password/pwm/svc/event/AuditService.java

@@ -93,13 +93,13 @@ public class AuditService extends AbstractPwmService implements PwmService
 
         if ( pwmApplication.getApplicationMode() == null || pwmApplication.getApplicationMode() == PwmApplicationMode.READ_ONLY )
         {
-            LOGGER.warn( () -> "unable to start - Application is in read-only mode" );
+            LOGGER.warn( getSessionLabel(), () -> "unable to start - Application is in read-only mode" );
             return STATUS.CLOSED;
         }
 
         if ( pwmApplication.getLocalDB() == null || pwmApplication.getLocalDB().status() != LocalDB.Status.OPEN )
         {
-            LOGGER.warn( () -> "unable to start - LocalDB is not available" );
+            LOGGER.warn( getSessionLabel(), () -> "unable to start - LocalDB is not available" );
             return STATUS.CLOSED;
         }
 

+ 1 - 1
server/src/main/java/password/pwm/svc/event/SyslogAuditService.java

@@ -255,7 +255,7 @@ public class SyslogAuditService
         }
         catch ( final PwmOperationalException e )
         {
-            LOGGER.warn( () -> "unable to add syslog message to queue: " + e.getMessage() );
+            LOGGER.warn( sessionLabel, () -> "unable to add syslog message to queue: " + e.getMessage() );
         }
     }
 

+ 10 - 8
server/src/main/java/password/pwm/svc/httpclient/ApachePwmHttpClient.java

@@ -110,10 +110,12 @@ public class ApachePwmHttpClient implements AutoCloseable, PwmHttpClientProvider
     private PwmApplication pwmApplication;
     private PwmHttpClientConfiguration pwmHttpClientConfiguration;
     private HttpClientService httpClientService;
+    private SessionLabel sessionLabel;
 
     private TrustManager[] trustManagers;
     private CloseableHttpClient httpClient;
 
+
     private volatile boolean open = true;
 
     public ApachePwmHttpClient()
@@ -123,11 +125,13 @@ public class ApachePwmHttpClient implements AutoCloseable, PwmHttpClientProvider
     public void init(
             final PwmApplication pwmApplication,
             final HttpClientService httpClientService,
-            final PwmHttpClientConfiguration pwmHttpClientConfiguration
+            final PwmHttpClientConfiguration pwmHttpClientConfiguration,
+            final SessionLabel sessionLabel
     )
             throws PwmUnrecoverableException
     {
         this.pwmApplication = Objects.requireNonNull( pwmApplication );
+        this.sessionLabel = sessionLabel;
         this.httpClientService = Objects.requireNonNull( httpClientService );
         this.pwmHttpClientConfiguration = pwmHttpClientConfiguration;
 
@@ -145,14 +149,14 @@ public class ApachePwmHttpClient implements AutoCloseable, PwmHttpClientProvider
     @Override
     public void close()
     {
-        LOGGER.trace( () -> "closed client #" + clientID );
+        LOGGER.trace( sessionLabel, () -> "closed client #" + clientID );
         try
         {
             httpClient.close();
         }
         catch ( final IOException e )
         {
-            LOGGER.trace( () -> "error closing ApacheHttpClient: " + e.getMessage() );
+            LOGGER.trace( sessionLabel, () -> "error closing ApacheHttpClient: " + e.getMessage() );
         }
         open = false;
     }
@@ -245,14 +249,13 @@ public class ApachePwmHttpClient implements AutoCloseable, PwmHttpClientProvider
 
     @Override
     public PwmHttpClientResponse makeRequest(
-            final PwmHttpClientRequest clientRequest,
-            final SessionLabel sessionLabel
+            final PwmHttpClientRequest clientRequest
     )
             throws PwmUnrecoverableException
     {
         try
         {
-            return makeRequestImpl( clientRequest, sessionLabel );
+            return makeRequestImpl( clientRequest );
         }
         catch ( final IOException e )
         {
@@ -261,8 +264,7 @@ public class ApachePwmHttpClient implements AutoCloseable, PwmHttpClientProvider
     }
 
     private PwmHttpClientResponse makeRequestImpl(
-            final PwmHttpClientRequest clientRequest,
-            final SessionLabel sessionLabel
+            final PwmHttpClientRequest clientRequest
     )
             throws IOException, PwmUnrecoverableException
     {

+ 5 - 4
server/src/main/java/password/pwm/svc/httpclient/HttpClientService.java

@@ -23,6 +23,7 @@ package password.pwm.svc.httpclient;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.bean.DomainID;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
@@ -110,13 +111,13 @@ public class HttpClientService extends AbstractPwmService implements PwmService
         }
     }
 
-    public PwmHttpClient getPwmHttpClient()
+    public PwmHttpClient getPwmHttpClient( final SessionLabel sessionLabel )
             throws PwmUnrecoverableException
     {
-        return this.getPwmHttpClient( PwmHttpClientConfiguration.builder().build() );
+        return this.getPwmHttpClient( PwmHttpClientConfiguration.builder().build(), sessionLabel );
     }
 
-    public PwmHttpClient getPwmHttpClient( final PwmHttpClientConfiguration pwmHttpClientConfiguration )
+    public PwmHttpClient getPwmHttpClient( final PwmHttpClientConfiguration pwmHttpClientConfiguration, final SessionLabel sessionLabel )
             throws PwmUnrecoverableException
     {
         Objects.requireNonNull( pwmHttpClientConfiguration );
@@ -135,7 +136,7 @@ public class HttpClientService extends AbstractPwmService implements PwmService
         try
         {
             final PwmHttpClientProvider newClient = httpClientClass.getDeclaredConstructor().newInstance();
-            newClient.init( getPwmApplication(), this, pwmHttpClientConfiguration );
+            newClient.init( getPwmApplication(), this, pwmHttpClientConfiguration, sessionLabel );
             issuedClients.put( newClient, null );
             threadLocal.set( newClient );
             stats.increment( StatsKey.createdClients );

+ 7 - 5
server/src/main/java/password/pwm/svc/httpclient/JavaPwmHttpClient.java

@@ -79,6 +79,7 @@ public class JavaPwmHttpClient implements PwmHttpClientProvider
     private HttpClient httpClient;
     private TrustManager[] trustManagers;
     private PwmHttpClientConfiguration pwmHttpClientConfiguration;
+    private SessionLabel sessionLabel;
 
     private final int clientID = CLIENT_COUNTER.next();
 
@@ -89,12 +90,14 @@ public class JavaPwmHttpClient implements PwmHttpClientProvider
     public void init(
             final PwmApplication pwmApplication,
             final HttpClientService httpClientService,
-            final PwmHttpClientConfiguration pwmHttpClientConfiguration
+            final PwmHttpClientConfiguration pwmHttpClientConfiguration,
+            final SessionLabel sessionLabel
     )
             throws PwmUnrecoverableException
     {
         this.pwmApplication = Objects.requireNonNull( pwmApplication );
         this.pwmHttpClientConfiguration = pwmHttpClientConfiguration;
+        this.sessionLabel = sessionLabel;
         this.httpClientService = Objects.requireNonNull( httpClientService );
         final AppConfig appConfig = pwmApplication.getConfig();
         final HttpTrustManagerHelper trustManagerHelper = new HttpTrustManagerHelper( pwmApplication.getConfig(), pwmHttpClientConfiguration );
@@ -141,7 +144,7 @@ public class JavaPwmHttpClient implements PwmHttpClientProvider
     }
 
     @Override
-    public PwmHttpClientResponse makeRequest( final PwmHttpClientRequest clientRequest, final SessionLabel sessionLabel )
+    public PwmHttpClientResponse makeRequest( final PwmHttpClientRequest clientRequest )
             throws PwmUnrecoverableException
     {
         try
@@ -174,7 +177,7 @@ public class JavaPwmHttpClient implements PwmHttpClientProvider
 
             final PwmHttpClientResponse pwmHttpClientResponse = builder.build();
 
-            logResponse( clientRequest, pwmHttpClientResponse, startTime, sessionLabel );
+            logResponse( clientRequest, pwmHttpClientResponse, startTime );
 
             return pwmHttpClientResponse;
 
@@ -209,8 +212,7 @@ public class JavaPwmHttpClient implements PwmHttpClientProvider
     private void logResponse(
             final PwmHttpClientRequest pwmHttpClientRequest,
             final PwmHttpClientResponse pwmHttpClientResponse,
-            final Instant startTime,
-            final SessionLabel sessionLabel
+            final Instant startTime
     )
     {
         StatisticsClient.incrementStat( pwmApplication, Statistic.HTTP_CLIENT_REQUESTS );

+ 1 - 5
server/src/main/java/password/pwm/svc/httpclient/PwmHttpClient.java

@@ -20,7 +20,6 @@
 
 package password.pwm.svc.httpclient;
 
-import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.secure.CertificateReadingTrustManager;
 
@@ -36,10 +35,7 @@ public interface PwmHttpClient extends AutoCloseable
 {
     boolean isOpen();
 
-    PwmHttpClientResponse makeRequest(
-            PwmHttpClientRequest clientRequest,
-            SessionLabel sessionLabel
-    )
+    PwmHttpClientResponse makeRequest( PwmHttpClientRequest clientRequest )
             throws PwmUnrecoverableException;
 
     InputStream streamForUrl( String inputUrl )

+ 7 - 1
server/src/main/java/password/pwm/svc/httpclient/PwmHttpClientProvider.java

@@ -21,11 +21,17 @@
 package password.pwm.svc.httpclient;
 
 import password.pwm.PwmApplication;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 
 public interface PwmHttpClientProvider extends PwmHttpClient
 {
-    void init( PwmApplication pwmApplication, HttpClientService httpClientService, PwmHttpClientConfiguration pwmHttpClientConfiguration )
+    void init(
+            PwmApplication pwmApplication,
+            HttpClientService httpClientService,
+            PwmHttpClientConfiguration pwmHttpClientConfiguration,
+            SessionLabel sessionLabel
+    )
             throws PwmUnrecoverableException;
 
 }

+ 2 - 2
server/src/main/java/password/pwm/svc/intruder/IntruderDomainService.java

@@ -180,12 +180,12 @@ public class IntruderDomainService extends AbstractPwmService implements PwmServ
             final IntruderSettings.TypeSettings typeSettings = intruderSettings.getTargetSettings().get( type );
             if ( typeSettings.isConfigured() )
             {
-                LOGGER.debug( getSessionLabel(), () -> "starting record manager for type '" + type + "' with settings: " + typeSettings );
+                LOGGER.trace( getSessionLabel(), () -> "starting record manager for type '" + type + "' with settings: " + typeSettings );
                 recordManagers.put( type, new IntruderRecordManagerImpl( pwmDomain, type, recordStore, intruderSettings ) );
             }
             else
             {
-                LOGGER.debug( getSessionLabel(), () -> "skipping record manager for type '" + type + "' (not configured)" );
+                LOGGER.trace( getSessionLabel(), () -> "skipping record manager for type '" + type + "' (not configured)" );
                 recordManagers.put( type, new StubRecordManager() );
             }
         }

+ 1 - 1
server/src/main/java/password/pwm/svc/sessiontrack/SessionTrackService.java

@@ -273,7 +273,7 @@ public class SessionTrackService extends AbstractPwmService implements PwmServic
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.error( () -> "unexpected error reading username: " + e.getMessage(), e );
+                LOGGER.error( loopSession.getLabel(), () -> "unexpected error reading username: " + e.getMessage(), e );
             }
         }
 

+ 2 - 1
server/src/main/java/password/pwm/svc/shorturl/AbstractUrlShortener.java

@@ -21,6 +21,7 @@
 package password.pwm.svc.shorturl;
 
 import password.pwm.PwmApplication;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 
 public interface AbstractUrlShortener
@@ -36,6 +37,6 @@ public interface AbstractUrlShortener
      * @throws PwmUnrecoverableException if the operation fails
      */
 
-    String shorten( String input, PwmApplication pwmApplication )
+    String shorten( String input, PwmApplication pwmApplication, SessionLabel sessionLabel )
             throws PwmUnrecoverableException;
 }

+ 2 - 1
server/src/main/java/password/pwm/svc/shorturl/BasicUrlShortener.java

@@ -21,6 +21,7 @@
 package password.pwm.svc.shorturl;
 
 import password.pwm.PwmApplication;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 
 import java.util.Properties;
@@ -49,7 +50,7 @@ public class BasicUrlShortener implements AbstractUrlShortener
     }
 
     @Override
-    public String shorten( final String input, final PwmApplication pwmApplication ) throws PwmUnrecoverableException
+    public String shorten( final String input, final PwmApplication pwmApplication, final SessionLabel sessionLabel ) throws PwmUnrecoverableException
     {
         /*
          * This function does nothing.

+ 4 - 3
server/src/main/java/password/pwm/svc/shorturl/TinyUrlShortener.java

@@ -21,6 +21,7 @@
 package password.pwm.svc.shorturl;
 
 import password.pwm.PwmApplication;
+import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.HttpMethod;
 import password.pwm.svc.httpclient.PwmHttpClient;
@@ -49,19 +50,19 @@ public class TinyUrlShortener extends BasicUrlShortener
     }
 
     @Override
-    public String shorten( final String input, final PwmApplication pwmApplication )
+    public String shorten( final String input, final PwmApplication pwmApplication, final SessionLabel sessionLabel )
             throws PwmUnrecoverableException
     {
         LOGGER.debug( () -> "Trying to shorten url: " + input );
         final String encodedUrl = StringUtil.urlEncode( input );
         final String callUrl = apiUrl + encodedUrl;
-        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient(  );
+        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( sessionLabel );
 
         final PwmHttpClientRequest request = PwmHttpClientRequest.builder()
                 .method( HttpMethod.GET )
                 .url( callUrl )
                 .build();
-        final PwmHttpClientResponse httpResponse = pwmHttpClient.makeRequest( request, null );
+        final PwmHttpClientResponse httpResponse = pwmHttpClient.makeRequest( request );
         final int httpResponseCode = httpResponse.getStatusCode();
         if ( httpResponseCode == 200 )
         {

+ 6 - 4
server/src/main/java/password/pwm/svc/shorturl/UrlShortenerService.java

@@ -23,6 +23,7 @@ package password.pwm.svc.shorturl;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.bean.DomainID;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.error.PwmException;
@@ -102,16 +103,17 @@ public class UrlShortenerService extends AbstractPwmService implements PwmServic
         return Collections.emptyList();
     }
 
-    public String shortenUrl( final String text ) throws PwmUnrecoverableException
+    public String shortenUrl( final String text, final SessionLabel sessionLabel )
+            throws PwmUnrecoverableException
     {
         if ( theShortener != null )
         {
-            return theShortener.shorten( text, getPwmApplication() );
+            return theShortener.shorten( text, getPwmApplication(), sessionLabel );
         }
         return text;
     }
 
-    public String shortenUrlInText( final String text ) throws PwmUnrecoverableException
+    public String shortenUrlInText( final String text, final SessionLabel sessionLabel ) throws PwmUnrecoverableException
     {
         final String urlRegex = getPwmApplication().getConfig().readAppProperty( AppProperty.URL_SHORTNER_URL_REGEX );
         try
@@ -129,7 +131,7 @@ public class UrlShortenerService extends AbstractPwmService implements PwmServic
                 end = m.end();
                 while ( found )
                 {
-                    result.append( shortenUrl( text.substring( start, end ) ) );
+                    result.append( shortenUrl( text.substring( start, end ), sessionLabel ) );
                     start = end;
                     found = m.find();
                     if ( found )

+ 32 - 44
server/src/main/java/password/pwm/svc/sms/SmsQueueService.java

@@ -99,11 +99,11 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
 
         try
         {
-            smsQueue.addSmsToQueue( smsItemBean );
+            smsQueue.addSmsToQueue( smsItemBean, sessionLabel );
         }
         catch ( final PwmUnrecoverableException e )
         {
-            LOGGER.warn( () -> "unable to add sms to queue: " + e.getMessage() );
+            LOGGER.warn( sessionLabel, () -> "unable to add sms to queue: " + e.getMessage() );
         }
     }
 
@@ -149,7 +149,7 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
     {
         if ( pwmApplication.getLocalDB() == null || pwmApplication.getLocalDB().status() != LocalDB.Status.OPEN )
         {
-            LOGGER.warn( () -> "localdb is not open,  will remain closed" );
+            LOGGER.warn( getSessionLabel(), () -> "localdb is not open,  will remain closed" );
             return STATUS.CLOSED;
         }
 
@@ -214,10 +214,10 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
         }
     }
 
-    public void addSmsToQueue( final SmsItemBean smsItem )
+    public void addSmsToQueue( final SmsItemBean smsItem, final SessionLabel sessionLabel )
             throws PwmUnrecoverableException
     {
-        final SmsItemBean shortenedBean = shortenMessageIfNeeded( smsItem );
+        final SmsItemBean shortenedBean = shortenMessageIfNeeded( smsItem, sessionLabel );
         if ( !determineIfItemCanBeDelivered( shortenedBean ) )
         {
             return;
@@ -229,12 +229,13 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
         }
         catch ( final Exception e )
         {
-            LOGGER.error( () -> "error writing to LocalDB queue, discarding sms send request: " + e.getMessage() );
+            LOGGER.error( sessionLabel, () -> "error writing to LocalDB queue, discarding sms send request: " + e.getMessage() );
         }
     }
 
     SmsItemBean shortenMessageIfNeeded(
-            final SmsItemBean smsItem
+            final SmsItemBean smsItem,
+            final SessionLabel sessionLabel
     )
             throws PwmUnrecoverableException
     {
@@ -242,35 +243,15 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
         if ( shorten )
         {
             final String message = smsItem.getMessage();
-            final String shortenedMessage = getPwmApplication().getUrlShortener().shortenUrlInText( message );
+            final String shortenedMessage = getPwmApplication().getUrlShortener().shortenUrlInText( message, sessionLabel );
             return new SmsItemBean( smsItem.getTo(), shortenedMessage, smsItem.getSessionLabel() );
         }
         return smsItem;
     }
 
-    public static boolean smsIsConfigured( final AppConfig config )
-    {
-        final String gatewayUrl = config.readSettingAsString( PwmSetting.SMS_GATEWAY_URL );
-        final String gatewayUser = config.readSettingAsString( PwmSetting.SMS_GATEWAY_USER );
-        final PasswordData gatewayPass = config.readSettingAsPassword( PwmSetting.SMS_GATEWAY_PASSWORD );
-        if ( gatewayUrl == null || gatewayUrl.length() < 1 )
-        {
-            LOGGER.debug( () -> "SMS gateway url is not configured" );
-            return false;
-        }
-
-        if ( gatewayUser != null && gatewayUser.length() > 0 && ( gatewayPass == null ) )
-        {
-            LOGGER.debug( () -> "SMS gateway user configured, but no password provided" );
-            return false;
-        }
-
-        return true;
-    }
-
     boolean determineIfItemCanBeDelivered( final SmsItemBean smsItem )
     {
-        if ( !smsIsConfigured( getPwmApplication().getConfig() ) )
+        if ( !getPwmApplication().getConfig().isSmsConfigured() )
         {
             return false;
         }
@@ -502,11 +483,16 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
     private static class SmsSendEngine
     {
         private static final PwmLogger LOGGER = PwmLogger.forClass( SmsSendEngine.class );
+
         private final PwmApplication pwmApplication;
         private final AppConfig config;
+
         private String lastResponseBody;
 
-        private SmsSendEngine( final PwmApplication pwmApplication, final AppConfig domainConfig )
+        private SmsSendEngine(
+                final PwmApplication pwmApplication,
+                final AppConfig domainConfig
+        )
         {
             this.pwmApplication = pwmApplication;
             this.config = domainConfig;
@@ -517,17 +503,17 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
         {
             lastResponseBody = null;
 
-            final String requestData = makeRequestData( to, message );
+            final String requestData = makeRequestData( to, message, sessionLabel );
 
-            LOGGER.trace( () -> "preparing to send SMS data: " + requestData );
+            LOGGER.trace( sessionLabel, () -> "preparing to send SMS data: " + requestData );
 
-            final PwmHttpClientRequest pwmHttpClientRequest = makeRequest( requestData );
+            final PwmHttpClientRequest pwmHttpClientRequest = makeRequest( requestData, sessionLabel );
 
             final PwmHttpClient pwmHttpClient;
             {
                 if ( CollectionUtil.isEmpty( config.readSettingAsCertificate( PwmSetting.SMS_GATEWAY_CERTIFICATES ) ) )
                 {
-                    pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( );
+                    pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( sessionLabel );
                 }
                 else
                 {
@@ -536,20 +522,20 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
                             .certificates( config.readSettingAsCertificate( PwmSetting.SMS_GATEWAY_CERTIFICATES ) )
                             .build();
 
-                    pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( clientConfiguration );
+                    pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( clientConfiguration, sessionLabel );
                 }
             }
 
             try
             {
-                final PwmHttpClientResponse pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest, sessionLabel );
+                final PwmHttpClientResponse pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest );
                 final int resultCode = pwmHttpClientResponse.getStatusCode();
 
                 final String responseBody = pwmHttpClientResponse.getBody();
                 lastResponseBody = responseBody;
 
                 determineIfResultSuccessful( config, resultCode, responseBody );
-                LOGGER.debug( () -> "SMS send successful, HTTP status: " + resultCode );
+                LOGGER.debug( sessionLabel, () -> "SMS send successful, HTTP status: " + resultCode );
             }
             catch ( final PwmUnrecoverableException e )
             {
@@ -562,7 +548,8 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
 
         private String makeRequestData(
                 final String to,
-                final String message
+                final String message,
+                final SessionLabel sessionLabel
         )
         {
 
@@ -570,7 +557,7 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
 
             String requestData = config.readSettingAsString( PwmSetting.SMS_REQUEST_DATA );
 
-            requestData = applyUserPassTokens( requestData );
+            requestData = applyUserPassTokens( requestData, sessionLabel );
 
             // Replace strings in requestData
             {
@@ -592,7 +579,7 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
             return requestData;
         }
 
-        private String applyUserPassTokens( final String input )
+        private String applyUserPassTokens( final String input, final SessionLabel sessionLabel )
         {
             final SmsDataEncoding encoding = config.readSettingAsEnum( PwmSetting.SMS_REQUEST_CONTENT_ENCODING, SmsDataEncoding.class );
 
@@ -610,14 +597,15 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
             }
             catch ( final PwmUnrecoverableException e )
             {
-                LOGGER.error( () -> "unable to read sms password while reading configuration: " + e.getMessage() );
+                LOGGER.error( sessionLabel, () -> "unable to read sms password while reading configuration: " + e.getMessage() );
             }
 
             return modifiableText;
         }
 
         private PwmHttpClientRequest makeRequest(
-                final String requestData
+                final String requestData,
+                final SessionLabel sessionLabel
         )
                 throws PwmUnrecoverableException
         {
@@ -657,12 +645,12 @@ public class SmsQueueService extends AbstractPwmService implements PwmService
                         {
                             final String headerName = matcher.group( 1 );
                             final String headerValue = matcher.group( 2 );
-                            final String tokenizedValue = applyUserPassTokens( headerValue );
+                            final String tokenizedValue = applyUserPassTokens( headerValue, sessionLabel );
                             headers.put( headerName, tokenizedValue );
                         }
                         else
                         {
-                            LOGGER.warn( () -> "Cannot parse HTTP header: " + header );
+                            LOGGER.warn( sessionLabel, () -> "Cannot parse HTTP header: " + header );
                         }
                     }
                 }

+ 1 - 1
server/src/main/java/password/pwm/svc/stats/StatisticsService.java

@@ -239,7 +239,7 @@ public class StatisticsService extends AbstractPwmService implements PwmService
                 }
                 catch ( final Exception e )
                 {
-                    LOGGER.warn( () -> "error loading saved stored cumulative statistics: " + e.getMessage() );
+                    LOGGER.warn( getSessionLabel(), () -> "error loading saved stored cumulative statistics: " + e.getMessage() );
                 }
             }
         }

+ 2 - 2
server/src/main/java/password/pwm/svc/telemetry/HttpTelemetrySender.java

@@ -65,7 +65,7 @@ public class HttpTelemetrySender implements TelemetrySender
         final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
                 .trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous )
                 .build();
-        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration );
+        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration, sessionLabel );
         final String body = JsonFactory.get().serialize( statsPublishBean );
         final Map<String, String> headers = new HashMap<>();
         headers.put( HttpHeader.ContentType.getHttpName(), HttpContentType.json.getHeaderValueWithEncoding() );
@@ -78,7 +78,7 @@ public class HttpTelemetrySender implements TelemetrySender
                 .build();
 
         LOGGER.trace( sessionLabel, () -> "preparing to send telemetry data to '" + settings.getUrl() + ")" );
-        pwmHttpClient.makeRequest( pwmHttpClientRequest, sessionLabel );
+        pwmHttpClient.makeRequest( pwmHttpClientRequest );
         LOGGER.trace( sessionLabel, () -> "sent telemetry data to '" + settings.getUrl() + ")" );
     }
 

+ 1 - 1
server/src/main/java/password/pwm/svc/userhistory/LdapXmlUserHistory.java

@@ -139,7 +139,7 @@ public class LdapXmlUserHistory implements UserHistoryStore
         {
             final String errorMsg = "error reading LDAP user event history for user " + userIdentity.toDisplayString() + ", error: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, errorMsg );
-            LOGGER.error( errorInformation::toDebugStr, e );
+            LOGGER.error( sessionLabel, errorInformation::toDebugStr, e );
             throw new PwmUnrecoverableException( errorInformation, e );
         }
 

+ 2 - 2
server/src/main/java/password/pwm/svc/wordlist/SharedHistoryService.java

@@ -189,7 +189,7 @@ public class SharedHistoryService extends AbstractPwmService implements PwmServi
         }
         catch ( final Exception e )
         {
-            LOGGER.error( () -> "error checking db version", e );
+            LOGGER.error( getSessionLabel(), () -> "error checking db version", e );
             setStatus( STATUS.CLOSED );
             return;
         }
@@ -211,7 +211,7 @@ public class SharedHistoryService extends AbstractPwmService implements PwmServi
         }
         catch ( final LocalDBException e )
         {
-            LOGGER.error( () -> "unexpected error loading oldest-entry meta record, will remain closed: " + e.getMessage(), e );
+            LOGGER.error( getSessionLabel(), () -> "unexpected error loading oldest-entry meta record, will remain closed: " + e.getMessage(), e );
             setStatus( STATUS.CLOSED );
             return;
         }

+ 4 - 1
server/src/main/java/password/pwm/svc/wordlist/WordlistImporter.java

@@ -20,6 +20,7 @@
 
 package password.pwm.svc.wordlist;
 
+import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
@@ -28,6 +29,7 @@ import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.MiscUtil;
 import password.pwm.util.java.Percent;
+import password.pwm.util.java.PwmNumberFormat;
 import password.pwm.util.java.StatisticAverageBundle;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
@@ -366,7 +368,8 @@ class WordlistImporter implements Runnable
         getLogger().info( this::makeStatString );
         final long wordlistSize = wordlistBucket.size();
 
-        getLogger().info( rootWordlist.getSessionLabel(), () -> "population complete, added " + wordlistSize
+        getLogger().info( rootWordlist.getSessionLabel(), () -> "population complete, added "
+                + PwmNumberFormat.forLocale( PwmConstants.DEFAULT_LOCALE ).format( wordlistSize )
                 + " total words", this.getImportDuration() );
 
         completed = true;

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

@@ -101,7 +101,7 @@ class WordlistSource
                 final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
                         .trustManagerType( promiscuous ? PwmHttpClientConfiguration.TrustManagerType.promiscuous : PwmHttpClientConfiguration.TrustManagerType.defaultJava )
                         .build();
-                final PwmHttpClient client = pwmApplication.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration );
+                final PwmHttpClient client = pwmApplication.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration, pwmApplication.getSessionLabel() );
                 return client.streamForUrl( wordlistConfiguration.getAutoImportUrl() );
             }
 
@@ -162,12 +162,12 @@ class WordlistSource
     {
         final Instant startTime = Instant.now();
 
-        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient();
+        final PwmHttpClient pwmHttpClient = pwmApplication.getHttpClientService().getPwmHttpClient( pwmApplication.getSessionLabel() );
         final PwmHttpClientRequest request = PwmHttpClientRequest.builder()
                 .method( HttpMethod.HEAD )
                 .url( importUrl )
                 .build();
-        final PwmHttpClientResponse response = pwmHttpClient.makeRequest( request, null );
+        final PwmHttpClientResponse response = pwmHttpClient.makeRequest( request );
         final Map<HttpHeader, String> returnResponses = new EnumMap<>( HttpHeader.class );
         for ( final Map.Entry<String, String> entry : response.getHeaders().entrySet() )
         {

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

@@ -167,8 +167,8 @@ public class CaptchaUtility
                     .build();
 
             LOGGER.debug( pwmRequest, () -> "sending reCaptcha verification request" );
-            final PwmHttpClient client = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient();
-            final PwmHttpClientResponse clientResponse = client.makeRequest( clientRequest, pwmRequest.getLabel()  );
+            final PwmHttpClient client = pwmRequest.getPwmDomain().getHttpClientService().getPwmHttpClient( pwmRequest.getLabel() );
+            final PwmHttpClientResponse clientResponse = client.makeRequest( clientRequest );
 
             if ( clientResponse.getStatusCode() != HttpServletResponse.SC_OK )
             {
@@ -216,7 +216,7 @@ public class CaptchaUtility
         catch ( final Exception e )
         {
             final String errorMsg = "unexpected error during reCaptcha API execution: " + e.getMessage();
-            LOGGER.error( () -> errorMsg, e );
+            LOGGER.error( pwmRequest, () -> errorMsg, e );
             final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_CAPTCHA_API_ERROR, errorMsg );
             throw new PwmUnrecoverableException( errorInfo, e );
         }

+ 2 - 1
server/src/main/java/password/pwm/util/OnejarHelper.java

@@ -24,6 +24,7 @@ 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.AppConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.ConfigurationFileManager;
@@ -110,7 +111,7 @@ public class OnejarHelper
             throws Exception
     {
         final File configFile = new File( applicationPath + File.separator + PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
-        final ConfigurationFileManager configReader = new ConfigurationFileManager( configFile );
+        final ConfigurationFileManager configReader = new ConfigurationFileManager( configFile, SessionLabel.ONEJAR_LABEL );
         final AppConfig config = configReader.getConfiguration();
         final PwmEnvironment pwmEnvironment = PwmEnvironment.builder()
                 .config( config )

+ 3 - 2
server/src/main/java/password/pwm/util/cli/MainClass.java

@@ -29,6 +29,7 @@ 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.AppConfig;
 import password.pwm.config.stored.ConfigurationFileManager;
 import password.pwm.error.ErrorInformation;
@@ -365,7 +366,7 @@ public class MainClass
         {
             final String errorMsg = "unable to establish operating environment: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_ENVIRONMENT_ERROR, errorMsg );
-            LOGGER.error( errorInformation::toDebugStr, e );
+            LOGGER.error( SessionLabel.CLI_SESSION_LABEL, errorInformation::toDebugStr, e );
             out( "unable to establish operating environment: " + e.getMessage() );
             System.exit( -1 );
             return;
@@ -443,7 +444,7 @@ public class MainClass
 
     private static ConfigurationFileManager loadConfiguration( final File configurationFile ) throws Exception
     {
-        final ConfigurationFileManager reader = new ConfigurationFileManager( configurationFile );
+        final ConfigurationFileManager reader = new ConfigurationFileManager( configurationFile, SessionLabel.CLI_SESSION_LABEL );
 
         if ( reader.getConfigMode() == PwmApplicationMode.ERROR )
         {

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

@@ -20,7 +20,6 @@
 
 package password.pwm.util.cli.commands;
 
-import password.pwm.bean.SessionLabel;
 import password.pwm.config.stored.ConfigurationFileManager;
 import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.StoredConfiguration;
@@ -49,7 +48,7 @@ public class ConfigLockCommand extends AbstractCliCommand
 
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
         modifier.writeConfigProperty( ConfigurationProperty.CONFIG_IS_EDITABLE, Boolean.toString( false ) );
-        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication(), SessionLabel.CLI_SESSION_LABEL );
+        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication() );
         out( "success: configuration has been locked" );
     }
 

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

@@ -54,7 +54,7 @@ public class ConfigResetHttpsCommand
             return;
         }
 
-        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile() );
+        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile(), SessionLabel.CLI_SESSION_LABEL );
         final StoredConfiguration storedConfiguration = configurationFileManager.getStoredConfiguration();
 
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
@@ -63,7 +63,7 @@ public class ConfigResetHttpsCommand
             final StoredConfigKey key = StoredConfigKey.forSetting( setting, null, DomainID.systemId() );
             modifier.resetSetting( key, null );
         }
-        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication(), SessionLabel.CLI_SESSION_LABEL );
+        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication() );
         out( "success" );
     }
 

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

@@ -20,7 +20,6 @@
 
 package password.pwm.util.cli.commands;
 
-import password.pwm.bean.SessionLabel;
 import password.pwm.config.stored.ConfigurationFileManager;
 import password.pwm.config.stored.StoredConfiguration;
 import password.pwm.config.stored.StoredConfigurationModifier;
@@ -44,7 +43,7 @@ public class ConfigSetPasswordCommand extends AbstractCliCommand
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
         final String password = getOptionalPassword();
         StoredConfigurationUtil.setPassword( modifier, password );
-        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication(), SessionLabel.CLI_SESSION_LABEL );
+        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication() );
         out( "success: new password has been set" );
     }
 

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

@@ -20,7 +20,6 @@
 
 package password.pwm.util.cli.commands;
 
-import password.pwm.bean.SessionLabel;
 import password.pwm.config.stored.ConfigurationFileManager;
 import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.StoredConfiguration;
@@ -50,7 +49,7 @@ public class ConfigUnlockCommand extends AbstractCliCommand
 
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
         modifier.writeConfigProperty( ConfigurationProperty.CONFIG_IS_EDITABLE, Boolean.toString( true ) );
-        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication(), SessionLabel.CLI_SESSION_LABEL );
+        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication() );
         out( "success: configuration has been unlocked" );
     }
 

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

@@ -66,7 +66,7 @@ public class ImportHttpsKeyStoreCommand extends AbstractCliCommand
         final String keyStorePassword = getOptionalPassword();
         final String inputAliasName = ( String ) cliEnvironment.getOptions().get( ALIAS_OPTIONNAME );
 
-        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile() );
+        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile(), SessionLabel.CLI_SESSION_LABEL );
         final StoredConfiguration storedConfiguration = configurationFileManager.getStoredConfiguration();
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
 
@@ -86,7 +86,7 @@ public class ImportHttpsKeyStoreCommand extends AbstractCliCommand
             return;
         }
 
-        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication(), SessionLabel.CLI_SESSION_LABEL );
+        configurationFileManager.saveConfiguration( modifier.newStoredConfiguration(), cliEnvironment.getPwmApplication() );
         out( "success: keystore has been imported" );
     }
 

+ 2 - 2
server/src/main/java/password/pwm/util/debug/LdapConnectionsDebugItemGenerator.java

@@ -22,7 +22,7 @@ package password.pwm.util.debug;
 
 import password.pwm.PwmConstants;
 import password.pwm.PwmDomain;
-import password.pwm.ldap.LdapConnectionService;
+import password.pwm.ldap.LdapDomainService;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.json.JsonProvider;
 
@@ -43,7 +43,7 @@ class LdapConnectionsDebugItemGenerator implements DomainItemGenerator
             throws IOException
     {
         final PwmDomain pwmDomain = debugItemInput.getPwmDomain();
-        final List<LdapConnectionService.ConnectionInfo> connectionInfos = pwmDomain.getLdapConnectionService().getConnectionInfos();
+        final List<LdapDomainService.ConnectionInfo> connectionInfos = pwmDomain.getLdapConnectionService().getConnectionInfos();
         final String jsonString = JsonFactory.get().serializeCollection( connectionInfos, JsonProvider.Flag.PrettyPrint );
         outputStream.write( jsonString.getBytes( PwmConstants.DEFAULT_CHARSET ) );
     }

+ 1 - 1
server/src/main/java/password/pwm/util/form/FormUtility.java

@@ -379,7 +379,7 @@ public class FormUtility
                     if ( compareResult )
                     {
                         final String label = labelMap.get( name );
-                        LOGGER.trace( sessionLabel, () ->  "found duplicate value for attribute '" + label + "' on entry " + userIdentity );
+                        LOGGER.trace( sessionLabel, () -> "found duplicate value for attribute '" + label + "' on entry " + userIdentity );
                         final ErrorInformation error = new ErrorInformation( PwmError.ERROR_FIELD_DUPLICATE, null, new String[]
                                 {
                                         label,

+ 23 - 25
server/src/main/java/password/pwm/util/localdb/WorkQueueProcessor.java

@@ -53,9 +53,7 @@ import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.LockSupport;
-import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * A work item queue manager.   Items submitted to the queue will eventually be worked on by the client side @code {@link ItemProcessor}.
@@ -68,13 +66,13 @@ public final class WorkQueueProcessor<W extends Serializable>
     private final Deque<String> queue;
     private final Settings settings;
     private final ItemProcessor<W> itemProcessor;
+    private final SessionLabel sessionLabel;
 
     private final PwmLogger logger;
 
     private volatile WorkerThread workerThread;
 
     private final AtomicLoopIntIncrementer idGenerator = new AtomicLoopIntIncrementer();
-    private final Lock submitLock = new ReentrantLock();
     private Instant eldestItem = null;
 
     private ThreadPoolExecutor executorService;
@@ -109,6 +107,7 @@ public final class WorkQueueProcessor<W extends Serializable>
             final Class<?> sourceClass
     )
     {
+        this.sessionLabel = sessionLabel;
         this.settings = settings;
         this.queue = queue;
         this.itemProcessor = itemProcessor;
@@ -157,7 +156,7 @@ public final class WorkQueueProcessor<W extends Serializable>
         workerThread = null;
 
         final Instant startTime = Instant.now();
-        logger.debug( () -> "attempting to flush queue prior to shutdown, items in queue=" + queueSize() );
+        logger.debug( sessionLabel, () -> "attempting to flush queue prior to shutdown, items in queue=" + queueSize() );
 
         localWorkerThread.flushQueueAndClose();
 
@@ -170,11 +169,11 @@ public final class WorkQueueProcessor<W extends Serializable>
         final String msg = "shutting down with " + queue.size() + " items remaining in work queue (" + timeDuration.asCompactString() + ")";
         if ( !queue.isEmpty() )
         {
-            logger.warn( () -> msg );
+            logger.warn( sessionLabel,  () -> msg );
         }
         else
         {
-            logger.debug( () -> msg );
+            logger.debug( sessionLabel, () -> msg );
         }
     }
 
@@ -233,13 +232,13 @@ public final class WorkQueueProcessor<W extends Serializable>
                 }
                 catch ( final Exception e )
                 {
-                    logger.error( () -> "error submitting to work queue after executor returned retry status: " + e.getMessage() );
+                    logger.error( sessionLabel, () -> "error submitting to work queue after executor returned retry status: " + e.getMessage() );
                 }
             }
         }
         catch ( final PwmOperationalException e )
         {
-            logger.error( () -> "unexpected error while processing itemWrapper: " + e.getMessage(), e );
+            logger.error( sessionLabel, () -> "unexpected error while processing itemWrapper: " + e.getMessage(), e );
         }
     }
 
@@ -279,13 +278,13 @@ public final class WorkQueueProcessor<W extends Serializable>
 
         if ( attempts > 1 )
         {
-            logger.trace( () -> "item submitted directly to queue: " + makeDebugText( itemWrapper ),
+            logger.trace( sessionLabel, () -> "item submitted directly to queue: " + makeDebugText( itemWrapper ),
                     TimeDuration.fromCurrent( startTime ) );
         }
         else
         {
             final int finalAttempts = attempts;
-            logger.debug( () -> "item submitted to queue after " + finalAttempts + " attempts: "
+            logger.debug( sessionLabel, () -> "item submitted to queue after " + finalAttempts + " attempts: "
                     + makeDebugText( itemWrapper ), TimeDuration.fromCurrent( startTime ) );
         }
     }
@@ -345,14 +344,14 @@ public final class WorkQueueProcessor<W extends Serializable>
             }
             catch ( final Throwable t )
             {
-                logger.error( () -> "unexpected error processing work item queue: " + JavaHelper.readHostileExceptionMessage( t ), t );
+                logger.error( sessionLabel, () -> "unexpected error processing work item queue: " + JavaHelper.readHostileExceptionMessage( t ), t );
             }
 
-            logger.trace( () -> "worker thread beginning shutdown..." );
+            logger.trace( sessionLabel, () -> "worker thread beginning shutdown..." );
 
             if ( !queue.isEmpty() )
             {
-                logger.trace( () -> "processing remaining " + queue.size() + " items" );
+                logger.trace( sessionLabel, () -> "processing remaining " + queue.size() + " items" );
 
                 try
                 {
@@ -364,29 +363,28 @@ public final class WorkQueueProcessor<W extends Serializable>
                 }
                 catch ( final Throwable t )
                 {
-                    logger.error( () -> "unexpected error processing work item queue: " + JavaHelper.readHostileExceptionMessage( t ), t );
+                    logger.error( sessionLabel, () -> "unexpected error processing work item queue: " + JavaHelper.readHostileExceptionMessage( t ), t );
                 }
             }
 
-            logger.trace( () -> "thread exiting..." );
+            logger.trace( sessionLabel, () -> "thread exiting..." );
             running.set( false );
         }
 
         void flushQueueAndClose( )
         {
             shutdownFlag.set( true );
-            logger.trace( () -> "shutdown flag set" );
+            logger.trace( sessionLabel, () -> "shutdown flag set" );
             notifyWorkPending();
 
             // rest until not running for up to 10 seconds....
             if ( running.get() )
             {
-                logger.trace( () -> "running = " + running.get() );
-                final TimeDuration maxWaitTime = TimeDuration.of( 10, TimeDuration.Unit.SECONDS );
+                logger.trace( sessionLabel, () -> "running = " + running.get() );
                 final Instant startTime = Instant.now();
-                maxWaitTime.of( 10, TimeDuration.Unit.SECONDS ).pause( CLOSE_RETRY_CYCLE_INTERVAL, () -> !running.get() );
+                TimeDuration.of( 10, TimeDuration.Unit.SECONDS ).pause( CLOSE_RETRY_CYCLE_INTERVAL, () -> !running.get() );
                 final TimeDuration waitTime = TimeDuration.fromCurrent( startTime );
-                logger.trace( () -> "waited " + waitTime.asCompactString() + " workQueueSize=" + queue.size() + " running=" + running.get() );
+                logger.trace( sessionLabel, () -> "waited " + waitTime.asCompactString() + " workQueueSize=" + queue.size() + " running=" + running.get() );
             }
         }
 
@@ -461,7 +459,7 @@ public final class WorkQueueProcessor<W extends Serializable>
                 if ( processResult == null )
                 {
                     removeQueueTop();
-                    logger.warn( () -> "itemProcessor.process() returned null, removing; item=" + makeDebugText( itemWrapper ) );
+                    logger.warn( sessionLabel, () -> "itemProcessor.process() returned null, removing; item=" + makeDebugText( itemWrapper ) );
                 }
                 else
                 {
@@ -470,14 +468,14 @@ public final class WorkQueueProcessor<W extends Serializable>
                         case FAILED:
                         {
                             removeQueueTop();
-                            logger.error( () -> "discarding item after process failure, item=" + makeDebugText( itemWrapper ) );
+                            logger.error( sessionLabel, () -> "discarding item after process failure, item=" + makeDebugText( itemWrapper ) );
                         }
                         break;
 
                         case RETRY:
                         {
                             retryWakeupTime = Instant.ofEpochMilli( System.currentTimeMillis() + settings.getRetryInterval().asMillis() );
-                            logger.debug( () -> "will retry item after failure, item=" + makeDebugText( itemWrapper ) );
+                            logger.debug( sessionLabel, () -> "will retry item after failure, item=" + makeDebugText( itemWrapper ) );
                         }
                         break;
 
@@ -502,7 +500,7 @@ public final class WorkQueueProcessor<W extends Serializable>
                 if ( !shutdownFlag.get() )
                 {
                     removeQueueTop();
-                    logger.error( () -> "unexpected error while processing work queue: " + e.getMessage() );
+                    logger.error( sessionLabel, () -> "unexpected error while processing work queue: " + e.getMessage() );
                 }
             }
 
@@ -610,7 +608,7 @@ public final class WorkQueueProcessor<W extends Serializable>
         final TimeDuration lagTime = TimeDuration.fromCurrent( itemWrapper.getDate() );
         avgLagTime.update( lagTime.asMillis() );
         sendRate.markEvents( 1 );
-        logger.trace( () -> "successfully processed item=" + makeDebugText( itemWrapper ) + "; lagTime=" + lagTime.asCompactString()
+        logger.trace( sessionLabel, () -> "processed item=" + makeDebugText( itemWrapper ) + "; lagTime=" + lagTime.asCompactString()
                 + "; " + StringUtil.mapToString( debugInfo() ), processDuration );
     }
 

+ 29 - 7
server/src/main/java/password/pwm/util/logging/LocalDBLogger.java

@@ -57,6 +57,7 @@ import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
@@ -81,7 +82,11 @@ public class LocalDBLogger extends AbstractPwmService implements PwmService
     private final StatisticCounterBundle<CounterStat> stats = new StatisticCounterBundle<>( CounterStat.class );
     private final StatisticAverageBundle<AverageStat> averages = new StatisticAverageBundle<>( AverageStat.class );
 
-    private final ConditionalTaskExecutor debugOutputter = ConditionalTaskExecutor.forPeriodicTask( this::periodicDebugOutput, TimeDuration.MINUTE.asDuration() );
+    private final ConditionalTaskExecutor debugOutputter = ConditionalTaskExecutor.forPeriodicTask(
+            this::periodicDebugOutput, TimeDuration.MINUTE.asDuration() );
+
+    private static final int LOG_OUTPUT_INCREMENTS = 10_000;
+    private final AtomicLong lastLogOutput = new AtomicLong( LOG_OUTPUT_INCREMENTS );
 
     enum CounterStat
     {
@@ -215,10 +220,11 @@ public class LocalDBLogger extends AbstractPwmService implements PwmService
             debugData.put( "EventsTailAge", tailAge == null ? "n/a" : TimeDuration.fromCurrent( tailAge ).asCompactString() );
         }
 
+        final TimeDuration latency = TimeDuration.of( (long) averages.getAverage( AverageStat.avgFlushLatency ), TimeDuration.Unit.MILLISECONDS );
         debugData.put( "EventsStored", String.valueOf( localDBListQueue.size() ) );
         debugData.put( "ConfiguredMaxEvents", MiscUtil.forDefaultLocale().format( settings.getMaxEvents() ) );
         debugData.put( "ConfiguredMaxAge", settings.getMaxAge().asCompactString() );
-        debugData.put( "BufferAverageLatency", averages.getFormattedAverage( AverageStat.avgFlushLatency ) );
+        debugData.put( "BufferAverageLatency", latency.asCompactString() );
         debugData.put( "BufferAverageSize", averages.getFormattedAverage( AverageStat.avgFlushCount ) );
         debugData.put( "BufferItemCount", String.valueOf( tempMemoryEventQueue.size() ) );
 
@@ -229,18 +235,23 @@ public class LocalDBLogger extends AbstractPwmService implements PwmService
 
     private void periodicDebugOutput()
     {
-        LOGGER.trace( () -> "periodic debug output: " + StringUtil.mapToString( debugStats() ) );
+        if ( lastLogOutput.get() + stats.get( CounterStat.EventsWritten ) > LOG_OUTPUT_INCREMENTS )
+        {
+            LOGGER.trace( () -> "periodic debug output: " + StringUtil.mapToString( debugStats() ) );
+            lastLogOutput.set( stats.get( CounterStat.EventsWritten ) );
+        }
     }
 
     @Override
     public void shutdownImpl( )
     {
         final Instant startTime = Instant.now();
-        int flushedEvents = 0;
+
+        final int flushedEvents;
         if ( status() != STATUS.CLOSED )
         {
             LOGGER.trace( () -> "LocalDBLogger closing" );
-            flushedEvents += tempMemoryEventQueue.size();
+            flushedEvents = tempMemoryEventQueue.size();
             if ( cleanerService != null )
             {
                 cleanerService.shutdown();
@@ -248,10 +259,21 @@ public class LocalDBLogger extends AbstractPwmService implements PwmService
             writerService.execute( new FlushTask() );
             JavaHelper.closeAndWaitExecutor( writerService, TimeDuration.SECONDS_10 );
         }
+        else
+        {
+            flushedEvents = 0;
+        }
+
         setStatus( STATUS.CLOSED );
 
-        final int finalFlushedEvents = flushedEvents;
-        LOGGER.trace( () -> "LocalDBLogger close completed (flushed during close: " + finalFlushedEvents + ")", TimeDuration.fromCurrent( startTime ) );
+        if ( flushedEvents > 0 )
+        {
+            LOGGER.trace( () -> "LocalDBLogger close completed (flushed during close: " + flushedEvents + ")", TimeDuration.fromCurrent( startTime ) );
+        }
+        else
+        {
+            LOGGER.trace( () -> "LocalDBLogger close completed", TimeDuration.fromCurrent( startTime ) );
+        }
     }
 
     public int getStoredEventCount( )

+ 9 - 9
server/src/main/java/password/pwm/util/logging/PwmLogger.java

@@ -333,14 +333,14 @@ public class PwmLogger
         doLogEvent( PwmLogLevel.DEBUG, null, message, null );
     }
 
-    public void debug( final Supplier<CharSequence> message, final TimeDuration timeDuration )
+    public void debug( final PwmRequest pwmRequest, final Supplier<CharSequence> message )
     {
-        doLogEvent( PwmLogLevel.DEBUG, null, message, null, timeDuration );
+        doPwmRequestLogEvent( PwmLogLevel.DEBUG, pwmRequest, message, null, null );
     }
 
-    public void debug( final PwmRequest pwmRequest, final Supplier<CharSequence> message )
+    public void debug( final PwmRequest pwmRequest, final Supplier<CharSequence> message, final Throwable exception )
     {
-        doPwmRequestLogEvent( PwmLogLevel.DEBUG, pwmRequest, message, null, null );
+        doPwmRequestLogEvent( PwmLogLevel.DEBUG, pwmRequest, message, exception, null );
     }
 
     public void debug( final PwmRequest pwmRequest, final ErrorInformation errorInformation )
@@ -363,11 +363,6 @@ public class PwmLogger
         doLogEvent( PwmLogLevel.DEBUG, sessionLabel, convertErrorInformation( errorInformation ), null );
     }
 
-    public void debug( final Supplier<CharSequence> message, final Throwable exception )
-    {
-        doPwmRequestLogEvent( PwmLogLevel.DEBUG, null, message, exception, null );
-    }
-
     public void info( final Supplier<CharSequence> message )
     {
         doLogEvent( PwmLogLevel.INFO, null, message, null );
@@ -468,6 +463,11 @@ public class PwmLogger
         doPwmRequestLogEvent( PwmLogLevel.WARN, pwmRequest, message, null, null );
     }
 
+    public void warn( final SessionLabel sessionLabel, final Supplier<CharSequence> message, final Throwable exception )
+    {
+        doLogEvent( PwmLogLevel.WARN, sessionLabel, message, exception );
+    }
+
     public void warn( final PwmRequest pwmRequest, final Supplier<CharSequence> message, final Throwable exception )
     {
         doPwmRequestLogEvent( PwmLogLevel.WARN, pwmRequest, message, exception, null );

+ 4 - 1
server/src/main/java/password/pwm/util/macro/ExternalRestMacro.java

@@ -92,8 +92,11 @@ class ExternalRestMacro extends AbstractMacro
 
             final String requestBody = JsonFactory.get().serializeMap( sendData );
             final String responseBody = RestClientHelper.makeOutboundRestWSCall( pwmDomain,
-                    PwmConstants.DEFAULT_LOCALE, url,
+                    macroRequestInfo.getSessionLabel(),
+                    PwmConstants.DEFAULT_LOCALE,
+                    url,
                     requestBody );
+
             final Map<String, Object> responseMap = JsonFactory.get().deserializeMap( responseBody, String.class, Object.class );
             if ( responseMap.containsKey( "output" ) )
             {

+ 3 - 3
server/src/main/java/password/pwm/util/operations/ActionExecutor.java

@@ -216,14 +216,14 @@ public class ActionExecutor
                             .certificates( webAction.getCertificates() )
                             .build();
 
-                    client = pwmDomain.getHttpClientService().getPwmHttpClient( clientConfiguration );
+                    client = pwmDomain.getHttpClientService().getPwmHttpClient( clientConfiguration, sessionLabel );
                 }
                 else
                 {
-                    client = pwmDomain.getHttpClientService().getPwmHttpClient( );
+                    client = pwmDomain.getHttpClientService().getPwmHttpClient( sessionLabel );
                 }
             }
-            final PwmHttpClientResponse clientResponse = client.makeRequest( clientRequest, sessionLabel );
+            final PwmHttpClientResponse clientResponse = client.makeRequest( clientRequest );
 
             final List<Integer> successStatus = webAction.getSuccessStatus() == null
                     ? Collections.emptyList()

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

@@ -287,7 +287,7 @@ public class PasswordUtility
         try
         {
             final PwmPasswordRuleValidator pwmPasswordRuleValidator = PwmPasswordRuleValidator.create( pwmRequest.getLabel(), pwmDomain, userInfo.getPasswordPolicy() );
-            pwmPasswordRuleValidator.testPassword( newPassword, null, userInfo, pwmSession.getSessionManager().getActor( ) );
+            pwmPasswordRuleValidator.testPassword( pwmSession.getLabel(), newPassword, null, userInfo, pwmSession.getSessionManager().getActor( ) );
         }
         catch ( final PwmDataValidationException e )
         {
@@ -415,7 +415,7 @@ public class PasswordUtility
                     PwmPasswordRuleValidator.Flag.BypassLdapRuleCheck
             );
 
-            pwmPasswordRuleValidator.testPassword( newPassword, null, userInfo, theUser );
+            pwmPasswordRuleValidator.testPassword( sessionLabel, newPassword, null, userInfo, theUser );
         }
         catch ( final ChaiUnavailableException e )
         {
@@ -1114,7 +1114,7 @@ public class PasswordUtility
                 {
                     final PwmPasswordRuleValidator pwmPasswordRuleValidator = PwmPasswordRuleValidator.create( sessionLabel, pwmDomain, userInfo.getPasswordPolicy(), locale );
                     final PasswordData oldPassword = loginInfoBean == null ? null : loginInfoBean.getUserCurrentPassword();
-                    pwmPasswordRuleValidator.testPassword( password, oldPassword, userInfo, user );
+                    pwmPasswordRuleValidator.testPassword( pwmRequestContext.getSessionLabel(), password, oldPassword, userInfo, user );
                     pass = true;
                     if ( cacheService != null && cacheKey != null )
                     {

+ 6 - 6
server/src/main/java/password/pwm/util/password/PwmPasswordRuleValidator.java

@@ -110,6 +110,7 @@ public class PwmPasswordRuleValidator
     }
 
     public boolean testPassword(
+            final SessionLabel sessionLabel,
             final PasswordData password,
             final PasswordData oldPassword,
             final UserInfo userInfo,
@@ -128,17 +129,17 @@ public class PwmPasswordRuleValidator
         {
             try
             {
-                LOGGER.trace( () -> "calling chai directory password validation checker" );
+                LOGGER.trace( sessionLabel, () -> "calling chai directory password validation checker" );
                 user.testPasswordPolicy( password.getStringValue() );
             }
             catch ( final UnsupportedOperationException e )
             {
-                LOGGER.trace( () -> "Unsupported operation was thrown while validating password: " + e );
+                LOGGER.trace( sessionLabel, () -> "Unsupported operation was thrown while validating password: " + e );
             }
             catch ( final ChaiUnavailableException e )
             {
                 StatisticsClient.incrementStat( pwmDomain.getPwmApplication(), Statistic.LDAP_UNAVAILABLE_COUNT );
-                LOGGER.warn( () -> "ChaiUnavailableException was thrown while validating password: " + e );
+                LOGGER.warn( sessionLabel, () -> "ChaiUnavailableException was thrown while validating password: " + e );
                 throw e;
             }
             catch ( final ChaiPasswordPolicyException e )
@@ -146,7 +147,7 @@ public class PwmPasswordRuleValidator
                 final ChaiError passwordError = e.getErrorCode();
                 final PwmError pwmError = PwmError.forChaiError( passwordError ).orElse( PwmError.PASSWORD_UNKNOWN_VALIDATION );
                 final ErrorInformation info = new ErrorInformation( pwmError );
-                LOGGER.trace( () -> "ChaiPasswordPolicyException was thrown while validating password: " + e );
+                LOGGER.trace( sessionLabel, () -> "ChaiPasswordPolicyException was thrown while validating password: " + e );
                 errorResults.add( info );
             }
         }
@@ -261,8 +262,7 @@ public class PwmPasswordRuleValidator
         final String jsonRequestBody = JsonFactory.get().serializeMap( sendData );
         try
         {
-            final String responseBody = RestClientHelper.makeOutboundRestWSCall( pwmDomain, locale, restURL,
-                    jsonRequestBody );
+            final String responseBody = RestClientHelper.makeOutboundRestWSCall( pwmDomain, sessionLabel, locale, restURL, jsonRequestBody );
             final Map<String, Object> responseMap = JsonFactory.get().deserializeMap( responseBody,
                     String.class,
                     Object.class );

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

@@ -198,7 +198,7 @@ public class X509Utils
         final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
                 .trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuousCertReader )
                 .build();
-        final PwmHttpClient pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration );
+        final PwmHttpClient pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration, sessionLabel );
         final PwmHttpClientRequest request = PwmHttpClientRequest.builder()
                 .method( HttpMethod.GET )
                 .url( uri.toString() )
@@ -209,7 +209,7 @@ public class X509Utils
         ErrorInformation requestError = null;
         try
         {
-            pwmHttpClient.makeRequest( request, sessionLabel );
+            pwmHttpClient.makeRequest( request );
         }
         catch ( final PwmException e )
         {

+ 3 - 2
server/src/main/java/password/pwm/ws/client/rest/RestClientHelper.java

@@ -47,6 +47,7 @@ public class RestClientHelper
 
     public static String makeOutboundRestWSCall(
             final PwmDomain pwmDomain,
+            final SessionLabel sessionLabel,
             final Locale locale,
             final String url,
             final String jsonRequestBody
@@ -56,7 +57,7 @@ public class RestClientHelper
         final PwmHttpClientConfiguration clientConfig = PwmHttpClientConfiguration.builder()
                 .trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous )
                 .build();
-        final PwmHttpClient pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( clientConfig );
+        final PwmHttpClient pwmHttpClient = pwmDomain.getHttpClientService().getPwmHttpClient( clientConfig, sessionLabel );
 
         final Map<String, String> httpPost = new LinkedHashMap<>();
         if ( locale != null )
@@ -78,7 +79,7 @@ public class RestClientHelper
         try
         {
             LOGGER.debug( () -> "beginning external rest call to: " + url + ", body: " + jsonRequestBody );
-            httpResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest, SessionLabel.SYSTEM_LABEL  );
+            httpResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest );
             final String responseBody = httpResponse.getBody();
             LOGGER.trace( () -> "external rest call returned: " + httpResponse.getStatusPhrase()  );
             if ( httpResponse.getStatusCode() != 200 )

+ 1 - 1
server/src/main/java/password/pwm/ws/client/rest/RestTokenDataClient.java

@@ -101,7 +101,7 @@ public class RestTokenDataClient implements RestClient
 
 
         final String jsonRequestData = JsonFactory.get().serializeMap( sendData );
-        final String responseBody = RestClientHelper.makeOutboundRestWSCall( pwmDomain, locale, url, jsonRequestData );
+        final String responseBody = RestClientHelper.makeOutboundRestWSCall( pwmDomain, sessionLabel, locale, url, jsonRequestData );
         return JsonFactory.get().deserialize( responseBody, TokenDestinationData.class );
     }
 

+ 5 - 3
server/src/main/java/password/pwm/ws/client/rest/form/RestFormDataClient.java

@@ -114,7 +114,7 @@ public class RestFormDataClient
         final PwmHttpClientResponse httpResponse;
         try
         {
-            httpResponse = getHttpClient( pwmDomain.getConfig() ).makeRequest( pwmHttpClientRequest, sessionLabel );
+            httpResponse = getHttpClient( pwmDomain.getConfig() ).makeRequest( pwmHttpClientRequest );
             final String responseBody = httpResponse.getBody();
             LOGGER.trace( () -> "external rest call returned: " + httpResponse.getStatusPhrase() + ", body: " + responseBody );
             if ( httpResponse.getStatusCode() != 200 )
@@ -134,7 +134,9 @@ public class RestFormDataClient
 
     }
 
-    private PwmHttpClient getHttpClient( final DomainConfig domainConfig )
+    private PwmHttpClient getHttpClient(
+            final DomainConfig domainConfig
+    )
             throws PwmUnrecoverableException
     {
 
@@ -144,7 +146,7 @@ public class RestFormDataClient
                 .trustManagerType( PwmHttpClientConfiguration.TrustManagerType.configuredCertificates )
                 .certificates( certificates )
                 .build();
-        return pwmDomain.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration );
+        return pwmDomain.getHttpClientService().getPwmHttpClient( pwmHttpClientConfiguration, this.sessionLabel );
     }
 
 }

+ 1 - 1
server/src/main/java/password/pwm/ws/server/RestServlet.java

@@ -220,7 +220,7 @@ public abstract class RestServlet extends HttpServlet
         }
         catch ( final PwmUnrecoverableException e )
         {
-            LOGGER.error( () -> "error while trying to log HTTP request data " + e.getMessage(), e );
+            LOGGER.error( sessionLabel, () -> "error while trying to log HTTP request data " + e.getMessage(), e );
         }
     }
 

+ 2 - 2
server/src/main/java/password/pwm/ws/server/rest/RestSetPasswordServer.java

@@ -216,14 +216,14 @@ public class RestSetPasswordServer extends RestServlet
         }
         catch ( final PwmException e )
         {
-            LOGGER.error( () -> "error during set password REST operation: " + e.getMessage() );
+            LOGGER.error( restRequest.getSessionLabel(), () -> "error during set password REST operation: " + e.getMessage() );
             return RestResultBean.fromError( restRequest, e.getErrorInformation() );
         }
         catch ( final Exception e )
         {
             final String errorMessage = "unexpected error executing web service: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, errorMessage );
-            LOGGER.error( () -> "error during set password REST operation: " + e.getMessage(), e );
+            LOGGER.error( restRequest.getSessionLabel(), () -> "error during set password REST operation: " + e.getMessage(), e );
             return RestResultBean.fromError( restRequest, errorInformation );
         }
     }

+ 11 - 10
server/src/test/java/password/pwm/http/client/PwmHttpClientTest.java

@@ -32,6 +32,7 @@ import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.bean.DomainID;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigKey;
@@ -131,11 +132,11 @@ public class PwmHttpClientTest
 
         // Obtain the HTTP client
         final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( tempAppPath.newFolder(), makeAppConfig( url, false, false ) );
-        final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(  );
+        final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient( SessionLabel.TEST_SESSION_LABEL );
 
         // Execute the HTTP request
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder().method( HttpMethod.GET ).url( url ).build();
-        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest, null );
+        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest );
 
         // Verify the response
         final int responseStatusCode = response.getStatusCode();
@@ -165,14 +166,14 @@ public class PwmHttpClientTest
 
         // Obtain the HTTP client
         final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( tempAppPath.newFolder(), makeAppConfig( null, false, false ) );
-        final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(  );
+        final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient( SessionLabel.TEST_SESSION_LABEL );
 
         // Execute the HTTP request
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder().method( HttpMethod.GET ).url( url ).build();
 
 
         // This should throw an exception, since we're doing https without setting SECURITY_HTTP_PROMISCUOUS_ENABLE, or setting certificates
-        httpClient.makeRequest( pwmHttpClientRequest, null );
+        httpClient.makeRequest( pwmHttpClientRequest );
     }
 
     /**
@@ -192,12 +193,12 @@ public class PwmHttpClientTest
         // Obtain the HTTP client
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( tempAppPath.newFolder(), makeAppConfig( null, true, false ) );
         final PwmHttpClient httpClient = pwmApplication.getHttpClientService().getPwmHttpClient(
-                PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous ).build()
+                PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous ).build(), SessionLabel.TEST_SESSION_LABEL
         );
 
         // Execute the HTTP request
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder().method( HttpMethod.GET ).url( url ).build();
-        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest, null );
+        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest );
 
         final int responseStatusCode = response.getStatusCode();
         Assert.assertEquals( 200, responseStatusCode );
@@ -225,12 +226,12 @@ public class PwmHttpClientTest
         final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( tempAppPath.newFolder(), makeAppConfig( null, false, true ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(
                 PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.configuredCertificates )
-                        .certificates( getWireMockSelfSignedCertificate() ).build()
+                        .certificates( getWireMockSelfSignedCertificate() ).build(), SessionLabel.TEST_SESSION_LABEL
         );
 
         // Execute the HTTP request
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder().method( HttpMethod.GET ).url( url ).build();
-        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest, null );
+        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest );
 
         // Verify the response
         final int responseStatusCode = response.getStatusCode();
@@ -259,14 +260,14 @@ public class PwmHttpClientTest
         final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( tempAppPath.newFolder(), makeAppConfig( proxyUrl, false, false ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(
                 PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.configuredCertificates )
-                        .certificates( getWireMockSelfSignedCertificate() ).build()
+                        .certificates( getWireMockSelfSignedCertificate() ).build(), SessionLabel.TEST_SESSION_LABEL
         );
 
 
         // We are making a request to www.example.com, but our server on localhost will receive it
         final String url = "http://www.example.com/simpleHello";
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder().method( HttpMethod.GET ).url( url ).build();
-        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest, null );
+        final PwmHttpClientResponse response = httpClient.makeRequest( pwmHttpClientRequest );
 
         // Verify the response
         final int responseStatusCode = response.getStatusCode();

+ 2 - 4
server/src/test/java/password/pwm/svc/sms/EmailQueueManagerTest.java

@@ -29,10 +29,10 @@ import org.mockito.Mockito;
 import password.pwm.AppProperty;
 import password.pwm.PwmConstants;
 import password.pwm.bean.EmailItemBean;
+import password.pwm.bean.SessionLabel;
 import password.pwm.config.AppConfig;
 import password.pwm.svc.email.EmailServer;
 import password.pwm.svc.email.EmailServerUtil;
-import password.pwm.svc.email.EmailService;
 import password.pwm.util.java.JavaHelper;
 
 import java.io.IOException;
@@ -44,8 +44,6 @@ public class EmailQueueManagerTest
     @Test
     public void testConvertEmailItemToMessage() throws MessagingException, IOException
     {
-        final EmailService emailService = new EmailService();
-
         final AppConfig config = Mockito.mock( AppConfig.class );
         Mockito.when( config.readAppProperty( AppProperty.SMTP_SUBJECT_ENCODING_CHARSET ) ).thenReturn( "UTF8" );
 
@@ -60,7 +58,7 @@ public class EmailQueueManagerTest
                 .javaMailProps( new Properties() )
                 .build();
 
-        final List<Message> messages = EmailServerUtil.convertEmailItemToMessages( emailItemBean, config, emailServer );
+        final List<Message> messages = EmailServerUtil.convertEmailItemToMessages( emailItemBean, config, emailServer, SessionLabel.TEST_SESSION_LABEL );
         Assert.assertEquals( 2, messages.size() );
 
         {