瀏覽代碼

Merge remote-tracking branch 'origin/master'

Jason Rivard 7 年之前
父節點
當前提交
e412960e2f

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

@@ -665,7 +665,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(

+ 6 - 0
server/src/main/java/password/pwm/config/option/SyslogOutputFormat.java

@@ -0,0 +1,6 @@
+package password.pwm.config.option;
+
+public enum SyslogOutputFormat {
+    JSON,
+    CEF,
+}

+ 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 - 0
server/src/main/resources/password/pwm/config/PwmSetting.xml

@@ -1639,6 +1639,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>

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

@@ -220,6 +220,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.
@@ -702,6 +703,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