Selaa lähdekoodia

cef logging improvements

jrivard@gmail.com 6 vuotta sitten
vanhempi
commit
bccbca5b98

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

@@ -41,7 +41,7 @@ public enum AppProperty
     AUDIT_EVENTS_EMAILFROM                          ( "audit.events.emailFrom" ),
     AUDIT_EVENTS_EMAILSUBJECT                       ( "audit.events.emailSubject" ),
     AUDIT_EVENTS_LOCALDB_MAX_BULK_REMOVALS          ( "audit.events.localdb.maxBulkRemovals" ),
-    AUDIT_SYSLOG_CEF_EXTENSIONS                     ( "audit.syslog.cef.extensions" ),
+    AUDIT_SYSLOG_CEF_TIMEZONE                       ( "audit.syslog.cef.timezone" ),
     AUDIT_SYSLOG_CEF_HEADER_PRODUCT                 ( "audit.syslog.cef.header.product" ),
     AUDIT_SYSLOG_CEF_HEADER_SEVERITY                ( "audit.syslog.cef.header.severity" ),
     AUDIT_SYSLOG_CEF_HEADER_VENDOR                  ( "audit.syslog.cef.header.vendor" ),

+ 3 - 2
server/src/main/java/password/pwm/config/profile/NewUserProfile.java

@@ -48,6 +48,7 @@ public class NewUserProfile extends AbstractProfile
 {
 
     private static final ProfileType PROFILE_TYPE = ProfileType.NewUser;
+    public static final String TEST_USER_CONFIG_VALUE = "TESTUSER";
 
     private Instant newUserPasswordPolicyCacheTime;
     private final Map<Locale, PwmPasswordPolicy> newUserPasswordPolicyCache = new HashMap<>();
@@ -107,7 +108,7 @@ public class NewUserProfile extends AbstractProfile
         {
 
             final String lookupDN;
-            if ( "TESTUSER".equalsIgnoreCase( configuredNewUserPasswordDN ) )
+            if ( TEST_USER_CONFIG_VALUE.equalsIgnoreCase( configuredNewUserPasswordDN ) )
             {
                 lookupDN = defaultLdapProfile.readSettingAsString( PwmSetting.LDAP_TEST_USER_DN );
                 if ( lookupDN == null || lookupDN.isEmpty() )
@@ -116,7 +117,7 @@ public class NewUserProfile extends AbstractProfile
                             + PwmSetting.LDAP_TEST_USER_DN.toMenuLocationDebug( defaultLdapProfile.getIdentifier(), PwmConstants.DEFAULT_LOCALE )
                             + " must be configured since setting "
                             + PwmSetting.NEWUSER_PASSWORD_POLICY_USER.toMenuLocationDebug( this.getIdentifier(), PwmConstants.DEFAULT_LOCALE )
-                            + " is set to TESTUSER";
+                            + " is set to " + TEST_USER_CONFIG_VALUE;
                     throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INVALID_CONFIG, errorMsg ) );
                 }
             }

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

@@ -88,6 +88,7 @@ public enum HealthMessage
     LocalDBLogger_NOTOPEN( HealthStatus.CAUTION, HealthTopic.LocalDB ),
     LocalDBLogger_HighRecordCount( HealthStatus.CAUTION, HealthTopic.LocalDB ),
     LocalDBLogger_OldRecordPresent( HealthStatus.CAUTION, HealthTopic.LocalDB ),
+    NewUser_PwTemplateBad( HealthStatus.CAUTION, HealthTopic.Configuration ),
     ServiceClosed( HealthStatus.CAUTION, HealthTopic.Application ),
     ServiceClosed_LocalDBUnavail( HealthStatus.CAUTION, HealthTopic.Application ),
     ServiceClosed_AppReadOnly( HealthStatus.CAUTION, HealthTopic.Application ),

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

@@ -56,7 +56,7 @@ public class HealthMonitor implements PwmService
     static
     {
         final List<HealthChecker> records = new ArrayList<>();
-        records.add( new LDAPStatusChecker() );
+        records.add( new LDAPHealthChecker() );
         records.add( new JavaChecker() );
         records.add( new ConfigurationChecker() );
         records.add( new LocalDBHealthChecker() );

+ 83 - 11
server/src/main/java/password/pwm/health/LDAPStatusChecker.java → server/src/main/java/password/pwm/health/LDAPHealthChecker.java

@@ -45,6 +45,7 @@ import password.pwm.config.PwmSettingCategory;
 import password.pwm.config.PwmSettingFlag;
 import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.profile.LdapProfile;
+import password.pwm.config.profile.NewUserProfile;
 import password.pwm.config.profile.PwmPasswordPolicy;
 import password.pwm.config.profile.PwmPasswordRule;
 import password.pwm.config.value.data.UserPermission;
@@ -56,6 +57,7 @@ import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfoFactory;
 import password.pwm.util.PasswordData;
 import password.pwm.util.RandomPasswordGenerator;
+import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
@@ -80,10 +82,10 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
-public class LDAPStatusChecker implements HealthChecker
+public class LDAPHealthChecker implements HealthChecker
 {
 
-    private static final PwmLogger LOGGER = PwmLogger.forClass( LDAPStatusChecker.class );
+    private static final PwmLogger LOGGER = PwmLogger.forClass( LDAPHealthChecker.class );
     private static final String TOPIC = "LDAP";
 
     public List<HealthRecord> doHealthCheck( final PwmApplication pwmApplication )
@@ -95,9 +97,9 @@ public class LDAPStatusChecker implements HealthChecker
         for ( final Map.Entry<String, LdapProfile> entry : ldapProfiles.entrySet() )
         {
             final String profileID = entry.getKey();
-            final List<HealthRecord> profileRecords = new ArrayList<>();
-            profileRecords.addAll(
-                    checkBasicLdapConnectivity( pwmApplication, config, entry.getValue(), true ) );
+            final List<HealthRecord> profileRecords = new ArrayList<>(
+                    checkBasicLdapConnectivity( pwmApplication, config, entry.getValue(), true )
+            );
 
             if ( profileRecords.isEmpty() )
             {
@@ -108,7 +110,6 @@ public class LDAPStatusChecker implements HealthChecker
             {
                 profileRecords.add( HealthRecord.forMessage( HealthMessage.LDAP_OK ) );
                 profileRecords.addAll( doLdapTestUserCheck( config, ldapProfiles.get( profileID ), pwmApplication ) );
-
             }
             returnRecords.addAll( profileRecords );
         }
@@ -147,6 +148,8 @@ public class LDAPStatusChecker implements HealthChecker
                 returnRecords.addAll( checkUserPermissionValues( pwmApplication ) );
 
                 returnRecords.addAll( checkLdapDNSyntaxValues( pwmApplication ) );
+
+                returnRecords.addAll( checkNewUserPasswordTemplateSetting( pwmApplication, config ) );
             }
         }
 
@@ -842,7 +845,7 @@ public class LDAPStatusChecker implements HealthChecker
                 if ( !pwmSetting.isHidden()
                         && pwmSetting.getCategory() == PwmSettingCategory.LDAP_PROFILE
                         && pwmSetting.getFlags().contains( PwmSettingFlag.ldapDNsyntax )
-                        )
+                )
                 {
                     for ( final String profile : config.getLdapProfiles().keySet() )
                     {
@@ -891,6 +894,75 @@ public class LDAPStatusChecker implements HealthChecker
         return returnList;
     }
 
+    private static List<HealthRecord> checkNewUserPasswordTemplateSetting(
+            final PwmApplication pwmApplication,
+            final Configuration configuration
+    )
+    {
+        final Locale locale = PwmConstants.DEFAULT_LOCALE;
+        if ( !configuration.readSettingAsBoolean( PwmSetting.NEWUSER_ENABLE ) )
+        {
+            return Collections.emptyList();
+        }
+
+        for ( final NewUserProfile newUserProfile : configuration.getNewUserProfiles().values() )
+        {
+            final String policyUserStr = newUserProfile.readSettingAsString( PwmSetting.NEWUSER_PASSWORD_POLICY_USER );
+
+            if ( StringUtil.isEmpty( policyUserStr ) )
+            {
+                return Collections.singletonList(
+                        HealthRecord.forMessage(
+                                HealthMessage.NewUser_PwTemplateBad,
+                                PwmSetting.NEWUSER_PASSWORD_POLICY_USER.toMenuLocationDebug( newUserProfile.getIdentifier(), locale ),
+                                LocaleHelper.valueNotApplicable( locale )
+                        )
+                );
+            }
+
+            try
+            {
+                final LdapProfile ldapProfile = configuration.getDefaultLdapProfile();
+                if ( NewUserProfile.TEST_USER_CONFIG_VALUE.equals( policyUserStr ) )
+                {
+                    final UserIdentity testUser = ldapProfile.getTestUser( pwmApplication );
+                    if ( testUser != null )
+                    {
+                        return Collections.emptyList();
+                    }
+                }
+
+                final UserIdentity newUserTemplateIdentity = new UserIdentity( policyUserStr, ldapProfile.getIdentifier() );
+
+                final ChaiUser chaiUser = pwmApplication.getProxiedChaiUser( newUserTemplateIdentity );
+
+                try
+                {
+                    if ( !chaiUser.exists() )
+                    {
+                        return Collections.singletonList(
+                                HealthRecord.forMessage(
+                                        HealthMessage.NewUser_PwTemplateBad,
+                                        PwmSetting.NEWUSER_PASSWORD_POLICY_USER.toMenuLocationDebug( newUserProfile.getIdentifier(), locale )
+                                )
+                        );
+                    }
+                }
+                catch ( ChaiUnavailableException e )
+                {
+                    throw PwmUnrecoverableException.fromChaiException( e );
+                }
+            }
+            catch ( PwmUnrecoverableException e )
+            {
+                LOGGER.error( "error checking new user password policy user settings:" + e.getMessage() );
+            }
+        }
+
+        return Collections.emptyList();
+    }
+
+
     private static List<HealthRecord> checkUserPermission(
             final PwmApplication pwmApplication,
             final UserPermission userPermission,
@@ -1031,15 +1103,15 @@ public class LDAPStatusChecker implements HealthChecker
             throws PwmUnrecoverableException
     {
         final PwmApplication tempApplication = new PwmApplication( pwmApplication.getPwmEnvironment().makeRuntimeInstance( config ) );
-        final LDAPStatusChecker ldapStatusChecker = new LDAPStatusChecker();
+        final LDAPHealthChecker ldapHealthChecker = new LDAPHealthChecker();
         final List<HealthRecord> profileRecords = new ArrayList<>();
 
         final LdapProfile ldapProfile = config.getLdapProfiles().get( profileID );
-        profileRecords.addAll( ldapStatusChecker.checkBasicLdapConnectivity( tempApplication, config, ldapProfile,
+        profileRecords.addAll( ldapHealthChecker.checkBasicLdapConnectivity( tempApplication, config, ldapProfile,
                 testContextless ) );
         if ( fullTest )
         {
-            profileRecords.addAll( ldapStatusChecker.checkLdapServerUrls( pwmApplication, config, ldapProfile ) );
+            profileRecords.addAll( ldapHealthChecker.checkLdapServerUrls( pwmApplication, config, ldapProfile ) );
         }
 
         if ( profileRecords.isEmpty() )
@@ -1049,7 +1121,7 @@ public class LDAPStatusChecker implements HealthChecker
 
         if ( fullTest )
         {
-            profileRecords.addAll( ldapStatusChecker.doLdapTestUserCheck( config, ldapProfile, tempApplication ) );
+            profileRecords.addAll( ldapHealthChecker.doLdapTestUserCheck( config, ldapProfile, tempApplication ) );
         }
 
         return HealthRecord.asHealthDataBean( config, locale, profileRecords );

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

@@ -58,7 +58,7 @@ import password.pwm.health.DatabaseStatusChecker;
 import password.pwm.health.HealthRecord;
 import password.pwm.health.HealthStatus;
 import password.pwm.health.HealthTopic;
-import password.pwm.health.LDAPStatusChecker;
+import password.pwm.health.LDAPHealthChecker;
 import password.pwm.http.HttpMethod;
 import password.pwm.http.JspUrl;
 import password.pwm.http.ProcessStatus;
@@ -672,7 +672,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         LOGGER.debug( pwmRequest, () -> "beginning restLdapHealthCheck" );
         final String profileID = pwmRequest.readParameterAsString( "profile" );
         final Configuration config = new Configuration( configManagerBean.getStoredConfiguration() );
-        final HealthData healthData = LDAPStatusChecker.healthForNewConfiguration( pwmRequest.getPwmApplication(), config, pwmRequest.getLocale(), profileID, true, true );
+        final HealthData healthData = LDAPHealthChecker.healthForNewConfiguration( pwmRequest.getPwmApplication(), config, pwmRequest.getLocale(), profileID, true, true );
         final RestResultBean restResultBean = RestResultBean.withData( healthData );
 
         pwmRequest.outputJsonResult( restResultBean );

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

@@ -49,7 +49,7 @@ import password.pwm.health.HealthMonitor;
 import password.pwm.health.HealthRecord;
 import password.pwm.health.HealthStatus;
 import password.pwm.health.HealthTopic;
-import password.pwm.health.LDAPStatusChecker;
+import password.pwm.health.LDAPHealthChecker;
 import password.pwm.http.ContextManager;
 import password.pwm.http.HttpMethod;
 import password.pwm.http.ProcessStatus;
@@ -238,7 +238,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
                 .getPwmEnvironment()
                 .makeRuntimeInstance( tempConfiguration ) );
 
-        final LDAPStatusChecker ldapStatusChecker = new LDAPStatusChecker();
+        final LDAPHealthChecker ldapHealthChecker = new LDAPHealthChecker();
         final List<HealthRecord> records = new ArrayList<>();
         final LdapProfile ldapProfile = tempConfiguration.getDefaultLdapProfile();
 
@@ -261,7 +261,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
             case LDAP_PROXY:
             {
-                records.addAll( ldapStatusChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, false ) );
+                records.addAll( ldapHealthChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, false ) );
                 if ( records.isEmpty() )
                 {
                     records.add( password.pwm.health.HealthRecord.forMessage( HealthMessage.LDAP_OK ) );
@@ -271,7 +271,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
             case LDAP_CONTEXT:
             {
-                records.addAll( ldapStatusChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, true ) );
+                records.addAll( ldapHealthChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, true ) );
                 if ( records.isEmpty() )
                 {
                     records.add( new HealthRecord( HealthStatus.GOOD, HealthTopic.LDAP, "LDAP Contextless Login Root validated" ) );
@@ -317,8 +317,8 @@ public class ConfigGuideServlet extends ControlledPwmServlet
                 final String testUserValue = configGuideBean.getFormData().get( ConfigGuideFormField.PARAM_LDAP_TEST_USER );
                 if ( testUserValue != null && !testUserValue.isEmpty() )
                 {
-                    records.addAll( ldapStatusChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, false ) );
-                    records.addAll( ldapStatusChecker.doLdapTestUserCheck( tempConfiguration, ldapProfile, tempApplication ) );
+                    records.addAll( ldapHealthChecker.checkBasicLdapConnectivity( tempApplication, tempConfiguration, ldapProfile, false ) );
+                    records.addAll( ldapHealthChecker.doLdapTestUserCheck( tempConfiguration, ldapProfile, tempApplication ) );
                 }
                 else
                 {

+ 38 - 0
server/src/main/java/password/pwm/svc/event/AuditField.java

@@ -0,0 +1,38 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2018 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.svc.event;
+
+public enum AuditField
+{
+    type,
+    eventCode,
+    timestamp,
+    message,
+    narrative,
+    perpetratorID,
+    perpetratorDN,
+    sourceAddress,
+    sourceHost,
+    targetID,
+    targetDN,
+}

+ 69 - 0
server/src/main/java/password/pwm/svc/event/CEFExtension.java

@@ -0,0 +1,69 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2018 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.svc.event;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public enum CEFExtension
+{
+    cat( AuditField.type ),
+    act( AuditField.eventCode ),
+    rt( AuditField.timestamp ),
+    msg( AuditField.message ),
+    reason ( AuditField.narrative ),
+    suid( AuditField.perpetratorID ),
+    suser( AuditField.perpetratorDN ),
+    src ( AuditField.sourceAddress ),
+    srchost( AuditField.sourceHost ),
+    duid( AuditField.targetID ),
+    duser( AuditField.targetDN ),
+    dvchost( null ),
+    dtz( null ),;
+
+    private final AuditField auditField;
+
+    public static final String CEF_EXTENSION_SEPARATOR = "|";
+
+    public static final Map<String, String> CEF_VALUE_ESCAPES;
+
+    static
+    {
+        final Map<String, String> map = new LinkedHashMap<>( );
+        map.put( "\\", "\\\\" );
+        map.put( "=", "\\=" );
+        map.put( "|", "\"" );
+        CEF_VALUE_ESCAPES = Collections.unmodifiableMap( map );
+    }
+
+    CEFExtension( final AuditField auditField )
+    {
+        this.auditField = auditField;
+    }
+
+    public AuditField getAuditField()
+    {
+        return auditField;
+    }
+}

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

@@ -75,9 +75,7 @@ import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -91,18 +89,6 @@ public class SyslogAuditService
     private static final String SYSLOG_INSTANCE_NAME = "syslog-audit";
     private static final int LENGTH_OVERSIZE = 1024;
 
-    private static final Map<String, String> CEF_VALUE_ESCAPES;
-
-
-    static
-    {
-        final Map<String, String> map = new LinkedHashMap<>( );
-        map.put( "\\", "\\\\" );
-        map.put( "=", "\\=" );
-        map.put( "|", "\"" );
-        CEF_VALUE_ESCAPES = Collections.unmodifiableMap( map );
-    }
-
     private SyslogIF syslogInstance = null;
     private ErrorInformation lastError = null;
     private List<X509Certificate> certificates = null;
@@ -113,7 +99,7 @@ public class SyslogAuditService
     private final Configuration configuration;
     private final PwmApplication pwmApplication;
     private final SyslogOutputFormat syslogOutputFormat;
-    private final Map<String, String> syslogCefExtensions;
+    private final String cefTimezone;
 
     public SyslogAuditService( final PwmApplication pwmApplication )
             throws LocalDBException
@@ -122,7 +108,7 @@ public class SyslogAuditService
         this.pwmApplication = pwmApplication;
         this.configuration = pwmApplication.getConfig();
         this.certificates = configuration.readSettingAsCertificate( PwmSetting.AUDIT_SYSLOG_CERTIFICATES );
-        this.syslogCefExtensions = figureCefSyslogExtensions( configuration );
+        this.cefTimezone = configuration.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_TIMEZONE );
 
         final List<String> syslogConfigStringArray = configuration.readSettingAsStringArray( PwmSetting.AUDIT_SYSLOG_SERVERS );
         try
@@ -368,7 +354,6 @@ public class SyslogAuditService
     }
 
 
-    private static final String CEF_EXTENSION_SEPARATOR = "|";
 
     private String convertAuditRecordToCEFMessage(
             final AuditRecord auditRecord,
@@ -385,7 +370,7 @@ public class SyslogAuditService
 
         final MacroMachine macroMachine = MacroMachine.forNonUserSpecific( pwmApplication, SessionLabel.SYSTEM_LABEL );
 
-        final String auditFieldName = LocaleHelper.getLocalizedMessage(
+        final String cefFieldName = LocaleHelper.getLocalizedMessage(
                 PwmConstants.DEFAULT_LOCALE,
                 auditRecord.getEventCode().getMessage(),
                 configuration
@@ -399,50 +384,57 @@ public class SyslogAuditService
             cefOutput.append( "CEF:0" );
 
             // Device Vendor
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
             cefOutput.append( macroMachine.expandMacros( headerVendor ) );
 
             // Device Product
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
             cefOutput.append( macroMachine.expandMacros( headerProduct ) );
 
             // Device Version
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
             cefOutput.append( PwmConstants.SERVLET_VERSION );
 
             // Device Event Class ID
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
             cefOutput.append( auditRecord.getEventCode() );
 
             // field name
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
-            cefOutput.append( auditFieldName );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( cefFieldName );
 
             // severity
-            cefOutput.append( CEF_EXTENSION_SEPARATOR );
+            cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
             cefOutput.append( macroMachine.expandMacros( headerSeverity ) );
         }
 
-        cefOutput.append( CEF_EXTENSION_SEPARATOR );
+        cefOutput.append( CEFExtension.CEF_EXTENSION_SEPARATOR );
 
-        srcHost.ifPresent( s -> appendCefValue( "dvchost", s, cefOutput ) );
+        srcHost.ifPresent( s -> appendCefValue( CEFExtension.dvchost.name(), s, cefOutput ) );
 
-        appendCefValue( "dtz", "Zulu", cefOutput );
+        if ( StringUtil.isEmpty( cefTimezone ) )
+        {
+            appendCefValue( CEFExtension.dtz.name(), cefTimezone, cefOutput );
+        }
 
-        for ( final Map.Entry<String, String> entry : syslogCefExtensions.entrySet() )
+        for ( final CEFExtension cefExtension : CEFExtension.values() )
         {
-            final Object value = auditRecordMap.get( entry.getKey() );
-            if ( value != null )
+            if ( cefExtension.getAuditField() != null )
             {
-                final String name = entry.getValue();
-                final String valueString = value.toString();
-                appendCefValue( name, valueString, cefOutput );
+                final String auditFieldName = cefExtension.getAuditField().name();
+                final Object value = auditRecordMap.get( auditFieldName );
+                if ( value != null )
+                {
+                    final String valueString = value.toString();
+                    appendCefValue( auditFieldName, valueString, cefOutput );
+                }
             }
         }
 
-        if ( cefOutput.substring( cefOutput.length() - CEF_EXTENSION_SEPARATOR.length() ).equals( CEF_EXTENSION_SEPARATOR ) )
+        final int cefLength = CEFExtension.CEF_EXTENSION_SEPARATOR.length();
+        if ( cefOutput.substring( cefOutput.length() - cefLength ).equals( CEFExtension.CEF_EXTENSION_SEPARATOR ) )
         {
-            cefOutput.replace( cefOutput.length() - CEF_EXTENSION_SEPARATOR.length(), cefOutput.length(), "" );
+            cefOutput.replace( cefOutput.length() - cefLength, cefOutput.length(), "" );
         }
 
         return cefOutput.toString();
@@ -462,7 +454,7 @@ public class SyslogAuditService
     private static String escapeCEFValue( final String value )
     {
         String replacedValue = value;
-        for ( final Map.Entry<String, String> entry : CEF_VALUE_ESCAPES.entrySet() )
+        for ( final Map.Entry<String, String> entry : CEFExtension.CEF_VALUE_ESCAPES.entrySet() )
         {
             final String pattern = entry.getKey();
             final String replacement = entry.getValue();
@@ -576,17 +568,6 @@ public class SyslogAuditService
         }
     }
 
-    private Map<String, String> figureCefSyslogExtensions( final Configuration config )
-    {
-        final String pairSplitter = ":";
-        final String keyValueSplitter = ",";
-        final String configuredString = config.readAppProperty( AppProperty.AUDIT_SYSLOG_CEF_EXTENSIONS );
-
-        final List<String> pairs = Arrays.asList( configuredString.split( pairSplitter ) );
-        final Map<String, String> map = StringUtil.convertStringListToNameValuePair( pairs, keyValueSplitter );
-        return Collections.unmodifiableMap( map );
-    }
-
     private static Optional<String> deriveLocalServerHostname( final Configuration configuration )
     {
         if ( configuration != null )

+ 1 - 1
server/src/main/resources/password/pwm/AppProperty.properties

@@ -32,7 +32,7 @@ application.wordlistRetryImportSeconds=600
 audit.events.emailFrom=Audit Event Notification <@DefaultEmailFromAddress@>
 audit.events.emailSubject=@PwmAppName@ - Audit Event - %EVENT%
 audit.events.localdb.maxBulkRemovals=301
-audit.syslog.cef.extensions=type,cat\:eventCode,act\:timestamp,rt\:message,msg\:narrative,reason\:perpetratorID,suid\:perpetratorDN,suser\:sourceAddress,src\:sourceHost,srchost\:targetID,duid\:targetDN,duser
+audit.syslog.cef.timezone=Zulu
 audit.syslog.cef.header.product=@PwmAppName@
 audit.syslog.cef.header.severity=Medium
 audit.syslog.cef.header.vendor=@PwmVendorName@

+ 1 - 0
server/src/main/resources/password/pwm/i18n/Health.properties

@@ -78,6 +78,7 @@ HealthMessage_LocalDB_CLOSED=LocalDB is CLOSED, statistics, online logging, word
 HealthMessage_LocalDBLogger_NOTOPEN=LocalDBLogger is not open, status is %1%
 HealthMessage_LocalDBLogger_HighRecordCount=LocalDBLogger event log record count of %1% records, is more than the configured maximum of %2%.  Excess records are being purged.
 HealthMessage_LocalDBLogger_OldRecordPresent=Oldest LocalDBLogger event log record is %1%, configured maximum is %2%.  Excess records are being purged.
+HealthMessage_NewUser_PwTemplateBad=The setting %1% is set to a LDAP DN value that is invalid
 HealthMessage_ServiceClosed=unable to start %1% service
 HealthMessage_ServiceClosed_LocalDBUnavail=unable to start %1% service, LocalDB is not available
 HealthMessage_ServiceClosed_AppReadOnly=unable to start %1% service, application is in read-only mode

+ 1 - 1
server/src/main/resources/password/pwm/i18n/PwmSetting.properties

@@ -494,7 +494,7 @@ Setting_Description_newUser.email.verification=Enable this option to have @PwmAp
 Setting_Description_newUser.enable=Enable this option to allow @PwmAppName@ to display the new user registration.
 Setting_Description_newUser.form=Specify the New User form creation attributes and fields. This is used to determine what information will need to be filled in before submitting the new user form to create the new user.
 Setting_Description_newUser.minimumWaitTime=Specify a delay time during a new user creation. @PwmAppName@ delays the creation of the user for at least this amount of time before forwarding the user to the next activity.  <br/><br/>Specify the value in seconds.
-Setting_Description_newUser.passwordPolicy.user=Specify the user @PwmAppName@ uses as a template for the new user password policy. If the value is <i>TESTUSER</i>, @PwmAppName@ uses the configured test user's password policy. The <i>TESTUSER</i> was entered at installation time.
+Setting_Description_newUser.passwordPolicy.user=Specify a valid LDAP user DN that @PwmAppName@ can use as a template for the new user password policy. If the value is the literal value "<b>TESTUSER</b>", @PwmAppName@ uses the configured test user's password policy as the policy for the new user prior to its actual creation in the LDAP directory.
 Setting_Description_newUser.profile.displayName=Specify the publicly viewable display name of this profile. This value will only be seen if the profile was enabled to be shown publicly.
 Setting_Description_newUser.profile.list=List of New User profiles. When you configure multiple new user profiles, the user can select which profile to complete.  @PwmAppName@ shows the profile name to the users as the value of the setting <code>@PwmSettingReference\:newUser.profile.displayName@</code>.
 Setting_Description_newUser.profile.visible=Show this New User profile to users when they select New User registration.  If disabled, this profile is still available by direct URL but is not shown as a selectable profile.