/* * JBoss, Home of Professional Open Source. * Copyright 2013, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.domain.management.security.auditlog; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.COMPOSITE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_RESOURCE_DESCRIPTION_OPERATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_RESOURCE_OPERATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STEPS; import java.io.File; import java.net.InetAddress; import java.util.List; import java.util.regex.Pattern; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.audit.SyslogAuditLogHandler.MessageTransfer; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.operations.common.Util; import org.jboss.as.domain.management.audit.AuditLogHandlerResourceDefinition; import org.jboss.as.domain.management.audit.AuditLogLoggerResourceDefinition; import org.jboss.as.domain.management.audit.FileAuditLogHandlerResourceDefinition; import org.jboss.as.domain.management.audit.JsonAuditLogFormatterResourceDefinition; import org.jboss.as.domain.management.audit.SyslogAuditLogHandlerResourceDefinition; import org.jboss.dmr.ModelNode; import org.jboss.logmanager.handlers.SyslogHandler.SyslogType; import org.junit.Assert; import org.junit.Test; /** * Don't use core-model test for this. It does not support runtime, and more importantly for backwards compatibility the audit logger cannot be used * * @author Kabir Khan */ public class AuditLogHandlerBootEnabledTestCase extends AbstractAuditLogHandlerTestCase { public AuditLogHandlerBootEnabledTestCase() { super(true, true); } @Test public void testAuditLoggerBootUp() throws Exception { File file = new File(logDir, "test-file.log"); List<ModelNode> bootRecords = readFile(file, 1); ModelNode bootRecord = bootRecords.get(0); List<ModelNode> bootOps = checkBootRecordHeader(bootRecord, 5, "core", false, true, true); for (int i = 0 ; i < 5 ; i++) { checkOpsEqual(bootOperations.get(i), bootOps.get(i)); } } @Test public void testCannotRemoveReferencedHandler() throws Exception { File file = new File(logDir, "test-file.log"); ModelNode op = createRemoveFileHandlerOperation("file"); executeForFailure(op); List<ModelNode> records = readFile(file, 2); //TODO This gets picked up as read-only since it did not actually get around to modifying the model List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", true, false, false); checkOpsEqual(op, ops.get(0)); } @Test public void testCanRemoveLoggerReference() throws Exception { File file = new File(logDir, "test-file.log"); ModelNode op = createRemoveHandlerReferenceOperation("test-file"); executeForResult(op); List<ModelNode> records = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); } @Test public void testCannotRemoveReferencedFormatter() throws Exception { File file = new File(logDir, "test-file.log"); ModelNode op = createRemoveJsonFormatterOperation("test-formatter"); executeForFailure(op); List<ModelNode> records = readFile(file, 2); //TODO This gets picked up as read-only since it did not actually get around to modifying the model List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", true, false, false); checkOpsEqual(op, ops.get(0)); op = createRemoveHandlerReferenceOperation("test-file"); executeForResult(op); records = readFile(file, 3); ops = checkBootRecordHeader(records.get(2), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createRemoveFileHandlerOperation("test-file"); executeForResult(op); readFile(file, 3); op = createRemoveJsonFormatterOperation("test-formatter"); executeForResult(op); readFile(file, 3); } @Test public void testDisableAndEnableAuditLogger() throws Exception { File file = new File(logDir, "test-file.log"); readFile(file, 1); ModelNode op = createAuditLogWriteAttributeOperation(AuditLogLoggerResourceDefinition.ENABLED.getName(), false); executeForResult(op); List<ModelNode> records = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = Util.createOperation(READ_RESOURCE_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); readFile(file, 2); op = createAuditLogWriteAttributeOperation(AuditLogLoggerResourceDefinition.ENABLED.getName(), false); executeForResult(op); readFile(file, 2); op = createAuditLogWriteAttributeOperation(AuditLogLoggerResourceDefinition.ENABLED.getName(), true); executeForResult(op); records = readFile(file, 3); ops = checkBootRecordHeader(records.get(2), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = Util.createOperation(READ_RESOURCE_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); records = readFile(file, 4); ops = checkBootRecordHeader(records.get(3), 1, "core", true, false, true); checkOpsEqual(op, ops.get(0)); } @Test public void testToggleReadOnly() throws Exception { File file = new File(logDir, "test-file.log"); readFile(file, 1); ModelNode op = createAuditLogWriteAttributeOperation(AuditLogLoggerResourceDefinition.LOG_READ_ONLY.getName(), false); executeForResult(op); List<ModelNode> records = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = Util.createOperation(READ_RESOURCE_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); readFile(file, 2); op = createAuditLogWriteAttributeOperation(AuditLogLoggerResourceDefinition.LOG_READ_ONLY.getName(), true); executeForResult(op); records = readFile(file, 3); ops = checkBootRecordHeader(records.get(2), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = Util.createOperation(READ_RESOURCE_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); records = readFile(file, 4); ops = checkBootRecordHeader(records.get(3), 1, "core", true, false, true); checkOpsEqual(op, ops.get(0)); } @Test public void testCannotAddHandlerWithSameName() throws Exception { File file = new File(logDir, "test-file.log"); ModelNode op = createAddFileHandlerOperation("test-file", "test-formatter", "fail.log"); executeForFailure(op); List<ModelNode> records = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", false, false, false); checkOpsEqual(op, ops.get(0)); op = createAddSyslogHandlerTcpOperation("test-file", "test-formatter", InetAddress.getByName("localhost"), SYSLOG_PORT, null, MessageTransfer.OCTET_COUNTING); executeForFailure(op); records = readFile(file, 3); ops = checkBootRecordHeader(records.get(2), 1, "core", false, false, false); checkOpsEqual(op, ops.get(0)); op = createAddSizeRotatingFileHandlerOperation("test-file", "test-formatter", "fail.log", "10m", 1); executeForFailure(op); records = readFile(file, 4); ops = checkBootRecordHeader(records.get(3), 1, "core", false, false, false); checkOpsEqual(op, ops.get(0)); op = createAddPeriodicRotatingFileHandlerOperation("test-file", "test-formatter", "fail.log", ".yyyy-MM-dd-hh"); executeForFailure(op); records = readFile(file, 5); ops = checkBootRecordHeader(records.get(4), 1, "core", false, false, false); checkOpsEqual(op, ops.get(0)); } @Test public void testAddNonExistingHandlerReference() throws Exception { File file = new File(logDir, "test-file.log"); ModelNode op = createAddHandlerReferenceOperation("notthere"); executeForFailure(op); List<ModelNode> records = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records.get(1), 1, "core", false, false, false); checkOpsEqual(op, ops.get(0)); } @Test public void testSyslogUdp() throws Exception { SimpleSyslogServer server = SimpleSyslogServer.createUdp(6666); runSyslogTest(server, 6666, createAddSyslogHandlerUdpOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, 0)); } @Test public void testSyslogTcpOctetCounting() throws Exception { SimpleSyslogServer server = SimpleSyslogServer.createTcp(6666, true); runSyslogTest(server, 6666, createAddSyslogHandlerTcpOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.OCTET_COUNTING)); } @Test public void testSyslogTcpNonTransparentFraming() throws Exception { SimpleSyslogServer server = SimpleSyslogServer.createTcp(6666, false); runSyslogTest(server, 6666, createAddSyslogHandlerTcpOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.NON_TRANSPARENT_FRAMING)); } @Test public void testSyslogTlsOctetCounting() throws Exception { File serverCertStore = new File(getClass().getResource("server-cert-store.jks").toURI()); File clientTrustStore = new File(getClass().getResource("client-trust-store.jks").toURI()); SimpleSyslogServer server = SimpleSyslogServer.createTls(6666, true, serverCertStore, "changeit", null, null); runSyslogTest(server, 6666, createAddSyslogHandlerTlsOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.OCTET_COUNTING, clientTrustStore, "changeit", null, null)); } @Test public void testSyslogTlsNonTransparentFraming() throws Exception { File serverCertStore = new File(getClass().getResource("server-cert-store.jks").toURI()); File clientTrustStore = new File(getClass().getResource("client-trust-store.jks").toURI()); SimpleSyslogServer server = SimpleSyslogServer.createTls(6666, false, serverCertStore, "changeit", null, null); runSyslogTest(server, 6666, createAddSyslogHandlerTlsOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.NON_TRANSPARENT_FRAMING, clientTrustStore, "changeit", null, null)); } @Test public void testSyslogTlsOctetCountingClientAuth() throws Exception { File serverCertStore = new File(getClass().getResource("server-cert-store.jks").toURI()); File clientTrustStore = new File(getClass().getResource("client-trust-store.jks").toURI()); File clientCertStore = new File(getClass().getResource("client-cert-store.jks").toURI()); File serverTrustStore = new File(getClass().getResource("server-trust-store.jks").toURI()); SimpleSyslogServer server = SimpleSyslogServer.createTls(6666, true, serverCertStore, "changeit", serverTrustStore, "changeit"); runSyslogTest(server, 6666, createAddSyslogHandlerTlsOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.OCTET_COUNTING, clientTrustStore, "changeit", clientCertStore, "changeit")); } @Test public void testSyslogTlsNonTransparentFramingClientAuth() throws Exception { File serverCertStore = new File(getClass().getResource("server-cert-store.jks").toURI()); File clientTrustStore = new File(getClass().getResource("client-trust-store.jks").toURI()); File clientCertStore = new File(getClass().getResource("client-cert-store.jks").toURI()); File serverTrustStore = new File(getClass().getResource("server-trust-store.jks").toURI()); SimpleSyslogServer server = SimpleSyslogServer.createTls(6666, false, serverCertStore, "changeit", serverTrustStore, "changeit"); runSyslogTest(server, 6666, createAddSyslogHandlerTlsOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, MessageTransfer.NON_TRANSPARENT_FRAMING, clientTrustStore, "changeit", clientCertStore, "changeit")); } private void runSyslogTest(SimpleSyslogServer server, int port, ModelNode handlerAddOperation) throws Exception { try { File file = new File(logDir, "test-file.log"); executeForResult(handlerAddOperation); List<ModelNode> records1 = readFile(file, 2); List<ModelNode> ops = checkBootRecordHeader(records1.get(1), 1, "core", false, false, true); checkOpsEqual(handlerAddOperation, ops.get(0)); ModelNode op = createAddHandlerReferenceOperation("syslog-test"); executeForResult(op); records1 = readFile(file, 3); ops = checkBootRecordHeader(records1.get(2), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); byte[] receivedBytes = server.receiveData(); List<ModelNode> syslogOps = checkBootRecordHeader(getSyslogRecord(receivedBytes), 1, "core", false, false, true); Assert.assertEquals(ops, syslogOps); //TODO check syslog format and contents op = Util.createOperation(READ_RESOURCE_DESCRIPTION_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); records1 = readFile(file, 4); ops = checkBootRecordHeader(records1.get(3), 1, "core", true, false, true); checkOpsEqual(op, ops.get(0)); receivedBytes = server.receiveData(); syslogOps = checkBootRecordHeader(getSyslogRecord(receivedBytes), 1, "core", true, false, true); Assert.assertEquals(ops, syslogOps); //Make sure that removing the syslog handler it still gets logged op = createRemoveHandlerReferenceOperation("syslog-test"); executeForResult(op); records1 = readFile(file, 5); ops = checkBootRecordHeader(records1.get(4), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); receivedBytes = server.receiveData(); syslogOps = checkBootRecordHeader(getSyslogRecord(receivedBytes), 1, "core", false, false, true); Assert.assertEquals(ops, syslogOps); op = Util.createOperation(READ_RESOURCE_DESCRIPTION_OPERATION, PathAddress.EMPTY_ADDRESS); executeForResult(op); records1 = readFile(file, 6); ops = checkBootRecordHeader(records1.get(5), 1, "core", true, false, true); checkOpsEqual(op, ops.get(0)); //Should be nothing in syslog Assert.assertNull(server.pollData()); //TODO remove handler and check nothing in syslog and expected in file } finally { server.close(); } } @Test public void testAddRemoveFileAuditLogHandler() throws Exception { File file1 = new File(logDir, "test-file.log"); File file2 = new File(logDir, "test-file2.log"); Assert.assertFalse(file2.exists()); ModelNode op = createAddFileHandlerOperation("file2", "test-formatter", "test-file2.log"); executeForResult(op); Assert.assertFalse(file2.exists()); List<ModelNode> records1 = readFile(file1, 2); List<ModelNode> ops = checkBootRecordHeader(records1.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createAddHandlerReferenceOperation("file2"); executeForResult(op); records1 = readFile(file1, 3); List<ModelNode> records2 = readFile(file2, 1); Assert.assertEquals(records1.get(2), records2.get(0)); ops = checkBootRecordHeader(records1.get(2), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createRemoveHandlerReferenceOperation("test-file"); executeForResult(op); records1 = readFile(file1, 4); records2 = readFile(file2, 2); Assert.assertEquals(records1.get(3), records2.get(1)); ops = checkBootRecordHeader(records1.get(3), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); //The file handler was closed so it creates a new file op = createAddHandlerReferenceOperation("test-file"); executeForResult(op); records1 = readFile(file1, 1); records2 = readFile(file2, 3); Assert.assertEquals(records1.get(0), records2.get(2)); ops = checkBootRecordHeader(records1.get(0), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createRemoveHandlerReferenceOperation("test-file"); executeForResult(op); records1 = readFile(file1, 2); records2 = readFile(file2, 4); Assert.assertEquals(records1.get(1), records2.get(3)); ops = checkBootRecordHeader(records1.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createRemoveFileHandlerOperation("test-file"); executeForResult(op); records1 = readFile(file1, 2); records2 = readFile(file2, 5); ops = checkBootRecordHeader(records2.get(4), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); } @Test public void testAddRemoveSyslogAuditLogHandler() throws Exception { File file1 = new File(logDir, "test-file.log"); SimpleSyslogServer server = SimpleSyslogServer.createTcp(6666, false); try { ModelNode op = createAddSyslogHandlerTcpOperation("tcp", "test-formatter", InetAddress.getByName("localhost"), SYSLOG_PORT, null, null); executeForResult(op); List<ModelNode> records1 = readFile(file1, 2); List<ModelNode> ops = checkBootRecordHeader(records1.get(1), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); op = createAddHandlerReferenceOperation("tcp"); executeForResult(op); records1 = readFile(file1, 3); ops = checkBootRecordHeader(records1.get(2), 1, "core", false, false, true); ModelNode syslogOp = checkBootRecordHeader(getSyslogRecord(server.receiveData()), 1, "core", false, false, true).get(0); checkOpsEqual(op, syslogOp); Assert.assertEquals(syslogOp, ops.get(0)); op = createRemoveHandlerReferenceOperation("tcp"); executeForResult(op); records1 = readFile(file1, 4); ops = checkBootRecordHeader(records1.get(3), 1, "core", false, false, true); syslogOp = checkBootRecordHeader(getSyslogRecord(server.receiveData()), 1, "core", false, false, true).get(0); checkOpsEqual(op, syslogOp); Assert.assertEquals(syslogOp, ops.get(0)); } finally { //Close the dummy server since it only accepts one connection server.close(); } server = SimpleSyslogServer.createTcp(6666, false); try { ModelNode op = createAddHandlerReferenceOperation("tcp"); executeForResult(op); List<ModelNode> records1 = readFile(file1, 5); List<ModelNode> ops = checkBootRecordHeader(records1.get(4), 1, "core", false, false, true); ModelNode syslogOp = checkBootRecordHeader(getSyslogRecord(server.receiveData()), 1, "core", false, false, true).get(0); checkOpsEqual(op, syslogOp); Assert.assertEquals(syslogOp, ops.get(0)); op = createRemoveHandlerReferenceOperation("test-file"); executeForResult(op); records1 = readFile(file1, 6); //records2 = readFile(file2, 4); //Assert.assertEquals(records1.get(5), records2.get(3)); ops = checkBootRecordHeader(records1.get(5), 1, "core", false, false, true); checkOpsEqual(op, ops.get(0)); } finally { server.close(); } } @Test public void testMessageTransfer() throws Exception { SimpleSyslogServer server1 = SimpleSyslogServer.createUdp(SYSLOG_PORT); try { SimpleSyslogServer server2 = SimpleSyslogServer.createUdp(SYSLOG_PORT2); try { executeForResult(createAddSyslogHandlerUdpOperation("rfc-3164", "test-formatter", InetAddress.getByName("localhost"), SYSLOG_PORT, SyslogType.RFC3164, 5000)); executeForResult(createAddSyslogHandlerUdpOperation("rfc-5424", "test-formatter", InetAddress.getByName("localhost"), SYSLOG_PORT2, SyslogType.RFC5424, 5000)); ModelNode composite = new ModelNode(); composite.get(OP_ADDR).setEmptyList(); composite.get(OP).set(COMPOSITE); composite.get(STEPS).add(createAddHandlerReferenceOperation("rfc-3164")); composite.get(STEPS).add(createAddHandlerReferenceOperation("rfc-5424")); executeForResult(composite); byte[] bytes1 = server1.receiveData(); byte[] bytes2 = server2.receiveData(); //The RFC-5424 format is longer than the RFC-3164 format Assert.assertTrue(bytes2.length > bytes1.length); ModelNode op1 = checkBootRecordHeader(getSyslogRecord(bytes1), 1, "core", false, false, true).get(0); checkOpsEqual(composite, op1); ModelNode op2 = checkBootRecordHeader(getSyslogRecord(bytes2), 1, "core", false, false, true).get(0); Assert.assertEquals(op1, op2); } finally { server2.close(); } } finally { server1.close(); } } @Test public void testUpdateFileHandlerFormatter() throws Exception { //testUpdateSyslogHandlerFormatter Does the same for the syslog hander File file = new File(logDir, "test-file.log"); String fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d - \\{[\\s\\S]*", fullRecord)); //This regexp allows for new lines file.delete(); ModelNode op = Util.getWriteAttributeOperation(createFileHandlerAddress("test-file"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("non-existent")); executeForFailure(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d - \\{[\\s\\S]*", fullRecord)); //This regexp allows for new lines ModelNode record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); ModelNode loggedOp = checkBootRecordHeader(record, 1, "core", false, false, false).get(0); checkOpsEqual(op, loggedOp); //Add some new formatters op = Util.createAddOperation(createJsonFormatterAddress("compact-formatter")); op.get(JsonAuditLogFormatterResourceDefinition.COMPACT.getName()).set(true); op.get(JsonAuditLogFormatterResourceDefinition.DATE_FORMAT.getName()).set("yyyy/MM/dd HH-mm-ss"); op.get(JsonAuditLogFormatterResourceDefinition.DATE_SEPARATOR.getName()).set(" xxx "); executeForResult(op); op = Util.createAddOperation(createJsonFormatterAddress("escaped-formatter")); op.get(JsonAuditLogFormatterResourceDefinition.INCLUDE_DATE.getName()).set(false); op.get(JsonAuditLogFormatterResourceDefinition.ESCAPE_NEW_LINE.getName()).set(true); executeForResult(op); //Update the handler formatter to the compact version and check the logged format file.delete(); op = Util.getWriteAttributeOperation(createFileHandlerAddress("test-file"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("compact-formatter")); executeForResult(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d \\d\\d-\\d\\d-\\d\\d xxx \\{.*", fullRecord)); //This regexp checks for no new lines record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); //Update the handler formatter to the escaped version and check the logged format file.delete(); op = Util.getWriteAttributeOperation(createFileHandlerAddress("test-file"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("escaped-formatter")); executeForResult(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\{.*", fullRecord)); //This regexp checks for no new lines Assert.assertTrue(fullRecord.indexOf("#012") > 0); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{')).replace("#012", "")); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); //Check removing formatter in use fails file.delete(); op = Util.createRemoveOperation(createJsonFormatterAddress("escaped-formatter")); executeForFailure(op); //Check can remove unused formatter op = Util.createRemoveOperation(createJsonFormatterAddress("compact-formatter")); executeForResult(op); //Now try changing the used formatter at runtime file.delete(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.ESCAPE_NEW_LINE.getName(), new ModelNode(false)); executeForResult(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\{[\\s\\S]*", fullRecord)); //This regexp allows for new lines Assert.assertTrue(fullRecord.indexOf("#012") == -1); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); file.delete(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.COMPACT.getName(), new ModelNode(true)); executeForResult(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\{.*", fullRecord)); //This regexp allows for new lines Assert.assertTrue(fullRecord.indexOf("#012") == -1); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.INCLUDE_DATE.getName(), new ModelNode(true)); executeForResult(op); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.DATE_FORMAT.getName(), new ModelNode("yyyy/MM/dd HH-mm-ss")); executeForResult(op); file.delete(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.DATE_SEPARATOR.getName(), new ModelNode(" xxx ")); executeForResult(op); fullRecord = readFullFileRecord(file); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d \\d\\d-\\d\\d-\\d\\d xxx \\{.*", fullRecord)); //This regexp checks for no new lines record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); } @Test public void testUpdateSyslogHandlerFormatter() throws Exception { //testUpdateFileHandlerFormatter does the same for the file handler SimpleSyslogServer server = SimpleSyslogServer.createUdp(6666); try { //Set up the syslog handler ModelNode op = createAddSyslogHandlerUdpOperation("syslog-test", "test-formatter", InetAddress.getByName("localhost"), 6666, null, 0); executeForResult(op); op = createAddHandlerReferenceOperation("syslog-test"); executeForResult(op); byte[] bytes = server.receiveData(); op = Util.getWriteAttributeOperation(createFileHandlerAddress("test-file"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("non-existent")); executeForFailure(op); bytes = server.receiveData(); String fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d - \\{[\\s\\S]*", fullRecord)); //This regexp allows for new lines ModelNode record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); ModelNode loggedOp = checkBootRecordHeader(record, 1, "core", false, false, false).get(0); checkOpsEqual(op, loggedOp); //Add some new formatters op = Util.createAddOperation(createJsonFormatterAddress("compact-formatter")); op.get(JsonAuditLogFormatterResourceDefinition.COMPACT.getName()).set(true); op.get(JsonAuditLogFormatterResourceDefinition.DATE_FORMAT.getName()).set("yyyy/MM/dd HH-mm-ss"); op.get(JsonAuditLogFormatterResourceDefinition.DATE_SEPARATOR.getName()).set(" xxx "); executeForResult(op); bytes = server.receiveData(); op = Util.createAddOperation(createJsonFormatterAddress("escaped-formatter")); op.get(JsonAuditLogFormatterResourceDefinition.INCLUDE_DATE.getName()).set(false); op.get(JsonAuditLogFormatterResourceDefinition.ESCAPE_NEW_LINE.getName()).set(true); executeForResult(op); bytes = server.receiveData(); //Update the handler formatter to the compact version and check the logged format op = Util.getWriteAttributeOperation(createSyslogHandlerAddress("syslog-test"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("compact-formatter")); executeForResult(op); bytes = server.receiveData(); fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d \\d\\d-\\d\\d-\\d\\d xxx \\{.*", fullRecord)); //This regexp checks for no new lines record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); //Update the handler formatter to the escaped version and check the logged format op = Util.getWriteAttributeOperation(createSyslogHandlerAddress("syslog-test"), FileAuditLogHandlerResourceDefinition.FORMATTER.getName(), new ModelNode("escaped-formatter")); executeForResult(op); bytes = server.receiveData(); fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\{.*", fullRecord)); //This regexp checks for no new lines Assert.assertTrue(fullRecord.indexOf("#012") > 0); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{')).replace("#012", "")); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); //Check removing formatter in use fails op = Util.createRemoveOperation(createJsonFormatterAddress("escaped-formatter")); executeForFailure(op); bytes = server.receiveData(); //Check can remove unused formatter op = Util.createRemoveOperation(createJsonFormatterAddress("compact-formatter")); executeForResult(op); bytes = server.receiveData(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.ESCAPE_NEW_LINE.getName(), new ModelNode(false)); executeForResult(op); bytes = server.receiveData(); fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\{[\\s\\S]*", fullRecord)); //This regexp allows for new lines Assert.assertTrue(fullRecord.indexOf("#012") == -1); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.COMPACT.getName(), new ModelNode(true)); executeForResult(op); bytes = server.receiveData(); fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\{.*", fullRecord)); //This regexp allows for new lines Assert.assertTrue(fullRecord.indexOf("#012") == -1); record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.INCLUDE_DATE.getName(), new ModelNode(true)); executeForResult(op); bytes = server.receiveData(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.DATE_FORMAT.getName(), new ModelNode("yyyy/MM/dd HH-mm-ss")); executeForResult(op); bytes = server.receiveData(); op = Util.getWriteAttributeOperation(createJsonFormatterAddress("escaped-formatter"), JsonAuditLogFormatterResourceDefinition.DATE_SEPARATOR.getName(), new ModelNode(" xxx ")); executeForResult(op); bytes = server.receiveData(); fullRecord = stripSyslogHeader(bytes); Assert.assertTrue(Pattern.matches("\\d\\d\\d\\d/\\d\\d/\\d\\d \\d\\d-\\d\\d-\\d\\d xxx \\{.*", fullRecord)); //This regexp checks for no new lines record = ModelNode.fromJSONString(fullRecord.substring(fullRecord.indexOf('{'))); loggedOp = checkBootRecordHeader(record, 1, "core", false, false, true).get(0); checkOpsEqual(op, loggedOp); } finally { server.close(); } } @Test public void testRuntimeFailureMetricsAndRecycle() throws Exception { ModelNode op = createAddSyslogHandlerTcpOperation("syslog", "test-formatter", InetAddress.getByName("localhost"), SYSLOG_PORT, null, MessageTransfer.OCTET_COUNTING); op.get(STEPS).asList().get(0).get(SyslogAuditLogHandlerResourceDefinition.MAX_FAILURE_COUNT.getName()).set(2); executeForResult(op); final ModelNode readResource = Util.createOperation(READ_RESOURCE_OPERATION, AUDIT_ADDR); readResource.get(ModelDescriptionConstants.RECURSIVE).set(true); readResource.get(ModelDescriptionConstants.INCLUDE_RUNTIME).set(true); ModelNode result = executeForResult(readResource); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 0, false); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 0, false); //Delete the log directory so we start seeing failures in the file handler for (File file : logDir.listFiles()) { file.delete(); } logDir.delete(); executeForResult(createAddHandlerReferenceOperation("syslog")); result = executeForResult(readResource); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 1, false); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 1, false); result = executeForResult(readResource); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 2, false); //syslog handler has been disabled after 2 failures checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 2, true); result = executeForResult(readResource); //File handler is disabled after 3 failures checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 3, true); //syslog handler should still be disabled checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 2, true); //Install syslog server so it is up and running SimpleSyslogServer server = SimpleSyslogServer.createTcp(6666, true); try { //File handler should still be disabled checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 3, true); //syslog handler should still be disabled checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 2, true); //Recycle the syslog handler so it reconnects and resets the failure count executeForResult(Util.createOperation(ModelDescriptionConstants.RECYCLE, createSyslogHandlerAddress("syslog"))); server.receiveData(); //Create the logging directory logDir.mkdir(); result = executeForResult(readResource); server.receiveData(); //File handler should still be disabled checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 3, true); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 0, false); //Recycle the file handler so it resets the failure count and starts logging again executeForResult(Util.createOperation(ModelDescriptionConstants.RECYCLE, createFileHandlerAddress("test-file"))); server.receiveData(); File file = new File(logDir, "test-file.log"); Assert.assertTrue(file.exists()); result = executeForResult(readResource); server.receiveData(); //Both handlers should work again checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 3, 0, false); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 2, 0, false); //Recycle the file handler and make sure it gets backed up long fileSize = file.length(); Assert.assertEquals(1, logDir.listFiles().length); executeForResult(Util.createOperation(ModelDescriptionConstants.RECYCLE, createFileHandlerAddress("test-file"))); server.receiveData(); Assert.assertEquals(2, logDir.listFiles().length); for (File current : logDir.listFiles()) { if (current.getName().equals(file.getName())){ Assert.assertFalse(fileSize == current.length()); } else { Assert.assertEquals(fileSize, current.length()); } } //Finally just update the max failure counts and see that works op = Util.getWriteAttributeOperation(createFileHandlerAddress("test-file"), AuditLogHandlerResourceDefinition.MAX_FAILURE_COUNT.getName(), new ModelNode(7)); executeForResult(op); server.receiveData(); op = Util.getWriteAttributeOperation(createSyslogHandlerAddress("syslog"), AuditLogHandlerResourceDefinition.MAX_FAILURE_COUNT.getName(), new ModelNode(4)); executeForResult(op); server.receiveData(); result = executeForResult(readResource); server.receiveData(); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.FILE_HANDLER, "test-file"), 7, 0, false); checkHandlerRuntimeFailureMetrics(result.get(ModelDescriptionConstants.SYSLOG_HANDLER, "syslog"), 4, 0, false); } finally { server.close(); } } }