/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, 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.wildfly.test.integration.elytron.audit;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintWriter;
import java.net.URL;
import org.codehaus.plexus.util.FileUtils;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.test.integration.management.util.CLIWrapper;
import org.jboss.as.test.integration.security.common.Utils;
import org.jboss.as.test.shared.ServerReload;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.test.security.common.elytron.FileAuditLog;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.jboss.as.test.shared.CliUtils.asAbsolutePath;
import static org.junit.Assert.assertTrue;
import static org.wildfly.test.integration.elytron.audit.AbstractAuditLogTestCase.SD_WITHOUT_LOGIN_PERMISSION;
import static org.wildfly.test.integration.elytron.audit.AbstractAuditLogTestCase.setEventListenerOfApplicationDomain;
/**
* Test case for 'file-audit-log' Elytron subsystem resource.
*
* @author Jan Tymel
*/
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({AbstractAuditLogTestCase.SecurityDomainSetupTask.class, FileAuditLogTestCase.FileAuditLogSetupTask.class})
public class FileAuditLogTestCase extends AbstractAuditLogTestCase {
private static final String NAME = FileAuditLogTestCase.class.getSimpleName();
private static final String AUDIT_LOG_NAME = "test-audit.log";
private static final File WORK_DIR = new File("target" + File.separatorChar + NAME);
private static final File AUDIT_LOG_FILE = new File(WORK_DIR, AUDIT_LOG_NAME);
/**
* Tests whether successful authentication was logged.
*/
@Test
@OperateOnDeployment(SD_DEFAULT)
public void testSuccessfulAuth() throws Exception {
final URL servletUrl = new URL(url.toExternalForm() + "role1");
discardCurrentContents(AUDIT_LOG_FILE);
Utils.makeCallWithBasicAuthn(servletUrl, USER, PASSWORD, SC_OK);
assertTrue("Successful authentication was not logged", loggedSuccessfulAuth(AUDIT_LOG_FILE, USER));
}
/**
* Tests whether failed authentication was logged.
*/
@Test
@OperateOnDeployment(SD_DEFAULT)
public void testFailedAuth() throws Exception {
final URL servletUrl = new URL(url.toExternalForm() + "role1");
discardCurrentContents(AUDIT_LOG_FILE);
Utils.makeCallWithBasicAuthn(servletUrl, UNKNOWN_USER, PASSWORD, SC_UNAUTHORIZED);
assertTrue("Failed authentication was not logged", loggedFailedAuth(AUDIT_LOG_FILE, UNKNOWN_USER));
}
/**
* Tests whether authentication with empty username was logged.
*/
@Ignore("https://issues.jboss.org/browse/ELY-1171")
@Test
@OperateOnDeployment(SD_DEFAULT)
public void testAuthWithEmptyName() throws Exception {
final URL servletUrl = new URL(url.toExternalForm() + "role1");
discardCurrentContents(AUDIT_LOG_FILE);
Utils.makeCallWithBasicAuthn(servletUrl, "", PASSWORD, SC_UNAUTHORIZED);
assertTrue("Authentication with empty username was not logged", loggedFailedAuth(AUDIT_LOG_FILE, USER));
}
/**
* Tests whether successful permission check was logged.
*/
@Test
@OperateOnDeployment(SD_DEFAULT)
public void testSuccessfulPermissionCheck() throws Exception {
final URL servletUrl = new URL(url.toExternalForm() + "role1");
discardCurrentContents(AUDIT_LOG_FILE);
Utils.makeCallWithBasicAuthn(servletUrl, USER, PASSWORD, SC_OK);
assertTrue("Successful permission check was not logged", loggedSuccessfulPermissionCheck(AUDIT_LOG_FILE, USER));
}
/**
* Tests whether failed permission check was logged.
*/
@Test
@OperateOnDeployment(SD_WITHOUT_LOGIN_PERMISSION)
public void testFailedPermissionCheck() throws Exception {
final URL servletUrl = new URL(url.toExternalForm() + "role1");
discardCurrentContents(AUDIT_LOG_FILE);
Utils.makeCallWithBasicAuthn(servletUrl, USER, PASSWORD, SC_UNAUTHORIZED);
assertTrue("Failed permission check was not logged", loggedFailedPermissionCheck(AUDIT_LOG_FILE, USER));
}
/**
* Creates Elytron 'file-audit-log' and sets it as ApplicationDomain's security listener.
*/
static class FileAuditLogSetupTask implements ServerSetupTask {
FileAuditLog auditLog;
@Override
public void setup(ManagementClient managementClient, String string) throws Exception {
try (CLIWrapper cli = new CLIWrapper(true)) {
createEmptyDirectory(WORK_DIR);
auditLog = FileAuditLog.builder().withName(NAME)
.withPath(asAbsolutePath(AUDIT_LOG_FILE))
.build();
auditLog.create(cli);
setEventListenerOfApplicationDomain(cli, NAME);
}
ServerReload.reloadIfRequired(managementClient.getControllerClient());
}
@Override
public void tearDown(ManagementClient managementClient, String containerId) throws Exception {
try (CLIWrapper cli = new CLIWrapper(true)) {
setDefaultEventListenerOfApplicationDomain(cli);
auditLog.remove(cli);
FileUtils.deleteDirectory(WORK_DIR);
}
ServerReload.reloadIfRequired(managementClient.getControllerClient());
}
}
private static boolean loggedSuccessfulAuth(File file, String user) throws Exception {
return loggedAuthResult(file, user, SUCCESSFUL_AUTH_EVENT);
}
private static boolean loggedFailedAuth(File file, String user) throws Exception {
return loggedAuthResult(file, user, UNSUCCESSFUL_AUTH_EVENT);
}
private static boolean loggedSuccessfulPermissionCheck(File file, String user) throws Exception {
return loggedAuthResult(file, user, SUCCESSFUL_PERMISSION_CHECK_EVENT);
}
private static boolean loggedFailedPermissionCheck(File file, String user) throws Exception {
return loggedAuthResult(file, user, UNSUCCESSFUL_PERMISSION_CHECK_EVENT);
}
private static boolean loggedAuthResult(File file, String user, String expectedEvent) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(expectedEvent) && line.contains(user)) {
return true;
}
}
return false;
}
private static void discardCurrentContents(File file) throws Exception {
try (PrintWriter writer = new PrintWriter(file)) {
writer.print("");
}
}
private static void createEmptyDirectory(File workDir) throws Exception {
FileUtils.deleteDirectory(workDir);
workDir.mkdirs();
Assert.assertTrue(workDir.exists());
Assert.assertTrue(workDir.isDirectory());
}
}