Преглед на файлове

Initial multiple email server implemintation

rkeil преди 7 години
родител
ревизия
b6fa2028fe

+ 24 - 29
server/pom.xml

@@ -42,12 +42,6 @@
                 <checkstyle.skip>true</checkstyle.skip>
             </properties>
         </profile>
-        <profile>
-            <id>skip-jspc</id>
-            <properties>
-                <jspc.skip>true</jspc.skip>
-            </properties>
-        </profile>
         <profile>
             <id>skip-spotbugs</id>
             <properties>
@@ -107,6 +101,7 @@
                     </dependency>
                 </dependencies>
                 <configuration>
+                    <fork>false</fork>
                     <excludeFilterFile>src/build/spotbugs-exclude.xml</excludeFilterFile>
                     <includeTests>false</includeTests>
                     <skip>${skipSpotbugs}</skip>
@@ -178,10 +173,28 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.3</version>
+                <version>3.7.0</version>
                 <configuration>
                     <source>${maven.compiler.source}</source>
                     <target>${maven.compiler.target}</target>
+
+                    <!-- following allows lombok processor to execute on jdk9+ -->
+                    <showDeprecation>true</showDeprecation>
+                    <showWarnings>true</showWarnings>
+                    <fork>true</fork>
+                    <compilerargs>
+                        <arg>-Werror</arg>
+                        <arg>-Xlint:all</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
+                        <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
+                    </compilerargs>
                 </configuration>
             </plugin>
             <plugin>
@@ -247,7 +260,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-checkstyle-plugin</artifactId>
-                <version>2.17</version>
+                <version>3.0.0</version>
                 <dependencies>
                     <dependency>
                         <groupId>com.puppycrawl.tools</groupId>
@@ -314,27 +327,9 @@
                 </executions>
             </plugin>
             <plugin>
-                <groupId>org.jasig.mojo.jspc</groupId>
+                <groupId>io.leonard.maven.plugins</groupId>
                 <artifactId>jspc-maven-plugin</artifactId>
-                <version>2.0.2</version>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.jasig.mojo.jspc</groupId>
-                        <artifactId>jspc-compiler-tomcat7</artifactId>
-                        <version>2.0.2</version>
-                    </dependency>
-                </dependencies>
-                <configuration>
-                    <includeInProject>false</includeInProject>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                        </goals>
-                        <phase>compile</phase>
-                    </execution>
-                </executions>
+                <version>2.4.2</version>
             </plugin>
             <plugin>
                 <artifactId>maven-clean-plugin</artifactId>
@@ -569,7 +564,7 @@
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
-            <version>1.16.18</version>
+            <version>1.16.20</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

+ 11 - 7
server/src/main/java/password/pwm/config/Configuration.java

@@ -32,17 +32,18 @@ import password.pwm.config.option.DataStorageMethod;
 import password.pwm.config.option.MessageSendMethod;
 import password.pwm.config.option.TokenStorageMethod;
 import password.pwm.config.profile.ChallengeProfile;
-import password.pwm.config.profile.DeleteAccountProfile;
+import password.pwm.config.profile.PwmPasswordPolicy;
+import password.pwm.config.profile.PwmPasswordRule;
+import password.pwm.config.profile.LdapProfile;
+import password.pwm.config.profile.ProfileType;
+import password.pwm.config.profile.EmailServerProfile;
 import password.pwm.config.profile.ForgottenPasswordProfile;
+import password.pwm.config.profile.DeleteAccountProfile;
 import password.pwm.config.profile.HelpdeskProfile;
-import password.pwm.config.profile.LdapProfile;
+import password.pwm.config.profile.UpdateAttributesProfile;
 import password.pwm.config.profile.NewUserProfile;
 import password.pwm.config.profile.Profile;
-import password.pwm.config.profile.ProfileType;
 import password.pwm.config.profile.ProfileUtility;
-import password.pwm.config.profile.PwmPasswordPolicy;
-import password.pwm.config.profile.PwmPasswordRule;
-import password.pwm.config.profile.UpdateAttributesProfile;
 import password.pwm.config.stored.ConfigurationProperty;
 import password.pwm.config.stored.StoredConfigurationImpl;
 import password.pwm.config.stored.StoredConfigurationUtil;
@@ -865,7 +866,6 @@ public class Configuration implements SettingReader {
 
     /* generic profile stuff */
 
-
     public Map<String,NewUserProfile> getNewUserProfiles() {
         final Map<String,NewUserProfile> returnMap = new LinkedHashMap<>();
         final Map<String,Profile> profileMap = profileMap(ProfileType.NewUser);
@@ -936,6 +936,10 @@ public class Configuration implements SettingReader {
                 newProfile = DeleteAccountProfile.makeFromStoredConfiguration(storedConfiguration, profileID);
                 break;
 
+            case EmailServers:
+                newProfile = EmailServerProfile.makeFromStoredConfiguration(storedConfiguration, profileID);
+                break;
+
             default: throw new IllegalArgumentException("unknown profile type: " + profileType.toString());
         }
 

+ 4 - 2
server/src/main/java/password/pwm/config/PwmSetting.java

@@ -280,7 +280,7 @@ public enum PwmSetting {
             "email.profile.list", PwmSettingSyntax.PROFILE, PwmSettingCategory.INTERNAL),
     EMAIL_SERVER_ADDRESSES(
             "email.smtp.addresses", PwmSettingSyntax.STRING, PwmSettingCategory.EMAIL_PROFILES),
-    EMAIL_SERVER_PORTs(
+    EMAIL_SERVER_PORTS(
             "email.smtp.ports", PwmSettingSyntax.NUMERIC, PwmSettingCategory.EMAIL_PROFILES),
     EMAIL_DEFAULT_FROM_ADDRESSES(
             "email.default.fromAddresses", PwmSettingSyntax.STRING, PwmSettingCategory.EMAIL_PROFILES),
@@ -300,6 +300,7 @@ public enum PwmSetting {
             "email.smtp.username", PwmSettingSyntax.STRING, PwmSettingCategory.EMAIL_SETTINGS),
     EMAIL_PASSWORD(
             "email.smtp.userpassword", PwmSettingSyntax.PASSWORD, PwmSettingCategory.EMAIL_SETTINGS),
+
     EMAIL_MAX_QUEUE_AGE(
             "email.queueMaxAge", PwmSettingSyntax.DURATION, PwmSettingCategory.EMAIL_SETTINGS),
     EMAIL_ADVANCED_SETTINGS(
@@ -678,7 +679,8 @@ public enum PwmSetting {
             "audit.syslog.servers", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.AUDIT_FORWARD),
     AUDIT_SYSLOG_CERTIFICATES(
             "audit.syslog.certificates", PwmSettingSyntax.X509CERT, PwmSettingCategory.AUDIT_FORWARD),
-
+    AUDIT_SYSLOG_OUTPUT_FORMAT(
+            "audit.syslog.outputFormat", PwmSettingSyntax.SELECT, PwmSettingCategory.AUDIT_FORWARD),
 
     // challenge settings
     CHALLENGE_ENABLE(

+ 1 - 0
server/src/main/java/password/pwm/config/profile/ProfileType.java

@@ -31,6 +31,7 @@ public enum ProfileType {
     NewUser             (false, PwmSettingCategory.NEWUSER_PROFILE,     null),
     UpdateAttributes    (true,  PwmSettingCategory.UPDATE_PROFILE,      PwmSetting.UPDATE_PROFILE_QUERY_MATCH),
     DeleteAccount(true,  PwmSettingCategory.DELETE_ACCOUNT_PROFILE, PwmSetting.DELETE_ACCOUNT_PERMISSION),
+    EmailServers(true, PwmSettingCategory.EMAIL_PROFILES, null),
     ;
     
     private final boolean authenticated;

+ 5 - 90
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java

@@ -51,7 +51,6 @@ import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmDataValidationException;
 import password.pwm.error.PwmError;
-import password.pwm.error.PwmException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.HttpMethod;
@@ -84,9 +83,7 @@ import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.svc.token.TokenPayload;
 import password.pwm.svc.token.TokenType;
 import password.pwm.util.CaptchaUtility;
-import password.pwm.util.PasswordData;
 import password.pwm.util.PostChangePasswordAction;
-import password.pwm.util.RandomPasswordGenerator;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
@@ -213,15 +210,15 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet {
         return ProcessStatus.Continue;
     }
 
-    private static ForgottenPasswordBean forgottenPasswordBean(final PwmRequest pwmRequest) throws PwmUnrecoverableException {
+    static ForgottenPasswordBean forgottenPasswordBean( final PwmRequest pwmRequest ) throws PwmUnrecoverableException {
         return pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, ForgottenPasswordBean.class);
     }
 
-    private static void clearForgottenPasswordBean(final PwmRequest pwmRequest) throws PwmUnrecoverableException {
+    static void clearForgottenPasswordBean( final PwmRequest pwmRequest ) throws PwmUnrecoverableException {
         pwmRequest.getPwmApplication().getSessionStateService().clearBean(pwmRequest, ForgottenPasswordBean.class);
     }
 
-    private static ForgottenPasswordProfile forgottenPasswordProfile(final PwmRequest pwmRequest) throws PwmUnrecoverableException {
+    static ForgottenPasswordProfile forgottenPasswordProfile( final PwmRequest pwmRequest ) throws PwmUnrecoverableException {
         final ForgottenPasswordBean forgottenPasswordBean = forgottenPasswordBean(pwmRequest);
         return pwmRequest.getConfig().getForgottenPasswordProfiles().get(forgottenPasswordBean.getForgottenPasswordProfileID());
     }
@@ -896,7 +893,7 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet {
 
         final RecoveryAction recoveryAction = ForgottenPasswordUtil.getRecoveryAction(config, forgottenPasswordBean);
         if (recoveryAction == RecoveryAction.SENDNEWPW || recoveryAction == RecoveryAction.SENDNEWPW_AND_EXPIRE) {
-            processSendNewPassword(pwmRequest);
+            ForgottenPasswordUtil.doActionSendNewPassword(pwmRequest);
             return;
         }
 
@@ -1005,88 +1002,6 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet {
         }
     }
 
-    private static void processSendNewPassword(final PwmRequest pwmRequest)
-            throws ChaiUnavailableException, IOException, ServletException, PwmUnrecoverableException
-    {
-        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
-        final PwmSession pwmSession = pwmRequest.getPwmSession();
-        final ForgottenPasswordBean forgottenPasswordBean = forgottenPasswordBean(pwmRequest);
-        final ForgottenPasswordProfile forgottenPasswordProfile = forgottenPasswordProfile(pwmRequest);
-        final RecoveryAction recoveryAction = ForgottenPasswordUtil.getRecoveryAction(pwmApplication.getConfig(), forgottenPasswordBean);
-
-        LOGGER.trace(pwmRequest,"beginning process to send new password to user");
-
-        if (!forgottenPasswordBean.getProgress().isAllPassed()) {
-            return;
-        }
-
-        final UserIdentity userIdentity = forgottenPasswordBean.getUserIdentity();
-        final ChaiUser theUser = pwmRequest.getPwmApplication().getProxiedChaiUser(userIdentity);
-
-        try { // try unlocking user
-            theUser.unlockPassword();
-            LOGGER.trace(pwmRequest, "unlock account succeeded");
-        } catch (ChaiOperationException e) {
-            final String errorMsg = "unable to unlock user " + theUser.getEntryDN() + " error: " + e.getMessage();
-            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNLOCK_FAILURE,errorMsg);
-            LOGGER.error(pwmRequest.getPwmSession(), errorInformation.toDebugStr());
-            pwmRequest.respondWithError(errorInformation);
-            return;
-        }
-
-        try {
-            pwmSession.getLoginInfoBean().setAuthenticated(true);
-            pwmSession.getLoginInfoBean().getAuthFlags().add(AuthenticationType.AUTH_FROM_PUBLIC_MODULE);
-            pwmSession.getLoginInfoBean().setUserIdentity(userIdentity);
-
-            LOGGER.info(pwmRequest, "user successfully supplied password recovery responses, emailing new password to: " + theUser.getEntryDN());
-
-            // add post change actions
-            addPostChangeAction(pwmRequest, userIdentity);
-
-            // create newpassword
-            final PasswordData newPassword = RandomPasswordGenerator.createRandomPassword(pwmSession, pwmApplication);
-
-            // set the password
-            LOGGER.trace(pwmRequest.getPwmSession(), "setting user password to system generated random value");
-            PasswordUtility.setActorPassword(pwmSession, pwmApplication, newPassword);
-
-            if (recoveryAction == RecoveryAction.SENDNEWPW_AND_EXPIRE) {
-                LOGGER.debug(pwmSession, "marking user password as expired");
-                theUser.expirePassword();
-            }
-
-            // mark the event log
-            pwmApplication.getAuditManager().submit(AuditEvent.RECOVER_PASSWORD, pwmSession.getUserInfo(), pwmSession);
-
-            final MessageSendMethod messageSendMethod = forgottenPasswordProfile.readSettingAsEnum(PwmSetting.RECOVERY_SENDNEWPW_METHOD,MessageSendMethod.class);
-
-            // send email or SMS
-            final String toAddress = PasswordUtility.sendNewPassword(
-                    pwmSession.getUserInfo(),
-                    pwmApplication,
-                    pwmSession.getSessionManager().getMacroMachine(pwmApplication),
-                    newPassword,
-                    pwmSession.getSessionStateBean().getLocale(),
-                    messageSendMethod
-            );
-
-            pwmRequest.getPwmResponse().forwardToSuccessPage(Message.Success_PasswordSend, toAddress);
-        } catch (PwmException e) {
-            LOGGER.warn(pwmSession,"unexpected error setting new password during recovery process for user: " + e.getMessage());
-            pwmRequest.respondWithError(e.getErrorInformation());
-        } catch (ChaiOperationException e) {
-            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,"unexpected ldap error while processing recovery action " + recoveryAction + ", error: " + e.getMessage());
-            LOGGER.warn(pwmSession,errorInformation.toDebugStr());
-            pwmRequest.respondWithError(errorInformation);
-        } finally {
-            clearForgottenPasswordBean(pwmRequest);
-            pwmSession.unauthenticateUser(pwmRequest);
-            pwmSession.getSessionStateBean().setPasswordModified(false);
-        }
-    }
-
-
     private static List<FormConfiguration> figureAttributeForm(
             final ForgottenPasswordProfile forgottenPasswordProfile,
             final ForgottenPasswordBean forgottenPasswordBean,
@@ -1126,7 +1041,7 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet {
         return returnList;
     }
 
-    private static void addPostChangeAction(
+    static void addPostChangeAction(
             final PwmRequest pwmRequest,
             final UserIdentity userIdentity
     )

+ 114 - 0
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordUtil.java

@@ -26,6 +26,8 @@ import com.novell.ldapchai.ChaiUser;
 import com.novell.ldapchai.cr.Challenge;
 import com.novell.ldapchai.cr.ChallengeSet;
 import com.novell.ldapchai.cr.ResponseSet;
+import com.novell.ldapchai.exception.ChaiException;
+import com.novell.ldapchai.exception.ChaiOperationException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.exception.ChaiValidationException;
 import password.pwm.AppProperty;
@@ -43,18 +45,25 @@ import password.pwm.config.profile.ForgottenPasswordProfile;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
+import password.pwm.error.PwmException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.bean.ForgottenPasswordBean;
 import password.pwm.http.filter.AuthenticationFilter;
+import password.pwm.i18n.Message;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfoFactory;
+import password.pwm.svc.event.AuditEvent;
+import password.pwm.svc.event.AuditRecord;
+import password.pwm.svc.event.AuditRecordFactory;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.svc.token.TokenPayload;
 import password.pwm.svc.token.TokenService;
 import password.pwm.svc.token.TokenType;
+import password.pwm.util.PasswordData;
+import password.pwm.util.RandomPasswordGenerator;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
@@ -488,4 +497,109 @@ class ForgottenPasswordUtil {
         return displayDestAddress;
     }
 
+    static void doActionSendNewPassword( final PwmRequest pwmRequest)
+            throws ChaiUnavailableException, IOException, ServletException, PwmUnrecoverableException
+    {
+        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
+        final ForgottenPasswordBean forgottenPasswordBean = ForgottenPasswordServlet.forgottenPasswordBean(pwmRequest);
+        final ForgottenPasswordProfile forgottenPasswordProfile = ForgottenPasswordServlet.forgottenPasswordProfile(pwmRequest);
+        final RecoveryAction recoveryAction = ForgottenPasswordUtil.getRecoveryAction(pwmApplication.getConfig(), forgottenPasswordBean);
+
+        LOGGER.trace(pwmRequest,"beginning process to send new password to user");
+
+        if (!forgottenPasswordBean.getProgress().isAllPassed()) {
+            return;
+        }
+
+        final UserIdentity userIdentity = forgottenPasswordBean.getUserIdentity();
+        final ChaiUser theUser = pwmRequest.getPwmApplication().getProxiedChaiUser(userIdentity);
+
+        try {
+            // try unlocking user
+            theUser.unlockPassword();
+            LOGGER.trace(pwmRequest, "unlock account succeeded");
+        } catch (ChaiOperationException e) {
+            final String errorMsg = "unable to unlock user " + theUser.getEntryDN() + " error: " + e.getMessage();
+            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNLOCK_FAILURE,errorMsg);
+            LOGGER.error(pwmRequest.getPwmSession(), errorInformation.toDebugStr());
+            pwmRequest.respondWithError(errorInformation);
+            return;
+        }
+
+        try {
+            final UserInfo userInfo = UserInfoFactory.newUserInfoUsingProxy(
+                    pwmApplication,
+                    pwmRequest.getSessionLabel(),
+                    userIdentity,
+                    pwmRequest.getLocale()
+            );
+
+            LOGGER.info(pwmRequest, "user successfully supplied password recovery responses, emailing new password to: " + theUser.getEntryDN());
+
+            // add post change actions
+            ForgottenPasswordServlet.addPostChangeAction(pwmRequest, userIdentity);
+
+            // create new password
+            final PasswordData newPassword = RandomPasswordGenerator.createRandomPassword(
+                    pwmRequest.getSessionLabel(),
+                    userInfo.getPasswordPolicy(),
+                    pwmApplication
+            );
+            LOGGER.trace(pwmRequest, "generated random password value based on password policy for "
+                    + userIdentity.toDisplayString());
+
+
+            // set the password
+            try {
+                theUser.setPassword(newPassword.getStringValue());
+                LOGGER.trace(pwmRequest, "set user " + userIdentity.toDisplayString()
+                        + " password to system generated random value");
+            } catch (ChaiException e) {
+                throw PwmUnrecoverableException.fromChaiException(e);
+            }
+
+            if (recoveryAction == RecoveryAction.SENDNEWPW_AND_EXPIRE) {
+                LOGGER.debug(pwmRequest, "marking user " + userIdentity.toDisplayString() + " password as expired");
+                theUser.expirePassword();
+            }
+
+            // mark the event log
+            {
+                final AuditRecord auditRecord = new AuditRecordFactory(pwmApplication).createUserAuditRecord(
+                        AuditEvent.RECOVER_PASSWORD,
+                        userIdentity,
+                        pwmRequest.getSessionLabel()
+                );
+                pwmApplication.getAuditManager().submit(auditRecord);
+            }
+
+            final MessageSendMethod messageSendMethod = forgottenPasswordProfile.readSettingAsEnum(PwmSetting.RECOVERY_SENDNEWPW_METHOD,MessageSendMethod.class);
+
+            // send email or SMS
+            final String toAddress = PasswordUtility.sendNewPassword(
+                    userInfo,
+                    pwmApplication,
+                    newPassword,
+                    pwmRequest.getLocale(),
+                    messageSendMethod
+            );
+
+            pwmRequest.getPwmResponse().forwardToSuccessPage( Message.Success_PasswordSend, toAddress);
+        } catch (PwmException e) {
+            LOGGER.warn(pwmRequest, "unexpected error setting new password during recovery process for user: " + e.getMessage());
+            pwmRequest.respondWithError(e.getErrorInformation());
+        } catch (ChaiOperationException e) {
+            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,"unexpected ldap error while processing recovery action " + recoveryAction + ", error: " + e.getMessage());
+            LOGGER.warn(pwmRequest, errorInformation.toDebugStr());
+            pwmRequest.respondWithError(errorInformation);
+        } finally {
+            ForgottenPasswordServlet.clearForgottenPasswordBean(pwmRequest);
+
+            // the user should not be authenticated, this is a safety method
+            pwmRequest.getPwmSession().unauthenticateUser(pwmRequest);
+
+            // the password set flag should not have been set, this is a safety method
+            pwmRequest.getPwmSession().getSessionStateBean().setPasswordModified(false);
+        }
+    }
 }

+ 50 - 20
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java

@@ -34,15 +34,16 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.bean.UserIdentity;
-import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.config.Configuration;
-import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.option.HelpdeskClearResponseMode;
 import password.pwm.config.option.HelpdeskUIMode;
 import password.pwm.config.option.IdentityVerificationMethod;
 import password.pwm.config.option.MessageSendMethod;
 import password.pwm.config.profile.HelpdeskProfile;
+import password.pwm.config.profile.PwmPasswordPolicy;
+import password.pwm.config.value.data.ActionConfiguration;
+import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
@@ -739,17 +740,17 @@ public class HelpdeskServlet extends ControlledPwmServlet {
         try {
             TokenService.TokenSender.sendToken(
                     TokenService.TokenSendInfo.builder()
-                    .pwmApplication( pwmRequest.getPwmApplication() )
-                    .userInfo( userInfo )
-                    .macroMachine( macroMachine )
-                    .configuredEmailSetting( emailItemBean )
-                    .tokenSendMethod( tokenSendMethod )
-                    .emailAddress( destEmailAddress )
-                    .smsNumber( userInfo.getUserSmsNumber() )
-                    .smsMessage( smsMessage )
-                    .tokenKey( tokenKey )
-                    .sessionLabel( pwmRequest.getSessionLabel() )
-                    .build()
+                            .pwmApplication( pwmRequest.getPwmApplication() )
+                            .userInfo( userInfo )
+                            .macroMachine( macroMachine )
+                            .configuredEmailSetting( emailItemBean )
+                            .tokenSendMethod( tokenSendMethod )
+                            .emailAddress( destEmailAddress )
+                            .smsNumber( userInfo.getUserSmsNumber() )
+                            .smsMessage( smsMessage )
+                            .tokenKey( tokenKey )
+                            .sessionLabel( pwmRequest.getSessionLabel() )
+                            .build()
             );
         } catch (PwmException e) {
             LOGGER.error(pwmRequest, e.getErrorInformation());
@@ -1153,13 +1154,13 @@ public class HelpdeskServlet extends ControlledPwmServlet {
     @ActionHandler(action = "setPassword")
     private ProcessStatus processSetPasswordAction(final PwmRequest pwmRequest) throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     {
+        final HelpdeskProfile helpdeskProfile = pwmRequest.getPwmSession().getSessionManager().getHelpdeskProfile(pwmRequest.getPwmApplication());
+
         final RestSetPasswordServer.JsonInputData jsonInput = JsonUtil.deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 RestSetPasswordServer.JsonInputData.class
         );
 
-        final PasswordData newPassword = new PasswordData(jsonInput.getPassword());
-        final HelpdeskProfile helpdeskProfile = pwmRequest.getPwmSession().getSessionManager().getHelpdeskProfile(pwmRequest.getPwmApplication());
         final UserIdentity userIdentity = UserIdentity.fromKey(jsonInput.getUsername(),pwmRequest.getPwmApplication());
         final ChaiUser chaiUser = getChaiUser(pwmRequest, helpdeskProfile, userIdentity);
         final UserInfo userInfo = UserInfoFactory.newUserInfo(
@@ -1171,16 +1172,45 @@ public class HelpdeskServlet extends ControlledPwmServlet {
         );
 
         HelpdeskServletUtil.checkIfUserIdentityViewable(pwmRequest, helpdeskProfile, userIdentity);
+        final HelpdeskUIMode mode = helpdeskProfile.readSettingAsEnum(PwmSetting.HELPDESK_SET_PASSWORD_MODE, HelpdeskUIMode.class);
 
-        {
-            final HelpdeskUIMode mode = helpdeskProfile.readSettingAsEnum(PwmSetting.HELPDESK_CLEAR_RESPONSES, HelpdeskUIMode.class);
-            if (mode == HelpdeskUIMode.none) {
+        if (mode == HelpdeskUIMode.none) {
+            throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,"setting "
+                    + PwmSetting.HELPDESK_SET_PASSWORD_MODE.toMenuLocationDebug(helpdeskProfile.getIdentifier(), pwmRequest.getLocale())
+                    + " must not be set to none"));
+        }
+
+
+        final PasswordData newPassword;
+        if (jsonInput.getPassword() == null) {
+            if (mode != HelpdeskUIMode.random) {
                 throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,"setting "
-                        + PwmSetting.HELPDESK_CLEAR_RESPONSES.toMenuLocationDebug(helpdeskProfile.getIdentifier(), pwmRequest.getLocale())
-                        + " must not be set to none"));
+                        + PwmSetting.HELPDESK_SET_PASSWORD_MODE.toMenuLocationDebug(helpdeskProfile.getIdentifier(), pwmRequest.getLocale())
+                        + " is set to " + mode + " and no password is included in request"));
+            }
+            final PwmPasswordPolicy passwordPolicy = PasswordUtility.readPasswordPolicyForUser(
+                    pwmRequest.getPwmApplication(),
+                    pwmRequest.getSessionLabel(),
+                    userIdentity,
+                    chaiUser,
+                    pwmRequest.getLocale()
+            );
+            newPassword = RandomPasswordGenerator.createRandomPassword(
+                    pwmRequest.getSessionLabel(),
+                    passwordPolicy,
+                    pwmRequest.getPwmApplication()
+            );
+        } else {
+            if (mode == HelpdeskUIMode.random) {
+                throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_SECURITY_VIOLATION,"setting "
+                        + PwmSetting.HELPDESK_SET_PASSWORD_MODE.toMenuLocationDebug(helpdeskProfile.getIdentifier(), pwmRequest.getLocale())
+                        + " is set to autogen yet a password is included in request"));
             }
+
+            newPassword = new PasswordData(jsonInput.getPassword());
         }
 
+
         try {
             PasswordUtility.helpdeskSetUserPassword(
                     pwmRequest.getPwmSession(),

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

@@ -22,6 +22,9 @@
 
 package password.pwm.svc.event;
 
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 import org.graylog2.syslog4j.SyslogIF;
 import org.graylog2.syslog4j.impl.AbstractSyslogConfigIF;
 import org.graylog2.syslog4j.impl.AbstractSyslogWriter;
@@ -39,6 +42,7 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
+import password.pwm.config.option.SyslogOutputFormat;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
@@ -47,6 +51,7 @@ import password.pwm.health.HealthStatus;
 import password.pwm.health.HealthTopic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
+import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
@@ -79,23 +84,23 @@ public class SyslogAuditService {
     private SyslogIF syslogInstance = null;
     private ErrorInformation lastError = null;
     private List<X509Certificate> certificates = null;
-
     private WorkQueueProcessor<String> workQueueProcessor;
 
+    private List<SyslogIF> syslogInstances = new ArrayList<>();
 
     private final Configuration configuration;
     private final PwmApplication pwmApplication;
-    private List<SyslogIF> syslogInstances = new ArrayList<>();
+    private final SyslogOutputFormat syslogOutputFormat;
 
     public SyslogAuditService(final PwmApplication pwmApplication)
             throws LocalDBException
     {
+        syslogOutputFormat = pwmApplication.getConfig().readSettingAsEnum(PwmSetting.AUDIT_SYSLOG_OUTPUT_FORMAT, SyslogOutputFormat.class);
         this.pwmApplication = pwmApplication;
         this.configuration = pwmApplication.getConfig();
         this.certificates = configuration.readSettingAsCertificate(PwmSetting.AUDIT_SYSLOG_CERTIFICATES);
 
         final List<String> syslogConfigStringArray = configuration.readSettingAsStringArray(PwmSetting.AUDIT_SYSLOG_SERVERS);
-
         try {
             for(String entry : syslogConfigStringArray) {
                 final SyslogConfig syslogCfg = SyslogConfig.fromConfigString(entry);
@@ -130,6 +135,7 @@ public class SyslogAuditService {
         }
     }
 
+
     private SyslogIF makeSyslogInstance(final SyslogConfig syslogConfig)
     {
         final AbstractSyslogConfigIF syslogConfigIF;
@@ -174,11 +180,27 @@ public class SyslogAuditService {
     }
 
     public void add(final AuditRecord event) throws PwmOperationalException {
+
+        final String syslogMsg;
+
+        switch ( syslogOutputFormat ) {
+            case JSON:
+                syslogMsg = convertAuditRecordToSyslogMessage( event, configuration );
+                break;
+
+            case CEF:
+                syslogMsg = convertAuditRecordToCEFMessage( event, configuration );
+                break;
+
+            default:
+                JavaHelper.unhandledSwitchStatement( syslogOutputFormat );
+                throw new IllegalStateException(  );
+        }
+
         try {
-            final String syslogMsg = convertAuditRecordToSyslogMessage(event, configuration);
             workQueueProcessor.submit(syslogMsg);
         } catch (PwmOperationalException e) {
-            LOGGER.warn("unable to add email to queue: " + e.getMessage());
+            LOGGER.warn("unable to add syslog message to queue: " + e.getMessage());
         }
     }
 
@@ -220,17 +242,20 @@ public class SyslogAuditService {
         syslogInstance = null;
     }
 
+
+
     private static String convertAuditRecordToSyslogMessage(
             final AuditRecord auditRecord,
             final Configuration configuration
     )
     {
         final int maxLength = Integer.parseInt(configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_MAX_MESSAGE_LENGTH));
+        String jsonValue = "";
         final StringBuilder message = new StringBuilder();
         message.append(PwmConstants.PWM_APP_NAME);
         message.append(" ");
 
-        final String jsonValue = JsonUtil.serialize(auditRecord);
+        jsonValue = JsonUtil.serialize(auditRecord);
 
         if (message.length() + jsonValue.length() <= maxLength) {
             message.append(jsonValue);
@@ -273,6 +298,54 @@ public class SyslogAuditService {
         return message.toString();
     }
 
+    private static String convertAuditRecordToCEFMessage(final AuditRecord auditRecord, final Configuration configuration) {
+
+        final String recordType = auditRecord.getType().name();
+        String recordString = "";
+        String translatedString = "";
+        if ("USER".equalsIgnoreCase(recordType)) {
+            final UserAuditRecord cefRecord = new UserAuditRecord(auditRecord.timestamp, auditRecord.eventCode, null, null, null,
+                    auditRecord.message, null, null);
+            recordString = JsonUtil.serialize(cefRecord);
+        } else if ("SYSTEM".equalsIgnoreCase(recordType)) {
+            final SystemAuditRecord cefRecord = new SystemAuditRecord(auditRecord.eventCode, auditRecord.message, null);
+            recordString = JsonUtil.serialize(cefRecord);
+        } else if ("HELPDESK".equalsIgnoreCase(recordType)) {
+            final HelpdeskAuditRecord cefRecord = new HelpdeskAuditRecord(auditRecord.timestamp, auditRecord.eventCode, null, null, null,
+                    auditRecord.message, null, null, null, null, null);
+            recordString = JsonUtil.serialize(cefRecord);
+        } else {
+            recordString = JsonUtil.serialize(auditRecord);
+        }
+        recordString = recordString.replace("\"", "");
+        recordString = recordString.replace("\\", "");
+        recordString = recordString.replace("{", "");
+        recordString = recordString.replace("}", "");
+
+        recordString = recordString.replace("type:", " cat | ");
+        recordString = recordString.replace("eventCode:", " act | ");
+        recordString = recordString.replace("timestamp:", " rt | ");
+        recordString = recordString.replace("message:", " msg | ");
+        recordString = recordString.replace("narrative:", " reason | ");
+        recordString = recordString.replace("perpetratorID:", " suid | ");
+        recordString = recordString.replace("perpetratorDN:", " suser | ");
+        recordString = recordString.replace("sourceAddress:", " dvc | ");
+        recordString = recordString.replace("sourceHost:", " dvchost | ");
+        recordString = recordString.replace("targetID:", " duid | ");
+        recordString = recordString.replace("targetDN:", " duser | ");
+        recordString = recordString.replace("SSPR:", " sproc | ");
+        recordString = recordString.replace("PWM:", " sproc | ");
+
+        translatedString = auditRecord.getTimestamp().toString();
+        translatedString = translatedString.concat(" host CEF:0 | security | threatmanager | 1.0 | 100 ");
+        recordString = recordString.replace(",", " ");
+
+        translatedString = translatedString.concat(recordString);
+        return (translatedString);
+    }
+
+    @Getter
+    @AllArgsConstructor(access = AccessLevel.PRIVATE)
     public static class SyslogConfig implements Serializable {
         public enum Protocol { sslTcp, tcp, udp, tls }
 
@@ -280,24 +353,6 @@ public class SyslogAuditService {
         private String host;
         private int port;
 
-        public SyslogConfig(final Protocol protocol, final String host, final int port) {
-            this.protocol = protocol;
-            this.host = host;
-            this.port = port;
-        }
-
-        public Protocol getProtocol() {
-            return protocol;
-        }
-
-        public String getHost() {
-            return host;
-        }
-
-        public int getPort() {
-            return port;
-        }
-
         public static SyslogConfig fromConfigString(final String input) throws IllegalArgumentException {
             if (input == null) {
                 throw new IllegalArgumentException("input cannot be null");

+ 9 - 5
server/src/main/java/password/pwm/util/operations/PasswordUtility.java

@@ -109,7 +109,6 @@ public class PasswordUtility {
     public static String sendNewPassword(
             final UserInfo userInfo,
             final PwmApplication pwmApplication,
-            final MacroMachine macroMachine,
             final PasswordData newPassword,
             final Locale userLocale,
             final MessageSendMethod messageSendMethod
@@ -120,6 +119,15 @@ public class PasswordUtility {
         final String smsNumber = userInfo.getUserSmsNumber();
         String returnToAddress = emailAddress;
 
+        final MacroMachine macroMachine;
+        {
+            final LoginInfoBean loginInfoBean = new LoginInfoBean();
+            loginInfoBean.setUserCurrentPassword(newPassword);
+            loginInfoBean.setUserIdentity(userInfo.getUserIdentity());
+            macroMachine = MacroMachine.forUser(pwmApplication, null, userInfo, loginInfoBean);
+        }
+
+
         final ErrorInformation error;
         switch (messageSendMethod) {
             case SMSONLY:
@@ -532,13 +540,9 @@ public class PasswordUtility {
                 messageSendMethod = forgottenPasswordProfile.readSettingAsEnum(PwmSetting.RECOVERY_SENDNEWPW_METHOD, MessageSendMethod.class);
 
             }
-            final LoginInfoBean loginInfoBean = new LoginInfoBean();
-            loginInfoBean.setUserCurrentPassword(newPassword);
-            final MacroMachine macroMachine = new MacroMachine(pwmApplication, pwmSession.getLabel(), userInfo, loginInfoBean);
             PasswordUtility.sendNewPassword(
                     userInfo,
                     pwmApplication,
-                    macroMachine,
                     newPassword,
                     pwmSession.getSessionStateBean().getLocale(),
                     messageSendMethod

+ 108 - 21
server/src/main/java/password/pwm/util/queue/EmailQueueManager.java

@@ -27,9 +27,12 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmApplicationMode;
 import password.pwm.PwmConstants;
 import password.pwm.bean.EmailItemBean;
+import password.pwm.bean.pub.EmailServerBean;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
+import password.pwm.config.StoredValue;
 import password.pwm.config.option.DataStorageMethod;
+import password.pwm.config.stored.StoredConfiguration;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
@@ -82,6 +85,8 @@ public class EmailQueueManager implements PwmService {
     private static final PwmLogger LOGGER = PwmLogger.forClass(EmailQueueManager.class);
 
     private PwmApplication pwmApplication;
+    private List<EmailServerBean> emailServers = new ArrayList<EmailServerBean>();
+    private static List<EmailServerBean> staticEmailServers = new ArrayList<EmailServerBean>();
     private Properties javaMailProps = new Properties();
     private WorkQueueProcessor<EmailItemBean> workQueueProcessor;
 
@@ -96,6 +101,62 @@ public class EmailQueueManager implements PwmService {
         status = STATUS.OPENING;
         this.pwmApplication = pwmApplication;
         javaMailProps = makeJavaMailProps(pwmApplication.getConfig());
+        String hostAddress = "";
+        String emailFromAddress = "";
+        String emailUsername = "";
+        PasswordData emailPassword = null;
+        int hostPort = 0;
+        boolean allAvailable = true;
+
+        final List<String> profiles = pwmApplication.getConfig().readSettingAsStringArray(PwmSetting.EMAIL_PROFILES);
+
+        try {
+            final StoredConfiguration storedConfiguration = pwmApplication.getConfig().getStoredConfiguration();
+
+            for (int i = 0; i < profiles.size(); i++) {
+                final String profileName = profiles.get(i);
+                final StoredValue address = storedConfiguration.readSetting(PwmSetting.EMAIL_SERVER_ADDRESSES, profileName);
+                if (null != address) {
+                    hostAddress = address.toString();
+                } else {
+                    allAvailable = false;
+                }
+                final StoredValue port = storedConfiguration.readSetting(PwmSetting.EMAIL_SERVER_PORTS, profileName);
+                if (null != port) {
+                    hostPort = Integer.parseInt(port.toString());
+                } else {
+                    allAvailable = false;
+                }
+                LOGGER.debug("Port value: " + port.toString());
+                final StoredValue fromAddress = storedConfiguration.readSetting(PwmSetting.EMAIL_DEFAULT_FROM_ADDRESSES, profileName);
+                if (null != fromAddress) {
+                    emailFromAddress = fromAddress.toString();
+                } else {
+                    allAvailable = false;
+                }
+                final StoredValue username = storedConfiguration.readSetting(PwmSetting.EMAIL_USERNAMES, profileName);
+                if (null != username) {
+                    emailUsername = username.toString();
+                } else {
+                    allAvailable = false;
+                }
+                final StoredValue mailPassword = storedConfiguration.readSetting(PwmSetting.EMAIL_PASSWORDS, profileName);
+                if (null != mailPassword) {
+                    emailPassword = Configuration.JavaTypeConverter.valueToPassword(mailPassword);
+                } else {
+                    allAvailable = false;
+                }
+                if (allAvailable) {
+                    final EmailServerBean emailServerBean = new EmailServerBean(hostAddress, hostPort, emailFromAddress, emailUsername, emailPassword, false);
+                    emailServers.add(emailServerBean);
+                }
+            }
+            staticEmailServers = emailServers;
+        } catch (PwmUnrecoverableException ure) {
+
+
+        }
+
 
         if (pwmApplication.getLocalDB() == null || pwmApplication.getLocalDB().status() != LocalDB.Status.OPEN) {
             LOGGER.warn("localdb is not open, EmailQueueManager will remain closed");
@@ -180,11 +241,17 @@ public class EmailQueueManager implements PwmService {
     }
 
     private boolean determineIfItemCanBeDelivered(final EmailItemBean emailItem) {
-        final String serverAddress = pwmApplication.getConfig().readSettingAsString(PwmSetting.EMAIL_SERVER_ADDRESS);
 
-        if (serverAddress == null || serverAddress.length() < 1) {
-            LOGGER.debug("discarding email send event (no SMTP server address configured) " + emailItem.toDebugString());
-            return false;
+        String serverAddress = "";
+
+        for (int i = 0; i < emailServers.size(); i++) {
+            serverAddress = emailServers.get(i).getServerAddress();
+            if (serverAddress == null || serverAddress.length() < 1) {
+                LOGGER.debug("discarding email send event (no SMTP server address configured) " + emailItem.toDebugString());
+                return false;
+            } else {
+                break;
+            }
         }
 
         if (emailItem.getFrom() == null || emailItem.getFrom().length() < 1) {
@@ -356,25 +423,41 @@ public class EmailQueueManager implements PwmService {
     private Transport getSmtpTransport()
             throws MessagingException, PwmUnrecoverableException
     {
-        final String mailUser = this.pwmApplication.getConfig().readSettingAsString(PwmSetting.EMAIL_USERNAME);
-        final PasswordData mailPassword = this.pwmApplication.getConfig().readSettingAsPassword(PwmSetting.EMAIL_PASSWORD);
-        final String mailhost = this.pwmApplication.getConfig().readSettingAsString(PwmSetting.EMAIL_SERVER_ADDRESS);
-        final int mailport = (int)this.pwmApplication.getConfig().readSettingAsLong(PwmSetting.EMAIL_SERVER_PORT);
+        Transport tr = null;
+        String mailHost;
+        int mailPort;
+        String mailUser;
+        PasswordData mailPassword;
+
+        for (int i = 0; i < emailServers.size(); i++) {
+            if (emailServers.get(i).isTried()) {
+                emailServers.get(i).setTried(false);
+                continue;
+            } else {
+                mailHost = emailServers.get(i).getServerAddress();
+                mailPort = emailServers.get(i).getPort();
+                mailUser = emailServers.get(i).getUsername();
+                mailPassword = emailServers.get(i).getPassword();
+                emailServers.get(i).setTried(true);
+            }
 
-        // Login to SMTP server first if both username and password is given
-        final javax.mail.Session session = javax.mail.Session.getInstance(javaMailProps, null);
-        final Transport tr = session.getTransport("smtp");
+            // Login to SMTP server first if both username and password is given
+            final javax.mail.Session session = javax.mail.Session.getInstance(javaMailProps, null);
+            tr = session.getTransport("smtp");
 
-        final boolean authenticated = !(mailUser == null || mailUser.length() < 1 || mailPassword == null);
+            final boolean authenticated = !(mailUser == null || mailUser.length() < 1 || mailPassword == null);
 
-        if (authenticated) {
-            // create a new Session object for the message
-            tr.connect(mailhost, mailport, mailUser, mailPassword.getStringValue());
-        } else {
-            tr.connect();
-        }
+            if (authenticated) {
+                // create a new Session object for the message
+                tr.connect(mailHost, mailPort, mailUser, mailPassword.getStringValue());
+            } else {
+                tr.connect();
+            }
 
-        LOGGER.debug("connected to " + mailhost + ":" + mailport + " " + (authenticated ? "(secure)" : "(plaintext)"));
+            LOGGER.debug("connected to " + mailHost + ":" + mailPort + " " + (authenticated ? "(secure)" : "(plaintext)"));
+            emailServers.get(i).setTried(false);
+            break;
+        }
         return tr;
     }
 
@@ -431,11 +514,15 @@ public class EmailQueueManager implements PwmService {
         //Create a properties item to start setting up the mail
         final Properties props = new Properties();
 
+        for (int i = 0; i < staticEmailServers.size(); i++) {
+            props.put("mail.smtp.host", staticEmailServers.get(i).getServerAddress());
+            props.put("mail.smtp.port",staticEmailServers.get(i).getPort());
+        }
         //Specify the desired SMTP server
-        props.put("mail.smtp.host", config.readSettingAsString(PwmSetting.EMAIL_SERVER_ADDRESS));
+        //props.put("mail.smtp.host", config.readSettingAsString(PwmSetting.EMAIL_SERVER_ADDRESS));
 
         //Specify SMTP server port
-        props.put("mail.smtp.port",(int)config.readSettingAsLong(PwmSetting.EMAIL_SERVER_PORT));
+        //props.put("mail.smtp.port",(int)config.readSettingAsLong(PwmSetting.EMAIL_SERVER_PORT));
 
         //Specify configured advanced settings.
         final Map<String, String> advancedSettingValues = StringUtil.convertStringListToNameValuePair(config.readSettingAsStringArray(PwmSetting.EMAIL_ADVANCED_SETTINGS), "=");

+ 11 - 0
server/src/main/resources/password/pwm/config/PwmSetting.xml

@@ -1679,6 +1679,15 @@
             <property key="Cert_ImportHandler">password.pwm.config.function.SyslogCertImportFunction</property>
         </properties>
     </setting>
+    <setting hidden="false" key="audit.syslog.outputFormat" level="1">
+        <default>
+            <value>JSON</value>
+        </default>
+        <options>
+            <option value="JSON">JSON</option>
+            <option value="CEF">CEF</option>
+        </options>
+    </setting>
     <setting hidden="false" key="token.storageMethod" level="1" required="true">
         <default>
             <value><![CDATA[STORE_CRYPTO]]></value>
@@ -2563,6 +2572,8 @@
             <value>{"name":"mail","minimumLength":1,"maximumLength":64,"type":"email","required":true,"confirmationRequired":false,"readonly":false,"labels":{"":"Email Address"},"regexErrors":{"":""},"description":{"":""},"selectOptions":{}}</value>
             <value>{"name":"sn","minimumLength":1,"maximumLength":64,"type":"text","required":true,"confirmationRequired":false,"readonly":false,"labels":{"":"Last Name"},"regexErrors":{"":""},"description":{"":""},"selectOptions":{}}</value>
         </default>
+        <option value="text">text</option>
+        <option value="password">password</option>
     </setting>
     <setting hidden="false" key="forgottenUsername.searchFilter" level="2">
         <default/>

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

@@ -48,8 +48,8 @@ Category_Description_EDIR_SETTINGS=NetIQ eDirectory specific settings.
 Category_Description_EMAIL=<p>Configuration settings for all sent emails.   The settings for the email body configuration are for both plaintext and HTML.  We encourage that for each configured setting and locale for the email body, that you configure both plaintext and HTML. @PwmAppName@ delivers the email in both formats and the email client can choose which to display.</p> <p>Email definitions might use macros.  For more information about macros, see the "View" menu "Show Macro Help".</p>
 Category_Description_EMAIL_SETTINGS=
 Category_Description_EMAIL_TEMPLATES=
-Category_Description_EMAIL_PROFILES=Multiple Email Settings
-#Categoty_Description_EMAIL_SETTING=Email settings
+Category_Description_EMAIL_PROFILES=Email Profile Settings
+Categoty_Description_EMAIL_SETTING=Email settings
 Category_Description_FORGOTTEN_USERNAME=Allows a user to search for a forgotten user name using a configurable search filter and attributes.
 Category_Description_GENERAL=General settings for the application.  Settings here control the functionality and behavior of the system overall.
 Category_Description_GUEST=Note\: The guest user registration module requires that the logged in user has sufficient permissions to create users and if so configured, to check for duplicate values.
@@ -144,7 +144,7 @@ Category_Label_EDIR_SETTINGS=eDirectory Settings
 Category_Label_EMAIL=Email
 Category_Label_EMAIL_SETTINGS=Email Settings
 Category_Label_EMAIL_TEMPLATES=Email Templates
-Category_Label_EMAIL_PROFILES=Multiple Email Server Settings
+Category_Label_EMAIL_PROFILES=Email Profile Settings
 #Category_Label_EMAIL_SETTING=Email Settings
 Category_Label_FORGOTTEN_USERNAME=Forgotten User Name
 Category_Label_GENERAL=Application
@@ -224,6 +224,7 @@ Setting_Description_activateUser.writePostAttributes=Add actions @PwmAppName@ ex
 Setting_Description_activateUser.writePreAttributes=Add actions @PwmAppName@ executes after it activates the users but before it sets the password.  Typically, use this to activate the account, as well as add some searchable indicator.<br/><br/>  You can use macros.
 Setting_Description_audit.syslog.certificates=Import the TLS Certificate of syslog service.
 Setting_Description_audit.syslog.servers=Specify one or more entries of the connection information for the syslog audit servers. When configured, @PwmAppName@ forwards all audit events to the specified syslog server entered as the first entry. If the first one fails then the others will be tried until there is a successful delivery. The format is <b>&lt;protocol&gt;</b>,<b>&lt;address&gt;</b>,<b>&lt;port&gt;</b>.  The value for <b>&lt;protocol&gt;</b> can be either <\b>UDP</b>, <b>TCP</b> or <b>TLS</b>. We recommend that UDP is used in the list as the last option because UDP does not report a failure.<br/><br/>Examples\:<table><tr><td>Protocol</td><td>Address</td><td>Port</td><td>Setting</td><tr><tr><td>UDP</td><td>127.0.0.1</td><td>514</td><td>udp,127.0.0.1,514</td><tr><tr><td>TCP</td><td>central-syslog.example.com</td><td>514</td><td>tcp,central-syslog.example.com,514</td><tr><tr><td>TLS</td><td>secure-syslog.example.com</td><td>6514</td><td>tls,central-syslog.example.com,6514</td><tr></table>
+Setting_Description_audit.syslog.outputFormat=Select a style for the syslog output syntax.  The default JSON syntax can be used for typical syslog servers.  The Common Event Format (CEF) can be used for CEF compatible audit servers. 
 Setting_Description_audit.system.eventList=Select system event types to record and act upon.
 Setting_Description_audit.user.eventList=Select user event types to record and act upon.
 Setting_Description_audit.userEvent.toAddress=Specify one or more email addresses that the system sends an email to when the User Audit events occur.
@@ -714,6 +715,7 @@ Setting_Label_activateUser.writePostAttributes=Post-Activation Actions (After Pa
 Setting_Label_activateUser.writePreAttributes=Activation Actions (Before Password Change)
 Setting_Label_audit.syslog.certificates=Syslog Audit Server Certificates
 Setting_Label_audit.syslog.servers=Syslog Audit Server
+Setting_Label_audit.syslog.outputFormat=Syslog Output Format
 Setting_Label_audit.system.eventList=System Audit Event Types
 Setting_Label_audit.user.eventList=User Audit Event Types
 Setting_Label_audit.userEvent.toAddress=User Audit Event Email Alerts