/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, Red Hat Middleware LLC, 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.web.test;
import static org.jboss.as.controller.capability.RuntimeCapability.buildDynamicCapabilityName;
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.EXTENSION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MANAGEMENT;
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.SECURITY_REALM;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TRUSTSTORE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import io.undertow.predicate.PredicateParser;
import io.undertow.server.handlers.builder.PredicatedHandlersParser;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationDefinition;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.ProcessType;
import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
import org.jboss.as.controller.RunningMode;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.access.management.DelegatingConfigurableAuthorizer;
import org.jboss.as.controller.access.management.ManagementSecurityIdentitySupplier;
import org.jboss.as.controller.capability.registry.RuntimeCapabilityRegistry;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
import org.jboss.as.controller.descriptions.common.ControllerResolver;
import org.jboss.as.controller.extension.ExtensionRegistry;
import org.jboss.as.controller.extension.ExtensionRegistryType;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.Resource;
import org.jboss.as.domain.management.CoreManagementResourceDefinition;
import org.jboss.as.domain.management.audit.EnvironmentNameReader;
import org.jboss.as.domain.management.security.KeystoreAttributes;
import org.jboss.as.network.SocketBinding;
import org.jboss.as.subsystem.test.AbstractSubsystemTest;
import org.jboss.as.subsystem.test.AdditionalInitialization;
import org.jboss.as.subsystem.test.ControllerInitializer;
import org.jboss.as.subsystem.test.KernelServices;
import org.jboss.as.web.WebExtension;
import org.jboss.dmr.ModelNode;
import org.junit.Test;
import org.wildfly.extension.io.IOExtension;
import org.wildfly.extension.undertow.Constants;
import org.wildfly.extension.undertow.UndertowExtension;
/**
* @author Stuart Douglas
*/
public class WebMigrateTestCase extends AbstractSubsystemTest {
public static final String UNDERTOW_SUBSYSTEM_NAME = "undertow";
public WebMigrateTestCase() {
super(WebExtension.SUBSYSTEM_NAME, new WebExtension());
}
@Test
public void testMigrateOperation() throws Exception {
String subsystemXml = readResource("subsystem-migrate-2.2.0.xml");
NewSubsystemAdditionalInitialization additionalInitialization = new NewSubsystemAdditionalInitialization();
KernelServices services = createKernelServicesBuilder(additionalInitialization).setSubsystemXml(subsystemXml).build();
ModelNode model = services.readWholeModel();
assertFalse(additionalInitialization.extensionAdded);
assertTrue(model.get(SUBSYSTEM, WebExtension.SUBSYSTEM_NAME).isDefined());
assertFalse(model.get(SUBSYSTEM, UNDERTOW_SUBSYSTEM_NAME).isDefined());
ModelNode migrateOp = new ModelNode();
migrateOp.get(OP).set("migrate");
migrateOp.get(OP_ADDR).add(SUBSYSTEM, WebExtension.SUBSYSTEM_NAME);
checkOutcome(services.executeOperation(migrateOp));
model = services.readWholeModel();
assertTrue(additionalInitialization.extensionAdded);
assertFalse(model.get(SUBSYSTEM, WebExtension.SUBSYSTEM_NAME).isDefined());
assertTrue(model.get(SUBSYSTEM, UNDERTOW_SUBSYSTEM_NAME).isDefined());
//make sure we have an IO subsystem
ModelNode ioSubsystem = model.get(SUBSYSTEM, "io");
assertTrue(ioSubsystem.isDefined());
assertTrue(ioSubsystem.get("worker", "default").isDefined());
assertTrue(ioSubsystem.get("buffer-pool", "default").isDefined());
ModelNode newSubsystem = model.get(SUBSYSTEM, UNDERTOW_SUBSYSTEM_NAME);
ModelNode newServer = newSubsystem.get("server", "default-server");
assertNotNull(newServer);
assertTrue(newServer.isDefined());
assertEquals("default-host", newServer.get(Constants.DEFAULT_HOST).asString());
//servlet container
ModelNode servletContainer = newSubsystem.get(Constants.SERVLET_CONTAINER, "default");
assertNotNull(servletContainer);
assertTrue(servletContainer.isDefined());
assertEquals("${prop.default-session-timeout:30}", servletContainer.get(Constants.DEFAULT_SESSION_TIMEOUT).asString());
assertEquals("${prop.listings:true}", servletContainer.get(Constants.DIRECTORY_LISTING).asString());
//jsp settings
ModelNode jsp = servletContainer.get(Constants.SETTING, Constants.JSP);
assertNotNull(jsp);
assertEquals("${prop.recompile-on-fail:true}", jsp.get(Constants.RECOMPILE_ON_FAIL).asString());
//welcome file
ModelNode welcome = servletContainer.get(Constants.WELCOME_FILE, "toto");
assertTrue(welcome.isDefined());
//mime mapping
ModelNode mimeMapping = servletContainer.get(Constants.MIME_MAPPING, "ogx");
assertTrue(mimeMapping.isDefined());
assertEquals("application/ogg", mimeMapping.get(Constants.VALUE).asString());
//http connector
ModelNode connector = newServer.get(Constants.HTTP_LISTENER, "http");
assertTrue(connector.isDefined());
assertEquals("http", connector.get(Constants.SOCKET_BINDING).asString());
assertEquals("${prop.enabled:true}", connector.get(Constants.ENABLED).asString());
assertEquals("${prop.enable-lookups:false}", connector.get(Constants.RESOLVE_PEER_ADDRESS).asString());
assertEquals("${prop.max-post-size:2097153}", connector.get(Constants.MAX_POST_SIZE).asString());
assertEquals("https", connector.get(Constants.REDIRECT_SOCKET).asString());
//https connector
ModelNode httpsConnector = newServer.get(Constants.HTTPS_LISTENER, "https");
String realmName = httpsConnector.get(Constants.SECURITY_REALM).asString();
assertTrue(realmName, realmName.startsWith("jbossweb-migration-security-realm"));
assertEquals("${prop.session-cache-size:512}", httpsConnector.get(Constants.SSL_SESSION_CACHE_SIZE).asString());
assertEquals("REQUESTED", httpsConnector.get(Constants.VERIFY_CLIENT).asString());
//realm name is dynamic
ModelNode realm = model.get(CORE_SERVICE, MANAGEMENT).get(SECURITY_REALM, realmName);
//trust store
ModelNode trustStore = realm.get(AUTHENTICATION, TRUSTSTORE);
assertEquals("${file-base}/jsse.keystore", trustStore.get(KeystoreAttributes.KEYSTORE_PATH.getName()).asString());
//Valves
ModelNode filters = newSubsystem.get(Constants.CONFIGURATION, Constants.FILTER);
ModelNode dumpFilter = filters.get("expression-filter", "request-dumper");
assertEquals("dump-request", dumpFilter.get("expression").asString());
validateExpressionFilter(dumpFilter);
ModelNode remoteAddrFilter = filters.get("expression-filter", "remote-addr");
assertEquals("access-control(acl={'192.168.1.20 deny', '127.0.0.1 allow', '127.0.0.2 allow'} , attribute=%a)", remoteAddrFilter.get("expression").asString());
validateExpressionFilter(remoteAddrFilter);
ModelNode stuckFilter = filters.get("expression-filter", "stuck");
assertEquals("stuck-thread-detector(threshhold='1000')", stuckFilter.get("expression").asString());
validateExpressionFilter(stuckFilter);
ModelNode proxyFilter = filters.get("expression-filter", "proxy");
assertEquals("regex(pattern=\"proxy1|proxy2\", value=%{i,x-forwarded-for}, full-match=true) and regex(pattern=\"192\\.168\\.0\\.10|192\\.168\\.0\\.11\", value=%{i,x-forwarded-for}, full-match=true) -> proxy-peer-address", proxyFilter.get("expression").asString());
validateExpressionFilter(proxyFilter);
ModelNode crawler = servletContainer.get(Constants.SETTING, Constants.CRAWLER_SESSION_MANAGEMENT);
assertTrue(crawler.isDefined());
assertEquals(1, crawler.get(Constants.SESSION_TIMEOUT).asInt());
assertEquals("Google", crawler.get(Constants.USER_AGENTS).asString());
//virtual host
ModelNode virtualHost = newServer.get(Constants.HOST, "default-host");
//welcome content
assertEquals("welcome-content", virtualHost.get("location", "/").get(Constants.HANDLER).asString());
assertEquals("localhost", virtualHost.get("alias").asList().get(0).asString());
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "request-dumper"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "remote-addr"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "proxy"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "stuck"));
assertFalse(virtualHost.hasDefined(Constants.FILTER_REF, "myvalve"));
ModelNode accessLog = virtualHost.get(Constants.SETTING, Constants.ACCESS_LOG);
assertEquals("prefix", accessLog.get(Constants.PREFIX).asString());
assertEquals("true", accessLog.get(Constants.ROTATE).asString());
assertEquals("extended", accessLog.get(Constants.PATTERN).asString());
assertEquals("toto", accessLog.get(Constants.DIRECTORY).asString());
assertEquals("jboss.server.base.dir", accessLog.get(Constants.RELATIVE_TO).asString());
//sso
ModelNode sso = virtualHost.get(Constants.SETTING, Constants.SINGLE_SIGN_ON);
assertEquals("${prop.domain:myDomain}", sso.get(Constants.DOMAIN).asString());
assertEquals("${prop.http-only:true}", sso.get(Constants.HTTP_ONLY).asString());
//global access log valve
virtualHost = newServer.get(Constants.HOST, "vs1");
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "request-dumper"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "remote-addr"));
assertFalse(virtualHost.hasDefined(Constants.FILTER_REF, "myvalve"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "proxy"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "stuck"));
accessLog = virtualHost.get(Constants.SETTING, Constants.ACCESS_LOG);
assertEquals("myapp_access_log.", accessLog.get(Constants.PREFIX).asString());
assertEquals(".log", accessLog.get(Constants.SUFFIX).asString());
assertEquals("true", accessLog.get(Constants.ROTATE).asString());
assertEquals("common", accessLog.get(Constants.PATTERN).asString());
assertEquals("${jboss.server.log.dir}", accessLog.get(Constants.DIRECTORY).asString());
assertEquals("exists(%{r,log-enabled})", accessLog.get(Constants.PREDICATE).asString());
//proxy valve
virtualHost = newServer.get(Constants.HOST, "vs1");
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "request-dumper"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "remote-addr"));
assertFalse(virtualHost.hasDefined(Constants.FILTER_REF, "myvalve"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "proxy"));
assertTrue(virtualHost.hasDefined(Constants.FILTER_REF, "stuck"));
assertEquals("myapp_access_log.", accessLog.get(Constants.PREFIX).asString());
assertEquals(".log", accessLog.get(Constants.SUFFIX).asString());
assertEquals("true", accessLog.get(Constants.ROTATE).asString());
assertEquals("common", accessLog.get(Constants.PATTERN).asString());
assertEquals("${jboss.server.log.dir}", accessLog.get(Constants.DIRECTORY).asString());
assertEquals("exists(%{r,log-enabled})", accessLog.get(Constants.PREDICATE).asString());
}
private void validateExpressionFilter(ModelNode filter) {
PredicatedHandlersParser.parse(filter.get("expression").asString(), PredicateParser.class.getClassLoader());
}
private static class NewSubsystemAdditionalInitialization extends AdditionalInitialization {
UndertowExtension undertow = new UndertowExtension();
IOExtension io = new IOExtension();
boolean extensionAdded = false;
@Override
protected void initializeExtraSubystemsAndModel(ExtensionRegistry extensionRegistry, Resource rootResource, ManagementResourceRegistration rootRegistration, RuntimeCapabilityRegistry capabilityRegistry) {
final OperationDefinition removeExtension = new SimpleOperationDefinitionBuilder("remove", new StandardResourceDescriptionResolver("test", "test", getClass().getClassLoader()))
.build();
PathElement webExtension = PathElement.pathElement(EXTENSION, "org.jboss.as.web");
rootRegistration.registerSubModel(new SimpleResourceDefinition(webExtension, ControllerResolver.getResolver(EXTENSION)))
.registerOperationHandler(removeExtension, new ReloadRequiredRemoveStepHandler());
rootResource.registerChild(webExtension, Resource.Factory.create());
rootRegistration.registerSubModel(new SimpleResourceDefinition(PathElement.pathElement(EXTENSION),
ControllerResolver.getResolver(EXTENSION), new OperationStepHandler() {
@Override
public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
if (!extensionAdded) {
extensionAdded = true;
undertow.initialize(extensionRegistry.getExtensionContext("org.wildfly.extension.undertow",
rootRegistration, ExtensionRegistryType.SERVER));
io.initialize(extensionRegistry.getExtensionContext("org.wildfly.extension.io",
rootRegistration, ExtensionRegistryType.SERVER));
}
}
}, null));
rootRegistration.registerSubModel(CoreManagementResourceDefinition.forStandaloneServer(new DelegatingConfigurableAuthorizer(), new ManagementSecurityIdentitySupplier(),
null, null, new EnvironmentNameReader() {
public boolean isServer() {
return true;
}
public String getServerName() {
return "Test";
}
public String getHostName() {
return null;
}
public String getProductName() {
return null;
}
}, null));
rootResource.registerChild(CoreManagementResourceDefinition.PATH_ELEMENT, Resource.Factory.create());
System.setProperty("file-base", new File(getClass().getClassLoader().getResource("server.keystore").getFile()).getParentFile().getAbsolutePath());
Map<String, Class> capabilities = new HashMap<>();
final String SOCKET_CAPABILITY = "org.wildfly.network.socket-binding";
capabilities.put(buildDynamicCapabilityName(SOCKET_CAPABILITY, "http"), SocketBinding.class);
capabilities.put(buildDynamicCapabilityName(SOCKET_CAPABILITY, "https"), SocketBinding.class);
registerServiceCapabilities(capabilityRegistry, capabilities);
}
@Override
protected RunningMode getRunningMode() {
return RunningMode.ADMIN_ONLY;
}
@Override
protected ProcessType getProcessType() {
return ProcessType.SELF_CONTAINED;
}
@Override
protected void setupController(ControllerInitializer controllerInitializer) {
controllerInitializer.addPath("jboss.controller.temp.dir", System.getProperty("java.io.tmpdir"), null);
}
}
}