diff --git a/legacy/web/pom.xml b/legacy/web/pom.xml index 6dc2d3f4e248..85f8f8bafc1f 100644 --- a/legacy/web/pom.xml +++ b/legacy/web/pom.xml @@ -52,6 +52,11 @@ wildfly-controller + + org.wildfly + wildfly-undertow + + org.jboss.logging jboss-logging diff --git a/legacy/web/src/main/java/org/jboss/as/web/WebDefinition.java b/legacy/web/src/main/java/org/jboss/as/web/WebDefinition.java index b9c126581158..248378dc882f 100644 --- a/legacy/web/src/main/java/org/jboss/as/web/WebDefinition.java +++ b/legacy/web/src/main/java/org/jboss/as/web/WebDefinition.java @@ -29,6 +29,7 @@ import org.jboss.as.controller.client.helpers.MeasurementUnit; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; @@ -71,5 +72,10 @@ private WebDefinition() { setDeprecated(WebExtension.DEPRECATED_SINCE); } + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + WebMigrateOperation.registerOperations(resourceRegistration, getResourceDescriptionResolver()); + } } diff --git a/legacy/web/src/main/java/org/jboss/as/web/WebExtension.java b/legacy/web/src/main/java/org/jboss/as/web/WebExtension.java index a785c190a532..59379d573ae8 100644 --- a/legacy/web/src/main/java/org/jboss/as/web/WebExtension.java +++ b/legacy/web/src/main/java/org/jboss/as/web/WebExtension.java @@ -31,11 +31,10 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; +import org.jboss.as.controller.Extension; import org.jboss.as.controller.ExtensionContext; import org.jboss.as.controller.ModelVersion; import org.jboss.as.controller.OperationFailedException; @@ -46,7 +45,8 @@ import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; import org.jboss.as.controller.descriptions.DeprecatedResourceDescriptionResolver; import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; -import org.jboss.as.controller.extension.AbstractLegacyExtension; +import org.jboss.as.controller.extension.UnsupportedSubsystemDescribeHandler; +import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; import org.jboss.as.controller.parsing.ExtensionParsingContext; import org.jboss.as.controller.registry.AliasEntry; import org.jboss.as.controller.registry.ManagementResourceRegistration; @@ -67,7 +67,7 @@ * @author Emanuel Muckenhuber * @author Tomaz Cerar */ -public class WebExtension extends AbstractLegacyExtension { +public class WebExtension implements Extension { public static final String SUBSYSTEM_NAME = "web"; public static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); public static final PathElement VALVE_PATH = PathElement.pathElement(Constants.VALVE); @@ -99,7 +99,6 @@ public class WebExtension extends AbstractLegacyExtension { new SensitivityClassification(SUBSYSTEM_NAME, "web-valve", false, false, false)); public WebExtension() { - super(extensionName, SUBSYSTEM_NAME); } static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String keyPrefix) { @@ -108,7 +107,7 @@ static StandardResourceDescriptionResolver getResourceDescriptionResolver(final } @Override - protected Set initializeLegacyModel(ExtensionContext context) { + public void initialize(ExtensionContext context) { final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, CURRENT_MODEL_VERSION); final ManagementResourceRegistration registration = subsystem.registerSubsystemModel(WebDefinition.INSTANCE); @@ -164,11 +163,13 @@ protected Set initializeLegacyModel(ExtensionCon registerTransformers_2_x_0(subsystem, 0); registerTransformers_2_x_0(subsystem, 1); } - return Collections.singleton(registration); + + registration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, + new UnsupportedSubsystemDescribeHandler(extensionName)); } @Override - protected void initializeLegacyParsers(ExtensionParsingContext context) { + public void initializeParsers(ExtensionParsingContext context) { for (Namespace ns : Namespace.values()) { if (ns.getUriString() != null) { context.setSubsystemXmlMapping(SUBSYSTEM_NAME, ns.getUriString(), WebSubsystemParser.getInstance()); diff --git a/legacy/web/src/main/java/org/jboss/as/web/WebMigrateOperation.java b/legacy/web/src/main/java/org/jboss/as/web/WebMigrateOperation.java new file mode 100644 index 000000000000..e660db101cd9 --- /dev/null +++ b/legacy/web/src/main/java/org/jboss/as/web/WebMigrateOperation.java @@ -0,0 +1,717 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2015, 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.web; + +import org.jboss.as.controller.CompositeOperationHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.RunningMode; +import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.descriptions.ResourceDescriptionResolver; +import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.domain.management.security.KeystoreAttributes; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.ValueExpression; +import org.wildfly.extension.io.IOExtension; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import static org.jboss.as.controller.OperationContext.Stage.MODEL; +import static org.jboss.as.controller.PathAddress.EMPTY_ADDRESS; +import static org.jboss.as.controller.PathAddress.pathAddress; +import static org.jboss.as.controller.PathElement.pathElement; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.AUTHENTICATION; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.COMPOSITE; +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.MODULE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROTOCOL; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELATIVE_TO; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SECURITY_REALM; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_IDENTITY; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SSL; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STEPS; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TRUSTSTORE; +import static org.jboss.as.controller.operations.common.Util.createAddOperation; +import static org.jboss.as.controller.operations.common.Util.createOperation; +import static org.jboss.as.controller.operations.common.Util.createRemoveOperation; + +/** + * Operation to migrate from the legacy web subsystem to the new undertow subsystem. + *

+ * This operation must be performed when the server is in admin-only mode. + * Internally, the operation: + *

+ *

    + *
  • query the description of all the web subsystem by invoking the :describe operation. + * This returns a list of :add operations for each web resources.
  • + *
  • :add the new org.widlfy.extension.undertow extension
  • + *
  • for each web resources, transform the :add operations to add the + * corresponding resource to the new undertow subsystem. + * In this step, changes to the resources model are taken into account
  • + *
  • :remove the messaging subsystem
  • + *
+ *

+ * The companion :describe-migration operation will return a list of all the actual operations that would be + * performed during the invocation of the :migrate operation. + *

+ * Note that all new operation addresses are generated for standalone mode. If this is a domain mode server + * then the addresses are fixed after they have been generated + * + * @author Jeff Mesnil (c) 2015 Red Hat inc. + * @author Stuart Douglas + */ + +public class WebMigrateOperation implements OperationStepHandler { + + private static final String UNDERTOW_EXTENSION = "org.wildfly.extension.undertow"; + private static final String IO_EXTENSION = "org.wildfly.extension.io"; + + private static final String REALM_NAME = "jbossweb-migration-security-realm"; + + private static final OperationStepHandler DESCRIBE_MIGRATION_INSTANCE = new WebMigrateOperation(true); + private static final OperationStepHandler MIGRATE_INSTANCE = new WebMigrateOperation(false); + public static final PathElement DEFAULT_SERVER_PATH = pathElement(Constants.SERVER, "default"); + + private final boolean describe; + + private WebMigrateOperation(boolean describe) { + + this.describe = describe; + } + + static void registerOperations(ManagementResourceRegistration registry, ResourceDescriptionResolver resourceDescriptionResolver) { + registry.registerOperationHandler(new SimpleOperationDefinitionBuilder("migrate", resourceDescriptionResolver) + .setRuntimeOnly() + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.READ_WHOLE_CONFIG) + .build(), + WebMigrateOperation.MIGRATE_INSTANCE); + registry.registerOperationHandler(new SimpleOperationDefinitionBuilder("describe-migration", resourceDescriptionResolver) + .setReplyType(ModelType.LIST).setReplyValueType(ModelType.OBJECT) + .setRuntimeOnly() + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.READ_WHOLE_CONFIG) + .build(), + WebMigrateOperation.DESCRIBE_MIGRATION_INSTANCE); + } + + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + if (!describe && context.getRunningMode() != RunningMode.ADMIN_ONLY) { + throw UndertowLogger.ROOT_LOGGER.migrateOperationAllowedOnlyInAdminOnly(); + } + + // node containing the description (list of add operations) of the legacy subsystem + final ModelNode legacyModelAddOps = new ModelNode(); + //we don't preserve order, instead we sort by address length + //TODO: is this ok in every case? + final Map migrationOperations = new TreeMap<>(new Comparator() { + @Override + public int compare(PathAddress o1, PathAddress o2) { + final int compare = Integer.compare(o1.size(), o2.size()); + if (compare != 0) { + return compare; + } + return o1.toString().compareTo(o2.toString()); + } + }); + + // invoke an OSH to describe the legacy messaging subsystem + describeLegacyWebResources(context, legacyModelAddOps); + // invoke an OSH to add the messaging-activemq extension + // FIXME: this does not work it the extension :add is added to the migrationOperations directly (https://issues.jboss.org/browse/WFCORE-323) + addExtension(context, migrationOperations, describe, UNDERTOW_EXTENSION); + addExtension(context, migrationOperations, describe, IO_EXTENSION); + + context.addStep(new OperationStepHandler() { + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + addDefaultResources(migrationOperations, legacyModelAddOps); + + //create the new IO subsystem + createIoSubsystem(context, migrationOperations); + + createWelcomeContentHandler(migrationOperations); + + // transform the legacy add operations and put them in migrationOperations + transformResources(context, legacyModelAddOps, migrationOperations); + + // put the /subsystem=messaging:remove operation + removeWebSubsystem(migrationOperations); + + fixAddressesForDomainMode(pathAddress(operation.get(ADDRESS)), migrationOperations); + + if (describe) { + // :describe-migration operation + + // for describe-migration operation, do nothing and return the list of operations that would + // be executed in the composite operation + context.getResult().set(migrationOperations.values()); + } else { + // :migrate operation + // invoke an OSH on a composite operation with all the migration operations + migrateSubsystems(context, migrationOperations); + } + } + }, MODEL); + } + + /** + * Creates the security realm + * + * @param context + * @param migrationOperations + * @return + */ + private SSLInformation createSecurityRealm(OperationContext context, Map migrationOperations, ModelNode legacyModelAddOps, String connector) { + ModelNode legacyAddOp = findResource(pathAddress(WebExtension.SUBSYSTEM_PATH, pathElement(WebExtension.CONNECTOR_PATH.getKey(), connector), pathElement("configuration", "ssl")), legacyModelAddOps); + if (legacyAddOp == null) { + return null; + } + //we have SSL + //now we need to find a unique name + //in domain mode different profiles could have different SSL configurations + //but the realms are not scoped to a profile + //if we hard coded a name migration would fail when migrating domains with multiple profiles + int counter = 1; + String realmName = REALM_NAME + counter; + boolean ok = false; + do { + Resource root = context.readResourceFromRoot(pathAddress(CORE_SERVICE, MANAGEMENT), false); + if (root.getChildrenNames(SECURITY_REALM).contains(realmName)) { + counter++; + realmName = REALM_NAME + counter; + } else { + ok = true; + } + } while (!ok); + + //we have a unique realm name + //add the realm + PathAddress addres = pathAddress(pathElement(CORE_SERVICE, MANAGEMENT), pathElement(SECURITY_REALM, realmName)); + migrationOperations.put(addres, createAddOperation(addres)); + + //read all the info from the SSL definition + ModelNode keyAlias = legacyAddOp.get(WebSSLDefinition.KEY_ALIAS.getName()); + ModelNode password = legacyAddOp.get(WebSSLDefinition.PASSWORD.getName()); + ModelNode certificateKeyFile = legacyAddOp.get(WebSSLDefinition.CERTIFICATE_KEY_FILE.getName()); + ModelNode cipherSuite = legacyAddOp.get(WebSSLDefinition.CIPHER_SUITE.getName()); + ModelNode protocol = legacyAddOp.get(WebSSLDefinition.PROTOCOL.getName()); + ModelNode verifyClient = legacyAddOp.get(WebSSLDefinition.VERIFY_CLIENT.getName()); + ModelNode verifyDepth = legacyAddOp.get(WebSSLDefinition.VERIFY_DEPTH.getName()); + ModelNode certificateFile = legacyAddOp.get(WebSSLDefinition.CERTIFICATE_FILE.getName()); + ModelNode caCertificateFile = legacyAddOp.get(WebSSLDefinition.CA_CERTIFICATE_FILE.getName()); + ModelNode caCertificatePassword = legacyAddOp.get(WebSSLDefinition.CA_CERTIFICATE_PASSWORD.getName()); + ModelNode csRevocationURL = legacyAddOp.get(WebSSLDefinition.CA_REVOCATION_URL.getName()); + ModelNode trustStoreType = legacyAddOp.get(WebSSLDefinition.TRUSTSTORE_TYPE.getName()); + ModelNode keystoreType = legacyAddOp.get(WebSSLDefinition.KEYSTORE_TYPE.getName()); + ModelNode sessionCacheSize = legacyAddOp.get(WebSSLDefinition.SESSION_CACHE_SIZE.getName()); + ModelNode sessionTimeout = legacyAddOp.get(WebSSLDefinition.SESSION_TIMEOUT.getName()); + ModelNode sslProtocol = legacyAddOp.get(WebSSLDefinition.SSL_PROTOCOL.getName()); + + //now lets add the trust store + addres = pathAddress(pathElement(CORE_SERVICE, MANAGEMENT), pathElement(SECURITY_REALM, realmName), pathElement(AUTHENTICATION, TRUSTSTORE)); + ModelNode addOp = createAddOperation(addres); + addOp.get(KeystoreAttributes.KEYSTORE_PATH.getName()).set(caCertificateFile); + addOp.get(KeystoreAttributes.KEYSTORE_PASSWORD.getName()).set(caCertificatePassword); + addOp.get(KeystoreAttributes.KEYSTORE_PROVIDER.getName()).set(trustStoreType); + migrationOperations.put(addres, addOp); + + + //now lets add the key store + addres = pathAddress(pathElement(CORE_SERVICE, MANAGEMENT), pathElement(SECURITY_REALM, realmName), pathElement(SERVER_IDENTITY, SSL)); + addOp = createAddOperation(addres); + addOp.get(KeystoreAttributes.KEYSTORE_PATH.getName()).set(certificateKeyFile); + addOp.get(KeystoreAttributes.KEYSTORE_PASSWORD.getName()).set(password); + addOp.get(KeystoreAttributes.KEYSTORE_PROVIDER.getName()).set(keystoreType); + addOp.get(KeystoreAttributes.ALIAS.getName()).set(keyAlias); + addOp.get(PROTOCOL).set(protocol); + //addOp.get(KeystoreAttributes.KEY_PASSWORD.getName()).set(password); //TODO: is this correct? both key and keystore have same password? + + if(verifyDepth.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSLDefinition.VERIFY_DEPTH.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + } + if(certificateFile.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSLDefinition.CERTIFICATE_FILE.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + } + + if(csRevocationURL.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSLDefinition.CA_REVOCATION_URL.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + } + + migrationOperations.put(addres, addOp); + + return new SSLInformation(realmName, verifyClient, sessionCacheSize, sessionTimeout, sslProtocol, cipherSuite); + } + + private void fixAddressesForDomainMode(PathAddress migrateAddress, Map migrationOperations) { + int i = 0; + while (i < migrateAddress.size()) { + if (migrateAddress.getElement(i).equals(WebExtension.SUBSYSTEM_PATH)) { + break; + } + ++i; + } + if (i == 0) { + //not domain mode, no need for a prefix + return; + } + PathAddress prefix = migrateAddress.subAddress(0, i); + Map old = new HashMap<>(migrationOperations); + migrationOperations.clear(); + for (Map.Entry e : old.entrySet()) { + if (e.getKey().getElement(0).getKey().equals(SUBSYSTEM)) { + final PathAddress oldAddress = pathAddress(e.getValue().get(ADDRESS)); + List elements = new ArrayList<>(); + for (PathElement j : prefix) { + elements.add(j); + } + for (PathElement j : oldAddress) { + elements.add(j); + } + PathAddress newAddress = pathAddress(elements); + e.getValue().get(ADDRESS).set(newAddress.toModelNode()); + migrationOperations.put(newAddress, e.getValue()); + } else { + //not targeted at a subsystem + migrationOperations.put(e.getKey(), e.getValue()); + } + } + } + + /** + * We need to create the IO subsystem, if it does not already exist + */ + private void createIoSubsystem(OperationContext context, Map migrationOperations) { + Resource root = context.readResourceFromRoot(PathAddress.EMPTY_ADDRESS, false); + if (root.getChildrenNames(SUBSYSTEM).contains(IOExtension.SUBSYSTEM_NAME)) { + // subsystem is already added, do nothing + return; + } + + PathAddress address = pathAddress(pathElement(SUBSYSTEM, IOExtension.SUBSYSTEM_NAME)); + migrationOperations.put(address, createAddOperation(address)); + address = pathAddress(pathElement(SUBSYSTEM, IOExtension.SUBSYSTEM_NAME), pathElement("worker", "default")); + migrationOperations.put(address, createAddOperation(address)); + address = pathAddress(pathElement(SUBSYSTEM, IOExtension.SUBSYSTEM_NAME), pathElement("buffer-pool", "default")); + migrationOperations.put(address, createAddOperation(address)); + + } + + + /** + * create a handler for serving welcome content + */ + private void createWelcomeContentHandler(Map migrationOperations) { + + PathAddress address = pathAddress(pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME), pathElement(Constants.CONFIGURATION, Constants.HANDLER)); + migrationOperations.put(address, createAddOperation(address)); + + address = pathAddress(pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME), pathElement(Constants.CONFIGURATION, Constants.HANDLER), pathElement(Constants.FILE, "welcome-content")); + final ModelNode add = createAddOperation(address); + add.get(Constants.PATH).set(new ModelNode(new ValueExpression("${jboss.home.dir}/welcome-content"))); + migrationOperations.put(address, add); + } + + private void addDefaultResources(Map migrationOperations, final ModelNode legacyModelDescription) { + //add the default server + PathAddress address = pathAddress(pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME), DEFAULT_SERVER_PATH); + ModelNode add = createAddOperation(address); + + ModelNode defaultSessionTimeout = null; + + //static resources + ModelNode directoryListing = null; + //todo: add support for some of these + ModelNode sendfile = null; + ModelNode fileEncoding = null; + ModelNode readOnly = null; + ModelNode webdav = null; + ModelNode secret = null; + ModelNode maxDepth = null; + ModelNode disabled = null; + + for (ModelNode legacyAddOp : legacyModelDescription.get(RESULT).asList()) { + final PathAddress la = pathAddress(legacyAddOp.get(ADDRESS)); + if (la.equals(pathAddress(WebExtension.SUBSYSTEM_PATH))) { + ModelNode defaultHost = legacyAddOp.get(WebDefinition.DEFAULT_VIRTUAL_SERVER.getName()); + if (defaultHost.isDefined()) { + add.get(Constants.DEFAULT_HOST).set(defaultHost.clone()); + } + ModelNode sessionTimeout = legacyAddOp.get(WebDefinition.DEFAULT_SESSION_TIMEOUT.getName()); + if (sessionTimeout.isDefined()) { + defaultSessionTimeout = sessionTimeout; + } + } else if (la.equals(pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.STATIC_RESOURCES_PATH))) { + ModelNode node = legacyAddOp.get(WebStaticResources.LISTINGS.getName()); + if (node.isDefined()) { + directoryListing = node; + } + node = legacyAddOp.get(WebStaticResources.SENDFILE.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.SENDFILE.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + sendfile = node; + } + node = legacyAddOp.get(WebStaticResources.FILE_ENCODING.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.FILE_ENCODING.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + fileEncoding = node; + } + node = legacyAddOp.get(WebStaticResources.READ_ONLY.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.READ_ONLY.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + readOnly = node; + } + node = legacyAddOp.get(WebStaticResources.WEBDAV.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.WEBDAV.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + webdav = node; + } + node = legacyAddOp.get(WebStaticResources.SECRET.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.SECRET.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + secret = node; + } + node = legacyAddOp.get(WebStaticResources.MAX_DEPTH.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.MAX_DEPTH.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + maxDepth = node; + } + node = legacyAddOp.get(WebStaticResources.DISABLED.getName()); + if (node.isDefined()) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebStaticResources.DISABLED.getName(), pathAddress(legacyAddOp.get(ADDRESS))); + disabled = node; + } + } + } + + migrationOperations.put(address, add); + address = pathAddress(pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME), pathElement(Constants.SERVLET_CONTAINER, "default")); + add = createAddOperation(address); + if (defaultSessionTimeout != null) { + add.get(Constants.DEFAULT_SESSION_TIMEOUT).set(defaultSessionTimeout.clone()); + } + if (directoryListing != null) { + add.get(Constants.DIRECTORY_LISTING).set(directoryListing); + } + + migrationOperations.put(address, add); + } + + /** + * It's possible that the extension is already present. In that case, this method does nothing. + */ + private void addExtension(OperationContext context, Map migrationOperations, boolean describe, String extension) { + Resource root = context.readResourceFromRoot(PathAddress.EMPTY_ADDRESS, false); + if (root.getChildrenNames(EXTENSION).contains(extension)) { + // extension is already added, do nothing + return; + } + PathAddress extensionAddress = pathAddress(EXTENSION, extension); + OperationEntry addEntry = context.getRootResourceRegistration().getOperationEntry(extensionAddress, ADD); + ModelNode addOperation = createAddOperation(extensionAddress); + addOperation.get(MODULE).set(extension); + if (describe) { + migrationOperations.put(extensionAddress, addOperation); + } else { + context.addStep(context.getResult().get(extensionAddress.toString()), addOperation, addEntry.getOperationHandler(), MODEL); + } + } + + private void removeWebSubsystem(Map migrationOperations) { + PathAddress subsystemAddress = pathAddress(WebExtension.SUBSYSTEM_PATH); + ModelNode removeOperation = createRemoveOperation(subsystemAddress); + migrationOperations.put(subsystemAddress, removeOperation); + } + + private void migrateSubsystems(OperationContext context, final Map migrationOperations) { + ModelNode compositeOp = createOperation(COMPOSITE, EMPTY_ADDRESS); + compositeOp.get(STEPS).set(migrationOperations.values()); + context.addStep(compositeOp, CompositeOperationHandler.INSTANCE, MODEL); + } + + private void transformResources(final OperationContext context, final ModelNode legacyModelDescription, final Map newAddOperations) throws OperationFailedException { + for (ModelNode legacyAddOp : legacyModelDescription.get(RESULT).asList()) { + final ModelNode newAddOp = legacyAddOp.clone(); + PathAddress address = pathAddress(newAddOp.get(ADDRESS)); + + if (address.size() == 1) { + //subsystem + migrateSubsystem(newAddOperations, newAddOp); + } else if (address.equals(pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.STATIC_RESOURCES_PATH))) { + //covered in the servlet container add, so just ignore + } else if (address.equals(pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.JSP_CONFIGURATION_PATH))) { + migrateJSPConfig(newAddOperations, newAddOp); + } else if (address.equals(pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.CONTAINER_PATH))) { + migrateMimeMapping(newAddOperations, newAddOp); + } else if (wildcardEquals(address, pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.CONNECTOR_PATH))) { + migrateConnector(context, newAddOperations, newAddOp, address, legacyModelDescription); + } else if (wildcardEquals(address, pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.HOST_PATH))) { + migrateVirtualHost(newAddOperations, newAddOp, address); + } else if (wildcardEquals(address, pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.HOST_PATH, WebExtension.ACCESS_LOG_PATH))) { + migrateAccessLog(newAddOperations, newAddOp, address, legacyModelDescription); + } else if (wildcardEquals(address, pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.HOST_PATH, WebExtension.ACCESS_LOG_PATH, WebExtension.DIRECTORY_PATH))) { + //ignore, handled by access-log + } else if (wildcardEquals(address, pathAddress(WebExtension.SUBSYSTEM_PATH, WebExtension.HOST_PATH, WebExtension.SSO_PATH))) { + migrateSso(newAddOperations, newAddOp, address); + } else { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(legacyAddOp); + } + + } + } + + private void migrateSso(Map newAddOperations, ModelNode newAddOp, PathAddress address) { + PathAddress newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.HOST, address.getElement(address.size() - 2).getValue()), UndertowExtension.PATH_SSO); + ModelNode add = createAddOperation(newAddress); + + add.get(Constants.DOMAIN).set(newAddOp.get(WebSSODefinition.DOMAIN.getName()).clone()); + add.get(Constants.HTTP_ONLY).set(newAddOp.get(WebSSODefinition.HTTP_ONLY.getName()).clone()); + + if (newAddOp.hasDefined(WebSSODefinition.CACHE_CONTAINER.getName())) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSODefinition.CACHE_CONTAINER.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + if (newAddOp.hasDefined(WebSSODefinition.REAUTHENTICATE.getName())) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSODefinition.REAUTHENTICATE.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + if (newAddOp.hasDefined(WebSSODefinition.CACHE_NAME.getName())) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebSSODefinition.CACHE_NAME.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + + newAddOperations.put(newAddress, add); + } + + private void migrateAccessLog(Map newAddOperations, ModelNode newAddOp, PathAddress address, ModelNode legacyAddOps) { + PathAddress newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.HOST, address.getElement(address.size() - 2).getValue()), UndertowExtension.PATH_ACCESS_LOG); + ModelNode add = createAddOperation(newAddress); + + //TODO: parse the pattern and modify to Undertow version + add.get(Constants.PATTERN).set(newAddOp.get(WebAccessLogDefinition.PATTERN.getName()).clone()); + add.get(Constants.PREFIX).set(newAddOp.get(WebAccessLogDefinition.PREFIX.getName()).clone()); + add.get(Constants.ROTATE).set(newAddOp.get(WebAccessLogDefinition.ROTATE.getName()).clone()); + if (newAddOp.hasDefined(WebAccessLogDefinition.RESOLVE_HOSTS.getName())) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebAccessLogDefinition.RESOLVE_HOSTS.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + //TODO: extended access log + if (newAddOp.hasDefined(WebAccessLogDefinition.EXTENDED.getName())) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebAccessLogDefinition.EXTENDED.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + + ModelNode directory = findResource(pathAddress(pathAddress(newAddOp.get(ADDRESS)), WebExtension.DIRECTORY_PATH), legacyAddOps); + if(directory != null){ + newAddOp.get(Constants.DIRECTORY).set(directory.get(PATH)); + newAddOp.get(Constants.RELATIVE_TO).set(directory.get(RELATIVE_TO)); + } + + newAddOperations.put(newAddress, add); + } + + private boolean wildcardEquals(PathAddress a1, PathAddress a2) { + if (a1.size() != a2.size()) { + return false; + } + for (int i = 0; i < a1.size(); ++i) { + PathElement p1 = a1.getElement(i); + PathElement p2 = a2.getElement(i); + if (!p1.getKey().equals(p2.getKey())) { + return false; + } + if (!p1.isWildcard() && !p2.isWildcard()) { + if (!p1.getValue().equals(p2.getValue())) { + return false; + } + } + } + return true; + } + + private void migrateVirtualHost(Map newAddOperations, ModelNode newAddOp, PathAddress address) { + PathAddress newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.HOST, address.getLastElement().getValue())); + ModelNode add = createAddOperation(newAddress); + + if (newAddOp.hasDefined(WebVirtualHostDefinition.ENABLE_WELCOME_ROOT.getName()) && newAddOp.get(WebVirtualHostDefinition.ENABLE_WELCOME_ROOT.getName()).asBoolean()) { + PathAddress welcomeAddress = pathAddress(newAddress, pathElement(Constants.LOCATION, "/")); + ModelNode welcomeAdd = createAddOperation(welcomeAddress); + welcomeAdd.get(Constants.HANDLER).set("welcome-content"); + newAddOperations.put(welcomeAddress, welcomeAdd); + } + add.get(Constants.ALIAS).set(newAddOp.get(WebVirtualHostDefinition.ALIAS.getName()).clone()); + add.get(Constants.DEFAULT_WEB_MODULE).set(newAddOp.get(WebVirtualHostDefinition.DEFAULT_WEB_MODULE.getName())); + + newAddOperations.put(newAddress, add); + } + + private void migrateConnector(OperationContext context, Map newAddOperations, ModelNode newAddOp, PathAddress address, ModelNode legacyModelAddOps) throws OperationFailedException { + String protocol = newAddOp.get(WebConnectorDefinition.PROTOCOL.getName()).asString(); + String scheme = null; + if (newAddOp.hasDefined(WebConnectorDefinition.SCHEME.getName())) { + scheme = newAddOp.get(WebConnectorDefinition.SCHEME.getName()).asString(); + } + final PathAddress newAddress; + final ModelNode addConnector; + switch (protocol) { + case "HTTP/1.1": + if (scheme == null || scheme.equals("http")) { + newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.HTTP_LISTENER, address.getLastElement().getValue())); + addConnector = createAddOperation(newAddress); + } else if (scheme.equals("https")) { + newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.HTTPS_LISTENER, address.getLastElement().getValue())); + addConnector = createAddOperation(newAddress); + + SSLInformation sslInfo = createSecurityRealm(context, newAddOperations, legacyModelAddOps, newAddress.getLastElement().getValue()); + if (sslInfo == null) { + throw UndertowLogger.ROOT_LOGGER.noSslConfig(); + } else { + addConnector.get(Constants.SECURITY_REALM).set(sslInfo.realmName); + addConnector.get(Constants.VERIFY_CLIENT).set(sslInfo.verifyClient); + addConnector.get(Constants.SSL_SESSION_CACHE_SIZE).set(sslInfo.sessionCacheSize); + addConnector.get(Constants.SSL_SESSION_TIMEOUT).set(sslInfo.sessionTimeout); + addConnector.get(Constants.ENABLED_PROTOCOLS).set(sslInfo.sslProtocol); + addConnector.get(Constants.ENABLED_CIPHER_SUITES).set(sslInfo.cipherSuites); + } + } else { + newAddress = null; + addConnector = null; + } + break; + case "AJP": + newAddress = pathAddress(UndertowExtension.SUBSYSTEM_PATH, DEFAULT_SERVER_PATH, pathElement(Constants.AJP_LISTENER, address.getLastElement().getValue())); + addConnector = createAddOperation(newAddress); + break; + default: + newAddress = null; + addConnector = null; + } + if (newAddress == null) { + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(newAddOp); + return; + } + addConnector.get(Constants.SOCKET_BINDING).set(newAddOp.get(SOCKET_BINDING)); + addConnector.get(Constants.SECURE).set(newAddOp.get(WebConnectorDefinition.SECURE.getName())); + addConnector.get(Constants.REDIRECT_SOCKET).set(newAddOp.get(WebConnectorDefinition.REDIRECT_BINDING.getName())); + addConnector.get(Constants.ENABLED).set(newAddOp.get(WebConnectorDefinition.ENABLED.getName())); + addConnector.get(Constants.RESOLVE_PEER_ADDRESS).set(newAddOp.get(WebConnectorDefinition.ENABLE_LOOKUPS.getName())); + addConnector.get(Constants.MAX_POST_SIZE).set(newAddOp.get(WebConnectorDefinition.MAX_POST_SIZE.getName())); + addConnector.get(Constants.REDIRECT_SOCKET).set(newAddOp.get(WebConnectorDefinition.REDIRECT_BINDING.getName())); + //TODO: secure + //TODO: max save post size + //TODO: proxy binding + if (newAddOp.hasDefined(WebConnectorDefinition.EXECUTOR.getName())) { + //TODO: migrate executor to worker + UndertowLogger.ROOT_LOGGER.couldNotMigrateResource(WebConnectorDefinition.EXECUTOR.getName(), pathAddress(newAddOp.get(ADDRESS))); + } + //TODO: expose max connections + newAddOperations.put(pathAddress(newAddOp.get(OP_ADDR)), addConnector); + } + + private void migrateMimeMapping(Map newAddOperations, ModelNode newAddOp) { + migrateWelcomeFiles(newAddOperations, newAddOp); + ModelNode mime = newAddOp.get("mime-mapping"); + if (mime.isDefined()) { + for (ModelNode w : mime.asList()) { + PathAddress wa = pathAddress(pathAddress(UndertowExtension.SUBSYSTEM_PATH, pathElement(Constants.SERVLET_CONTAINER, "default"), pathElement(Constants.MIME_MAPPING, w.asProperty().getName()))); + ModelNode add = createAddOperation(wa); + add.get(Constants.VALUE).set(w.asProperty().getValue()); + newAddOperations.put(wa, add); + + } + } + } + + private void migrateWelcomeFiles(Map newAddOperations, ModelNode newAddOp) { + ModelNode welcome = newAddOp.get("welcome-file"); + if (welcome.isDefined()) { + for (ModelNode w : welcome.asList()) { + PathAddress wa = pathAddress(pathAddress(UndertowExtension.SUBSYSTEM_PATH, pathElement(Constants.SERVLET_CONTAINER, "default"), pathElement(Constants.WELCOME_FILE, w.asString()))); + ModelNode add = createAddOperation(wa); + newAddOperations.put(wa, add); + } + } + } + + private void migrateJSPConfig(Map newAddOperations, ModelNode newAddOp) { + newAddOp.get(ADDRESS).set(pathAddress(UndertowExtension.SUBSYSTEM_PATH, pathElement(Constants.SERVLET_CONTAINER, "default"), UndertowExtension.PATH_JSP).toModelNode()); + newAddOperations.put(pathAddress(newAddOp.get(OP_ADDR)), newAddOp); + } + + private void migrateSubsystem(Map newAddOperations, ModelNode newAddOp) { + newAddOp.get(ADDRESS).set(pathAddress(pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME)).toModelNode()); + newAddOperations.put(pathAddress(newAddOp.get(OP_ADDR)), newAddOp); + } + + private void describeLegacyWebResources(OperationContext context, ModelNode legacyModelDescription) { + ModelNode describeLegacySubsystem = createOperation(GenericSubsystemDescribeHandler.DEFINITION, context.getCurrentAddress()); + context.addStep(legacyModelDescription, describeLegacySubsystem, GenericSubsystemDescribeHandler.INSTANCE, MODEL, true); + } + + private static ModelNode findResource(PathAddress address, ModelNode legacyAddOps) { + for (ModelNode legacyAddOp : legacyAddOps.get(RESULT).asList()) { + final PathAddress la = pathAddress(legacyAddOp.get(ADDRESS)); + if (la.equals(address)) { + return legacyAddOp; + } + } + return null; + } + + private class SSLInformation { + final String realmName; + final ModelNode verifyClient; + final ModelNode sessionCacheSize; + final ModelNode sessionTimeout; + final ModelNode sslProtocol; + final ModelNode cipherSuites; + + private SSLInformation(String realmName, ModelNode verifyClient, ModelNode sessionCacheSize, ModelNode sessionTimeout, ModelNode sslProtocol, ModelNode cipherSuites) { + this.realmName = realmName; + this.verifyClient = verifyClient; + this.sessionCacheSize = sessionCacheSize; + this.sessionTimeout = sessionTimeout; + this.sslProtocol = sslProtocol; + this.cipherSuites = cipherSuites; + } + } +} diff --git a/legacy/web/src/main/resources/org/jboss/as/web/LocalDescriptions.properties b/legacy/web/src/main/resources/org/jboss/as/web/LocalDescriptions.properties index 93e0b21b0b1d..ecfe1bf0d97e 100644 --- a/legacy/web/src/main/resources/org/jboss/as/web/LocalDescriptions.properties +++ b/legacy/web/src/main/resources/org/jboss/as/web/LocalDescriptions.properties @@ -6,6 +6,8 @@ web.instance-id=Set the identifier for this server instance. web.native=Add the native initialization listener to the web container. web.remove=Operation removing the web subsystem. web.deprecated=The Web subsystem is deprecated and may be removed or limited to managed domain legacy server use in future versions. +web.describe-migration=Describes the steps that will be taken to migrate this configuration to Undertow +web.migrate=Migrates this web subsystem config to Undertow web.container=Common container configuration web.container.add=Adds web container diff --git a/legacy/web/src/test/java/org/jboss/as/web/test/WebMigrateTestCase.java b/legacy/web/src/test/java/org/jboss/as/web/test/WebMigrateTestCase.java new file mode 100644 index 000000000000..c2d318466358 --- /dev/null +++ b/legacy/web/src/test/java/org/jboss/as/web/test/WebMigrateTestCase.java @@ -0,0 +1,227 @@ +/* +* 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 org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.RunningMode; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.access.management.DelegatingConfigurableAuthorizer; +import org.jboss.as.controller.capability.registry.RuntimeCapabilityRegistry; +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.subsystem.test.AbstractSubsystemTest; +import org.jboss.as.subsystem.test.AdditionalInitialization; +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; + +import java.io.File; + +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; + +/** + * + * @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"); + 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()); + + //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()); + + + //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()); + + 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()); + + //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()); + + + } + + 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) { + 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(), 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()); + } + + @Override + protected RunningMode getRunningMode() { + return RunningMode.ADMIN_ONLY; + } + } +} diff --git a/legacy/web/src/test/resources/jsse.keystore b/legacy/web/src/test/resources/jsse.keystore new file mode 100644 index 000000000000..ec7beec053a7 Binary files /dev/null and b/legacy/web/src/test/resources/jsse.keystore differ diff --git a/legacy/web/src/test/resources/org/jboss/as/web/test/subsystem-migrate-2.2.0.xml b/legacy/web/src/test/resources/org/jboss/as/web/test/subsystem-migrate-2.2.0.xml new file mode 100644 index 000000000000..14c8255c8cd0 --- /dev/null +++ b/legacy/web/src/test/resources/org/jboss/as/web/test/subsystem-migrate-2.2.0.xml @@ -0,0 +1,101 @@ + + + + + + + + + toto + ${prop.welcome.file:titi} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacy/web/src/test/resources/server.keystore b/legacy/web/src/test/resources/server.keystore new file mode 100644 index 000000000000..46ad2223cd04 Binary files /dev/null and b/legacy/web/src/test/resources/server.keystore differ diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java b/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java index 4df9fef5b586..c5226c31cff2 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java @@ -198,4 +198,13 @@ public interface Constants { String ENABLE_NODES = "enable-nodes"; String DISABLE_NODES = "disable-nodes"; String STOP_NODES = "stop-nodes"; + String DEFAULT_SESSION_TIMEOUT = "default-session-timeout"; + String PREDICATE = "predicate"; + String SSL_SESSION_CACHE_SIZE = "ssl-session-cache-size"; + String SSL_SESSION_TIMEOUT = "ssl-session-timeout"; + String VERIFY_CLIENT = "verify-client"; + String ENABLED_CIPHER_SUITES = "enabled-cipher-suites"; + String ENABLED_PROTOCOLS = "enabled-protocols"; + String ENABLE_HTTP2 = "enable-http2"; + String ENABLE_SPDY = "enable-spdy"; } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerAdd.java b/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerAdd.java index b6861d5975a4..9a78e00d2460 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerAdd.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerAdd.java @@ -47,6 +47,8 @@ ListenerService createService(String name, final Stri HttpsListenerResourceDefinition.VERIFY_CLIENT.resolveOption(context, model,builder); HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES.resolveOption(context, model, builder); HttpsListenerResourceDefinition.ENABLED_PROTOCOLS.resolveOption(context, model, builder); + HttpsListenerResourceDefinition.SSL_SESSION_CACHE_SIZE.resolveOption(context, model, builder); + HttpsListenerResourceDefinition.SSL_SESSION_TIMEOUT.resolveOption(context, model, builder); OptionMap.Builder listenerBuilder = OptionMap.builder().addAll(listenerOptions); HttpsListenerResourceDefinition.ENABLE_HTTP2.resolveOption(context, model,listenerBuilder); diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java b/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java index 5a32a9ccc49f..a242345a905b 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java @@ -31,6 +31,7 @@ import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.client.helpers.MeasurementUnit; import org.jboss.as.controller.operations.validation.EnumValidator; import org.jboss.as.controller.operations.validation.StringLengthValidator; import org.jboss.as.controller.registry.AttributeAccess; @@ -54,7 +55,7 @@ public class HttpsListenerResourceDefinition extends ListenerResourceDefinition .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setValidator(new StringLengthValidator(1)) .build(); - protected static final OptionAttributeDefinition VERIFY_CLIENT = OptionAttributeDefinition.builder("verify-client", SSL_CLIENT_AUTH_MODE) + protected static final OptionAttributeDefinition VERIFY_CLIENT = OptionAttributeDefinition.builder(Constants.VERIFY_CLIENT, SSL_CLIENT_AUTH_MODE) .setAllowNull(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) @@ -62,32 +63,35 @@ public class HttpsListenerResourceDefinition extends ListenerResourceDefinition .setDefaultValue(new ModelNode(SslClientAuthMode.NOT_REQUESTED.name())) .build(); - protected static final OptionAttributeDefinition ENABLED_CIPHER_SUITES = OptionAttributeDefinition.builder("enabled-cipher-suites", Options.SSL_ENABLED_CIPHER_SUITES) + protected static final OptionAttributeDefinition ENABLED_CIPHER_SUITES = OptionAttributeDefinition.builder(Constants.ENABLED_CIPHER_SUITES, Options.SSL_ENABLED_CIPHER_SUITES) .setAllowNull(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) .build(); - protected static final OptionAttributeDefinition ENABLED_PROTOCOLS = OptionAttributeDefinition.builder("enabled-protocols", Options.SSL_ENABLED_PROTOCOLS) + protected static final OptionAttributeDefinition ENABLED_PROTOCOLS = OptionAttributeDefinition.builder(Constants.ENABLED_PROTOCOLS, Options.SSL_ENABLED_PROTOCOLS) .setAllowNull(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) .build(); - protected static final OptionAttributeDefinition ENABLE_HTTP2 = OptionAttributeDefinition.builder("enable-http2", UndertowOptions.ENABLE_HTTP2) + protected static final OptionAttributeDefinition ENABLE_HTTP2 = OptionAttributeDefinition.builder(Constants.ENABLE_HTTP2, UndertowOptions.ENABLE_HTTP2) .setAllowNull(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) .setDefaultValue(new ModelNode(false)) .build(); - protected static final OptionAttributeDefinition ENABLE_SPDY = OptionAttributeDefinition.builder("enable-spdy", UndertowOptions.ENABLE_SPDY) + protected static final OptionAttributeDefinition ENABLE_SPDY = OptionAttributeDefinition.builder(Constants.ENABLE_SPDY, UndertowOptions.ENABLE_SPDY) .setAllowNull(true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) .setDefaultValue(new ModelNode(false)) .build(); + public static final OptionAttributeDefinition SSL_SESSION_CACHE_SIZE = OptionAttributeDefinition.builder(Constants.SSL_SESSION_CACHE_SIZE, Options.SSL_SERVER_SESSION_CACHE_SIZE).setAllowNull(true).setAllowExpression(true).build(); + public static final OptionAttributeDefinition SSL_SESSION_TIMEOUT = OptionAttributeDefinition.builder(Constants.SSL_SESSION_TIMEOUT, Options.SSL_SERVER_SESSION_TIMEOUT).setMeasurementUnit(MeasurementUnit.SECONDS).setAllowNull(true).setAllowExpression(true).build(); + private HttpsListenerResourceDefinition() { super(UndertowExtension.HTTPS_LISTENER_PATH); } @@ -101,6 +105,8 @@ public Collection getAttributes() { res.add(ENABLED_PROTOCOLS); res.add(ENABLE_HTTP2); res.add(ENABLE_SPDY); + res.add(SSL_SESSION_CACHE_SIZE); + res.add(SSL_SESSION_TIMEOUT); return res; } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/ServletContainerDefinition.java b/undertow/src/main/java/org/wildfly/extension/undertow/ServletContainerDefinition.java index 4503e0ca315d..d3b77b727cb1 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/ServletContainerDefinition.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/ServletContainerDefinition.java @@ -95,7 +95,7 @@ class ServletContainerDefinition extends PersistentResourceDefinition { .build(); protected static final AttributeDefinition DEFAULT_SESSION_TIMEOUT = - new SimpleAttributeDefinitionBuilder("default-session-timeout", ModelType.INT, true) + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SESSION_TIMEOUT, ModelType.INT, true) .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) .setAllowExpression(true) .setMeasurementUnit(MeasurementUnit.MINUTES) diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java index bad64b80c18a..e1073a617c0e 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java @@ -44,25 +44,26 @@ public class UndertowExtension implements Extension { public static final String SUBSYSTEM_NAME = "undertow"; + + public static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); public static final PathElement PATH_HANDLERS = PathElement.pathElement(Constants.CONFIGURATION, Constants.HANDLER); public static final PathElement PATH_FILTERS = PathElement.pathElement(Constants.CONFIGURATION, Constants.FILTER); - protected static final PathElement PATH_JSP = PathElement.pathElement(Constants.SETTING, Constants.JSP); - protected static final PathElement PATH_SESSION_COOKIE = PathElement.pathElement(Constants.SETTING, Constants.SESSION_COOKIE); - protected static final PathElement PATH_PERSISTENT_SESSIONS = PathElement.pathElement(Constants.SETTING, Constants.PERSISTENT_SESSIONS); - protected static final PathElement PATH_WEBSOCKETS = PathElement.pathElement(Constants.SETTING, Constants.WEBSOCKETS); - protected static final PathElement PATH_MIME_MAPPING = PathElement.pathElement(Constants.MIME_MAPPING); - protected static final PathElement PATH_WELCOME_FILE = PathElement.pathElement(Constants.WELCOME_FILE); - protected static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME); - protected static final PathElement AJP_LISTENER_PATH = PathElement.pathElement(Constants.AJP_LISTENER); - protected static final PathElement HOST_PATH = PathElement.pathElement(Constants.HOST); - protected static final PathElement HTTP_LISTENER_PATH = PathElement.pathElement(Constants.HTTP_LISTENER); - protected static final PathElement HTTPS_LISTENER_PATH = PathElement.pathElement(Constants.HTTPS_LISTENER); - protected static final PathElement PATH_SERVLET_CONTAINER = PathElement.pathElement(Constants.SERVLET_CONTAINER); - protected static final PathElement PATH_BUFFER_CACHE = PathElement.pathElement(Constants.BUFFER_CACHE); - protected static final PathElement PATH_LOCATION = PathElement.pathElement(Constants.LOCATION); - protected static final PathElement SERVER_PATH = PathElement.pathElement(Constants.SERVER); - protected static final PathElement PATH_ACCESS_LOG = PathElement.pathElement(Constants.SETTING, Constants.ACCESS_LOG); - protected static final PathElement PATH_SSO = PathElement.pathElement(Constants.SETTING, Constants.SINGLE_SIGN_ON); + public static final PathElement PATH_JSP = PathElement.pathElement(Constants.SETTING, Constants.JSP); + public static final PathElement PATH_SESSION_COOKIE = PathElement.pathElement(Constants.SETTING, Constants.SESSION_COOKIE); + public static final PathElement PATH_PERSISTENT_SESSIONS = PathElement.pathElement(Constants.SETTING, Constants.PERSISTENT_SESSIONS); + public static final PathElement PATH_WEBSOCKETS = PathElement.pathElement(Constants.SETTING, Constants.WEBSOCKETS); + public static final PathElement PATH_MIME_MAPPING = PathElement.pathElement(Constants.MIME_MAPPING); + public static final PathElement PATH_WELCOME_FILE = PathElement.pathElement(Constants.WELCOME_FILE); + public static final PathElement AJP_LISTENER_PATH = PathElement.pathElement(Constants.AJP_LISTENER); + public static final PathElement HOST_PATH = PathElement.pathElement(Constants.HOST); + public static final PathElement HTTP_LISTENER_PATH = PathElement.pathElement(Constants.HTTP_LISTENER); + public static final PathElement HTTPS_LISTENER_PATH = PathElement.pathElement(Constants.HTTPS_LISTENER); + public static final PathElement PATH_SERVLET_CONTAINER = PathElement.pathElement(Constants.SERVLET_CONTAINER); + public static final PathElement PATH_BUFFER_CACHE = PathElement.pathElement(Constants.BUFFER_CACHE); + public static final PathElement PATH_LOCATION = PathElement.pathElement(Constants.LOCATION); + public static final PathElement SERVER_PATH = PathElement.pathElement(Constants.SERVER); + public static final PathElement PATH_ACCESS_LOG = PathElement.pathElement(Constants.SETTING, Constants.ACCESS_LOG); + public static final PathElement PATH_SSO = PathElement.pathElement(Constants.SETTING, Constants.SINGLE_SIGN_ON); public static final PathElement BALANCER = PathElement.pathElement(Constants.BALANCER); public static final PathElement CONTEXT = PathElement.pathElement(Constants.CONTEXT); public static final PathElement LOAD_BALANCING_GROUP = PathElement.pathElement(Constants.LOAD_BALANCING_GROUP); diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java index b389810dfc94..9c891e4a5248 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java @@ -87,7 +87,7 @@ public class UndertowSubsystemParser_3_0 extends PersistentResourceXMLParser { builder(HttpsListenerResourceDefinition.INSTANCE) .addAttributes(AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED) .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) - .addAttributes(HttpsListenerResourceDefinition.SECURITY_REALM, HttpsListenerResourceDefinition.VERIFY_CLIENT, HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES, HttpsListenerResourceDefinition.ENABLED_PROTOCOLS, HttpsListenerResourceDefinition.ENABLE_HTTP2, HttpsListenerResourceDefinition.ENABLE_SPDY) + .addAttributes(HttpsListenerResourceDefinition.SECURITY_REALM, HttpsListenerResourceDefinition.VERIFY_CLIENT, HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES, HttpsListenerResourceDefinition.ENABLED_PROTOCOLS, HttpsListenerResourceDefinition.ENABLE_HTTP2, HttpsListenerResourceDefinition.ENABLE_SPDY, HttpsListenerResourceDefinition.SSL_SESSION_CACHE_SIZE, HttpsListenerResourceDefinition.SSL_SESSION_TIMEOUT) .addAttributes(ListenerResourceDefinition.MAX_HEADER_SIZE, ListenerResourceDefinition.MAX_ENTITY_SIZE, ListenerResourceDefinition.BUFFER_PIPELINED_DATA, ListenerResourceDefinition.MAX_PARAMETERS, ListenerResourceDefinition.MAX_HEADERS, ListenerResourceDefinition.MAX_COOKIES, ListenerResourceDefinition.ALLOW_ENCODED_SLASH, ListenerResourceDefinition.DECODE_URL, ListenerResourceDefinition.URL_CHARSET, ListenerResourceDefinition.ALWAYS_SET_KEEP_ALIVE, ListenerResourceDefinition.MAX_BUFFERED_REQUEST_SIZE, ListenerResourceDefinition.RECORD_REQUEST_START_TIME, diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/logging/UndertowLogger.java b/undertow/src/main/java/org/wildfly/extension/undertow/logging/UndertowLogger.java index 2efba3d279f8..d7042e83335f 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/logging/UndertowLogger.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/logging/UndertowLogger.java @@ -30,6 +30,8 @@ import java.net.InetSocketAddress; import java.util.List; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; import org.jboss.as.server.deployment.DeploymentUnit; import org.jboss.as.server.deployment.DeploymentUnitProcessingException; import org.jboss.dmr.ModelNode; @@ -326,4 +328,18 @@ public interface UndertowLogger extends BasicLogger { @Message(id = 76, value = "Cannot remove resource of type %s") IllegalArgumentException cannotRemoveResourceOfType(String type); + + @Message(id = 77, value = "Migrate operation only allowed in admin only mode") + OperationFailedException migrateOperationAllowedOnlyInAdminOnly(); + + @LogMessage(level = WARN) + @Message(id = 78, value = "Could not migrate resource %s") + void couldNotMigrateResource(ModelNode node); + + @LogMessage(level = WARN) + @Message(id = 79, value = "Could not migrate attribute %s from resource %s") + void couldNotMigrateResource(String attribute, PathAddress node); + + @Message(id = 80, value = "Could not migrate SSL connector as no SSL config is defined") + OperationFailedException noSslConfig(); } diff --git a/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties b/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties index f015415b0493..9ef1b61f7ee6 100644 --- a/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties +++ b/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties @@ -164,6 +164,8 @@ undertow.listener.reset-statistics=Resets all the connector statistics to zero undertow.listener.enable-http2=Enables HTTP2 support for this listener undertow.listener.enable-spdy=Enables SPDY support for this listener undertow.listener.disallowed-methods=A comma separated list of HTTP methods that are not allowed +undertow.listener.ssl-session-cache-size=The maximum number of active SSL sessions +undertow.listener.ssl-session-timeout=The timeout for SSL sessions, in seconds undertow.host=An Undertow host undertow.host.add=Adds a new host undertow.host.remove=Removes a host diff --git a/undertow/src/main/resources/schema/wildfly-undertow_3_0.xsd b/undertow/src/main/resources/schema/wildfly-undertow_3_0.xsd index 74a9bd0a7081..f92381c3b31f 100644 --- a/undertow/src/main/resources/schema/wildfly-undertow_3_0.xsd +++ b/undertow/src/main/resources/schema/wildfly-undertow_3_0.xsd @@ -160,6 +160,8 @@ + +