Ver código fonte

Merge remote-tracking branch 'origin/master'

Jason Rivard 7 anos atrás
pai
commit
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.servers", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.AUDIT_FORWARD),
     AUDIT_SYSLOG_CERTIFICATES(
     AUDIT_SYSLOG_CERTIFICATES(
             "audit.syslog.certificates", PwmSettingSyntax.X509CERT, PwmSettingCategory.AUDIT_FORWARD),
             "audit.syslog.certificates", PwmSettingSyntax.X509CERT, PwmSettingCategory.AUDIT_FORWARD),
-
+    AUDIT_SYSLOG_OUTPUT_FORMAT(
+            "audit.syslog.outputFormat", PwmSettingSyntax.SELECT, PwmSettingCategory.AUDIT_FORWARD),
 
 
     // challenge settings
     // challenge settings
     CHALLENGE_ENABLE(
     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;
 package password.pwm.svc.event;
 
 
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 import org.graylog2.syslog4j.SyslogIF;
 import org.graylog2.syslog4j.SyslogIF;
 import org.graylog2.syslog4j.impl.AbstractSyslogConfigIF;
 import org.graylog2.syslog4j.impl.AbstractSyslogConfigIF;
 import org.graylog2.syslog4j.impl.AbstractSyslogWriter;
 import org.graylog2.syslog4j.impl.AbstractSyslogWriter;
@@ -39,6 +42,7 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
+import password.pwm.config.option.SyslogOutputFormat;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
@@ -47,6 +51,7 @@ import password.pwm.health.HealthStatus;
 import password.pwm.health.HealthTopic;
 import password.pwm.health.HealthTopic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.svc.stats.StatisticsManager;
+import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDB;
@@ -79,23 +84,23 @@ public class SyslogAuditService {
     private SyslogIF syslogInstance = null;
     private SyslogIF syslogInstance = null;
     private ErrorInformation lastError = null;
     private ErrorInformation lastError = null;
     private List<X509Certificate> certificates = null;
     private List<X509Certificate> certificates = null;
-
     private WorkQueueProcessor<String> workQueueProcessor;
     private WorkQueueProcessor<String> workQueueProcessor;
 
 
+    private List<SyslogIF> syslogInstances = new ArrayList<>();
 
 
     private final Configuration configuration;
     private final Configuration configuration;
     private final PwmApplication pwmApplication;
     private final PwmApplication pwmApplication;
-    private List<SyslogIF> syslogInstances = new ArrayList<>();
+    private final SyslogOutputFormat syslogOutputFormat;
 
 
     public SyslogAuditService(final PwmApplication pwmApplication)
     public SyslogAuditService(final PwmApplication pwmApplication)
             throws LocalDBException
             throws LocalDBException
     {
     {
+        syslogOutputFormat = pwmApplication.getConfig().readSettingAsEnum(PwmSetting.AUDIT_SYSLOG_OUTPUT_FORMAT, SyslogOutputFormat.class);
         this.pwmApplication = pwmApplication;
         this.pwmApplication = pwmApplication;
         this.configuration = pwmApplication.getConfig();
         this.configuration = pwmApplication.getConfig();
         this.certificates = configuration.readSettingAsCertificate(PwmSetting.AUDIT_SYSLOG_CERTIFICATES);
         this.certificates = configuration.readSettingAsCertificate(PwmSetting.AUDIT_SYSLOG_CERTIFICATES);
 
 
         final List<String> syslogConfigStringArray = configuration.readSettingAsStringArray(PwmSetting.AUDIT_SYSLOG_SERVERS);
         final List<String> syslogConfigStringArray = configuration.readSettingAsStringArray(PwmSetting.AUDIT_SYSLOG_SERVERS);
-
         try {
         try {
             for(String entry : syslogConfigStringArray) {
             for(String entry : syslogConfigStringArray) {
                 final SyslogConfig syslogCfg = SyslogConfig.fromConfigString(entry);
                 final SyslogConfig syslogCfg = SyslogConfig.fromConfigString(entry);
@@ -130,6 +135,7 @@ public class SyslogAuditService {
         }
         }
     }
     }
 
 
+
     private SyslogIF makeSyslogInstance(final SyslogConfig syslogConfig)
     private SyslogIF makeSyslogInstance(final SyslogConfig syslogConfig)
     {
     {
         final AbstractSyslogConfigIF syslogConfigIF;
         final AbstractSyslogConfigIF syslogConfigIF;
@@ -174,11 +180,27 @@ public class SyslogAuditService {
     }
     }
 
 
     public void add(final AuditRecord event) throws PwmOperationalException {
     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 {
         try {
-            final String syslogMsg = convertAuditRecordToSyslogMessage(event, configuration);
             workQueueProcessor.submit(syslogMsg);
             workQueueProcessor.submit(syslogMsg);
         } catch (PwmOperationalException e) {
         } 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;
         syslogInstance = null;
     }
     }
 
 
+
+
     private static String convertAuditRecordToSyslogMessage(
     private static String convertAuditRecordToSyslogMessage(
             final AuditRecord auditRecord,
             final AuditRecord auditRecord,
             final Configuration configuration
             final Configuration configuration
     )
     )
     {
     {
         final int maxLength = Integer.parseInt(configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_MAX_MESSAGE_LENGTH));
         final int maxLength = Integer.parseInt(configuration.readAppProperty(AppProperty.AUDIT_SYSLOG_MAX_MESSAGE_LENGTH));
+        String jsonValue = "";
         final StringBuilder message = new StringBuilder();
         final StringBuilder message = new StringBuilder();
         message.append(PwmConstants.PWM_APP_NAME);
         message.append(PwmConstants.PWM_APP_NAME);
         message.append(" ");
         message.append(" ");
 
 
-        final String jsonValue = JsonUtil.serialize(auditRecord);
+        jsonValue = JsonUtil.serialize(auditRecord);
 
 
         if (message.length() + jsonValue.length() <= maxLength) {
         if (message.length() + jsonValue.length() <= maxLength) {
             message.append(jsonValue);
             message.append(jsonValue);
@@ -273,6 +298,54 @@ public class SyslogAuditService {
         return message.toString();
         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 static class SyslogConfig implements Serializable {
         public enum Protocol { sslTcp, tcp, udp, tls }
         public enum Protocol { sslTcp, tcp, udp, tls }
 
 
@@ -280,24 +353,6 @@ public class SyslogAuditService {
         private String host;
         private String host;
         private int port;
         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 {
         public static SyslogConfig fromConfigString(final String input) throws IllegalArgumentException {
             if (input == null) {
             if (input == null) {
                 throw new IllegalArgumentException("input cannot be 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>
             <property key="Cert_ImportHandler">password.pwm.config.function.SyslogCertImportFunction</property>
         </properties>
         </properties>
     </setting>
     </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">
     <setting hidden="false" key="token.storageMethod" level="1" required="true">
         <default>
         <default>
             <value><![CDATA[STORE_CRYPTO]]></value>
             <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_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.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.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.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.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.
 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_activateUser.writePreAttributes=Activation Actions (Before Password Change)
 Setting_Label_audit.syslog.certificates=Syslog Audit Server Certificates
 Setting_Label_audit.syslog.certificates=Syslog Audit Server Certificates
 Setting_Label_audit.syslog.servers=Syslog Audit Server
 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.system.eventList=System Audit Event Types
 Setting_Label_audit.user.eventList=User Audit Event Types
 Setting_Label_audit.user.eventList=User Audit Event Types
 Setting_Label_audit.userEvent.toAddress=User Audit Event Email Alerts
 Setting_Label_audit.userEvent.toAddress=User Audit Event Email Alerts