/*
* JBoss, Home of Professional Open Source
* Copyright 2014, JBoss Inc., and individual contributors as indicated
* by the @authors tag.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.test.manualmode.auditlog;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.AUTHENTICATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CORE_SERVICE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.LOCAL;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MANAGEMENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SECURITY_REALM;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.domain.management.CoreManagementResourceDefinition;
import org.jboss.as.domain.management.audit.AccessAuditResourceDefinition;
import org.jboss.as.domain.management.audit.AuditLogLoggerResourceDefinition;
import org.jboss.as.test.categories.CommonCriteria;
import org.jboss.as.test.integration.auditlog.AuditLogToSyslogSetup;
import org.jboss.as.test.integration.auditlog.AuditLogToUDPSyslogSetup;
import org.jboss.as.test.integration.security.common.CoreUtils;
import org.jboss.as.test.shared.TimeoutUtil;
import org.jboss.as.test.syslogserver.BlockedSyslogServerEventHandler;
import org.jboss.as.test.syslogserver.Rfc5424SyslogEvent;
import org.jboss.dmr.ModelNode;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.productivity.java.syslog4j.server.SyslogServerEventIF;
import org.wildfly.core.testrunner.ServerControl;
import org.wildfly.core.testrunner.ServerController;
import org.wildfly.core.testrunner.WildflyTestRunner;
import org.xnio.IoUtils;
/**
* Tests that fields of Audit log have right content.
*
* @author Ondrej Lukas
* @author Josef Cacek
*/
@RunWith(WildflyTestRunner.class)
@ServerControl(manual = true)
@Category(CommonCriteria.class)
public class AuditLogFieldsOfLogTestCase {
private final BlockingQueue<SyslogServerEventIF> queue = BlockedSyslogServerEventHandler.getQueue();
private static final AuditLogToUDPSyslogSetup SYSLOG_SETUP = new AuditLogToUDPSyslogSetup();
private final Pattern DATE_STAMP_PATTERN = Pattern.compile("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d - \\{");
@Inject
private ServerController container;
private File file;
private PathAddress auditLogConfigAddress;
private PathAddress mgmtRealmConfigAddress;
private PathAddress syslogHandlerAddress;
private PathAddress addSyslogHandler;
private static final int ADJUSTED_SECOND = TimeoutUtil.adjust(1000);
/**
* @test.objective Test whether fields in Audit Log have right content
* @test.expectedResult All asserts are correct and test finishes without any exception.
*/
@Test
public void testAuditLoggingFields() throws Exception {
container.start();
if (file.exists()) {
file.delete();
}
queue.clear();
SyslogServerEventIF syslogEvent = null;
Assert.assertTrue(makeOneLog());
syslogEvent = queue.poll(5 * ADJUSTED_SECOND, TimeUnit.MILLISECONDS);
Assert.assertNotNull("Event wasn't logged into the syslog", syslogEvent);
Rfc5424SyslogEvent event = (Rfc5424SyslogEvent) syslogEvent;
String message = event.getMessage();
Assert.assertNotNull("Message in the syslog event is empty", message);
message = DATE_STAMP_PATTERN.matcher(message).replaceFirst("{");
ModelNode syslogNode = ModelNode.fromJSONString(message);
checkLog("Syslog", syslogNode);
List<ModelNode> logs = readFile(file, 1);
ModelNode log = logs.get(0);
checkLog("File", log);
}
private void checkLog(String handler, ModelNode log) {
final String failMsg = "Unexpected value in " + handler;
Assert.assertEquals(failMsg, "core", log.get("type").asString());
Assert.assertEquals(failMsg, "false", log.get("r/o").asString());
Assert.assertEquals(failMsg, "false", log.get("booting").asString());
Assert.assertTrue(failMsg, log.get("version").isDefined());
Assert.assertEquals(failMsg, "IAmAdmin", log.get("user").asString());
Assert.assertFalse(failMsg, log.get("domainUUID").isDefined());
Assert.assertEquals(failMsg, "NATIVE", log.get("access").asString());
Assert.assertTrue(failMsg, log.get("remote-address").isDefined());
Assert.assertEquals(failMsg, "true", log.get("success").asString());
List<ModelNode> operations = log.get("ops").asList();
Assert.assertEquals(failMsg, 1, operations.size());
}
private boolean makeOneLog() throws IOException {
ModelNode op = Util.getWriteAttributeOperation(auditLogConfigAddress,
AuditLogLoggerResourceDefinition.LOG_BOOT.getName(), new ModelNode(true));
ModelNode result = container.getClient().getControllerClient().execute(op);
return SUCCESS.equals(result.get(OUTCOME).asString());
}
@Before
public void beforeTest() throws Exception {
file = new File(System.getProperty("jboss.home"));
file = new File(file, "standalone");
file = new File(file, "data");
file = new File(file, "audit-log.log");
if (file.exists()) {
file.delete();
}
container.start();
final ModelControllerClient client = container.getClient().getControllerClient();
ModelNode op;
ModelNode result;
mgmtRealmConfigAddress = PathAddress.pathAddress(PathElement.pathElement(CORE_SERVICE, MANAGEMENT),
PathElement.pathElement(SECURITY_REALM, "ManagementRealm"), PathElement.pathElement(AUTHENTICATION, LOCAL));
op = Util.getWriteAttributeOperation(mgmtRealmConfigAddress, "default-user", new ModelNode("IAmAdmin"));
result = client.execute(op);
auditLogConfigAddress = PathAddress.pathAddress(CoreManagementResourceDefinition.PATH_ELEMENT,
AccessAuditResourceDefinition.PATH_ELEMENT, AuditLogLoggerResourceDefinition.PATH_ELEMENT);
op = Util.getWriteAttributeOperation(auditLogConfigAddress, AuditLogLoggerResourceDefinition.ENABLED.getName(),
new ModelNode(true));
result = client.execute(op);
Assert.assertEquals(result.get("failure-description").asString(), SUCCESS, result.get(OUTCOME).asString());
SYSLOG_SETUP.setup(container.getClient());
op = Util.getWriteAttributeOperation(AuditLogToSyslogSetup.AUDIT_LOG_LOGGER_ADDR, ENABLED, true);
CoreUtils.applyUpdate(op, client);
container.stop();
}
@After
public void afterTest() throws Exception {
SYSLOG_SETUP.tearDown(container.getClient());
final ModelControllerClient client = container.getClient().getControllerClient();
ModelNode op = Util.getWriteAttributeOperation(auditLogConfigAddress,
AuditLogLoggerResourceDefinition.ENABLED.getName(), new ModelNode(false));
client.execute(op);
op = Util.getWriteAttributeOperation(mgmtRealmConfigAddress, "default-user", new ModelNode("$local"));
client.execute(op);
op = Util.getResourceRemoveOperation(addSyslogHandler);
client.execute(op);
op = Util.getResourceRemoveOperation(syslogHandlerAddress);
client.execute(op);
if (file.exists()) {
file.delete();
}
try {
// Stop the container
container.stop();
} finally {
IoUtils.safeClose(client);
}
}
protected List<ModelNode> readFile(File file, int expectedRecords) throws IOException {
List<ModelNode> list = new ArrayList<>();
final BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8);
try {
StringWriter writer = null;
String line = reader.readLine();
while (line != null) {
if (DATE_STAMP_PATTERN.matcher(line).find()) {
if (writer != null) {
list.add(ModelNode.fromJSONString(writer.getBuffer().toString()));
}
writer = new StringWriter();
writer.append("{");
} else {
if (writer != null) { writer.append("\n" + line); }
}
line = reader.readLine();
}
if (writer != null) {
list.add(ModelNode.fromJSONString(writer.getBuffer().toString()));
}
} finally {
IoUtils.safeClose(reader);
}
Assert.assertEquals(list.toString(), expectedRecords, list.size());
return list;
}
}