Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHandlerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHandlerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractHandlerDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,104 @@ +/* + * 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.extension.undertow; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AbstractRemoveStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public abstract class AbstractHandlerDefinition extends PersistentResourceDefinition implements Handler { + + private static final List CONSTRAINTS = new SensitiveTargetAccessConstraintDefinition( + new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, "undertow-filter", false, false, false) + ).wrapAsList(); + + protected AbstractHandlerDefinition(final String name, AbstractAddStepHandler addHandler, AbstractRemoveStepHandler removeHandler) { + this(name, Constants.HANDLER, addHandler, removeHandler); + } + + protected AbstractHandlerDefinition(final String name) { + this(name, Constants.HANDLER); + } + + protected AbstractHandlerDefinition(final String name, String prefix, AbstractAddStepHandler addHandler, AbstractRemoveStepHandler removeHandler) { + super(PathElement.pathElement(name), UndertowExtension.getResolver(prefix, name), addHandler, removeHandler); + } + + protected AbstractHandlerDefinition(final String name, String prefix) { + super(PathElement.pathElement(name), UndertowExtension.getResolver(prefix, name)); + } + + protected AbstractHandlerDefinition(final Parameters parameters) { + super(parameters); + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + if (resourceRegistration.getOperationEntry(PathAddress.EMPTY_ADDRESS, ModelDescriptionConstants.ADD) == null) { + registerAddOperation(resourceRegistration, new AbstractAddStepHandler(getAttributes()), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } + if (resourceRegistration.getOperationEntry(PathAddress.EMPTY_ADDRESS, ModelDescriptionConstants.REMOVE) == null) { + registerRemoveOperation(resourceRegistration, new DefaultHandlerRemove(), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } + } + + @Override + public Class getHandlerClass() { + return null; + } + + @Override + public List getAccessConstraints() { + return CONSTRAINTS; + } + + @Override + public Collection getAttributes() { + return Collections.emptyList(); + } + + protected static class DefaultHandlerRemove extends AbstractRemoveStepHandler { + private DefaultHandlerRemove() { + + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractPersistentSessionManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractPersistentSessionManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AbstractPersistentSessionManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,182 @@ +/* + * 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.extension.undertow; + +import io.undertow.servlet.UndertowServletLogger; +import io.undertow.servlet.api.SessionPersistenceManager; +import org.jboss.marshalling.ByteBufferInput; +import org.jboss.marshalling.Marshaller; +import org.jboss.marshalling.MarshallerFactory; +import org.jboss.marshalling.MarshallingConfiguration; +import org.jboss.marshalling.ModularClassResolver; +import org.jboss.marshalling.OutputStreamByteOutput; +import org.jboss.marshalling.Unmarshaller; +import org.jboss.marshalling.river.RiverMarshallerFactory; +import org.jboss.modules.ModuleLoader; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Persistent session manager + * + * @author Stuart Douglas + */ +public abstract class AbstractPersistentSessionManager implements SessionPersistenceManager, Service { + + public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("undertow", "persistent-session-manager"); + + private MarshallerFactory factory; + private MarshallingConfiguration configuration; + + private final InjectedValue moduleLoaderInjectedValue = new InjectedValue<>(); + + @Override + public void persistSessions(String deploymentName, Map sessionData) { + try { + final Marshaller marshaller = createMarshaller(); + try { + final Map serializedData = new HashMap(); + for (Map.Entry sessionEntry : sessionData.entrySet()) { + Map data = new HashMap(); + for (Map.Entry sessionAttribute : sessionEntry.getValue().getSessionData().entrySet()) { + try { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + marshaller.start(new OutputStreamByteOutput(out)); + marshaller.writeObject(sessionAttribute.getValue()); + marshaller.finish(); + data.put(sessionAttribute.getKey(), out.toByteArray()); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.failedToPersistSessionAttribute(sessionAttribute.getKey(), sessionAttribute.getValue(), sessionEntry.getKey(), e); + } + } + serializedData.put(sessionEntry.getKey(), new SessionEntry(sessionEntry.getValue().getExpiration(), data)); + } + persistSerializedSessions(deploymentName, serializedData); + } finally { + marshaller.close(); + } + } catch (Exception e) { + UndertowServletLogger.ROOT_LOGGER.failedToPersistSessions(e); + } + + } + + protected abstract void persistSerializedSessions(String deploymentName, Map serializedData) throws IOException; + + protected abstract Map loadSerializedSessions(final String deploymentName) throws IOException; + + @Override + public Map loadSessionAttributes(String deploymentName, final ClassLoader classLoader) { + try { + Unmarshaller unmarshaller = createUnmarshaller(); + try { + long time = System.currentTimeMillis(); + Map data = loadSerializedSessions(deploymentName); + if (data != null) { + Map ret = new HashMap(); + for (Map.Entry sessionEntry : data.entrySet()) { + if (sessionEntry.getValue().expiry.getTime() > time) { + Map session = new HashMap(); + for (Map.Entry sessionAttribute : sessionEntry.getValue().data.entrySet()) { + unmarshaller.start(new ByteBufferInput(ByteBuffer.wrap(sessionAttribute.getValue()))); + session.put(sessionAttribute.getKey(), unmarshaller.readObject()); + unmarshaller.finish(); + } + ret.put(sessionEntry.getKey(), new PersistentSession(sessionEntry.getValue().expiry, session)); + } + } + return ret; + } + } finally { + unmarshaller.close(); + } + } catch (Exception e) { + UndertowServletLogger.ROOT_LOGGER.failedtoLoadPersistentSessions(e); + } + return null; + } + + protected Marshaller createMarshaller() throws IOException { + return factory.createMarshaller(configuration); + } + + protected Unmarshaller createUnmarshaller() throws IOException { + return factory.createUnmarshaller(configuration); + } + + @Override + public void clear(String deploymentName) { + } + + @Override + public synchronized void start(StartContext startContext) throws StartException { + final RiverMarshallerFactory factory = new RiverMarshallerFactory(); + final MarshallingConfiguration configuration = new MarshallingConfiguration(); + configuration.setClassResolver(ModularClassResolver.getInstance(moduleLoaderInjectedValue.getValue())); + this.configuration = configuration; + this.factory = factory; + } + + @Override + public synchronized void stop(StopContext stopContext) { + } + + @Override + public synchronized SessionPersistenceManager getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + public InjectedValue getModuleLoaderInjectedValue() { + return moduleLoaderInjectedValue; + } + + protected static final class SessionEntry implements Serializable { + private final Date expiry; + private final Map data; + + private SessionEntry(Date expiry, Map data) { + this.expiry = expiry; + this.data = data; + } + + public Date getExpiry() { + return expiry; + } + + public Map getData() { + return data; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,92 @@ +/* + * 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.extension.undertow; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.as.controller.services.path.PathManagerService; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.xnio.XnioWorker; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class AccessLogAdd extends AbstractAddStepHandler { + + private AccessLogAdd() { + super(AccessLogDefinition.ATTRIBUTES); + } + + static final AccessLogAdd INSTANCE = new AccessLogAdd(); + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + + final PathAddress address = context.getCurrentAddress(); + final PathAddress hostAddress = address.getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + final String worker = AccessLogDefinition.WORKER.resolveModelAttribute(context, model).asString(); + final String pattern = AccessLogDefinition.PATTERN.resolveModelAttribute(context, model).asString(); + final String directory = AccessLogDefinition.DIRECTORY.resolveModelAttribute(context, model).asString(); + final String filePrefix = AccessLogDefinition.PREFIX.resolveModelAttribute(context, model).asString(); + final String fileSuffix = AccessLogDefinition.SUFFIX.resolveModelAttribute(context, model).asString(); + final boolean useServerLog = AccessLogDefinition.USE_SERVER_LOG.resolveModelAttribute(context, model).asBoolean(); + final boolean rotate = AccessLogDefinition.ROTATE.resolveModelAttribute(context, model).asBoolean(); + final boolean extended = AccessLogDefinition.EXTENDED.resolveModelAttribute(context, model).asBoolean(); + final ModelNode relativeToNode = AccessLogDefinition.RELATIVE_TO.resolveModelAttribute(context, model); + final String relativeTo = relativeToNode.isDefined() ? relativeToNode.asString() : null; + + Predicate predicate = null; + ModelNode predicateNode = AccessLogDefinition.PREDICATE.resolveModelAttribute(context, model); + if(predicateNode.isDefined()) { + predicate = Predicates.parse(predicateNode.asString(), getClass().getClassLoader()); + } + + final AccessLogService service; + if (useServerLog) { + service = new AccessLogService(pattern, extended, predicate); + } else { + service = new AccessLogService(pattern, directory, relativeTo, filePrefix, fileSuffix, rotate, extended, predicate); + } + + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + + final CapabilityServiceBuilder builder = context.getCapabilityServiceTarget().addCapability(AccessLogDefinition.ACCESS_LOG_CAPABILITY, service) + .addCapabilityRequirement(Capabilities.REF_IO_WORKER, XnioWorker.class, service.getWorker(), worker) + .addDependency(PathManagerService.SERVICE_NAME, PathManager.class, service.getPathManager()) + .addCapabilityRequirement(Capabilities.CAPABILITY_HOST, Host.class, service.getHost(), serverName, hostName); + //only for backward compatibility + builder.addAliases(UndertowService.accessLogServiceName(serverName, hostName)); + + builder.setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,152 @@ +/* + * 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.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.ValueExpression; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class AccessLogDefinition extends PersistentResourceDefinition { + static final RuntimeCapability ACCESS_LOG_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_ACCESS_LOG, true, AccessLogService.class) + .setDynamicNameMapper(path -> new String[]{ + path.getParent().getParent().getLastElement().getValue(), + path.getParent().getLastElement().getValue(), + path.getLastElement().getValue()}) + .build(); + + + protected static final SimpleAttributeDefinition PATTERN = new SimpleAttributeDefinitionBuilder(Constants.PATTERN, ModelType.STRING, true) + .setDefaultValue(new ModelNode("common")) + .setValidator(new StringLengthValidator(1, true)) + .setRestartAllServices() + .build(); + protected static final SimpleAttributeDefinition WORKER = new SimpleAttributeDefinitionBuilder(Constants.WORKER, ModelType.STRING) + .setRequired(false) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(Capabilities.REF_IO_WORKER) + .build(); + protected static final SimpleAttributeDefinition PREFIX = new SimpleAttributeDefinitionBuilder(Constants.PREFIX, ModelType.STRING, true) + .setDefaultValue(new ModelNode("access_log.")) + .setValidator(new StringLengthValidator(1, true)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + protected static final SimpleAttributeDefinition SUFFIX = new SimpleAttributeDefinitionBuilder(Constants.SUFFIX, ModelType.STRING, true) + .setDefaultValue(new ModelNode("log")) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + protected static final SimpleAttributeDefinition ROTATE = new SimpleAttributeDefinitionBuilder(Constants.ROTATE, ModelType.BOOLEAN, true) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + protected static final SimpleAttributeDefinition DIRECTORY = new SimpleAttributeDefinitionBuilder(Constants.DIRECTORY, ModelType.STRING) + .setRequired(false) + .setValidator(new StringLengthValidator(1, true)) + .setDefaultValue(new ModelNode(new ValueExpression("${jboss.server.log.dir}"))) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + protected static final SimpleAttributeDefinition RELATIVE_TO = new SimpleAttributeDefinitionBuilder(Constants.RELATIVE_TO, ModelType.STRING) + .setRequired(false) + .setValidator(new StringLengthValidator(1, true)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + protected static final SimpleAttributeDefinition USE_SERVER_LOG = new SimpleAttributeDefinitionBuilder(Constants.USE_SERVER_LOG, ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + protected static final SimpleAttributeDefinition EXTENDED = new SimpleAttributeDefinitionBuilder(Constants.EXTENDED, ModelType.BOOLEAN, true) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + protected static final SimpleAttributeDefinition PREDICATE = new SimpleAttributeDefinitionBuilder(Constants.PREDICATE, ModelType.STRING, true) + .setAllowExpression(true) + .setValidator(PredicateValidator.INSTANCE) + .setRestartAllServices() + .build(); + + static final Collection ATTRIBUTES = Arrays.asList( + // IMPORTANT -- keep these in xsd order as this order controls marshalling + WORKER, + PATTERN, + PREFIX, + SUFFIX, + ROTATE, + DIRECTORY, + USE_SERVER_LOG, + RELATIVE_TO, + EXTENDED, + PREDICATE + ); + static final AccessLogDefinition INSTANCE = new AccessLogDefinition(); + private final List accessConstraints; + + + private AccessLogDefinition() { + super(new Parameters(UndertowExtension.PATH_ACCESS_LOG, UndertowExtension.getResolver(Constants.ACCESS_LOG)) + .setAddHandler(AccessLogAdd.INSTANCE) + .setRemoveHandler(AccessLogRemove.INSTANCE) + .setCapabilities(ACCESS_LOG_CAPABILITY) + ); + SensitivityClassification sc = new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, "web-access-log", false, false, false); + this.accessConstraints = new SensitiveTargetAccessConstraintDefinition(sc).wrapAsList(); + } + + @Override + public List getAccessConstraints() { + return accessConstraints; + } + + @Override + public Collection getAttributes() { + //noinspection unchecked + return (Collection) ATTRIBUTES; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogRemove.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogRemove.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogRemove.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,52 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AbstractRemoveStepHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceName; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class AccessLogRemove extends AbstractRemoveStepHandler { + + public static final AccessLogRemove INSTANCE = new AccessLogRemove(); + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) { + final PathAddress hostAddress = context.getCurrentAddress().getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + final String hostName = hostAddress.getLastElement().getValue(); + final String serverName = serverAddress.getLastElement().getValue(); + final ServiceName serviceName = UndertowService.accessLogServiceName(serverName, hostName); + context.removeService(serviceName); + } + + protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + AccessLogAdd.INSTANCE.performRuntime(context, operation, model); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AccessLogService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,180 @@ +/* + * 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.extension.undertow; + +import io.undertow.attribute.ExchangeAttribute; +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.accesslog.AccessLogHandler; +import io.undertow.server.handlers.accesslog.AccessLogReceiver; +import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver; +import io.undertow.server.handlers.accesslog.ExtendedAccessLogParser; +import io.undertow.server.handlers.accesslog.JBossLoggingAccessLogReceiver; +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.IoUtils; +import org.xnio.XnioWorker; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class AccessLogService implements Service { + private final InjectedValue host = new InjectedValue<>(); + protected final InjectedValue worker = new InjectedValue<>(); + private final String pattern; + private final String path; + private final String pathRelativeTo; + private final String filePrefix; + private final String fileSuffix; + private final boolean rotate; + private final boolean useServerLog; + private final boolean extended; + private final Predicate predicate; + private volatile AccessLogReceiver logReceiver; + + + private PathManager.Callback.Handle callbackHandle; + + private Path directory; + private ExchangeAttribute extendedPattern; + + private final InjectedValue pathManager = new InjectedValue(); + + + AccessLogService(String pattern, boolean extended, Predicate predicate) { + this.pattern = pattern; + this.extended = extended; + this.path = null; + this.pathRelativeTo = null; + this.filePrefix = null; + this.fileSuffix = null; + this.useServerLog = true; + this.rotate = false; //doesn't really matter + this.predicate = predicate == null ? Predicates.truePredicate() : predicate; + } + + AccessLogService(String pattern, String path, String pathRelativeTo, String filePrefix, String fileSuffix, boolean rotate, boolean extended, Predicate predicate) { + this.pattern = pattern; + this.path = path; + this.pathRelativeTo = pathRelativeTo; + this.filePrefix = filePrefix; + this.fileSuffix = fileSuffix; + this.rotate = rotate; + this.extended = extended; + this.useServerLog = false; + this.predicate = predicate == null ? Predicates.truePredicate() : predicate; + } + + @Override + public void start(StartContext context) throws StartException { + if (useServerLog) { + logReceiver = new JBossLoggingAccessLogReceiver(); + } else { + if (pathRelativeTo != null) { + callbackHandle = pathManager.getValue().registerCallback(pathRelativeTo, PathManager.ReloadServerCallback.create(), PathManager.Event.UPDATED, PathManager.Event.REMOVED); + } + directory = Paths.get(pathManager.getValue().resolveRelativePathEntry(path, pathRelativeTo)); + if (!Files.exists(directory)) { + try { + Files.createDirectories(directory); + } catch (IOException e) { + throw UndertowLogger.ROOT_LOGGER.couldNotCreateLogDirectory(directory, e); + } + } + try { + DefaultAccessLogReceiver.Builder builder = DefaultAccessLogReceiver.builder().setLogWriteExecutor(worker.getValue()) + .setOutputDirectory(directory) + .setLogBaseName(filePrefix) + .setLogNameSuffix(fileSuffix) + .setRotate(rotate); + if(extended) { + builder.setLogFileHeaderGenerator(new ExtendedAccessLogParser.ExtendedAccessLogHeaderGenerator(pattern)); + extendedPattern = new ExtendedAccessLogParser(getClass().getClassLoader()).parse(pattern); + } else { + extendedPattern = null; + } + logReceiver = builder.build(); + } catch (IllegalStateException e) { + throw new StartException(e); + } + } + host.getValue().setAccessLogService(this); + } + + @Override + public void stop(StopContext context) { + host.getValue().setAccessLogService(null); + if (callbackHandle != null) { + callbackHandle.remove(); + callbackHandle = null; + } + if( logReceiver instanceof DefaultAccessLogReceiver ) { + IoUtils.safeClose((DefaultAccessLogReceiver) logReceiver); + } + logReceiver = null; + } + + @Override + public AccessLogService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + InjectedValue getWorker() { + return worker; + } + + InjectedValue getPathManager() { + return pathManager; + } + + protected AccessLogHandler configureAccessLogHandler(HttpHandler handler) { + if(extendedPattern != null) { + return new AccessLogHandler(handler, logReceiver, pattern, extendedPattern, predicate); + } else { + return new AccessLogHandler(handler, logReceiver, pattern, getClass().getClassLoader(), predicate); + } + } + + public InjectedValue getHost() { + return host; + } + + boolean isRotate() { + return rotate; + } + + String getPath() { + return path; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.REF_SOCKET_BINDING; + +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.network.SocketBinding; +import org.jboss.dmr.ModelNode; +import org.xnio.OptionMap; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +class AjpListenerAdd extends ListenerAdd { + + AjpListenerAdd(AjpListenerResourceDefinition def) { + super(def); + } + + @Override + ListenerService createService(String name, final String serverName, final OperationContext context, ModelNode model, OptionMap listenerOptions, OptionMap socketOptions) throws OperationFailedException { + ModelNode schemeNode = AjpListenerResourceDefinition.SCHEME.resolveModelAttribute(context, model); + String scheme = null; + if (schemeNode.isDefined()) { + scheme = schemeNode.asString(); + } + OptionMap.Builder listenerBuilder = OptionMap.builder().addAll(listenerOptions); + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE.resolveOption(context, model,listenerBuilder); + return new AjpListenerService(name, scheme, listenerBuilder.getMap(), socketOptions); + } + + @Override + void configureAdditionalDependencies(OperationContext context, CapabilityServiceBuilder serviceBuilder, ModelNode model, ListenerService service) throws OperationFailedException { + ModelNode redirectBindingRef = ListenerResourceDefinition.REDIRECT_SOCKET.resolveModelAttribute(context, model); + if (redirectBindingRef.isDefined()) { + serviceBuilder.addCapabilityRequirement(REF_SOCKET_BINDING, SocketBinding.class, service.getRedirectSocket(), redirectBindingRef.asString()); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerResourceDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,81 @@ +/* + * 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.extension.undertow; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel; + +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.IntRangeValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.io.OptionAttributeDefinition; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class AjpListenerResourceDefinition extends ListenerResourceDefinition { + protected static final AjpListenerResourceDefinition INSTANCE = new AjpListenerResourceDefinition(); + + protected static final SimpleAttributeDefinition SCHEME = new SimpleAttributeDefinitionBuilder(Constants.SCHEME, ModelType.STRING) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .build(); + public static final OptionAttributeDefinition MAX_AJP_PACKET_SIZE = OptionAttributeDefinition + .builder("max-ajp-packet-size", UndertowOptions.MAX_AJP_PACKET_SIZE) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(AjpClientRequestClientStreamSinkChannel.DEFAULT_MAX_DATA_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + private AjpListenerResourceDefinition() { + super(UndertowExtension.AJP_LISTENER_PATH); + } + + @Override + protected ListenerAdd getAddHandler() { + return new AjpListenerAdd(this); + } + + + public Collection getAttributes() { + List attrs = new ArrayList<>(super.getAttributes()); + attrs.add(SCHEME); + attrs.add(REDIRECT_SOCKET); + attrs.add(MAX_AJP_PACKET_SIZE); + return attrs; + } + + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/AjpListenerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,103 @@ +/* + * 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.extension.undertow; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import io.undertow.UndertowOptions; +import io.undertow.server.OpenListener; +import io.undertow.server.protocol.ajp.AjpOpenListener; + +import org.jboss.as.network.NetworkUtils; +import org.jboss.msc.service.StartContext; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.ChannelListener; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import org.xnio.StreamConnection; +import org.xnio.XnioWorker; +import org.xnio.channels.AcceptingChannel; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class AjpListenerService extends ListenerService { + + private volatile AcceptingChannel server; + private final String scheme; + + public AjpListenerService(String name, final String scheme, OptionMap listenerOptions, OptionMap socketOptions) { + super(name, listenerOptions, socketOptions, false); + this.scheme = scheme; + } + + @Override + protected OpenListener createOpenListener() { + AjpOpenListener ajpOpenListener = new AjpOpenListener(getBufferPool().getValue(), OptionMap.builder().addAll(commonOptions).addAll(listenerOptions).set(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, getUndertowService().isStatisticsEnabled()).getMap()); + ajpOpenListener.setScheme(scheme); + return ajpOpenListener; + } + + @Override + void startListening(XnioWorker worker, InetSocketAddress socketAddress, ChannelListener> acceptListener) throws IOException { + server = worker.createStreamConnectionServer(socketAddress, acceptListener, OptionMap.builder().addAll(commonOptions).addAll(socketOptions).getMap()); + server.resumeAccepts(); + final InetSocketAddress boundAddress = server.getLocalAddress(InetSocketAddress.class); + UndertowLogger.ROOT_LOGGER.listenerStarted("AJP", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + } + + @Override + protected void cleanFailedStart() { + //noting to do + } + + @Override + void stopListening() { + final InetSocketAddress boundAddress = server.getLocalAddress(InetSocketAddress.class); + server.suspendAccepts(); + UndertowLogger.ROOT_LOGGER.listenerSuspend("AJP", getName()); + IoUtils.safeClose(server); + UndertowLogger.ROOT_LOGGER.listenerStopped("AJP", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + } + + @Override + public AjpListenerService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + @Override + public boolean isSecure() { + return scheme != null && scheme.equals("https"); + } + + @Override + protected void preStart(final StartContext context) { + + } + + @Override + public String getProtocol() { + return "ajp"; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,493 @@ +/* + * 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.extension.undertow; + +import static java.security.AccessController.doPrivileged; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_APPLICATION_SECURITY_DOMAIN; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS; +import static org.wildfly.extension.undertow.Capabilities.REF_HTTP_AUTHENTICATION_FACTORY; +import static org.wildfly.extension.undertow.Capabilities.REF_JACC_POLICY; + +import static org.wildfly.extension.undertow.Capabilities.REF_SECURITY_DOMAIN; +import static org.wildfly.security.http.HttpConstants.BASIC_NAME; +import static org.wildfly.security.http.HttpConstants.CLIENT_CERT_NAME; +import static org.wildfly.security.http.HttpConstants.DIGEST_NAME; +import static org.wildfly.security.http.HttpConstants.FORM_NAME; + +import java.security.Policy; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import org.jboss.as.clustering.controller.SimpleCapabilityServiceConfigurator; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.CapabilityServiceTarget; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationContext.AttachmentKey; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.OperationStepHandler; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.access.constraint.ApplicationTypeConfig; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.ApplicationTypeAccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.metadata.javaee.jboss.RunAsIdentityMetaData; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceController.Mode; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.wildfly.clustering.service.ServiceConfigurator; +import org.wildfly.elytron.web.undertow.server.servlet.AuthenticationManager; +import org.wildfly.extension.undertow.security.jacc.JACCAuthorizationManager; +import org.wildfly.extension.undertow.security.sso.DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider; +import org.wildfly.security.auth.server.HttpAuthenticationFactory; + +import org.wildfly.security.auth.server.MechanismConfiguration; +import org.wildfly.security.auth.server.MechanismConfigurationSelector; +import org.wildfly.security.auth.server.MechanismRealmConfiguration; +import org.wildfly.security.auth.server.SecurityDomain; +import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory; +import org.wildfly.security.http.impl.ServerMechanismFactoryImpl; +import org.wildfly.security.http.util.FilterServerMechanismFactory; +import org.wildfly.security.http.util.sso.DefaultSingleSignOnManager; +import org.wildfly.security.http.util.sso.SingleSignOnServerMechanismFactory; +import org.wildfly.security.http.util.sso.SingleSignOnServerMechanismFactory.SingleSignOnConfiguration; +import org.wildfly.security.http.util.sso.SingleSignOnSessionFactory; +import org.wildfly.security.manager.WildFlySecurityManager; + +import io.undertow.server.session.SecureRandomSessionIdGenerator; +import io.undertow.server.session.SessionIdGenerator; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.LoginConfig; + +/** + * A {@link ResourceDefinition} to define the mapping from a security domain as specified in a web application + * to an {@link HttpAuthenticationFactory} plus additional policy information. + * + * @author Darran Lofthouse + */ +public class ApplicationSecurityDomainDefinition extends PersistentResourceDefinition { + + private static Predicate SERVLET_MECHANISM; + + static { + Set defaultMechanisms = new HashSet<>(4); + defaultMechanisms.add(BASIC_NAME); + defaultMechanisms.add(CLIENT_CERT_NAME); + defaultMechanisms.add(DIGEST_NAME); + defaultMechanisms.add(FORM_NAME); + + SERVLET_MECHANISM = defaultMechanisms::contains; + } + + static final RuntimeCapability APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY = RuntimeCapability + .Builder.of(CAPABILITY_APPLICATION_SECURITY_DOMAIN, true, BiFunction.class) + .build(); + + static final RuntimeCapability APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS_CAPABILITY = RuntimeCapability + .Builder.of(CAPABILITY_APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS, true) + .build(); + + static final SimpleAttributeDefinition HTTP_AUTHENTICATION_FACTORY = new SimpleAttributeDefinitionBuilder(Constants.HTTP_AUTHENITCATION_FACTORY, ModelType.STRING, false) + .setMinSize(1) + .setRestartAllServices() + .setCapabilityReference(REF_HTTP_AUTHENTICATION_FACTORY) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.AUTHENTICATION_FACTORY_REF) + .setAlternatives(Constants.SECURITY_DOMAIN) + .build(); + + static final SimpleAttributeDefinition OVERRIDE_DEPLOYMENT_CONFIG = new SimpleAttributeDefinitionBuilder(Constants.OVERRIDE_DEPLOYMENT_CONFIG, ModelType.BOOLEAN, true) + .setDefaultValue(new ModelNode(false)) + .setRestartAllServices() + .setRequires(Constants.HTTP_AUTHENITCATION_FACTORY) + .build(); + + static final SimpleAttributeDefinition SECURITY_DOMAIN = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_DOMAIN, ModelType.STRING, false) + .setMinSize(1) + .setRestartAllServices() + .setCapabilityReference(REF_SECURITY_DOMAIN) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.ELYTRON_SECURITY_DOMAIN_REF) + .setAlternatives(Constants.HTTP_AUTHENITCATION_FACTORY) + .build(); + + private static final StringListAttributeDefinition REFERENCING_DEPLOYMENTS = new StringListAttributeDefinition.Builder(Constants.REFERENCING_DEPLOYMENTS) + .setStorageRuntime() + .build(); + + static final SimpleAttributeDefinition ENABLE_JACC = new SimpleAttributeDefinitionBuilder(Constants.ENABLE_JACC, ModelType.BOOLEAN, true) + .setDefaultValue(new ModelNode(false)) + .setMinSize(1) + .setRestartAllServices() + .build(); + + private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[] { SECURITY_DOMAIN, HTTP_AUTHENTICATION_FACTORY, OVERRIDE_DEPLOYMENT_CONFIG, ENABLE_JACC }; + + static final ApplicationSecurityDomainDefinition INSTANCE = new ApplicationSecurityDomainDefinition(); + + private static final Set knownApplicationSecurityDomains = Collections.synchronizedSet(new HashSet<>()); + + private static final AttachmentKey KNOWN_DEPLOYMENTS_KEY = AttachmentKey.create(KnownDeploymentsApi.class); + + private ApplicationSecurityDomainDefinition() { + this((Parameters) new Parameters(UndertowExtension.PATH_APPLICATION_SECURITY_DOMAIN, + UndertowExtension.getResolver(Constants.APPLICATION_SECURITY_DOMAIN)) + .setCapabilities(APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY) + .addAccessConstraints(new SensitiveTargetAccessConstraintDefinition(new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, Constants.APPLICATION_SECURITY_DOMAIN, false, false, false)), + new ApplicationTypeAccessConstraintDefinition(new ApplicationTypeConfig(UndertowExtension.SUBSYSTEM_NAME, Constants.APPLICATION_SECURITY_DOMAIN))) + , new AddHandler()); + } + + private ApplicationSecurityDomainDefinition(Parameters parameters, AbstractAddStepHandler add) { + super(parameters.setAddHandler(add).setRemoveHandler(new RemoveHandler(add))); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + knownApplicationSecurityDomains.clear(); // If we are registering, time for a clean start. + super.registerAttributes(resourceRegistration); + if (resourceRegistration.getProcessType().isServer()) { + resourceRegistration.registerReadOnlyAttribute(REFERENCING_DEPLOYMENTS, new ReferencingDeploymentsHandler()); + } + } + + @Override + protected List getChildren() { + return Collections.singletonList(new ApplicationSecurityDomainSingleSignOnDefinition()); + } + + private static class ReferencingDeploymentsHandler implements OperationStepHandler { + + @Override + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + if (context.isDefaultRequiresRuntime()) { + context.addStep((ctx, op) -> { + final KnownDeploymentsApi knownDeploymentsApi = context.getCapabilityRuntimeAPI( + CAPABILITY_APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS, ctx.getCurrentAddressValue(), + KnownDeploymentsApi.class); + + ModelNode deploymentList = new ModelNode(); + for (String current : knownDeploymentsApi.getKnownDeployments()) { + deploymentList.add(current); + } + + context.getResult().set(deploymentList); + }, OperationContext.Stage.RUNTIME); + } + } + + } + + private static class AddHandler extends AbstractAddStepHandler { + + private AddHandler() { + super(ATTRIBUTES); + } + + /* (non-Javadoc) + * @see org.jboss.as.controller.AbstractAddStepHandler#populateModel(org.jboss.as.controller.OperationContext, org.jboss.dmr.ModelNode, org.jboss.as.controller.registry.Resource) + */ + @Override + protected void populateModel(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + super.populateModel(context, operation, resource); + knownApplicationSecurityDomains.add(context.getCurrentAddressValue()); + } + + @Override + protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + super.recordCapabilitiesAndRequirements(context, operation, resource); + KnownDeploymentsApi knownDeployments = new KnownDeploymentsApi(); + context.registerCapability(RuntimeCapability.Builder + .of(CAPABILITY_APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS, true, knownDeployments).build() + .fromBaseCapability(context.getCurrentAddressValue())); + context.attach(KNOWN_DEPLOYMENTS_KEY, knownDeployments); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + ModelNode model = resource.getModel(); + CapabilityServiceTarget target = context.getCapabilityServiceTarget(); + + final String securityDomain = SECURITY_DOMAIN.resolveModelAttribute(context, model).asStringOrNull(); + final String httpServerMechanismFactory = HTTP_AUTHENTICATION_FACTORY.resolveModelAttribute(context, model).asStringOrNull(); + boolean overrideDeploymentConfig = OVERRIDE_DEPLOYMENT_CONFIG.resolveModelAttribute(context, model).asBoolean(); + boolean enableJacc = ENABLE_JACC.resolveModelAttribute(context, model).asBoolean(); + + String securityDomainName = context.getCurrentAddressValue(); + + ServiceName applicationSecurityDomainName = APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.getCapabilityServiceName(context.getCurrentAddress()); + + ServiceBuilder serviceBuilder = target + .addService(applicationSecurityDomainName) + .setInitialMode(Mode.LAZY); + + final Function factoryFunction; + if (httpServerMechanismFactory != null) { + Supplier httpAuthenticationFactorySupplier = serviceBuilder.requires(context.getCapabilityServiceName(REF_HTTP_AUTHENTICATION_FACTORY, HttpAuthenticationFactory.class, httpServerMechanismFactory)); + factoryFunction = (s) -> httpAuthenticationFactorySupplier.get(); + } else { + Supplier securityDomainSupplier = serviceBuilder.requires(context.getCapabilityServiceName(REF_SECURITY_DOMAIN, SecurityDomain.class, securityDomain)); + factoryFunction = toHttpAuthenticationFactoryFunction(securityDomainSupplier); + } + + if (enableJacc) { + serviceBuilder.requires(context.getCapabilityServiceName(REF_JACC_POLICY, Policy.class)); + } + + final Supplier> transformerSupplier; + if (resource.hasChild(UndertowExtension.PATH_SSO)) { + ModelNode ssoModel = resource.getChild(UndertowExtension.PATH_SSO).getModel(); + + String cookieName = SingleSignOnDefinition.Attribute.COOKIE_NAME.resolveModelAttribute(context, ssoModel).asString(); + String domain = SingleSignOnDefinition.Attribute.DOMAIN.resolveModelAttribute(context, ssoModel).asString(); + String path = SingleSignOnDefinition.Attribute.PATH.resolveModelAttribute(context, ssoModel).asString(); + boolean httpOnly = SingleSignOnDefinition.Attribute.HTTP_ONLY.resolveModelAttribute(context, ssoModel).asBoolean(); + boolean secure = SingleSignOnDefinition.Attribute.SECURE.resolveModelAttribute(context, ssoModel).asBoolean(); + SingleSignOnConfiguration singleSignOnConfiguration = new SingleSignOnConfiguration(cookieName, domain, path, httpOnly, secure); + + ServiceName managerServiceName = new SingleSignOnManagerServiceNameProvider(securityDomainName).getServiceName(); + SessionIdGenerator generator = new SecureRandomSessionIdGenerator(); + + DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.INSTANCE + .map(provider -> provider.getServiceConfigurator(managerServiceName, securityDomainName, generator)) + .orElse(new SimpleCapabilityServiceConfigurator<>(managerServiceName, new DefaultSingleSignOnManager(new ConcurrentHashMap<>(), generator::createSessionId))) + .configure(context).build(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + + ServiceConfigurator factoryConfigurator = new SingleSignOnSessionFactoryServiceConfigurator(securityDomainName).configure(context, ssoModel); + factoryConfigurator.build(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + + Supplier singleSignOnSessionFactorySupplier = serviceBuilder.requires(factoryConfigurator.getServiceName()); + UnaryOperator transformer = (factory) -> new SingleSignOnServerMechanismFactory(factory, singleSignOnSessionFactorySupplier.get(), singleSignOnConfiguration); + transformerSupplier = () -> transformer; + + } else { + transformerSupplier = () -> null; + } + + Consumer, Registration>> valueConsumer = serviceBuilder.provides(applicationSecurityDomainName); + ApplicationSecurityDomainService service = new ApplicationSecurityDomainService(overrideDeploymentConfig, enableJacc, factoryFunction, transformerSupplier, valueConsumer); + serviceBuilder.setInstance(service); + serviceBuilder.install(); + + KnownDeploymentsApi knownDeploymentsApi = context.getAttachment(KNOWN_DEPLOYMENTS_KEY); + knownDeploymentsApi.setApplicationSecurityDomainService(service); + } + + } + + private static Function toHttpAuthenticationFactoryFunction(final Supplier securityDomainSupplier) { + final HttpServerAuthenticationMechanismFactory mechanismFactory = new FilterServerMechanismFactory(new ServerMechanismFactoryImpl(), SERVLET_MECHANISM); + return (realmName) -> HttpAuthenticationFactory.builder().setFactory(mechanismFactory) + .setSecurityDomain(securityDomainSupplier.get()) + .setMechanismConfigurationSelector( + MechanismConfigurationSelector.constantSelector(realmName == null ? MechanismConfiguration.EMPTY + : MechanismConfiguration.builder() + .addMechanismRealm( + MechanismRealmConfiguration.builder().setRealmName(realmName).build()) + .build())) + .build(); + } + + private static class RemoveHandler extends ServiceRemoveStepHandler { + + /** + * @param addOperation + */ + protected RemoveHandler(AbstractAddStepHandler addOperation) { + super(addOperation, APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY, APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS_CAPABILITY); + } + + @Override + protected void performRemove(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + super.performRemove(context, operation, model); + knownApplicationSecurityDomains.remove(context.getCurrentAddressValue()); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) { + super.performRuntime(context, operation, model); + if (context.isResourceServiceRestartAllowed()) { + final String securityDomainName = context.getCurrentAddressValue(); + context.removeService(new SingleSignOnManagerServiceNameProvider(securityDomainName).getServiceName()); + context.removeService(new SingleSignOnSessionFactoryServiceNameProvider(securityDomainName).getServiceName()); + } + } + + @Override + protected ServiceName serviceName(String name) { + RuntimeCapability dynamicCapability = APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.fromBaseCapability(name); + return dynamicCapability.getCapabilityServiceName(BiFunction.class); // no-arg getCapabilityServiceName() would be fine too + } + + } + + @Override + public Collection getAttributes() { + return Arrays.asList(ATTRIBUTES); + } + + Predicate getKnownSecurityDomainPredicate() { + return knownApplicationSecurityDomains::contains; + } + + private static class ApplicationSecurityDomainService implements Service, BiFunction, Registration> { + + private final Function factoryFunction; + private final Supplier> singleSignOnTransformerSupplier; + + private final Consumer, Registration>> valueConsumer; + + private final boolean overrideDeploymentConfig; + private final Set registrations = new HashSet<>(); + private final boolean enableJacc; + + private ApplicationSecurityDomainService(final boolean overrideDeploymentConfig, boolean enableJacc, Function factoryFunction, Supplier> singleSignOnTransformerSupplier, Consumer, Registration>> valueConsumer) { + this.overrideDeploymentConfig = overrideDeploymentConfig; + this.enableJacc = enableJacc; + this.factoryFunction = factoryFunction; + this.singleSignOnTransformerSupplier = singleSignOnTransformerSupplier; + this.valueConsumer = valueConsumer; + } + + @Override + public void start(StartContext context) throws StartException { + valueConsumer.accept(this); + } + + @Override + public void stop(StopContext context) {} + + @Override + public Registration apply(DeploymentInfo deploymentInfo, Function runAsMapper) { + AuthenticationManager.Builder builder = AuthenticationManager.builder() + .setHttpAuthenticationFactory(factoryFunction.apply(getRealmName(deploymentInfo))) + .setOverrideDeploymentConfig(overrideDeploymentConfig) + .setHttpAuthenticationFactoryTransformer(singleSignOnTransformerSupplier.get()) + .setRunAsMapper(runAsMapper); + + if (enableJacc) { + builder.setAuthorizationManager(JACCAuthorizationManager.INSTANCE); + } + + AuthenticationManager authenticationManager = builder.build(); + authenticationManager.configure(deploymentInfo); + + RegistrationImpl registration = new RegistrationImpl(deploymentInfo); + synchronized(registrations) { + registrations.add(registration); + } + return registration; + } + + private String getRealmName(final DeploymentInfo deploymentInfo) { + LoginConfig loginConfig = deploymentInfo.getLoginConfig(); + return loginConfig != null ? loginConfig.getRealmName() : null; + } + + private List getDeployments() { + synchronized (registrations) { + List deployments = new ArrayList<>(registrations.size()); + for (RegistrationImpl registration : registrations) { + deployments.add(registration.deploymentInfo.getDeploymentName()); + } + return deployments; + } + } + + private class RegistrationImpl implements Registration { + + final DeploymentInfo deploymentInfo; + + private RegistrationImpl(DeploymentInfo deploymentInfo) { + this.deploymentInfo = deploymentInfo; + } + + @Override + public void cancel() { + if (WildFlySecurityManager.isChecking()) { + doPrivileged((PrivilegedAction) () -> { + SecurityDomain.unregisterClassLoader(deploymentInfo.getClassLoader()); + return null; + }); + } else { + SecurityDomain.unregisterClassLoader(deploymentInfo.getClassLoader()); + } + synchronized(registrations) { + registrations.remove(this); + } + } + + } + + } + + public interface Registration { + + /** + * Cancel the registration. + */ + void cancel(); + + } + + private static class KnownDeploymentsApi { + + private volatile ApplicationSecurityDomainService service; + + List getKnownDeployments() { + return service != null ? service.getDeployments() : Collections.emptyList(); + + } + + void setApplicationSecurityDomainService(final ApplicationSecurityDomainService service) { + this.service = service; + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainSingleSignOnDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainSingleSignOnDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ApplicationSecurityDomainSingleSignOnDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,93 @@ +/* + * 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.extension.undertow; + +import java.util.function.UnaryOperator; + +import org.jboss.as.clustering.controller.CapabilityReference; +import org.jboss.as.clustering.controller.CommonUnaryRequirement; +import org.jboss.as.clustering.controller.UnaryCapabilityNameResolver; +import org.jboss.as.clustering.controller.ReloadRequiredResourceRegistration; +import org.jboss.as.clustering.controller.ResourceDescriptor; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.security.CredentialReference; +import org.jboss.dmr.ModelType; + +/** + * @author Paul Ferraro + */ +public class ApplicationSecurityDomainSingleSignOnDefinition extends SingleSignOnDefinition { + + enum Capability implements org.jboss.as.clustering.controller.Capability { + SSO_CREDENTIAL_STORE("org.wildfly.extension.undertow.application-security-domain.single-sign-on.credential-store"), + SSO_KEY_STORE("org.wildfly.extension.undertow.application-security-domain.single-sign-on.key-store"), + SSO_SSL_CONTEXT("org.wildfly.extension.undertow.application-security-domain.single-sign-on.client-ssl-context"), + ; + private final RuntimeCapability definition; + + Capability(String name) { + this.definition = RuntimeCapability.Builder.of(name, true).setDynamicNameMapper(UnaryCapabilityNameResolver.PARENT).build(); + } + + @Override + public RuntimeCapability getDefinition() { + return this.definition; + } + } + + enum Attribute implements org.jboss.as.clustering.controller.Attribute { + CREDENTIAL(CredentialReference.getAttributeBuilder(CredentialReference.CREDENTIAL_REFERENCE, CredentialReference.CREDENTIAL_REFERENCE, false, new CapabilityReference(Capability.SSO_CREDENTIAL_STORE, CommonUnaryRequirement.CREDENTIAL_STORE)).setAccessConstraints(SensitiveTargetAccessConstraintDefinition.CREDENTIAL).build()), + KEY_ALIAS("key-alias", ModelType.STRING, builder -> builder.setAllowExpression(true).addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SSL_REF)), + KEY_STORE("key-store", ModelType.STRING, builder -> builder.setCapabilityReference(new CapabilityReference(Capability.SSO_KEY_STORE, CommonUnaryRequirement.KEY_STORE)).addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SSL_REF)), + SSL_CONTEXT("client-ssl-context", ModelType.STRING, builder -> builder.setRequired(false).setCapabilityReference(new CapabilityReference(Capability.SSO_SSL_CONTEXT, CommonUnaryRequirement.SSL_CONTEXT)).setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SSL_REF)), + ; + private final AttributeDefinition definition; + + Attribute(String name, ModelType type, UnaryOperator configurator) { + this.definition = configurator.apply(new SimpleAttributeDefinitionBuilder(name, type).setRequired(true)).build(); + } + + Attribute(AttributeDefinition definition) { + this.definition = definition; + } + + @Override + public AttributeDefinition getDefinition() { + return this.definition; + } + } + + @Override + public void registerOperations(ManagementResourceRegistration registration) { + ResourceDescriptor descriptor = new ResourceDescriptor(this.getResourceDescriptionResolver()) + .addAttributes(Attribute.class) + .addAttributes(SingleSignOnDefinition.Attribute.class) + .addCapabilities(Capability.class) + ; + new ReloadRequiredResourceRegistration(descriptor).register(registration); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,67 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; + + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceTarget; + +/** + * @author Stuart Douglas + */ +final class BufferCacheAdd extends AbstractAddStepHandler { + static final BufferCacheAdd INSTANCE = new BufferCacheAdd(); + + BufferCacheAdd() { + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : BufferCacheDefinition.INSTANCE.getAttributes()) { + def.validateAndSet(operation, model); + } + } + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR)); + final String name = address.getLastElement().getValue(); + int bufferSize = BufferCacheDefinition.BUFFER_SIZE.resolveModelAttribute(context, model).asInt(); + int buffersPerRegions = BufferCacheDefinition.BUFFERS_PER_REGION.resolveModelAttribute(context, model).asInt(); + int maxRegions = BufferCacheDefinition.MAX_REGIONS.resolveModelAttribute(context, model).asInt(); + + final BufferCacheService service = new BufferCacheService(bufferSize, buffersPerRegions, maxRegions); + final ServiceTarget target = context.getServiceTarget(); + + target.addService(BufferCacheService.SERVICE_NAME.append(name), service) + .setInitialMode(ServiceController.Mode.ON_DEMAND) + .install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,78 @@ +/* + * 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.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class BufferCacheDefinition extends PersistentResourceDefinition { + protected static final SimpleAttributeDefinition BUFFER_SIZE = new SimpleAttributeDefinitionBuilder(Constants.BUFFER_SIZE, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, false, true)) + .setDefaultValue(new ModelNode(1024)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition BUFFERS_PER_REGION = new SimpleAttributeDefinitionBuilder(Constants.BUFFERS_PER_REGION, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, false, true)) + .setDefaultValue(new ModelNode(1024)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition MAX_REGIONS = new SimpleAttributeDefinitionBuilder(Constants.MAX_REGIONS, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, false, true)) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(10)) + .build(); + static final BufferCacheDefinition INSTANCE = new BufferCacheDefinition(); + private static final List ATTRIBUTES = Collections.unmodifiableList(Arrays.asList(BUFFER_SIZE, BUFFERS_PER_REGION, MAX_REGIONS)); + + private BufferCacheDefinition() { + super(UndertowExtension.PATH_BUFFER_CACHE, + UndertowExtension.getResolver(Constants.BUFFER_CACHE), + BufferCacheAdd.INSTANCE, + new ServiceRemoveStepHandler(BufferCacheService.SERVICE_NAME, BufferCacheAdd.INSTANCE)); + } + + @Override + public Collection getAttributes() { + return (Collection) ATTRIBUTES; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/BufferCacheService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,65 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.handlers.cache.DirectBufferCache; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; + +/** + * @author Stuart Douglas + */ +public class BufferCacheService implements Service { + + public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("undertow", "bufferCache"); + + private final int bufferSize; + private final int buffersPerRegion; + private final int maxRegions; + + private volatile DirectBufferCache value; + + public BufferCacheService(final int bufferSize, final int buffersPerRegion, final int maxRegions) { + this.bufferSize = bufferSize; + this.buffersPerRegion = buffersPerRegion; + this.maxRegions = maxRegions; + } + + @Override + public void start(final StartContext startContext) throws StartException { + value = new DirectBufferCache(bufferSize, buffersPerRegion, maxRegions * buffersPerRegion * bufferSize); + } + + @Override + public void stop(final StopContext stopContext) { + value = null; + } + + @Override + public DirectBufferCache getValue() throws IllegalStateException, IllegalArgumentException { + return value; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ByteBufferPoolDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ByteBufferPoolDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ByteBufferPoolDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,180 @@ +package org.wildfly.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; + +import io.undertow.connector.ByteBufferPool; +import io.undertow.server.DefaultByteBufferPool; + +public class ByteBufferPoolDefinition extends PersistentResourceDefinition { + + + static final RuntimeCapability UNDERTOW_BUFFER_POOL_RUNTIME_CAPABILITY = + RuntimeCapability.Builder.of(Capabilities.CAPABILITY_BYTE_BUFFER_POOL, true, ByteBufferPool.class).build(); + + + private static final int defaultBufferSize; + private static final boolean defaultDirectBuffers; + + static { + long maxMemory = Runtime.getRuntime().maxMemory(); + //smaller than 64mb of ram we use 512b buffers + if (maxMemory < 64 * 1024 * 1024) { + //use 512b buffers + defaultDirectBuffers = false; + defaultBufferSize = 512; + } else if (maxMemory < 128 * 1024 * 1024) { + //use 1k buffers + defaultDirectBuffers = true; + defaultBufferSize = 1024; + } else { + //use 16k buffers for best performance + //as 16k is generally the max amount of data that can be sent in a single write() call + defaultDirectBuffers = true; + defaultBufferSize = 1024 * 16; + } + } + protected static final SimpleAttributeDefinition BUFFER_SIZE = new SimpleAttributeDefinitionBuilder(Constants.BUFFER_SIZE, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition MAX_POOL_SIZE = new SimpleAttributeDefinitionBuilder(Constants.MAX_POOL_SIZE, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition DIRECT = new SimpleAttributeDefinitionBuilder(Constants.DIRECT, ModelType.BOOLEAN) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition THREAD_LOCAL_CACHE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.THREAD_LOCAL_CACHE_SIZE, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(12)) + .build(); + + + protected static final SimpleAttributeDefinition LEAK_DETECTION_PERCENT = new SimpleAttributeDefinitionBuilder(Constants.LEAK_DETECTION_PERCENT, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(0)) + .build(); + + private static final List ATTRIBUTES = Arrays.asList(BUFFER_SIZE, MAX_POOL_SIZE, DIRECT, THREAD_LOCAL_CACHE_SIZE, LEAK_DETECTION_PERCENT); + + + public static final ByteBufferPoolDefinition INSTANCE = new ByteBufferPoolDefinition(); + + private ByteBufferPoolDefinition() { + super(UndertowExtension.BYTE_BUFFER_POOL_PATH, + UndertowExtension.getResolver(Constants.BYTE_BUFFER_POOL), + new BufferPoolAdd(), + new ReloadRequiredRemoveStepHandler() + ); + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(UNDERTOW_BUFFER_POOL_RUNTIME_CAPABILITY); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + + private static class BufferPoolAdd extends AbstractAddStepHandler { + + private BufferPoolAdd() { + super(ByteBufferPoolDefinition.ATTRIBUTES); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final ModelNode bufferSizeModel = BUFFER_SIZE.resolveModelAttribute(context, model); + final ModelNode maxPoolSizeModel = MAX_POOL_SIZE.resolveModelAttribute(context, model); + final ModelNode directModel = DIRECT.resolveModelAttribute(context, model); + final int threadLocalCacheSize = THREAD_LOCAL_CACHE_SIZE.resolveModelAttribute(context, model).asInt(); + final int leakDetectionPercent = LEAK_DETECTION_PERCENT.resolveModelAttribute(context, model).asInt(); + + final int bufferSize = bufferSizeModel.asInt(defaultBufferSize); + final int maxPoolSize = maxPoolSizeModel.asInt(-1); + final boolean direct = directModel.asBoolean(defaultDirectBuffers); + + final ByteBufferPoolService service = new ByteBufferPoolService(direct, bufferSize, maxPoolSize, threadLocalCacheSize, leakDetectionPercent); + context.getCapabilityServiceTarget().addCapability(UNDERTOW_BUFFER_POOL_RUNTIME_CAPABILITY, service) + .setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + + } + } + + private static final class ByteBufferPoolService implements Service { + + private final boolean direct; + private final int size; + private final int maxSize; + private final int threadLocalCacheSize; + private final int leakDetectionPercent; + + + private volatile ByteBufferPool pool; + + private ByteBufferPoolService(boolean direct, int size, int maxSize, int threadLocalCacheSize, int leakDetectionPercent) { + this.direct = direct; + this.size = size; + this.maxSize = maxSize; + this.threadLocalCacheSize = threadLocalCacheSize; + this.leakDetectionPercent = leakDetectionPercent; + } + + + @Override + public void start(StartContext startContext) throws StartException { + pool = new DefaultByteBufferPool(direct, size, maxSize, threadLocalCacheSize, leakDetectionPercent); + } + + @Override + public void stop(StopContext stopContext) { + pool.close(); + pool = null; + } + + @Override + public ByteBufferPool getValue() throws IllegalStateException, IllegalArgumentException { + return pool; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Capabilities.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Capabilities.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Capabilities.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow; + +/** + * @author Tomaz Cerar (c) 2017 Red Hat Inc. + */ +public final class Capabilities { + /* + Capabilities in this subsystem + */ + public static final String CAPABILITY_UNDERTOW = "org.wildfly.undertow"; + public static final String CAPABILITY_LISTENER = "org.wildfly.undertow.listener"; + public static final String CAPABILITY_SERVER = "org.wildfly.undertow.server"; + public static final String CAPABILITY_HOST = "org.wildfly.undertow.host"; + public static final String CAPABILITY_HOST_SSO = "org.wildfly.undertow.host.sso"; + public static final String CAPABILITY_LOCATION = "org.wildfly.undertow.host.location"; + public static final String CAPABILITY_ACCESS_LOG = "org.wildfly.undertow.host.access-log"; + public static final String CAPABILITY_HANDLER = "org.wildfly.extension.undertow.handler"; + public static final String CAPABILITY_MOD_CLUSTER_FILTER = "org.wildfly.undertow.mod_cluster-filter"; + public static final String CAPABILITY_SERVLET_CONTAINER = "org.wildfly.undertow.servlet-container"; + public static final String CAPABILITY_WEBSOCKET = "org.wildfly.undertow.servlet-container.websocket"; + public static final String CAPABILITY_HTTP_INVOKER = "org.wildfly.undertow.http-invoker"; + public static final String CAPABILITY_HTTP_INVOKER_HOST = "org.wildfly.undertow.http-invoker.host"; + public static final String CAPABILITY_APPLICATION_SECURITY_DOMAIN = "org.wildfly.undertow.application-security-domain"; + public static final String CAPABILITY_APPLICATION_SECURITY_DOMAIN_KNOWN_DEPLOYMENTS = "org.wildfly.undertow.application-security-domain.known-deployments"; + public static final String CAPABILITY_REVERSE_PROXY_HANDLER_HOST = "org.wildfly.undertow.reverse-proxy.host"; + public static final String CAPABILITY_BYTE_BUFFER_POOL = "org.wildfly.undertow.byte-buffer-pool"; + + /* + References to capabilities outside of the subsystem + */ + + public static final String REF_IO_WORKER = "org.wildfly.io.worker"; + public static final String REF_SECURITY_DOMAIN = "org.wildfly.security.security-domain"; + public static final String REF_SOCKET_BINDING = "org.wildfly.network.socket-binding"; + public static final String REF_SSL_CONTEXT = "org.wildfly.security.ssl-context"; + public static final String REF_HTTP_AUTHENTICATION_FACTORY = "org.wildfly.security.http-authentication-factory"; + public static final String REF_JACC_POLICY = "org.wildfly.security.jacc-policy"; + public static final String REF_OUTBOUND_SOCKET = "org.wildfly.network.outbound-socket-binding"; + public static final String REF_REQUEST_CONTROLLER = "org.wildfly.request-controller"; +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleRedirectService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleRedirectService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ConsoleRedirectService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,171 @@ +/* + * 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.extension.undertow; + +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.RedirectHandler; +import io.undertow.util.Headers; +import org.jboss.as.network.NetworkInterfaceBinding; +import org.jboss.as.server.mgmt.domain.HttpManagement; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * A service to setup a redirect for the web administration console. + * + * @author James R. Perkins + */ +class ConsoleRedirectService implements Service { + + private static final String CONSOLE_PATH = "/console"; + private static final String NO_CONSOLE = "/noconsole.html"; + private static final String NO_REDIRECT = "/noredirect.html"; + + private final InjectedValue httpManagementInjector = new InjectedValue<>(); + private final InjectedValue hostInjector = new InjectedValue<>(); + + @Override + public void start(final StartContext startContext) throws StartException { + final Host host = hostInjector.getValue(); + UndertowLogger.ROOT_LOGGER.debugf("Starting console redirect for %s", host.getName()); + final HttpManagement httpManagement = httpManagementInjector.getOptionalValue(); + if (httpManagement != null) { + if (httpManagement.hasConsole()) { + host.registerHandler(CONSOLE_PATH, new ConsoleRedirectHandler(httpManagement)); + } else { + host.registerHandler(CONSOLE_PATH, new RedirectHandler(NO_CONSOLE)); + } + } else { + host.registerHandler(CONSOLE_PATH, new RedirectHandler(NO_CONSOLE)); + } + } + + @Override + public void stop(final StopContext stopContext) { + final Host host = hostInjector.getValue(); + UndertowLogger.ROOT_LOGGER.debugf("Stopping console redirect for %s", host.getName()); + host.unregisterHandler(CONSOLE_PATH); + } + + @Override + public ConsoleRedirectService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + protected InjectedValue getHttpManagementInjector() { + return httpManagementInjector; + } + + protected InjectedValue getHostInjector() { + return hostInjector; + } + + private static class ConsoleRedirectHandler implements HttpHandler { + private static final int DEFAULT_PORT = 80; + private static final String HTTP = "http"; + private static final String HTTPS = "https"; + private static final int SECURE_DEFAULT_PORT = 443; + + private final int port; + private final int securePort; + private final NetworkInterfaceBinding networkInterfaceBinding; + private final NetworkInterfaceBinding secureNetworkInterfaceBinding; + + ConsoleRedirectHandler(final HttpManagement httpManagement) { + port = httpManagement.getHttpPort(); + securePort = httpManagement.getHttpsPort(); + networkInterfaceBinding = httpManagement.getHttpNetworkInterfaceBinding(); + secureNetworkInterfaceBinding = httpManagement.getHttpsNetworkInterfaceBinding(); + } + + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception { + String location = NO_REDIRECT; + // Both ports should likely never be less than 0, but should result in a NO_REDIRECT if they are + if (port > -1 || securePort > -1) { + try { + // Use secure port if available by default + if (securePort > -1) { + location = assembleURI(HTTPS, secureNetworkInterfaceBinding, securePort, SECURE_DEFAULT_PORT, exchange); + } else { + location = assembleURI(HTTP, networkInterfaceBinding, port, DEFAULT_PORT, exchange); + } + } catch (URISyntaxException e) { + UndertowLogger.ROOT_LOGGER.invalidRedirectURI(e); + } + } + // Use a new redirect each time as different clients could be requesting the console with different host names + final RedirectHandler redirectHandler = new RedirectHandler(location); + redirectHandler.handleRequest(exchange); + } + + private String assembleURI(final String scheme, final NetworkInterfaceBinding interfaceBinding, final int port, final int defaultPort, final HttpServerExchange exchange) + throws URISyntaxException { + final int p = (port != defaultPort ? port : -1); + final String hostname = getRedirectHostname(interfaceBinding.getAddress(), exchange); + if (hostname == null) { + return NO_REDIRECT; + } + return new URI(scheme, null, hostname, p, CONSOLE_PATH, null, null).toString(); + } + + private String getRedirectHostname(final InetAddress managementAddress, final HttpServerExchange exchange) { + final InetAddress destinationAddress = exchange.getDestinationAddress().getAddress(); + // If hosts are equal use the host from the header + if (managementAddress.equals(destinationAddress) || managementAddress.isAnyLocalAddress()) { + String hostname = exchange.getRequestHeaders().getFirst(Headers.HOST); + if (hostname != null) { + // Remove the port if it exists + final int portPos = hostname.indexOf(':'); + if (portPos > 0) { + hostname = hostname.substring(0, portPos); + } + return hostname; + } + } + + // Host names don't match, use the IP address of the management host if both are loopback + if (managementAddress.isLoopbackAddress() && destinationAddress.isLoopbackAddress()) { + String hostname = managementAddress.getHostAddress(); + final int zonePos = hostname.indexOf('%'); + if (zonePos > 0) { + // Remove the zone identifier + hostname = hostname.substring(0, zonePos); + } + return hostname; + } + + // Nothing matched, don't expose the management IP + return null; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Constants.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Constants.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Constants.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,264 @@ +/* + * 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.extension.undertow; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ + +public interface Constants { + String ACCESS_LOG = "access-log"; + String AJP_LISTENER = "ajp-listener"; + String BUFFER_CACHE = "buffer-cache"; + String BUFFER_CACHES = "buffer-caches"; + String BUFFER_SIZE = "buffer-size"; + String BUFFERS_PER_REGION = "buffers-per-region"; + String CONFIGURATION = "configuration"; + String MAX_REGIONS = "max-regions"; + String BUFFER_POOL = "buffer-pool"; + String SETTING = "setting"; + String SECURITY_REALM = "security-realm"; + String SOCKET_BINDING = "socket-binding"; + String SSL_CONTEXT = "ssl-context"; + String PATH = "path"; + String HTTP_LISTENER = "http-listener"; + String HTTPS_LISTENER = "https-listener"; + String HTTP_INVOKER = "http-invoker"; + String LISTENER = "listener"; + String INSTANCE_ID = "instance-id"; + String NAME = "name"; + String WORKER = "worker"; + String SERVLET_CONTAINER = "servlet-container"; + String LOCATION = "location"; + String JSP = "jsp"; + String JSP_CONFIG = "jsp-config"; + String HANDLER = "handler"; + String HANDLERS = "handlers"; + String SERVER = "server"; + String HOST = "host"; + String PATTERN = "pattern"; + String PREFIX = "prefix"; + String SUFFIX = "suffix"; + String ROTATE = "rotate"; + //String CLASS = "class"; + String DEFAULT_HOST = "default-host"; + String DEFAULT_VIRTUAL_HOST = "default-virtual-host"; + String DEFAULT_SERVLET_CONTAINER = "default-servlet-container"; + String DEFAULT_SERVER = "default-server"; + String DEFAULT_WEB_MODULE = "default-web-module"; + String ALIAS = "alias"; + String ERROR_PAGE = "error-page"; + String ERROR_PAGES = "error-pages"; + String SIMPLE_ERROR_PAGE = "simple-error-page"; + String SCHEME = "scheme"; + String MAX_POST_SIZE = "max-post-size"; + String DEFAULT_RESPONSE_CODE = "default-response-code"; + /*JSP config */ + String CHECK_INTERVAL = "check-interval"; + String CONTAINER = "container"; + String DEVELOPMENT = "development"; + String DISABLED = "disabled"; + String DISPLAY_SOURCE_FRAGMENT = "display-source-fragment"; + String DUMP_SMAP = "dump-smap"; + String ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE = "error-on-use-bean-invalid-class-attribute"; + String FILE = "file"; + String FILE_ENCODING = "file-encoding"; + String GENERATE_STRINGS_AS_CHAR_ARRAYS = "generate-strings-as-char-arrays"; + String OPTIMIZE_SCRIPTLETS = "optimize-scriptlets"; + String JAVA_ENCODING = "java-encoding"; + String JSP_CONFIGURATION = "jsp-configuration"; + String KEEP_GENERATED = "keep-generated"; + String LISTINGS = "listings"; + String MAPPED_FILE = "mapped-file"; + String MAX_DEPTH = "max-depth"; + String MIME_MAPPING = "mime-mapping"; + String MODIFICATION_TEST_INTERVAL = "modification-test-interval"; + String READ_ONLY = "read-only"; + String RECOMPILE_ON_FAIL = "recompile-on-fail"; + String SCRATCH_DIR = "scratch-dir"; + String SECRET = "secret"; + String SENDFILE = "sendfile"; + String SINGLE_SIGN_ON = "single-sign-on"; + String SMAP = "smap"; + String SOURCE_VM = "source-vm"; + String SSL = "ssl"; + String STATIC_RESOURCES = "static-resources"; + String TAG_POOLING = "tag-pooling"; + String TARGET_VM = "target-vm"; + String TRIM_SPACES = "trim-spaces"; + String WEBDAV = "webdav"; + String WELCOME_FILE = "welcome-file"; + String X_POWERED_BY = "x-powered-by"; + String ENABLED = "enabled"; + String DIRECTORY_LISTING = "directory-listing"; + String FILTER = "filter"; + String FILTERS = "filters"; + String FILTER_REF = "filter-ref"; + + //session cookie config + String SESSION_COOKIE = "session-cookie"; + String DOMAIN = "domain"; + String COMMENT = "comment"; + String HTTP_ONLY = "http-only"; + String SECURE = "secure"; + String MAX_AGE = "max-age"; + String ALLOW_NON_STANDARD_WRAPPERS = "allow-non-standard-wrappers"; + + String PERSISTENT_SESSIONS = "persistent-sessions"; + String DEFAULT_BUFFER_CACHE = "default-buffer-cache"; + + String RELATIVE_TO = "relative-to"; + String REDIRECT_SOCKET = "redirect-socket"; + String DIRECTORY = "directory"; + String STACK_TRACE_ON_ERROR = "stack-trace-on-error"; + String DEFAULT_ENCODING = "default-encoding"; + String USE_LISTENER_ENCODING = "use-listener-encoding"; + String NONE = "none"; + String PROBLEM_SERVER_RETRY = "problem-server-retry"; + String STICKY_SESSION_LIFETIME = "sticky-session-lifetime"; + String SESSION_COOKIE_NAMES = "session-cookie-names"; + String CONNECTIONS_PER_THREAD = "connections-per-thread"; + String REVERSE_PROXY = "reverse-proxy"; + String MAX_REQUEST_TIME = "max-request-time"; + String CERTIFICATE_FORWARDING = "certificate-forwarding"; + String OPTIONS = "options"; + String IGNORE_FLUSH = "ignore-flush"; + + String WEBSOCKETS = "websockets"; + //mod_cluster + String MOD_CLUSTER = "mod-cluster"; + String MANAGEMENT_SOCKET_BINDING = "management-socket-binding"; + String ADVERTISE_SOCKET_BINDING = "advertise-socket-binding"; + String SECURITY_KEY = "security-key"; + String ADVERTISE_PROTOCOL = "advertise-protocol"; + String ADVERTISE_PATH = "advertise-path"; + String ADVERTISE_FREQUENCY = "advertise-frequency"; + String HEALTH_CHECK_INTERVAL = "health-check-interval"; + String BROKEN_NODE_TIMEOUT = "broken-node-timeout"; + String MANAGEMENT_ACCESS_PREDICATE = "management-access-predicate"; + String REQUEST_QUEUE_SIZE = "request-queue-size"; + String CACHED_CONNECTIONS_PER_THREAD = "cached-connections-per-thread"; + String CONNECTION_IDLE_TIMEOUT = "connection-idle-timeout"; + String FAILOVER_STRATEGY = "failover-strategy"; + + String USE_SERVER_LOG = "use-server-log"; + String VALUE = "value"; + + String REWRITE = "rewrite"; + String DISALLOWED_METHODS = "disallowed-methods"; + String RESOLVE_PEER_ADDRESS = "resolve-peer-address"; + String BALANCER = "balancer"; + String CONTEXT = "context"; + String NODE = "node"; + String STATUS = "status"; + String REQUESTS = "requests"; + String ENABLE = "enable"; + String DISABLE = "disable"; + String LOAD = "load"; + String USE_ALIAS = "use-alias"; + String LOAD_BALANCING_GROUP = "load-balancing-group"; + String CACHE_CONNECTIONS = "cache-connections"; + String FLUSH_WAIT = "flush-wait"; + String MAX_CONNECTIONS = "max-connections"; + String OPEN_CONNECTIONS = "open-connections"; + String PING = "ping"; + String READ = "read"; + String SMAX = "smax"; + String TIMEOUT = "timeout"; + String WRITTEN = "written"; + String TTL = "ttl"; + + String STICKY_SESSION = "sticky-session"; + String STICKY_SESSION_COOKIE = "sticky-session-cookie"; + String STICKY_SESSION_PATH = "sticky-session-path"; + String STICKY_SESSION_FORCE = "sticky-session-force"; + String STICKY_SESSION_REMOVE= "sticky-session-remove"; + String WAIT_WORKER = "wait-worker"; + String MAX_ATTEMPTS = "max-attempts"; + String FLUSH_PACKETS = "flush-packets"; + String QUEUE_NEW_REQUESTS = "queue-new-requests"; + String STOP = "stop"; + 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"; + String URI = "uri"; + String ALIASES = "aliases"; + String ELECTED = "elected"; + String PROACTIVE_AUTHENTICATION = "proactive-authentication"; + String SESSION_ID_LENGTH = "session-id-length"; + String EXTENDED = "extended"; + String MAX_BUFFERED_REQUEST_SIZE = "max-buffered-request-size"; + String MAX_SESSIONS = "max-sessions"; + String USER_AGENTS = "user-agents"; + String SESSION_TIMEOUT = "session-timeout"; + String CRAWLER_SESSION_MANAGEMENT = "crawler-session-management"; + String MAX_AJP_PACKET_SIZE = "max-ajp-packet-size"; + String STATISTICS_ENABLED = "statistics-enabled"; + String DEFAULT_SECURITY_DOMAIN = "default-security-domain"; + String DISABLE_FILE_WATCH_SERVICE = "disable-file-watch-service"; + String DISABLE_SESSION_ID_REUSE = "disable-session-id-reuse"; + String PER_MESSAGE_DEFLATE = "per-message-deflate"; + String DEFLATER_LEVEL = "deflater-level"; + String MAX_RETRIES = "max-retries"; + + // Elytron Integration + String APPLICATION_SECURITY_DOMAIN = "application-security-domain"; + String APPLICATION_SECURITY_DOMAINS = "application-security-domains"; + String HTTP_AUTHENITCATION_FACTORY = "http-authentication-factory"; + String OVERRIDE_DEPLOYMENT_CONFIG = "override-deployment-config"; + String REFERENCING_DEPLOYMENTS = "referencing-deployments"; + String SECURITY_DOMAIN = "security-domain"; + String ENABLE_JACC = "enable-jacc"; + + String FILE_CACHE_MAX_FILE_SIZE = "file-cache-max-file-size"; + String FILE_CACHE_METADATA_SIZE = "file-cache-metadata-size"; + String FILE_CACHE_TIME_TO_LIVE = "file-cache-time-to-live"; + String SESSION_ID = "session-id"; + String ATTRIBUTE = "attribute"; + String INVALIDATE_SESSION = "invalidate-session"; + String LIST_SESSIONS = "list-sessions"; + String LIST_SESSION_ATTRIBUTE_NAMES = "list-session-attribute-names"; + String LIST_SESSION_ATTRIBUTES = "list-session-attributes"; + String GET_SESSION_ATTRIBUTE = "get-session-attribute"; + String GET_SESSION_LAST_ACCESSED_TIME = "get-session-last-accessed-time"; + String GET_SESSION_LAST_ACCESSED_TIME_MILLIS = "get-session-last-accessed-time-millis"; + String GET_SESSION_CREATION_TIME = "get-session-creation-time"; + String GET_SESSION_CREATION_TIME_MILLIS = "get-session-creation-time-millis"; + String DEFAULT_COOKIE_VERSION = "default-cookie-version"; + + String PROXY_PROTOCOL = "proxy-protocol"; + String MAX_POOL_SIZE = "max-pool-size"; + String THREAD_LOCAL_CACHE_SIZE = "thread-local-cache-size"; + String DIRECT = "direct"; + String LEAK_DETECTION_PERCENT = "leak-detection-percent"; + String BYTE_BUFFER_POOL = "byte-buffer-pool"; +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/CrawlerSessionManagementDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/CrawlerSessionManagementDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/CrawlerSessionManagementDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,146 @@ +/* + * 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.extension.undertow; + +import io.undertow.servlet.api.CrawlerSessionManagerConfig; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Global session cookie config + * + * @author Stuart Douglas + */ +class CrawlerSessionManagementDefinition extends PersistentResourceDefinition { + + static final CrawlerSessionManagementDefinition INSTANCE = new CrawlerSessionManagementDefinition(); + + protected static final SimpleAttributeDefinition USER_AGENTS = + new SimpleAttributeDefinitionBuilder(Constants.USER_AGENTS, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition SESSION_TIMEOUT = + new SimpleAttributeDefinitionBuilder(Constants.SESSION_TIMEOUT, ModelType.INT, true) + .setRestartAllServices() + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + USER_AGENTS, + SESSION_TIMEOUT + }; + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + + private CrawlerSessionManagementDefinition() { + super(UndertowExtension.CRAWLER_SESSION_MANAGEMENT, + UndertowExtension.getResolver(UndertowExtension.CRAWLER_SESSION_MANAGEMENT.getKeyValuePair()), + new CrawlerSessionManagementAdd(), + new CrawlerSessionManagementRemove()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } + + public CrawlerSessionManagerConfig getConfig(final OperationContext context, final ModelNode model) throws OperationFailedException { + if(!model.isDefined()) { + return null; + } + ModelNode agents = USER_AGENTS.resolveModelAttribute(context, model); + ModelNode timeout = SESSION_TIMEOUT.resolveModelAttribute(context, model); + if(timeout.isDefined() && agents.isDefined()) { + return new CrawlerSessionManagerConfig(timeout.asInt(), agents.asString()); + } else if(timeout.isDefined()) { + return new CrawlerSessionManagerConfig(timeout.asInt()); + } else if(agents.isDefined()) { + return new CrawlerSessionManagerConfig(agents.asString()); + } + return new CrawlerSessionManagerConfig(); + } + + + private static class CrawlerSessionManagementAdd extends RestartParentResourceAddHandler { + protected CrawlerSessionManagementAdd() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } + + private static class CrawlerSessionManagementRemove extends RestartParentResourceRemoveHandler { + + protected CrawlerSessionManagementRemove() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/DefaultResponseCodeHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/DefaultResponseCodeHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/DefaultResponseCodeHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,67 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.StatusCodes; + +import org.jboss.logging.Logger; + +/** + * Simple hander to set default code + * + * @author baranowb + * + */ +public class DefaultResponseCodeHandler implements HttpHandler { + + protected static final Logger log = Logger.getLogger(DefaultResponseCodeHandler.class); + protected static final boolean traceEnabled; + static { + traceEnabled = log.isTraceEnabled(); + } + + private final int responseCode; + private volatile boolean suspended = false; + + public DefaultResponseCodeHandler(final int defaultCode) { + this.responseCode = defaultCode; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if(suspended) { + exchange.setStatusCode(StatusCodes.SERVICE_UNAVAILABLE); + } else { + exchange.setStatusCode(this.responseCode); + } + if (traceEnabled) { + log.tracef("Setting response code %s for exchange %s", responseCode, exchange); + } + } + + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,440 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.jboss.as.controller.AbstractRuntimeOnlyHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationDefinition; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.descriptions.ResourceDescriptionResolver; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.Property; +import org.jboss.msc.service.ServiceController; +import org.wildfly.extension.undertow.deployment.UndertowDeploymentService; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import io.undertow.server.session.Session; +import io.undertow.server.session.SessionManager; +import io.undertow.server.session.SessionManagerStatistics; +import io.undertow.servlet.api.Deployment; + +/** + * @author Tomaz Cerar + */ +public class DeploymentDefinition extends SimpleResourceDefinition { + + private static final ResourceDescriptionResolver DEFAULT_RESOLVER = UndertowExtension.getResolver("deployment"); + + public static final DeploymentDefinition INSTANCE = new DeploymentDefinition(); + + public static final AttributeDefinition SERVER = new SimpleAttributeDefinitionBuilder("server", ModelType.STRING).setStorageRuntime().build(); + public static final AttributeDefinition CONTEXT_ROOT = new SimpleAttributeDefinitionBuilder("context-root", ModelType.STRING).setStorageRuntime().build(); + public static final AttributeDefinition VIRTUAL_HOST = new SimpleAttributeDefinitionBuilder("virtual-host", ModelType.STRING).setStorageRuntime().build(); + static final AttributeDefinition SESSIOND_ID = new SimpleAttributeDefinitionBuilder(Constants.SESSION_ID, ModelType.STRING) + .setRequired(true) + .setAllowExpression(false) + .build(); + + static final AttributeDefinition ATTRIBUTE = new SimpleAttributeDefinitionBuilder(Constants.ATTRIBUTE, ModelType.STRING) + .setRequired(true) + .setAllowExpression(false) + .build(); + + + static final OperationDefinition INVALIDATE_SESSION = new SimpleOperationDefinitionBuilder(Constants.INVALIDATE_SESSION, DEFAULT_RESOLVER) + .addParameter(SESSIOND_ID) + .setRuntimeOnly() + .setReplyType(ModelType.BOOLEAN) + .build(); + + static final OperationDefinition LIST_SESSIONS = new SimpleOperationDefinitionBuilder(Constants.LIST_SESSIONS, DEFAULT_RESOLVER) + .setRuntimeOnly() + .setReplyType(ModelType.LIST) + .setReplyValueType(ModelType.STRING) + .build(); + + static final OperationDefinition LIST_SESSION_ATTRIBUTE_NAMES = new SimpleOperationDefinitionBuilder(Constants.LIST_SESSION_ATTRIBUTE_NAMES, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.LIST) + .setReplyValueType(ModelType.STRING) + .build(); + + static final OperationDefinition LIST_SESSION_ATTRIBUTES = new SimpleOperationDefinitionBuilder(Constants.LIST_SESSION_ATTRIBUTES, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.LIST) + .setReplyValueType(ModelType.PROPERTY) + .build(); + + static final OperationDefinition GET_SESSION_ATTRIBUTE = new SimpleOperationDefinitionBuilder(Constants.GET_SESSION_ATTRIBUTE, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .addParameter(ATTRIBUTE) + .setReplyType(ModelType.STRING) + .setReplyValueType(ModelType.PROPERTY) + .build(); + + static final OperationDefinition GET_SESSION_LAST_ACCESSED_TIME = new SimpleOperationDefinitionBuilder(Constants.GET_SESSION_LAST_ACCESSED_TIME, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.STRING) + .build(); + + + static final OperationDefinition GET_SESSION_LAST_ACCESSED_TIME_MILLIS = new SimpleOperationDefinitionBuilder(Constants.GET_SESSION_LAST_ACCESSED_TIME_MILLIS, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.LONG) + .build(); + + static final OperationDefinition GET_SESSION_CREATION_TIME = new SimpleOperationDefinitionBuilder(Constants.GET_SESSION_CREATION_TIME, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.STRING) + .build(); + + + static final OperationDefinition GET_SESSION_CREATION_TIME_MILLIS = new SimpleOperationDefinitionBuilder(Constants.GET_SESSION_CREATION_TIME_MILLIS, DEFAULT_RESOLVER) + .setRuntimeOnly() + .addParameter(SESSIOND_ID) + .setReplyType(ModelType.LONG) + .build(); + + private DeploymentDefinition() { + super(new Parameters(PathElement.pathElement(SUBSYSTEM, UndertowExtension.SUBSYSTEM_NAME), DEFAULT_RESOLVER) + .setFeature(false)); + } + + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerReadOnlyAttribute(CONTEXT_ROOT, null); + resourceRegistration.registerReadOnlyAttribute(VIRTUAL_HOST, null); + resourceRegistration.registerReadOnlyAttribute(SERVER, null); + for (SessionStat stat : SessionStat.values()) { + resourceRegistration.registerMetric(stat.definition, SessionManagerStatsHandler.getInstance()); + } + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + SessionManagerOperationHandler handler = new SessionManagerOperationHandler(); + + resourceRegistration.registerOperationHandler(INVALIDATE_SESSION, handler); + resourceRegistration.registerOperationHandler(LIST_SESSIONS, handler); + resourceRegistration.registerOperationHandler(LIST_SESSION_ATTRIBUTE_NAMES, handler); + resourceRegistration.registerOperationHandler(LIST_SESSION_ATTRIBUTES, handler); + resourceRegistration.registerOperationHandler(GET_SESSION_ATTRIBUTE, handler); + resourceRegistration.registerOperationHandler(GET_SESSION_LAST_ACCESSED_TIME, handler); + resourceRegistration.registerOperationHandler(GET_SESSION_LAST_ACCESSED_TIME_MILLIS, handler); + resourceRegistration.registerOperationHandler(GET_SESSION_CREATION_TIME, handler); + resourceRegistration.registerOperationHandler(GET_SESSION_CREATION_TIME_MILLIS, handler); + } + + static class SessionManagerOperationHandler extends AbstractRuntimeOnlyHandler { + + @Override + protected void executeRuntimeStep(OperationContext operationContext, ModelNode modelNode) throws OperationFailedException { + ModelNode result = new ModelNode(); + SessionManager sessionManager = getSessionManager(operationContext, modelNode); + + String name = modelNode.get(OP).asString(); + //list-sessions does not take a session id param + if (name.equals(Constants.LIST_SESSIONS)) { + result.setEmptyList(); + Set sessions = sessionManager.getAllSessions(); + for (String s : sessions) { + result.add(s); + } + operationContext.getResult().set(result); + return; + } + String sessionId = SESSIOND_ID.resolveModelAttribute(operationContext, modelNode).asString(); + Session session = sessionManager.getSession(sessionId); + if (session == null && !name.equals(Constants.INVALIDATE_SESSION)) { + throw UndertowLogger.ROOT_LOGGER.sessionNotFound(sessionId); + } + + switch (name) { + case Constants.INVALIDATE_SESSION: { + if(session == null) { + result.set(false); + } else { + session.invalidate(null); + result.set(true); + } + break; + } + case Constants.LIST_SESSION_ATTRIBUTE_NAMES: { + result.setEmptyList(); + Set sessions = session.getAttributeNames(); + for (String s : sessions) { + result.add(s); + } + break; + } + case Constants.LIST_SESSION_ATTRIBUTES: { + result.setEmptyList(); + Set sessions = session.getAttributeNames(); + for (String s : sessions) { + Object attribute = session.getAttribute(s); + ModelNode m = new ModelNode(); + if (attribute != null) { + m.set(attribute.toString()); + } + result.add(new Property(s, m)); + } + break; + } + case Constants.GET_SESSION_ATTRIBUTE: { + String a = ATTRIBUTE.resolveModelAttribute(operationContext, modelNode).asString(); + Object attribute = session.getAttribute(a); + if (attribute != null) { + result.set(attribute.toString()); + } + break; + } + case Constants.GET_SESSION_LAST_ACCESSED_TIME: { + long accessTime = session.getLastAccessedTime(); + result.set(DateTimeFormatter.ISO_DATE_TIME + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(accessTime))); + break; + } + case Constants.GET_SESSION_LAST_ACCESSED_TIME_MILLIS: { + long accessTime = session.getLastAccessedTime(); + result.set(accessTime); + break; + } + case Constants.GET_SESSION_CREATION_TIME: { + long accessTime = session.getCreationTime(); + result.set(DateTimeFormatter.ISO_DATE_TIME + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(accessTime))); + break; + } + case Constants.GET_SESSION_CREATION_TIME_MILLIS: { + long accessTime = session.getCreationTime(); + result.set(accessTime); + break; + } + } + + operationContext.getResult().set(result); + } + } + + static class SessionManagerStatsHandler extends AbstractRuntimeOnlyHandler { + + static SessionManagerStatsHandler INSTANCE = new SessionManagerStatsHandler(); + + private SessionManagerStatsHandler() { + } + + public static SessionManagerStatsHandler getInstance() { + return INSTANCE; + } + + @Override + protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { + + final PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.OP_ADDR)); + + final Resource web = context.readResourceFromRoot(address.subAddress(0, address.size()), false); + final ModelNode subModel = web.getModel(); + + final String host = VIRTUAL_HOST.resolveModelAttribute(context, subModel).asString(); + final String path = CONTEXT_ROOT.resolveModelAttribute(context, subModel).asString(); + final String server = SERVER.resolveModelAttribute(context, subModel).asString(); + + SessionStat stat = SessionStat.getStat(operation.require(ModelDescriptionConstants.NAME).asString()); + + if (stat == null) { + context.getFailureDescription().set(UndertowLogger.ROOT_LOGGER.unknownMetric(operation.require(ModelDescriptionConstants.NAME).asString())); + } else { + ModelNode result = new ModelNode(); + final ServiceController controller = context.getServiceRegistry(false).getService(UndertowService.deploymentServiceName(server, host, path)); + if (controller != null && controller.getState() != ServiceController.State.UP) {//check if deployment is active at all + return; + } + final UndertowDeploymentService deploymentService = (UndertowDeploymentService) controller.getService(); + if (deploymentService == null || deploymentService.getDeployment() == null) { //we might be in shutdown and it is possible + return; + } + Deployment deployment = deploymentService.getDeployment(); + SessionManager sessionManager = deployment.getSessionManager(); + SessionManagerStatistics sms = sessionManager.getStatistics(); + + switch (stat) { + case ACTIVE_SESSIONS: + result.set(sessionManager.getActiveSessions().size()); + break; + case EXPIRED_SESSIONS: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getExpiredSessionCount()); + } + break; + case MAX_ACTIVE_SESSIONS: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getMaxActiveSessions()); + } + break; + case SESSIONS_CREATED: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getCreatedSessionCount()); + } + break; + //case DUPLICATED_SESSION_IDS: + // result.set(sm.getDuplicates()); + // break; + case SESSION_AVG_ALIVE_TIME: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getAverageSessionAliveTime() / 1000); + } + break; + case SESSION_MAX_ALIVE_TIME: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getMaxSessionAliveTime() / 1000); + } + break; + case REJECTED_SESSIONS: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getRejectedSessions()); + } + break; + case HIGHEST_SESSION_COUNT: + if (sms == null) { + result.set(0); + } else { + result.set((int) sms.getHighestSessionCount()); + } + break; + default: + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.unknownMetric(stat)); + } + context.getResult().set(result); + } + } + } + + private static SessionManager getSessionManager(OperationContext context, ModelNode operation) throws OperationFailedException { + final PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.OP_ADDR)); + final Resource web = context.readResourceFromRoot(address.subAddress(0, address.size()), false); + final ModelNode subModel = web.getModel(); + final String host = VIRTUAL_HOST.resolveModelAttribute(context, subModel).asString(); + final String path = CONTEXT_ROOT.resolveModelAttribute(context, subModel).asString(); + final String server = SERVER.resolveModelAttribute(context, subModel).asString(); + + final UndertowDeploymentService deploymentService; + final ServiceController controller = context.getServiceRegistry(false).getService(UndertowService.deploymentServiceName(server, host, path)); + if (controller != null && controller.getState() != ServiceController.State.UP) {//check if deployment is active at all + throw UndertowLogger.ROOT_LOGGER.sessionManagerNotAvailable(); + } else { + deploymentService = (UndertowDeploymentService) controller.getService(); + if (deploymentService == null || deploymentService.getDeployment() == null) { //we might be in shutdown and it is possible + throw UndertowLogger.ROOT_LOGGER.sessionManagerNotAvailable(); + } + } + Deployment deployment = deploymentService.getDeployment(); + return deployment.getSessionManager(); + } + + public enum SessionStat { + ACTIVE_SESSIONS(new SimpleAttributeDefinitionBuilder("active-sessions", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + EXPIRED_SESSIONS(new SimpleAttributeDefinitionBuilder("expired-sessions", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + SESSIONS_CREATED(new SimpleAttributeDefinitionBuilder("sessions-created", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + //DUPLICATED_SESSION_IDS(new SimpleAttributeDefinition("duplicated-session-ids", ModelType.INT, false)), + SESSION_AVG_ALIVE_TIME(new SimpleAttributeDefinitionBuilder("session-avg-alive-time", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + SESSION_MAX_ALIVE_TIME(new SimpleAttributeDefinitionBuilder("session-max-alive-time", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + REJECTED_SESSIONS(new SimpleAttributeDefinitionBuilder("rejected-sessions", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + MAX_ACTIVE_SESSIONS(new SimpleAttributeDefinitionBuilder("max-active-sessions", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + HIGHEST_SESSION_COUNT(new SimpleAttributeDefinitionBuilder("highest-session-count", ModelType.INT) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()); + + private static final Map MAP = new HashMap<>(); + + static { + for (SessionStat stat : EnumSet.allOf(SessionStat.class)) { + MAP.put(stat.toString(), stat); + } + } + + final AttributeDefinition definition; + + SessionStat(final AttributeDefinition definition) { + this.definition = definition; + } + + @Override + public final String toString() { + return definition.getName(); + } + + public static synchronized SessionStat getStat(final String stringForm) { + return MAP.get(stringForm); + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentServletDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentServletDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentServletDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,159 @@ +/* + * 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.extension.undertow; + +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.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleListAttributeDefinition; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceController; +import org.wildfly.extension.undertow.deployment.UndertowDeploymentService; +import org.wildfly.extension.undertow.deployment.UndertowMetricsCollector; + +import io.undertow.server.handlers.MetricsHandler; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.ServletInfo; + +/** + * @author Tomaz Cerar + * @created 23.2.12 18:35 + */ +public class DeploymentServletDefinition extends SimpleResourceDefinition { + public static final DeploymentServletDefinition INSTANCE = new DeploymentServletDefinition(); + + static final SimpleAttributeDefinition SERVLET_NAME = new SimpleAttributeDefinitionBuilder("servlet-name", ModelType.STRING, false).setStorageRuntime().build(); + static final SimpleAttributeDefinition SERVLET_CLASS = new SimpleAttributeDefinitionBuilder("servlet-class", ModelType.STRING, false).setStorageRuntime().build(); + static final SimpleAttributeDefinition MAX_REQUEST_TIME = new SimpleAttributeDefinitionBuilder("max-request-time", ModelType.LONG, true).setStorageRuntime().build(); + static final SimpleAttributeDefinition MIN_REQUEST_TIME = new SimpleAttributeDefinitionBuilder("min-request-time", ModelType.LONG, true).setStorageRuntime().build(); + static final SimpleAttributeDefinition TOTAL_REQUEST_TIME = new SimpleAttributeDefinitionBuilder("total-request-time", ModelType.LONG, true).setStorageRuntime().build(); + static final SimpleAttributeDefinition REQUEST_COUNT = new SimpleAttributeDefinitionBuilder("request-count", ModelType.LONG, true).setStorageRuntime().build(); + static final SimpleListAttributeDefinition SERVLET_MAPPINGS = new SimpleListAttributeDefinition.Builder("mappings", new SimpleAttributeDefinitionBuilder("mapping", ModelType.STRING).setRequired(false).build()) + .setRequired(false) + .setStorageRuntime() + .build(); + + + private DeploymentServletDefinition() { + super(PathElement.pathElement("servlet"), + UndertowExtension.getResolver("deployment.servlet")); + } + + @Override + public void registerAttributes(ManagementResourceRegistration registration) { + registration.registerReadOnlyAttribute(SERVLET_NAME, null); + registration.registerReadOnlyAttribute(SERVLET_CLASS, null); + registration.registerMetric(MAX_REQUEST_TIME, new AbstractMetricsHandler() { + @Override + void handle(final ModelNode response, final String name, final MetricsHandler.MetricResult metricResult, final ServletInfo servlet) { + response.set((long) metricResult.getMaxRequestTime()); + } + }); + registration.registerMetric(MIN_REQUEST_TIME, new AbstractMetricsHandler() { + @Override + void handle(final ModelNode response, final String name, final MetricsHandler.MetricResult metricResult, final ServletInfo servlet) { + response.set((long) metricResult.getMinRequestTime()); + } + }); + registration.registerMetric(TOTAL_REQUEST_TIME, new AbstractMetricsHandler() { + @Override + void handle(final ModelNode response, final String name, final MetricsHandler.MetricResult metricResult, final ServletInfo servlet) { + response.set(metricResult.getTotalRequestTime()); + } + }); + registration.registerMetric(REQUEST_COUNT, new AbstractMetricsHandler() { + @Override + void handle(final ModelNode response, final String name, final MetricsHandler.MetricResult metricResult, final ServletInfo servlet) { + response.set(metricResult.getTotalRequests()); + } + }); + registration.registerMetric(SERVLET_MAPPINGS, new AbstractMetricsHandler() { + @Override + void handle(final ModelNode response, final String name, final MetricsHandler.MetricResult metricResult, final ServletInfo servlet) { + for (String mapping : servlet.getMappings()) { + response.add(mapping); + } + } + + @Override + void putDefault(ModelNode response) { + response.setEmptyList(); + } + }); + } + + abstract static class AbstractMetricsHandler implements OperationStepHandler { + + abstract void handle(ModelNode response, String name, MetricsHandler.MetricResult metricResult, ServletInfo infos); + + void putDefault(ModelNode response) { + response.set(0L); + } + + @Override + public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException { + final PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.OP_ADDR)); + + final Resource web = context.readResourceFromRoot(address.subAddress(0, address.size() - 1), false); + final ModelNode subModel = web.getModel(); + + final String host = DeploymentDefinition.VIRTUAL_HOST.resolveModelAttribute(context, subModel).asString(); + final String path = DeploymentDefinition.CONTEXT_ROOT.resolveModelAttribute(context, subModel).asString(); + final String server = DeploymentDefinition.SERVER.resolveModelAttribute(context, subModel).asString(); + + context.addStep(new OperationStepHandler() { + @Override + public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException { + final ServiceController deploymentServiceController = context.getServiceRegistry(false).getService(UndertowService.deploymentServiceName(server, host, path)); + if (deploymentServiceController == null) { + return; + } + final UndertowDeploymentService deploymentService = (UndertowDeploymentService) deploymentServiceController.getService(); + final DeploymentInfo deploymentInfo = deploymentService.getDeploymentInfoInjectedValue().getValue(); + final UndertowMetricsCollector collector = (UndertowMetricsCollector)deploymentInfo.getMetricsCollector(); + + final String name = address.getLastElement().getValue(); + final ServletInfo servlet = deploymentInfo.getServlets().get(name); + final ModelNode response = new ModelNode(); + MetricsHandler.MetricResult result = collector != null ? collector.getMetrics(name) : null; + if (result == null) { + putDefault(response); + } else { + handle(response, name, result, servlet); + } + context.getResult().set(response); + } + }, OperationContext.Stage.RUNTIME); + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentWebSocketDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentWebSocketDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/DeploymentWebSocketDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,54 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelType; + +/** + * @author Stuart Douglas + */ +public class DeploymentWebSocketDefinition extends SimpleResourceDefinition { + public static final DeploymentWebSocketDefinition INSTANCE = new DeploymentWebSocketDefinition(); + + static final SimpleAttributeDefinition PATH = new SimpleAttributeDefinitionBuilder("path", ModelType.STRING, false).setStorageRuntime().build(); + static final SimpleAttributeDefinition ENDPOINT_CLASS = new SimpleAttributeDefinitionBuilder("endpoint-class", ModelType.STRING, false).setStorageRuntime().build(); + + + + private DeploymentWebSocketDefinition() { + super(PathElement.pathElement("websocket"), + UndertowExtension.getResolver("deployment.websocket")); + } + + @Override + public void registerAttributes(ManagementResourceRegistration registration) { + registration.registerReadOnlyAttribute(PATH, null); + registration.registerReadOnlyAttribute(ENDPOINT_CLASS, null); + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/DiskBasedModularPersistentSessionManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/DiskBasedModularPersistentSessionManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/DiskBasedModularPersistentSessionManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,134 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.marshalling.InputStreamByteInput; +import org.jboss.marshalling.Marshaller; +import org.jboss.marshalling.OutputStreamByteOutput; +import org.jboss.marshalling.Unmarshaller; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.IoUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Map; + +/** + * Persistent session manager that stores persistent session information to disk + * + * @author Stuart Douglas + */ +public class DiskBasedModularPersistentSessionManager extends AbstractPersistentSessionManager { + private final String path; + private final String pathRelativeTo; + private File baseDir; + private PathManager.Callback.Handle callbackHandle; + + private final InjectedValue pathManager = new InjectedValue(); + + public DiskBasedModularPersistentSessionManager(String path, String pathRelativeTo) { + this.path = path; + this.pathRelativeTo = pathRelativeTo; + } + + @Override + public synchronized void stop(StopContext stopContext) { + super.stop(stopContext); + if (callbackHandle != null) { + callbackHandle.remove(); + } + } + + @Override + public synchronized void start(StartContext startContext) throws StartException { + super.start(startContext); + if (pathRelativeTo != null) { + callbackHandle = pathManager.getValue().registerCallback(pathRelativeTo, PathManager.ReloadServerCallback.create(), PathManager.Event.UPDATED, PathManager.Event.REMOVED); + } + baseDir = new File(pathManager.getValue().resolveRelativePathEntry(path, pathRelativeTo)); + if (!baseDir.exists()) { + if (!baseDir.mkdirs()) { + throw UndertowLogger.ROOT_LOGGER.failedToCreatePersistentSessionDir(baseDir); + } + } + if (!baseDir.isDirectory()) { + throw UndertowLogger.ROOT_LOGGER.invalidPersistentSessionDir(baseDir); + } + } + + + @Override + protected void persistSerializedSessions(String deploymentName, Map serializedData) throws IOException { + File file = new File(baseDir, deploymentName); + FileOutputStream out = new FileOutputStream(file, false); + try { + Marshaller marshaller = createMarshaller(); + try { + marshaller.start(new OutputStreamByteOutput(out)); + marshaller.writeObject(serializedData); + marshaller.finish(); + } finally { + marshaller.close(); + } + } finally { + IoUtils.safeClose(out); + } + } + + @Override + protected Map loadSerializedSessions(String deploymentName) throws IOException { + File file = new File(baseDir, deploymentName); + if (!file.exists()) { + return null; + } + FileInputStream in = new FileInputStream(file); + try { + Unmarshaller unMarshaller = createUnmarshaller(); + try { + try { + unMarshaller.start(new InputStreamByteInput(in)); + return (Map) unMarshaller.readObject(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } finally { + unMarshaller.finish(); + } + } finally { + unMarshaller.close(); + } + } finally { + IoUtils.safeClose(in); + } + + } + + public InjectedValue getPathManager() { + return pathManager; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventInvoker.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventInvoker.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/EventInvoker.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,34 @@ +/* + * 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.extension.undertow; + +/** + * Implementation of this class knows how to invoke an event on the {@link UndertowEventListener}. + * + * @author Radoslav Husar + * @since 8.0 + */ +public interface EventInvoker { + + void invoke(UndertowEventListener listener); +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/FilterLocation.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/FilterLocation.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/FilterLocation.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,34 @@ +/* + * 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.extension.undertow; + +/** + * @author Stuart Douglas + */ +public interface FilterLocation { + + void addFilter(UndertowFilter filterRef); + + void removeFilter(UndertowFilter filterRef); + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Handler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Handler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Handler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,42 @@ +/* + * 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.extension.undertow; + +import java.util.Collection; + +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.dmr.ModelNode; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public interface Handler { + Collection getAttributes(); + + Class getHandlerClass(); + + HttpHandler createHttpHandler(final Predicate predicate, final ModelNode model, final HttpHandler next); + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Host.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Host.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Host.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,417 @@ +/* + * 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.extension.undertow; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +import io.undertow.Handlers; +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.PathHandler; +import io.undertow.server.handlers.resource.PathResourceManager; +import io.undertow.server.handlers.resource.ResourceHandler; +import io.undertow.server.handlers.resource.ResourceManager; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.util.CopyOnWriteMap; +import io.undertow.util.Methods; +import org.jboss.as.controller.ControlledProcessState; +import org.jboss.as.controller.ControlledProcessStateService; +import org.jboss.as.server.suspend.ServerActivity; +import org.jboss.as.server.suspend.ServerActivityCallback; +import org.jboss.as.server.suspend.SuspendController; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.deployment.GateHandlerWrapper; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.manager.WildFlySecurityManager; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + * @author Radoslav Husar + */ +public class Host implements Service, FilterLocation { + private final PathHandler pathHandler = new PathHandler(); + private volatile HttpHandler rootHandler = null; + private final Set allAliases; + private final String name; + private final String defaultWebModule; + private final InjectedValue server = new InjectedValue<>(); + private final InjectedValue undertowService = new InjectedValue<>(); + private volatile AccessLogService accessLogService; + private final List filters = new CopyOnWriteArrayList<>(); + private final Set deployments = new CopyOnWriteArraySet<>(); + private final Map locations = new CopyOnWriteMap<>(); + private final Map additionalAuthenticationMechanisms = new ConcurrentHashMap<>(); + private final HostRootHandler hostRootHandler = new HostRootHandler(); + private final InjectedValue controlledProcessStateServiceInjectedValue = new InjectedValue<>(); + private volatile GateHandlerWrapper gateHandlerWrapper; + private final DefaultResponseCodeHandler defaultHandler; + private final boolean queueRequestsOnStart; + private final int defaultResponseCode; + + private final InjectedValue suspendControllerInjectedValue = new InjectedValue<>(); + + + ServerActivity suspendListener = new ServerActivity() { + @Override + public void preSuspend(ServerActivityCallback listener) { + defaultHandler.setSuspended(true); + listener.done(); + } + + @Override + public void suspended(ServerActivityCallback listener) { + listener.done(); + } + + @Override + public void resume() { + defaultHandler.setSuspended(false); + } + }; + + public Host(final String name, final List aliases, final String defaultWebModule, final int defaultResponseCode, final boolean queueRequestsOnStart ) { + this.name = name; + this.defaultWebModule = defaultWebModule; + Set hosts = new HashSet<>(aliases.size() + 1); + hosts.add(name); + hosts.addAll(aliases); + allAliases = Collections.unmodifiableSet(hosts); + this.queueRequestsOnStart = queueRequestsOnStart; + this.defaultHandler = new DefaultResponseCodeHandler(defaultResponseCode); + this.defaultResponseCode = defaultResponseCode; + this.setupDefaultResponseCodeHandler(); + } + + private String getDeployedContextPath(DeploymentInfo deploymentInfo) { + return "".equals(deploymentInfo.getContextPath()) ? "/" : deploymentInfo.getContextPath(); + } + + @Override + public void start(StartContext context) throws StartException { + suspendControllerInjectedValue.getValue().registerActivity(suspendListener); + if(suspendControllerInjectedValue.getValue().getState() == SuspendController.State.RUNNING) { + defaultHandler.setSuspended(false); + } else { + defaultHandler.setSuspended(true); + } + ControlledProcessStateService controlledProcessStateService = controlledProcessStateServiceInjectedValue.getValue(); + //may be null for tests + if(controlledProcessStateService != null && controlledProcessStateService.getCurrentState() == ControlledProcessState.State.STARTING) { + gateHandlerWrapper = new GateHandlerWrapper(queueRequestsOnStart ? -1 : defaultResponseCode); + controlledProcessStateService.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + controlledProcessStateService.removePropertyChangeListener(this); + if(gateHandlerWrapper != null) { + gateHandlerWrapper.open(); + gateHandlerWrapper = null; + } + rootHandler = null; + } + }); + } + server.getValue().registerHost(this); + UndertowLogger.ROOT_LOGGER.hostStarting(name); + } + + private HttpHandler configureRootHandler() { + AccessLogService logService = accessLogService; + HttpHandler rootHandler = pathHandler; + + ArrayList filters = new ArrayList<>(this.filters); + + //handle options * requests + rootHandler = new OptionsHandler(rootHandler); + + //handle requests that use the Expect: 100-continue header + rootHandler = Handlers.httpContinueRead(rootHandler); + + rootHandler = LocationService.configureHandlerChain(rootHandler, filters); + if (logService != null) { + rootHandler = logService.configureAccessLogHandler(rootHandler); + } + + // handle .well-known requests from ACME certificate authorities + String path = WildFlySecurityManager.getPropertyPrivileged("jboss.home.dir", "."); + Path base; + try { + base = Paths.get(path).normalize().toRealPath(); + } catch (IOException e) { + throw new RuntimeException(e); + } + final int cacheBufferSize = 1024; + final int cacheBuffers = 1024; + PathResourceManager resourceManager = new PathResourceManager(base, cacheBufferSize * cacheBuffers, true, false); + rootHandler = new AcmeResourceHandler(resourceManager, rootHandler); + + GateHandlerWrapper gateHandlerWrapper = this.gateHandlerWrapper; + if(gateHandlerWrapper != null) { + rootHandler = gateHandlerWrapper.wrap(rootHandler); + } + return rootHandler; + } + + @Override + public void stop(StopContext context) { + server.getValue().unregisterHost(this); + pathHandler.clearPaths(); + if(gateHandlerWrapper != null) { + gateHandlerWrapper.open(); + gateHandlerWrapper = null; + } + UndertowLogger.ROOT_LOGGER.hostStopping(name); + suspendControllerInjectedValue.getValue().unRegisterActivity(suspendListener); + } + + @Override + public Host getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + protected InjectedValue getServerInjection() { + return server; + } + + void setAccessLogService(AccessLogService service) { + this.accessLogService = service; + rootHandler = null; + } + + public Server getServer() { + return server.getValue(); + } + + protected InjectedValue getUndertowService() { + return undertowService; + } + + public Set getAllAliases() { + return allAliases; + } + + public String getName() { + return name; + } + + protected HttpHandler getRootHandler() { + return hostRootHandler; + } + + List getFilters() { + return Collections.unmodifiableList(filters); + } + + protected HttpHandler getOrCreateRootHandler() { + HttpHandler root = rootHandler; + if(root == null) { + synchronized (this) { + root = rootHandler; + if(root == null) { + return rootHandler = configureRootHandler(); + } + } + } + return root; + } + + public String getDefaultWebModule() { + return defaultWebModule; + } + + public void registerDeployment(final Deployment deployment, HttpHandler handler) { + DeploymentInfo deploymentInfo = deployment.getDeploymentInfo(); + String path = getDeployedContextPath(deploymentInfo); + registerHandler(path, handler); + deployments.add(deployment); + UndertowLogger.ROOT_LOGGER.registerWebapp(path, getServer().getName()); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStart(deployment, Host.this)); + } + + public void unregisterDeployment(final Deployment deployment) { + DeploymentInfo deploymentInfo = deployment.getDeploymentInfo(); + String path = getDeployedContextPath(deploymentInfo); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStop(deployment, Host.this)); + unregisterHandler(path); + deployments.remove(deployment); + UndertowLogger.ROOT_LOGGER.unregisterWebapp(path, getServer().getName()); + } + + void registerLocation(String path) { + String realPath = path.startsWith("/") ? path : "/" + path; + locations.put(realPath, null); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStart(realPath, Host.this)); + } + + void unregisterLocation(String path) { + String realPath = path.startsWith("/") ? path : "/" + path; + locations.remove(realPath); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStop(realPath, Host.this)); + } + + public void registerHandler(String path, HttpHandler handler) { + pathHandler.addPrefixPath(path, handler); + } + + public void unregisterHandler(String path) { + pathHandler.removePrefixPath(path); + // if there is registered location for given path, serve it from now on + LocationService location = locations.get(path); + if (location != null) { + pathHandler.addPrefixPath(location.getLocationPath(), location.getLocationHandler()); + } + // else serve the default response code + else if (path.equals("/")) { + this.setupDefaultResponseCodeHandler(); + } + } + + void registerLocation(LocationService location) { + locations.put(location.getLocationPath(), location); + registerHandler(location.getLocationPath(), location.getLocationHandler()); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStart(location.getLocationPath(), Host.this)); + } + + void unregisterLocation(LocationService location) { + locations.remove(location.getLocationPath()); + unregisterHandler(location.getLocationPath()); + undertowService.getValue().fireEvent(listener -> listener.onDeploymentStop(location.getLocationPath(), Host.this)); + } + + public Set getLocations() { + return Collections.unmodifiableSet(locations.keySet()); + } + + /** + * @return set of currently registered {@link Deployment}s on this host + */ + public Set getDeployments() { + return Collections.unmodifiableSet(deployments); + } + + void registerAdditionalAuthenticationMechanism(String name, AuthenticationMechanism authenticationMechanism){ + additionalAuthenticationMechanisms.put(name, authenticationMechanism); + } + + void unregisterAdditionalAuthenticationMechanism(String name){ + additionalAuthenticationMechanisms.remove(name); + } + + public Map getAdditionalAuthenticationMechanisms() { + return new LinkedHashMap<>(additionalAuthenticationMechanisms); + } + + public InjectedValue getSuspendControllerInjectedValue() { + return suspendControllerInjectedValue; + } + + @Override + public void addFilter(UndertowFilter filterRef) { + filters.add(filterRef); + rootHandler = null; + } + + @Override + public void removeFilter(UndertowFilter filterRef) { + filters.remove(filterRef); + rootHandler = null; + } + + protected void setupDefaultResponseCodeHandler(){ + if(this.defaultHandler != null){ + this.registerHandler("/", this.defaultHandler); + } + } + + InjectedValue getControlledProcessStateServiceInjectedValue() { + return controlledProcessStateServiceInjectedValue; + } + + private static final class OptionsHandler implements HttpHandler { + + private final HttpHandler next; + + private OptionsHandler(HttpHandler next) { + this.next = next; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if(exchange.getRequestMethod().equals(Methods.OPTIONS) && + exchange.getRelativePath().equals("*")) { + //handle the OPTIONS requests + //basically just return an empty response + exchange.endExchange(); + return; + } + next.handleRequest(exchange); + } + } + + private static final class AcmeResourceHandler extends ResourceHandler { + private static final String ACME_CHALLENGE_REGEX = "/\\.well-known/acme-challenge/[A-Za-z0-9_-]+"; + + private final HttpHandler next; + + private AcmeResourceHandler(ResourceManager resourceManager, HttpHandler next) { + super(resourceManager, next); + this.next = next; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if (exchange.getRequestMethod().equals(Methods.GET) && exchange.getRelativePath().matches(ACME_CHALLENGE_REGEX)) { + super.handleRequest(exchange); + } else { + next.handleRequest(exchange); + } + } + } + + private class HostRootHandler implements HttpHandler { + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + getOrCreateRootHandler().handleRequest(exchange); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,158 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.HostDefinition.HOST_CAPABILITY; +import static org.wildfly.extension.undertow.ServerDefinition.SERVER_CAPABILITY; + +import java.util.LinkedList; +import java.util.List; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.ControlledProcessStateService; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.ProcessType; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.server.mgmt.UndertowHttpManagementService; +import org.jboss.as.server.mgmt.domain.HttpManagement; +import org.jboss.as.server.suspend.SuspendController; +import org.jboss.as.web.host.CommonWebServer; +import org.jboss.as.web.host.WebHost; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceController.Mode; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.requestcontroller.RequestController; +import org.wildfly.extension.undertow.deployment.DefaultDeploymentMappingProvider; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class HostAdd extends AbstractAddStepHandler { + + static final HostAdd INSTANCE = new HostAdd(); + + private HostAdd() { + super(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE, HostDefinition.DEFAULT_RESPONSE_CODE, HostDefinition.DISABLE_CONSOLE_REDIRECT, HostDefinition.QUEUE_REQUESTS_ON_START); + } + + @Override + protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + super.recordCapabilitiesAndRequirements(context, operation, resource); + + String ourCap = HOST_CAPABILITY.getDynamicName(context.getCurrentAddress()); + String serverCap = SERVER_CAPABILITY.getDynamicName(context.getCurrentAddress().getParent()); + context.registerAdditionalCapabilityRequirement(serverCap, ourCap, null); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final PathAddress serverAddress = address.getParent(); + final PathAddress subsystemAddress = serverAddress.getParent(); + final ModelNode subsystemModel = Resource.Tools.readModel(context.readResourceFromRoot(subsystemAddress, false), 0); + final ModelNode serverModel = Resource.Tools.readModel(context.readResourceFromRoot(serverAddress, false), 0); + + final String name = address.getLastElement().getValue(); + final List aliases = HostDefinition.ALIAS.unwrap(context, model); + final String defaultWebModule = HostDefinition.DEFAULT_WEB_MODULE.resolveModelAttribute(context, model).asString(); + final String defaultServerName = UndertowRootDefinition.DEFAULT_SERVER.resolveModelAttribute(context, subsystemModel).asString(); + final String defaultHostName = ServerDefinition.DEFAULT_HOST.resolveModelAttribute(context, serverModel).asString(); + final String serverName = serverAddress.getLastElement().getValue(); + final boolean isDefaultHost = defaultServerName.equals(serverName) && name.equals(defaultHostName); + final int defaultResponseCode = HostDefinition.DEFAULT_RESPONSE_CODE.resolveModelAttribute(context, model).asInt(); + final boolean enableConsoleRedirect = !HostDefinition.DISABLE_CONSOLE_REDIRECT.resolveModelAttribute(context, model).asBoolean(); + final boolean queueRequestsOnStart = HostDefinition.QUEUE_REQUESTS_ON_START.resolveModelAttribute(context, model).asBoolean(); + DefaultDeploymentMappingProvider.instance().addMapping(defaultWebModule, serverName, name); + + final ServiceName virtualHostServiceName = HostDefinition.HOST_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName(); + + final Host service = new Host(name, aliases == null ? new LinkedList<>(): aliases, defaultWebModule, defaultResponseCode, queueRequestsOnStart); + + final ServiceBuilder builder = context.getCapabilityServiceTarget().addCapability(HostDefinition.HOST_CAPABILITY, service) + .addCapabilityRequirement(Capabilities.CAPABILITY_SERVER, Server.class, service.getServerInjection(), serverName) + .addCapabilityRequirement(Capabilities.CAPABILITY_UNDERTOW, UndertowService.class, service.getUndertowService()) + .addDependency(SuspendController.SERVICE_NAME, SuspendController.class, service.getSuspendControllerInjectedValue()) + .addDependency(ControlledProcessStateService.SERVICE_NAME, ControlledProcessStateService.class, service.getControlledProcessStateServiceInjectedValue()); + + builder.setInitialMode(Mode.ON_DEMAND); + + if (isDefaultHost) { + addCommonHost(context, aliases, serverName, virtualHostServiceName); + builder.addAliases(UndertowService.DEFAULT_HOST);//add alias for default host of default server service + } + //this is workaround for a bit so old service names still work! + builder.addAliases(UndertowService.virtualHostName(serverName, name)); + builder.install(); + + if (enableConsoleRedirect) { + // Setup the web console redirect + final ServiceName consoleRedirectName = UndertowService.consoleRedirectServiceName(serverName, name); + // A standalone server is the only process type with a console redirect + if (context.getProcessType() == ProcessType.STANDALONE_SERVER) { + final ConsoleRedirectService redirectService = new ConsoleRedirectService(); + final ServiceBuilder redirectBuilder = context.getServiceTarget().addService(consoleRedirectName, redirectService) + .addDependency(UndertowHttpManagementService.SERVICE_NAME, HttpManagement.class, redirectService.getHttpManagementInjector()) + .addDependency(virtualHostServiceName, Host.class, redirectService.getHostInjector()) + .setInitialMode(Mode.PASSIVE); + redirectBuilder.install(); + } else { + // Other process types don't have a console, not depending on the UndertowHttpManagementService should + // result in a null dependency in the service and redirect accordingly + final ConsoleRedirectService redirectService = new ConsoleRedirectService(); + final ServiceBuilder redirectBuilder = context.getServiceTarget().addService(consoleRedirectName, redirectService) + .addDependency(virtualHostServiceName, Host.class, redirectService.getHostInjector()) + .setInitialMode(Mode.PASSIVE); + redirectBuilder.install(); + } + } + } + + private ServiceController addCommonHost(OperationContext context, List aliases, + String serverName, ServiceName virtualHostServiceName) { + WebHostService service = new WebHostService(); + final CapabilityServiceBuilder builder = context.getCapabilityServiceTarget() + .addCapability(WebHost.CAPABILITY, service) + .addCapabilityRequirement(Capabilities.CAPABILITY_SERVER, Server.class, service.getServer(), serverName) + .addCapabilityRequirement(CommonWebServer.CAPABILITY_NAME, CommonWebServer.class) + .addDependency(virtualHostServiceName, Host.class, service.getHost()); + + if(context.hasOptionalCapability(Capabilities.REF_REQUEST_CONTROLLER, null, null)) { + builder.addCapabilityRequirement(Capabilities.REF_REQUEST_CONTROLLER, RequestController.class, service.getRequestControllerInjectedValue()); + } + + builder.addAliases(WebHost.SERVICE_NAME.append(context.getCurrentAddressValue())); + if (aliases != null) { + for (String alias : aliases) { + builder.addAliases(WebHost.SERVICE_NAME.append(alias)); + } + } + + builder.setInitialMode(Mode.PASSIVE); + return builder.install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,123 @@ +/* + * 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.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.web.host.WebHost; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class HostDefinition extends PersistentResourceDefinition { + + static final RuntimeCapability HOST_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_HOST, true, Host.class) + .addRequirements(Capabilities.CAPABILITY_UNDERTOW) + //addDynamicRequirements(Capabilities.CAPABILITY_SERVER) -- has no function so don't use it + .setDynamicNameMapper(pathElements -> new String[]{ + pathElements.getParent().getLastElement().getValue(), + pathElements.getLastElement().getValue()}) + .build(); + + + static final StringListAttributeDefinition ALIAS = new StringListAttributeDefinition.Builder(Constants.ALIAS) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setElementValidator(new StringLengthValidator(1)) + .setAllowExpression(true) + .setAttributeParser(AttributeParser.COMMA_DELIMITED_STRING_LIST) + .setAttributeMarshaller(AttributeMarshaller.COMMA_STRING_LIST) + .build(); + static final SimpleAttributeDefinition DEFAULT_WEB_MODULE = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_WEB_MODULE, ModelType.STRING, true) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1, true, false)) + .setDefaultValue(new ModelNode("ROOT.war")) + .build(); + + static final SimpleAttributeDefinition DEFAULT_RESPONSE_CODE = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_RESPONSE_CODE, ModelType.INT, true) + .setRestartAllServices() + .setValidator(new IntRangeValidator(400, 599, true, true)) + .setDefaultValue(new ModelNode(404)) + .setAllowExpression(true) + .build(); + static final SimpleAttributeDefinition DISABLE_CONSOLE_REDIRECT = new SimpleAttributeDefinitionBuilder("disable-console-redirect", ModelType.BOOLEAN, true) + .setRestartAllServices() + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + static final SimpleAttributeDefinition QUEUE_REQUESTS_ON_START = new SimpleAttributeDefinitionBuilder("queue-requests-on-start", ModelType.BOOLEAN, true) + .setRestartAllServices() + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + + static final HostDefinition INSTANCE = new HostDefinition(); + private static final Collection ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(ALIAS, DEFAULT_WEB_MODULE, DEFAULT_RESPONSE_CODE, DISABLE_CONSOLE_REDIRECT, QUEUE_REQUESTS_ON_START)); + private static final List CHILDREN = Collections.unmodifiableList(Arrays.asList( + LocationDefinition.INSTANCE, + AccessLogDefinition.INSTANCE, + FilterRefDefinition.INSTANCE, + HttpInvokerDefinition.INSTANCE, + new HostSingleSignOnDefinition() + )); + + private HostDefinition() { + super(UndertowExtension.HOST_PATH, UndertowExtension.getResolver(Constants.HOST), + HostAdd.INSTANCE, + new HostRemove()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + public List getChildren() { + return CHILDREN; + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(HOST_CAPABILITY); + resourceRegistration.registerCapability(WebHost.CAPABILITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostRemove.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostRemove.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostRemove.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AbstractRemoveStepHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.web.host.WebHost; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.undertow.deployment.DefaultDeploymentMappingProvider; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class HostRemove extends AbstractRemoveStepHandler { + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final PathAddress parent = address.getParent(); + final String name = address.getLastElement().getValue(); + final String serverName = parent.getLastElement().getValue(); + final ServiceName virtualHostServiceName = HostDefinition.HOST_CAPABILITY.getCapabilityServiceName(serverName, name); + context.removeService(virtualHostServiceName); + final ServiceName consoleRedirectName = UndertowService.consoleRedirectServiceName(serverName, name); + context.removeService(consoleRedirectName); + final ServiceName commonHostName = WebHost.SERVICE_NAME.append(name); + context.removeService(commonHostName); + final String defaultWebModule = HostDefinition.DEFAULT_WEB_MODULE.resolveModelAttribute(context, model).asString(); + DefaultDeploymentMappingProvider.instance().removeMapping(defaultWebModule); + } + + protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + if (context.isResourceServiceRestartAllowed()) { + HostAdd.INSTANCE.performRuntime(context, operation, model); + } else { + context.revertReloadRequired(); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,50 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.clustering.controller.ResourceDescriptor; +import org.jboss.as.clustering.controller.SimpleResourceRegistration; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +/** + * @author Paul Ferraro + */ +public class HostSingleSignOnDefinition extends SingleSignOnDefinition { + + //we use a runtime API of Object as a hack, so we can check for the presence of the capability in a DUP + public static final RuntimeCapability HOST_SSO_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_HOST_SSO, true, new Object()) + .addRequirements(Capabilities.CAPABILITY_UNDERTOW) + .setServiceType(SingleSignOnService.class) + .setDynamicNameMapper(pathElements -> new String[]{ + pathElements.getParent().getParent().getLastElement().getValue(), + pathElements.getParent().getLastElement().getValue()}) + .build(); + + @Override + public void registerOperations(ManagementResourceRegistration registration) { + ResourceDescriptor descriptor = new ResourceDescriptor(this.getResourceDescriptionResolver()) + .addAttributes(SingleSignOnDefinition.Attribute.class).addCapabilities(() -> HOST_SSO_CAPABILITY); + new SimpleResourceRegistration(descriptor, new HostSingleSignOnServiceHandler()).register(registration); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnServiceHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnServiceHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HostSingleSignOnServiceHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,98 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.SingleSignOnDefinition.Attribute.COOKIE_NAME; +import static org.wildfly.extension.undertow.SingleSignOnDefinition.Attribute.DOMAIN; +import static org.wildfly.extension.undertow.SingleSignOnDefinition.Attribute.HTTP_ONLY; +import static org.wildfly.extension.undertow.SingleSignOnDefinition.Attribute.PATH; +import static org.wildfly.extension.undertow.SingleSignOnDefinition.Attribute.SECURE; + +import org.jboss.as.clustering.controller.ResourceServiceHandler; +import org.jboss.as.clustering.controller.SimpleCapabilityServiceConfigurator; +import org.jboss.as.clustering.dmr.ModelNodes; +import org.jboss.as.controller.CapabilityServiceTarget; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.undertow.security.sso.DistributableHostSingleSignOnManagerServiceConfiguratorProvider; + +import io.undertow.security.impl.InMemorySingleSignOnManager; +import io.undertow.security.impl.SingleSignOnManager; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + * @author Paul Ferraro + */ +class HostSingleSignOnServiceHandler implements ResourceServiceHandler { + + @Override + public void installServices(OperationContext context, ModelNode model) throws OperationFailedException { + PathAddress address = context.getCurrentAddress(); + PathAddress hostAddress = address.getParent(); + PathAddress serverAddress = hostAddress.getParent(); + String hostName = hostAddress.getLastElement().getValue(); + String serverName = serverAddress.getLastElement().getValue(); + + String domain = ModelNodes.optionalString(DOMAIN.resolveModelAttribute(context, model)).orElse(null); + String path = PATH.resolveModelAttribute(context, model).asString(); + boolean secure = SECURE.resolveModelAttribute(context, model).asBoolean(); + boolean httpOnly = HTTP_ONLY.resolveModelAttribute(context, model).asBoolean(); + String cookieName = COOKIE_NAME.resolveModelAttribute(context, model).asString(); + + ServiceName serviceName = UndertowService.ssoServiceName(serverName, hostName); + ServiceName virtualHostServiceName = HostDefinition.HOST_CAPABILITY.getCapabilityServiceName(serverName,hostName); + + CapabilityServiceTarget target = context.getCapabilityServiceTarget(); + + ServiceName managerServiceName = serviceName.append("manager"); + DistributableHostSingleSignOnManagerServiceConfiguratorProvider.INSTANCE.map(provider -> provider.getServiceConfigurator(managerServiceName, serverName, hostName)) + .orElse(new SimpleCapabilityServiceConfigurator<>(managerServiceName, new InMemorySingleSignOnManager())) + .configure(context).build(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + + SingleSignOnService service = new SingleSignOnService(domain, path, httpOnly, secure, cookieName); + target.addCapability(HostSingleSignOnDefinition.HOST_SSO_CAPABILITY, service) + .addAliases(serviceName) + .addDependency(virtualHostServiceName, Host.class, service.getHost()) + .addDependency(managerServiceName, SingleSignOnManager.class, service.getSingleSignOnSessionManager()) + .setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + } + + @Override + public void removeServices(OperationContext context, ModelNode model) throws OperationFailedException { + PathAddress address = context.getCurrentAddress(); + PathAddress hostAddress = address.getParent(); + PathAddress serverAddress = hostAddress.getParent(); + String hostName = hostAddress.getLastElement().getValue(); + String serverName = serverAddress.getLastElement().getValue(); + + ServiceName serviceName = UndertowService.ssoServiceName(serverName, hostName); + context.removeService(serviceName.append("manager")); + context.removeService(HostSingleSignOnDefinition.HOST_SSO_CAPABILITY.getCapabilityServiceName(address)); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,165 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.UndertowRootDefinition.HTTP_INVOKER_RUNTIME_CAPABILITY; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_HTTP_INVOKER_HOST; + +import java.util.Arrays; +import java.util.Collection; + +import io.undertow.server.handlers.PathHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.domain.management.SecurityRealm; +import org.jboss.as.domain.management.security.SecurityRealmService; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.wildfly.security.auth.server.HttpAuthenticationFactory; + +/** + * @author Stuart Douglas + */ +public class HttpInvokerDefinition extends PersistentResourceDefinition { + + static final RuntimeCapability HTTP_INVOKER_HOST_CAPABILITY = + RuntimeCapability.Builder.of(CAPABILITY_HTTP_INVOKER_HOST, true, Void.class) + .setDynamicNameMapper(address -> new String[]{ + address.getParent().getLastElement().getValue(), + address.getLastElement().getValue()}) + //.addDynamicRequirements(Capabilities.CAPABILITY_HOST) + .addRequirements(Capabilities.CAPABILITY_HTTP_INVOKER) + .build(); + + static final SimpleAttributeDefinition HTTP_AUTHENTICATION_FACTORY = new SimpleAttributeDefinitionBuilder(Constants.HTTP_AUTHENITCATION_FACTORY, ModelType.STRING, true) + .setValidator(new StringLengthValidator(1, true)) + .setRestartAllServices() + .setCapabilityReference(Capabilities.REF_HTTP_AUTHENTICATION_FACTORY) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.AUTHENTICATION_FACTORY_REF) + .setAlternatives(Constants.SECURITY_REALM) + .build(); + + + protected static final SimpleAttributeDefinition SECURITY_REALM = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_REALM, ModelType.STRING, true) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, false)) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SECURITY_REALM_REF) + .setAlternatives(Constants.HTTP_AUTHENITCATION_FACTORY) + .build(); + + protected static final SimpleAttributeDefinition PATH = new SimpleAttributeDefinitionBuilder(Constants.PATH, ModelType.STRING, true) + .setValidator(new StringLengthValidator(1)) + .setDefaultValue(new ModelNode("wildfly-services")) + .setRestartAllServices() + .build(); + + static final Collection ATTRIBUTES = Arrays.asList( + // IMPORTANT -- keep these in xsd order as this order controls marshalling + PATH, + HTTP_AUTHENTICATION_FACTORY, + SECURITY_REALM + ); + static final HttpInvokerDefinition INSTANCE = new HttpInvokerDefinition(); + + private HttpInvokerDefinition() { + super(new Parameters(UndertowExtension.PATH_HTTP_INVOKER, UndertowExtension.getResolver(Constants.HTTP_INVOKER)) + .setAddHandler(new HttpInvokerAdd()) + .setRemoveHandler(new HttpInvokerRemove()) + .setCapabilities(HTTP_INVOKER_HOST_CAPABILITY) + ); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + private static final class HttpInvokerAdd extends AbstractAddStepHandler { + + HttpInvokerAdd() { + super(ATTRIBUTES); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final PathAddress hostAddress = address.getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + String path = PATH.resolveModelAttribute(context, model).asString(); + String httpAuthenticationFactory = null; + String securityRealmString = null; + final ModelNode authFactory = HTTP_AUTHENTICATION_FACTORY.resolveModelAttribute(context, model); + final ModelNode securityRealm = SECURITY_REALM.resolveModelAttribute(context, model); + if (authFactory.isDefined()) { + httpAuthenticationFactory = authFactory.asString(); + } else if(securityRealm.isDefined()) { + securityRealmString = securityRealm.asString(); + } + + final HttpInvokerHostService service = new HttpInvokerHostService(path); + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + + final CapabilityServiceBuilder builder = context.getCapabilityServiceTarget() + .addCapability(HTTP_INVOKER_HOST_CAPABILITY, service) + .addCapabilityRequirement(HTTP_INVOKER_RUNTIME_CAPABILITY.getName(), PathHandler.class, service.getRemoteHttpInvokerServiceInjectedValue()) + .addCapabilityRequirement(Capabilities.CAPABILITY_HOST, Host.class, service.getHost(), serverName, hostName) + ; + + if (httpAuthenticationFactory != null) { + builder.addCapabilityRequirement(Capabilities.REF_HTTP_AUTHENTICATION_FACTORY, HttpAuthenticationFactory.class, service.getHttpAuthenticationFactoryInjectedValue(), httpAuthenticationFactory); + } else if(securityRealmString != null) { + final ServiceName realmServiceName = SecurityRealm.ServiceUtil.createServiceName(securityRealmString); + builder.addDependency(realmServiceName, SecurityRealmService.class, service.getRealmService()); + } + + builder.setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + } + } + + private static final class HttpInvokerRemove extends ServiceRemoveStepHandler { + + HttpInvokerRemove() { + super(new HttpInvokerAdd()); + } + + + @Override + protected ServiceName serviceName(String name, PathAddress address) { + return HTTP_INVOKER_HOST_CAPABILITY.getCapabilityServiceName(address); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerHostService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerHostService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpInvokerHostService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,152 @@ +/* + * 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.extension.undertow; + +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.jboss.as.domain.management.security.SecurityRealmService; +import org.jboss.as.web.session.SimpleRoutingSupport; +import org.jboss.as.web.session.SimpleSessionIdentifierCodec; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.elytron.web.undertow.server.ElytronContextAssociationHandler; +import org.wildfly.elytron.web.undertow.server.ElytronHttpExchange; +import org.wildfly.httpclient.common.ElytronIdentityHandler; +import org.wildfly.security.auth.server.HttpAuthenticationFactory; +import org.wildfly.security.auth.server.SecurityIdentity; +import org.wildfly.security.http.HttpServerAuthenticationMechanism; +import io.undertow.security.handlers.AuthenticationCallHandler; +import io.undertow.security.handlers.AuthenticationConstraintHandler; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.Cookie; +import io.undertow.server.handlers.PathHandler; + +/** + * @author Stuart Douglas + */ +class HttpInvokerHostService implements Service { + + private static final String JSESSIONID = "JSESSIONID"; + + private final String path; + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue httpAuthenticationFactoryInjectedValue = new InjectedValue<>(); + private final InjectedValue realmService = new InjectedValue<>(); + private final InjectedValue remoteHttpInvokerServiceInjectedValue = new InjectedValue<>(); + + public HttpInvokerHostService(String path) { + this.path = path; + } + + @Override + public void start(StartContext startContext) throws StartException { + HttpHandler handler = remoteHttpInvokerServiceInjectedValue.getValue(); + if(httpAuthenticationFactoryInjectedValue.getOptionalValue() != null) { + handler = secureAccess(handler, httpAuthenticationFactoryInjectedValue.getOptionalValue()); + } else if(realmService.getOptionalValue() != null) { + handler = secureAccess(handler, realmService.getOptionalValue().getHttpAuthenticationFactory()); + } + handler = setupRoutes(handler); + host.getValue().registerHandler(path, handler); + host.getValue().registerLocation(path); + } + + @Override + public void stop(StopContext stopContext) { + host.getValue().unregisterHandler(path); + host.getValue().unregisterLocation(path); + } + + private HttpHandler setupRoutes(HttpHandler handler) { + final SimpleSessionIdentifierCodec codec = new SimpleSessionIdentifierCodec(new SimpleRoutingSupport(), this.host.getValue().getServer().getRoute()); + return exchange -> { + exchange.addResponseCommitListener(ex -> { + Cookie cookie = ex.getResponseCookies().get(JSESSIONID); + if(cookie != null ) { + cookie.setValue(codec.encode(cookie.getValue())); + } + }); + handler.handleRequest(exchange); + }; + } + + private static HttpHandler secureAccess(HttpHandler domainHandler, final HttpAuthenticationFactory httpAuthenticationFactory) { + domainHandler = new AuthenticationCallHandler(domainHandler); + domainHandler = new AuthenticationConstraintHandler(domainHandler); + Supplier> mechanismSupplier = () -> + httpAuthenticationFactory.getMechanismNames().stream() + .map(s -> { + try { + return httpAuthenticationFactory.createMechanism(s); + } catch (Exception e) { + return null; + } + }) + .collect(Collectors.toList()); + domainHandler = ElytronContextAssociationHandler.builder() + .setNext(domainHandler) + .setMechanismSupplier(mechanismSupplier) + .setHttpExchangeSupplier(h -> new ElytronHttpExchange(h) { + + @Override + public void authenticationComplete(SecurityIdentity securityIdentity, String mechanismName) { + super.authenticationComplete(securityIdentity, mechanismName); + h.putAttachment(ElytronIdentityHandler.IDENTITY_KEY, securityIdentity); + } + + }) + .build(); + + return domainHandler; + } + + @Override + public HttpInvokerHostService getValue() throws IllegalStateException, IllegalArgumentException { + return null; + } + + public String getPath() { + return path; + } + + public InjectedValue getHost() { + return host; + } + + public InjectedValue getHttpAuthenticationFactoryInjectedValue() { + return httpAuthenticationFactoryInjectedValue; + } + + public InjectedValue getRemoteHttpInvokerServiceInjectedValue() { + return remoteHttpInvokerServiceInjectedValue; + } + + public InjectedValue getRealmService() { + return realmService; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,80 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.REF_SOCKET_BINDING; + +import io.undertow.server.ListenerRegistry; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.network.SocketBinding; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceName; +import org.xnio.OptionMap; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class HttpListenerAdd extends ListenerAdd { + + static final ServiceName REGISTRY_SERVICE_NAME = ServiceName.JBOSS.append("http", "listener", "registry"); + + HttpListenerAdd(ListenerResourceDefinition definition) { + super(definition); + } + + @Override + ListenerService createService(String name, final String serverName, final OperationContext context, ModelNode model, OptionMap listenerOptions, OptionMap socketOptions) throws OperationFailedException { + final boolean proxyProtocol = HttpListenerResourceDefinition.PROXY_PROTOCOL.resolveModelAttribute(context, model).asBoolean(); + final boolean certificateForwarding = HttpListenerResourceDefinition.CERTIFICATE_FORWARDING.resolveModelAttribute(context, model).asBoolean(); + final boolean proxyAddressForwarding = HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING.resolveModelAttribute(context, model).asBoolean(); + OptionMap.Builder listenerBuilder = OptionMap.builder().addAll(listenerOptions); + HttpListenerResourceDefinition.ENABLE_HTTP2.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11.resolveOption(context, model,listenerBuilder); + + + handleHttp2Options(context, model, listenerBuilder); + + return new HttpListenerService(name, serverName, listenerBuilder.getMap(), socketOptions, certificateForwarding, proxyAddressForwarding, proxyProtocol); + } + + static void handleHttp2Options(OperationContext context, ModelNode model, OptionMap.Builder listenerBuilder) throws OperationFailedException { + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE.resolveOption(context, model,listenerBuilder); + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE.resolveOption(context, model,listenerBuilder); + } + + @Override + void configureAdditionalDependencies(OperationContext context, CapabilityServiceBuilder serviceBuilder, ModelNode model, ListenerService service) throws OperationFailedException { + ModelNode redirectBindingRef = ListenerResourceDefinition.REDIRECT_SOCKET.resolveModelAttribute(context, model); + if (redirectBindingRef.isDefined()) { + ServiceName serviceName = context.getCapabilityServiceName(REF_SOCKET_BINDING, redirectBindingRef.asString(), SocketBinding.class); + serviceBuilder.addDependency(serviceName, SocketBinding.class, service.getRedirectSocket()); + } + serviceBuilder.addDependency(REGISTRY_SERVICE_NAME, ListenerRegistry.class, ((HttpListenerService) service).getHttpListenerRegistry()); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerResourceDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,168 @@ +/* + * 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.extension.undertow; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.http2.Http2Channel; + +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.IntRangeValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.io.OptionAttributeDefinition; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class HttpListenerResourceDefinition extends ListenerResourceDefinition { + protected static final HttpListenerResourceDefinition INSTANCE = new HttpListenerResourceDefinition(); + + + protected static final SimpleAttributeDefinition CERTIFICATE_FORWARDING = new SimpleAttributeDefinitionBuilder(Constants.CERTIFICATE_FORWARDING, ModelType.BOOLEAN) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition PROXY_ADDRESS_FORWARDING = new SimpleAttributeDefinitionBuilder("proxy-address-forwarding", ModelType.BOOLEAN) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final OptionAttributeDefinition ENABLE_HTTP2 = OptionAttributeDefinition.builder("enable-http2", UndertowOptions.ENABLE_HTTP2) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_ENABLE_PUSH = OptionAttributeDefinition.builder("http2-enable-push", UndertowOptions.HTTP2_SETTINGS_ENABLE_PUSH) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(true)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_HEADER_TABLE_SIZE = OptionAttributeDefinition.builder("http2-header-table-size", UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE_DEFAULT)) + .setValidator(new IntRangeValidator(1)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_INITIAL_WINDOW_SIZE = OptionAttributeDefinition.builder("http2-initial-window-size", UndertowOptions.HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_INITIAL_WINDOW_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_MAX_CONCURRENT_STREAMS = OptionAttributeDefinition.builder("http2-max-concurrent-streams", UndertowOptions.HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setValidator(new IntRangeValidator(1)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_MAX_FRAME_SIZE = OptionAttributeDefinition.builder("http2-max-frame-size", UndertowOptions.HTTP2_SETTINGS_MAX_FRAME_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_MAX_FRAME_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + protected static final OptionAttributeDefinition HTTP2_MAX_HEADER_LIST_SIZE = OptionAttributeDefinition.builder("http2-max-header-list-size", UndertowOptions.HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setValidator(new IntRangeValidator(1)) + .build(); + + protected static final OptionAttributeDefinition REQUIRE_HOST_HTTP11 = OptionAttributeDefinition.builder("require-host-http11", UndertowOptions.REQUIRE_HOST_HTTP11) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final SimpleAttributeDefinition PROXY_PROTOCOL = new SimpleAttributeDefinitionBuilder(Constants.PROXY_PROTOCOL, ModelType.BOOLEAN) + .setDefaultValue(new ModelNode(false)) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setAllowExpression(true) + .build(); + + private HttpListenerResourceDefinition() { + super(UndertowExtension.HTTP_LISTENER_PATH); + } + + @Override + protected ListenerAdd getAddHandler() { + return new HttpListenerAdd(this); + } + + public Collection getAttributes() { + List attrs = new ArrayList<>(super.getAttributes()); + attrs.add(CERTIFICATE_FORWARDING); + attrs.add(REDIRECT_SOCKET); + attrs.add(PROXY_ADDRESS_FORWARDING); + attrs.add(ENABLE_HTTP2); + attrs.add(HTTP2_ENABLE_PUSH); + attrs.add(HTTP2_HEADER_TABLE_SIZE); + attrs.add(HTTP2_INITIAL_WINDOW_SIZE); + attrs.add(HTTP2_MAX_CONCURRENT_STREAMS); + attrs.add(HTTP2_MAX_HEADER_LIST_SIZE); + attrs.add(HTTP2_MAX_FRAME_SIZE); + attrs.add(REQUIRE_HOST_HTTP11); + attrs.add(PROXY_PROTOCOL); + return attrs; + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + //register as normal + super.registerAttributes(resourceRegistration); + //override + resourceRegistration.unregisterAttribute(WORKER.getName()); + resourceRegistration.registerReadWriteAttribute(WORKER, null, new HttpListenerWorkerAttributeWriteHandler(WORKER)); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,146 @@ +/* + * 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.extension.undertow; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import io.undertow.UndertowOptions; +import io.undertow.server.ListenerRegistry; +import io.undertow.server.OpenListener; +import io.undertow.server.handlers.ChannelUpgradeHandler; +import io.undertow.server.handlers.ProxyPeerAddressHandler; +import io.undertow.server.handlers.SSLHeaderHandler; +import io.undertow.server.protocol.http.HttpOpenListener; +import io.undertow.server.protocol.http2.Http2UpgradeHandler; + +import org.jboss.as.network.NetworkUtils; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.ValueService; +import org.jboss.msc.value.ImmediateValue; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.ChannelListener; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import org.xnio.StreamConnection; +import org.xnio.XnioWorker; +import org.xnio.channels.AcceptingChannel; + +/** + * @author Stuart Douglas + * @author Tomaz Cerar + */ +public class HttpListenerService extends ListenerService { + private volatile AcceptingChannel server; + + private final ChannelUpgradeHandler httpUpgradeHandler = new ChannelUpgradeHandler(); + protected final InjectedValue httpListenerRegistry = new InjectedValue<>(); + static final ServiceName HTTP_UPGRADE_REGISTRY = ServiceName.JBOSS.append("http-upgrade-registry"); + static final String PROTOCOL = "http"; + + private final String serverName; + + public HttpListenerService(String name, final String serverName, OptionMap listenerOptions, OptionMap socketOptions, boolean certificateForwarding, boolean proxyAddressForwarding, boolean proxyProtocol) { + super(name, listenerOptions, socketOptions, proxyProtocol); + this.serverName = serverName; + addWrapperHandler(handler -> { + httpUpgradeHandler.setNonUpgradeHandler(handler); + return httpUpgradeHandler; + }); + if(listenerOptions.get(UndertowOptions.ENABLE_HTTP2, false)) { + addWrapperHandler(Http2UpgradeHandler::new); + } + if (certificateForwarding) { + addWrapperHandler(SSLHeaderHandler::new); + } + if (proxyAddressForwarding) { + addWrapperHandler(ProxyPeerAddressHandler::new); + } + } + + @Override + protected OpenListener createOpenListener() { + return new HttpOpenListener(getBufferPool().getValue(), OptionMap.builder().addAll(commonOptions).addAll(listenerOptions).set(UndertowOptions.ENABLE_STATISTICS, getUndertowService().isStatisticsEnabled()).getMap()); + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + protected void preStart(final StartContext context) { + //adds the HTTP upgrade service + //TODO: have a bit more of a think about how we handle this + context.getChildTarget().addService(HTTP_UPGRADE_REGISTRY.append(getName()), new ValueService(new ImmediateValue(httpUpgradeHandler))) + .install(); + ListenerRegistry.Listener listener = new ListenerRegistry.Listener(getProtocol(), getName(), serverName, getBinding().getValue().getSocketAddress()); + listener.setContextInformation("socket-binding", getBinding().getValue()); + httpListenerRegistry.getValue().addListener(listener); + } + + protected void startListening(XnioWorker worker, InetSocketAddress socketAddress, ChannelListener> acceptListener) + throws IOException { + server = worker.createStreamConnectionServer(socketAddress, acceptListener, OptionMap.builder().addAll(commonOptions).addAll(socketOptions).getMap()); + server.resumeAccepts(); + + final InetSocketAddress boundAddress = server.getLocalAddress(InetSocketAddress.class); + UndertowLogger.ROOT_LOGGER.listenerStarted("HTTP", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + } + + @Override + protected void cleanFailedStart() { + httpListenerRegistry.getValue().removeListener(getName()); + } + + protected void unregisterBinding() { + httpListenerRegistry.getValue().removeListener(getName()); + super.unregisterBinding(); + } + + @Override + protected void stopListening() { + final InetSocketAddress boundAddress = server.getLocalAddress(InetSocketAddress.class); + server.suspendAccepts(); + UndertowLogger.ROOT_LOGGER.listenerSuspend("HTTP", getName()); + IoUtils.safeClose(server); + server = null; + UndertowLogger.ROOT_LOGGER.listenerStopped("HTTP", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + } + + @Override + public HttpListenerService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + public InjectedValue getHttpListenerRegistry() { + return httpListenerRegistry; + } + + @Override + public String getProtocol() { + return PROTOCOL; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerWorkerAttributeWriteHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerWorkerAttributeWriteHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpListenerWorkerAttributeWriteHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,57 @@ +/* + * 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.extension.undertow; + +import java.util.logging.Level; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * http/https write handler for worker attribute. + * + * @author baranowb + * + */ +public class HttpListenerWorkerAttributeWriteHandler extends ReloadRequiredWriteAttributeHandler { + + public HttpListenerWorkerAttributeWriteHandler(AttributeDefinition... definitions) { + super(definitions); + // TODO Auto-generated constructor stub + } + + @Override + protected void finishModelStage(OperationContext context, ModelNode operation, String attributeName, ModelNode newValue, + ModelNode oldValue, Resource model) throws OperationFailedException { + super.finishModelStage(context, operation, attributeName, newValue, oldValue, model); + + context.addResponseWarning(Level.WARNING, UndertowLogger.ROOT_LOGGER.workerValueInHTTPListenerMustMatchRemoting()); + + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,124 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; + +import javax.net.ssl.SSLContext; + +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.domain.management.SecurityRealm; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.OptionMap; + +import io.undertow.server.ListenerRegistry; + +/** + * Add handler for HTTPS listeners. + * + * @author Darran Lofthouse + */ +public class HttpsListenerAdd extends ListenerAdd { + + HttpsListenerAdd(HttpsListenerResourceDefinition def) { + super(def); + } + + @Override + ListenerService createService(String name, final String serverName, final OperationContext context, ModelNode model, OptionMap listenerOptions, OptionMap socketOptions) throws OperationFailedException { + OptionMap.Builder builder = OptionMap.builder().addAll(socketOptions); + + ModelNode securityRealmModel = HttpsListenerResourceDefinition.SECURITY_REALM.resolveModelAttribute(context, model); + final boolean proxyProtocol = HttpListenerResourceDefinition.PROXY_PROTOCOL.resolveModelAttribute(context, model).asBoolean(); + String cipherSuites = null; + if(securityRealmModel.isDefined()) { + //we only support setting these options for security realms + HttpsListenerResourceDefinition.VERIFY_CLIENT.resolveOption(context, model, builder); + + ModelNode value = HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES.resolveModelAttribute(context, model); + cipherSuites = value.isDefined() ? value.asString() : null; + + 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); + HttpListenerAdd.handleHttp2Options(context, model, listenerBuilder); + + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11.resolveOption(context, model,listenerBuilder); + + final boolean certificateForwarding = HttpListenerResourceDefinition.CERTIFICATE_FORWARDING.resolveModelAttribute(context, model).asBoolean(); + final boolean proxyAddressForwarding = HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING.resolveModelAttribute(context, model).asBoolean(); + return new HttpsListenerService(name, serverName, listenerBuilder.getMap(), cipherSuites, builder.getMap(), certificateForwarding, proxyAddressForwarding, proxyProtocol); + } + + @Override + void configureAdditionalDependencies(OperationContext context, CapabilityServiceBuilder serviceBuilder, ModelNode model, ListenerService service) throws OperationFailedException { + serviceBuilder.addDependency(HttpListenerAdd.REGISTRY_SERVICE_NAME, ListenerRegistry.class, ((HttpListenerService) service).getHttpListenerRegistry()); + + ModelNode sslContextModel = HttpsListenerResourceDefinition.SSL_CONTEXT.resolveModelAttribute(context, model); + ModelNode securityRealmModel = HttpsListenerResourceDefinition.SECURITY_REALM.resolveModelAttribute(context, model); + + final String sslContextRef = sslContextModel.isDefined() ? sslContextModel.asString() : null; + final String securityRealmRef = securityRealmModel.isDefined() ? securityRealmModel.asString() : null; + + final InjectedValue sslContextInjector = new InjectedValue<>(); + final InjectedValue securityRealmInjector = new InjectedValue<>(); + + if (securityRealmRef != null) { + SecurityRealm.ServiceUtil.addDependency(serviceBuilder, securityRealmInjector, securityRealmRef); + } + + if (sslContextRef != null) { + serviceBuilder.addCapabilityRequirement(REF_SSL_CONTEXT, SSLContext.class, sslContextInjector, sslContextRef); + } + + ((HttpsListenerService)service).setSSLContextSupplier(()-> { + if (sslContextRef != null) { + return sslContextInjector.getValue(); + } + + if (securityRealmRef != null) { + SSLContext sslContext = securityRealmInjector.getValue().getSSLContext(); + + if (sslContext == null) { + throw UndertowLogger.ROOT_LOGGER.noSslContextInSecurityRealm(securityRealmRef); + } + return sslContext; + } + + try { + return SSLContext.getDefault(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }); + + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerResourceDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,163 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; +import static org.xnio.Options.SSL_CLIENT_AUTH_MODE; + +import java.util.Collection; +import java.util.LinkedList; + +import io.undertow.UndertowOptions; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +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; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.io.OptionAttributeDefinition; +import org.xnio.Options; +import org.xnio.SslClientAuthMode; + +/** + * An extension to the {@see HttpListenerResourceDefinition} to allow a security-realm to be associated to obtain a pre-defined + * SSLContext. + * + * @author Darran Lofthouse + */ +public class HttpsListenerResourceDefinition extends ListenerResourceDefinition { + + protected static final HttpsListenerResourceDefinition INSTANCE = new HttpsListenerResourceDefinition(); + + protected static final SimpleAttributeDefinition SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.SSL_CONTEXT, ModelType.STRING, false) + .setAlternatives(Constants.SECURITY_REALM, Constants.VERIFY_CLIENT, Constants.ENABLED_CIPHER_SUITES, Constants.ENABLED_PROTOCOLS, Constants.SSL_SESSION_CACHE_SIZE, Constants.SSL_SESSION_TIMEOUT) + .setCapabilityReference(REF_SSL_CONTEXT) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SSL_REF) + .build(); + + protected static final SimpleAttributeDefinition SECURITY_REALM = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_REALM, ModelType.STRING, false) + .setAlternatives(Constants.SSL_CONTEXT) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1)) + .setDeprecated(ModelVersion.create(4, 0, 0)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SECURITY_REALM_REF) + .build(); + + protected static final OptionAttributeDefinition VERIFY_CLIENT = OptionAttributeDefinition.builder(Constants.VERIFY_CLIENT, SSL_CLIENT_AUTH_MODE) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setValidator(new EnumValidator<>(SslClientAuthMode.class, true, true)) + .setDefaultValue(new ModelNode(SslClientAuthMode.NOT_REQUESTED.name())) + .setDeprecated(ModelVersion.create(4, 0, 0)) + .setAlternatives(Constants.SSL_CONTEXT) + .build(); + + protected static final OptionAttributeDefinition ENABLED_CIPHER_SUITES = OptionAttributeDefinition.builder(Constants.ENABLED_CIPHER_SUITES, Options.SSL_ENABLED_CIPHER_SUITES) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDeprecated(ModelVersion.create(4, 0, 0)) + .setAlternatives(Constants.SSL_CONTEXT) + .build(); + + protected static final OptionAttributeDefinition ENABLED_PROTOCOLS = OptionAttributeDefinition.builder(Constants.ENABLED_PROTOCOLS, Options.SSL_ENABLED_PROTOCOLS) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDeprecated(ModelVersion.create(4, 0, 0)) + .setAlternatives(Constants.SSL_CONTEXT) + .build(); + + protected static final OptionAttributeDefinition ENABLE_HTTP2 = OptionAttributeDefinition.builder(Constants.ENABLE_HTTP2, UndertowOptions.ENABLE_HTTP2) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final OptionAttributeDefinition ENABLE_SPDY = OptionAttributeDefinition.builder(Constants.ENABLE_SPDY, UndertowOptions.ENABLE_SPDY) + .setRequired(false) + .setDeprecated(ModelVersion.create(3, 2)) + .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) + .setDeprecated(ModelVersion.create(4, 0, 0)).setRequired(false).setAllowExpression(true) + .setAlternatives(Constants.SSL_CONTEXT).build(); + public static final OptionAttributeDefinition SSL_SESSION_TIMEOUT = OptionAttributeDefinition.builder(Constants.SSL_SESSION_TIMEOUT, Options.SSL_SERVER_SESSION_TIMEOUT) + .setDeprecated(ModelVersion.create(4, 0, 0)).setMeasurementUnit(MeasurementUnit.SECONDS).setRequired(false).setAllowExpression(true).setAlternatives(Constants.SSL_CONTEXT).build(); + + private HttpsListenerResourceDefinition() { + super(UndertowExtension.HTTPS_LISTENER_PATH); + } + + @Override + public Collection getAttributes() { + Collection res = new LinkedList<>(super.getAttributes()); + res.add(SSL_CONTEXT); + res.add(SECURITY_REALM); + res.add(VERIFY_CLIENT); + res.add(ENABLED_CIPHER_SUITES); + res.add(ENABLED_PROTOCOLS); + res.add(ENABLE_HTTP2); + res.add(ENABLE_SPDY); + res.add(SSL_SESSION_CACHE_SIZE); + res.add(SSL_SESSION_TIMEOUT); + res.add(HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH); + res.add(HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE); + res.add(HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE); + res.add(HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS); + res.add(HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE); + res.add(HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE); + res.add(HttpListenerResourceDefinition.CERTIFICATE_FORWARDING); + res.add(HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING); + res.add(HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11); + res.add(HttpListenerResourceDefinition.PROXY_PROTOCOL); + return res; + } + + @Override + protected ListenerAdd getAddHandler() { + return new HttpsListenerAdd(this); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + //register as normal + super.registerAttributes(resourceRegistration); + //override + resourceRegistration.unregisterAttribute(WORKER.getName()); + resourceRegistration.registerReadWriteAttribute(WORKER, null, new HttpListenerWorkerAttributeWriteHandler(WORKER)); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/HttpsListenerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,171 @@ +/* + * 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.extension.undertow; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.function.Supplier; + +import javax.net.ssl.SSLContext; + +import io.undertow.UndertowOptions; +import io.undertow.connector.ByteBufferPool; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import io.undertow.server.OpenListener; +import io.undertow.server.protocol.http.AlpnOpenListener; +import io.undertow.server.protocol.http.HttpOpenListener; +import io.undertow.server.protocol.http2.Http2OpenListener; + +import org.jboss.as.network.NetworkUtils; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.ssl.CipherSuiteSelector; +import org.xnio.ChannelListener; +import org.xnio.IoUtils; +import org.xnio.Option; +import org.xnio.OptionMap; +import org.xnio.OptionMap.Builder; +import org.xnio.Options; +import org.xnio.Sequence; +import org.xnio.StreamConnection; +import org.xnio.XnioWorker; +import org.xnio.channels.AcceptingChannel; +import org.xnio.ssl.SslConnection; +import org.xnio.ssl.XnioSsl; + +/** + * An extension of {@see HttpListenerService} to add SSL. + * + * @author Darran Lofthouse + * @author Tomaz Cerar + */ +public class HttpsListenerService extends HttpListenerService { + + private Supplier sslContextSupplier; + private volatile AcceptingChannel sslServer; + static final String PROTOCOL = "https"; + private final String cipherSuites; + private final boolean proxyProtocol; + + public HttpsListenerService(final String name, String serverName, OptionMap listenerOptions, String cipherSuites, OptionMap socketOptions, boolean proxyProtocol) { + this(name, serverName, listenerOptions, cipherSuites, socketOptions, false, false, proxyProtocol); + } + + HttpsListenerService(final String name, String serverName, OptionMap listenerOptions, String cipherSuites, OptionMap socketOptions, boolean certificateForwarding, boolean proxyAddressForwarding, boolean proxyProtocol) { + super(name, serverName, listenerOptions, socketOptions, certificateForwarding, proxyAddressForwarding, proxyProtocol); + this.cipherSuites = cipherSuites; + this.proxyProtocol = proxyProtocol; + } + + void setSSLContextSupplier(Supplier sslContextSupplier) { + this.sslContextSupplier = sslContextSupplier; + } + + @Override + protected UndertowXnioSsl getSsl() { + SSLContext sslContext = sslContextSupplier.get(); + OptionMap combined = getSSLOptions(sslContext); + + return new UndertowXnioSsl(worker.getValue().getXnio(), combined, sslContext); + } + + protected OptionMap getSSLOptions(SSLContext sslContext) { + Builder builder = OptionMap.builder().addAll(commonOptions); + builder.addAll(socketOptions); + builder.set(Options.USE_DIRECT_BUFFERS, true); + + if (cipherSuites != null) { + String[] cipherList = CipherSuiteSelector.fromString(cipherSuites).evaluate(sslContext.getSupportedSSLParameters().getCipherSuites()); + builder.setSequence((Option>) HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES.getOption(), cipherList); + } + + return builder.getMap(); + } + + @Override + protected OpenListener createOpenListener() { + if(listenerOptions.get(UndertowOptions.ENABLE_HTTP2, false)) { + try { + return createAlpnOpenListener(); + } catch (Throwable e) { + UndertowLogger.ROOT_LOGGER.alpnNotFound(getName()); + UndertowLogger.ROOT_LOGGER.debug("Exception creating ALPN listener", e); + return super.createOpenListener(); + } + } else { + return super.createOpenListener(); + } + } + + private OpenListener createAlpnOpenListener() { + OptionMap undertowOptions = OptionMap.builder().addAll(commonOptions).addAll(listenerOptions).set(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, getUndertowService().isStatisticsEnabled()).getMap(); + ByteBufferPool bufferPool = getBufferPool().getValue(); + HttpOpenListener http = new HttpOpenListener(bufferPool, undertowOptions); + AlpnOpenListener alpn = new AlpnOpenListener(bufferPool, undertowOptions, http); + + if(listenerOptions.get(UndertowOptions.ENABLE_HTTP2, false)) { + Http2OpenListener http2 = new Http2OpenListener(bufferPool, undertowOptions, "h2"); + alpn.addProtocol(Http2OpenListener.HTTP2, http2, 10); + Http2OpenListener http2_14 = new Http2OpenListener(bufferPool, undertowOptions, "h2-14"); + alpn.addProtocol(Http2OpenListener.HTTP2_14, http2_14, 9); + } + return alpn; + } + + + + @Override + protected void startListening(XnioWorker worker, InetSocketAddress socketAddress, ChannelListener> acceptListener) throws IOException { + + if(proxyProtocol) { + sslServer = worker.createStreamConnectionServer(socketAddress, (ChannelListener) acceptListener, getSSLOptions(sslContextSupplier.get())); + } else { + XnioSsl ssl = getSsl(); + sslServer = ssl.createSslConnectionServer(worker, socketAddress, (ChannelListener) acceptListener, getSSLOptions(sslContextSupplier.get())); + } + sslServer.resumeAccepts(); + + final InetSocketAddress boundAddress = sslServer.getLocalAddress(InetSocketAddress.class); + UndertowLogger.ROOT_LOGGER.listenerStarted("HTTPS", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + } + + @Override + public boolean isSecure() { + return true; + } + + @Override + protected void stopListening() { + final InetSocketAddress boundAddress = sslServer.getLocalAddress(InetSocketAddress.class); + sslServer.suspendAccepts(); + UndertowLogger.ROOT_LOGGER.listenerSuspend("HTTPS", getName()); + IoUtils.safeClose(sslServer); + sslServer = null; + UndertowLogger.ROOT_LOGGER.listenerStopped("HTTPS", getName(), NetworkUtils.formatIPAddressForURI(boundAddress.getAddress()), boundAddress.getPort()); + httpListenerRegistry.getValue().removeListener(getName()); + } + + @Override + public String getProtocol() { + return PROTOCOL; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ImportedClassELResolver.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ImportedClassELResolver.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ImportedClassELResolver.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,126 @@ +/* + * 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.extension.undertow; + +import javax.el.ELClass; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.ImportHandler; +import java.beans.FeatureDescriptor; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.manager.WildFlySecurityManager; + +/** + * An {@link ELResolver} which supports resolution of EL expressions which use imported classes (for static field/method references) + * + * @author Jaikiran Pai + * @see Section 1.5.3 of EL 3.0 spec + */ +public class ImportedClassELResolver extends ELResolver { + + private final Map cache = new ConcurrentHashMap<>(); + + private static final Object NULL_MARKER = new Object(); + + @Override + public Object getValue(final ELContext context, final Object base, final Object property) { + if (base != null) { + return null; + } + if (!(property instanceof String)) { + return null; + } + final ImportHandler importHandler = context.getImportHandler(); + if (importHandler == null) { + return null; + } + final String klassName = (String) property; + Object cacheResult = cache.get(klassName); + if(cacheResult != null) { + if(cacheResult == NULL_MARKER) { + return null; + } else { + return cacheResult; + } + } + final Class klass; + if (WildFlySecurityManager.isChecking()) { + klass = AccessController.doPrivileged(new PrivilegedAction>() { + @Override + public Class run() { + return importHandler.resolveClass(klassName); + } + }); + } else { + klass = importHandler.resolveClass(klassName); + } + + if (klass != null) { + cache.put(klassName, klass); + context.setPropertyResolved(true); + return new ELClass(klass); + } else { + cache.put(klassName, NULL_MARKER); + } + return null; + } + + @Override + public Class getType(final ELContext context, final Object base, final Object property) { + // we don't set any value on invocation of setValue of this resolver, so this getType method should just return + // null and *not* mark the base, property combination as resolved + return null; + } + + @Override + public void setValue(final ELContext context, final Object base, final Object property, final Object value) { + Objects.requireNonNull(context, UndertowLogger.ROOT_LOGGER.nullNotAllowed("ELContext")); + // we don't allow setting any value so this method + } + + @Override + public boolean isReadOnly(final ELContext context, final Object base, final Object property) { + if (context == null) { + throw new NullPointerException("ELContext cannot be null"); + } + // we don't allow setting any value via this resolver, so this is always read-only + return true; + } + + @Override + public Iterator getFeatureDescriptors(final ELContext context, final Object base) { + return null; + } + + @Override + public Class getCommonPropertyType(final ELContext context, final Object base) { + return null; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/InMemoryModularPersistentSessionManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/InMemoryModularPersistentSessionManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/InMemoryModularPersistentSessionManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,49 @@ +/* + * 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.extension.undertow; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Persistent session manager that simply stores the session information in a map + * + * @author Stuart Douglas + */ +public class InMemoryModularPersistentSessionManager extends AbstractPersistentSessionManager { + + /** + * The serialized sessions + */ + private final Map> sessionData = Collections.synchronizedMap(new HashMap>()); + + @Override + protected void persistSerializedSessions(String deploymentName, Map serializedData) { + sessionData.put(deploymentName, serializedData); + } + + @Override + protected Map loadSerializedSessions(String deploymentName) { + return sessionData.remove(deploymentName); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/JSPConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/JSPConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/JSPConfig.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,82 @@ +/* + * 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.extension.undertow; + +import io.undertow.servlet.api.ServletInfo; +import org.apache.jasper.servlet.JspServlet; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class JSPConfig { + private final ServletInfo servletInfo; + + + public JSPConfig(final boolean developmentMode, + final boolean disabled, + final boolean keepGenerated, final boolean trimSpaces, final boolean tagPooling, + final boolean mappedFile, final int checkInterval, int modificationTestInterval, + final boolean recompileOnFail, boolean smap, boolean dumpSmap, + boolean genStringAsCharArray, boolean errorOnUseBeanInvalidClassAttribute, + String scratchDir, String sourceVm, String targetVm, String javaEncoding, + boolean xPoweredBy, boolean displaySourceFragment, boolean optimizeScriptlets) { + if (disabled) { + servletInfo = null; + } else { + + final io.undertow.servlet.api.ServletInfo jspServlet = new ServletInfo("jsp", JspServlet.class); + jspServlet.setRequireWelcomeFileMapping(true); + + jspServlet.addInitParam("development", Boolean.toString(developmentMode)); + jspServlet.addInitParam("keepgenerated", Boolean.toString(keepGenerated)); + jspServlet.addInitParam("trimSpaces", Boolean.toString(trimSpaces)); + jspServlet.addInitParam("enablePooling", Boolean.toString(tagPooling)); + jspServlet.addInitParam("mappedfile", Boolean.toString(mappedFile)); + jspServlet.addInitParam("checkInterval", Integer.toString(checkInterval)); + jspServlet.addInitParam("modificationTestInterval", Integer.toString(modificationTestInterval)); + jspServlet.addInitParam("recompileOnFail", Boolean.toString(recompileOnFail)); + jspServlet.addInitParam("suppressSmap", Boolean.toString(!smap)); + jspServlet.addInitParam("dumpSmap", Boolean.toString(dumpSmap)); + jspServlet.addInitParam("genStringAsCharArray", Boolean.toString(genStringAsCharArray)); + jspServlet.addInitParam("errorOnUseBeanInvalidClassAttribute", Boolean.toString(errorOnUseBeanInvalidClassAttribute)); + jspServlet.addInitParam("optimizeScriptlets", Boolean.toString(optimizeScriptlets)); + if (scratchDir != null) { + jspServlet.addInitParam("scratchdir", scratchDir); + } + // jasper will find the right defaults. + jspServlet.addInitParam("compilerSourceVM", sourceVm); + jspServlet.addInitParam("compilerTargetVM", targetVm); + jspServlet.addInitParam("javaEncoding", javaEncoding); + jspServlet.addInitParam("xpoweredBy", Boolean.toString(xPoweredBy)); + jspServlet.addInitParam("displaySourceFragment", Boolean.toString(displaySourceFragment)); + this.servletInfo = jspServlet; + } + } + + public ServletInfo createJSPServletInfo() { + if(servletInfo == null) { + return null; + } + return servletInfo.clone(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/JspDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/JspDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/JspDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,290 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.operations.validation.ModelTypeValidator; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Tomaz Cerar + * @created 23.2.12 18:47 + */ +class JspDefinition extends PersistentResourceDefinition { + protected static final SimpleAttributeDefinition DEVELOPMENT = + new SimpleAttributeDefinitionBuilder(Constants.DEVELOPMENT, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition DISABLED = + new SimpleAttributeDefinitionBuilder(Constants.DISABLED, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition KEEP_GENERATED = + new SimpleAttributeDefinitionBuilder(Constants.KEEP_GENERATED, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition TRIM_SPACES = + new SimpleAttributeDefinitionBuilder(Constants.TRIM_SPACES, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition TAG_POOLING = + new SimpleAttributeDefinitionBuilder(Constants.TAG_POOLING, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition MAPPED_FILE = + new SimpleAttributeDefinitionBuilder(Constants.MAPPED_FILE, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition CHECK_INTERVAL = + new SimpleAttributeDefinitionBuilder(Constants.CHECK_INTERVAL, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(0)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition MODIFICATION_TEST_INTERVAL = + new SimpleAttributeDefinitionBuilder(Constants.MODIFICATION_TEST_INTERVAL, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(4)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition RECOMPILE_ON_FAIL = + new SimpleAttributeDefinitionBuilder(Constants.RECOMPILE_ON_FAIL, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition SMAP = + new SimpleAttributeDefinitionBuilder(Constants.SMAP, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition DUMP_SMAP = + new SimpleAttributeDefinitionBuilder(Constants.DUMP_SMAP, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition GENERATE_STRINGS_AS_CHAR_ARRAYS = + new SimpleAttributeDefinitionBuilder(Constants.GENERATE_STRINGS_AS_CHAR_ARRAYS, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE = + new SimpleAttributeDefinitionBuilder(Constants.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition SCRATCH_DIR = + new SimpleAttributeDefinitionBuilder(Constants.SCRATCH_DIR, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1, true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition SOURCE_VM = + new SimpleAttributeDefinitionBuilder(Constants.SOURCE_VM, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1, true)) + .setDefaultValue(new ModelNode("1.8")) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition TARGET_VM = + new SimpleAttributeDefinitionBuilder(Constants.TARGET_VM, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1, true)) + .setDefaultValue(new ModelNode("1.8")) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition JAVA_ENCODING = + new SimpleAttributeDefinitionBuilder(Constants.JAVA_ENCODING, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1, true)) + .setDefaultValue(new ModelNode("UTF8")) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition X_POWERED_BY = + new SimpleAttributeDefinitionBuilder(Constants.X_POWERED_BY, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new ModelTypeValidator(ModelType.BOOLEAN, true)) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition DISPLAY_SOURCE_FRAGMENT = + new SimpleAttributeDefinitionBuilder(Constants.DISPLAY_SOURCE_FRAGMENT, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new ModelTypeValidator(ModelType.BOOLEAN, true)) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition OPTIMIZE_SCRIPTLETS = + new SimpleAttributeDefinitionBuilder(Constants.OPTIMIZE_SCRIPTLETS, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new ModelTypeValidator(ModelType.BOOLEAN, true)) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + // IMPORTANT -- keep these in xsd order as this order controls marshalling + DISABLED, + DEVELOPMENT, + KEEP_GENERATED, + TRIM_SPACES, + TAG_POOLING, + MAPPED_FILE, + CHECK_INTERVAL, + MODIFICATION_TEST_INTERVAL, + RECOMPILE_ON_FAIL, + SMAP, + DUMP_SMAP, + GENERATE_STRINGS_AS_CHAR_ARRAYS, + ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + SCRATCH_DIR, + SOURCE_VM, + TARGET_VM, + JAVA_ENCODING, + X_POWERED_BY, + DISPLAY_SOURCE_FRAGMENT, + OPTIMIZE_SCRIPTLETS + }; + static final JspDefinition INSTANCE = new JspDefinition(); + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + private JspDefinition() { + super(UndertowExtension.PATH_JSP, + UndertowExtension.getResolver(UndertowExtension.PATH_JSP.getKeyValuePair()), + new JSPAdd(), + new JSPRemove()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } + + public JSPConfig getConfig(final OperationContext context, final ModelNode model) throws OperationFailedException { + if (!model.isDefined()) { + return null; + } + boolean disabled = DISABLED.resolveModelAttribute(context, model).asBoolean(); + boolean development = DEVELOPMENT.resolveModelAttribute(context, model).asBoolean(); + boolean keepGenerated = KEEP_GENERATED.resolveModelAttribute(context, model).asBoolean(); + boolean trimSpaces = TRIM_SPACES.resolveModelAttribute(context, model).asBoolean(); + boolean tagPooling = TAG_POOLING.resolveModelAttribute(context, model).asBoolean(); + boolean mappedFile = MAPPED_FILE.resolveModelAttribute(context, model).asBoolean(); + int checkInterval = CHECK_INTERVAL.resolveModelAttribute(context, model).asInt(); + int modificationTestInterval = MODIFICATION_TEST_INTERVAL.resolveModelAttribute(context, model).asInt(); + boolean recompileOnFile = RECOMPILE_ON_FAIL.resolveModelAttribute(context, model).asBoolean(); + boolean snap = SMAP.resolveModelAttribute(context, model).asBoolean(); + boolean dumpSnap = DUMP_SMAP.resolveModelAttribute(context, model).asBoolean(); + boolean generateStringsAsCharArrays = GENERATE_STRINGS_AS_CHAR_ARRAYS.resolveModelAttribute(context, model).asBoolean(); + boolean errorOnUseBeanInvalidClassAttribute = ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE.resolveModelAttribute(context, model).asBoolean(); + final ModelNode scratchDirValue = SCRATCH_DIR.resolveModelAttribute(context, model); + String scratchDir = scratchDirValue.isDefined() ? scratchDirValue.asString() : null; + String sourceVm = SOURCE_VM.resolveModelAttribute(context, model).asString(); + String targetVm = TARGET_VM.resolveModelAttribute(context, model).asString(); + String javaEncoding = JAVA_ENCODING.resolveModelAttribute(context, model).asString(); + boolean xPoweredBy = X_POWERED_BY.resolveModelAttribute(context, model).asBoolean(); + boolean displaySourceFragment = DISPLAY_SOURCE_FRAGMENT.resolveModelAttribute(context, model).asBoolean(); + boolean optimizeScriptlets = OPTIMIZE_SCRIPTLETS.resolveModelAttribute(context, model).asBoolean(); + return new JSPConfig(development, disabled, keepGenerated, trimSpaces, tagPooling, mappedFile, checkInterval, modificationTestInterval, + recompileOnFile, snap, dumpSnap, generateStringsAsCharArrays, errorOnUseBeanInvalidClassAttribute, scratchDir, + sourceVm, targetVm, javaEncoding, xPoweredBy, displaySourceFragment, optimizeScriptlets); + } + + private static class JSPAdd extends RestartParentResourceAddHandler { + protected JSPAdd() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } + + private static class JSPRemove extends RestartParentResourceRemoveHandler { + + protected JSPRemove() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,119 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.REF_IO_WORKER; +import static org.wildfly.extension.undertow.Capabilities.REF_SOCKET_BINDING; +import static org.wildfly.extension.undertow.ListenerResourceDefinition.LISTENER_CAPABILITY; +import static org.wildfly.extension.undertow.ServerDefinition.SERVER_CAPABILITY; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import io.undertow.connector.ByteBufferPool; +import io.undertow.server.handlers.DisallowedMethodsHandler; +import io.undertow.server.handlers.PeerNameResolvingHandler; +import io.undertow.servlet.handlers.MarkSecureHandler; +import io.undertow.util.HttpString; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.network.SocketBinding; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.io.OptionList; +import org.xnio.OptionMap; +import org.xnio.XnioWorker; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +abstract class ListenerAdd extends AbstractAddStepHandler { + + ListenerAdd(ListenerResourceDefinition definition) { + super(definition.getAttributes()); + } + + @Override + protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + super.recordCapabilitiesAndRequirements(context, operation, resource); + + String ourCap = LISTENER_CAPABILITY.getDynamicName(context.getCurrentAddress()); + String serverCap = SERVER_CAPABILITY.getDynamicName(context.getCurrentAddress().getParent()); + context.registerAdditionalCapabilityRequirement(serverCap, ourCap, null); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final PathAddress parent = address.getParent(); + final String name = context.getCurrentAddressValue(); + final String bindingRef = ListenerResourceDefinition.SOCKET_BINDING.resolveModelAttribute(context, model).asString(); + final String workerName = ListenerResourceDefinition.WORKER.resolveModelAttribute(context, model).asString(); + final String bufferPoolName = ListenerResourceDefinition.BUFFER_POOL.resolveModelAttribute(context, model).asString(); + final boolean enabled = ListenerResourceDefinition.ENABLED.resolveModelAttribute(context, model).asBoolean(); + final boolean peerHostLookup = ListenerResourceDefinition.RESOLVE_PEER_ADDRESS.resolveModelAttribute(context, model).asBoolean(); + final boolean secure = ListenerResourceDefinition.SECURE.resolveModelAttribute(context, model).asBoolean(); + + OptionMap listenerOptions = OptionList.resolveOptions(context, model, ListenerResourceDefinition.LISTENER_OPTIONS); + OptionMap socketOptions = OptionList.resolveOptions(context, model, ListenerResourceDefinition.SOCKET_OPTIONS); + String serverName = parent.getLastElement().getValue(); + final ListenerService service = createService(name, serverName, context, model, listenerOptions,socketOptions); + if (peerHostLookup) { + service.addWrapperHandler(PeerNameResolvingHandler::new); + } + service.setEnabled(enabled); + if(secure) { + service.addWrapperHandler(MarkSecureHandler.WRAPPER); + } + List disallowedMethods = ListenerResourceDefinition.DISALLOWED_METHODS.unwrap(context, model); + if(!disallowedMethods.isEmpty()) { + final Set methodSet = new HashSet<>(); + for (String i : disallowedMethods) { + HttpString httpString = new HttpString(i.trim()); + methodSet.add(httpString); + } + service.addWrapperHandler(handler -> new DisallowedMethodsHandler(handler, methodSet)); + } + + final CapabilityServiceBuilder serviceBuilder = context.getCapabilityServiceTarget().addCapability(ListenerResourceDefinition.LISTENER_CAPABILITY, service); + serviceBuilder.addCapabilityRequirement(REF_IO_WORKER, XnioWorker.class, service.getWorker(), workerName) + .addCapabilityRequirement(REF_SOCKET_BINDING, SocketBinding.class, service.getBinding(), bindingRef) + .addCapabilityRequirement(Capabilities.CAPABILITY_BYTE_BUFFER_POOL, ByteBufferPool.class, service.getBufferPool(), bufferPoolName) + .addCapabilityRequirement(Capabilities.CAPABILITY_SERVER, Server.class, service.getServerService(), serverName) + .addAliases(UndertowService.listenerName(name)) + ; + + configureAdditionalDependencies(context, serviceBuilder, model, service); + serviceBuilder.install(); + + } + + abstract ListenerService createService(String name, final String serverName, final OperationContext context, ModelNode model, OptionMap listenerOptions, OptionMap socketOptions) throws OperationFailedException; + + abstract void configureAdditionalDependencies(OperationContext context, CapabilityServiceBuilder serviceBuilder, ModelNode model, ListenerService service) throws OperationFailedException; + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerRemoveHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerRemoveHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerRemoveHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,41 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.msc.service.ServiceName; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class ListenerRemoveHandler extends ServiceRemoveStepHandler { + + ListenerRemoveHandler(ListenerAdd addOperation) { + super(addOperation); + } + + @Override + protected ServiceName serviceName(String name) { + return ListenerResourceDefinition.LISTENER_CAPABILITY.getCapabilityServiceName(name); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerResourceDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerResourceDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerResourceDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,355 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; +import static org.wildfly.extension.undertow.Capabilities.REF_IO_WORKER; +import static org.wildfly.extension.undertow.Capabilities.REF_SOCKET_BINDING; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import io.undertow.UndertowOptions; +import io.undertow.server.ConnectorStatistics; +import org.jboss.as.controller.AbstractWriteAttributeHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ModelVersion; +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.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.operations.validation.LongRangeValidator; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.io.OptionAttributeDefinition; +import org.xnio.Options; + +/** + * @author Tomaz Cerar + * @author Stuart Douglas + */ +abstract class ListenerResourceDefinition extends PersistentResourceDefinition { + + static final RuntimeCapability LISTENER_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_LISTENER, true, UndertowListener.class) + //.addDynamicRequirements(Capabilities.CAPABILITY_SERVER) -- has no function so don't use it + .setAllowMultipleRegistrations(true) //hack to support mod_cluster's legacy profiles + .build(); + protected static final SimpleAttributeDefinition SOCKET_BINDING = new SimpleAttributeDefinitionBuilder(Constants.SOCKET_BINDING, ModelType.STRING) + .setRequired(true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1)) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(REF_SOCKET_BINDING, LISTENER_CAPABILITY) + .build(); + protected static final SimpleAttributeDefinition WORKER = new SimpleAttributeDefinitionBuilder(Constants.WORKER, ModelType.STRING) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1)) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(REF_IO_WORKER, LISTENER_CAPABILITY) + .build(); + + protected static final SimpleAttributeDefinition BUFFER_POOL = new SimpleAttributeDefinitionBuilder(Constants.BUFFER_POOL, ModelType.STRING) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setValidator(new StringLengthValidator(1)) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(Capabilities.CAPABILITY_BYTE_BUFFER_POOL, LISTENER_CAPABILITY) + .build(); + + protected static final SimpleAttributeDefinition ENABLED = new SimpleAttributeDefinitionBuilder(Constants.ENABLED, ModelType.BOOLEAN) + .setRequired(false) + .setDeprecated(ModelVersion.create(3, 2)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition REDIRECT_SOCKET = new SimpleAttributeDefinitionBuilder(Constants.REDIRECT_SOCKET, ModelType.STRING) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setAllowExpression(false) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(REF_SOCKET_BINDING, LISTENER_CAPABILITY) + .build(); + + protected static final SimpleAttributeDefinition RESOLVE_PEER_ADDRESS = new SimpleAttributeDefinitionBuilder(Constants.RESOLVE_PEER_ADDRESS, ModelType.BOOLEAN) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final StringListAttributeDefinition DISALLOWED_METHODS = new StringListAttributeDefinition.Builder(Constants.DISALLOWED_METHODS) + .setDefaultValue(new ModelNode().add("TRACE")) + .setRequired(false) + .setValidator(new StringLengthValidator(0)) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition SECURE = new SimpleAttributeDefinitionBuilder(Constants.SECURE, ModelType.BOOLEAN) + .setDefaultValue(new ModelNode(false)) + .setRequired(false) + .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES) + .setAllowExpression(true) + .build(); + + public static final OptionAttributeDefinition BACKLOG = OptionAttributeDefinition.builder("tcp-backlog", Options.BACKLOG).setDefaultValue(new ModelNode(10000)).setAllowExpression(true).setValidator(new IntRangeValidator(1)).build(); + public static final OptionAttributeDefinition RECEIVE_BUFFER = OptionAttributeDefinition.builder("receive-buffer", Options.RECEIVE_BUFFER).setAllowExpression(true).setValidator(new IntRangeValidator(1)).build(); + public static final OptionAttributeDefinition SEND_BUFFER = OptionAttributeDefinition.builder("send-buffer", Options.SEND_BUFFER).setAllowExpression(true).setValidator(new IntRangeValidator(1)).build(); + public static final OptionAttributeDefinition KEEP_ALIVE = OptionAttributeDefinition.builder("tcp-keep-alive", Options.KEEP_ALIVE).setAllowExpression(true).build(); + public static final OptionAttributeDefinition READ_TIMEOUT = OptionAttributeDefinition.builder("read-timeout", Options.READ_TIMEOUT).setAllowExpression(true).setMeasurementUnit(MeasurementUnit.MILLISECONDS).build(); + public static final OptionAttributeDefinition WRITE_TIMEOUT = OptionAttributeDefinition.builder("write-timeout", Options.WRITE_TIMEOUT).setAllowExpression(true).setMeasurementUnit(MeasurementUnit.MILLISECONDS).build(); + public static final OptionAttributeDefinition MAX_CONNECTIONS = OptionAttributeDefinition.builder(Constants.MAX_CONNECTIONS, Options.CONNECTION_HIGH_WATER).setValidator(new IntRangeValidator(1)).setAllowExpression(true).build(); + + + public static final OptionAttributeDefinition MAX_HEADER_SIZE = OptionAttributeDefinition.builder("max-header-size", UndertowOptions.MAX_HEADER_SIZE).setDefaultValue(new ModelNode(UndertowOptions.DEFAULT_MAX_HEADER_SIZE)).setAllowExpression(true).setMeasurementUnit(MeasurementUnit.BYTES).setValidator(new IntRangeValidator(1)).build(); + public static final OptionAttributeDefinition MAX_ENTITY_SIZE = OptionAttributeDefinition.builder(Constants.MAX_POST_SIZE, UndertowOptions.MAX_ENTITY_SIZE).setDefaultValue(new ModelNode(10485760L)).setValidator(new LongRangeValidator(0)).setMeasurementUnit(MeasurementUnit.BYTES).setAllowExpression(true).build(); + public static final OptionAttributeDefinition BUFFER_PIPELINED_DATA = OptionAttributeDefinition.builder("buffer-pipelined-data", UndertowOptions.BUFFER_PIPELINED_DATA).setDefaultValue(new ModelNode(false)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition MAX_PARAMETERS = OptionAttributeDefinition.builder("max-parameters", UndertowOptions.MAX_PARAMETERS).setDefaultValue(new ModelNode(1000)).setValidator(new IntRangeValidator(1)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition MAX_HEADERS = OptionAttributeDefinition.builder("max-headers", UndertowOptions.MAX_HEADERS).setDefaultValue(new ModelNode(200)).setValidator(new IntRangeValidator(1)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition MAX_COOKIES = OptionAttributeDefinition.builder("max-cookies", UndertowOptions.MAX_COOKIES).setDefaultValue(new ModelNode(200)).setValidator(new IntRangeValidator(1)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition ALLOW_ENCODED_SLASH = OptionAttributeDefinition.builder("allow-encoded-slash", UndertowOptions.ALLOW_ENCODED_SLASH).setDefaultValue(new ModelNode(false)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition DECODE_URL = OptionAttributeDefinition.builder("decode-url", UndertowOptions.DECODE_URL).setDefaultValue(new ModelNode(true)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition URL_CHARSET = OptionAttributeDefinition.builder("url-charset", UndertowOptions.URL_CHARSET).setDefaultValue(new ModelNode("UTF-8")).setAllowExpression(true).build(); + public static final OptionAttributeDefinition ALWAYS_SET_KEEP_ALIVE = OptionAttributeDefinition.builder("always-set-keep-alive", UndertowOptions.ALWAYS_SET_KEEP_ALIVE).setDefaultValue(new ModelNode(true)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition MAX_BUFFERED_REQUEST_SIZE = OptionAttributeDefinition.builder(Constants.MAX_BUFFERED_REQUEST_SIZE, UndertowOptions.MAX_BUFFERED_REQUEST_SIZE).setDefaultValue(new ModelNode(16384)).setValidator(new IntRangeValidator(1)).setMeasurementUnit(MeasurementUnit.BYTES).setAllowExpression(true).build(); + public static final OptionAttributeDefinition RECORD_REQUEST_START_TIME = OptionAttributeDefinition.builder("record-request-start-time", UndertowOptions.RECORD_REQUEST_START_TIME).setDefaultValue(new ModelNode(false)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition ALLOW_EQUALS_IN_COOKIE_VALUE = OptionAttributeDefinition.builder("allow-equals-in-cookie-value", UndertowOptions.ALLOW_EQUALS_IN_COOKIE_VALUE).setDefaultValue(new ModelNode(false)).setAllowExpression(true).build(); + public static final OptionAttributeDefinition NO_REQUEST_TIMEOUT = OptionAttributeDefinition.builder("no-request-timeout", UndertowOptions.NO_REQUEST_TIMEOUT).setDefaultValue(new ModelNode(60000)).setMeasurementUnit(MeasurementUnit.MILLISECONDS).setRequired(false).setAllowExpression(true).build(); + public static final OptionAttributeDefinition REQUEST_PARSE_TIMEOUT = OptionAttributeDefinition.builder("request-parse-timeout", UndertowOptions.REQUEST_PARSE_TIMEOUT).setMeasurementUnit(MeasurementUnit.MILLISECONDS).setRequired(false).setAllowExpression(true).build(); + public static final OptionAttributeDefinition RFC6265_COOKIE_VALIDATION = OptionAttributeDefinition.builder("rfc6265-cookie-validation", UndertowOptions.ENABLE_RFC6265_COOKIE_VALIDATION).setDefaultValue(new ModelNode(false)).setRequired(false).setAllowExpression(true).build(); + public static final OptionAttributeDefinition ALLOW_UNESCAPED_CHARACTERS_IN_URL = OptionAttributeDefinition.builder("allow-unescaped-characters-in-url", UndertowOptions.ALLOW_UNESCAPED_CHARACTERS_IN_URL).setDefaultValue(new ModelNode(false)).setRequired(false).setAllowExpression(true).build(); + + public enum ConnectorStat { + REQUEST_COUNT(new SimpleAttributeDefinitionBuilder("request-count", ModelType.LONG) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + BYTES_SENT(new SimpleAttributeDefinitionBuilder("bytes-sent", ModelType.LONG) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + BYTES_RECEIVED(new SimpleAttributeDefinitionBuilder("bytes-received", ModelType.LONG) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + ERROR_COUNT(new SimpleAttributeDefinitionBuilder("error-count", ModelType.LONG) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + PROCESSING_TIME(new SimpleAttributeDefinitionBuilder("processing-time", ModelType.LONG) + .setMeasurementUnit(MeasurementUnit.NANOSECONDS) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()), + MAX_PROCESSING_TIME(new SimpleAttributeDefinitionBuilder("max-processing-time", ModelType.LONG) + .setMeasurementUnit(MeasurementUnit.NANOSECONDS) + .setUndefinedMetricValue(new ModelNode(0)).setStorageRuntime().build()); + + private static final Map MAP = new HashMap<>(); + + static { + for (ConnectorStat stat : EnumSet.allOf(ConnectorStat.class)) { + MAP.put(stat.toString(), stat); + } + } + + final AttributeDefinition definition; + + private ConnectorStat(final AttributeDefinition definition) { + this.definition = definition; + } + + @Override + public final String toString() { + return definition.getName(); + } + + public static synchronized ConnectorStat getStat(final String stringForm) { + return MAP.get(stringForm); + } + } + + protected static final Collection ATTRIBUTES; + private static final List CONSTRAINTS = Collections.singletonList(UndertowExtension.LISTENER_CONSTRAINT); + + static final List LISTENER_OPTIONS = Arrays.asList(MAX_HEADER_SIZE, MAX_ENTITY_SIZE, + BUFFER_PIPELINED_DATA, MAX_PARAMETERS, MAX_HEADERS, MAX_COOKIES, ALLOW_ENCODED_SLASH, DECODE_URL, + URL_CHARSET, ALWAYS_SET_KEEP_ALIVE, MAX_BUFFERED_REQUEST_SIZE, RECORD_REQUEST_START_TIME, + ALLOW_EQUALS_IN_COOKIE_VALUE, NO_REQUEST_TIMEOUT, REQUEST_PARSE_TIMEOUT, RFC6265_COOKIE_VALIDATION, + ALLOW_UNESCAPED_CHARACTERS_IN_URL); + + static final List SOCKET_OPTIONS = Arrays.asList(BACKLOG, RECEIVE_BUFFER, SEND_BUFFER, KEEP_ALIVE, READ_TIMEOUT, WRITE_TIMEOUT, MAX_CONNECTIONS); + + static { + ATTRIBUTES = new LinkedHashSet<>(Arrays.asList(SOCKET_BINDING, WORKER, BUFFER_POOL, ENABLED, RESOLVE_PEER_ADDRESS, DISALLOWED_METHODS, SECURE)); + ATTRIBUTES.addAll(LISTENER_OPTIONS); + ATTRIBUTES.addAll(SOCKET_OPTIONS); + } + + public ListenerResourceDefinition(PathElement pathElement) { + super(new PersistentResourceDefinition.Parameters(pathElement, UndertowExtension.getResolver(Constants.LISTENER)) + .setCapabilities(LISTENER_CAPABILITY)); + } + + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + super.registerAddOperation(resourceRegistration, getAddHandler(), OperationEntry.Flag.RESTART_NONE); + super.registerRemoveOperation(resourceRegistration, new ListenerRemoveHandler(getAddHandler()), OperationEntry.Flag.RESTART_NONE); + resourceRegistration.registerOperationHandler(ResetConnectorStatisticsHandler.DEFINITION, ResetConnectorStatisticsHandler.INSTANCE); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + // DO NOT call super, as we need non-standard handling for enabled + + Collection ads = getAttributes(); + OperationStepHandler rrh = new ReloadRequiredWriteAttributeHandler(ads); // we include ENABLED in this set, but it doesn't matter we don't register rrh for it + OperationStepHandler enh = new EnabledAttributeHandler(); + for (AttributeDefinition ad : ads) { + OperationStepHandler osh = ad == ENABLED ? enh : rrh; + resourceRegistration.registerReadWriteAttribute(ad, null, osh); + } + + for(ConnectorStat attr : ConnectorStat.values()) { + resourceRegistration.registerMetric(attr.definition, ReadStatisticHandler.INSTANCE); + } + } + + @Override + public List getAccessConstraints() { + return CONSTRAINTS; + } + + protected abstract ListenerAdd getAddHandler(); + + + private static class ReadStatisticHandler implements OperationStepHandler { + + public static final ReadStatisticHandler INSTANCE = new ReadStatisticHandler(); + + private ReadStatisticHandler() { + + } + + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + ListenerService service = getListenerService(context); + if (service == null) { + context.getResult().set(0L); + return; + } + String op = operation.get(NAME).asString(); + ConnectorStatistics stats = service.getOpenListener().getConnectorStatistics(); + if(stats != null) { + ConnectorStat element = ConnectorStat.getStat(op); + switch (element) { + case BYTES_RECEIVED: + context.getResult().set(stats.getBytesReceived()); + break; + case BYTES_SENT: + context.getResult().set(stats.getBytesSent()); + break; + case ERROR_COUNT: + context.getResult().set(stats.getErrorCount()); + break; + case MAX_PROCESSING_TIME: + context.getResult().set(stats.getMaxProcessingTime()); + break; + case PROCESSING_TIME: + context.getResult().set(stats.getProcessingTime()); + break; + case REQUEST_COUNT: + context.getResult().set(stats.getRequestCount()); + break; + } + } else { + context.getResult().set(0L); + } + context.completeStep(OperationContext.RollbackHandler.NOOP_ROLLBACK_HANDLER); + } + } + + static ListenerService getListenerService(OperationContext context) { + final String name = context.getCurrentAddressValue(); + ServiceName serviceName = LISTENER_CAPABILITY.getCapabilityServiceName(name); + ServiceController listenerSC = (ServiceController) context.getServiceRegistry(false).getService(serviceName); + if (listenerSC == null || listenerSC.getState() != ServiceController.State.UP) { + return null; + } + return listenerSC.getValue(); + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(LISTENER_CAPABILITY); + } + + private static class EnabledAttributeHandler extends AbstractWriteAttributeHandler { + @Override + protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode resolvedValue, ModelNode currentValue, HandbackHolder handbackHolder) throws OperationFailedException { + + boolean enabled = resolvedValue.asBoolean(); + // We don't try and analyze currentValue to see if we were already enabled, as the resolution result + // may be different now than it was before (different system props, or vault contents) + // Instead we consider the previous setting to be enabled if the service Mode != Mode.NEVER + ListenerService listenerService = getListenerService(context); + if (listenerService != null) { + boolean currentEnabled = listenerService.isEnabled(); + handbackHolder.setHandback(currentEnabled); + listenerService.setEnabled(enabled); + } + return false; + } + + @Override + protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode valueToRestore, ModelNode valueToRevert, Boolean handback) throws OperationFailedException { + if (handback != null) { + ListenerService listenerService = getListenerService(context); + if (listenerService != null) { + listenerService.setEnabled(handback); + } + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ListenerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,311 @@ +/* + * 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.extension.undertow; + +import java.io.IOException; +import java.net.BindException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import javax.net.ssl.SSLContext; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import io.undertow.connector.ByteBufferPool; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.OpenListener; +import io.undertow.server.protocol.proxy.ProxyProtocolOpenListener; +import io.undertow.util.StatusCodes; + +import org.jboss.as.network.ManagedBinding; +import org.jboss.as.network.SocketBinding; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceContainer; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; + +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import org.xnio.ChannelListener; +import org.xnio.ChannelListeners; +import org.xnio.OptionMap; +import org.xnio.Options; +import org.xnio.StreamConnection; +import org.xnio.XnioWorker; +import org.xnio.channels.AcceptingChannel; + +/** + * @author Tomaz Cerar + */ +public abstract class ListenerService implements Service, UndertowListener { + + protected static final OptionMap commonOptions = OptionMap.builder() + .set(Options.TCP_NODELAY, true) + .set(Options.REUSE_ADDRESSES, true) + .set(Options.BALANCING_TOKENS, 1) + .set(Options.BALANCING_CONNECTIONS, 2) + .getMap(); + + protected final InjectedValue worker = new InjectedValue<>(); + protected final InjectedValue binding = new InjectedValue<>(); + protected final InjectedValue redirectSocket = new InjectedValue<>(); + @SuppressWarnings("rawtypes") + protected final InjectedValue bufferPool = new InjectedValue<>(); + protected final InjectedValue serverService = new InjectedValue<>(); + private final List listenerHandlerWrappers = new ArrayList<>(); + + private final String name; + protected final OptionMap listenerOptions; + protected final OptionMap socketOptions; + protected volatile OpenListener openListener; + private volatile boolean enabled; + private volatile boolean started; + private Consumer statisticsChangeListener; + private final boolean proxyProtocol; + private volatile HandlerWrapper stoppingWrapper; + + protected ListenerService(String name, OptionMap listenerOptions, OptionMap socketOptions, boolean proxyProtocol) { + this.name = name; + this.listenerOptions = listenerOptions; + this.socketOptions = socketOptions; + this.proxyProtocol = proxyProtocol; + } + + public InjectedValue getWorker() { + return worker; + } + + public InjectedValue getBinding() { + return binding; + } + + public InjectedValue getRedirectSocket() { + return redirectSocket; + } + + @SuppressWarnings("rawtypes") + public InjectedValue getBufferPool() { + return bufferPool; + } + + public InjectedValue getServerService() { + return serverService; + } + + protected UndertowService getUndertowService() { + return serverService.getValue().getUndertowService(); + } + + public String getName() { + return name; + } + + @Override + public Server getServer() { + return this.serverService.getValue(); + } + + public boolean isEnabled() { + return enabled; + } + + protected UndertowXnioSsl getSsl() { + return null; + } + + protected OptionMap getSSLOptions(SSLContext sslContext) { + return OptionMap.EMPTY; + } + + public synchronized void setEnabled(boolean enabled) { + if(started && enabled != this.enabled) { + if(enabled) { + final InetSocketAddress socketAddress = binding.getValue().getSocketAddress(); + final ChannelListener> acceptListener = ChannelListeners.openListenerAdapter(openListener); + try { + startListening(worker.getValue(), socketAddress, acceptListener); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + stopListening(); + } + } + this.enabled = enabled; + } + + public abstract boolean isSecure(); + + protected void registerBinding() { + binding.getValue().getSocketBindings().getNamedRegistry().registerBinding(new ListenerBinding(binding.getValue())); + } + + protected void unregisterBinding() { + final SocketBinding binding = this.binding.getValue(); + binding.getSocketBindings().getNamedRegistry().unregisterBinding(binding.getName()); + } + + protected abstract void preStart(StartContext context); + + @Override + public void start(final StartContext context) throws StartException { + started = true; + preStart(context); + serverService.getValue().registerListener(this); + try { + openListener = createOpenListener(); + HttpHandler handler = serverService.getValue().getRoot(); + for(HandlerWrapper wrapper : listenerHandlerWrappers) { + handler = wrapper.wrap(handler); + } + openListener.setRootHandler(handler); + if(enabled) { + final InetSocketAddress socketAddress = binding.getValue().getSocketAddress(); + + + final ChannelListener> acceptListener; + if(proxyProtocol) { + UndertowXnioSsl xnioSsl = getSsl(); + acceptListener = ChannelListeners.openListenerAdapter(new ProxyProtocolOpenListener(openListener, xnioSsl, bufferPool.getValue(), xnioSsl != null ? getSSLOptions(xnioSsl.getSslContext()) : null)); + } else { + acceptListener = ChannelListeners.openListenerAdapter(openListener); + } + startListening(worker.getValue(), socketAddress, acceptListener); + } + registerBinding(); + } catch (IOException e) { + cleanFailedStart(); + if (e instanceof BindException) { + final StringBuilder sb = new StringBuilder().append(e.getLocalizedMessage()); + final InetSocketAddress socketAddress = binding.getValue().getSocketAddress(); + if (socketAddress != null) + sb.append(" ").append(socketAddress); + throw new StartException(sb.toString()); + } else { + throw UndertowLogger.ROOT_LOGGER.couldNotStartListener(name, e); + } + } + statisticsChangeListener = (enabled) -> { + OptionMap options = openListener.getUndertowOptions(); + OptionMap.Builder builder = OptionMap.builder().addAll(options); + builder.set(UndertowOptions.ENABLE_STATISTICS, enabled); + openListener.setUndertowOptions(builder.getMap()); + }; + getUndertowService().registerStatisticsListener(statisticsChangeListener); + final ServiceContainer container = context.getController().getServiceContainer(); + this.stoppingWrapper = new HandlerWrapper() { + @Override + public HttpHandler wrap(HttpHandler handler) { + return new HttpHandler() { + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + //graceful shutdown is handled by the host service, so if the container is actually shutting down there + //is a brief window where this will result in a 404 rather than a 503 + //even without graceful shutdown we start returning 503 once the container has started shutting down + if(container.isShutdown()) { + exchange.setStatusCode(StatusCodes.SERVICE_UNAVAILABLE); + return; + } + handler.handleRequest(exchange); + } + }; + } + }; + addWrapperHandler(stoppingWrapper); + } + + protected abstract void cleanFailedStart(); + + @Override + public void stop(StopContext context) { + started = false; + serverService.getValue().unregisterListener(this); + if(enabled) { + stopListening(); + } + unregisterBinding(); + getUndertowService().unregisterStatisticsListener(statisticsChangeListener); + statisticsChangeListener = null; + listenerHandlerWrappers.remove(stoppingWrapper); + stoppingWrapper = null; + } + + void addWrapperHandler(HandlerWrapper wrapper){ + listenerHandlerWrappers.add(wrapper); + } + + public OpenListener getOpenListener() { + return openListener; + } + + protected abstract OpenListener createOpenListener(); + + abstract void startListening(XnioWorker worker, InetSocketAddress socketAddress, ChannelListener> acceptListener) throws IOException; + + abstract void stopListening(); + + public abstract String getProtocol(); + + @Override + public boolean isShutdown() { + XnioWorker worker = getWorker().getOptionalValue(); + return worker == null || worker.isShutdown(); + } + + @Override + public SocketBinding getSocketBinding() { + return binding.getValue(); + } + + private static class ListenerBinding implements ManagedBinding { + + private final SocketBinding binding; + + private ListenerBinding(final SocketBinding binding) { + this.binding = binding; + } + + @Override + public String getSocketBindingName() { + return binding.getName(); + } + + @Override + public InetSocketAddress getBindAddress() { + return binding.getSocketAddress(); + } + + @Override + public void close() throws IOException { + + } + } + + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,64 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class LocationAdd extends AbstractAddStepHandler { + static LocationAdd INSTANCE = new LocationAdd(); + + private LocationAdd() { + super(LocationDefinition.HANDLER); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress hostAddress = context.getCurrentAddress().getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + final String name = context.getCurrentAddressValue(); + final String handler = LocationDefinition.HANDLER.resolveModelAttribute(context, model).asString(); + + final LocationService service = new LocationService(name); + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + final ServiceName serviceName = UndertowService.locationServiceName(serverName, hostName, name); + final ServiceBuilder builder = context.getCapabilityServiceTarget().addCapability(LocationDefinition.LOCATION_CAPABILITY, service) + .addCapabilityRequirement(Capabilities.CAPABILITY_HANDLER, HttpHandler.class, service.getHttpHandler(),handler) + .addCapabilityRequirement(Capabilities.CAPABILITY_HOST, Host.class, service.getHost(), serverName, hostName); + + builder.setInitialMode(ServiceController.Mode.ACTIVE) + .addAliases(serviceName) + .install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,92 @@ +/* + * 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.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class LocationDefinition extends PersistentResourceDefinition { + static final RuntimeCapability LOCATION_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_LOCATION, true, LocationService.class) + .addRequirements(Capabilities.CAPABILITY_UNDERTOW) + .setDynamicNameMapper(path -> new String[]{ + path.getParent().getParent().getLastElement().getValue(), + path.getParent().getLastElement().getValue(), + path.getLastElement().getValue()}) + .build(); + + static final AttributeDefinition HANDLER = new SimpleAttributeDefinitionBuilder(Constants.HANDLER, ModelType.STRING) + .setRequired(true) + .setValidator(new StringLengthValidator(1)) + .setCapabilityReference(Capabilities.CAPABILITY_HANDLER) + .setRestartAllServices() + .build(); + private static final List CHILDREN = Collections.unmodifiableList(Arrays.asList(FilterRefDefinition.INSTANCE)); + static final LocationDefinition INSTANCE = new LocationDefinition(); + + + private LocationDefinition() { + super(UndertowExtension.PATH_LOCATION, + UndertowExtension.getResolver(Constants.HOST, Constants.LOCATION), + LocationAdd.INSTANCE, + new ServiceRemoveStepHandler(LocationAdd.INSTANCE) { + + @Override + protected ServiceName serviceName(String name, PathAddress address) { + return LOCATION_CAPABILITY.getCapabilityServiceName(address); + } + } + ); + } + + @Override + public Collection getAttributes() { + return Collections.singleton(HANDLER); + } + + @Override + public List getChildren() { + return CHILDREN; + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(LOCATION_CAPABILITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/LocationService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,131 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class LocationService implements Service, FilterLocation { + + private final String locationPath; + private final InjectedValue httpHandler = new InjectedValue<>(); + private final InjectedValue host = new InjectedValue<>(); + private final CopyOnWriteArrayList filters = new CopyOnWriteArrayList<>(); + private final LocationHandler locationHandler = new LocationHandler(); + private volatile HttpHandler configuredHandler; + + public LocationService(String locationPath) { + this.locationPath = locationPath; + } + + @Override + public void start(StartContext context) throws StartException { + UndertowLogger.ROOT_LOGGER.tracef("registering handler %s under path '%s'", httpHandler.getValue(), locationPath); + host.getValue().registerLocation(this); + } + + @Override + public void stop(StopContext context) { + host.getValue().unregisterLocation(this); + } + + @Override + public LocationService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + InjectedValue getHost() { + return host; + } + + InjectedValue getHttpHandler() { + return httpHandler; + } + + String getLocationPath() { + return locationPath; + } + + LocationHandler getLocationHandler() { + return locationHandler; + } + + private HttpHandler configureHandler() { + ArrayList filters = new ArrayList<>(this.filters); + return configureHandlerChain(getHttpHandler().getValue(), filters); + } + + protected static HttpHandler configureHandlerChain(HttpHandler rootHandler, List filters) { + filters.sort((o1, o2) -> o1.getPriority() >= o2.getPriority() ? 1 : -1); + Collections.reverse(filters); //handler chain goes last first + HttpHandler handler = rootHandler; + for (UndertowFilter filter : filters) { + handler = filter.wrap(handler); + } + + return handler; + } + + @Override + public void addFilter(UndertowFilter filterRef) { + filters.add(filterRef); + configuredHandler = null; + } + + @Override + public void removeFilter(UndertowFilter filterRef) { + filters.remove(filterRef); + configuredHandler = null; + } + + private class LocationHandler implements HttpHandler { + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + HttpHandler root = configuredHandler; + if(root == null) { + synchronized (LocationService.this) { + root = configuredHandler; + if(root == null) { + root = configuredHandler = configureHandler(); + } + } + } + root.handleRequest(exchange); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/MimeMappingDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/MimeMappingDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/MimeMappingDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,75 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredAddStepHandler; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelType; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Global mime mapping config for file types + * + * @author Stuart Douglas + */ +class MimeMappingDefinition extends PersistentResourceDefinition { + + + protected static final SimpleAttributeDefinition VALUE = + new SimpleAttributeDefinitionBuilder(Constants.VALUE, ModelType.STRING, false) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + VALUE + }; + + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + static final MimeMappingDefinition INSTANCE = new MimeMappingDefinition(); + + private MimeMappingDefinition() { + super(UndertowExtension.PATH_MIME_MAPPING, + UndertowExtension.getResolver(Constants.MIME_MAPPING), new ReloadRequiredAddStepHandler(ATTRIBUTES), new ReloadRequiredRemoveStepHandler()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Namespace.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Namespace.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Namespace.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,83 @@ +/* + * 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.extension.undertow; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +enum Namespace { + + // must be first + UNKNOWN(null), + + UNDERTOW_1_0("urn:jboss:domain:undertow:1.0"), + UNDERTOW_1_1("urn:jboss:domain:undertow:1.1"), + UNDERTOW_1_2("urn:jboss:domain:undertow:1.2"), + UNDERTOW_2_0("urn:jboss:domain:undertow:2.0"), + UNDERTOW_3_0("urn:jboss:domain:undertow:3.0"), + UNDERTOW_3_1("urn:jboss:domain:undertow:3.1"), + UNDERTOW_4_0("urn:jboss:domain:undertow:4.0"), + UNDERTOW_5_0("urn:jboss:domain:undertow:5.0"), + UNDERTOW_6_0("urn:jboss:domain:undertow:6.0"), + UNDERTOW_7_0("urn:jboss:domain:undertow:7.0"); + + /** + * The current namespace version. + */ + public static final Namespace CURRENT = UNDERTOW_7_0; + + private final String name; + + Namespace(final String name) { + this.name = name; + } + + /** + * Get the URI of this namespace. + * + * @return the URI + */ + public String getUriString() { + return name; + } + + private static final Map MAP; + + static { + final Map map = new HashMap(); + for (Namespace namespace : values()) { + final String name = namespace.getUriString(); + if (name != null) { map.put(name, namespace); } + } + MAP = map; + } + + public static Namespace forUri(String uri) { + final Namespace element = MAP.get(uri); + return element == null ? UNKNOWN : element; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/PersistentSessionsDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/PersistentSessionsDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/PersistentSessionsDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,191 @@ +/* + * 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.extension.undertow; + +import io.undertow.servlet.api.SessionPersistenceManager; +import org.jboss.as.controller.AttributeDefinition; +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.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.as.controller.services.path.PathManagerService; +import org.jboss.as.server.Services; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.modules.ModuleLoader; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Global session cookie config + * + * @author Stuart Douglas + */ +class PersistentSessionsDefinition extends PersistentResourceDefinition { + + static final PersistentSessionsDefinition INSTANCE = new PersistentSessionsDefinition(); + + protected static final SimpleAttributeDefinition PATH = + new SimpleAttributeDefinitionBuilder(Constants.PATH, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition RELATIVE_TO = + new SimpleAttributeDefinitionBuilder(Constants.RELATIVE_TO, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + PATH, + RELATIVE_TO + }; + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + + private PersistentSessionsDefinition() { + super(UndertowExtension.PATH_PERSISTENT_SESSIONS, + UndertowExtension.getResolver(UndertowExtension.PATH_PERSISTENT_SESSIONS.getKeyValuePair()), + new PersistentSessionsAdd(), + new PersistentSessionsRemove()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } + + public static boolean isEnabled(final OperationContext context, final ModelNode model) throws OperationFailedException { + return model.isDefined(); + } + + + private static class PersistentSessionsAdd extends RestartParentResourceAddHandler { + protected PersistentSessionsAdd() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException { + super.execute(context, operation); + if (requiresRuntime(context)) { + context.addStep(new OperationStepHandler() { + public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException { + performRuntime(context, operation, operation); + + + context.completeStep(new OperationContext.RollbackHandler() { + @Override + public void handleRollback(OperationContext context, ModelNode operation) { + rollbackRuntime(context, operation, operation); + } + }); + } + }, OperationContext.Stage.RUNTIME); + } + } + + private void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + if (isEnabled(context, model)) { + ModelNode pathValue = PATH.resolveModelAttribute(context, model); + ServiceBuilder builder; + if (pathValue.isDefined()) { + String path = pathValue.asString(); + ModelNode relativeToValue = RELATIVE_TO.resolveModelAttribute(context, model); + String relativeTo = relativeToValue.isDefined() ? relativeToValue.asString() : null; + final DiskBasedModularPersistentSessionManager service = new DiskBasedModularPersistentSessionManager(path, relativeTo); + builder = context.getServiceTarget().addService(AbstractPersistentSessionManager.SERVICE_NAME, service) + .addDependency(Services.JBOSS_SERVICE_MODULE_LOADER, ModuleLoader.class, service.getModuleLoaderInjectedValue()) + .addDependency(PathManagerService.SERVICE_NAME, PathManager.class, service.getPathManager()); + + } else { + final InMemoryModularPersistentSessionManager service = new InMemoryModularPersistentSessionManager(); + builder = context.getServiceTarget().addService(AbstractPersistentSessionManager.SERVICE_NAME, service) + .addDependency(Services.JBOSS_SERVICE_MODULE_LOADER, ModuleLoader.class, service.getModuleLoaderInjectedValue()); + } + builder.install(); + } + } + + private void rollbackRuntime(OperationContext context, ModelNode operation, ModelNode model) { + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } + + private static class PersistentSessionsRemove extends RestartParentResourceRemoveHandler { + + protected PersistentSessionsRemove() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void removeServices(OperationContext context, ServiceName parentService, ModelNode parentModel) throws OperationFailedException { + super.removeServices(context, parentService, parentModel); + context.removeService(AbstractPersistentSessionManager.SERVICE_NAME); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/PredicateValidator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/PredicateValidator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/PredicateValidator.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,58 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.operations.validation.ModelTypeValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import io.undertow.predicate.PredicateParser; + +/** + * @author Stuart Douglas + */ +public class PredicateValidator extends ModelTypeValidator { + + public static final PredicateValidator INSTANCE = new PredicateValidator(); + + private PredicateValidator() { + super(ModelType.STRING, true, true); + } + + /** + * {@inheritDoc} + */ + @Override + public void validateParameter(String parameterName, ModelNode value) throws OperationFailedException { + super.validateParameter(parameterName, value); + if (value.isDefined() && value.getType() != ModelType.EXPRESSION) { + String val = value.asString(); + try { + PredicateParser.parse(val, getClass().getClassLoader()); + } catch (Exception e) { + throw new OperationFailedException(UndertowLogger.ROOT_LOGGER.predicateNotValid(val, e.getMessage()), e); + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/RemoteHttpInvokerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/RemoteHttpInvokerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/RemoteHttpInvokerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,68 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.handlers.CookieImpl; +import io.undertow.server.session.SecureRandomSessionIdGenerator; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import io.undertow.server.handlers.PathHandler; + +/** + * Service that exposes the Wildfly + * + * @author Stuart Douglas + */ +public class RemoteHttpInvokerService implements Service { + + private static final String AFFINITY_PATH = "/common/v1/affinity"; + + private final PathHandler pathHandler = new PathHandler(); + + @Override + public void start(StartContext context) throws StartException { + pathHandler.clearPaths(); + SecureRandomSessionIdGenerator generator = new SecureRandomSessionIdGenerator(); + + pathHandler.addPrefixPath(AFFINITY_PATH, exchange -> { + String resolved = exchange.getResolvedPath(); + int index = resolved.lastIndexOf(AFFINITY_PATH); + if(index > 0) { + resolved = resolved.substring(0, index); + } + exchange.getResponseCookies().put("JSESSIONID", new CookieImpl("JSESSIONID", generator.createSessionId()).setPath(resolved)); + }); + } + + @Override + public void stop(StopContext context) { + pathHandler.clearPaths(); + } + + @Override + public PathHandler getValue() throws IllegalStateException, IllegalArgumentException { + return pathHandler; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ResetConnectorStatisticsHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ResetConnectorStatisticsHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ResetConnectorStatisticsHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,63 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.ConnectorStatistics; +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.SimpleOperationDefinitionBuilder; +import org.jboss.dmr.ModelNode; + + +/** + * Defines and handles reseting connector statistics + * + * @author Stuart Douglas + */ +public class ResetConnectorStatisticsHandler implements OperationStepHandler { + public static final String OPERATION_NAME = "reset-statistics"; + + public static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, UndertowExtension.getResolver("listener")) + .setRuntimeOnly() + .build(); + + public static final ResetConnectorStatisticsHandler INSTANCE = new ResetConnectorStatisticsHandler(); + + private ResetConnectorStatisticsHandler() { + + } + + public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + ListenerService service = ListenerResourceDefinition.getListenerService(context); + if (service != null) { + ConnectorStatistics stats = service.getOpenListener().getConnectorStatistics(); + if (stats != null) { + stats.reset(); + } + } + context.completeStep(OperationContext.RollbackHandler.NOOP_ROLLBACK_HANDLER); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/Server.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/Server.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/Server.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,192 @@ +/* + * 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.extension.undertow; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.CanonicalPathHandler; +import io.undertow.server.handlers.NameVirtualHostHandler; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.server.handlers.error.SimpleErrorPageHandler; +import io.undertow.util.Headers; +import org.jboss.as.network.SocketBinding; +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class Server implements Service { + private final String defaultHost; + private final String name; + private final NameVirtualHostHandler virtualHostHandler = new NameVirtualHostHandler(); + private final InjectedValue servletContainer = new InjectedValue<>(); + private final InjectedValue undertowService = new InjectedValue<>(); + private volatile HttpHandler root; + private final List listeners = new CopyOnWriteArrayList<>(); + private final Set hosts = new CopyOnWriteArraySet<>(); + + private final HashMap securePortMappings = new HashMap<>(); + + protected Server(String name, String defaultHost) { + this.name = name; + this.defaultHost = defaultHost; + } + + @Override + public void start(StartContext startContext) throws StartException { + root = virtualHostHandler; + root = new SimpleErrorPageHandler(root); + root = new CanonicalPathHandler(root); + root = new DefaultHostHandler(root); + + UndertowLogger.ROOT_LOGGER.startedServer(name); + undertowService.getValue().registerServer(this); + } + + protected void registerListener(ListenerService listener) { + listeners.add(listener); + if (!listener.isSecure()) { + SocketBinding binding = listener.getBinding().getValue(); + SocketBinding redirectBinding = listener.getRedirectSocket().getOptionalValue(); + if (redirectBinding!=null) { + securePortMappings.put(binding.getAbsolutePort(), redirectBinding.getAbsolutePort()); + }else{ + securePortMappings.put(binding.getAbsolutePort(), -1); + } + } + } + + protected void unregisterListener(ListenerService listener) { + listeners.remove(listener); + if (!listener.isSecure()) { + SocketBinding binding = listener.getBinding().getValue(); + securePortMappings.remove(binding.getAbsolutePort()); + } + } + + protected void registerHost(final Host host) { + hosts.add(host); + for (String hostName : host.getAllAliases()) { + virtualHostHandler.addHost(hostName, host.getRootHandler()); + } + if (host.getName().equals(getDefaultHost())) { + virtualHostHandler.setDefaultHandler(host.getRootHandler()); + } + } + + protected void unregisterHost(Host host) { + for (String hostName : host.getAllAliases()) { + virtualHostHandler.removeHost(hostName); + hosts.remove(host); + } + if (host.getName().equals(getDefaultHost())) { + virtualHostHandler.setDefaultHandler(ResponseCodeHandler.HANDLE_404); + } + } + + public int lookupSecurePort(final int unsecurePort) { + return securePortMappings.get(unsecurePort); + } + + @Override + public void stop(StopContext stopContext) { + undertowService.getValue().unregisterServer(this); + } + + @Override + public Server getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + Injector getServletContainerInjector() { + return servletContainer; + } + + public ServletContainerService getServletContainer() { + return servletContainer.getValue(); + } + + protected HttpHandler getRoot() { + return root; + } + + protected Injector getUndertowServiceInjector() { + return undertowService; + } + + UndertowService getUndertowService() { + return undertowService.getValue(); + } + + public String getName() { + return name; + } + + public String getDefaultHost() { + return defaultHost; + } + + public Set getHosts() { + return Collections.unmodifiableSet(hosts); + } + + public List getListeners() { + return (List)listeners; + } + + public String getRoute() { + UndertowService service = this.undertowService.getValue(); + String defaultServerRoute = service.getInstanceId(); + return this.name.equals(service.getDefaultServer()) ? defaultServerRoute : String.join("-", defaultServerRoute, this.name); + } + + private final class DefaultHostHandler implements HttpHandler { + + private final HttpHandler next; + + private DefaultHostHandler(HttpHandler next) { + this.next = next; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if(!exchange.getRequestHeaders().contains(Headers.HOST)) { + exchange.getRequestHeaders().put(Headers.HOST, defaultHost + ":" + exchange.getDestinationAddress().getPort()); + } + next.handleRequest(exchange); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,119 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.ServerDefinition.SERVER_CAPABILITY; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.web.host.CommonWebServer; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.Property; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.extension.undertow.session.DistributableSessionIdentifierCodecServiceConfiguratorProvider; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class ServerAdd extends AbstractAddStepHandler { + + ServerAdd() { + super(new Parameters() + .addAttribute(ServerDefinition.ATTRIBUTES) + .addRuntimeCapability(SERVER_CAPABILITY)//only have server capability automatically registered + ); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + final ModelNode parentModel = context.readResourceFromRoot(context.getCurrentAddress().getParent(), false).getModel(); + + final String name = context.getCurrentAddressValue(); + final String defaultHost = ServerDefinition.DEFAULT_HOST.resolveModelAttribute(context, resource.getModel()).asString(); + final String servletContainer = ServerDefinition.SERVLET_CONTAINER.resolveModelAttribute(context, resource.getModel()).asString(); + final String defaultServerName = UndertowRootDefinition.DEFAULT_SERVER.resolveModelAttribute(context, parentModel).asString(); + + final Server service = new Server(name, defaultHost); + final ServiceBuilder builder = context.getCapabilityServiceTarget().addCapability(SERVER_CAPABILITY, service) + .addCapabilityRequirement(Capabilities.CAPABILITY_SERVLET_CONTAINER, ServletContainerService.class, service.getServletContainerInjector(), servletContainer) + .addCapabilityRequirement(Capabilities.CAPABILITY_UNDERTOW, UndertowService.class, service.getUndertowServiceInjector()); + + builder.setInitialMode(ServiceController.Mode.ACTIVE); + boolean isDefaultServer = name.equals(defaultServerName); + + if (isDefaultServer) { //only install for default server + builder.addAliases(UndertowService.DEFAULT_SERVER);//register default server service name + + WebServerService commonWebServer = new WebServerService(); + final ServiceBuilder commonServerBuilder = context.getCapabilityServiceTarget().addCapability(CommonWebServer.CAPABILITY, commonWebServer) + .addCapabilityRequirement(Capabilities.CAPABILITY_SERVER, Server.class, commonWebServer.getServerInjectedValue(), name) + .setInitialMode(ServiceController.Mode.PASSIVE); + + addCommonHostListenerDeps(context, commonServerBuilder, UndertowExtension.HTTP_LISTENER_PATH); + addCommonHostListenerDeps(context, commonServerBuilder, UndertowExtension.AJP_LISTENER_PATH); + addCommonHostListenerDeps(context, commonServerBuilder, UndertowExtension.HTTPS_LISTENER_PATH); + //backward compatibility + commonServerBuilder.addAliases(CommonWebServer.SERVICE_NAME); + commonServerBuilder.install(); + } + builder.install(); + + ServiceTarget target = context.getServiceTarget(); + DistributableSessionIdentifierCodecServiceConfiguratorProvider provider = DistributableSessionIdentifierCodecServiceConfiguratorProvider.INSTANCE.orElse(null); + if (provider != null) { + for (CapabilityServiceConfigurator configurator : provider.getServerServiceConfigurators(name)) { + configurator.configure(context).build(target).install(); + } + } + } + + @Override + protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + super.recordCapabilitiesAndRequirements(context, operation, resource); + + ModelNode parentModel = context.readResourceFromRoot(context.getCurrentAddress().getParent(), false).getModel(); + final String defaultServerName = UndertowRootDefinition.DEFAULT_SERVER.resolveModelAttribute(context, parentModel).asString(); + boolean isDefaultServer = context.getCurrentAddressValue().equals(defaultServerName); + if (isDefaultServer) { + context.registerCapability(CommonWebServer.CAPABILITY); + } + } + + private void addCommonHostListenerDeps(OperationContext context, ServiceBuilder builder, final PathElement listenerPath) { + ModelNode listeners = Resource.Tools.readModel(context.readResource(PathAddress.pathAddress(listenerPath)), 1); + if (listeners.isDefined()) { + for (Property p : listeners.asPropertyList()) { + for (Property listener : p.getValue().asPropertyList()) { + builder.addDependency(ListenerResourceDefinition.LISTENER_CAPABILITY.getCapabilityServiceName(listener.getName())); + } + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServerDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,89 @@ +/* + * 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.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.web.host.CommonWebServer; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class ServerDefinition extends PersistentResourceDefinition { + static final RuntimeCapability SERVER_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_SERVER, true, Server.class) + .addRequirements(Capabilities.CAPABILITY_UNDERTOW) + .build(); + + static final SimpleAttributeDefinition DEFAULT_HOST = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_HOST, ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("default-host")) + .setRestartAllServices() + .build(); + static final SimpleAttributeDefinition SERVLET_CONTAINER = new SimpleAttributeDefinitionBuilder(Constants.SERVLET_CONTAINER, ModelType.STRING) + .setRequired(false) + .setDefaultValue(new ModelNode("default")) + .setRestartAllServices() + .build(); + static final AttributeDefinition[] ATTRIBUTES = {DEFAULT_HOST, SERVLET_CONTAINER}; + private static final List CHILDREN = Arrays.asList( + AjpListenerResourceDefinition.INSTANCE, + HttpListenerResourceDefinition.INSTANCE, + HttpsListenerResourceDefinition.INSTANCE, + HostDefinition.INSTANCE); + + static final ServerDefinition INSTANCE = new ServerDefinition(); + + private ServerDefinition() { + super(UndertowExtension.SERVER_PATH, UndertowExtension.getResolver(Constants.SERVER), new ServerAdd(), ReloadRequiredRemoveStepHandler.INSTANCE); + } + + @Override + public Collection getAttributes() { + //noinspection unchecked + return Arrays.asList(ATTRIBUTES); + } + + @Override + protected List getChildren() { + return CHILDREN; + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + super.registerCapabilities(resourceRegistration); + resourceRegistration.registerCapability(SERVER_CAPABILITY); + resourceRegistration.registerCapability(CommonWebServer.CAPABILITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,160 @@ +/* + * 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.extension.undertow; + +import io.undertow.connector.ByteBufferPool; +import io.undertow.security.api.AuthenticationMechanismFactory; +import io.undertow.server.handlers.cache.DirectBufferCache; +import io.undertow.servlet.api.CrawlerSessionManagerConfig; +import io.undertow.servlet.api.ServletStackTraces; +import io.undertow.servlet.api.SessionPersistenceManager; + +import org.jboss.as.controller.AbstractBoottimeAddStepHandler; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.Property; +import org.jboss.msc.service.ServiceController; +import org.jboss.security.negotiation.NegotiationMechanismFactory; +import org.wildfly.extension.undertow.security.digest.DigestAuthenticationMechanismFactory; +import org.xnio.XnioWorker; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +final class ServletContainerAdd extends AbstractBoottimeAddStepHandler { + static final ServletContainerAdd INSTANCE = new ServletContainerAdd(); + + ServletContainerAdd() { + super(ServletContainerDefinition.ATTRIBUTES); + } + + @Override + protected void performBoottime(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + installRuntimeServices(context, resource.getModel(), context.getCurrentAddressValue()); + } + + public void installRuntimeServices(OperationContext context, ModelNode model, String name) throws OperationFailedException { + final ModelNode fullModel = Resource.Tools.readModel(context.readResource(PathAddress.EMPTY_ADDRESS), 2); + + final SessionCookieConfig config = SessionCookieDefinition.INSTANCE.getConfig(context, fullModel.get(SessionCookieDefinition.INSTANCE.getPathElement().getKeyValuePair())); + final CrawlerSessionManagerConfig crawlerSessionManagerConfig = CrawlerSessionManagementDefinition.INSTANCE.getConfig(context, fullModel.get(CrawlerSessionManagementDefinition.INSTANCE.getPathElement().getKeyValuePair())); + final boolean persistentSessions = PersistentSessionsDefinition.isEnabled(context, fullModel.get(PersistentSessionsDefinition.INSTANCE.getPathElement().getKeyValuePair())); + final boolean allowNonStandardWrappers = ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS.resolveModelAttribute(context, model).asBoolean(); + final boolean proactiveAuth = ServletContainerDefinition.PROACTIVE_AUTHENTICATION.resolveModelAttribute(context, model).asBoolean(); + final String bufferCache = ServletContainerDefinition.DEFAULT_BUFFER_CACHE.resolveModelAttribute(context, model).asString(); + final boolean disableFileWatchService = ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE.resolveModelAttribute(context, model).asBoolean(); + final boolean disableSessionIdReususe = ServletContainerDefinition.DISABLE_SESSION_ID_REUSE.resolveModelAttribute(context, model).asBoolean(); + + JSPConfig jspConfig = JspDefinition.INSTANCE.getConfig(context, fullModel.get(JspDefinition.INSTANCE.getPathElement().getKeyValuePair())); + + final String stackTracesString = ServletContainerDefinition.STACK_TRACE_ON_ERROR.resolveModelAttribute(context, model).asString(); + final ModelNode defaultEncodingValue = ServletContainerDefinition.DEFAULT_ENCODING.resolveModelAttribute(context, model); + final String defaultEncoding = defaultEncodingValue.isDefined()? defaultEncodingValue.asString() : null; + final boolean useListenerEncoding = ServletContainerDefinition.USE_LISTENER_ENCODING.resolveModelAttribute(context, model).asBoolean(); + final boolean ignoreFlush = ServletContainerDefinition.IGNORE_FLUSH.resolveModelAttribute(context, model).asBoolean(); + final boolean eagerFilterInit = ServletContainerDefinition.EAGER_FILTER_INIT.resolveModelAttribute(context, model).asBoolean(); + final boolean disableCachingForSecuredPages = ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES.resolveModelAttribute(context, model).asBoolean(); + final int sessionIdLength = ServletContainerDefinition.SESSION_ID_LENGTH.resolveModelAttribute(context, model).asInt(); + final int fileCacheMetadataSize = ServletContainerDefinition.FILE_CACHE_METADATA_SIZE.resolveModelAttribute(context, model).asInt(); + final int fileCacheMaxFileSize = ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE.resolveModelAttribute(context, model).asInt(); + final ModelNode fileCacheTtlNode = ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE.resolveModelAttribute(context, model); + final Integer fileCacheTimeToLive = fileCacheTtlNode.isDefined() ? fileCacheTtlNode.asInt() : null; + final int defaultCookieVersion = ServletContainerDefinition.DEFAULT_COOKIE_VERSION.resolveModelAttribute(context, model).asInt(); + + Boolean directoryListingEnabled = null; + if(model.hasDefined(Constants.DIRECTORY_LISTING)) { + directoryListingEnabled = ServletContainerDefinition.DIRECTORY_LISTING.resolveModelAttribute(context, model).asBoolean(); + } + Integer maxSessions = null; + if(model.hasDefined(Constants.MAX_SESSIONS)) { + maxSessions = ServletContainerDefinition.MAX_SESSIONS.resolveModelAttribute(context, model).asInt(); + } + + final int sessionTimeout = ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT.resolveModelAttribute(context, model).asInt(); + + WebsocketsDefinition.WebSocketInfo webSocketInfo = WebsocketsDefinition.INSTANCE.getConfig(context, fullModel.get(WebsocketsDefinition.INSTANCE.getPathElement().getKeyValuePair())); + + final Map mimeMappings = new HashMap<>(); + if (fullModel.hasDefined(Constants.MIME_MAPPING)) { + for (final Property mapping : fullModel.get(Constants.MIME_MAPPING).asPropertyList()) { + mimeMappings.put(mapping.getName(), MimeMappingDefinition.VALUE.resolveModelAttribute(context, mapping.getValue()).asString()); + } + } + + List welcomeFiles = new ArrayList<>(); + if (fullModel.hasDefined(Constants.WELCOME_FILE)) { + for (final Property welcome : fullModel.get(Constants.WELCOME_FILE).asPropertyList()) { + welcomeFiles.add(welcome.getName()); + } + } + + // WFLY-2553 Adding default WildFly specific mechanisms here - subsequently we could enhance the servlet-container + // config to override / add mechanisms. + Map authenticationMechanisms = new HashMap<>(); + authenticationMechanisms.put("SPNEGO", new NegotiationMechanismFactory()); + authenticationMechanisms.put(HttpServletRequest.DIGEST_AUTH, DigestAuthenticationMechanismFactory.FACTORY); + + final ServletContainerService container = new ServletContainerService(allowNonStandardWrappers, + ServletStackTraces.valueOf(stackTracesString.toUpperCase().replace('-', '_')), + config, + jspConfig, + defaultEncoding, + useListenerEncoding, + ignoreFlush, + eagerFilterInit, + sessionTimeout, + disableCachingForSecuredPages, webSocketInfo != null, webSocketInfo != null && webSocketInfo.isDispatchToWorker(), + webSocketInfo != null && webSocketInfo.isPerMessageDeflate(), webSocketInfo == null ? -1 : webSocketInfo.getDeflaterLevel(), + mimeMappings, + welcomeFiles, directoryListingEnabled, proactiveAuth, sessionIdLength, authenticationMechanisms, maxSessions, crawlerSessionManagerConfig, disableFileWatchService, disableSessionIdReususe, fileCacheMetadataSize, fileCacheMaxFileSize, fileCacheTimeToLive, defaultCookieVersion); + + + final CapabilityServiceBuilder builder = context.getCapabilityServiceTarget() + .addCapability(ServletContainerDefinition.SERVLET_CONTAINER_CAPABILITY, container); + if(bufferCache != null) { + builder.addDependency(BufferCacheService.SERVICE_NAME.append(bufferCache), DirectBufferCache.class, container.getBufferCacheInjectedValue()); + } + if(persistentSessions) { + builder.addDependency(AbstractPersistentSessionManager.SERVICE_NAME, SessionPersistenceManager.class, container.getSessionPersistenceManagerInjectedValue()); + } + if(webSocketInfo != null) { + builder.addCapabilityRequirement(Capabilities.REF_IO_WORKER, XnioWorker.class, container.getWebsocketsWorker(), webSocketInfo.getWorker()); + builder.addCapabilityRequirement(Capabilities.CAPABILITY_BYTE_BUFFER_POOL, ByteBufferPool.class, container.getWebsocketsBufferPool(), webSocketInfo.getBufferPool()); + } + + builder.setInitialMode(ServiceController.Mode.ON_DEMAND) + .addAliases(UndertowService.SERVLET_CONTAINER.append(name)) + .install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,251 @@ +/* + * 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.extension.undertow; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import io.undertow.servlet.api.ServletStackTraces; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.operations.validation.EnumValidator; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class ServletContainerDefinition extends PersistentResourceDefinition { + static final RuntimeCapability SERVLET_CONTAINER_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_SERVLET_CONTAINER, true, ServletContainerService.class) + .addRequirements(Capabilities.CAPABILITY_UNDERTOW) + .build(); + + + protected static final SimpleAttributeDefinition ALLOW_NON_STANDARD_WRAPPERS = + new SimpleAttributeDefinitionBuilder(Constants.ALLOW_NON_STANDARD_WRAPPERS, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition DEFAULT_BUFFER_CACHE = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_BUFFER_CACHE, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("default")) + .build(); + + protected static final SimpleAttributeDefinition STACK_TRACE_ON_ERROR = + new SimpleAttributeDefinitionBuilder(Constants.STACK_TRACE_ON_ERROR, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(ServletStackTraces.LOCAL_ONLY.toString())) + .setValidator(new EnumValidator<>(ServletStackTraces.class, true, true)) + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition DEFAULT_ENCODING = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_ENCODING, ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition USE_LISTENER_ENCODING = + new SimpleAttributeDefinitionBuilder(Constants.USE_LISTENER_ENCODING, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + + protected static final AttributeDefinition IGNORE_FLUSH = + new SimpleAttributeDefinitionBuilder(Constants.IGNORE_FLUSH, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final AttributeDefinition EAGER_FILTER_INIT = + new SimpleAttributeDefinitionBuilder("eager-filter-initialization", ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final AttributeDefinition DEFAULT_SESSION_TIMEOUT = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SESSION_TIMEOUT, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.MINUTES) + .setDefaultValue(new ModelNode(30)) + .build(); //30 minutes + + + protected static final AttributeDefinition DISABLE_CACHING_FOR_SECURED_PAGES = + new SimpleAttributeDefinitionBuilder("disable-caching-for-secured-pages", ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(true)) + .build(); + + protected static final AttributeDefinition DIRECTORY_LISTING = + new SimpleAttributeDefinitionBuilder(Constants.DIRECTORY_LISTING, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition PROACTIVE_AUTHENTICATION = + new SimpleAttributeDefinitionBuilder(Constants.PROACTIVE_AUTHENTICATION, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(true)) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition SESSION_ID_LENGTH = + new SimpleAttributeDefinitionBuilder(Constants.SESSION_ID_LENGTH, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setValidator(new IntRangeValidator(16, 200, true, true)) + .setDefaultValue(new ModelNode(30)) + .build(); + + + protected static final AttributeDefinition MAX_SESSIONS = + new SimpleAttributeDefinitionBuilder(Constants.MAX_SESSIONS, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .build(); + + + protected static final AttributeDefinition DISABLE_FILE_WATCH_SERVICE = + new SimpleAttributeDefinitionBuilder(Constants.DISABLE_FILE_WATCH_SERVICE, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition DISABLE_SESSION_ID_REUSE = + new SimpleAttributeDefinitionBuilder(Constants.DISABLE_SESSION_ID_REUSE, ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition FILE_CACHE_METADATA_SIZE = + new SimpleAttributeDefinitionBuilder(Constants.FILE_CACHE_METADATA_SIZE, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(100)) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition FILE_CACHE_MAX_FILE_SIZE = + new SimpleAttributeDefinitionBuilder(Constants.FILE_CACHE_MAX_FILE_SIZE, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode(10 * 1024 * 1024)) + .setAllowExpression(true) + .build(); + + protected static final AttributeDefinition FILE_CACHE_TIME_TO_LIVE = + new SimpleAttributeDefinitionBuilder(Constants.FILE_CACHE_TIME_TO_LIVE, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .build(); + + + protected static final AttributeDefinition DEFAULT_COOKIE_VERSION = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_COOKIE_VERSION, ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(0)) + .setValidator(new IntRangeValidator(0, 1, true,true)) + .build(); + + private static final List CHILDREN; + static final Collection ATTRIBUTES = Arrays.asList( + ALLOW_NON_STANDARD_WRAPPERS, + DEFAULT_BUFFER_CACHE, + STACK_TRACE_ON_ERROR, + DEFAULT_ENCODING, + USE_LISTENER_ENCODING, + IGNORE_FLUSH, + EAGER_FILTER_INIT, + DEFAULT_SESSION_TIMEOUT, + DISABLE_CACHING_FOR_SECURED_PAGES, + DIRECTORY_LISTING, + PROACTIVE_AUTHENTICATION, + SESSION_ID_LENGTH, + MAX_SESSIONS, + DISABLE_FILE_WATCH_SERVICE, + DISABLE_SESSION_ID_REUSE, + FILE_CACHE_METADATA_SIZE, + FILE_CACHE_MAX_FILE_SIZE, + FILE_CACHE_TIME_TO_LIVE, + DEFAULT_COOKIE_VERSION + ); + + static final ServletContainerDefinition INSTANCE = new ServletContainerDefinition(); + + static { + List children = new ArrayList<>(); + children.add(JspDefinition.INSTANCE); + children.add(SessionCookieDefinition.INSTANCE); + children.add(PersistentSessionsDefinition.INSTANCE); + children.add(WebsocketsDefinition.INSTANCE); + children.add(MimeMappingDefinition.INSTANCE); + children.add(WelcomeFileDefinition.INSTANCE); + children.add(CrawlerSessionManagementDefinition.INSTANCE); + CHILDREN = Collections.unmodifiableList(children); + } + + private ServletContainerDefinition() { + super(UndertowExtension.PATH_SERVLET_CONTAINER, + UndertowExtension.getResolver(Constants.SERVLET_CONTAINER), + ServletContainerAdd.INSTANCE, + ReloadRequiredRemoveStepHandler.INSTANCE); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + public List getChildren() { + return CHILDREN; + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(SERVLET_CONTAINER_CAPABILITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/ServletContainerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,281 @@ +/* + * 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.extension.undertow; + +import io.undertow.connector.ByteBufferPool; +import io.undertow.security.api.AuthenticationMechanismFactory; +import io.undertow.server.handlers.cache.DirectBufferCache; +import io.undertow.servlet.api.CrawlerSessionManagerConfig; +import io.undertow.servlet.api.ServletContainer; +import io.undertow.servlet.api.ServletStackTraces; +import io.undertow.servlet.api.SessionPersistenceManager; + +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.xnio.XnioWorker; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Central Undertow 'Container' HTTP listeners will make this container accessible whilst deployers will add content. + * + * @author Darran Lofthouse + */ +public class ServletContainerService implements Service { + + private final boolean allowNonStandardWrappers; + private final ServletStackTraces stackTraces; + private final SessionCookieConfig sessionCookieConfig; + private final JSPConfig jspConfig; + private volatile ServletContainer servletContainer; + private final InjectedValue bufferCacheInjectedValue = new InjectedValue<>(); + private final InjectedValue sessionPersistenceManagerInjectedValue = new InjectedValue<>(); + private final String defaultEncoding; + private final boolean useListenerEncoding; + private final boolean ignoreFlush; + private final boolean eagerFilterInit; + private final int defaultSessionTimeout; + private final boolean disableCachingForSecuredPages; + private final Boolean directoryListingEnabled; + private final int sessionIdLength; + private final CrawlerSessionManagerConfig crawlerSessionManagerConfig; + + private final boolean websocketsEnabled; + private final InjectedValue websocketsBufferPool = new InjectedValue<>(); + private final InjectedValue websocketsWorker = new InjectedValue<>(); + private final boolean dispatchWebsocketInvocationToWorker; + private final boolean perMessageDeflate; + private final int deflaterLevel; + + private final Map mimeMappings; + private final List welcomeFiles; + private final boolean proactiveAuth; + private final Map authenticationMechanisms; + private final Integer maxSessions; + private final boolean disableFileWatchService; + private final boolean disableSessionIdReuse; + private final int fileCacheMetadataSize; + private final int fileCacheMaxFileSize; + private final Integer fileCacheTimeToLive; + private final int defaultCookieVersion; + + public ServletContainerService(boolean allowNonStandardWrappers, ServletStackTraces stackTraces, SessionCookieConfig sessionCookieConfig, JSPConfig jspConfig, + String defaultEncoding, boolean useListenerEncoding, boolean ignoreFlush, boolean eagerFilterInit, int defaultSessionTimeout, + boolean disableCachingForSecuredPages, boolean websocketsEnabled, boolean dispatchWebsocketInvocationToWorker, boolean perMessageDeflate, + int deflaterLevel, Map mimeMappings, List welcomeFiles, Boolean directoryListingEnabled, boolean proactiveAuth, + int sessionIdLength, Map authenticationMechanisms, Integer maxSessions, + CrawlerSessionManagerConfig crawlerSessionManagerConfig, boolean disableFileWatchService, boolean disableSessionIdReuse, int fileCacheMetadataSize, int fileCacheMaxFileSize, Integer fileCacheTimeToLive, int defaultCookieVersion) { + + this.allowNonStandardWrappers = allowNonStandardWrappers; + this.stackTraces = stackTraces; + this.sessionCookieConfig = sessionCookieConfig; + this.jspConfig = jspConfig; + this.defaultEncoding = defaultEncoding; + this.useListenerEncoding = useListenerEncoding; + this.ignoreFlush = ignoreFlush; + this.eagerFilterInit = eagerFilterInit; + this.defaultSessionTimeout = defaultSessionTimeout; + this.disableCachingForSecuredPages = disableCachingForSecuredPages; + this.websocketsEnabled = websocketsEnabled; + this.dispatchWebsocketInvocationToWorker = dispatchWebsocketInvocationToWorker; + this.perMessageDeflate = perMessageDeflate; + this.deflaterLevel = deflaterLevel; + this.directoryListingEnabled = directoryListingEnabled; + this.proactiveAuth = proactiveAuth; + this.maxSessions = maxSessions; + this.crawlerSessionManagerConfig = crawlerSessionManagerConfig; + this.disableFileWatchService = disableFileWatchService; + this.welcomeFiles = new ArrayList<>(welcomeFiles); + this.mimeMappings = new HashMap<>(mimeMappings); + this.sessionIdLength = sessionIdLength; + this.authenticationMechanisms = authenticationMechanisms; + this.disableSessionIdReuse = disableSessionIdReuse; + this.fileCacheMetadataSize = fileCacheMetadataSize; + this.fileCacheMaxFileSize = fileCacheMaxFileSize; + this.fileCacheTimeToLive = fileCacheTimeToLive; + this.defaultCookieVersion = defaultCookieVersion; + } + + @Override + public void start(StartContext context) throws StartException { + servletContainer = ServletContainer.Factory.newInstance(); + } + + @Override + public void stop(StopContext context) { + + } + + @Override + public ServletContainerService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + public Map getAuthenticationMechanisms() { + return authenticationMechanisms; + } + + public ServletContainer getServletContainer() { + return servletContainer; + } + + public boolean isAllowNonStandardWrappers() { + return allowNonStandardWrappers; + } + + public JSPConfig getJspConfig() { + return jspConfig; + } + + public ServletStackTraces getStackTraces() { + return stackTraces; + } + + public SessionCookieConfig getSessionCookieConfig() { + return sessionCookieConfig; + } + + InjectedValue getBufferCacheInjectedValue() { + return bufferCacheInjectedValue; + } + + public DirectBufferCache getBufferCache() { + return bufferCacheInjectedValue.getOptionalValue(); + } + + public boolean isDisableCachingForSecuredPages() { + return disableCachingForSecuredPages; + } + + public boolean isDispatchWebsocketInvocationToWorker() { + return dispatchWebsocketInvocationToWorker; + } + + public InjectedValue getWebsocketsWorker() { + return websocketsWorker; + } + + public InjectedValue getWebsocketsBufferPool() { + return websocketsBufferPool; + } + + public boolean isPerMessageDeflate() { + return perMessageDeflate; + } + + public int getDeflaterLevel() { + return deflaterLevel; + } + + public boolean isWebsocketsEnabled() { + return websocketsEnabled; + } + + public boolean isDisableSessionIdReuse() { + return disableSessionIdReuse; + } + + InjectedValue getSessionPersistenceManagerInjectedValue() { + return sessionPersistenceManagerInjectedValue; + } + + public SessionPersistenceManager getSessionPersistenceManager() { + return sessionPersistenceManagerInjectedValue.getOptionalValue(); + } + + public String getDefaultEncoding() { + return defaultEncoding; + } + + public boolean isUseListenerEncoding() { + return useListenerEncoding; + } + + public boolean isIgnoreFlush() { + return ignoreFlush; + } + + public boolean isEagerFilterInit() { + return eagerFilterInit; + } + + public int getDefaultSessionTimeout() { + return defaultSessionTimeout; + } + + public Map getMimeMappings() { + return Collections.unmodifiableMap(mimeMappings); + } + + public List getWelcomeFiles() { + return welcomeFiles; + } + + public Boolean getDirectoryListingEnabled() { + return directoryListingEnabled; + } + + + public boolean isProactiveAuth() { + return proactiveAuth; + } + + public int getSessionIdLength() { + return sessionIdLength; + } + + public Integer getMaxSessions() { + return maxSessions; + } + + public boolean isDisableFileWatchService() { + return disableFileWatchService; + } + + public CrawlerSessionManagerConfig getCrawlerSessionManagerConfig() { + return crawlerSessionManagerConfig; + } + + public int getFileCacheMetadataSize() { + return fileCacheMetadataSize; + } + + public int getFileCacheMaxFileSize() { + return fileCacheMaxFileSize; + } + + public Integer getFileCacheTimeToLive() { + return fileCacheTimeToLive; + } + + public int getDefaultCookieVersion() { + return defaultCookieVersion; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieConfig.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,72 @@ +/* + * 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.extension.undertow; + +/** + * + * Service that provides the default session cookie config. The config can be overriden on a per + * app basis, and may not be present. + * + * @author Stuart Douglas + */ +public class SessionCookieConfig { + + private final String name; + private final String domain; + private final String comment; + private final Boolean httpOnly; + private final Boolean secure; + private final Integer maxAge; + + public SessionCookieConfig(final String name, final String domain, final String comment, final Boolean httpOnly, final Boolean secure, final Integer maxAge) { + this.name = name; + this.domain = domain; + this.comment = comment; + this.httpOnly = httpOnly; + this.secure = secure; + this.maxAge = maxAge; + } + + public String getName() { + return name; + } + + public String getDomain() { + return domain; + } + + public String getComment() { + return comment; + } + + public Boolean getHttpOnly() { + return httpOnly; + } + + public Boolean getSecure() { + return secure; + } + + public Integer getMaxAge() { + return maxAge; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SessionCookieDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,172 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Global session cookie config + * + * @author Stuart Douglas + */ +class SessionCookieDefinition extends PersistentResourceDefinition { + + static final SessionCookieDefinition INSTANCE = new SessionCookieDefinition(); + + protected static final SimpleAttributeDefinition NAME = + new SimpleAttributeDefinitionBuilder(Constants.NAME, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition DOMAIN = + new SimpleAttributeDefinitionBuilder(Constants.DOMAIN, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition COMMENT = + new SimpleAttributeDefinitionBuilder(Constants.COMMENT, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition HTTP_ONLY = + new SimpleAttributeDefinitionBuilder(Constants.HTTP_ONLY, ModelType.BOOLEAN, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + protected static final SimpleAttributeDefinition SECURE = + new SimpleAttributeDefinitionBuilder(Constants.SECURE, ModelType.BOOLEAN, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + protected static final SimpleAttributeDefinition MAX_AGE = + new SimpleAttributeDefinitionBuilder(Constants.MAX_AGE, ModelType.INT, true) + .setRestartAllServices() + .setAllowExpression(true) + .build(); + + + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + NAME, + DOMAIN, + COMMENT, + HTTP_ONLY, + SECURE, + MAX_AGE + }; + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + + private SessionCookieDefinition() { + super(UndertowExtension.PATH_SESSION_COOKIE, + UndertowExtension.getResolver(UndertowExtension.PATH_SESSION_COOKIE.getKeyValuePair()), + new SessionCookieAdd(), + new SessionCookieRemove()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } + + public SessionCookieConfig getConfig(final OperationContext context, final ModelNode model) throws OperationFailedException { + if(!model.isDefined()) { + return null; + } + ModelNode nameValue = NAME.resolveModelAttribute(context, model); + ModelNode domainValue = DOMAIN.resolveModelAttribute(context, model); + ModelNode commentValue = COMMENT.resolveModelAttribute(context, model); + ModelNode secureValue = SECURE.resolveModelAttribute(context, model); + ModelNode httpOnlyValue = HTTP_ONLY.resolveModelAttribute(context, model); + ModelNode maxAgeValue = MAX_AGE.resolveModelAttribute(context, model); + final String name = nameValue.isDefined() ? nameValue.asString() : null; + final String domain = domainValue.isDefined() ? domainValue.asString() : null; + final String comment = commentValue.isDefined() ? commentValue.asString() : null; + final Boolean secure = secureValue.isDefined() ? secureValue.asBoolean() : null; + final Boolean httpOnly = httpOnlyValue.isDefined() ? httpOnlyValue.asBoolean() : null; + final Integer maxAge = maxAgeValue.isDefined() ? maxAgeValue.asInt() : null; + return new SessionCookieConfig(name, domain, comment, httpOnly, secure, maxAge); + } + + + private static class SessionCookieAdd extends RestartParentResourceAddHandler { + protected SessionCookieAdd() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } + + private static class SessionCookieRemove extends RestartParentResourceRemoveHandler { + + protected SessionCookieRemove() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return UndertowService.SERVLET_CONTAINER.append(parentAddress.getLastElement().getValue()); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,73 @@ +/* + * 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.extension.undertow; + +import java.util.Collection; +import java.util.Collections; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar 2014 Red Hat Inc. + * @author Paul Ferraro + */ +class SingleSignOnDefinition extends PersistentResourceDefinition { + + enum Attribute implements org.jboss.as.clustering.controller.Attribute { + DOMAIN(Constants.DOMAIN, ModelType.STRING, null), + PATH("path", ModelType.STRING, new ModelNode("/")), + HTTP_ONLY("http-only", ModelType.BOOLEAN, new ModelNode(false)), + SECURE("secure", ModelType.BOOLEAN, new ModelNode(false)), + COOKIE_NAME("cookie-name", ModelType.STRING, new ModelNode("JSESSIONIDSSO")), + ; + private final AttributeDefinition definition; + + Attribute(String name, ModelType type, ModelNode defaultValue) { + this.definition = new SimpleAttributeDefinitionBuilder(name, type) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(defaultValue) + .setRestartAllServices() + .build(); + } + + @Override + public AttributeDefinition getDefinition() { + return this.definition; + } + } + + SingleSignOnDefinition() { + super(new Parameters(UndertowExtension.PATH_SSO, UndertowExtension.getResolver(Constants.SINGLE_SIGN_ON))); + } + + @Override + public Collection getAttributes() { + // Attributes will be registered by the parent implementation + return Collections.emptyList(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnManagerServiceNameProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnManagerServiceNameProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnManagerServiceNameProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,43 @@ +/* + * 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.extension.undertow; + +import org.jboss.msc.service.ServiceName; +import org.wildfly.clustering.service.ServiceNameProvider; + +/** + * @author Paul Ferraro + */ +public class SingleSignOnManagerServiceNameProvider implements ServiceNameProvider { + + private final ServiceName name; + + public SingleSignOnManagerServiceNameProvider(String securityDomainName) { + this.name = ApplicationSecurityDomainDefinition.APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.fromBaseCapability(securityDomainName).getCapabilityServiceName().append("sso", "manager"); + } + + @Override + public ServiceName getServiceName() { + return this.name; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,86 @@ +/* + * 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.extension.undertow; + +import io.undertow.security.impl.SingleSignOnManager; +import io.undertow.servlet.handlers.security.ServletSingleSignOnAuthenticationMechanism; + +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + * @author Paul Ferraro + */ +public class SingleSignOnService implements Service { + + public static final String AUTHENTICATION_MECHANISM_NAME = "SSO"; + + private final String domain; + private final String path; + private final String cookieName; + private final boolean httpOnly; + private final boolean secure; + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue manager = new InjectedValue<>(); + + SingleSignOnService(String domain, String path, boolean httpOnly, boolean secure, String cookieName) { + this.domain = domain; + this.path = path; + this.httpOnly = httpOnly; + this.secure = secure; + this.cookieName = cookieName; + } + + @Override + public void start(StartContext startContext) { + ServletSingleSignOnAuthenticationMechanism mechanism = new ServletSingleSignOnAuthenticationMechanism(this.manager.getValue()); + mechanism.setDomain(this.domain); + mechanism.setPath(this.path); + mechanism.setHttpOnly(this.httpOnly); + mechanism.setSecure(this.secure); + mechanism.setCookieName(this.cookieName); + this.host.getValue().registerAdditionalAuthenticationMechanism(AUTHENTICATION_MECHANISM_NAME, mechanism); + } + + @Override + public void stop(StopContext stopContext) { + this.host.getValue().unregisterAdditionalAuthenticationMechanism(AUTHENTICATION_MECHANISM_NAME); + } + + @Override + public SingleSignOnService getValue() { + return this; + } + + Injector getHost() { + return this.host; + } + + Injector getSingleSignOnSessionManager() { + return this.manager; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceConfigurator.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,128 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.ApplicationSecurityDomainSingleSignOnDefinition.Attribute.CREDENTIAL; +import static org.wildfly.extension.undertow.ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_ALIAS; +import static org.wildfly.extension.undertow.ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_STORE; +import static org.wildfly.extension.undertow.ApplicationSecurityDomainSingleSignOnDefinition.Attribute.SSL_CONTEXT; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.net.ssl.SSLContext; + +import org.jboss.as.clustering.controller.CommonUnaryRequirement; +import org.jboss.as.clustering.controller.CredentialSourceDependency; +import org.jboss.as.clustering.controller.ResourceServiceConfigurator; +import org.jboss.as.clustering.dmr.ModelNodes; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.CompositeDependency; +import org.wildfly.clustering.service.FunctionalService; +import org.wildfly.clustering.service.ServiceConfigurator; +import org.wildfly.clustering.service.ServiceSupplierDependency; +import org.wildfly.clustering.service.SupplierDependency; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.credential.PasswordCredential; +import org.wildfly.security.credential.source.CredentialSource; +import org.wildfly.security.http.util.sso.DefaultSingleSignOnSessionFactory; +import org.wildfly.security.http.util.sso.SingleSignOnManager; +import org.wildfly.security.http.util.sso.SingleSignOnSessionFactory; +import org.wildfly.security.password.interfaces.ClearPassword; + +/** + * @author Paul Ferraro + */ +public class SingleSignOnSessionFactoryServiceConfigurator extends SingleSignOnSessionFactoryServiceNameProvider implements ResourceServiceConfigurator, Supplier { + + private final SupplierDependency manager; + + private volatile SupplierDependency keyStore; + private volatile SupplierDependency sslContext; + private volatile SupplierDependency credentialSource; + private volatile String keyAlias; + + public SingleSignOnSessionFactoryServiceConfigurator(String securityDomainName) { + super(securityDomainName); + this.manager = new ServiceSupplierDependency<>(new SingleSignOnManagerServiceNameProvider(securityDomainName)); + } + + @Override + public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException { + String keyStore = KEY_STORE.resolveModelAttribute(context, model).asString(); + this.keyStore = new ServiceSupplierDependency<>(CommonUnaryRequirement.KEY_STORE.getServiceName(context, keyStore)); + this.keyAlias = KEY_ALIAS.resolveModelAttribute(context, model).asString(); + this.credentialSource = new CredentialSourceDependency(context, CREDENTIAL, model); + Optional sslContext = ModelNodes.optionalString(SSL_CONTEXT.resolveModelAttribute(context, model)); + this.sslContext = sslContext.map(value -> new ServiceSupplierDependency(CommonUnaryRequirement.SSL_CONTEXT.getServiceName(context, value))).orElse(null); + return this; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceBuilder builder = target.addService(this.getServiceName()); + Consumer factory = new CompositeDependency(this.manager, this.keyStore, this.credentialSource, this.sslContext).register(builder).provides(this.getServiceName()); + Service service = new FunctionalService<>(factory, Function.identity(), this); + return builder.setInstance(service); + } + + @Override + public SingleSignOnSessionFactory get() { + KeyStore store = this.keyStore.get(); + String alias = this.keyAlias; + CredentialSource source = this.credentialSource.get(); + try { + if (!store.containsAlias(alias)) { + throw UndertowLogger.ROOT_LOGGER.missingKeyStoreEntry(alias); + } + if (!store.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) { + throw UndertowLogger.ROOT_LOGGER.keyStoreEntryNotPrivate(alias); + } + PasswordCredential credential = source.getCredential(PasswordCredential.class); + if (credential == null) { + throw UndertowLogger.ROOT_LOGGER.missingCredential(source.toString()); + } + ClearPassword password = credential.getPassword(ClearPassword.class); + if (password == null) { + throw UndertowLogger.ROOT_LOGGER.credentialNotClearPassword(credential.toString()); + } + KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) store.getEntry(alias, new KeyStore.PasswordProtection(password.getPassword())); + KeyPair keyPair = new KeyPair(entry.getCertificate().getPublicKey(), entry.getPrivateKey()); + Optional context = Optional.ofNullable(this.sslContext).map(dependency -> dependency.get()); + return new DefaultSingleSignOnSessionFactory(this.manager.get(), keyPair, connection -> context.ifPresent(ctx -> connection.setSSLSocketFactory(ctx.getSocketFactory()))); + } catch (GeneralSecurityException | IOException e) { + throw new IllegalArgumentException(e); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceNameProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceNameProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/SingleSignOnSessionFactoryServiceNameProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,43 @@ +/* + * 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.extension.undertow; + +import org.jboss.msc.service.ServiceName; +import org.wildfly.clustering.service.ServiceNameProvider; + +/** + * @author Paul Ferraro + */ +public class SingleSignOnSessionFactoryServiceNameProvider implements ServiceNameProvider { + + private final ServiceName name; + + public SingleSignOnSessionFactoryServiceNameProvider(String securityDomainName) { + this.name = ApplicationSecurityDomainDefinition.APPLICATION_SECURITY_DOMAIN_RUNTIME_CAPABILITY.fromBaseCapability(securityDomainName).getCapabilityServiceName().append("sso", "factory"); + } + + @Override + public ServiceName getServiceName() { + return this.name; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowEventListener.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowEventListener.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowEventListener.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,76 @@ +/* + * 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.extension.undertow; + +import io.undertow.servlet.api.Deployment; + +/** + * Server/deployment lifecycle event listener. + *

+ * TODO: implement commented out Undertow events + * + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + * @author Radoslav Husar + */ +public interface UndertowEventListener { + default void onShutdown() { + } + + //void onDeploymentAdd(DeploymentInfo deploymentInfo, Host host); + + default void onDeploymentStart(Deployment deployment, Host host) { + } + + default void onDeploymentStop(Deployment deployment, Host host) { + } + + default void onDeploymentStart(String contextPath, Host host) { + + } + + default void onDeploymentStop(String contextPath, Host host) { + + } + + //void onDeploymentRemove(DeploymentInfo deploymentInfo, Host host); + + //void onHostAdd(Host host); + + //void onHostRemove(Host host); + + default void onHostStart(Host host) { + } + + default void onHostStop(Host host) { + } + + //void onServerAdd(Server server); + + //void onServerRemove(Server server); + + default void onServerStart(Server server) { + } + + default void onServerStop(Server server) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtension.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtension.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowExtension.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,120 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; + +import org.jboss.as.controller.Extension; +import org.jboss.as.controller.ExtensionContext; +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.SubsystemRegistration; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; +import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; +import org.jboss.as.controller.parsing.ExtensionParsingContext; +import org.jboss.as.controller.registry.ManagementResourceRegistration; + + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +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 BYTE_BUFFER_POOL_PATH = PathElement.pathElement(Constants.BYTE_BUFFER_POOL); + public static final PathElement PATH_HANDLERS = PathElement.pathElement(Constants.CONFIGURATION, Constants.HANDLER); + public static final PathElement PATH_FILTERS = PathElement.pathElement(Constants.CONFIGURATION, Constants.FILTER); + 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 CRAWLER_SESSION_MANAGEMENT = PathElement.pathElement(Constants.SETTING, Constants.CRAWLER_SESSION_MANAGEMENT); + 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 PATH_HTTP_INVOKER = PathElement.pathElement(Constants.SETTING,Constants.HTTP_INVOKER); + public static final PathElement LOAD_BALANCING_GROUP = PathElement.pathElement(Constants.LOAD_BALANCING_GROUP); + public static final PathElement NODE = PathElement.pathElement(Constants.NODE); + public static final PathElement PATH_FILTER_REF = PathElement.pathElement(Constants.FILTER_REF); + static final PathElement PATH_APPLICATION_SECURITY_DOMAIN = PathElement.pathElement(Constants.APPLICATION_SECURITY_DOMAIN); + + private static final String RESOURCE_NAME = UndertowExtension.class.getPackage().getName() + ".LocalDescriptions"; + static final AccessConstraintDefinition LISTENER_CONSTRAINT = new SensitiveTargetAccessConstraintDefinition( + new SensitivityClassification(SUBSYSTEM_NAME, "web-connector", false, false, false)); + + private static final ModelVersion CURRENT_MODEL_VERSION = ModelVersion.create(7, 0, 0); + + + public static StandardResourceDescriptionResolver getResolver(final String... keyPrefix) { + StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME); + for (String kp : keyPrefix) { + prefix.append('.').append(kp); + } + return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, UndertowExtension.class.getClassLoader(), true, false); + } + + @Override + public void initializeParsers(ExtensionParsingContext context) { + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_1_0.getUriString(), UndertowSubsystemParser_1_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_1_1.getUriString(), UndertowSubsystemParser_1_1::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_1_2.getUriString(), UndertowSubsystemParser_1_2::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_2_0.getUriString(), UndertowSubsystemParser_2_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_3_0.getUriString(), UndertowSubsystemParser_3_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_3_1.getUriString(), UndertowSubsystemParser_3_1::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_4_0.getUriString(), UndertowSubsystemParser_4_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_5_0.getUriString(), UndertowSubsystemParser_5_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_6_0.getUriString(), UndertowSubsystemParser_6_0::new); + context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_7_0.getUriString(), UndertowSubsystemParser_7_0::new); + } + + @Override + public void initialize(ExtensionContext context) { + final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, CURRENT_MODEL_VERSION); + final ManagementResourceRegistration registration = subsystem.registerSubsystemModel(UndertowRootDefinition.INSTANCE); + registration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE, false); + + final ManagementResourceRegistration deployments = subsystem.registerDeploymentModel(DeploymentDefinition.INSTANCE); + deployments.registerSubModel(DeploymentServletDefinition.INSTANCE); + deployments.registerSubModel(DeploymentWebSocketDefinition.INSTANCE); + + subsystem.registerXMLElementWriter(UndertowSubsystemParser_7_0::new); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowFilter.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowFilter.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowFilter.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,33 @@ +/* + * 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.extension.undertow; + +import io.undertow.server.HandlerWrapper; + +/** + * @author Stuart Douglas + */ +public interface UndertowFilter extends HandlerWrapper { + + int getPriority(); + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowListener.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowListener.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowListener.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,76 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.network.SocketBinding; + +/** + * Represents the externally accessible interface provided by Undertow's listeners + * + * @author Stuart Douglas + */ +public interface UndertowListener { + + /** + * Returns the listeners socket binding. + * + * @return The listeners socket binding + */ + SocketBinding getSocketBinding(); + + /** + * Returns true if the listener is secure. In general this will be true for HTTPS listeners, however other listener + * types may have been explicitly marked as secure. + * + * @return true if the listener is considered security + */ + boolean isSecure(); + + /** + * Returns the transport protocol. This will generally either be http, https or ajp. + * + * @return The transport protocol + */ + String getProtocol(); + + /** + * Returns the listener name + * + * @return The listener name + */ + String getName(); + + /** + * Returns the server this listener is registered with. + * + * @return the server this listener is registered with + */ + Server getServer(); + + /** + * Returns true if the listener has shut down. + * + * @return true if the listener has been shutdown + */ + boolean isShutdown(); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowRootDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowRootDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowRootDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,177 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_HTTP_INVOKER; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import io.undertow.server.handlers.PathHandler; +import org.jboss.as.controller.AbstractWriteAttributeHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.ValueExpression; +import org.jboss.msc.service.ServiceController; +import org.jboss.security.SecurityConstants; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +class UndertowRootDefinition extends PersistentResourceDefinition { + + static final RuntimeCapability UNDERTOW_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_UNDERTOW, false, UndertowService.class) + .build(); + + static final RuntimeCapability HTTP_INVOKER_RUNTIME_CAPABILITY = + RuntimeCapability.Builder.of(CAPABILITY_HTTP_INVOKER, false, PathHandler.class) + .build(); + + protected static final SimpleAttributeDefinition DEFAULT_SERVLET_CONTAINER = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SERVLET_CONTAINER, ModelType.STRING, true) + .setRestartAllServices() + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(UNDERTOW_CAPABILITY, Capabilities.CAPABILITY_SERVLET_CONTAINER) + .build(); + protected static final SimpleAttributeDefinition DEFAULT_SERVER = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SERVER, ModelType.STRING, true) + .setRestartAllServices() + .setDefaultValue(new ModelNode("default-server")) + .setCapabilityReference(UNDERTOW_CAPABILITY, Capabilities.CAPABILITY_SERVER) + .build(); + + protected static final SimpleAttributeDefinition DEFAULT_VIRTUAL_HOST = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_VIRTUAL_HOST, ModelType.STRING, true) + .setRestartAllServices() + .setDefaultValue(new ModelNode("default-host")) + .setCapabilityReference(UNDERTOW_CAPABILITY, Capabilities.CAPABILITY_HOST, DEFAULT_SERVER) + .build(); + + protected static final SimpleAttributeDefinition INSTANCE_ID = + new SimpleAttributeDefinitionBuilder(Constants.INSTANCE_ID, ModelType.STRING, true) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode().set(new ValueExpression("${jboss.node.name}"))) + .build(); + protected static final SimpleAttributeDefinition STATISTICS_ENABLED = + new SimpleAttributeDefinitionBuilder(Constants.STATISTICS_ENABLED, ModelType.BOOLEAN, true) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + protected static final SimpleAttributeDefinition DEFAULT_SECURITY_DOMAIN = + new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SECURITY_DOMAIN, ModelType.STRING, true) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(SecurityConstants.DEFAULT_APPLICATION_POLICY)) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SECURITY_DOMAIN_REF) + .setRestartAllServices() + .build(); + + + static final ApplicationSecurityDomainDefinition APPLICATION_SECURITY_DOMAIN = ApplicationSecurityDomainDefinition.INSTANCE; + static final AttributeDefinition[] ATTRIBUTES = { DEFAULT_VIRTUAL_HOST, DEFAULT_SERVLET_CONTAINER, DEFAULT_SERVER, INSTANCE_ID, STATISTICS_ENABLED, DEFAULT_SECURITY_DOMAIN }; + static final PersistentResourceDefinition[] CHILDREN = { + ByteBufferPoolDefinition.INSTANCE, + BufferCacheDefinition.INSTANCE, + ServerDefinition.INSTANCE, + ServletContainerDefinition.INSTANCE, + HandlerDefinitions.INSTANCE, + FilterDefinitions.INSTANCE, + APPLICATION_SECURITY_DOMAIN + }; + + public static final UndertowRootDefinition INSTANCE = new UndertowRootDefinition(); + + private UndertowRootDefinition() { + super(UndertowExtension.SUBSYSTEM_PATH, + UndertowExtension.getResolver(), + new UndertowSubsystemAdd(APPLICATION_SECURITY_DOMAIN.getKnownSecurityDomainPredicate()), + ReloadRequiredRemoveStepHandler.INSTANCE); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(ATTRIBUTES); + } + + @Override + public List getChildren() { + return Arrays.asList(CHILDREN); + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + super.registerCapabilities(resourceRegistration); + resourceRegistration.registerCapability(UNDERTOW_CAPABILITY); + resourceRegistration.registerCapability(HTTP_INVOKER_RUNTIME_CAPABILITY); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + ReloadRequiredWriteAttributeHandler handler = new ReloadRequiredWriteAttributeHandler(getAttributes()); + for (AttributeDefinition attr : getAttributes()) { + if (attr == STATISTICS_ENABLED) { + resourceRegistration.registerReadWriteAttribute(attr, null, new AbstractWriteAttributeHandler(STATISTICS_ENABLED) { + @Override + protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode resolvedValue, ModelNode currentValue, HandbackHolder handbackHolder) throws OperationFailedException { + ServiceController controller = context.getServiceRegistry(false).getService(UndertowService.UNDERTOW); + if (controller != null) { + UndertowService service = (UndertowService) controller.getService(); + if (service != null) { + service.setStatisticsEnabled(resolvedValue.asBoolean()); + } + } + return false; + } + + @Override + protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode valueToRestore, ModelNode valueToRevert, Void handback) throws OperationFailedException { + ServiceController controller = context.getServiceRegistry(false).getService(UndertowService.UNDERTOW); + if (controller != null) { + UndertowService service = (UndertowService) controller.getService(); + if (service != null) { + service.setStatisticsEnabled(valueToRestore.asBoolean()); + } + } + } + }); + } else { + resourceRegistration.registerReadWriteAttribute(attr, null, handler); + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,290 @@ +/* + * 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.extension.undertow; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.function.Consumer; +import javax.security.jacc.PolicyContext; +import javax.security.jacc.PolicyContextException; + +import io.undertow.Version; +import org.jboss.as.controller.PathAddress; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.security.SecurityConstants; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.security.jacc.HttpServletRequestPolicyContextHandler; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + * @author Stuart Douglas + */ +@SuppressWarnings("ALL") +public class UndertowService implements Service { + + @Deprecated + public static final ServiceName UNDERTOW = ServiceName.JBOSS.append("undertow"); + @Deprecated + public static final ServiceName SERVLET_CONTAINER = UNDERTOW.append(Constants.SERVLET_CONTAINER); + @Deprecated + public static final ServiceName SERVER = UNDERTOW.append(Constants.SERVER); + /** + * service name under which default server is bound. + */ + public static final ServiceName DEFAULT_SERVER = UNDERTOW.append("default-server"); + + /** + * service name under which default host of default server is bound. + */ + public static final ServiceName DEFAULT_HOST = DEFAULT_SERVER.append("default-host"); + + public static final ServiceName UNDERTOW_DEPLOYMENT = ServiceName.of("undertow-deployment"); + /** + * The base name for listener/handler/filter services. + */ + public static final ServiceName HANDLER = UNDERTOW.append(Constants.HANDLER); + public static final ServiceName FILTER = UNDERTOW.append(Constants.FILTER); + + + /** + * The base name for web deployments. + */ + static final ServiceName WEB_DEPLOYMENT_BASE = UNDERTOW.append("deployment"); + private final String defaultContainer; + private final String defaultServer; + private final String defaultVirtualHost; + private final Set registeredServers = new CopyOnWriteArraySet<>(); + private final List listeners = Collections.synchronizedList(new LinkedList()); + private final String instanceId; + private volatile boolean statisticsEnabled; + private final Set> statisticsChangeListenters = new HashSet<>(); + + protected UndertowService(String defaultContainer, String defaultServer, String defaultVirtualHost, String instanceId, boolean statisticsEnabled) { + this.defaultContainer = defaultContainer; + this.defaultServer = defaultServer; + this.defaultVirtualHost = defaultVirtualHost; + this.instanceId = instanceId; + this.statisticsEnabled = statisticsEnabled; + } + + public static ServiceName deploymentServiceName(ServiceName deploymentServiceName) { + return deploymentServiceName.append(UNDERTOW_DEPLOYMENT); + } + + /** + * The old deployment unit service name. This is still registered as an alias, however {{@link #deploymentServiceName(ServiceName)}} + * should be used instead. + * @param serverName The server name + * @param virtualHost The virtual host + * @param contextPath The context path + * @return The legacy deployment service alias + */ + @Deprecated + public static ServiceName deploymentServiceName(final String serverName, final String virtualHost, final String contextPath) { + return WEB_DEPLOYMENT_BASE.append(serverName).append(virtualHost).append("".equals(contextPath) ? "/" : contextPath); + } + + @Deprecated + public static ServiceName virtualHostName(final String server, final String virtualHost) { + return SERVER.append(server).append(virtualHost); + } + + public static ServiceName locationServiceName(final String server, final String virtualHost, final String locationName) { + return virtualHostName(server, virtualHost).append(Constants.LOCATION, locationName); + } + + public static ServiceName accessLogServiceName(final String server, final String virtualHost) { + return virtualHostName(server, virtualHost).append(Constants.ACCESS_LOG); + } + + public static ServiceName ssoServiceName(final String server, final String virtualHost) { + return virtualHostName(server, virtualHost).append("single-sign-on"); + } + + public static ServiceName consoleRedirectServiceName(final String server, final String virtualHost) { + return virtualHostName(server, virtualHost).append("console", "redirect"); + } + + public static ServiceName filterRefName(final String server, final String virtualHost, final String locationName, final String filterName) { + return virtualHostName(server, virtualHost).append(Constants.LOCATION, locationName).append("filter-ref").append(filterName); + } + + public static ServiceName filterRefName(final String server, final String virtualHost, final String filterName) { + return SERVER.append(server).append(virtualHost).append("filter-ref").append(filterName); + } + + public static ServiceName getFilterRefServiceName(final PathAddress address, String name) { + final PathAddress oneUp = address.subAddress(0, address.size() - 1); + final PathAddress twoUp = oneUp.subAddress(0, oneUp.size() - 1); + final PathAddress threeUp = twoUp.subAddress(0, twoUp.size() - 1); + ServiceName serviceName; + if (address.getLastElement().getKey().equals(Constants.FILTER_REF)) { + if (oneUp.getLastElement().getKey().equals(Constants.HOST)) { //adding reference + String host = oneUp.getLastElement().getValue(); + String server = twoUp.getLastElement().getValue(); + serviceName = UndertowService.filterRefName(server, host, name); + } else { + String location = oneUp.getLastElement().getValue(); + String host = twoUp.getLastElement().getValue(); + String server = threeUp.getLastElement().getValue(); + serviceName = UndertowService.filterRefName(server, host, location, name); + } + } else if (address.getLastElement().getKey().equals(Constants.HOST)) { + String host = address.getLastElement().getValue(); + String server = oneUp.getLastElement().getValue(); + serviceName = UndertowService.filterRefName(server, host, name); + } else { + String location = address.getLastElement().getValue(); + String host = oneUp.getLastElement().getValue(); + String server = twoUp.getLastElement().getValue(); + serviceName = UndertowService.filterRefName(server, host, location, name); + } + return serviceName; + } + + @Deprecated + public static ServiceName listenerName(String listenerName) { + return UNDERTOW.append(Constants.LISTENER).append(listenerName); + } + + @Override + public void start(StartContext context) throws StartException { + UndertowLogger.ROOT_LOGGER.serverStarting(Version.getVersionString()); + // Register the active request PolicyContextHandler + try { + PolicyContext.registerHandler(SecurityConstants.WEB_REQUEST_KEY, + new HttpServletRequestPolicyContextHandler(), true); + } catch (PolicyContextException pce) { + UndertowLogger.ROOT_LOGGER.failedToRegisterPolicyContextHandler(SecurityConstants.WEB_REQUEST_KEY, pce); + } + } + + @Override + public void stop(StopContext context) { + // Remove PolicyContextHandler + Set handlerKeys = PolicyContext.getHandlerKeys(); + handlerKeys.remove(SecurityConstants.WEB_REQUEST_KEY); + + UndertowLogger.ROOT_LOGGER.serverStopping(Version.getVersionString()); + + fireEvent(new EventInvoker() { + @Override + public void invoke(UndertowEventListener listener) { + listener.onShutdown(); + } + }); + } + + @Override + public UndertowService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + protected void registerServer(final Server server) { + registeredServers.add(server); + fireEvent(new EventInvoker() { + @Override + public void invoke(UndertowEventListener listener) { + listener.onServerStart(server); + } + }); + } + + protected void unregisterServer(final Server server) { + registeredServers.remove(server); + fireEvent(new EventInvoker() { + @Override + public void invoke(UndertowEventListener listener) { + listener.onServerStop(server); + } + }); + } + + public String getDefaultContainer() { + return defaultContainer; + } + + public String getDefaultServer() { + return defaultServer; + } + + public String getDefaultVirtualHost() { + return defaultVirtualHost; + } + + public Set getServers() { + return Collections.unmodifiableSet(registeredServers); + } + + public String getInstanceId() { + return instanceId; + } + + public boolean isStatisticsEnabled() { + return statisticsEnabled; + } + + public synchronized void setStatisticsEnabled(boolean statisticsEnabled) { + this.statisticsEnabled = statisticsEnabled; + for(Consumer listener: statisticsChangeListenters) { + listener.accept(statisticsEnabled); + } + } + + public synchronized void registerStatisticsListener(Consumer listener) { + statisticsChangeListenters.add(listener); + } + + public synchronized void unregisterStatisticsListener(Consumer listener) { + statisticsChangeListenters.remove(listener); + } + + /** + * Registers custom Event listener to server + * + * @param listener event listener to register + */ + public void registerListener(UndertowEventListener listener) { + this.listeners.add(listener); + } + + public void unregisterListener(UndertowEventListener listener) { + this.listeners.remove(listener); + } + + protected void fireEvent(EventInvoker invoker) { + synchronized (listeners) { + for (UndertowEventListener listener : listeners) { + invoker.invoke(listener); + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,153 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.UndertowRootDefinition.HTTP_INVOKER_RUNTIME_CAPABILITY; + +import java.util.function.Predicate; + +import org.jboss.as.controller.AbstractBoottimeAddStepHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.server.AbstractDeploymentChainStep; +import org.jboss.as.server.DeploymentProcessorTarget; +import org.jboss.as.server.deployment.Phase; +import org.jboss.as.server.deployment.jbossallxml.JBossAllXmlParserRegisteringProcessor; +import org.jboss.as.web.common.SharedTldsMetaDataBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.wildfly.extension.undertow.deployment.DefaultDeploymentMappingProvider; +import org.wildfly.extension.undertow.deployment.DefaultSecurityDomainProcessor; +import org.wildfly.extension.undertow.deployment.DeploymentRootExplodedMountProcessor; +import org.wildfly.extension.undertow.deployment.EarContextRootProcessor; +import org.wildfly.extension.undertow.deployment.ExternalTldParsingDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.JBossWebParsingDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.ServletContainerInitializerDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.SharedSessionManagerDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.TldParsingDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.UndertowAttachments; +import org.wildfly.extension.undertow.deployment.UndertowDependencyProcessor; +import org.wildfly.extension.undertow.deployment.UndertowDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.UndertowHandlersDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.UndertowJSRWebSocketDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.UndertowServletContainerDependencyProcessor; +import org.wildfly.extension.undertow.deployment.WarAnnotationDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.WarDeploymentInitializingProcessor; +import org.wildfly.extension.undertow.deployment.WarMetaDataProcessor; +import org.wildfly.extension.undertow.deployment.WarStructureDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.WebFragmentParsingDeploymentProcessor; +import org.wildfly.extension.undertow.deployment.WebJBossAllParser; +import org.wildfly.extension.undertow.deployment.WebParsingDeploymentProcessor; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.session.SharedSessionConfigParser_1_0; + + +/** + * Handler responsible for adding the subsystem resource to the model + * + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +class UndertowSubsystemAdd extends AbstractBoottimeAddStepHandler { + + + private final Predicate knownSecurityDomain; + + UndertowSubsystemAdd(Predicate knownSecurityDomain) { + super(UndertowRootDefinition.ATTRIBUTES); + this.knownSecurityDomain = knownSecurityDomain; + } + + /** + * {@inheritDoc} + */ + @Override + protected void performBoottime(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { + + try { + Class.forName("org.apache.jasper.compiler.JspRuntimeContext", true, this.getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.couldNotInitJsp(e); + } + final ModelNode model = resource.getModel(); + + final String defaultVirtualHost = UndertowRootDefinition.DEFAULT_VIRTUAL_HOST.resolveModelAttribute(context, model).asString(); + final String defaultContainer = UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER.resolveModelAttribute(context, model).asString(); + final String defaultServer = UndertowRootDefinition.DEFAULT_SERVER.resolveModelAttribute(context, model).asString(); + final boolean stats = UndertowRootDefinition.STATISTICS_ENABLED.resolveModelAttribute(context, model).asBoolean(); + final String defaultSecurityDomain = UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN.resolveModelAttribute(context, model).asString(); + + final ModelNode instanceIdModel = UndertowRootDefinition.INSTANCE_ID.resolveModelAttribute(context, model); + final String instanceId = instanceIdModel.isDefined() ? instanceIdModel.asString() : null; + + + DefaultDeploymentMappingProvider.instance().clear();//we clear provider on system boot, as on reload it could cause issues. + + context.getCapabilityServiceTarget().addCapability(UndertowRootDefinition.UNDERTOW_CAPABILITY, new UndertowService(defaultContainer, defaultServer, defaultVirtualHost, instanceId, stats)) + .setInitialMode(ServiceController.Mode.ACTIVE) + .addAliases(UndertowService.UNDERTOW) + .install(); + + context.addStep(new AbstractDeploymentChainStep() { + @Override + protected void execute(DeploymentProcessorTarget processorTarget) { + + final SharedTldsMetaDataBuilder sharedTldsBuilder = new SharedTldsMetaDataBuilder(model.clone()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, Phase.STRUCTURE_EXPLODED_MOUNT, new DeploymentRootExplodedMountProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, Phase.STRUCTURE_REGISTER_JBOSS_ALL_UNDERTOW_SHARED_SESSION, new JBossAllXmlParserRegisteringProcessor<>(SharedSessionConfigParser_1_0.ROOT_ELEMENT, UndertowAttachments.SHARED_SESSION_MANAGER_CONFIG, SharedSessionConfigParser_1_0.INSTANCE)); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, Phase.STRUCTURE_REGISTER_JBOSS_ALL_WEB, new JBossAllXmlParserRegisteringProcessor<>(WebJBossAllParser.ROOT_ELEMENT, WebJBossAllParser.ATTACHMENT_KEY, new WebJBossAllParser())); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, Phase.STRUCTURE_WAR_DEPLOYMENT_INIT, new WarDeploymentInitializingProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.STRUCTURE, Phase.STRUCTURE_WAR, new WarStructureDeploymentProcessor(sharedTldsBuilder)); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_DEPLOYMENT, new WebParsingDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_DEPLOYMENT_FRAGMENT, new WebFragmentParsingDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_JBOSS_WEB_DEPLOYMENT, new JBossWebParsingDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_ANNOTATION_WAR, new WarAnnotationDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_EAR_CONTEXT_ROOT, new EarContextRootProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_MERGE_METADATA, new WarMetaDataProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_MERGE_METADATA + 1, new TldParsingDeploymentProcessor()); //todo: fix priority + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_MERGE_METADATA + 2, new org.wildfly.extension.undertow.deployment.WebComponentProcessor()); //todo: fix priority + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.PARSE, Phase.PARSE_WEB_MERGE_METADATA + 3, new DefaultSecurityDomainProcessor(defaultSecurityDomain)); //todo: fix priority + + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.DEPENDENCIES, Phase.DEPENDENCIES_WAR_MODULE, new UndertowDependencyProcessor()); + + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_UNDERTOW_WEBSOCKETS, new UndertowJSRWebSocketDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_UNDERTOW_HANDLERS, new UndertowHandlersDeploymentProcessor()); + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_UNDERTOW_HANDLERS + 1, new ExternalTldParsingDeploymentProcessor()); //todo: fix priority + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.POST_MODULE, Phase.POST_MODULE_UNDERTOW_HANDLERS + 2, new UndertowServletContainerDependencyProcessor(defaultContainer)); //todo: fix priority + + + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.INSTALL, Phase.INSTALL_SHARED_SESSION_MANAGER, new SharedSessionManagerDeploymentProcessor(defaultServer)); + + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.INSTALL, Phase.INSTALL_SERVLET_INIT_DEPLOYMENT, new ServletContainerInitializerDeploymentProcessor()); + + processorTarget.addDeploymentProcessor(UndertowExtension.SUBSYSTEM_NAME, Phase.INSTALL, Phase.INSTALL_WAR_DEPLOYMENT, new UndertowDeploymentProcessor(defaultVirtualHost, defaultContainer, defaultServer, defaultSecurityDomain, knownSecurityDomain)); + + } + }, OperationContext.Stage.RUNTIME); + + context.getCapabilityServiceTarget() + .addCapability(HTTP_INVOKER_RUNTIME_CAPABILITY, new RemoteHttpInvokerService()) + .install(); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,230 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.BasicAuthHandler; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_1_0 extends PersistentResourceXMLParser{ + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_1_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_1_0.getUriString()) + .addAttributes(UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, UndertowRootDefinition.DEFAULT_SERVER, UndertowRootDefinition.INSTANCE_ID) + .addAttribute(UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + //.addAttribute(BufferCacheDefinition.BUFFER_SIZE, new AttributeParser.DiscardOldDefaultValueParser("blah")) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + .setXmlWrapperElement(Constants.BUFFER_CACHES) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + builder(AjpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(AjpListenerResourceDefinition.SCHEME, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED, AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + ) + .addChild( + builder(HttpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpListenerResourceDefinition.BUFFER_POOL, HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, HttpListenerResourceDefinition.ENABLED, HttpListenerResourceDefinition.SOCKET_BINDING, HttpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET, HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + ).addChild( + builder(HttpsListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED) + .addAttributes(HttpsListenerResourceDefinition.SECURITY_REALM, HttpsListenerResourceDefinition.VERIFY_CLIENT, HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES,HttpsListenerResourceDefinition.ENABLED_PROTOCOLS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE) + ) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.PREFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE) + ).addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE) + ).addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_WEBSOCKETS))); //backwards compat + }) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + ) + .addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + .setNoAddOperation(true) + .setXmlWrapperElement(Constants.ERROR_PAGES)) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttribute(FileHandler.DIRECTORY_LISTING, new AttributeParser.DiscardOldDefaultValueParser("true")) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes(ReverseProxyHandlerHost.INSTANCE_ID)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(BasicAuthHandler.INSTANCE.getPathElement()) + .addAttributes(BasicAuthHandler.SECURITY_DOMAIN) + ) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .setXmlElementName("connection-limit") + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_1.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_1.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_1.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,232 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.BasicAuthHandler; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_1_1 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_1_1() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_1_1.getUriString()) + .addAttributes(UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, UndertowRootDefinition.DEFAULT_SERVER, UndertowRootDefinition.INSTANCE_ID) + .addAttribute(UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + builder(AjpListenerResourceDefinition.INSTANCE.getPathElement()) + + .addAttributes(AjpListenerResourceDefinition.SCHEME, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED, AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE) + ) + .addChild( + builder(HttpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpListenerResourceDefinition.BUFFER_POOL, HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, HttpListenerResourceDefinition.ENABLED, HttpListenerResourceDefinition.SOCKET_BINDING, HttpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET, HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE) + ).addChild( + builder(HttpsListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED) + .addAttributes(HttpsListenerResourceDefinition.SECURITY_REALM, HttpsListenerResourceDefinition.VERIFY_CLIENT, HttpsListenerResourceDefinition.ENABLED_CIPHER_SUITES, HttpsListenerResourceDefinition.ENABLED_PROTOCOLS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE) + ) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE) + ).addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE) + ).addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_WEBSOCKETS))); //backwards compat + }) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + ) + .addChild( //todo add NOOP element parser + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + .setNoAddOperation(true) + .setXmlWrapperElement(Constants.ERROR_PAGES)) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes(ReverseProxyHandlerHost.INSTANCE_ID) + ) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(BasicAuthHandler.INSTANCE.getPathElement()) + .addAttributes(BasicAuthHandler.SECURITY_DOMAIN) + ) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .setXmlElementName("connection-limit") + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_2.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_2.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_1_2.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,244 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.BasicAuthHandler; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_1_2 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_1_2(){ + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_1_2.getUriString()) + .addAttributes(UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, UndertowRootDefinition.DEFAULT_SERVER, UndertowRootDefinition.INSTANCE_ID) + .addAttribute(UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + builder(AjpListenerResourceDefinition.INSTANCE.getPathElement()) + + .addAttributes(AjpListenerResourceDefinition.SCHEME, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED, AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE,ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ) + .addChild( + builder(HttpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpListenerResourceDefinition.BUFFER_POOL, HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, HttpListenerResourceDefinition.ENABLED, HttpListenerResourceDefinition.SOCKET_BINDING, HttpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET, HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ).addChild( + builder(HttpsListenerResourceDefinition.INSTANCE.getPathElement()) + .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) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE) + ).addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ).addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER + ) + ) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes(ReverseProxyHandlerHost.INSTANCE_ID, ReverseProxyHandlerHost.PATH, ReverseProxyHandlerHost.SCHEME, ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(BasicAuthHandler.INSTANCE.getPathElement()) + .addAttributes(BasicAuthHandler.SECURITY_DOMAIN) + ) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .setXmlElementName("connection-limit") + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_2_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_2_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_2_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,266 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.BasicAuthHandler; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_2_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_2_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_2_0.getUriString()) + .addAttributes(UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, UndertowRootDefinition.DEFAULT_SERVER, UndertowRootDefinition.INSTANCE_ID) + .addAttribute(UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + builder(AjpListenerResourceDefinition.INSTANCE.getPathElement()) + + .addAttributes(AjpListenerResourceDefinition.SCHEME, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED, AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ) + .addChild( + builder(HttpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpListenerResourceDefinition.BUFFER_POOL, HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, HttpListenerResourceDefinition.ENABLED, HttpListenerResourceDefinition.SOCKET_BINDING, HttpListenerResourceDefinition.WORKER, ListenerResourceDefinition.REDIRECT_SOCKET, HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, HttpListenerResourceDefinition.ENABLE_HTTP2) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ).addChild( + builder(HttpsListenerResourceDefinition.INSTANCE.getPathElement()) + .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(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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.RELATIVE_TO, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE, AccessLogDefinition.USE_SERVER_LOG) + ).addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ).addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER + ) + ) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes(ReverseProxyHandlerHost.INSTANCE_ID, ReverseProxyHandlerHost.PATH, ReverseProxyHandlerHost.SCHEME, ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(BasicAuthHandler.INSTANCE.getPathElement()) + .addAttributes(BasicAuthHandler.SECURITY_DOMAIN) + .setNoAddOperation(true) + ) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .setXmlElementName("connection-limit") + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,286 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_3_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_3_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_3_0.getUriString()) + .addAttributes(UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, UndertowRootDefinition.DEFAULT_SERVER, UndertowRootDefinition.INSTANCE_ID, UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN) + .addAttribute(UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + builder(AjpListenerResourceDefinition.INSTANCE.getPathElement()) + + .addAttributes(AjpListenerResourceDefinition.SCHEME, AjpListenerResourceDefinition.BUFFER_POOL, AjpListenerResourceDefinition.ENABLED, ListenerResourceDefinition.REDIRECT_SOCKET, AjpListenerResourceDefinition.SOCKET_BINDING, AjpListenerResourceDefinition.WORKER) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, ListenerResourceDefinition.DISALLOWED_METHODS) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT, ListenerResourceDefinition.MAX_CONNECTIONS, ListenerResourceDefinition.SECURE) + ) + .addChild( + builder(HttpListenerResourceDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpListenerResourceDefinition.BUFFER_POOL, HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, HttpListenerResourceDefinition.ENABLED, ListenerResourceDefinition.REDIRECT_SOCKET, HttpListenerResourceDefinition.SOCKET_BINDING, HttpListenerResourceDefinition.WORKER, HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, HttpListenerResourceDefinition.ENABLE_HTTP2) + .addAttribute(ListenerResourceDefinition.RESOLVE_PEER_ADDRESS) + .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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, ListenerResourceDefinition.DISALLOWED_METHODS) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT, ListenerResourceDefinition.MAX_CONNECTIONS, ListenerResourceDefinition.SECURE) + ).addChild( + builder(HttpsListenerResourceDefinition.INSTANCE.getPathElement()) + .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, 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, ListenerResourceDefinition.NO_REQUEST_TIMEOUT, ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, ListenerResourceDefinition.DISALLOWED_METHODS) + .addAttributes(ListenerResourceDefinition.BACKLOG, ListenerResourceDefinition.RECEIVE_BUFFER, ListenerResourceDefinition.SEND_BUFFER, ListenerResourceDefinition.KEEP_ALIVE, ListenerResourceDefinition.READ_TIMEOUT, ListenerResourceDefinition.WRITE_TIMEOUT, ListenerResourceDefinition.MAX_CONNECTIONS, ListenerResourceDefinition.SECURE) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE, HostDefinition.DEFAULT_RESPONSE_CODE, HostDefinition.DISABLE_CONSOLE_REDIRECT) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.RELATIVE_TO, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE, AccessLogDefinition.USE_SERVER_LOG, AccessLogDefinition.EXTENDED, AccessLogDefinition.PREDICATE) + ).addChild( + builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY) + ).addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes(ReverseProxyHandlerHost.INSTANCE_ID, ReverseProxyHandlerHost.PATH, ReverseProxyHandlerHost.SCHEME, ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, ReverseProxyHandlerHost.SECURITY_REALM)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.VALUE, ResponseHeaderFilter.NAME) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_1.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_1.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_3_1.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,361 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_3_1 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_3_1() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_3_1.getUriString()) + .addAttributes( + UndertowRootDefinition.DEFAULT_SERVER, + UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, + UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, + UndertowRootDefinition.INSTANCE_ID, + UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN, + UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + listenerBuilder(AjpListenerResourceDefinition.INSTANCE) + // xsd ajp-listener-type + .addAttributes(AjpListenerResourceDefinition.SCHEME, + ListenerResourceDefinition.REDIRECT_SOCKET, + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE) + ) + .addChild( + listenerBuilder(HttpListenerResourceDefinition.INSTANCE) + // xsd http-listener-type + .addAttributes( + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + ListenerResourceDefinition.REDIRECT_SOCKET, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.ENABLE_HTTP2, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE) + ).addChild( + listenerBuilder(HttpsListenerResourceDefinition.INSTANCE) + // xsd https-listener-type + .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, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE, HostDefinition.DEFAULT_RESPONSE_CODE, HostDefinition.DISABLE_CONSOLE_REDIRECT) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild(filterRefBuilder()) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes( + AccessLogDefinition.PATTERN, + AccessLogDefinition.WORKER, + AccessLogDefinition.DIRECTORY, + AccessLogDefinition.RELATIVE_TO, + AccessLogDefinition.PREFIX, + AccessLogDefinition.SUFFIX, + AccessLogDefinition.ROTATE, + AccessLogDefinition.USE_SERVER_LOG, + AccessLogDefinition.EXTENDED, + AccessLogDefinition.PREDICATE) + ).addChild(filterRefBuilder()) + .addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes( + ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, + ReverseProxyHandlerHost.SCHEME, + ReverseProxyHandlerHost.PATH, + ReverseProxyHandlerHost.INSTANCE_ID, + ReverseProxyHandlerHost.SECURITY_REALM)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2, + ModClusterDefinition.MAX_AJP_PACKET_SIZE, + ModClusterDefinition.HTTP2_ENABLE_PUSH, + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE, + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE, + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE, + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } + + /** Registers attributes common across listener types */ + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder listenerBuilder(PersistentResourceDefinition resource) { + return builder(resource.getPathElement()) + // xsd socket-optionsType + .addAttributes( + ListenerResourceDefinition.RECEIVE_BUFFER, + ListenerResourceDefinition.SEND_BUFFER, + ListenerResourceDefinition.BACKLOG, + ListenerResourceDefinition.KEEP_ALIVE, + ListenerResourceDefinition.READ_TIMEOUT, + ListenerResourceDefinition.WRITE_TIMEOUT, + ListenerResourceDefinition.MAX_CONNECTIONS) + // xsd listener-type + .addAttributes( + ListenerResourceDefinition.SOCKET_BINDING, + ListenerResourceDefinition.WORKER, + ListenerResourceDefinition.BUFFER_POOL, + ListenerResourceDefinition.ENABLED, + ListenerResourceDefinition.RESOLVE_PEER_ADDRESS, + ListenerResourceDefinition.MAX_ENTITY_SIZE, + ListenerResourceDefinition.BUFFER_PIPELINED_DATA, + ListenerResourceDefinition.MAX_HEADER_SIZE, + 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, + ListenerResourceDefinition.NO_REQUEST_TIMEOUT, + ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, + ListenerResourceDefinition.DISALLOWED_METHODS, + ListenerResourceDefinition.SECURE); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY); + } +} + Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_4_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_4_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_4_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,397 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_4_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_4_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_4_0.getUriString()) + .addAttributes( + UndertowRootDefinition.DEFAULT_SERVER, + UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, + UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, + UndertowRootDefinition.INSTANCE_ID, + UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN, + UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + listenerBuilder(AjpListenerResourceDefinition.INSTANCE) + // xsd ajp-listener-type + .addAttributes(AjpListenerResourceDefinition.SCHEME, + ListenerResourceDefinition.REDIRECT_SOCKET, + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE) + ) + .addChild( + listenerBuilder(HttpListenerResourceDefinition.INSTANCE) + // xsd http-listener-type + .addAttributes( + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + ListenerResourceDefinition.REDIRECT_SOCKET, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.ENABLE_HTTP2, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11) + ).addChild( + listenerBuilder(HttpsListenerResourceDefinition.INSTANCE) + // xsd https-listener-type + .setMarshallDefaultValues(true) + .addAttributes( + HttpsListenerResourceDefinition.SSL_CONTEXT, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + 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, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE, HostDefinition.DEFAULT_RESPONSE_CODE, HostDefinition.DISABLE_CONSOLE_REDIRECT) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild(filterRefBuilder()) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes( + AccessLogDefinition.PATTERN, + AccessLogDefinition.WORKER, + AccessLogDefinition.DIRECTORY, + AccessLogDefinition.RELATIVE_TO, + AccessLogDefinition.PREFIX, + AccessLogDefinition.SUFFIX, + AccessLogDefinition.ROTATE, + AccessLogDefinition.USE_SERVER_LOG, + AccessLogDefinition.EXTENDED, + AccessLogDefinition.PREDICATE) + ).addChild(filterRefBuilder()) + .addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ).addChild(builder(HttpInvokerDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpInvokerDefinition.PATH, HttpInvokerDefinition.HTTP_AUTHENTICATION_FACTORY, HttpInvokerDefinition.SECURITY_REALM)) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addAttribute(ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE) + .addAttribute(ServletContainerDefinition.DISABLE_SESSION_ID_REUSE) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .setMarshallDefaultValues(true) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER, + WebsocketsDefinition.PER_MESSAGE_DEFLATE, + WebsocketsDefinition.DEFLATER_LEVEL + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT, + ReverseProxyHandler.MAX_RETRIES) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes( + ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, + ReverseProxyHandlerHost.SCHEME, + ReverseProxyHandlerHost.PATH, + ReverseProxyHandlerHost.INSTANCE_ID, + ReverseProxyHandlerHost.SSL_CONTEXT, + ReverseProxyHandlerHost.SECURITY_REALM, + ReverseProxyHandlerHost.ENABLE_HTTP2)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.FAILOVER_STRATEGY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SSL_CONTEXT, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2, + ModClusterDefinition.MAX_AJP_PACKET_SIZE, + ModClusterDefinition.HTTP2_ENABLE_PUSH, + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE, + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE, + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE, + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + ModClusterDefinition.MAX_RETRIES) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + .addChild( + builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS) + .addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG, ApplicationSecurityDomainDefinition.ENABLE_JACC) + .addChild(builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_STORE.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_ALIAS.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.SSL_CONTEXT.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.CREDENTIAL.getDefinition(), AttributeParser.OBJECT_PARSER, AttributeMarshaller.ATTRIBUTE_OBJECT) + ) + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } + + /** Registers attributes common across listener types */ + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder listenerBuilder(PersistentResourceDefinition resource) { + return builder(resource.getPathElement()) + // xsd socket-optionsType + .addAttributes( + ListenerResourceDefinition.RECEIVE_BUFFER, + ListenerResourceDefinition.SEND_BUFFER, + ListenerResourceDefinition.BACKLOG, + ListenerResourceDefinition.KEEP_ALIVE, + ListenerResourceDefinition.READ_TIMEOUT, + ListenerResourceDefinition.WRITE_TIMEOUT, + ListenerResourceDefinition.MAX_CONNECTIONS) + // xsd listener-type + .addAttributes( + ListenerResourceDefinition.SOCKET_BINDING, + ListenerResourceDefinition.WORKER, + ListenerResourceDefinition.BUFFER_POOL, + ListenerResourceDefinition.ENABLED, + ListenerResourceDefinition.RESOLVE_PEER_ADDRESS, + ListenerResourceDefinition.MAX_ENTITY_SIZE, + ListenerResourceDefinition.BUFFER_PIPELINED_DATA, + ListenerResourceDefinition.MAX_HEADER_SIZE, + 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, + ListenerResourceDefinition.NO_REQUEST_TIMEOUT, + ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, + ListenerResourceDefinition.DISALLOWED_METHODS, + ListenerResourceDefinition.SECURE, + ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_5_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_5_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_5_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,400 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_5_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_5_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_5_0.getUriString()) + .addAttributes( + UndertowRootDefinition.DEFAULT_SERVER, + UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, + UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, + UndertowRootDefinition.INSTANCE_ID, + UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN, + UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + listenerBuilder(AjpListenerResourceDefinition.INSTANCE) + // xsd ajp-listener-type + .addAttributes(AjpListenerResourceDefinition.SCHEME, + ListenerResourceDefinition.REDIRECT_SOCKET, + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE) + ) + .addChild( + listenerBuilder(HttpListenerResourceDefinition.INSTANCE) + // xsd http-listener-type + .addAttributes( + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + ListenerResourceDefinition.REDIRECT_SOCKET, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.ENABLE_HTTP2, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11) + ).addChild( + listenerBuilder(HttpsListenerResourceDefinition.INSTANCE) + // xsd https-listener-type + .setMarshallDefaultValues(true) + .addAttributes( + HttpsListenerResourceDefinition.SSL_CONTEXT, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + 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, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, HostDefinition.DEFAULT_WEB_MODULE, HostDefinition.DEFAULT_RESPONSE_CODE, HostDefinition.DISABLE_CONSOLE_REDIRECT) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild(filterRefBuilder()) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes( + AccessLogDefinition.PATTERN, + AccessLogDefinition.WORKER, + AccessLogDefinition.DIRECTORY, + AccessLogDefinition.RELATIVE_TO, + AccessLogDefinition.PREFIX, + AccessLogDefinition.SUFFIX, + AccessLogDefinition.ROTATE, + AccessLogDefinition.USE_SERVER_LOG, + AccessLogDefinition.EXTENDED, + AccessLogDefinition.PREDICATE) + ).addChild(filterRefBuilder()) + .addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ).addChild(builder(HttpInvokerDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpInvokerDefinition.PATH, HttpInvokerDefinition.HTTP_AUTHENTICATION_FACTORY, HttpInvokerDefinition.SECURITY_REALM)) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addAttribute(ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE) + .addAttribute(ServletContainerDefinition.DISABLE_SESSION_ID_REUSE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_METADATA_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .setMarshallDefaultValues(true) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER, + WebsocketsDefinition.PER_MESSAGE_DEFLATE, + WebsocketsDefinition.DEFLATER_LEVEL + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT, + ReverseProxyHandler.MAX_RETRIES) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes( + ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, + ReverseProxyHandlerHost.SCHEME, + ReverseProxyHandlerHost.PATH, + ReverseProxyHandlerHost.INSTANCE_ID, + ReverseProxyHandlerHost.SSL_CONTEXT, + ReverseProxyHandlerHost.SECURITY_REALM, + ReverseProxyHandlerHost.ENABLE_HTTP2)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.FAILOVER_STRATEGY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SSL_CONTEXT, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2, + ModClusterDefinition.MAX_AJP_PACKET_SIZE, + ModClusterDefinition.HTTP2_ENABLE_PUSH, + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE, + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE, + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE, + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + ModClusterDefinition.MAX_RETRIES) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + .addChild( + builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS) + .addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG, ApplicationSecurityDomainDefinition.ENABLE_JACC) + .addChild(builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_STORE.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_ALIAS.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.SSL_CONTEXT.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.CREDENTIAL.getDefinition(), AttributeParser.OBJECT_PARSER, AttributeMarshaller.ATTRIBUTE_OBJECT) + ) + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } + + /** Registers attributes common across listener types */ + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder listenerBuilder(PersistentResourceDefinition resource) { + return builder(resource.getPathElement()) + // xsd socket-optionsType + .addAttributes( + ListenerResourceDefinition.RECEIVE_BUFFER, + ListenerResourceDefinition.SEND_BUFFER, + ListenerResourceDefinition.BACKLOG, + ListenerResourceDefinition.KEEP_ALIVE, + ListenerResourceDefinition.READ_TIMEOUT, + ListenerResourceDefinition.WRITE_TIMEOUT, + ListenerResourceDefinition.MAX_CONNECTIONS) + // xsd listener-type + .addAttributes( + ListenerResourceDefinition.SOCKET_BINDING, + ListenerResourceDefinition.WORKER, + ListenerResourceDefinition.BUFFER_POOL, + ListenerResourceDefinition.ENABLED, + ListenerResourceDefinition.RESOLVE_PEER_ADDRESS, + ListenerResourceDefinition.MAX_ENTITY_SIZE, + ListenerResourceDefinition.BUFFER_PIPELINED_DATA, + ListenerResourceDefinition.MAX_HEADER_SIZE, + 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, + ListenerResourceDefinition.NO_REQUEST_TIMEOUT, + ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, + ListenerResourceDefinition.DISALLOWED_METHODS, + ListenerResourceDefinition.SECURE, + ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_6_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_6_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_6_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,412 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_6_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_6_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_6_0.getUriString()) + .addAttributes( + UndertowRootDefinition.DEFAULT_SERVER, + UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, + UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, + UndertowRootDefinition.INSTANCE_ID, + UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN, + UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(ByteBufferPoolDefinition.INSTANCE.getPathElement()) + .addAttributes(ByteBufferPoolDefinition.DIRECT, ByteBufferPoolDefinition.BUFFER_SIZE, ByteBufferPoolDefinition.MAX_POOL_SIZE, ByteBufferPoolDefinition.THREAD_LOCAL_CACHE_SIZE, ByteBufferPoolDefinition.LEAK_DETECTION_PERCENT) + ) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + listenerBuilder(AjpListenerResourceDefinition.INSTANCE) + // xsd ajp-listener-type + .addAttributes(AjpListenerResourceDefinition.SCHEME, + ListenerResourceDefinition.REDIRECT_SOCKET, + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE) + ) + .addChild( + listenerBuilder(HttpListenerResourceDefinition.INSTANCE) + // xsd http-listener-type + .addAttributes( + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + ListenerResourceDefinition.REDIRECT_SOCKET, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.ENABLE_HTTP2, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11, + HttpListenerResourceDefinition.PROXY_PROTOCOL) + ).addChild( + listenerBuilder(HttpsListenerResourceDefinition.INSTANCE) + // xsd https-listener-type + .setMarshallDefaultValues(true) + .addAttributes( + HttpsListenerResourceDefinition.SSL_CONTEXT, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + 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, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11, + HttpListenerResourceDefinition.PROXY_PROTOCOL) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, + HostDefinition.DEFAULT_WEB_MODULE, + HostDefinition.DEFAULT_RESPONSE_CODE, + HostDefinition.DISABLE_CONSOLE_REDIRECT, + HostDefinition.QUEUE_REQUESTS_ON_START) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild(filterRefBuilder()) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes( + AccessLogDefinition.PATTERN, + AccessLogDefinition.WORKER, + AccessLogDefinition.DIRECTORY, + AccessLogDefinition.RELATIVE_TO, + AccessLogDefinition.PREFIX, + AccessLogDefinition.SUFFIX, + AccessLogDefinition.ROTATE, + AccessLogDefinition.USE_SERVER_LOG, + AccessLogDefinition.EXTENDED, + AccessLogDefinition.PREDICATE) + ).addChild(filterRefBuilder()) + .addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ).addChild(builder(HttpInvokerDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpInvokerDefinition.PATH, HttpInvokerDefinition.HTTP_AUTHENTICATION_FACTORY, HttpInvokerDefinition.SECURITY_REALM)) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addAttribute(ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE) + .addAttribute(ServletContainerDefinition.DISABLE_SESSION_ID_REUSE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_METADATA_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE) + .addAttribute(ServletContainerDefinition.DEFAULT_COOKIE_VERSION) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .setMarshallDefaultValues(true) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER, + WebsocketsDefinition.PER_MESSAGE_DEFLATE, + WebsocketsDefinition.DEFLATER_LEVEL + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT, + ReverseProxyHandler.MAX_RETRIES) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes( + ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, + ReverseProxyHandlerHost.SCHEME, + ReverseProxyHandlerHost.PATH, + ReverseProxyHandlerHost.INSTANCE_ID, + ReverseProxyHandlerHost.SSL_CONTEXT, + ReverseProxyHandlerHost.SECURITY_REALM, + ReverseProxyHandlerHost.ENABLE_HTTP2)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.FAILOVER_STRATEGY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SSL_CONTEXT, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2, + ModClusterDefinition.MAX_AJP_PACKET_SIZE, + ModClusterDefinition.HTTP2_ENABLE_PUSH, + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE, + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE, + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE, + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + ModClusterDefinition.MAX_RETRIES) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + .addChild( + builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS) + .addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG, ApplicationSecurityDomainDefinition.ENABLE_JACC) + .addChild(builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_STORE.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_ALIAS.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.SSL_CONTEXT.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.CREDENTIAL.getDefinition(), AttributeParser.OBJECT_PARSER, AttributeMarshaller.ATTRIBUTE_OBJECT) + ) + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } + + /** Registers attributes common across listener types */ + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder listenerBuilder(PersistentResourceDefinition resource) { + return builder(resource.getPathElement()) + // xsd socket-optionsType + .addAttributes( + ListenerResourceDefinition.RECEIVE_BUFFER, + ListenerResourceDefinition.SEND_BUFFER, + ListenerResourceDefinition.BACKLOG, + ListenerResourceDefinition.KEEP_ALIVE, + ListenerResourceDefinition.READ_TIMEOUT, + ListenerResourceDefinition.WRITE_TIMEOUT, + ListenerResourceDefinition.MAX_CONNECTIONS) + // xsd listener-type + .addAttributes( + ListenerResourceDefinition.SOCKET_BINDING, + ListenerResourceDefinition.WORKER, + ListenerResourceDefinition.BUFFER_POOL, + ListenerResourceDefinition.ENABLED, + ListenerResourceDefinition.RESOLVE_PEER_ADDRESS, + ListenerResourceDefinition.MAX_ENTITY_SIZE, + ListenerResourceDefinition.BUFFER_PIPELINED_DATA, + ListenerResourceDefinition.MAX_HEADER_SIZE, + 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, + ListenerResourceDefinition.NO_REQUEST_TIMEOUT, + ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, + ListenerResourceDefinition.DISALLOWED_METHODS, + ListenerResourceDefinition.SECURE, + ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION, + ListenerResourceDefinition.ALLOW_UNESCAPED_CHARACTERS_IN_URL); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_7_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_7_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowSubsystemParser_7_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,412 @@ +/* + * 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.extension.undertow; + +import static org.jboss.as.controller.PersistentResourceXMLDescription.builder; + +import org.jboss.as.controller.AttributeMarshaller; +import org.jboss.as.controller.AttributeParser; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentResourceXMLParser; +import org.jboss.as.controller.operations.common.Util; +import org.wildfly.extension.undertow.filters.CustomFilterDefinition; +import org.wildfly.extension.undertow.filters.ErrorPageDefinition; +import org.wildfly.extension.undertow.filters.ExpressionFilterDefinition; +import org.wildfly.extension.undertow.filters.FilterDefinitions; +import org.wildfly.extension.undertow.filters.FilterRefDefinition; +import org.wildfly.extension.undertow.filters.GzipFilter; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; +import org.wildfly.extension.undertow.filters.RequestLimitHandler; +import org.wildfly.extension.undertow.filters.ResponseHeaderFilter; +import org.wildfly.extension.undertow.filters.RewriteFilterDefinition; +import org.wildfly.extension.undertow.handlers.FileHandler; +import org.wildfly.extension.undertow.handlers.HandlerDefinitions; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandler; +import org.wildfly.extension.undertow.handlers.ReverseProxyHandlerHost; + +/** + * @author Tomaz Cerar (c) 2012 Red Hat Inc. + */ +public class UndertowSubsystemParser_7_0 extends PersistentResourceXMLParser { + private final PersistentResourceXMLDescription xmlDescription; + + UndertowSubsystemParser_7_0() { + xmlDescription = builder(UndertowRootDefinition.INSTANCE.getPathElement(), Namespace.UNDERTOW_7_0.getUriString()) + .addAttributes( + UndertowRootDefinition.DEFAULT_SERVER, + UndertowRootDefinition.DEFAULT_VIRTUAL_HOST, + UndertowRootDefinition.DEFAULT_SERVLET_CONTAINER, + UndertowRootDefinition.INSTANCE_ID, + UndertowRootDefinition.DEFAULT_SECURITY_DOMAIN, + UndertowRootDefinition.STATISTICS_ENABLED) + .addChild( + builder(ByteBufferPoolDefinition.INSTANCE.getPathElement()) + .addAttributes(ByteBufferPoolDefinition.DIRECT, ByteBufferPoolDefinition.BUFFER_SIZE, ByteBufferPoolDefinition.MAX_POOL_SIZE, ByteBufferPoolDefinition.THREAD_LOCAL_CACHE_SIZE, ByteBufferPoolDefinition.LEAK_DETECTION_PERCENT) + ) + .addChild( + builder(BufferCacheDefinition.INSTANCE.getPathElement()) + .addAttributes(BufferCacheDefinition.BUFFER_SIZE, BufferCacheDefinition.BUFFERS_PER_REGION, BufferCacheDefinition.MAX_REGIONS) + ) + .addChild(builder(ServerDefinition.INSTANCE.getPathElement()) + .addAttributes(ServerDefinition.DEFAULT_HOST, ServerDefinition.SERVLET_CONTAINER) + .addChild( + listenerBuilder(AjpListenerResourceDefinition.INSTANCE) + // xsd ajp-listener-type + .addAttributes(AjpListenerResourceDefinition.SCHEME, + ListenerResourceDefinition.REDIRECT_SOCKET, + AjpListenerResourceDefinition.MAX_AJP_PACKET_SIZE) + ) + .addChild( + listenerBuilder(HttpListenerResourceDefinition.INSTANCE) + // xsd http-listener-type + .addAttributes( + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + ListenerResourceDefinition.REDIRECT_SOCKET, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.ENABLE_HTTP2, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11, + HttpListenerResourceDefinition.PROXY_PROTOCOL) + ).addChild( + listenerBuilder(HttpsListenerResourceDefinition.INSTANCE) + // xsd https-listener-type + .setMarshallDefaultValues(true) + .addAttributes( + HttpsListenerResourceDefinition.SSL_CONTEXT, + HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING, + HttpListenerResourceDefinition.CERTIFICATE_FORWARDING, + 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, + HttpListenerResourceDefinition.HTTP2_ENABLE_PUSH, + HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE, + HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE, + HttpListenerResourceDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11, + HttpListenerResourceDefinition.PROXY_PROTOCOL) + ).addChild( + builder(HostDefinition.INSTANCE.getPathElement()) + .addAttributes(HostDefinition.ALIAS, + HostDefinition.DEFAULT_WEB_MODULE, + HostDefinition.DEFAULT_RESPONSE_CODE, + HostDefinition.DISABLE_CONSOLE_REDIRECT, + HostDefinition.QUEUE_REQUESTS_ON_START) + .addChild( + builder(LocationDefinition.INSTANCE.getPathElement()) + .addAttributes(LocationDefinition.HANDLER) + .addChild(filterRefBuilder()) + ).addChild( + builder(AccessLogDefinition.INSTANCE.getPathElement()) + .addAttributes( + AccessLogDefinition.PATTERN, + AccessLogDefinition.WORKER, + AccessLogDefinition.DIRECTORY, + AccessLogDefinition.RELATIVE_TO, + AccessLogDefinition.PREFIX, + AccessLogDefinition.SUFFIX, + AccessLogDefinition.ROTATE, + AccessLogDefinition.USE_SERVER_LOG, + AccessLogDefinition.EXTENDED, + AccessLogDefinition.PREDICATE) + ).addChild(filterRefBuilder()) + .addChild( + builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + ).addChild(builder(HttpInvokerDefinition.INSTANCE.getPathElement()) + .addAttributes(HttpInvokerDefinition.PATH, HttpInvokerDefinition.HTTP_AUTHENTICATION_FACTORY, HttpInvokerDefinition.SECURITY_REALM)) + ) + ) + .addChild( + builder(ServletContainerDefinition.INSTANCE.getPathElement()) + .addAttribute(ServletContainerDefinition.ALLOW_NON_STANDARD_WRAPPERS) + .addAttribute(ServletContainerDefinition.DEFAULT_BUFFER_CACHE) + .addAttribute(ServletContainerDefinition.STACK_TRACE_ON_ERROR) + .addAttribute(ServletContainerDefinition.DEFAULT_ENCODING) + .addAttribute(ServletContainerDefinition.USE_LISTENER_ENCODING) + .addAttribute(ServletContainerDefinition.IGNORE_FLUSH) + .addAttribute(ServletContainerDefinition.EAGER_FILTER_INIT) + .addAttribute(ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT) + .addAttribute(ServletContainerDefinition.DISABLE_CACHING_FOR_SECURED_PAGES) + .addAttribute(ServletContainerDefinition.DIRECTORY_LISTING) + .addAttribute(ServletContainerDefinition.PROACTIVE_AUTHENTICATION) + .addAttribute(ServletContainerDefinition.SESSION_ID_LENGTH) + .addAttribute(ServletContainerDefinition.MAX_SESSIONS) + .addAttribute(ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE) + .addAttribute(ServletContainerDefinition.DISABLE_SESSION_ID_REUSE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_METADATA_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE) + .addAttribute(ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE) + .addAttribute(ServletContainerDefinition.DEFAULT_COOKIE_VERSION) + .addChild( + builder(JspDefinition.INSTANCE.getPathElement()) + .setXmlElementName(Constants.JSP_CONFIG) + .addAttributes( + JspDefinition.DISABLED, + JspDefinition.DEVELOPMENT, + JspDefinition.KEEP_GENERATED, + JspDefinition.TRIM_SPACES, + JspDefinition.TAG_POOLING, + JspDefinition.MAPPED_FILE, + JspDefinition.CHECK_INTERVAL, + JspDefinition.MODIFICATION_TEST_INTERVAL, + JspDefinition.RECOMPILE_ON_FAIL, + JspDefinition.SMAP, + JspDefinition.DUMP_SMAP, + JspDefinition.GENERATE_STRINGS_AS_CHAR_ARRAYS, + JspDefinition.ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE, + JspDefinition.SCRATCH_DIR, + JspDefinition.SOURCE_VM, + JspDefinition.TARGET_VM, + JspDefinition.JAVA_ENCODING, + JspDefinition.X_POWERED_BY, + JspDefinition.DISPLAY_SOURCE_FRAGMENT, + JspDefinition.OPTIMIZE_SCRIPTLETS) + ) + .addChild( + builder(SessionCookieDefinition.INSTANCE.getPathElement()) + .addAttributes( + SessionCookieDefinition.NAME, + SessionCookieDefinition.DOMAIN, + SessionCookieDefinition.COMMENT, + SessionCookieDefinition.HTTP_ONLY, + SessionCookieDefinition.SECURE, + SessionCookieDefinition.MAX_AGE + ) + ) + .addChild( + builder(PersistentSessionsDefinition.INSTANCE.getPathElement()) + .addAttributes( + PersistentSessionsDefinition.PATH, + PersistentSessionsDefinition.RELATIVE_TO + ) + ) + .addChild( + builder(WebsocketsDefinition.INSTANCE.getPathElement()) + .setMarshallDefaultValues(true) + .addAttributes( + WebsocketsDefinition.WORKER, + WebsocketsDefinition.BUFFER_POOL, + WebsocketsDefinition.DISPATCH_TO_WORKER, + WebsocketsDefinition.PER_MESSAGE_DEFLATE, + WebsocketsDefinition.DEFLATER_LEVEL + ) + ) + .addChild(builder(MimeMappingDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement("mime-mappings") + .addAttributes( + MimeMappingDefinition.VALUE + )) + .addChild(builder(WelcomeFileDefinition.INSTANCE.getPathElement()).setXmlWrapperElement("welcome-files")) + .addChild(builder(CrawlerSessionManagementDefinition.INSTANCE.getPathElement()) + .addAttributes(CrawlerSessionManagementDefinition.USER_AGENTS, CrawlerSessionManagementDefinition.SESSION_TIMEOUT)) + ) + .addChild( + builder(HandlerDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HANDLERS) + .setNoAddOperation(true) + .addChild( + builder(FileHandler.INSTANCE.getPathElement()) + .addAttributes( + FileHandler.PATH, + FileHandler.CACHE_BUFFER_SIZE, + FileHandler.CACHE_BUFFERS, + FileHandler.DIRECTORY_LISTING, + FileHandler.FOLLOW_SYMLINK, + FileHandler.SAFE_SYMLINK_PATHS, + FileHandler.CASE_SENSITIVE + ) + ) + .addChild( + builder(ReverseProxyHandler.INSTANCE.getPathElement()) + .addAttributes( + ReverseProxyHandler.CONNECTIONS_PER_THREAD, + ReverseProxyHandler.SESSION_COOKIE_NAMES, + ReverseProxyHandler.PROBLEM_SERVER_RETRY, + ReverseProxyHandler.MAX_REQUEST_TIME, + ReverseProxyHandler.REQUEST_QUEUE_SIZE, + ReverseProxyHandler.CACHED_CONNECTIONS_PER_THREAD, + ReverseProxyHandler.CONNECTION_IDLE_TIMEOUT, + ReverseProxyHandler.MAX_RETRIES) + .addChild(builder(ReverseProxyHandlerHost.INSTANCE.getPathElement()) + .setXmlElementName(Constants.HOST) + .addAttributes( + ReverseProxyHandlerHost.OUTBOUND_SOCKET_BINDING, + ReverseProxyHandlerHost.SCHEME, + ReverseProxyHandlerHost.PATH, + ReverseProxyHandlerHost.INSTANCE_ID, + ReverseProxyHandlerHost.SSL_CONTEXT, + ReverseProxyHandlerHost.SECURITY_REALM, + ReverseProxyHandlerHost.ENABLE_HTTP2)) + ) + + + ) + .addChild( + builder(FilterDefinitions.INSTANCE.getPathElement()) + .setXmlElementName(Constants.FILTERS) + .setNoAddOperation(true) + .addChild( + builder(RequestLimitHandler.INSTANCE.getPathElement()) + .addAttributes(RequestLimitHandler.MAX_CONCURRENT_REQUESTS, RequestLimitHandler.QUEUE_SIZE) + ).addChild( + builder(ResponseHeaderFilter.INSTANCE.getPathElement()) + .addAttributes(ResponseHeaderFilter.NAME, ResponseHeaderFilter.VALUE) + ).addChild( + builder(GzipFilter.INSTANCE.getPathElement()) + ).addChild( + builder(ErrorPageDefinition.INSTANCE.getPathElement()) + .addAttributes(ErrorPageDefinition.CODE, ErrorPageDefinition.PATH) + ).addChild( + builder(ModClusterDefinition.INSTANCE.getPathElement()) + .addAttributes(ModClusterDefinition.MANAGEMENT_SOCKET_BINDING, + ModClusterDefinition.ADVERTISE_SOCKET_BINDING, + ModClusterDefinition.SECURITY_KEY, + ModClusterDefinition.ADVERTISE_PROTOCOL, + ModClusterDefinition.ADVERTISE_PATH, + ModClusterDefinition.ADVERTISE_FREQUENCY, + ModClusterDefinition.FAILOVER_STRATEGY, + ModClusterDefinition.HEALTH_CHECK_INTERVAL, + ModClusterDefinition.BROKEN_NODE_TIMEOUT, + ModClusterDefinition.WORKER, + ModClusterDefinition.MAX_REQUEST_TIME, + ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE, + ModClusterDefinition.CONNECTIONS_PER_THREAD, + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD, + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT, + ModClusterDefinition.REQUEST_QUEUE_SIZE, + ModClusterDefinition.SSL_CONTEXT, + ModClusterDefinition.SECURITY_REALM, + ModClusterDefinition.USE_ALIAS, + ModClusterDefinition.ENABLE_HTTP2, + ModClusterDefinition.MAX_AJP_PACKET_SIZE, + ModClusterDefinition.HTTP2_ENABLE_PUSH, + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE, + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE, + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS, + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE, + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE, + ModClusterDefinition.MAX_RETRIES) + ).addChild( + builder(CustomFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(CustomFilterDefinition.CLASS_NAME, CustomFilterDefinition.MODULE, CustomFilterDefinition.PARAMETERS) + .setXmlElementName("filter") + ).addChild( + builder(ExpressionFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(ExpressionFilterDefinition.EXPRESSION, ExpressionFilterDefinition.MODULE) + ).addChild( + builder(RewriteFilterDefinition.INSTANCE.getPathElement()) + .addAttributes(RewriteFilterDefinition.TARGET, RewriteFilterDefinition.REDIRECT) + ) + + ) + .addChild( + builder(ApplicationSecurityDomainDefinition.INSTANCE.getPathElement()) + .setXmlWrapperElement(Constants.APPLICATION_SECURITY_DOMAINS) + .addAttributes(ApplicationSecurityDomainDefinition.HTTP_AUTHENTICATION_FACTORY, ApplicationSecurityDomainDefinition.OVERRIDE_DEPLOYMENT_CONFIG, ApplicationSecurityDomainDefinition.SECURITY_DOMAIN, ApplicationSecurityDomainDefinition.ENABLE_JACC) + .addChild(builder(UndertowExtension.PATH_SSO) + .addAttribute(SingleSignOnDefinition.Attribute.DOMAIN.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.PATH.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.HTTP_ONLY.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.SECURE.getDefinition()) + .addAttribute(SingleSignOnDefinition.Attribute.COOKIE_NAME.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_STORE.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.KEY_ALIAS.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.SSL_CONTEXT.getDefinition()) + .addAttribute(ApplicationSecurityDomainSingleSignOnDefinition.Attribute.CREDENTIAL.getDefinition(), AttributeParser.OBJECT_PARSER, AttributeMarshaller.ATTRIBUTE_OBJECT) + ) + ) + //here to make sure we always add filters & handlers path to mgmt model + .setAdditionalOperationsGenerator((address, addOperation, operations) -> { + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_FILTERS))); + operations.add(Util.createAddOperation(address.append(UndertowExtension.PATH_HANDLERS))); + }) + .build(); + } + + @Override + public PersistentResourceXMLDescription getParserDescription() { + return xmlDescription; + } + + /** Registers attributes common across listener types */ + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder listenerBuilder(PersistentResourceDefinition resource) { + return builder(resource.getPathElement()) + // xsd socket-optionsType + .addAttributes( + ListenerResourceDefinition.RECEIVE_BUFFER, + ListenerResourceDefinition.SEND_BUFFER, + ListenerResourceDefinition.BACKLOG, + ListenerResourceDefinition.KEEP_ALIVE, + ListenerResourceDefinition.READ_TIMEOUT, + ListenerResourceDefinition.WRITE_TIMEOUT, + ListenerResourceDefinition.MAX_CONNECTIONS) + // xsd listener-type + .addAttributes( + ListenerResourceDefinition.SOCKET_BINDING, + ListenerResourceDefinition.WORKER, + ListenerResourceDefinition.BUFFER_POOL, + ListenerResourceDefinition.ENABLED, + ListenerResourceDefinition.RESOLVE_PEER_ADDRESS, + ListenerResourceDefinition.MAX_ENTITY_SIZE, + ListenerResourceDefinition.BUFFER_PIPELINED_DATA, + ListenerResourceDefinition.MAX_HEADER_SIZE, + 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, + ListenerResourceDefinition.ALLOW_EQUALS_IN_COOKIE_VALUE, + ListenerResourceDefinition.NO_REQUEST_TIMEOUT, + ListenerResourceDefinition.REQUEST_PARSE_TIMEOUT, + ListenerResourceDefinition.DISALLOWED_METHODS, + ListenerResourceDefinition.SECURE, + ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION, + ListenerResourceDefinition.ALLOW_UNESCAPED_CHARACTERS_IN_URL); + } + + private static PersistentResourceXMLDescription.PersistentResourceXMLBuilder filterRefBuilder() { + return builder(FilterRefDefinition.INSTANCE.getPathElement()) + .addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowTransformers.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowTransformers.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/UndertowTransformers.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,243 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.SECURITY_DOMAIN; +import static org.wildfly.extension.undertow.Constants.ENABLE_HTTP2; +import static org.wildfly.extension.undertow.HostDefinition.QUEUE_REQUESTS_ON_START; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.CERTIFICATE_FORWARDING; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.HTTP2_HEADER_TABLE_SIZE; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.HTTP2_INITIAL_WINDOW_SIZE; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.HTTP2_MAX_FRAME_SIZE; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.PROXY_ADDRESS_FORWARDING; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.PROXY_PROTOCOL; +import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.REQUIRE_HOST_HTTP11; +import static org.wildfly.extension.undertow.HttpsListenerResourceDefinition.SSL_CONTEXT; +import static org.wildfly.extension.undertow.ListenerResourceDefinition.ALLOW_UNESCAPED_CHARACTERS_IN_URL; +import static org.wildfly.extension.undertow.ListenerResourceDefinition.RFC6265_COOKIE_VALIDATION; +import static org.wildfly.extension.undertow.ServletContainerDefinition.DEFAULT_COOKIE_VERSION; +import static org.wildfly.extension.undertow.ServletContainerDefinition.DISABLE_FILE_WATCH_SERVICE; +import static org.wildfly.extension.undertow.ServletContainerDefinition.DISABLE_SESSION_ID_REUSE; +import static org.wildfly.extension.undertow.ServletContainerDefinition.FILE_CACHE_MAX_FILE_SIZE; +import static org.wildfly.extension.undertow.ServletContainerDefinition.FILE_CACHE_METADATA_SIZE; +import static org.wildfly.extension.undertow.ServletContainerDefinition.FILE_CACHE_TIME_TO_LIVE; +import static org.wildfly.extension.undertow.WebsocketsDefinition.DEFLATER_LEVEL; +import static org.wildfly.extension.undertow.WebsocketsDefinition.PER_MESSAGE_DEFLATE; +import static org.wildfly.extension.undertow.filters.ModClusterDefinition.FAILOVER_STRATEGY; +import static org.wildfly.extension.undertow.filters.ModClusterDefinition.MAX_AJP_PACKET_SIZE; +import static org.wildfly.extension.undertow.handlers.ReverseProxyHandler.CONNECTIONS_PER_THREAD; +import static org.wildfly.extension.undertow.handlers.ReverseProxyHandler.MAX_RETRIES; + +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.transform.ExtensionTransformerRegistration; +import org.jboss.as.controller.transform.SubsystemTransformerRegistration; +import org.jboss.as.controller.transform.TransformationContext; +import org.jboss.as.controller.transform.description.AttributeConverter; +import org.jboss.as.controller.transform.description.AttributeConverter.DefaultValueAttributeConverter; +import org.jboss.as.controller.transform.description.AttributeTransformationDescriptionBuilder; +import org.jboss.as.controller.transform.description.ChainedTransformationDescriptionBuilder; +import org.jboss.as.controller.transform.description.DiscardAttributeChecker; +import org.jboss.as.controller.transform.description.DiscardAttributeChecker.DiscardAttributeValueChecker; +import org.jboss.as.controller.transform.description.RejectAttributeChecker; +import org.jboss.as.controller.transform.description.RejectAttributeChecker.SimpleRejectAttributeChecker; +import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder; +import org.jboss.as.controller.transform.description.TransformationDescriptionBuilder; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.filters.ModClusterDefinition; + + +/** + * @author Tomaz Cerar (c) 2016 Red Hat Inc. + */ +public class UndertowTransformers implements ExtensionTransformerRegistration { + public static final DiscardAttributeValueChecker FALSE_DISCARD_CHECKER = new DiscardAttributeValueChecker(new ModelNode(false)); + private static ModelVersion MODEL_VERSION_EAP7_0_0 = ModelVersion.create(3, 1, 0); + private static ModelVersion MODEL_VERSION_EAP7_1_0 = ModelVersion.create(4, 0, 0); + + @Override + public String getSubsystemName() { + return UndertowExtension.SUBSYSTEM_NAME; + } + + @Override + public void registerTransformers(SubsystemTransformerRegistration subsystemRegistration) { + + ChainedTransformationDescriptionBuilder chainedBuilder = TransformationDescriptionBuilder.Factory.createChainedSubystemInstance(subsystemRegistration.getCurrentSubsystemVersion()); + + registerTransformers_EAP_7_1_0(chainedBuilder.createBuilder(subsystemRegistration.getCurrentSubsystemVersion(), MODEL_VERSION_EAP7_1_0)); + registerTransformers_EAP_7_0_0(chainedBuilder.createBuilder(MODEL_VERSION_EAP7_1_0, MODEL_VERSION_EAP7_0_0)); + + chainedBuilder.buildAndRegister(subsystemRegistration, new ModelVersion[]{MODEL_VERSION_EAP7_1_0, MODEL_VERSION_EAP7_0_0}); + } + + + private static void registerTransformers_EAP_7_1_0(ResourceTransformationDescriptionBuilder subsystemBuilder) { + final ResourceTransformationDescriptionBuilder serverBuilder = subsystemBuilder.addChildResource(UndertowExtension.SERVER_PATH); + final ResourceTransformationDescriptionBuilder hostBuilder = serverBuilder.addChildResource(UndertowExtension.HOST_PATH); + subsystemBuilder + .addChildResource(UndertowExtension.PATH_APPLICATION_SECURITY_DOMAIN) + .getAttributeBuilder() + .addRejectCheck(RejectAttributeChecker.DEFINED, SECURITY_DOMAIN) + .end(); + + subsystemBuilder + .addChildResource(UndertowExtension.PATH_SERVLET_CONTAINER) + .getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(10 * 1024 * 1024)), FILE_CACHE_MAX_FILE_SIZE) + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(100)), FILE_CACHE_METADATA_SIZE) + .setDiscard(DiscardAttributeChecker.UNDEFINED, FILE_CACHE_TIME_TO_LIVE) + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(0)), DEFAULT_COOKIE_VERSION) + .addRejectCheck(RejectAttributeChecker.DEFINED, + FILE_CACHE_MAX_FILE_SIZE, FILE_CACHE_METADATA_SIZE, FILE_CACHE_TIME_TO_LIVE, DEFAULT_COOKIE_VERSION) + .end(); + + final AttributeTransformationDescriptionBuilder http = serverBuilder.addChildResource(UndertowExtension.HTTP_LISTENER_PATH).getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(false)), PROXY_PROTOCOL) + .addRejectCheck(new SimpleRejectAttributeChecker(new ModelNode(true)), PROXY_PROTOCOL.getName()); + addCommonListenerRules_EAP_7_1_0(http); + + final AttributeTransformationDescriptionBuilder https = serverBuilder.addChildResource(UndertowExtension.HTTPS_LISTENER_PATH).getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(false)), PROXY_PROTOCOL) + .addRejectCheck(new SimpleRejectAttributeChecker(new ModelNode(true)), PROXY_PROTOCOL); + addCommonListenerRules_EAP_7_1_0(https); + + final AttributeTransformationDescriptionBuilder ajp = serverBuilder.addChildResource(UndertowExtension.AJP_LISTENER_PATH).getAttributeBuilder(); + addCommonListenerRules_EAP_7_1_0(ajp); + + hostBuilder.getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(QUEUE_REQUESTS_ON_START.getDefaultValue()), QUEUE_REQUESTS_ON_START) + .addRejectCheck(RejectAttributeChecker.DEFINED, QUEUE_REQUESTS_ON_START) + .end(); + subsystemBuilder.rejectChildResource(UndertowExtension.BYTE_BUFFER_POOL_PATH); + } + + private static void addCommonListenerRules_EAP_7_1_0(AttributeTransformationDescriptionBuilder listener) { + convertCommonListenerAttributes(listener); + listener + .setDiscard(FALSE_DISCARD_CHECKER, ALLOW_UNESCAPED_CHARACTERS_IN_URL) + .addRejectCheck(RejectAttributeChecker.DEFINED, ALLOW_UNESCAPED_CHARACTERS_IN_URL); + } + + private static void registerTransformers_EAP_7_0_0(ResourceTransformationDescriptionBuilder subsystemBuilder) { + final ResourceTransformationDescriptionBuilder serverBuilder = subsystemBuilder.addChildResource(UndertowExtension.SERVER_PATH); + final ResourceTransformationDescriptionBuilder hostBuilder = serverBuilder.addChildResource(UndertowExtension.HOST_PATH); + + // Version 4.0.0 adds the new SSL_CONTEXT attribute, however it is mutually exclusive to the SECURITY_REALM attribute, both of which can + // now be set to 'undefined' so instead of rejecting a defined SSL_CONTEXT, reject an undefined SECURITY_REALM as that covers the + // two new combinations. + AttributeTransformationDescriptionBuilder https = + serverBuilder.addChildResource(UndertowExtension.HTTPS_LISTENER_PATH) + .getAttributeBuilder() + .setDiscard(FALSE_DISCARD_CHECKER, + CERTIFICATE_FORWARDING, PROXY_ADDRESS_FORWARDING) + .setDiscard(DiscardAttributeChecker.UNDEFINED, SSL_CONTEXT) + .addRejectCheck(RejectAttributeChecker.DEFINED, + CERTIFICATE_FORWARDING, PROXY_ADDRESS_FORWARDING, SSL_CONTEXT) + .addRejectCheck(RejectAttributeChecker.UNDEFINED, Constants.SECURITY_REALM); + addCommonListenerRules_EAP_7_0_0(https).end(); + + AttributeTransformationDescriptionBuilder http = + serverBuilder.addChildResource(UndertowExtension.HTTP_LISTENER_PATH).getAttributeBuilder(); + addCommonListenerRules_EAP_7_0_0(http); + http.end(); + + serverBuilder.addChildResource(UndertowExtension.AJP_LISTENER_PATH) + .getAttributeBuilder() + .setDiscard(FALSE_DISCARD_CHECKER, + RFC6265_COOKIE_VALIDATION) + .addRejectCheck(RejectAttributeChecker.DEFINED, + RFC6265_COOKIE_VALIDATION) + .end(); + + + subsystemBuilder + .addChildResource(UndertowExtension.PATH_SERVLET_CONTAINER) + .getAttributeBuilder() + .setDiscard(FALSE_DISCARD_CHECKER, DISABLE_FILE_WATCH_SERVICE, DISABLE_SESSION_ID_REUSE) + .addRejectCheck(RejectAttributeChecker.DEFINED, DISABLE_FILE_WATCH_SERVICE, DISABLE_SESSION_ID_REUSE) + .end() + .addChildResource(UndertowExtension.PATH_WEBSOCKETS) + .getAttributeBuilder() + .setDiscard(FALSE_DISCARD_CHECKER, PER_MESSAGE_DEFLATE) + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(0)), DEFLATER_LEVEL) + .addRejectCheck(RejectAttributeChecker.DEFINED, PER_MESSAGE_DEFLATE, DEFLATER_LEVEL) + .end(); + + subsystemBuilder.addChildResource(UndertowExtension.PATH_HANDLERS) + .addChildResource(PathElement.pathElement(Constants.REVERSE_PROXY)) + .getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(new ModelNode(1L)), MAX_RETRIES) + .addRejectCheck(RejectAttributeChecker.DEFINED, MAX_RETRIES) + .setValueConverter(new DefaultValueAttributeConverter(CONNECTIONS_PER_THREAD), CONNECTIONS_PER_THREAD) + .end() + .addChildResource(PathElement.pathElement(Constants.HOST)) + .getAttributeBuilder() + .setDiscard(DiscardAttributeChecker.UNDEFINED, SSL_CONTEXT) + .setDiscard(DiscardAttributeChecker.ALWAYS, ENABLE_HTTP2) //we just discard, as older versions will just continue to use HTTP/1.1, and enabling this does not guarentee a HTTP/2 connection anyway (if the backend does not support it) + .addRejectCheck(RejectAttributeChecker.DEFINED, SSL_CONTEXT) + .end(); + + subsystemBuilder.addChildResource(UndertowExtension.PATH_FILTERS) + .addChildResource(PathElement.pathElement(Constants.MOD_CLUSTER)) + .getAttributeBuilder() + .setDiscard(new DiscardAttributeValueChecker(FAILOVER_STRATEGY.getDefaultValue()), FAILOVER_STRATEGY) + .setDiscard(new DiscardAttributeValueChecker(ModClusterDefinition.MAX_RETRIES.getDefaultValue()), ModClusterDefinition.MAX_RETRIES) + .setDiscard(DiscardAttributeChecker.UNDEFINED, SSL_CONTEXT) + .addRejectCheck(RejectAttributeChecker.SIMPLE_EXPRESSIONS, MAX_AJP_PACKET_SIZE) + .addRejectCheck(RejectAttributeChecker.DEFINED, + ModClusterDefinition.MAX_RETRIES, FAILOVER_STRATEGY, SSL_CONTEXT) + .addRejectCheck(RejectAttributeChecker.UNDEFINED, Constants.SECURITY_REALM) + .setValueConverter(new DefaultValueAttributeConverter(MAX_AJP_PACKET_SIZE), MAX_AJP_PACKET_SIZE) + .end(); + + hostBuilder.rejectChildResource(UndertowExtension.PATH_HTTP_INVOKER); + + subsystemBuilder.rejectChildResource(UndertowExtension.PATH_APPLICATION_SECURITY_DOMAIN); + } + + private static AttributeTransformationDescriptionBuilder addCommonListenerRules_EAP_7_0_0(AttributeTransformationDescriptionBuilder builder) { + return builder + .setDiscard(FALSE_DISCARD_CHECKER, + REQUIRE_HOST_HTTP11, RFC6265_COOKIE_VALIDATION) + .addRejectCheck(RejectAttributeChecker.DEFINED, + RFC6265_COOKIE_VALIDATION, REQUIRE_HOST_HTTP11) + .setValueConverter(new DefaultValueAttributeConverter(HTTP2_HEADER_TABLE_SIZE), HTTP2_HEADER_TABLE_SIZE) + .setValueConverter(new DefaultValueAttributeConverter(HTTP2_INITIAL_WINDOW_SIZE), HTTP2_INITIAL_WINDOW_SIZE) + .setValueConverter(new DefaultValueAttributeConverter(HTTP2_MAX_FRAME_SIZE), HTTP2_MAX_FRAME_SIZE); + } + + private static AttributeTransformationDescriptionBuilder convertCommonListenerAttributes(AttributeTransformationDescriptionBuilder builder) { + builder.setValueConverter(new AttributeConverter.DefaultAttributeConverter() { + @Override + protected void convertAttribute(PathAddress address, String attributeName, ModelNode attributeValue, TransformationContext context) { + if (attributeValue.isDefined() && attributeValue.asLong() == 0L) { + attributeValue.set(Long.MAX_VALUE); + } + } + }, ListenerResourceDefinition.MAX_ENTITY_SIZE); + + return builder; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebHostService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebHostService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebHostService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,158 @@ +/* + * 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.extension.undertow; + +import java.util.Map; +import javax.servlet.Servlet; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.resource.PathResourceManager; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; +import io.undertow.servlet.api.ServletContainer; +import io.undertow.servlet.api.ServletInfo; +import io.undertow.servlet.util.ImmediateInstanceFactory; +import org.jboss.as.web.host.ServletBuilder; +import org.jboss.as.web.host.WebDeploymentBuilder; +import org.jboss.as.web.host.WebDeploymentController; +import org.jboss.as.web.host.WebHost; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.requestcontroller.ControlPoint; +import org.wildfly.extension.requestcontroller.RequestController; +import org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler; + +/** + * Implementation of WebHost from common web, service starts with few more dependencies than default Host + * + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class WebHostService implements Service, WebHost { + private final InjectedValue server = new InjectedValue<>(); + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue requestControllerInjectedValue = new InjectedValue<>(); + private volatile ControlPoint controlPoint; + + protected InjectedValue getServer() { + return server; + } + + protected InjectedValue getHost() { + return host; + } + + @Override + public WebDeploymentController addWebDeployment(final WebDeploymentBuilder webDeploymentBuilder) throws Exception { + + DeploymentInfo d = new DeploymentInfo(); + d.setDeploymentName(webDeploymentBuilder.getContextRoot()); + d.setContextPath(webDeploymentBuilder.getContextRoot()); + d.setClassLoader(webDeploymentBuilder.getClassLoader()); + d.setResourceManager(new PathResourceManager(webDeploymentBuilder.getDocumentRoot().toPath().toAbsolutePath(), 1024 * 1024)); + d.setIgnoreFlush(false); + for (ServletBuilder servlet : webDeploymentBuilder.getServlets()) { + ServletInfo s; + if (servlet.getServlet() == null) { + s = new ServletInfo(servlet.getServletName(), (Class) servlet.getServletClass()); + } else { + s = new ServletInfo(servlet.getServletName(), (Class) servlet.getServletClass(), new ImmediateInstanceFactory<>(servlet.getServlet())); + } + if (servlet.isForceInit()) { + s.setLoadOnStartup(1); + } + s.addMappings(servlet.getUrlMappings()); + for (Map.Entry param : servlet.getInitParams().entrySet()) { + s.addInitParam(param.getKey(), param.getValue()); + } + d.addServlet(s); + } + + if (controlPoint != null) { + d.addOuterHandlerChainWrapper(GlobalRequestControllerHandler.wrapper(controlPoint, webDeploymentBuilder.getAllowRequestPredicates())); + } + + return new WebDeploymentControllerImpl(d); + } + + private class WebDeploymentControllerImpl implements WebDeploymentController { + + private final DeploymentInfo deploymentInfo; + private volatile DeploymentManager manager; + + private WebDeploymentControllerImpl(final DeploymentInfo deploymentInfo) { + this.deploymentInfo = deploymentInfo; + } + + @Override + public void create() throws Exception { + ServletContainer container = server.getValue().getServletContainer().getValue().getServletContainer(); + manager = container.addDeployment(deploymentInfo); + manager.deploy(); + } + + @Override + public void start() throws Exception { + HttpHandler handler = manager.start(); + host.getValue().registerDeployment(manager.getDeployment(), handler); + } + + @Override + public void stop() throws Exception { + host.getValue().unregisterDeployment(manager.getDeployment()); + manager.stop(); + } + + @Override + public void destroy() throws Exception { + manager.undeploy(); + ServletContainer container = server.getValue().getServletContainer().getValue().getServletContainer(); + container.removeDeployment(deploymentInfo); + } + } + + @Override + public void start(StartContext context) throws StartException { + RequestController rq = requestControllerInjectedValue.getOptionalValue(); + if(rq != null) { + controlPoint = rq.getControlPoint("", "org.wildfly.undertow.webhost." + server.getValue().getName() + "." + host.getValue().getName()); + } + } + + @Override + public void stop(StopContext context) { + if(controlPoint != null) { + requestControllerInjectedValue.getValue().removeControlPoint(controlPoint); + } + } + + @Override + public WebHost getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + public InjectedValue getRequestControllerInjectedValue() { + return requestControllerInjectedValue; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebServerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebServerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebServerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,93 @@ +/* + * 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.extension.undertow; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.as.network.SocketBinding; +import org.jboss.as.web.host.CommonWebServer; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Stuart Douglas + */ +class WebServerService implements CommonWebServer, Service { + private InjectedValue serverInjectedValue = new InjectedValue<>(); + + InjectedValue getServerInjectedValue() { + return serverInjectedValue; + } + + //todo we need to handle cases when deployments reference listeners/server/host directly + @Override + public int getPort(final String protocol, final boolean secure) { + Map listeners = getListenerMap(); + UndertowListener listener = null; + for (String p : listeners.keySet()) { + if (protocol.toLowerCase().contains(p)) { + listener = listeners.get(p); + } + } + if (listener != null && listener.getProtocol() == HttpListenerService.PROTOCOL && secure) { + if (listeners.containsKey(HttpsListenerService.PROTOCOL)) { + listener = listeners.get(HttpsListenerService.PROTOCOL); + } else { + UndertowLogger.ROOT_LOGGER.secureListenerNotAvailableForPort(protocol); + } + } + if (listener != null) { + SocketBinding binding = listener.getSocketBinding(); + return binding.getAbsolutePort(); + } + throw UndertowLogger.ROOT_LOGGER.noPortListeningForProtocol(protocol); + + } + + private Map getListenerMap() { + HashMap listeners = new HashMap<>(); + for (UndertowListener listener : serverInjectedValue.getValue().getListeners()) { + listeners.put(listener.getProtocol(), listener); + } + return listeners; + } + + @Override + public void start(final StartContext context) throws StartException { + + } + + @Override + public void stop(final StopContext context) { + } + + @Override + public WebServerService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebsocketsDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebsocketsDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/WebsocketsDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,216 @@ +/* + * 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.extension.undertow; + +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_BYTE_BUFFER_POOL; +import static org.wildfly.extension.undertow.Capabilities.REF_IO_WORKER; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.RestartParentResourceAddHandler; +import org.jboss.as.controller.RestartParentResourceRemoveHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceName; + +/** + * Global websocket configuration + * + * @author Stuart Douglas + */ +class WebsocketsDefinition extends PersistentResourceDefinition { + + private static final RuntimeCapability WEBSOCKET_CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_WEBSOCKET, true, UndertowListener.class) + .setDynamicNameMapper(pathElements -> new String[]{ + pathElements.getParent().getLastElement().getValue() + }) + .build(); + + protected static final SimpleAttributeDefinition BUFFER_POOL = + new SimpleAttributeDefinitionBuilder("buffer-pool", ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(CAPABILITY_BYTE_BUFFER_POOL) + .build(); + + protected static final SimpleAttributeDefinition WORKER = + new SimpleAttributeDefinitionBuilder("worker", ModelType.STRING, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(REF_IO_WORKER) + .build(); + + protected static final SimpleAttributeDefinition DISPATCH_TO_WORKER = + new SimpleAttributeDefinitionBuilder("dispatch-to-worker", ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(true)) + .build(); + + protected static final SimpleAttributeDefinition PER_MESSAGE_DEFLATE = + new SimpleAttributeDefinitionBuilder("per-message-deflate", ModelType.BOOLEAN, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .build(); + + protected static final SimpleAttributeDefinition DEFLATER_LEVEL = + new SimpleAttributeDefinitionBuilder("deflater-level", ModelType.INT, true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .setAllowExpression(true) + .setValidator(new IntRangeValidator(0, 9, true, true)) + .setDefaultValue(new ModelNode(0)) + .build(); + + protected static final List ATTRIBUTES = Arrays.asList( + BUFFER_POOL, + WORKER, + DISPATCH_TO_WORKER, + PER_MESSAGE_DEFLATE, + DEFLATER_LEVEL + ); + + static final WebsocketsDefinition INSTANCE = new WebsocketsDefinition(); + + + private WebsocketsDefinition() { + super(UndertowExtension.PATH_WEBSOCKETS, + UndertowExtension.getResolver(UndertowExtension.PATH_WEBSOCKETS.getKeyValuePair()), + new WebsocketsAdd(), + new WebsocketsRemove()); + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerCapability(WEBSOCKET_CAPABILITY); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + public WebSocketInfo getConfig(final OperationContext context, final ModelNode model) throws OperationFailedException { + if (!model.isDefined()) { + return null; + } + boolean dispatchToWorker = DISPATCH_TO_WORKER.resolveModelAttribute(context, model).asBoolean(); + String bufferPool = BUFFER_POOL.resolveModelAttribute(context, model).asString(); + String worker = WORKER.resolveModelAttribute(context, model).asString(); + boolean perMessageDeflate = PER_MESSAGE_DEFLATE.resolveModelAttribute(context, model).asBoolean(); + int deflaterLevel = DEFLATER_LEVEL.resolveModelAttribute(context, model).asInt(); + + return new WebSocketInfo(worker, bufferPool, dispatchToWorker, perMessageDeflate, deflaterLevel); + } + + private static class WebsocketsAdd extends RestartParentResourceAddHandler { + protected WebsocketsAdd() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey(), Collections.singleton(WEBSOCKET_CAPABILITY), ATTRIBUTES); + } + + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return ServletContainerDefinition.SERVLET_CONTAINER_CAPABILITY.getCapabilityServiceName(parentAddress); + } + } + + private static class WebsocketsRemove extends RestartParentResourceRemoveHandler { + + protected WebsocketsRemove() { + super(ServletContainerDefinition.INSTANCE.getPathElement().getKey()); + } + + @Override + protected void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel) throws OperationFailedException { + ServletContainerAdd.INSTANCE.installRuntimeServices(context, parentModel, parentAddress.getLastElement().getValue()); + } + + @Override + protected ServiceName getParentServiceName(PathAddress parentAddress) { + return ServletContainerDefinition.SERVLET_CONTAINER_CAPABILITY.getCapabilityServiceName(parentAddress); + } + } + + public static class WebSocketInfo { + private final String worker; + private final String bufferPool; + private final boolean dispatchToWorker; + private final boolean perMessageDeflate; + private final int deflaterLevel; + + public WebSocketInfo(String worker, String bufferPool, boolean dispatchToWorker, boolean perMessageDeflate, + int deflaterLevel) { + this.worker = worker; + this.bufferPool = bufferPool; + this.dispatchToWorker = dispatchToWorker; + this.perMessageDeflate = perMessageDeflate; + this.deflaterLevel = deflaterLevel; + } + + public String getWorker() { + return worker; + } + + public String getBufferPool() { + return bufferPool; + } + + public boolean isDispatchToWorker() { + return dispatchToWorker; + } + + public boolean isPerMessageDeflate() { + return perMessageDeflate; + } + + public int getDeflaterLevel() { + return deflaterLevel; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/WelcomeFileDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/WelcomeFileDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/WelcomeFileDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,66 @@ +/* + * 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.extension.undertow; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredAddStepHandler; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Global welcome file definition + * + * @author Stuart Douglas + */ +class WelcomeFileDefinition extends PersistentResourceDefinition { + + static final WelcomeFileDefinition INSTANCE = new WelcomeFileDefinition(); + + protected static final SimpleAttributeDefinition[] ATTRIBUTES = { + + }; + + static final Map ATTRIBUTES_MAP = new HashMap<>(); + + static { + for (SimpleAttributeDefinition attr : ATTRIBUTES) { + ATTRIBUTES_MAP.put(attr.getName(), attr); + } + } + + + private WelcomeFileDefinition() { + super(UndertowExtension.PATH_WELCOME_FILE, + UndertowExtension.getResolver(Constants.WELCOME_FILE), new ReloadRequiredAddStepHandler(), new ReloadRequiredRemoveStepHandler()); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES_MAP.values(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/AuthMethodParser.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/AuthMethodParser.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/AuthMethodParser.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,89 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.servlet.api.AuthMethodConfig; +import io.undertow.util.QueryParameterUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.Map; + +/** + * @author Stuart Douglas + */ +public class AuthMethodParser { + + public static final String UTF_8 = "UTF-8"; + + public static List parse(final String methods, final Map replacements) { + try { + if (methods == null || methods.isEmpty()) { + return Collections.emptyList(); + } + final List ret = new ArrayList(); + String[] parts = methods.split(","); + for (String part : parts) { + if (part.isEmpty()) { + continue; + } + int index = part.indexOf('?'); + if (index == -1) { + ret.add(createAuthMethodConfig(part, replacements)); + } else { + final String name = part.substring(0, index); + Map> props = QueryParameterUtils.parseQueryString(part.substring(index + 1), UTF_8); + final AuthMethodConfig authMethodConfig = createAuthMethodConfig(name, replacements); + for (Map.Entry> entry : props.entrySet()) { + Deque val = entry.getValue(); + if (val.isEmpty()) { + authMethodConfig.getProperties().put(entry.getKey(), ""); + } else { + authMethodConfig.getProperties().put(entry.getKey(), val.getFirst()); + } + } + ret.add(authMethodConfig); + } + } + return ret; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private static AuthMethodConfig createAuthMethodConfig(String part, Map replacements) throws UnsupportedEncodingException { + String name = URLDecoder.decode(part, UTF_8); + if (replacements.containsKey(name)) { + return new AuthMethodConfig(replacements.get(name)); + } + return new AuthMethodConfig(name); + } + + private AuthMethodParser() { + + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ConfiguredHandlerWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ConfiguredHandlerWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ConfiguredHandlerWrapper.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,93 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import org.jboss.common.beans.property.BeanUtils; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.manager.WildFlySecurityManager; + +import java.lang.reflect.Constructor; +import java.util.Map; +import java.util.Properties; + +/** + * Handler wrapper that create a new instance of the specified {@link HandlerWrapper} or + * {@link HttpHandler} class, and configures it via the specified properties. + * + * @author Stuart Douglas + */ +public class ConfiguredHandlerWrapper implements HandlerWrapper { + + private final Class handlerClass; + private final Map properties; + + public ConfiguredHandlerWrapper(Class handlerClass, Map properties) { + this.handlerClass = handlerClass; + this.properties = properties; + } + + @Override + public HttpHandler wrap(HttpHandler handler) { + try { + final Object instance; + if (HttpHandler.class.isAssignableFrom(handlerClass)) { + final Constructor ctor = handlerClass.getConstructor(HttpHandler.class); + // instantiate the handler with the TCCL as the handler class' classloader + final ClassLoader prevCL = WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(handlerClass); + try { + instance = ctor.newInstance(handler); + } finally { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(prevCL); + } + } else if (HandlerWrapper.class.isAssignableFrom(handlerClass)) { + // instantiate the handler with the TCCL as the handler class' classloader + final ClassLoader prevCL = WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(handlerClass); + try { + instance = handlerClass.newInstance(); + } finally { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(prevCL); + } + } else { + throw UndertowLogger.ROOT_LOGGER.handlerWasNotAHandlerOrWrapper(handlerClass); + } + Properties p = new Properties(); + p.putAll(properties); + + ClassLoader oldCl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(); + try { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(BeanUtils.class); + BeanUtils.mapJavaBeanProperties(instance, p); + } finally { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldCl); + } + if (HttpHandler.class.isAssignableFrom(handlerClass)) { + return (HttpHandler) instance; + } else { + return ((HandlerWrapper) instance).wrap(handler); + } + } catch (Exception e) { + throw UndertowLogger.ROOT_LOGGER.failedToConfigureHandler(handlerClass, e); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultDeploymentMappingProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultDeploymentMappingProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultDeploymentMappingProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,66 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.AbstractMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2016 Red Hat Inc. + */ +public final class DefaultDeploymentMappingProvider { + + private static DefaultDeploymentMappingProvider INSTANCE = new DefaultDeploymentMappingProvider(); + + public static DefaultDeploymentMappingProvider instance() { + return INSTANCE; + } + + private final ConcurrentHashMap> mappings; + + private DefaultDeploymentMappingProvider() { + this.mappings = new ConcurrentHashMap<>(); + } + + + public Map.Entry getMapping(String deploymentName) { + return mappings.get(deploymentName); + } + + public void removeMapping(String deploymentName) { + mappings.remove(deploymentName); + } + + public void addMapping(String deploymentName, String serverName, String hostName) { + if (mappings.putIfAbsent(deploymentName, new AbstractMap.SimpleEntry<>(serverName, hostName)) != null) { + throw UndertowLogger.ROOT_LOGGER.duplicateDefaultWebModuleMapping(deploymentName, serverName, hostName); + } + } + public void clear(){ + mappings.clear(); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultSecurityDomainProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultSecurityDomainProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DefaultSecurityDomainProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,46 @@ +/* + * 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.extension.undertow.deployment; + +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; + +public class DefaultSecurityDomainProcessor implements DeploymentUnitProcessor { + + private String defaultSecurityDomain; + public DefaultSecurityDomainProcessor(String securityDomain) { + defaultSecurityDomain = securityDomain; + } + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + phaseContext.getDeploymentUnit().putAttachment(UndertowAttachments.DEFAULT_SECURITY_DOMAIN, defaultSecurityDomain); + + } + + @Override + public void undeploy(DeploymentUnit context) { + context.removeAttachment(UndertowAttachments.DEFAULT_SECURITY_DOMAIN); + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DelegatingResourceManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DelegatingResourceManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DelegatingResourceManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,85 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.handlers.resource.Resource; +import io.undertow.server.handlers.resource.ResourceChangeListener; +import io.undertow.server.handlers.resource.ResourceManager; +import org.xnio.IoUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Stuart Douglas + */ +public class DelegatingResourceManager implements ResourceManager { + + private final List delegates; + + public DelegatingResourceManager(List delegates) { + this.delegates = new ArrayList<>(delegates); + } + + @Override + public Resource getResource(String path) throws IOException { + for(ResourceManager d : delegates) { + Resource res = d.getResource(path); + if(res != null) { + return res; + } + } + return null; + } + + @Override + public boolean isResourceChangeListenerSupported() { + return true; + } + + @Override + public void registerResourceChangeListener(ResourceChangeListener listener) { + for(ResourceManager del : delegates) { + if(del.isResourceChangeListenerSupported()) { + del.registerResourceChangeListener(listener); + } + } + } + + @Override + public void removeResourceChangeListener(ResourceChangeListener listener) { + for(ResourceManager del : delegates) { + if(del.isResourceChangeListenerSupported()) { + del.removeResourceChangeListener(listener); + } + } + } + + @Override + public void close() throws IOException { + for(ResourceManager del : delegates) { + IoUtils.safeClose(del); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DeploymentRootExplodedMountProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DeploymentRootExplodedMountProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/DeploymentRootExplodedMountProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,53 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.Locale; + +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.MountExplodedMarker; + +/** + * Processor that marks a deployment as exploded. + * + * @author Thomas.Diesler@jboss.com + * @since 05-Oct-2011 + */ +public class DeploymentRootExplodedMountProcessor implements DeploymentUnitProcessor { + + private static final String WAR_EXTENSION = ".war"; + + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + DeploymentUnit depUnit = phaseContext.getDeploymentUnit(); + String depName = depUnit.getName().toLowerCase(Locale.ENGLISH); + if (depName.endsWith(WAR_EXTENSION)) { + MountExplodedMarker.setMountExploded(depUnit); + } + } + + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/EarContextRootProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/EarContextRootProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/EarContextRootProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,96 @@ +/* + * 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.extension.undertow.deployment; + +import org.jboss.as.ee.structure.Attachments; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.ear.spec.EarMetaData; +import org.jboss.metadata.ear.spec.ModuleMetaData; +import org.jboss.metadata.ear.spec.ModulesMetaData; +import org.jboss.metadata.ear.spec.WebModuleMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; + +import static org.jboss.metadata.ear.spec.ModuleMetaData.ModuleType.Web; + +/** + * Deployment unit processor responsible for detecting web deployments and determining if they have a parent EAR file and + * if so applying the EAR defined context root to web metadata. + * + * @author John Bailey + */ +public class EarContextRootProcessor implements DeploymentUnitProcessor { + + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if(warMetaData == null) { + return; // Nothing we can do without WarMetaData + } + final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.DEPLOYMENT_ROOT); + if(deploymentRoot == null) { + return; // We don't have a root to work with + } + + final DeploymentUnit parent = deploymentUnit.getParent(); + if(parent == null || !DeploymentTypeMarker.isType(DeploymentType.EAR, parent)) { + return; // Only care if this war is nested in an EAR + } + + final EarMetaData earMetaData = parent.getAttachment(Attachments.EAR_METADATA); + if(earMetaData == null) { + return; // Nothing to see here + } + + final ModulesMetaData modulesMetaData = earMetaData.getModules(); + if(modulesMetaData != null) for(ModuleMetaData moduleMetaData : modulesMetaData) { + if(Web.equals(moduleMetaData.getType()) && moduleMetaData.getFileName().equals(deploymentRoot.getRootName())) { + String contextRoot = WebModuleMetaData.class.cast(moduleMetaData.getValue()).getContextRoot(); + + if(contextRoot == null && (warMetaData.getJBossWebMetaData() == null || warMetaData.getJBossWebMetaData().getContextRoot() == null)) { + contextRoot = "/" + parent.getName().substring(0, parent.getName().length() - 4) + "/" + + deploymentUnit.getName().substring(0, deploymentUnit.getName().length() - 4); + } + + if(contextRoot != null) { + JBossWebMetaData jBossWebMetaData = warMetaData.getJBossWebMetaData(); + if(jBossWebMetaData == null) { + jBossWebMetaData = new JBossWebMetaData(); + warMetaData.setJBossWebMetaData(jBossWebMetaData); + } + jBossWebMetaData.setContextRoot(contextRoot); + } + return; + } + } + } + + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ExternalTldParsingDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ExternalTldParsingDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ExternalTldParsingDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,164 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.parser.jsp.TldMetaDataParser; +import org.jboss.metadata.parser.util.NoopXMLResolver; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.TldMetaData; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleLoadException; +import org.jboss.modules.Resource; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * + * Looks for external TLD's + * + * @author Stuart Douglas + */ +public class ExternalTldParsingDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String IMPLICIT_TLD = "implicit.tld"; + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetaData == null || warMetaData.getMergedJBossWebMetaData() == null) { + return; + } + TldsMetaData tldsMetaData = deploymentUnit.getAttachment(TldsMetaData.ATTACHMENT_KEY); + Map tlds = tldsMetaData.getTlds(); + + Set sharedTldUris = new HashSet<>(); + for(TldMetaData shared : tldsMetaData.getSharedTlds(deploymentUnit)) { + sharedTldUris.add(shared.getUri()); + } + + Module module = deploymentUnit.getAttachment(Attachments.MODULE); + try { + Iterator resources = module.globResources("META-INF/**.tld"); + while (resources.hasNext()) { + final Resource resource = resources.next(); + //horrible hack + //we don't want to parse JSF TLD's + //this would be picked up by the shared tlds check below, but this means we don't + //waste time re-parsing them + if(resource.getURL().toString().contains("com/sun/jsf-impl/main")) { + continue; + } + + if(resource.getName().startsWith("META-INF/")) { + if(tlds.containsKey(resource.getName())) { + continue; + } + if(resource.getURL().getProtocol().equals("vfs")) { + continue; + } + final TldMetaData value = parseTLD(resource); + if(sharedTldUris.contains(value.getUri())) { + //don't re-include shared TLD's + continue; + } + String key = "/" + resource.getName(); + if (!tlds.containsKey(key)) { + tlds.put(key, value); + } + if (!tlds.containsKey(value.getUri())) { + tlds.put(value.getUri(), value); + } + if (value.getListeners() != null) { + for (ListenerMetaData l : value.getListeners()) { + List listeners = warMetaData.getMergedJBossWebMetaData().getListeners(); + if(listeners == null) { + warMetaData.getMergedJBossWebMetaData().setListeners(listeners = new ArrayList()); + } + listeners.add(l); + } + } + } + + } + } catch (ModuleLoadException e) { + throw new DeploymentUnitProcessingException(e); + } + } + + + @Override + public void undeploy(final DeploymentUnit context) { + } + + private TldMetaData parseTLD(Resource tld) + throws DeploymentUnitProcessingException { + if (IMPLICIT_TLD.equals(tld.getName())) { + // Implicit TLDs are different from regular TLDs + return new TldMetaData(); + } + InputStream is = null; + try { + is = tld.openStream(); + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setXMLResolver(NoopXMLResolver.create()); + XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is); + return TldMetaDataParser.parse(xmlReader); + } catch (XMLStreamException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(tld.getName(), e.getLocation().getLineNumber(), + e.getLocation().getColumnNumber()), e); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(tld.getName()), e); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + // Ignore + } + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GateHandlerWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GateHandlerWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GateHandlerWrapper.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,119 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.SameThreadExecutor; + +import java.util.ArrayList; +import java.util.List; + +/** + * A handler that will prevent requests from progressing until the gate is opened. + * + * This will either queue or reject the requests, based on the configured behaviour + * + * @author Stuart Douglas + */ +public class GateHandlerWrapper implements HandlerWrapper { + + private final List held = new ArrayList<>(); + + private volatile boolean open = false; + + /** + * If this is >0 then requests when the gate is closed will be rejected with this value + * + * Otherwise they will be queued + */ + private final int statusCode; + + public GateHandlerWrapper(int statusCode) { + this.statusCode = statusCode; + } + + + public synchronized void open() { + open = true; + for(Holder holder : held) { + holder.exchange.dispatch(holder.next); + } + held.clear(); + } + + @Override + public HttpHandler wrap(HttpHandler handler) { + return new GateHandler(handler); + } + + private final class GateHandler implements HttpHandler { + + private final HttpHandler next; + + private GateHandler(HttpHandler next) { + this.next = next; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + if(open) { + next.handleRequest(exchange); + return; + } + if(statusCode > 0) { + exchange.setStatusCode(statusCode); + return; + } + synchronized (GateHandlerWrapper.this) { + if(open) { + next.handleRequest(exchange); + } else { + exchange.dispatch(SameThreadExecutor.INSTANCE, new Runnable() { + @Override + public void run() { + synchronized (GateHandlerWrapper.this) { + if(open) { + exchange.dispatch(next); + } else { + held.add(new Holder(next, exchange)); + } + } + } + }); + } + } + } + } + + private static final class Holder { + final HttpHandler next; + final HttpServerExchange exchange; + + private Holder(HttpHandler next, HttpServerExchange exchange) { + this.next = next; + this.exchange = exchange; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GlobalRequestControllerHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GlobalRequestControllerHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/GlobalRequestControllerHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,103 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.List; + +import org.wildfly.extension.requestcontroller.ControlPoint; +import org.wildfly.extension.requestcontroller.RunResult; + +import io.undertow.predicate.Predicate; +import io.undertow.server.ExchangeCompletionListener; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletRequestContext; + +/** + * Undertow handler that hooks into the global request controller. + * + * @author Stuart Douglas + */ +public class GlobalRequestControllerHandler implements HttpHandler { + + public static final String ORG_WILDFLY_SUSPENDED = "org.wildfly.suspended"; + private final HttpHandler next; + private final ControlPoint entryPoint; + private final List allowSuspendedRequests; + + private final ExchangeCompletionListener listener = new ExchangeCompletionListener() { + @Override + public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) { + entryPoint.requestComplete(); + nextListener.proceed(); + } + }; + + public GlobalRequestControllerHandler(HttpHandler next, ControlPoint entryPoint, List allowSuspendedRequests) { + this.next = next; + this.entryPoint = entryPoint; + this.allowSuspendedRequests = allowSuspendedRequests; + } + + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception { + RunResult result = entryPoint.beginRequest(); + try { + if(result == RunResult.RUN) { + next.handleRequest(exchange); + } else { + boolean allowed = false; + for(Predicate allow : allowSuspendedRequests) { + if(allow.resolve(exchange)) { + allowed = true; + ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + if(src != null) { + src.getServletRequest().setAttribute(ORG_WILDFLY_SUSPENDED, "true"); + } + next.handleRequest(exchange); + break; + } + } + if (!allowed) { + exchange.setStatusCode(503); + exchange.endExchange(); + } + } + } finally { + if(result == RunResult.RUN && (exchange.isComplete() || !exchange.isDispatched())) { + entryPoint.requestComplete(); + } else if(result == RunResult.RUN) { + exchange.addExchangeCompleteListener(listener); + } + } + } + + public static HandlerWrapper wrapper(final ControlPoint entryPoint, List allowSuspendedRequests) { + return handler -> new GlobalRequestControllerHandler(handler, entryPoint, allowSuspendedRequests); + } + + public HttpHandler getNext() { + return next; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ImmediateSessionManagerFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ImmediateSessionManagerFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ImmediateSessionManagerFactory.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,44 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.session.SessionManager; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.SessionManagerFactory; + +/** + * @author Stuart Douglas + */ +public class ImmediateSessionManagerFactory implements SessionManagerFactory{ + + private final SessionManager sessionManager; + + public ImmediateSessionManagerFactory(SessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + @Override + public SessionManager createSessionManager(Deployment deployment) { + return sessionManager; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JBossWebParsingDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JBossWebParsingDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JBossWebParsingDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,111 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.ee.structure.JBossDescriptorPropertyReplacement; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.parser.jbossweb.JBossWebMetaDataParser; +import org.jboss.metadata.parser.util.NoopXMLResolver; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.jboss.ValveMetaData; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.undertow.logging.UndertowLogger; + + +/** + * @author Jean-Frederic Clere + */ +public class JBossWebParsingDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String JBOSS_WEB_XML = "WEB-INF/jboss-web.xml"; + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + final VirtualFile deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot(); + final VirtualFile jbossWebXml = deploymentRoot.getChild(JBOSS_WEB_XML); + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + if (jbossWebXml.exists()) { + InputStream is = null; + try { + is = jbossWebXml.openStream(); + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setXMLResolver(NoopXMLResolver.create()); + XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is); + + final JBossWebMetaData jBossWebMetaData = JBossWebMetaDataParser.parse(xmlReader, JBossDescriptorPropertyReplacement.propertyReplacer(deploymentUnit)); + warMetaData.setJBossWebMetaData(jBossWebMetaData); + // if the jboss-web.xml has a distinct-name configured, then attach the value to this + // deployment unit + if(jBossWebMetaData.getValves() != null) { + for(ValveMetaData valve : jBossWebMetaData.getValves()) { + UndertowLogger.ROOT_LOGGER.unsupportedValveFeature(valve.getValveClass()); + } + } + if (jBossWebMetaData.getDistinctName() != null) { + deploymentUnit.putAttachment(org.jboss.as.ee.structure.Attachments.DISTINCT_NAME, jBossWebMetaData.getDistinctName()); + } + } catch (XMLStreamException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(jbossWebXml.toString(), e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()), e); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(jbossWebXml.toString()), e); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + // Ignore + } + } + } else { + //jboss web embedded inside jboss-all.xml + final JBossWebMetaData jbMeta = deploymentUnit.getAttachment(WebJBossAllParser.ATTACHMENT_KEY); + if(jbMeta != null) { + warMetaData.setJBossWebMetaData(jbMeta); + } + } + } + + @Override + public void undeploy(DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspApplicationContextWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspApplicationContextWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspApplicationContextWrapper.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,97 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.List; + +import javax.el.ELContextListener; +import javax.el.ELResolver; +import javax.el.ExpressionFactory; +import javax.servlet.ServletContext; +import javax.servlet.jsp.JspContext; + +import org.apache.jasper.el.ELContextImpl; +import org.apache.jasper.runtime.JspApplicationContextImpl; +import org.jboss.as.web.common.ExpressionFactoryWrapper; + +/** + * @author pmuir + */ +public class JspApplicationContextWrapper extends JspApplicationContextImpl { + + private final JspApplicationContextImpl delegate; + private final List wrapperList; + private final ServletContext servletContext; + private volatile ExpressionFactory factory; + + protected JspApplicationContextWrapper(JspApplicationContextImpl delegate, List wrapperList, ServletContext servletContext) { + this.delegate = delegate; + this.wrapperList = wrapperList; + this.servletContext = servletContext; + } + + @Override + public void addELContextListener(ELContextListener listener) { + delegate.addELContextListener(listener); + } + + @Override + public void addELResolver(ELResolver resolver) throws IllegalStateException { + delegate.addELResolver(resolver); + } + + @Override + public ELContextImpl createELContext(JspContext arg0) { + return delegate.createELContext(arg0); + } + + @Override + public ExpressionFactory getExpressionFactory() { + if (factory == null) { + synchronized (this) { + if (factory == null) { + factory = delegate.getExpressionFactory(); + for (ExpressionFactoryWrapper wrapper : wrapperList) { + factory = wrapper.wrap(factory, servletContext); + } + } + } + } + return factory; + } + + @Override + public boolean equals(Object obj) { + return this == obj || delegate.equals(obj); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspConfigDescriptorImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspConfigDescriptorImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspConfigDescriptorImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow.deployment; + +import org.apache.jasper.deploy.JspPropertyGroup; +import org.apache.jasper.deploy.TagLibraryInfo; + +import javax.servlet.descriptor.JspConfigDescriptor; +import javax.servlet.descriptor.JspPropertyGroupDescriptor; +import javax.servlet.descriptor.TaglibDescriptor; +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author Stuart Douglas + */ +public class JspConfigDescriptorImpl implements JspConfigDescriptor { + + private final Collection taglibs; + private final Collection jspPropertyGroups; + + public JspConfigDescriptorImpl(Collection taglibs, Collection jspPropertyGroups) { + this.taglibs = new ArrayList(); + for(TagLibraryInfo t : taglibs) { + this.taglibs.add(new TaglibDescriptorImpl(t)); + } + this.jspPropertyGroups = new ArrayList(); + for(JspPropertyGroup p : jspPropertyGroups) { + this.jspPropertyGroups.add(new JspPropertyGroupDescriptorImpl(p)); + } + } + + @Override + public Collection getTaglibs() { + return new ArrayList(taglibs); + } + + @Override + public Collection getJspPropertyGroups() { + return new ArrayList(jspPropertyGroups); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspInitializationListener.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspInitializationListener.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspInitializationListener.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,65 @@ +/* + * 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.extension.undertow.deployment; + +import org.apache.jasper.runtime.JspApplicationContextImpl; +import org.jboss.as.web.common.ExpressionFactoryWrapper; +import org.wildfly.extension.undertow.ImportedClassELResolver; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.jsp.JspApplicationContext; +import javax.servlet.jsp.JspFactory; +import java.util.List; + +/** + * Listener that sets up the {@link JspApplicationContext} with any wrapped EL expression factories and also + * setting up any relevant {@link javax.el.ELResolver}s + * + * @author Stuart Douglas + */ +public class JspInitializationListener implements ServletContextListener { + + public static final String CONTEXT_KEY = "org.jboss.as.web.deployment.JspInitializationListener.wrappers"; + + @Override + public void contextInitialized(final ServletContextEvent sce) { + // if the servlet version is 3.1 or higher, setup a ELResolver which allows usage of static fields java.lang.* + final ServletContext servletContext = sce.getServletContext(); + final JspApplicationContext jspApplicationContext = JspFactory.getDefaultFactory().getJspApplicationContext(servletContext); + if (servletContext.getEffectiveMajorVersion() >= 3 && servletContext.getEffectiveMinorVersion() >= 1) { + jspApplicationContext.addELResolver(new ImportedClassELResolver()); + } + // setup a wrapped JspApplicationContext if there are any EL expression factory wrappers for this servlet context + final List expressionFactoryWrappers = (List) sce.getServletContext().getAttribute(CONTEXT_KEY); + if (expressionFactoryWrappers != null && !expressionFactoryWrappers.isEmpty()) { + final JspApplicationContextWrapper jspApplicationContextWrapper = new JspApplicationContextWrapper(JspApplicationContextImpl.getInstance(servletContext), expressionFactoryWrappers, sce.getServletContext()); + sce.getServletContext().setAttribute(JspApplicationContextImpl.class.getName(), jspApplicationContextWrapper); + } + } + + @Override + public void contextDestroyed(final ServletContextEvent sce) { + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspPropertyGroupDescriptorImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspPropertyGroupDescriptorImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/JspPropertyGroupDescriptorImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,100 @@ +/* + * 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.extension.undertow.deployment; + +import org.apache.jasper.deploy.JspPropertyGroup; + +import javax.servlet.descriptor.JspPropertyGroupDescriptor; +import java.util.Collection; + +/** + * @author Stuart Douglas + */ +public class JspPropertyGroupDescriptorImpl implements JspPropertyGroupDescriptor { + + private final JspPropertyGroup propertyGroup; + + public JspPropertyGroupDescriptorImpl(JspPropertyGroup propertyGroup) { + this.propertyGroup = propertyGroup; + } + + @Override + public Collection getUrlPatterns() { + return propertyGroup.getUrlPatterns(); + } + + @Override + public String getElIgnored() { + return propertyGroup.getElIgnored(); + } + + @Override + public String getPageEncoding() { + return propertyGroup.getPageEncoding(); + } + + @Override + public String getScriptingInvalid() { + return propertyGroup.getScriptingInvalid(); + } + + @Override + public String getIsXml() { + return propertyGroup.getIsXml(); + } + + @Override + public Collection getIncludePreludes() { + return propertyGroup.getIncludePreludes(); + } + + @Override + public Collection getIncludeCodas() { + return propertyGroup.getIncludeCodas(); + } + + @Override + public String getDeferredSyntaxAllowedAsLiteral() { + return propertyGroup.getDeferredSyntaxAllowedAsLiteral(); + } + + @Override + public String getTrimDirectiveWhitespaces() { + return propertyGroup.getTrimDirectiveWhitespaces(); + } + + @Override + public String getDefaultContentType() { + return propertyGroup.getDefaultContentType(); + } + + @Override + public String getBuffer() { + return propertyGroup.getBuffer(); + } + + @Override + public String getErrorOnUndeclaredNamespace() { + return propertyGroup.getErrorOnUndeclaredNamespace(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/LogoutSessionListener.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/LogoutSessionListener.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/LogoutSessionListener.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,115 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.security.api.AuthenticatedSessionManager; +import io.undertow.security.api.SecurityContext; +import io.undertow.security.idm.Account; +import io.undertow.server.session.Session; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler; +import io.undertow.servlet.spec.HttpSessionImpl; +import org.jboss.security.AuthenticationManager; +import org.wildfly.extension.undertow.security.AccountImpl; +import org.wildfly.security.manager.WildFlySecurityManager; + +import javax.security.auth.Subject; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedAction; + +/** + * Undertow session listener that performs logout on session invalidation. The {@code AuthenticationManager} logout + * takes care of flushing the principal from cache if a security cache is in use. + * + * + * @author Stuart Douglas + */ +class LogoutSessionListener implements HttpSessionListener { + + private final AuthenticationManager manager; + + LogoutSessionListener(AuthenticationManager manager) { + this.manager = manager; + } + + @Override + public void sessionCreated(HttpSessionEvent se) { + } + @Override + public void sessionDestroyed(HttpSessionEvent se) { + if(WildFlySecurityManager.isChecking()) { + //we don't use doUnchecked here as there is a chance the below method + //can run user supplied code + AccessController.doPrivileged((PrivilegedAction) () -> { + sessionDestroyedImpl(se); + return null; + }); + } else { + sessionDestroyedImpl(se); + } + } + + private void sessionDestroyedImpl(HttpSessionEvent se) { + //we need to get the current account + //there are two options here, we can look for the account in the current request + //or we can look for the account that has been saved in the session + //for maximum compatibility we do both + ServletRequestContext src = ServletRequestContext.current(); + Account requestAccount = null; + if (src != null) { + SecurityContext securityContext = src.getExchange().getSecurityContext(); + if(securityContext != null) { + requestAccount = securityContext.getAuthenticatedAccount(); + if (requestAccount != null) { + clearAccount(requestAccount); + } + } + } + if (se.getSession() instanceof HttpSessionImpl) { + final HttpSessionImpl impl = (HttpSessionImpl) se.getSession(); + Session session = impl.getSession(); + if (session != null) { + AuthenticatedSessionManager.AuthenticatedSession authenticatedSession = (AuthenticatedSessionManager.AuthenticatedSession) session.getAttribute(CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession"); + if(authenticatedSession != null) { + Account sessionAccount = authenticatedSession.getAccount(); + if (sessionAccount != null && !sessionAccount.equals(requestAccount)) { + clearAccount(sessionAccount); + } + } + } + } + } + + private void clearAccount(Account account) { + Principal principal = (account instanceof AccountImpl) ? ((AccountImpl) account).getOriginalPrincipal() : + account.getPrincipal(); + if (principal != null) { + // perform the logout of the principal using the subject currently set in the security context. + Subject subject = SecurityActions.getSubject(); + this.manager.logout(principal, subject); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/RewriteCorrectingHandlerWrappers.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/RewriteCorrectingHandlerWrappers.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/RewriteCorrectingHandlerWrappers.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,76 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletPathMatch; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.util.AttachmentKey; + +/** + * Handler that works around issues with rewrites() and undertow-handlers.conf. + *

+ * Because the rewrite happens after the initial dispatch this handler detects if + * the path has been rewritten and updates the servlet target. + * + * This is a bit of a hack, it needs a lot more thinking about a clean way to handle + * this + */ +class RewriteCorrectingHandlerWrappers { + + private static final AttachmentKey OLD_RELATIVE_PATH = AttachmentKey.create(String.class); + + static class PreWrapper implements HandlerWrapper { + + @Override + public HttpHandler wrap(final HttpHandler handler) { + return new HttpHandler() { + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + exchange.putAttachment(OLD_RELATIVE_PATH, exchange.getRelativePath()); + handler.handleRequest(exchange); + } + }; + } + } + + static class PostWrapper implements HandlerWrapper { + @Override + public HttpHandler wrap(final HttpHandler handler) { + return new HttpHandler() { + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + String old = exchange.getAttachment(OLD_RELATIVE_PATH); + if(!old.equals(exchange.getRelativePath())) { + ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + ServletPathMatch info = src.getDeployment().getServletPaths().getServletHandlerByPath(exchange.getRelativePath()); + src.setCurrentServlet(info.getServletChain()); + src.setServletPathMatch(info); + } + handler.handleRequest(exchange); + } + }; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ScisMetaData.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ScisMetaData.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ScisMetaData.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,65 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContainerInitializer; + +import org.jboss.as.server.deployment.AttachmentKey; + +/** + * @author Remy Maucherat + */ +public class ScisMetaData { + + public static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(ScisMetaData.class); + + /** + * SCIs. + */ + private Set scis; + + /** + * Handles types. + */ + private Map>> handlesTypes; + + public Set getScis() { + return scis; + } + + public void setScis(Set scis) { + this.scis = scis; + } + + public Map>> getHandlesTypes() { + return handlesTypes; + } + + public void setHandlesTypes(Map>> handlesTypes) { + this.handlesTypes = handlesTypes; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityActions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityActions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SecurityActions.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,73 @@ +/* + * 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.extension.undertow.deployment; + +import java.security.PrivilegedAction; + +import org.jboss.security.SecurityContext; +import org.jboss.security.SecurityContextAssociation; +import org.wildfly.security.manager.WildFlySecurityManager; + +import static java.security.AccessController.doPrivileged; + +import javax.security.auth.Subject; + +/** + * Privileged blocks for this package + */ +class SecurityActions { + + static SecurityContext getSecurityContext() { + if (WildFlySecurityManager.isChecking()) { + return doPrivileged(new PrivilegedAction() { + public SecurityContext run() { + return SecurityContextAssociation.getSecurityContext(); + } + }); + } else { + return SecurityContextAssociation.getSecurityContext(); + } + } + + static Subject getSubject() { + if (WildFlySecurityManager.isChecking()) { + return doPrivileged(new PrivilegedAction() { + public Subject run() { + Subject subject = null; + SecurityContext sc = getSecurityContext(); + if (sc != null) { + subject = sc.getUtil().getSubject(); + } + return subject; + } + }); + } else { + Subject subject = null; + SecurityContext sc = getSecurityContext(); + if (sc != null) { + subject = sc.getUtil().getSubject(); + } + return subject; + } + } +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletContainerInitializerDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletContainerInitializerDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletContainerInitializerDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,297 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; + +import javax.servlet.ServletContainerInitializer; +import javax.servlet.annotation.HandlesTypes; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.annotation.CompositeIndex; +import org.jboss.as.server.deployment.module.ModuleDependency; +import org.jboss.as.server.deployment.module.ModuleSpecification; +import org.jboss.as.server.moduleservice.ServiceModuleLoader; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.jandex.FieldInfo; +import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.MethodParameterInfo; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleLoadException; +import org.jboss.vfs.VirtualFile; + +/** + * SCI deployment processor. + * + * @author Emanuel Muckenhuber + * @author Remy Maucherat + * @author Ales Justin + */ +public class ServletContainerInitializerDeploymentProcessor implements DeploymentUnitProcessor { + + /** + * Process SCIs. + */ + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION); + final ServiceModuleLoader loader = deploymentUnit.getAttachment(Attachments.SERVICE_MODULE_LOADER); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + final Module module = deploymentUnit.getAttachment(Attachments.MODULE); + if (module == null) { + throw UndertowLogger.ROOT_LOGGER.failedToResolveModule(deploymentUnit); + } + final ClassLoader classLoader = module.getClassLoader(); + ScisMetaData scisMetaData = deploymentUnit.getAttachment(ScisMetaData.ATTACHMENT_KEY); + if (scisMetaData == null) { + scisMetaData = new ScisMetaData(); + deploymentUnit.putAttachment(ScisMetaData.ATTACHMENT_KEY, scisMetaData); + } + Set scis = scisMetaData.getScis(); + Set> sciClasses = new HashSet<>(); + if (scis == null) { + scis = new LinkedHashSet<>(); + scisMetaData.setScis(scis); + } + Map>> handlesTypes = scisMetaData.getHandlesTypes(); + if (handlesTypes == null) { + handlesTypes = new HashMap>>(); + scisMetaData.setHandlesTypes(handlesTypes); + } + // Find the SCIs from shared modules + for (ModuleDependency dependency : moduleSpecification.getAllDependencies()) { + // Should not include SCI if services is not included + if (!dependency.isImportServices()) { + continue; + } + try { + Module depModule = loader.loadModule(dependency.getIdentifier()); + ServiceLoader serviceLoader = depModule.loadService(ServletContainerInitializer.class); + for (ServletContainerInitializer service : serviceLoader) { + if(sciClasses.add(service.getClass())) { + scis.add(service); + } + } + } catch (ModuleLoadException e) { + if (!dependency.isOptional()) { + throw UndertowLogger.ROOT_LOGGER.errorLoadingSCIFromModule(dependency.getIdentifier().toString(), e); + } + } + } + // Find local ServletContainerInitializer services + List order = warMetaData.getOrder(); + Map localScis = warMetaData.getScis(); + if (order != null && localScis != null) { + for (String jar : order) { + VirtualFile sci = localScis.get(jar); + if (sci != null) { + scis.addAll(loadSci(classLoader, sci, jar, true, sciClasses)); + } + } + } + + //SCI's deployed in the war itself + if(localScis != null) { + VirtualFile warDeployedScis = localScis.get("classes"); + if(warDeployedScis != null) { + scis.addAll(loadSci(classLoader, warDeployedScis, deploymentUnit.getName(), true, sciClasses)); + } + } + + // Process HandlesTypes for ServletContainerInitializer + Map, Set> typesMap = new HashMap, Set>(); + for (ServletContainerInitializer service : scis) { + if (service.getClass().isAnnotationPresent(HandlesTypes.class)) { + HandlesTypes handlesTypesAnnotation = service.getClass().getAnnotation(HandlesTypes.class); + Class[] typesArray = handlesTypesAnnotation.value(); + if (typesArray != null) { + for (Class type : typesArray) { + Set servicesSet = typesMap.get(type); + if (servicesSet == null) { + servicesSet = new HashSet(); + typesMap.put(type, servicesSet); + } + servicesSet.add(service); + handlesTypes.put(service, new HashSet>()); + } + } + } + } + Class[] typesArray = typesMap.keySet().toArray(new Class[0]); + + final CompositeIndex index = deploymentUnit.getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX); + if (index == null) { + throw UndertowLogger.ROOT_LOGGER.unableToResolveAnnotationIndex(deploymentUnit); + } + final CompositeIndex parent; + if(deploymentUnit.getParent() != null) { + parent = deploymentUnit.getParent().getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX); + } else { + parent = null; + } + //WFLY-4205, look in the parent as well as the war + CompositeIndex parentIndex = deploymentUnit.getParent() == null ? null : deploymentUnit.getParent().getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX); + + // Find classes which extend, implement, or are annotated by HandlesTypes + for (Class type : typesArray) { + DotName className = DotName.createSimple(type.getName()); + Set classInfos = new HashSet<>(); + classInfos.addAll(processHandlesType(className, type, index, parent)); + if(parentIndex != null) { + classInfos.addAll(processHandlesType(className, type, parentIndex, parent)); + } + Set> classes = loadClassInfoSet(classInfos, classLoader); + Set sciSet = typesMap.get(type); + for (ServletContainerInitializer sci : sciSet) { + handlesTypes.get(sci).addAll(classes); + } + } + } + + public void undeploy(final DeploymentUnit context) { + context.removeAttachment(ScisMetaData.ATTACHMENT_KEY); + } + + private List loadSci(ClassLoader classLoader, VirtualFile sci, String jar, boolean error, Set> sciClasses) throws DeploymentUnitProcessingException { + final List scis = new ArrayList(); + InputStream is = null; + try { + // Get the ServletContainerInitializer class name + is = sci.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String servletContainerInitializerClassName = reader.readLine(); + while (servletContainerInitializerClassName != null) { + try { + int pos = servletContainerInitializerClassName.indexOf('#'); + if (pos >= 0) { + servletContainerInitializerClassName = servletContainerInitializerClassName.substring(0, pos); + } + servletContainerInitializerClassName = servletContainerInitializerClassName.trim(); + if (!servletContainerInitializerClassName.isEmpty()) { + // Instantiate the ServletContainerInitializer + ServletContainerInitializer service = (ServletContainerInitializer) classLoader.loadClass(servletContainerInitializerClassName).newInstance(); + if (service != null) { + if(sciClasses.add(service.getClass())) { + scis.add(service); + } + } + } + servletContainerInitializerClassName = reader.readLine(); + } catch (Exception e) { + if (error) { + throw UndertowLogger.ROOT_LOGGER.errorProcessingSCI(jar, e); + } else { + UndertowLogger.ROOT_LOGGER.skippedSCI(jar, e); + } + } + } + } catch (Exception e) { + if (error) { + throw UndertowLogger.ROOT_LOGGER.errorProcessingSCI(jar, e); + } else { + UndertowLogger.ROOT_LOGGER.skippedSCI(jar, e); + } + } finally { + try { + if (is != null) + is.close(); + } catch (IOException e) { + // Ignore + } + } + return scis; + } + + private Set processHandlesType(DotName typeName, Class type, CompositeIndex index, CompositeIndex parent) throws DeploymentUnitProcessingException { + Set classes = new HashSet(); + if (type.isAnnotation()) { + List instances = index.getAnnotations(typeName); + for (AnnotationInstance instance : instances) { + AnnotationTarget annotationTarget = instance.target(); + if (annotationTarget instanceof ClassInfo) { + classes.add((ClassInfo) annotationTarget); + } else if (annotationTarget instanceof FieldInfo) { + classes.add(((FieldInfo) annotationTarget).declaringClass()); + } else if (annotationTarget instanceof MethodInfo) { + classes.add(((MethodInfo) annotationTarget).declaringClass()); + } else if (annotationTarget instanceof MethodParameterInfo) { + classes.add(((MethodParameterInfo) annotationTarget).method().declaringClass()); + } + } + } else { + classes.addAll(index.getAllKnownSubclasses(typeName)); + classes.addAll(index.getAllKnownImplementors(typeName)); + if(parent != null) { + Set parentImplementors = new HashSet<>(); + parentImplementors.addAll(parent.getAllKnownImplementors(typeName)); + parentImplementors.addAll(parent.getAllKnownSubclasses(typeName)); + for(ClassInfo pc: parentImplementors) { + classes.addAll(index.getAllKnownSubclasses(pc.name())); + classes.addAll(index.getAllKnownImplementors(pc.name())); + } + } + + } + return classes; + } + + private Set> loadClassInfoSet(Set classInfos, ClassLoader classLoader) throws DeploymentUnitProcessingException { + Set> classes = new HashSet>(); + for (ClassInfo classInfo : classInfos) { + Class type; + try { + type = classLoader.loadClass(classInfo.name().toString()); + classes.add(type); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.cannotLoadDesignatedHandleTypes(classInfo, e); + } + } + return classes; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResource.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResource.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResource.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,148 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.io.IoCallback; +import io.undertow.io.Sender; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.resource.RangeAwareResource; +import io.undertow.server.handlers.resource.Resource; +import io.undertow.util.ETag; +import io.undertow.util.MimeMappings; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; +import java.util.Date; +import java.util.List; + +/** + * + * Resource implementation that wraps an underlying resource, and overrides the list() method to take overlays into account. + * + * @author Stuart Douglas + */ +public class ServletResource implements Resource, RangeAwareResource { + + private final ServletResourceManager resourceManager; + private final Resource underlying; + + public ServletResource(ServletResourceManager resourceManager, Resource underlying) { + this.resourceManager = resourceManager; + this.underlying = underlying; + } + + @Override + public String getPath() { + return underlying.getPath(); + } + + @Override + public Date getLastModified() { + return underlying.getLastModified(); + } + + @Override + public String getLastModifiedString() { + return underlying.getLastModifiedString(); + } + + @Override + public ETag getETag() { + return underlying.getETag(); + } + + @Override + public String getName() { + return underlying.getName(); + } + + @Override + public boolean isDirectory() { + return underlying.isDirectory(); + } + + @Override + public List list() { + return resourceManager.list(getPath()); + } + + @Override + public String getContentType(MimeMappings mimeMappings) { + return underlying.getContentType(mimeMappings); + } + + @Override + public void serve(Sender sender, HttpServerExchange exchange, IoCallback completionCallback) { + underlying.serve(sender, exchange, completionCallback); + } + + @Override + public Long getContentLength() { + return underlying.getContentLength(); + } + + @Override + public String getCacheKey() { + return underlying.getCacheKey(); + } + + @Override + public File getFile() { + return underlying.getFile(); + } + + @Override + public File getResourceManagerRoot() { + return underlying.getResourceManagerRoot(); + } + + @Override + public URL getUrl() { + return underlying.getUrl(); + } + + + public Path getResourceManagerRootPath() { + return getResourceManagerRoot().toPath(); + } + + public Path getFilePath() { + if(getFile() == null) { + return null; + } + return getFile().toPath(); + } + + @Override + public void serveRange(Sender sender, HttpServerExchange exchange, long start, long end, IoCallback completionCallback) { + ((RangeAwareResource) underlying).serveRange(sender, exchange, start, end, completionCallback); + } + + @Override + public boolean isRangeSupported() { + if(underlying instanceof RangeAwareResource) { + return ((RangeAwareResource) underlying).isRangeSupported(); + } + return false; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResourceManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResourceManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/ServletResourceManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,179 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.jboss.vfs.VirtualFile; +import io.undertow.server.handlers.resource.PathResourceManager; +import io.undertow.server.handlers.resource.Resource; +import io.undertow.server.handlers.resource.ResourceChangeListener; +import io.undertow.server.handlers.resource.ResourceManager; +import io.undertow.util.CanonicalPathUtils; + +/** + * Resource manager that deals with overlays + * + * @author Stuart Douglas + */ +public class ServletResourceManager implements ResourceManager { + + public static final int TRANSFER_MIN_SIZE = 1024 * 1024; + private final PathResourceManager deploymentResourceManager; + private final Collection overlays; + private final ResourceManager[] externalOverlays; + private final boolean explodedDeployment; + + public ServletResourceManager(final VirtualFile resourcesRoot, final Collection overlays, + boolean explodedDeployment, boolean followSymlink, boolean disableFileWatchService, + List externalOverlays) throws IOException { + this.explodedDeployment = explodedDeployment; + Path physicalFile = resourcesRoot.getPhysicalFile().toPath().toRealPath(); + deploymentResourceManager = new PathResourceManager(physicalFile, TRANSFER_MIN_SIZE, true, + followSymlink, !disableFileWatchService); + this.overlays = overlays; + if(externalOverlays == null) { + this.externalOverlays = new ResourceManager[0]; + } else { + this.externalOverlays = new ResourceManager[externalOverlays.size()]; + for (int i = 0; i < externalOverlays.size(); ++i) { + String path = externalOverlays.get(i); + PathResourceManager pr = new PathResourceManager(Paths.get(path).toRealPath(), TRANSFER_MIN_SIZE, + true, followSymlink, !disableFileWatchService); + this.externalOverlays[i] = pr; + } + } + } + + @Override + public Resource getResource(final String path) throws IOException { + Resource res = deploymentResourceManager.getResource(path); + if (res != null) { + return new ServletResource(this, res); + } + String p = path; + if (p.startsWith("/")) { + p = p.substring(1); + } + if (overlays != null) { + String canonical = CanonicalPathUtils.canonicalize(p); //we don't need to do this for other resources, as the underlying RM will handle it + for (VirtualFile overlay : overlays) { + VirtualFile child = overlay.getChild(canonical); + if (child.exists()) { + try { + //we make sure the child is actually a child of the parent + //CanonicalPathUtils should make sure this cannot happen + //but just to be safe we do it anyway + child.getPathNameRelativeTo(overlay); + return new ServletResource(this, new VirtualFileResource(overlay.getPhysicalFile(), child, canonical)); + } catch (IllegalArgumentException ignore) { + + } + } + } + } + for (int i = 0; i < externalOverlays.length; ++i) { + ResourceManager manager = externalOverlays[i]; + res = manager.getResource(path); + if(res != null) { + return res; + } + } + return null; + } + + @Override + public boolean isResourceChangeListenerSupported() { + return true; + } + + @Override + public void registerResourceChangeListener(ResourceChangeListener listener) { + if(explodedDeployment && deploymentResourceManager.isResourceChangeListenerSupported()) { + deploymentResourceManager.registerResourceChangeListener(listener); + } + for(ResourceManager external : externalOverlays) { + if(external.isResourceChangeListenerSupported()) { + external.registerResourceChangeListener(listener); + } + } + } + + @Override + public void removeResourceChangeListener(ResourceChangeListener listener) { + if(deploymentResourceManager.isResourceChangeListenerSupported()) { + deploymentResourceManager.removeResourceChangeListener(listener); + } + for(ResourceManager external : externalOverlays) { + if(external.isResourceChangeListenerSupported()) { + external.removeResourceChangeListener(listener); + } + } + } + + @Override + public void close() throws IOException { + deploymentResourceManager.close(); + } + + /** + * Lists all children of a particular path, taking overlays into account + * + * @param path The path + * @return The list of children + */ + public List list(String path) { + try { + final List ret = new ArrayList<>(); + + Resource res = deploymentResourceManager.getResource(path); + if (res != null) { + for (Resource child : res.list()) { + ret.add(new ServletResource(this, child)); + } + } + String p = path; + if (p.startsWith("/")) { + p = p.substring(1); + } + if (overlays != null) { + for (VirtualFile overlay : overlays) { + VirtualFile child = overlay.getChild(p); + if (child.exists()) { + VirtualFileResource vfsResource = new VirtualFileResource(overlay.getPhysicalFile(), child, path); + for (Resource c : vfsResource.list()) { + ret.add(new ServletResource(this, c)); + } + } + } + } + return ret; + } catch (IOException e) { + throw new RuntimeException(e); //this method really should have thrown IOException + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SharedSessionManagerDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SharedSessionManagerDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/SharedSessionManagerDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,101 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.clustering.controller.SimpleCapabilityServiceConfigurator; +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.modules.Module; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.extension.undertow.session.DistributableSessionIdentifierCodecServiceConfiguratorProvider; +import org.wildfly.extension.undertow.session.DistributableSessionManagerFactoryServiceConfiguratorProvider; +import org.wildfly.extension.undertow.session.SharedSessionManagerConfig; +import org.wildfly.extension.undertow.session.SimpleDistributableSessionManagerConfiguration; +import org.wildfly.extension.undertow.session.SimpleSessionIdentifierCodecServiceConfigurator; + +import io.undertow.server.session.InMemorySessionManager; + +/** + * @author Stuart Douglas + */ +public class SharedSessionManagerDeploymentProcessor implements DeploymentUnitProcessor { + private final String defaultServerName; + + public SharedSessionManagerDeploymentProcessor(String defaultServerName) { + this.defaultServerName = defaultServerName; + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + SharedSessionManagerConfig sharedConfig = deploymentUnit.getAttachment(UndertowAttachments.SHARED_SESSION_MANAGER_CONFIG); + if (sharedConfig == null) return; + + String deploymentName = (deploymentUnit.getParent() == null) ? deploymentUnit.getName() : String.join(".", deploymentUnit.getParent().getName(), deploymentUnit.getName()); + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + String serverName = Optional.ofNullable(warMetaData).map(metaData -> metaData.getMergedJBossWebMetaData().getServerInstanceName()) + .orElse(Optional.ofNullable(DefaultDeploymentMappingProvider.instance().getMapping(deploymentName)).map(Map.Entry::getKey).orElse(this.defaultServerName)); + + CapabilityServiceSupport support = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); + Module module = deploymentUnit.getAttachment(Attachments.MODULE); + ServiceTarget target = phaseContext.getServiceTarget(); + ServiceName deploymentServiceName = deploymentUnit.getServiceName(); + + ServiceName managerServiceName = deploymentServiceName.append(SharedSessionManagerConfig.SHARED_SESSION_MANAGER_SERVICE_NAME); + CapabilityServiceConfigurator factoryConfigurator = DistributableSessionManagerFactoryServiceConfiguratorProvider.INSTANCE + .map(provider -> provider.getServiceConfigurator(managerServiceName, new SimpleDistributableSessionManagerConfiguration(sharedConfig, serverName, deploymentUnit.getName(), module))) + .orElseGet(() -> { + InMemorySessionManager manager = new InMemorySessionManager(deploymentUnit.getName(), sharedConfig.getMaxActiveSessions()); + if (sharedConfig.getSessionConfig() != null) { + if (sharedConfig.getSessionConfig().getSessionTimeoutSet()) { + manager.setDefaultSessionTimeout(sharedConfig.getSessionConfig().getSessionTimeout()); + } + } + return new SimpleCapabilityServiceConfigurator<>(managerServiceName, new ImmediateSessionManagerFactory(manager)); + }); + + ServiceName codecServiceName = deploymentServiceName.append(SharedSessionManagerConfig.SHARED_SESSION_IDENTIFIER_CODEC_SERVICE_NAME); + CapabilityServiceConfigurator codecConfigurator = DistributableSessionIdentifierCodecServiceConfiguratorProvider.INSTANCE + .map(provider -> provider.getDeploymentServiceConfigurator(codecServiceName, serverName, deploymentUnit.getName())) + .orElse(new SimpleSessionIdentifierCodecServiceConfigurator(codecServiceName, serverName)); + + for (CapabilityServiceConfigurator configurator : Arrays.asList(factoryConfigurator, codecConfigurator)) { + configurator.configure(support).build(target).install(); + } + } + + @Override + public void undeploy(DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TaglibDescriptorImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TaglibDescriptorImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TaglibDescriptorImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,49 @@ +/* + * 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.extension.undertow.deployment; + +import org.apache.jasper.deploy.TagLibraryInfo; + +import javax.servlet.descriptor.TaglibDescriptor; + +/** + * @author Stuart Douglas + */ +public class TaglibDescriptorImpl implements TaglibDescriptor { + + private final TagLibraryInfo tagLibraryInfo; + + public TaglibDescriptorImpl(TagLibraryInfo tagLibraryInfo) { + this.tagLibraryInfo = tagLibraryInfo; + } + + @Override + public String getTaglibURI() { + return tagLibraryInfo.getUri(); + } + + @Override + public String getTaglibLocation() { + return tagLibraryInfo.getLocation(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldParsingDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldParsingDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldParsingDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,246 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.parser.jsp.TldMetaDataParser; +import org.jboss.metadata.parser.util.NoopXMLResolver; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.JspConfigMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.TaglibMetaData; +import org.jboss.metadata.web.spec.TldMetaData; +import org.jboss.vfs.VirtualFile; + +/** + * @author Remy Maucherat + */ +public class TldParsingDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String TLD = ".tld"; + private static final String META_INF = "META-INF"; + private static final String WEB_INF = "WEB-INF"; + private static final String CLASSES = "classes"; + private static final String LIB = "lib"; + private static final String IMPLICIT_TLD = "implicit.tld"; + private static final String RESOURCES = "resources"; + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetaData == null || warMetaData.getMergedJBossWebMetaData() == null) { + return; + } + + + TldsMetaData tldsMetaData = deploymentUnit.getAttachment(TldsMetaData.ATTACHMENT_KEY); + if (tldsMetaData == null) { + tldsMetaData = new TldsMetaData(); + deploymentUnit.putAttachment(TldsMetaData.ATTACHMENT_KEY, tldsMetaData); + } + Map tlds = new HashMap(); + tldsMetaData.setTlds(tlds); + final List uniqueTlds = new ArrayList<>(); + + final VirtualFile deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT).getRoot(); + final List testRoots = new ArrayList(); + testRoots.add(deploymentRoot); + testRoots.add(deploymentRoot.getChild(WEB_INF)); + testRoots.add(deploymentRoot.getChild(META_INF)); + for (ResourceRoot root : deploymentUnit.getAttachmentList(Attachments.RESOURCE_ROOTS)) { + testRoots.add(root.getRoot()); + testRoots.add(root.getRoot().getChild(META_INF)); + testRoots.add(root.getRoot().getChild(META_INF).getChild(RESOURCES)); + } + + JspConfigMetaData merged = warMetaData.getMergedJBossWebMetaData().getJspConfig(); + if (merged != null && merged.getTaglibs() != null) { + for (final TaglibMetaData tld : merged.getTaglibs()) { + boolean found = false; + for (final VirtualFile root : testRoots) { + VirtualFile child = root.getChild(tld.getTaglibLocation()); + if (child.exists()) { + String pathNameRelativeToRoot; + try { + pathNameRelativeToRoot = child.getPathNameRelativeTo(deploymentRoot); + } catch (IllegalArgumentException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.tldFileNotContainedInRoot(child.getPathName(), + deploymentRoot.getPathName()), e); + } + final TldMetaData value = parseTLD(child); + value.setUri(tld.getTaglibUri()); + uniqueTlds.add(value); + String key = "/" + pathNameRelativeToRoot; + if (!tlds.containsKey(key)) { + tlds.put(key, value); + } + if (!tlds.containsKey(tld.getTaglibUri())) { + tlds.put(tld.getTaglibUri(), value); + } + found = true; + break; + } + } + if (!found) { + UndertowLogger.ROOT_LOGGER.tldNotFound(tld.getTaglibLocation()); + } + + } + } + + // TLDs are located in WEB-INF or any subdir (except the top level "classes" and "lib") + // and in JARs from WEB-INF/lib, in META-INF or any subdir + List resourceRoots = deploymentUnit.getAttachmentList(Attachments.RESOURCE_ROOTS); + for (ResourceRoot resourceRoot : resourceRoots) { + if (resourceRoot.getRoot().getName().toLowerCase(Locale.ENGLISH).endsWith(".jar")) { + VirtualFile webFragment = resourceRoot.getRoot().getChild(META_INF); + if (webFragment.exists() && webFragment.isDirectory()) { + processTlds(deploymentRoot, webFragment.getChildren(), tlds, uniqueTlds); + } + } + } + VirtualFile webInf = deploymentRoot.getChild(WEB_INF); + if (webInf.exists() && webInf.isDirectory()) { + for (VirtualFile file : webInf.getChildren()) { + if (file.isFile() && file.getName().toLowerCase(Locale.ENGLISH).endsWith(TLD)) { + String pathNameRelativeToRoot; + try { + pathNameRelativeToRoot = file.getPathNameRelativeTo(deploymentRoot); + } catch (IllegalArgumentException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.tldFileNotContainedInRoot(file.getPathName(), + deploymentRoot.getPathName()), e); + } + + final TldMetaData value = parseTLD(file); + uniqueTlds.add(value); + String key = "/" + pathNameRelativeToRoot; + if (!tlds.containsKey(key)) { + tlds.put(key, value); + } + } else if (file.isDirectory() && !CLASSES.equals(file.getName()) && !LIB.equals(file.getName())) { + processTlds(deploymentRoot, file.getChildren(), tlds, uniqueTlds); + } + } + } + + JBossWebMetaData mergedMd = warMetaData.getMergedJBossWebMetaData(); + if (mergedMd.getListeners() == null) { + mergedMd.setListeners(new ArrayList()); + } + + final ArrayList allTlds = new ArrayList<>(uniqueTlds); + allTlds.addAll(tldsMetaData.getSharedTlds(deploymentUnit)); + + + for (final TldMetaData tld : allTlds) { + if (tld.getListeners() != null) { + for (ListenerMetaData l : tld.getListeners()) { + mergedMd.getListeners().add(l); + } + } + } + } + + + @Override + public void undeploy(final DeploymentUnit context) { + } + + private void processTlds(VirtualFile root, List files, Map tlds, final List uniqueTlds) + throws DeploymentUnitProcessingException { + for (VirtualFile file : files) { + if (file.isFile() && file.getName().toLowerCase(Locale.ENGLISH).endsWith(TLD)) { + String pathNameRelativeToRoot; + try { + pathNameRelativeToRoot = file.getPathNameRelativeTo(root); + } catch (IllegalArgumentException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.tldFileNotContainedInRoot(file.getPathName(), + root.getPathName()), e); + } + final TldMetaData value = parseTLD(file); + String key = "/" + pathNameRelativeToRoot; + uniqueTlds.add(value); + if (!tlds.containsKey(key)) { + tlds.put(key, value); + } + } else if (file.isDirectory()) { + processTlds(root, file.getChildren(), tlds, uniqueTlds); + } + } + } + + private TldMetaData parseTLD(VirtualFile tld) + throws DeploymentUnitProcessingException { + if (IMPLICIT_TLD.equals(tld.getName())) { + // Implicit TLDs are different from regular TLDs + return new TldMetaData(); + } + InputStream is = null; + try { + is = tld.openStream(); + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setXMLResolver(NoopXMLResolver.create()); + XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is); + return TldMetaDataParser.parse(xmlReader); + } catch (XMLStreamException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(tld.toString(), e.getLocation().getLineNumber(), + e.getLocation().getColumnNumber()), e); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(tld.toString()), e); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + // Ignore + } + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldsMetaData.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldsMetaData.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/TldsMetaData.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,66 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.List; +import java.util.Map; + +import org.jboss.as.server.deployment.AttachmentKey; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.web.common.SharedTldsMetaDataBuilder; +import org.jboss.metadata.web.spec.TldMetaData; + +/** + * @author Remy Maucherat + */ +public class TldsMetaData { + + public static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(TldsMetaData.class); + + /** + * Shared TLDs. + */ + private SharedTldsMetaDataBuilder sharedTlds; + + /** + * Webapp TLDs. + */ + private Map tlds; + + public List getSharedTlds(DeploymentUnit deploymentUnit) { + return sharedTlds.getSharedTlds(deploymentUnit); + } + + public void setSharedTlds(SharedTldsMetaDataBuilder sharedTlds) { + this.sharedTlds = sharedTlds; + } + + public Map getTlds() { + return tlds; + } + + public void setTlds(Map tlds) { + this.tlds = tlds; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowAttachments.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowAttachments.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowAttachments.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,71 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.File; + +import org.jboss.as.server.deployment.AttachmentKey; +import org.jboss.as.server.deployment.AttachmentList; +import org.wildfly.extension.undertow.ServletContainerService; +import org.wildfly.extension.undertow.session.SharedSessionManagerConfig; + +import io.undertow.predicate.Predicate; +import io.undertow.server.HandlerWrapper; +import io.undertow.servlet.ServletExtension; +import io.undertow.servlet.api.ThreadSetupHandler; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; + +/** + * Class defining {@link AttachmentKey}s for Undertow-specific attachments. + * + * @author Radoslav Husar + * @version Oct 2013 + * @since 8.0 + */ +public final class UndertowAttachments { + + public static final AttachmentKey> UNDERTOW_INITIAL_HANDLER_CHAIN_WRAPPERS = AttachmentKey.createList(HandlerWrapper.class); + + public static final AttachmentKey> UNDERTOW_INNER_HANDLER_CHAIN_WRAPPERS = AttachmentKey.createList(HandlerWrapper.class); + + public static final AttachmentKey> UNDERTOW_OUTER_HANDLER_CHAIN_WRAPPERS = AttachmentKey.createList(HandlerWrapper.class); + + public static final AttachmentKey> UNDERTOW_THREAD_SETUP_ACTIONS = AttachmentKey.createList(ThreadSetupHandler.class); + + public static final AttachmentKey> UNDERTOW_SERVLET_EXTENSIONS = AttachmentKey.createList(ServletExtension.class); + + public static final AttachmentKey SHARED_SESSION_MANAGER_CONFIG = AttachmentKey.create(SharedSessionManagerConfig.class); + + public static final AttachmentKey WEB_SOCKET_DEPLOYMENT_INFO = AttachmentKey.create(WebSocketDeploymentInfo.class); + + public static final AttachmentKey> EXTERNAL_RESOURCES = AttachmentKey.createList(File.class); + + public static final AttachmentKey SERVLET_CONTAINER_SERVICE = AttachmentKey.create(ServletContainerService.class); + + public static final AttachmentKey> ALLOW_REQUEST_WHEN_SUSPENDED = AttachmentKey.createList(Predicate.class); + + public static final AttachmentKey DEFAULT_SECURITY_DOMAIN = AttachmentKey.create(String.class); + + private UndertowAttachments() { + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDependencyProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDependencyProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDependencyProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,95 @@ +/* + * 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.extension.undertow.deployment; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ModuleDependency; +import org.jboss.as.server.deployment.module.ModuleSpecification; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleIdentifier; +import org.jboss.modules.ModuleLoader; + +/** + * Module dependencies processor. + * + * @author Emanuel Muckenhuber + * @author Stan Silvert + */ +public class UndertowDependencyProcessor implements DeploymentUnitProcessor { + + private static final ModuleIdentifier JSTL = ModuleIdentifier.create("javax.servlet.jstl.api"); + + private static final ModuleIdentifier UNDERTOW_CORE = ModuleIdentifier.create("io.undertow.core"); + private static final ModuleIdentifier UNDERTOW_SERVLET = ModuleIdentifier.create("io.undertow.servlet"); + private static final ModuleIdentifier UNDERTOW_JSP = ModuleIdentifier.create("io.undertow.jsp"); + private static final ModuleIdentifier UNDERTOW_WEBSOCKET = ModuleIdentifier.create("io.undertow.websocket"); + private static final ModuleIdentifier UNDERTOW_JS = ModuleIdentifier.create("io.undertow.js"); + private static final ModuleIdentifier CLUSTERING_API = ModuleIdentifier.create("org.wildfly.clustering.web.api"); + + private static final ModuleIdentifier SERVLET_API = ModuleIdentifier.create("javax.servlet.api"); + private static final ModuleIdentifier JSP_API = ModuleIdentifier.create("javax.servlet.jsp.api"); + private static final ModuleIdentifier WEBSOCKET_API = ModuleIdentifier.create("javax.websocket.api"); + + static { + Module module = Module.forClass(UndertowDependencyProcessor.class); + if (module != null) { + //When testing the subsystems we are running in a non-modular environment + //so module will be null. Having a null entry kills ModularURLStreamHandlerFactory + Module.registerURLStreamHandlerFactoryModule(module); + } + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + + final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION); + final ModuleLoader moduleLoader = Module.getBootModuleLoader(); + + //add the api classes for every deployment + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, SERVLET_API, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, JSP_API, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, WEBSOCKET_API, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, JSTL, false, false, false, false)); + + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, UNDERTOW_CORE, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, UNDERTOW_SERVLET, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, UNDERTOW_JSP, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, UNDERTOW_WEBSOCKET, false, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, UNDERTOW_JS, true, false, true, false)); + moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, CLUSTERING_API, true, false, false, false)); + } + + @Override + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,1509 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.Handlers; +import io.undertow.jsp.JspFileHandler; +import io.undertow.jsp.JspServletBuilder; +import io.undertow.predicate.Predicate; +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.AuthenticationMechanismFactory; +import io.undertow.security.api.AuthenticationMode; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.builder.PredicatedHandler; +import io.undertow.server.handlers.resource.CachingResourceManager; +import io.undertow.server.handlers.resource.FileResourceManager; +import io.undertow.server.handlers.resource.ResourceManager; +import io.undertow.server.session.SecureRandomSessionIdGenerator; +import io.undertow.servlet.ServletExtension; +import io.undertow.servlet.Servlets; +import io.undertow.servlet.api.AuthMethodConfig; +import io.undertow.servlet.api.ClassIntrospecter; +import io.undertow.servlet.api.ConfidentialPortManager; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.ErrorPage; +import io.undertow.servlet.api.FilterInfo; +import io.undertow.servlet.api.HttpMethodSecurityInfo; +import io.undertow.servlet.api.InstanceFactory; +import io.undertow.servlet.api.InstanceHandle; +import io.undertow.servlet.api.ListenerInfo; +import io.undertow.servlet.api.LoginConfig; +import io.undertow.servlet.api.MimeMapping; +import io.undertow.servlet.api.SecurityConstraint; +import io.undertow.servlet.api.ServletContainerInitializerInfo; +import io.undertow.servlet.api.ServletInfo; +import io.undertow.servlet.api.ServletSecurityInfo; +import io.undertow.servlet.api.ServletSessionConfig; +import io.undertow.servlet.api.SessionManagerFactory; +import io.undertow.servlet.api.ThreadSetupHandler; +import io.undertow.servlet.api.WebResourceCollection; +import io.undertow.servlet.handlers.DefaultServlet; +import io.undertow.servlet.handlers.ServletPathMatches; +import io.undertow.servlet.util.ImmediateInstanceFactory; +import io.undertow.websockets.extensions.PerMessageDeflateHandshake; +import io.undertow.websockets.jsr.ServerWebSocketContainer; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; + +import org.apache.jasper.deploy.JspPropertyGroup; +import org.apache.jasper.deploy.TagLibraryInfo; +import org.apache.jasper.servlet.JspServlet; +import org.jboss.as.ee.component.ComponentRegistry; +import org.jboss.as.naming.ManagedReference; +import org.jboss.as.naming.ManagedReferenceFactory; +import org.jboss.as.security.plugins.SecurityDomainContext; +import org.jboss.as.server.deployment.SetupAction; +import org.jboss.as.server.suspend.ServerActivity; +import org.jboss.as.server.suspend.ServerActivityCallback; +import org.jboss.as.server.suspend.SuspendController; +import org.jboss.as.web.common.ExpressionFactoryWrapper; +import org.jboss.as.web.common.ServletContextAttribute; +import org.jboss.as.web.common.WebInjectionContainer; +import org.jboss.as.web.session.SessionIdentifierCodec; +import org.jboss.metadata.javaee.jboss.RunAsIdentityMetaData; +import org.jboss.metadata.javaee.spec.ParamValueMetaData; +import org.jboss.metadata.javaee.spec.SecurityRoleRefMetaData; +import org.jboss.metadata.web.jboss.JBossServletMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.CookieConfigMetaData; +import org.jboss.metadata.web.spec.DispatcherType; +import org.jboss.metadata.web.spec.EmptyRoleSemanticType; +import org.jboss.metadata.web.spec.ErrorPageMetaData; +import org.jboss.metadata.web.spec.FilterMappingMetaData; +import org.jboss.metadata.web.spec.FilterMetaData; +import org.jboss.metadata.web.spec.HttpMethodConstraintMetaData; +import org.jboss.metadata.web.spec.JspConfigMetaData; +import org.jboss.metadata.web.spec.JspPropertyGroupMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.LocaleEncodingMetaData; +import org.jboss.metadata.web.spec.LoginConfigMetaData; +import org.jboss.metadata.web.spec.MimeMappingMetaData; +import org.jboss.metadata.web.spec.MultipartConfigMetaData; +import org.jboss.metadata.web.spec.SecurityConstraintMetaData; +import org.jboss.metadata.web.spec.ServletMappingMetaData; +import org.jboss.metadata.web.spec.SessionConfigMetaData; +import org.jboss.metadata.web.spec.SessionTrackingModeType; +import org.jboss.metadata.web.spec.TransportGuaranteeType; +import org.jboss.metadata.web.spec.WebResourceCollectionMetaData; +import org.jboss.modules.Module; +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.jboss.security.audit.AuditManager; +import org.jboss.security.auth.login.JASPIAuthenticationInfo; +import org.jboss.security.authorization.config.AuthorizationModuleEntry; +import org.jboss.security.authorization.modules.JACCAuthorizationModule; +import org.jboss.security.config.ApplicationPolicy; +import org.jboss.security.config.AuthorizationInfo; +import org.jboss.security.config.SecurityConfiguration; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.requestcontroller.ControlPoint; +import org.wildfly.extension.undertow.Host; +import org.wildfly.extension.undertow.JSPConfig; +import org.wildfly.extension.undertow.ServletContainerService; +import org.wildfly.extension.undertow.SessionCookieConfig; +import org.wildfly.extension.undertow.SingleSignOnService; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.UndertowService; +import org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.Registration; +import org.wildfly.extension.undertow.security.AuditNotificationReceiver; +import org.wildfly.extension.undertow.security.JAASIdentityManagerImpl; +import org.wildfly.extension.undertow.security.JbossAuthorizationManager; +import org.wildfly.extension.undertow.security.LogoutNotificationReceiver; +import org.wildfly.extension.undertow.security.RunAsLifecycleInterceptor; +import org.wildfly.extension.undertow.security.SecurityContextAssociationHandler; +import org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction; +import org.wildfly.extension.undertow.security.jacc.JACCAuthorizationManager; +import org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler; +import org.wildfly.extension.undertow.security.jaspi.JASPICAuthenticationMechanism; +import org.wildfly.extension.undertow.security.jaspi.JASPICSecureResponseHandler; +import org.wildfly.extension.undertow.security.jaspi.JASPICSecurityContextFactory; +import org.wildfly.extension.undertow.session.CodecSessionConfigWrapper; +import org.wildfly.extension.undertow.session.SharedSessionManagerConfig; +import org.xnio.IoUtils; + +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.SessionTrackingMode; +import javax.servlet.http.HttpServletRequest; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.jboss.security.AuthenticationManager; + +import static io.undertow.servlet.api.SecurityInfo.EmptyRoleSemantic.AUTHENTICATE; +import static io.undertow.servlet.api.SecurityInfo.EmptyRoleSemantic.DENY; +import static io.undertow.servlet.api.SecurityInfo.EmptyRoleSemantic.PERMIT; + +import org.jboss.as.server.ServerEnvironment; +import org.jboss.security.authentication.JBossCachedAuthenticationManager; + +/** + * Service that builds up the undertow metadata. + * + * @author Stuart Douglas + */ +public class UndertowDeploymentInfoService implements Service { + + public static final ServiceName SERVICE_NAME = ServiceName.of("UndertowDeploymentInfoService"); + + public static final String DEFAULT_SERVLET_NAME = "default"; + public static final String UNDERTOW = "undertow"; + + private DeploymentInfo deploymentInfo; + private Registration registration; + + private final JBossWebMetaData mergedMetaData; + private final String deploymentName; + private final Module module; + private final HashMap tldInfo; + private final ScisMetaData scisMetaData; + private final VirtualFile deploymentRoot; + private final String jaccContextId; + private final String securityDomain; + private final List attributes; + private final String contextPath; + private final List setupActions; + private final Set overlays; + private final List expressionFactoryWrappers; + private final List predicatedHandlers; + private final List initialHandlerChainWrappers; + private final List innerHandlerChainWrappers; + private final List outerHandlerChainWrappers; + private final List threadSetupActions; + private final List servletExtensions; + private final SharedSessionManagerConfig sharedSessionManagerConfig; + private final boolean explodedDeployment; + + private final InjectedValue undertowService = new InjectedValue<>(); + private final InjectedValue sessionManagerFactory = new InjectedValue<>(); + private final InjectedValue sessionIdentifierCodec = new InjectedValue<>(); + private final InjectedValue securityDomainContextValue = new InjectedValue(); + private final InjectedValue container = new InjectedValue<>(); + private final InjectedValue componentRegistryInjectedValue = new InjectedValue<>(); + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue controlPointInjectedValue = new InjectedValue<>(); + private final InjectedValue suspendControllerInjectedValue = new InjectedValue<>(); + private final InjectedValue serverEnvironmentInjectedValue = new InjectedValue<>(); + private final Map> executorsByName = new HashMap>(); + private final WebSocketDeploymentInfo webSocketDeploymentInfo; + private final File tempDir; + private final List externalResources; + private final InjectedValue securityFunction = new InjectedValue<>(); + private final List allowSuspendedRequests; + + private UndertowDeploymentInfoService(final JBossWebMetaData mergedMetaData, final String deploymentName, final HashMap tldInfo, final Module module, final ScisMetaData scisMetaData, final VirtualFile deploymentRoot, final String jaccContextId, final String securityDomain, final List attributes, final String contextPath, final List setupActions, final Set overlays, final List expressionFactoryWrappers, List predicatedHandlers, List initialHandlerChainWrappers, List innerHandlerChainWrappers, List outerHandlerChainWrappers, List threadSetupActions, boolean explodedDeployment, List servletExtensions, SharedSessionManagerConfig sharedSessionManagerConfig, WebSocketDeploymentInfo webSocketDeploymentInfo, File tempDir, List externalResources, List allowSuspendedRequests) { + this.mergedMetaData = mergedMetaData; + this.deploymentName = deploymentName; + this.tldInfo = tldInfo; + this.module = module; + this.scisMetaData = scisMetaData; + this.deploymentRoot = deploymentRoot; + this.jaccContextId = jaccContextId; + this.securityDomain = securityDomain; + this.attributes = attributes; + this.contextPath = contextPath; + this.setupActions = setupActions; + this.overlays = overlays; + this.expressionFactoryWrappers = expressionFactoryWrappers; + this.predicatedHandlers = predicatedHandlers; + this.initialHandlerChainWrappers = initialHandlerChainWrappers; + this.innerHandlerChainWrappers = innerHandlerChainWrappers; + this.outerHandlerChainWrappers = outerHandlerChainWrappers; + this.threadSetupActions = threadSetupActions; + this.explodedDeployment = explodedDeployment; + this.servletExtensions = servletExtensions; + this.sharedSessionManagerConfig = sharedSessionManagerConfig; + this.webSocketDeploymentInfo = webSocketDeploymentInfo; + this.tempDir = tempDir; + this.externalResources = externalResources; + this.allowSuspendedRequests = allowSuspendedRequests; + } + + @Override + public synchronized void start(final StartContext startContext) throws StartException { + ClassLoader oldTccl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(module.getClassLoader()); + DeploymentInfo deploymentInfo = createServletConfig(); + + deploymentInfo.setConfidentialPortManager(getConfidentialPortManager()); + + handleDistributable(deploymentInfo); + if (securityFunction.getOptionalValue() == null) { + if (securityDomain != null) { + handleIdentityManager(deploymentInfo); + handleJASPIMechanism(deploymentInfo); + handleJACCAuthorization(deploymentInfo); + handleAuthManagerLogout(deploymentInfo, mergedMetaData); + } else { + deploymentInfo.setSecurityDisabled(true); + } + + if(mergedMetaData.isUseJBossAuthorization()) { + deploymentInfo.setAuthorizationManager(new JbossAuthorizationManager(deploymentInfo.getAuthorizationManager())); + } + } + handleAdditionalAuthenticationMechanisms(deploymentInfo); + + + SessionConfigMetaData sessionConfig = mergedMetaData.getSessionConfig(); + if(sharedSessionManagerConfig != null && sharedSessionManagerConfig.getSessionConfig() != null) { + sessionConfig = sharedSessionManagerConfig.getSessionConfig(); + } + ServletSessionConfig config = null; + //default session config + SessionCookieConfig defaultSessionConfig = container.getValue().getSessionCookieConfig(); + if (defaultSessionConfig != null) { + config = new ServletSessionConfig(); + if (defaultSessionConfig.getName() != null) { + config.setName(defaultSessionConfig.getName()); + } + if (defaultSessionConfig.getDomain() != null) { + config.setDomain(defaultSessionConfig.getDomain()); + } + if (defaultSessionConfig.getHttpOnly() != null) { + config.setHttpOnly(defaultSessionConfig.getHttpOnly()); + } + if (defaultSessionConfig.getSecure() != null) { + config.setSecure(defaultSessionConfig.getSecure()); + } + if (defaultSessionConfig.getMaxAge() != null) { + config.setMaxAge(defaultSessionConfig.getMaxAge()); + } + if (defaultSessionConfig.getComment() != null) { + config.setComment(defaultSessionConfig.getComment()); + } + } + SecureRandomSessionIdGenerator sessionIdGenerator = new SecureRandomSessionIdGenerator(); + sessionIdGenerator.setLength(container.getValue().getSessionIdLength()); + deploymentInfo.setSessionIdGenerator(sessionIdGenerator); + + boolean sessionTimeoutSet = false; + if (sessionConfig != null) { + if (sessionConfig.getSessionTimeoutSet()) { + deploymentInfo.setDefaultSessionTimeout(sessionConfig.getSessionTimeout() * 60); + sessionTimeoutSet = true; + } + CookieConfigMetaData cookieConfig = sessionConfig.getCookieConfig(); + if (config == null) { + config = new ServletSessionConfig(); + } + if (cookieConfig != null) { + if (cookieConfig.getName() != null) { + config.setName(cookieConfig.getName()); + } + if (cookieConfig.getDomain() != null) { + config.setDomain(cookieConfig.getDomain()); + } + if (cookieConfig.getComment() != null) { + config.setComment(cookieConfig.getComment()); + } + config.setSecure(cookieConfig.getSecure()); + config.setPath(cookieConfig.getPath()); + config.setMaxAge(cookieConfig.getMaxAge()); + config.setHttpOnly(cookieConfig.getHttpOnly()); + } + List modes = sessionConfig.getSessionTrackingModes(); + if (modes != null && !modes.isEmpty()) { + final Set trackingModes = new HashSet<>(); + for (SessionTrackingModeType mode : modes) { + switch (mode) { + case COOKIE: + trackingModes.add(SessionTrackingMode.COOKIE); + break; + case SSL: + trackingModes.add(SessionTrackingMode.SSL); + break; + case URL: + trackingModes.add(SessionTrackingMode.URL); + break; + } + } + config.setSessionTrackingModes(trackingModes); + } + } + if(!sessionTimeoutSet) { + deploymentInfo.setDefaultSessionTimeout(container.getValue().getDefaultSessionTimeout() * 60); + } + if (config != null) { + deploymentInfo.setServletSessionConfig(config); + } + + for (final SetupAction action : setupActions) { + deploymentInfo.addThreadSetupAction(new UndertowThreadSetupAction(action)); + } + + if (initialHandlerChainWrappers != null) { + for (HandlerWrapper handlerWrapper : initialHandlerChainWrappers) { + deploymentInfo.addInitialHandlerChainWrapper(handlerWrapper); + } + } + + if (innerHandlerChainWrappers != null) { + for (HandlerWrapper handlerWrapper : innerHandlerChainWrappers) { + deploymentInfo.addInnerHandlerChainWrapper(handlerWrapper); + } + } + + if (outerHandlerChainWrappers != null) { + for (HandlerWrapper handlerWrapper : outerHandlerChainWrappers) { + deploymentInfo.addOuterHandlerChainWrapper(handlerWrapper); + } + } + + if (threadSetupActions != null) { + for (ThreadSetupHandler threadSetupAction : threadSetupActions) { + deploymentInfo.addThreadSetupAction(threadSetupAction); + } + } + deploymentInfo.setServerName(serverEnvironmentInjectedValue.getValue().getProductConfig().getPrettyVersionString()); + if (undertowService.getValue().isStatisticsEnabled()) { + deploymentInfo.setMetricsCollector(new UndertowMetricsCollector()); + } + + ControlPoint controlPoint = controlPointInjectedValue.getOptionalValue(); + if (controlPoint != null) { + deploymentInfo.addOuterHandlerChainWrapper(GlobalRequestControllerHandler.wrapper(controlPoint, allowSuspendedRequests)); + } + + for (Map.Entry e : container.getValue().getAuthenticationMechanisms().entrySet()) { + deploymentInfo.addAuthenticationMechanism(e.getKey(), e.getValue()); + } + deploymentInfo.setUseCachedAuthenticationMechanism(!deploymentInfo.getAuthenticationMechanisms().containsKey(SingleSignOnService.AUTHENTICATION_MECHANISM_NAME)); + + this.deploymentInfo = deploymentInfo; + } finally { + Thread.currentThread().setContextClassLoader(oldTccl); + } + + } + + private void handleAuthManagerLogout(DeploymentInfo deploymentInfo, JBossWebMetaData mergedMetaData) { + AuthenticationManager manager = securityDomainContextValue.getValue().getAuthenticationManager(); + deploymentInfo.addNotificationReceiver(new LogoutNotificationReceiver(manager, securityDomain)); + if(mergedMetaData.isFlushOnSessionInvalidation()) { + LogoutSessionListener listener = new LogoutSessionListener(manager); + deploymentInfo.addListener(Servlets.listener(LogoutSessionListener.class, new ImmediateInstanceFactory(listener))); + } + } + + @Override + public synchronized void stop(final StopContext stopContext) { + IoUtils.safeClose(this.deploymentInfo.getResourceManager()); + if (securityDomain != null && securityFunction.getOptionalValue() == null) { + AuthenticationManager authManager = securityDomainContextValue.getValue().getAuthenticationManager(); + if (authManager != null && authManager instanceof JBossCachedAuthenticationManager) { + ((JBossCachedAuthenticationManager) authManager).releaseModuleEntries(module.getClassLoader()); + } + } + this.deploymentInfo.setConfidentialPortManager(null); + this.deploymentInfo = null; + if (registration != null) { + registration.cancel(); + } + } + + @Override + public synchronized DeploymentInfo getValue() throws IllegalStateException, IllegalArgumentException { + return deploymentInfo; + } + + /** + *

Adds to the deployment the {@link org.wildfly.extension.undertow.security.jaspi.JASPICAuthenticationMechanism}, if necessary. The handler will be added if the security domain + * is configured with JASPI authentication.

+ * + * @param deploymentInfo + */ + private void handleJASPIMechanism(final DeploymentInfo deploymentInfo) { + ApplicationPolicy applicationPolicy = SecurityConfiguration.getApplicationPolicy(this.securityDomain); + + if (applicationPolicy != null && JASPIAuthenticationInfo.class.isInstance(applicationPolicy.getAuthenticationInfo())) { + String authMethod = null; + LoginConfig loginConfig = deploymentInfo.getLoginConfig(); + if (loginConfig != null && loginConfig.getAuthMethods().size() > 0) { + authMethod = loginConfig.getAuthMethods().get(0).getName(); + } + deploymentInfo.setJaspiAuthenticationMechanism(new JASPICAuthenticationMechanism(securityDomain, authMethod)); + deploymentInfo.setSecurityContextFactory(new JASPICSecurityContextFactory(this.securityDomain)); + deploymentInfo.addOuterHandlerChainWrapper(next -> new JASPICSecureResponseHandler(next)); + } + } + + /** + *

+ * Sets the {@link JACCAuthorizationManager} in the specified {@link DeploymentInfo} if the webapp security domain + * has defined a JACC authorization module. + *

+ * + * @param deploymentInfo the {@link DeploymentInfo} instance. + */ + private void handleJACCAuthorization(final DeploymentInfo deploymentInfo) { + // TODO make the authorization manager implementation configurable in Undertow or jboss-web.xml + ApplicationPolicy applicationPolicy = SecurityConfiguration.getApplicationPolicy(this.securityDomain); + if (applicationPolicy != null) { + AuthorizationInfo authzInfo = applicationPolicy.getAuthorizationInfo(); + if (authzInfo != null) { + for (AuthorizationModuleEntry entry : authzInfo.getModuleEntries()) { + if (JACCAuthorizationModule.class.getName().equals(entry.getPolicyModuleName())) { + deploymentInfo.setAuthorizationManager(JACCAuthorizationManager.INSTANCE); + break; + } + } + } + } + } + + private void handleAdditionalAuthenticationMechanisms(final DeploymentInfo deploymentInfo) { + for (Map.Entry am : host.getValue().getAdditionalAuthenticationMechanisms().entrySet()) { + deploymentInfo.addFirstAuthenticationMechanism(am.getKey(), am.getValue()); + } + } + + private void handleIdentityManager(final DeploymentInfo deploymentInfo) { + SecurityDomainContext sdc = securityDomainContextValue.getValue(); + deploymentInfo.setIdentityManager(new JAASIdentityManagerImpl(sdc)); + AuditManager auditManager = sdc.getAuditManager(); + if (auditManager != null && !mergedMetaData.isDisableAudit()) { + deploymentInfo.addNotificationReceiver(new AuditNotificationReceiver(auditManager)); + } + } + + private ConfidentialPortManager getConfidentialPortManager() { + return new ConfidentialPortManager() { + + @Override + public int getConfidentialPort(HttpServerExchange exchange) { + int port = exchange.getConnection().getLocalAddress(InetSocketAddress.class).getPort(); + if (port<0){ + UndertowLogger.ROOT_LOGGER.debugf("Confidential port not defined for port %s", port); + } + return host.getValue().getServer().getValue().lookupSecurePort(port); + } + }; + } + + private void handleDistributable(final DeploymentInfo deploymentInfo) { + SessionManagerFactory managerFactory = this.sessionManagerFactory.getOptionalValue(); + if (managerFactory != null) { + deploymentInfo.setSessionManagerFactory(managerFactory); + } + SessionIdentifierCodec codec = this.sessionIdentifierCodec.getOptionalValue(); + if (codec != null) { + deploymentInfo.setSessionConfigWrapper(new CodecSessionConfigWrapper(codec)); + } + } + + /* + This is to address WFLY-1894 but should probably be moved to some other place. + */ + private String resolveContextPath() { + if (deploymentName.equals(host.getValue().getDefaultWebModule())) { + return "/"; + } else { + return contextPath; + } + } + + private DeploymentInfo createServletConfig() throws StartException { + final ComponentRegistry componentRegistry = componentRegistryInjectedValue.getValue(); + try { + if (!mergedMetaData.isMetadataComplete()) { + mergedMetaData.resolveAnnotations(); + } + mergedMetaData.resolveRunAs(); + final DeploymentInfo d = new DeploymentInfo(); + d.setContextPath(resolveContextPath()); + if (mergedMetaData.getDescriptionGroup() != null) { + d.setDisplayName(mergedMetaData.getDescriptionGroup().getDisplayName()); + } + d.setDeploymentName(deploymentName); + d.setHostName(host.getValue().getName()); + + final ServletContainerService servletContainer = container.getValue(); + try { + //TODO: make the caching limits configurable + List externalOverlays = mergedMetaData.getOverlays(); + + ResourceManager resourceManager = new ServletResourceManager(deploymentRoot, overlays, explodedDeployment, mergedMetaData.isSymbolicLinkingEnabled(), servletContainer.isDisableFileWatchService(), externalOverlays); + + resourceManager = new CachingResourceManager(servletContainer.getFileCacheMetadataSize(), servletContainer.getFileCacheMaxFileSize(), servletContainer.getBufferCache(), resourceManager, servletContainer.getFileCacheTimeToLive() == null ? (explodedDeployment ? 2000 : -1) : servletContainer.getFileCacheTimeToLive()); + if(externalResources != null && !externalResources.isEmpty()) { + //TODO: we don't cache external deployments, as they are intended for development use + //should be make this configurable or something? + List delegates = new ArrayList<>(); + for(File resource : externalResources) { + delegates.add(new FileResourceManager(resource.getCanonicalFile(), 1024, true, mergedMetaData.isSymbolicLinkingEnabled(), "/")); + } + delegates.add(resourceManager); + resourceManager = new DelegatingResourceManager(delegates); + } + + d.setResourceManager(resourceManager); + } catch (IOException e) { + throw new StartException(e); + } + + d.setTempDir(tempDir); + + d.setClassLoader(module.getClassLoader()); + final String servletVersion = mergedMetaData.getServletVersion(); + if (servletVersion != null) { + d.setMajorVersion(Integer.parseInt(servletVersion.charAt(0) + "")); + d.setMinorVersion(Integer.parseInt(servletVersion.charAt(2) + "")); + } else { + d.setMajorVersion(3); + d.setMinorVersion(1); + } + + d.setDefaultCookieVersion(servletContainer.getDefaultCookieVersion()); + + //in most cases flush just hurts performance for no good reason + d.setIgnoreFlush(servletContainer.isIgnoreFlush()); + + //controls initialization of filters on start of application + d.setEagerFilterInit(servletContainer.isEagerFilterInit()); + + d.setAllowNonStandardWrappers(servletContainer.isAllowNonStandardWrappers()); + d.setServletStackTraces(servletContainer.getStackTraces()); + d.setDisableCachingForSecuredPages(servletContainer.isDisableCachingForSecuredPages()); + if(servletContainer.isDisableSessionIdReuse()) { + d.setCheckOtherSessionManagers(false); + } + + if (servletContainer.getSessionPersistenceManager() != null) { + d.setSessionPersistenceManager(servletContainer.getSessionPersistenceManager()); + } + + //for 2.2 apps we do not require a leading / in path mappings + boolean is22OrOlder; + if (d.getMajorVersion() == 1) { + is22OrOlder = true; + } else if (d.getMajorVersion() == 2) { + is22OrOlder = d.getMinorVersion() < 3; + } else { + is22OrOlder = false; + } + JSPConfig jspConfig = servletContainer.getJspConfig(); + final Set seenMappings = new HashSet<>(); + + //default JSP servlet + final ServletInfo jspServlet = jspConfig != null ? jspConfig.createJSPServletInfo() : null; + if (jspServlet != null) { //this would be null if jsp support is disabled + HashMap propertyGroups = createJspConfig(mergedMetaData); + JspServletBuilder.setupDeployment(d, propertyGroups, tldInfo, new UndertowJSPInstanceManager(new WebInjectionContainer(module.getClassLoader(), componentRegistryInjectedValue.getValue()))); + + if (mergedMetaData.getJspConfig() != null) { + Collection values = new LinkedHashSet<>(propertyGroups.values()); + d.setJspConfigDescriptor(new JspConfigDescriptorImpl(tldInfo.values(), values)); + } + + d.addServlet(jspServlet); + + final Set jspPropertyGroupMappings = propertyGroups.keySet(); + for (final String mapping : jspPropertyGroupMappings) { + if(!jspServlet.getMappings().contains(mapping)) { + jspServlet.addMapping(mapping); + } + } + seenMappings.addAll(jspPropertyGroupMappings); + //setup JSP application context initializing listener + d.addListener(new ListenerInfo(JspInitializationListener.class)); + d.addServletContextAttribute(JspInitializationListener.CONTEXT_KEY, expressionFactoryWrappers); + } + + d.setClassIntrospecter(new ComponentClassIntrospector(componentRegistry)); + + final Map> servletMappings = new HashMap<>(); + + if (mergedMetaData.getExecutorName() != null) { + d.setExecutor(executorsByName.get(mergedMetaData.getExecutorName()).getValue()); + } + + Boolean proactiveAuthentication = mergedMetaData.getProactiveAuthentication(); + if(proactiveAuthentication == null) { + proactiveAuthentication = container.getValue().isProactiveAuth(); + } + d.setAuthenticationMode(proactiveAuthentication ? AuthenticationMode.PRO_ACTIVE : AuthenticationMode.CONSTRAINT_DRIVEN); + + if (servletExtensions != null) { + for (ServletExtension extension : servletExtensions) { + d.addServletExtension(extension); + } + } + + if (mergedMetaData.getServletMappings() != null) { + for (final ServletMappingMetaData mapping : mergedMetaData.getServletMappings()) { + List list = servletMappings.get(mapping.getServletName()); + if (list == null) { + servletMappings.put(mapping.getServletName(), list = new ArrayList<>()); + } + list.add(mapping); + } + } + if (jspServlet != null) { + jspServlet.addHandlerChainWrapper(JspFileHandler.jspFileHandlerWrapper(null)); // we need to clear the file attribute if it is set (WFLY-4106) + List list = servletMappings.get(jspServlet.getName()); + if(list != null && ! list.isEmpty()) { + for (final ServletMappingMetaData mapping : list) { + for(String urlPattern : mapping.getUrlPatterns()) { + jspServlet.addMapping(urlPattern); + } + seenMappings.addAll(mapping.getUrlPatterns()); + } + } + } + + for (final JBossServletMetaData servlet : mergedMetaData.getServlets()) { + final ServletInfo s; + + if (servlet.getJspFile() != null) { + s = new ServletInfo(servlet.getName(), JspServlet.class); + s.addHandlerChainWrapper(JspFileHandler.jspFileHandlerWrapper(servlet.getJspFile())); + } else { + if (servlet.getServletClass() == null) { + if(DEFAULT_SERVLET_NAME.equals(servlet.getName())) { + s = new ServletInfo(servlet.getName(), DefaultServlet.class); + } else { + throw UndertowLogger.ROOT_LOGGER.servletClassNotDefined(servlet.getServletName()); + } + } else { + Class servletClass = (Class) module.getClassLoader().loadClass(servlet.getServletClass()); + ManagedReferenceFactory creator = componentRegistry.createInstanceFactory(servletClass); + if (creator != null) { + InstanceFactory factory = createInstanceFactory(creator); + s = new ServletInfo(servlet.getName(), servletClass, factory); + } else { + s = new ServletInfo(servlet.getName(), servletClass); + } + } + } + s.setAsyncSupported(servlet.isAsyncSupported()) + .setJspFile(servlet.getJspFile()) + .setEnabled(servlet.isEnabled()); + if (servlet.getRunAs() != null) { + s.setRunAs(servlet.getRunAs().getRoleName()); + } + if (servlet.getLoadOnStartupSet()) {//todo why not cleanup api and just use int everywhere + s.setLoadOnStartup(servlet.getLoadOnStartupInt()); + } + + if (servlet.getExecutorName() != null) { + s.setExecutor(executorsByName.get(servlet.getExecutorName()).getValue()); + } + + handleServletMappings(is22OrOlder, seenMappings, servletMappings, s); + + if (servlet.getInitParam() != null) { + for (ParamValueMetaData initParam : servlet.getInitParam()) { + if (!s.getInitParams().containsKey(initParam.getParamName())) { + s.addInitParam(initParam.getParamName(), initParam.getParamValue()); + } + } + } + if (servlet.getServletSecurity() != null) { + ServletSecurityInfo securityInfo = new ServletSecurityInfo(); + s.setServletSecurityInfo(securityInfo); + securityInfo.setEmptyRoleSemantic(servlet.getServletSecurity().getEmptyRoleSemantic() == EmptyRoleSemanticType.DENY ? DENY : PERMIT) + .setTransportGuaranteeType(transportGuaranteeType(servlet.getServletSecurity().getTransportGuarantee())) + .addRolesAllowed(servlet.getServletSecurity().getRolesAllowed()); + if (servlet.getServletSecurity().getHttpMethodConstraints() != null) { + for (HttpMethodConstraintMetaData method : servlet.getServletSecurity().getHttpMethodConstraints()) { + securityInfo.addHttpMethodSecurityInfo( + new HttpMethodSecurityInfo() + .setEmptyRoleSemantic(method.getEmptyRoleSemantic() == EmptyRoleSemanticType.DENY ? DENY : PERMIT) + .setTransportGuaranteeType(transportGuaranteeType(method.getTransportGuarantee())) + .addRolesAllowed(method.getRolesAllowed()) + .setMethod(method.getMethod())); + } + } + } + if (servlet.getSecurityRoleRefs() != null) { + for (final SecurityRoleRefMetaData ref : servlet.getSecurityRoleRefs()) { + s.addSecurityRoleRef(ref.getRoleName(), ref.getRoleLink()); + } + } + + if (servlet.getMultipartConfig() != null) { + MultipartConfigMetaData mp = servlet.getMultipartConfig(); + s.setMultipartConfig(Servlets.multipartConfig(mp.getLocation(), mp.getMaxFileSize(), mp.getMaxRequestSize(), mp.getFileSizeThreshold())); + } + + d.addServlet(s); + } + + if(jspServlet != null) { + if(!seenMappings.contains("*.jsp")) { + jspServlet.addMapping("*.jsp"); + } + if(!seenMappings.contains("*.jspx")) { + jspServlet.addMapping("*.jspx"); + } + } + + //we explicitly add the default servlet, to allow it to be mapped + if (!mergedMetaData.getServlets().containsKey(ServletPathMatches.DEFAULT_SERVLET_NAME)) { + ServletInfo defaultServlet = Servlets.servlet(DEFAULT_SERVLET_NAME, DefaultServlet.class); + handleServletMappings(is22OrOlder, seenMappings, servletMappings, defaultServlet); + + d.addServlet(defaultServlet); + } + + if(servletContainer.getDirectoryListingEnabled() != null) { + ServletInfo defaultServlet = d.getServlets().get(DEFAULT_SERVLET_NAME); + defaultServlet.addInitParam(DefaultServlet.DIRECTORY_LISTING, servletContainer.getDirectoryListingEnabled().toString()); + } + + if (mergedMetaData.getFilters() != null) { + for (final FilterMetaData filter : mergedMetaData.getFilters()) { + Class filterClass = (Class) module.getClassLoader().loadClass(filter.getFilterClass()); + ManagedReferenceFactory creator = componentRegistry.createInstanceFactory(filterClass); + FilterInfo f; + if (creator != null) { + InstanceFactory instanceFactory = createInstanceFactory(creator); + f = new FilterInfo(filter.getName(), filterClass, instanceFactory); + } else { + f = new FilterInfo(filter.getName(), filterClass); + } + f.setAsyncSupported(filter.isAsyncSupported()); + d.addFilter(f); + + if (filter.getInitParam() != null) { + for (ParamValueMetaData initParam : filter.getInitParam()) { + f.addInitParam(initParam.getParamName(), initParam.getParamValue()); + } + } + } + } + if (mergedMetaData.getFilterMappings() != null) { + for (final FilterMappingMetaData mapping : mergedMetaData.getFilterMappings()) { + if (mapping.getUrlPatterns() != null) { + for (String url : mapping.getUrlPatterns()) { + if (is22OrOlder && !url.startsWith("*") && !url.startsWith("/")) { + url = "/" + url; + } + if (mapping.getDispatchers() != null && !mapping.getDispatchers().isEmpty()) { + for (DispatcherType dispatcher : mapping.getDispatchers()) { + + d.addFilterUrlMapping(mapping.getFilterName(), url, javax.servlet.DispatcherType.valueOf(dispatcher.name())); + } + } else { + d.addFilterUrlMapping(mapping.getFilterName(), url, javax.servlet.DispatcherType.REQUEST); + } + } + } + if (mapping.getServletNames() != null) { + for (String servletName : mapping.getServletNames()) { + if (mapping.getDispatchers() != null && !mapping.getDispatchers().isEmpty()) { + for (DispatcherType dispatcher : mapping.getDispatchers()) { + d.addFilterServletNameMapping(mapping.getFilterName(), servletName, javax.servlet.DispatcherType.valueOf(dispatcher.name())); + } + } else { + d.addFilterServletNameMapping(mapping.getFilterName(), servletName, javax.servlet.DispatcherType.REQUEST); + } + } + } + } + } + + if (scisMetaData != null && scisMetaData.getHandlesTypes() != null) { + for (final ServletContainerInitializer sci : scisMetaData.getScis()) { + final ImmediateInstanceFactory instanceFactory = new ImmediateInstanceFactory<>(sci); + d.addServletContainerInitalizer(new ServletContainerInitializerInfo(sci.getClass(), instanceFactory, scisMetaData.getHandlesTypes().get(sci))); + } + } + + if (mergedMetaData.getListeners() != null) { + Set tldListeners = new HashSet<>(); + for(Map.Entry e : tldInfo.entrySet()) { + tldListeners.addAll(Arrays.asList(e.getValue().getListeners())); + } + for (ListenerMetaData listener : mergedMetaData.getListeners()) { + addListener(module.getClassLoader(), componentRegistry, d, listener, tldListeners.contains(listener.getListenerClass())); + } + + } + if (mergedMetaData.getContextParams() != null) { + for (ParamValueMetaData param : mergedMetaData.getContextParams()) { + d.addInitParameter(param.getParamName(), param.getParamValue()); + } + } + + if (mergedMetaData.getWelcomeFileList() != null && + mergedMetaData.getWelcomeFileList().getWelcomeFiles() != null) { + List welcomeFiles = mergedMetaData.getWelcomeFileList().getWelcomeFiles(); + for (String file : welcomeFiles) { + if (file.startsWith("/")) { + d.addWelcomePages(file.substring(1)); + } else { + d.addWelcomePages(file); + } + } + } else { + d.addWelcomePages("index.html", "index.htm", "index.jsp"); + } + d.addWelcomePages(servletContainer.getWelcomeFiles()); + + if (mergedMetaData.getErrorPages() != null) { + for (final ErrorPageMetaData page : mergedMetaData.getErrorPages()) { + final ErrorPage errorPage; + if (page.getExceptionType() != null && !page.getExceptionType().isEmpty()) { + errorPage = new ErrorPage(page.getLocation(), (Class) module.getClassLoader().loadClass(page.getExceptionType())); + } else if (page.getErrorCode() != null && !page.getErrorCode().isEmpty()) { + errorPage = new ErrorPage(page.getLocation(), Integer.parseInt(page.getErrorCode())); + } else { + errorPage = new ErrorPage(page.getLocation()); + } + d.addErrorPages(errorPage); + } + } + + for(Map.Entry entry : servletContainer.getMimeMappings().entrySet()) { + d.addMimeMapping(new MimeMapping(entry.getKey(), entry.getValue())); + } + + if (mergedMetaData.getMimeMappings() != null) { + for (final MimeMappingMetaData mapping : mergedMetaData.getMimeMappings()) { + d.addMimeMapping(new MimeMapping(mapping.getExtension(), mapping.getMimeType())); + } + } + + d.setDenyUncoveredHttpMethods(mergedMetaData.getDenyUncoveredHttpMethods() != null); + Set securityRoleNames = mergedMetaData.getSecurityRoleNames(); + if (mergedMetaData.getSecurityConstraints() != null) { + for (SecurityConstraintMetaData constraint : mergedMetaData.getSecurityConstraints()) { + SecurityConstraint securityConstraint = new SecurityConstraint() + .setTransportGuaranteeType(transportGuaranteeType(constraint.getTransportGuarantee())); + + List roleNames = constraint.getRoleNames(); + if (constraint.getAuthConstraint() == null) { + // no auth constraint means we permit the empty roles + securityConstraint.setEmptyRoleSemantic(PERMIT); + } else if (roleNames.size() == 1 && roleNames.contains("*") && securityRoleNames.contains("*")) { + // AS7-6932 - Trying to do a * to * mapping which JBossWeb passed through, for Undertow enable + // authentication only mode. + // TODO - AS7-6933 - Revisit workaround added to allow switching between JBoss Web and Undertow. + securityConstraint.setEmptyRoleSemantic(AUTHENTICATE); + } else { + securityConstraint.addRolesAllowed(roleNames); + } + + if (constraint.getResourceCollections() != null) { + for (final WebResourceCollectionMetaData resourceCollection : constraint.getResourceCollections()) { + securityConstraint.addWebResourceCollection(new WebResourceCollection() + .addHttpMethods(resourceCollection.getHttpMethods()) + .addHttpMethodOmissions(resourceCollection.getHttpMethodOmissions()) + .addUrlPatterns(resourceCollection.getUrlPatterns())); + } + } + d.addSecurityConstraint(securityConstraint); + } + } + final LoginConfigMetaData loginConfig = mergedMetaData.getLoginConfig(); + if (loginConfig != null) { + List authMethod = authMethod(loginConfig.getAuthMethod()); + if (loginConfig.getFormLoginConfig() != null) { + d.setLoginConfig(new LoginConfig(loginConfig.getRealmName(), loginConfig.getFormLoginConfig().getLoginPage(), loginConfig.getFormLoginConfig().getErrorPage())); + } else { + d.setLoginConfig(new LoginConfig(loginConfig.getRealmName())); + } + for (AuthMethodConfig method : authMethod) { + d.getLoginConfig().addLastAuthMethod(method); + } + } + + d.addSecurityRoles(mergedMetaData.getSecurityRoleNames()); + Map> principalVersusRolesMap = mergedMetaData.getPrincipalVersusRolesMap(); + + BiFunction, Registration> securityFunction = this.securityFunction.getOptionalValue(); + if (securityFunction != null) { + Map runAsIdentityMap = mergedMetaData.getRunAsIdentity(); + registration = securityFunction.apply(d, runAsIdentityMap::get); + d.addOuterHandlerChainWrapper(JACCContextIdHandler.wrapper(jaccContextId)); + if(mergedMetaData.isUseJBossAuthorization()) { + UndertowLogger.ROOT_LOGGER.configurationOptionIgnoredWhenUsingElytron("use-jboss-authorization"); + } + } else { + if (securityDomain != null) { + d.addThreadSetupAction(new SecurityContextThreadSetupAction(securityDomain, securityDomainContextValue.getValue(), principalVersusRolesMap)); + + d.addInnerHandlerChainWrapper(SecurityContextAssociationHandler.wrapper(mergedMetaData.getRunAsIdentity())); + d.addOuterHandlerChainWrapper(JACCContextIdHandler.wrapper(jaccContextId)); + + d.addLifecycleInterceptor(new RunAsLifecycleInterceptor(mergedMetaData.getRunAsIdentity())); + } + } + + if (principalVersusRolesMap != null) { + for (Map.Entry> entry : principalVersusRolesMap.entrySet()) { + d.addPrincipalVsRoleMappings(entry.getKey(), entry.getValue()); + } + } + + // Setup an deployer configured ServletContext attributes + if(attributes != null) { + for (ServletContextAttribute attribute : attributes) { + d.addServletContextAttribute(attribute.getName(), attribute.getValue()); + } + } + + //now setup websockets if they are enabled + if(servletContainer.isWebsocketsEnabled() && webSocketDeploymentInfo != null) { + webSocketDeploymentInfo.setBuffers(servletContainer.getWebsocketsBufferPool().getValue()); + webSocketDeploymentInfo.setWorker(servletContainer.getWebsocketsWorker().getValue()); + webSocketDeploymentInfo.setDispatchToWorkerThread(servletContainer.isDispatchWebsocketInvocationToWorker()); + + if(servletContainer.isPerMessageDeflate()) { + PerMessageDeflateHandshake perMessageDeflate = new PerMessageDeflateHandshake(false, servletContainer.getDeflaterLevel()); + webSocketDeploymentInfo.addExtension(perMessageDeflate); + } + + final AtomicReference serverActivity = new AtomicReference<>(); + webSocketDeploymentInfo.addListener(wsc -> { + serverActivity.set(new ServerActivity() { + @Override + public void preSuspend(ServerActivityCallback listener) { + listener.done(); + } + + @Override + public void suspended(final ServerActivityCallback listener) { + if(wsc.getConfiguredServerEndpoints().isEmpty()) { + //TODO: remove this once undertow bug fix is upstream + listener.done(); + return; + } + wsc.pause(new ServerWebSocketContainer.PauseListener() { + @Override + public void paused() { + listener.done(); + } + + @Override + public void resumed() { + } + }); + } + + @Override + public void resume() { + wsc.resume(); + } + }); + suspendControllerInjectedValue.getValue().registerActivity(serverActivity.get()); + }); + ServletContextListener sl = new ServletContextListener() { + @Override + public void contextInitialized(ServletContextEvent sce) {} + + @Override + public void contextDestroyed(ServletContextEvent sce) { + final ServerActivity activity = serverActivity.get(); + if(activity != null) { + suspendControllerInjectedValue.getValue().unRegisterActivity(activity); + } + } + }; + d.addListener(new ListenerInfo(sl.getClass(), new ImmediateInstanceFactory(sl))); + + d.addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, webSocketDeploymentInfo); + + } + + + if (mergedMetaData.getLocalEncodings() != null && + mergedMetaData.getLocalEncodings().getMappings() != null) { + for (LocaleEncodingMetaData locale : mergedMetaData.getLocalEncodings().getMappings()) { + d.addLocaleCharsetMapping(locale.getLocale(), locale.getEncoding()); + } + } + + if (predicatedHandlers != null && !predicatedHandlers.isEmpty()) { + d.addOuterHandlerChainWrapper(new RewriteCorrectingHandlerWrappers.PostWrapper()); + d.addOuterHandlerChainWrapper(new HandlerWrapper() { + @Override + public HttpHandler wrap(HttpHandler handler) { + return Handlers.predicates(predicatedHandlers, handler); + } + }); + d.addOuterHandlerChainWrapper(new RewriteCorrectingHandlerWrappers.PreWrapper()); + } + + if (mergedMetaData.getDefaultEncoding() != null) { + d.setDefaultEncoding(mergedMetaData.getDefaultEncoding()); + } else if (servletContainer.getDefaultEncoding() != null) { + d.setDefaultEncoding(servletContainer.getDefaultEncoding()); + } + d.setCrawlerSessionManagerConfig(servletContainer.getCrawlerSessionManagerConfig()); + + return d; + } catch (ClassNotFoundException e) { + throw new StartException(e); + } + } + + private void handleServletMappings(boolean is22OrOlder, Set seenMappings, Map> servletMappings, ServletInfo s) { + List mappings = servletMappings.get(s.getName()); + if (mappings != null) { + for (ServletMappingMetaData mapping : mappings) { + for (String pattern : mapping.getUrlPatterns()) { + if (is22OrOlder && !pattern.startsWith("*") && !pattern.startsWith("/")) { + pattern = "/" + pattern; + } + if (!seenMappings.contains(pattern)) { + s.addMapping(pattern); + seenMappings.add(pattern); + } else { + UndertowLogger.ROOT_LOGGER.duplicateServletMapping(pattern); + } + } + } + } + } + + /** + * Convert the authentication method name from the format specified in the web.xml to the format used by + * {@link javax.servlet.http.HttpServletRequest}. + *

+ * If the auth method is not recognised then it is returned as-is. + * + * @return The converted auth method. + * @throws NullPointerException if no configuredMethod is supplied. + */ + private static List authMethod(String configuredMethod) { + if (configuredMethod == null) { + return Collections.singletonList(new AuthMethodConfig(HttpServletRequest.BASIC_AUTH)); + } + return AuthMethodParser.parse(configuredMethod, Collections.singletonMap("CLIENT-CERT", HttpServletRequest.CLIENT_CERT_AUTH)); + } + + private static io.undertow.servlet.api.TransportGuaranteeType transportGuaranteeType(final TransportGuaranteeType type) { + if (type == null) { + return io.undertow.servlet.api.TransportGuaranteeType.NONE; + } + switch (type) { + case CONFIDENTIAL: + return io.undertow.servlet.api.TransportGuaranteeType.CONFIDENTIAL; + case INTEGRAL: + return io.undertow.servlet.api.TransportGuaranteeType.INTEGRAL; + case NONE: + return io.undertow.servlet.api.TransportGuaranteeType.NONE; + } + throw new RuntimeException("UNREACHABLE"); + } + + private static HashMap createJspConfig(JBossWebMetaData metaData) { + final HashMap result = new HashMap<>(); + // JSP Config + JspConfigMetaData config = metaData.getJspConfig(); + if (config != null) { + // JSP Property groups + List groups = config.getPropertyGroups(); + if (groups != null) { + for (JspPropertyGroupMetaData group : groups) { + org.apache.jasper.deploy.JspPropertyGroup jspPropertyGroup = new org.apache.jasper.deploy.JspPropertyGroup(); + for (String pattern : group.getUrlPatterns()) { + jspPropertyGroup.addUrlPattern(pattern); + } + jspPropertyGroup.setElIgnored(group.getElIgnored()); + jspPropertyGroup.setPageEncoding(group.getPageEncoding()); + jspPropertyGroup.setScriptingInvalid(group.getScriptingInvalid()); + jspPropertyGroup.setIsXml(group.getIsXml()); + if (group.getIncludePreludes() != null) { + for (String includePrelude : group.getIncludePreludes()) { + jspPropertyGroup.addIncludePrelude(includePrelude); + } + } + if (group.getIncludeCodas() != null) { + for (String includeCoda : group.getIncludeCodas()) { + jspPropertyGroup.addIncludeCoda(includeCoda); + } + } + jspPropertyGroup.setDeferredSyntaxAllowedAsLiteral(group.getDeferredSyntaxAllowedAsLiteral()); + jspPropertyGroup.setTrimDirectiveWhitespaces(group.getTrimDirectiveWhitespaces()); + jspPropertyGroup.setDefaultContentType(group.getDefaultContentType()); + jspPropertyGroup.setBuffer(group.getBuffer()); + jspPropertyGroup.setErrorOnUndeclaredNamespace(group.getErrorOnUndeclaredNamespace()); + for (String pattern : jspPropertyGroup.getUrlPatterns()) { + // Split off the groups to individual mappings + result.put(pattern, jspPropertyGroup); + } + } + } + } + + //it looks like jasper needs these in order of least specified to most specific + final LinkedHashMap ret = new LinkedHashMap<>(); + final ArrayList paths = new ArrayList<>(result.keySet()); + Collections.sort(paths, new Comparator() { + @Override + public int compare(final String o1, final String o2) { + return o1.length() - o2.length(); + } + }); + for (String path : paths) { + ret.put(path, result.get(path)); + } + return ret; + } + + private static void addListener(final ClassLoader classLoader, final ComponentRegistry components, final DeploymentInfo d, final ListenerMetaData listener, boolean programatic) throws ClassNotFoundException { + + ListenerInfo l; + final Class listenerClass = (Class) classLoader.loadClass(listener.getListenerClass()); + ManagedReferenceFactory creator = components.createInstanceFactory(listenerClass); + if (creator != null) { + InstanceFactory factory = createInstanceFactory(creator); + l = new ListenerInfo(listenerClass, factory, programatic); + } else { + l = new ListenerInfo(listenerClass, programatic); + } + d.addListener(l); + } + + private static InstanceFactory createInstanceFactory(final ManagedReferenceFactory creator) { + return new InstanceFactory() { + @Override + public InstanceHandle createInstance() throws InstantiationException { + final ManagedReference instance = creator.getReference(); + return new InstanceHandle() { + @Override + public T getInstance() { + return (T) instance.getInstance(); + } + + @Override + public void release() { + instance.release(); + } + }; + } + }; + } + + public void addInjectedExecutor(final String name, final InjectedValue injected) { + executorsByName.put(name, injected); + } + + public InjectedValue getContainer() { + return container; + } + + public InjectedValue getSecurityDomainContextValue() { + return securityDomainContextValue; + } + + public Injector getSessionManagerFactoryInjector() { + return this.sessionManagerFactory; + } + + public Injector getSessionIdentifierCodecInjector() { + return this.sessionIdentifierCodec; + } + + public InjectedValue getUndertowService() { + return undertowService; + } + + public InjectedValue getControlPointInjectedValue() { + return controlPointInjectedValue; + } + + public InjectedValue getComponentRegistryInjectedValue() { + return componentRegistryInjectedValue; + } + + public InjectedValue getSuspendControllerInjectedValue() { + return suspendControllerInjectedValue; + } + + public InjectedValue getServerEnvironmentInjectedValue() { + return serverEnvironmentInjectedValue; + } + + public Injector getSecurityFunctionInjector() { + return securityFunction; + } + + public InjectedValue getHost() { + return host; + } + + private static class ComponentClassIntrospector implements ClassIntrospecter { + private final ComponentRegistry componentRegistry; + + public ComponentClassIntrospector(final ComponentRegistry componentRegistry) { + this.componentRegistry = componentRegistry; + } + + @Override + public InstanceFactory createInstanceFactory(final Class clazz) throws NoSuchMethodException { + final ManagedReferenceFactory component = componentRegistry.createInstanceFactory(clazz); + return new ManagedReferenceInstanceFactory<>(component); + } + } + + private static class ManagedReferenceInstanceFactory implements InstanceFactory { + private final ManagedReferenceFactory component; + + public ManagedReferenceInstanceFactory(final ManagedReferenceFactory component) { + this.component = component; + } + + @Override + public InstanceHandle createInstance() throws InstantiationException { + final ManagedReference reference = component.getReference(); + return new InstanceHandle() { + @Override + public T getInstance() { + return (T) reference.getInstance(); + } + + @Override + public void release() { + reference.release(); + } + }; + } + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private JBossWebMetaData mergedMetaData; + private String deploymentName; + private HashMap tldInfo; + private Module module; + private ScisMetaData scisMetaData; + private VirtualFile deploymentRoot; + private String jaccContextId; + private List attributes; + private String contextPath; + private String securityDomain; + private List setupActions; + private Set overlays; + private List expressionFactoryWrappers; + private List predicatedHandlers; + private List initialHandlerChainWrappers; + private List innerHandlerChainWrappers; + private List outerHandlerChainWrappers; + private List threadSetupActions; + private List servletExtensions; + private SharedSessionManagerConfig sharedSessionManagerConfig; + private boolean explodedDeployment; + private WebSocketDeploymentInfo webSocketDeploymentInfo; + private File tempDir; + private List externalResources; + List allowSuspendedRequests; + + Builder setMergedMetaData(final JBossWebMetaData mergedMetaData) { + this.mergedMetaData = mergedMetaData; + return this; + } + + public Builder setDeploymentName(final String deploymentName) { + this.deploymentName = deploymentName; + return this; + } + + public Builder setTldInfo(HashMap tldInfo) { + this.tldInfo = tldInfo; + return this; + } + + public Builder setModule(final Module module) { + this.module = module; + return this; + } + + public Builder setScisMetaData(final ScisMetaData scisMetaData) { + this.scisMetaData = scisMetaData; + return this; + } + + public Builder setDeploymentRoot(final VirtualFile deploymentRoot) { + this.deploymentRoot = deploymentRoot; + return this; + } + + public Builder setJaccContextId(final String jaccContextId) { + this.jaccContextId = jaccContextId; + return this; + } + + public Builder setAttributes(final List attributes) { + this.attributes = attributes; + return this; + } + + public Builder setContextPath(final String contextPath) { + this.contextPath = contextPath; + return this; + } + + public Builder setSetupActions(final List setupActions) { + this.setupActions = setupActions; + return this; + } + + public Builder setSecurityDomain(final String securityDomain) { + this.securityDomain = securityDomain; + return this; + } + + public Builder setOverlays(final Set overlays) { + this.overlays = overlays; + return this; + } + + public Builder setExpressionFactoryWrappers(final List expressionFactoryWrappers) { + this.expressionFactoryWrappers = expressionFactoryWrappers; + return this; + } + + public Builder setPredicatedHandlers(List predicatedHandlers) { + this.predicatedHandlers = predicatedHandlers; + return this; + } + + public Builder setInitialHandlerChainWrappers(List initialHandlerChainWrappers) { + this.initialHandlerChainWrappers = initialHandlerChainWrappers; + return this; + } + + public Builder setInnerHandlerChainWrappers(List innerHandlerChainWrappers) { + this.innerHandlerChainWrappers = innerHandlerChainWrappers; + return this; + } + + public Builder setOuterHandlerChainWrappers(List outerHandlerChainWrappers) { + this.outerHandlerChainWrappers = outerHandlerChainWrappers; + return this; + } + + public Builder setThreadSetupActions(List threadSetupActions) { + this.threadSetupActions = threadSetupActions; + return this; + } + + public Builder setExplodedDeployment(boolean explodedDeployment) { + this.explodedDeployment = explodedDeployment; + return this; + } + + public List getServletExtensions() { + return servletExtensions; + } + + public Builder setServletExtensions(List servletExtensions) { + this.servletExtensions = servletExtensions; + return this; + } + + public Builder setSharedSessionManagerConfig(SharedSessionManagerConfig sharedSessionManagerConfig) { + this.sharedSessionManagerConfig = sharedSessionManagerConfig; + return this; + } + + public Builder setWebSocketDeploymentInfo(WebSocketDeploymentInfo webSocketDeploymentInfo) { + this.webSocketDeploymentInfo = webSocketDeploymentInfo; + return this; + } + + public File getTempDir() { + return tempDir; + } + + public Builder setTempDir(File tempDir) { + this.tempDir = tempDir; + return this; + } + + public Builder setAllowSuspendedRequests(List allowSuspendedRequests) { + this.allowSuspendedRequests = allowSuspendedRequests; + return this; + } + + public Builder setExternalResources(List externalResources) { + this.externalResources = externalResources; + return this; + } + + public UndertowDeploymentInfoService createUndertowDeploymentInfoService() { + return new UndertowDeploymentInfoService(mergedMetaData, deploymentName, tldInfo, module, + scisMetaData, deploymentRoot, jaccContextId, securityDomain, attributes, contextPath, setupActions, overlays, + expressionFactoryWrappers, predicatedHandlers, initialHandlerChainWrappers, innerHandlerChainWrappers, outerHandlerChainWrappers, + threadSetupActions, explodedDeployment, servletExtensions, sharedSessionManagerConfig, webSocketDeploymentInfo, tempDir, externalResources, allowSuspendedRequests); + } + } + + private static class UndertowThreadSetupAction implements ThreadSetupHandler { + + private final SetupAction action; + + private UndertowThreadSetupAction(SetupAction action) { + this.action = action; + } + + @Override + public Action create(Action action) { + return (exchange, context) -> { + UndertowThreadSetupAction.this.action.setup(Collections.emptyMap()); + try { + return action.call(exchange, context); + } finally { + UndertowThreadSetupAction.this.action.teardown(Collections.emptyMap()); + } + }; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,721 @@ +/* + * 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.extension.undertow.deployment; + +import java.net.MalformedURLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +import javax.security.jacc.PolicyConfiguration; + +import org.apache.jasper.Constants; +import org.apache.jasper.deploy.FunctionInfo; +import org.apache.jasper.deploy.TagAttributeInfo; +import org.apache.jasper.deploy.TagFileInfo; +import org.apache.jasper.deploy.TagInfo; +import org.apache.jasper.deploy.TagLibraryInfo; +import org.apache.jasper.deploy.TagLibraryValidatorInfo; +import org.apache.jasper.deploy.TagVariableInfo; +import org.jboss.annotation.javaee.Icon; +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.clustering.controller.SimpleCapabilityServiceConfigurator; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.ee.component.ComponentRegistry; +import org.jboss.as.ee.component.EEModuleDescription; +import org.jboss.as.security.deployment.AbstractSecurityDeployer; +import org.jboss.as.security.deployment.SecurityAttachments; +import org.jboss.as.security.plugins.SecurityDomainContext; +import org.jboss.as.security.service.JaccService; +import org.jboss.as.security.service.SecurityDomainService; +import org.jboss.as.server.ServerEnvironment; +import org.jboss.as.server.ServerEnvironmentService; +import org.jboss.as.server.Services; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentResourceSupport; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.ExplodedDeploymentMarker; +import org.jboss.as.server.deployment.SetupAction; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.server.suspend.SuspendController; +import org.jboss.as.web.common.ExpressionFactoryWrapper; +import org.jboss.as.web.common.ServletContextAttribute; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.as.web.common.WebComponentDescription; +import org.jboss.as.web.common.WebInjectionContainer; +import org.jboss.as.web.session.SessionIdentifierCodec; +import org.jboss.dmr.ModelNode; +import org.jboss.metadata.ear.jboss.JBossAppMetaData; +import org.jboss.metadata.ear.spec.EarMetaData; +import org.jboss.metadata.javaee.spec.DescriptionGroupMetaData; +import org.jboss.metadata.javaee.spec.ParamValueMetaData; +import org.jboss.metadata.web.jboss.JBossServletMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.AttributeMetaData; +import org.jboss.metadata.web.spec.FunctionMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.TagFileMetaData; +import org.jboss.metadata.web.spec.TagMetaData; +import org.jboss.metadata.web.spec.TldMetaData; +import org.jboss.metadata.web.spec.VariableMetaData; +import org.jboss.modules.Module; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController.Mode; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.value.ImmediateValue; +import org.jboss.msc.value.InjectedValue; +import org.jboss.security.SecurityUtil; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.io.IOServices; +import org.wildfly.extension.requestcontroller.ControlPoint; +import org.wildfly.extension.requestcontroller.ControlPointService; +import org.wildfly.extension.requestcontroller.RequestControllerActivationMarker; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.DeploymentDefinition; +import org.wildfly.extension.undertow.Host; +import org.wildfly.extension.undertow.HostSingleSignOnDefinition; +import org.wildfly.extension.undertow.ServletContainerService; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowService; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.security.jacc.WarJACCDeployer; +import org.wildfly.extension.undertow.session.DistributableSessionIdentifierCodecServiceConfiguratorProvider; +import org.wildfly.extension.undertow.session.DistributableSessionManagerConfiguration; +import org.wildfly.extension.undertow.session.DistributableSessionManagerFactoryServiceConfiguratorProvider; +import org.wildfly.extension.undertow.session.SharedSessionManagerConfig; +import org.wildfly.extension.undertow.session.SimpleDistributableSessionManagerConfiguration; +import org.wildfly.extension.undertow.session.SimpleSessionIdentifierCodecServiceConfigurator; + +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.SessionManagerFactory; +import io.undertow.servlet.core.InMemorySessionManagerFactory; + +public class UndertowDeploymentProcessor implements DeploymentUnitProcessor { + + public static final String OLD_URI_PREFIX = "http://java.sun.com"; + public static final String NEW_URI_PREFIX = "http://xmlns.jcp.org"; + + + private final String defaultServer; + private final String defaultHost; + private final String defaultContainer; + private final String defaultSecurityDomain; + private final Predicate knownSecurityDomain; + /** + default module mappings, where we have key as name of default deployment, + for value we have Map.Entry which has key as server-name where deployment is bound to, + value is host name where deployment is bound to. + */ + private final DefaultDeploymentMappingProvider defaultModuleMappingProvider; + + public UndertowDeploymentProcessor(String defaultHost, final String defaultContainer, String defaultServer, String defaultSecurityDomain, Predicate knownSecurityDomain) { + this.defaultHost = defaultHost; + this.defaultSecurityDomain = defaultSecurityDomain; + this.defaultModuleMappingProvider = DefaultDeploymentMappingProvider.instance(); + if (defaultHost == null) { + throw UndertowLogger.ROOT_LOGGER.nullDefaultHost(); + } + this.defaultContainer = defaultContainer; + this.defaultServer = defaultServer; + this.knownSecurityDomain = knownSecurityDomain; + } + + @Override + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + + //install the control point for the top level deployment no matter what + if(RequestControllerActivationMarker.isRequestControllerEnabled(deploymentUnit)) { + if(deploymentUnit.getParent() == null) { + ControlPointService.install(phaseContext.getServiceTarget(), deploymentUnit.getName(), UndertowExtension.SUBSYSTEM_NAME); + } + } + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetaData == null) { + return; + } + String deploymentName; + if (deploymentUnit.getParent() == null) { + deploymentName = deploymentUnit.getName(); + } else { + deploymentName = deploymentUnit.getParent().getName() + "." + deploymentUnit.getName(); + } + + final Map.Entry severHost = defaultModuleMappingProvider.getMapping(deploymentName); + String defaultHostForDeployment; + String defaultServerForDeployment; + if (severHost != null) { + defaultServerForDeployment = severHost.getKey(); + defaultHostForDeployment = severHost.getValue(); + } else { + defaultServerForDeployment = this.defaultServer; + defaultHostForDeployment = this.defaultHost; + } + + String serverInstanceName = warMetaData.getMergedJBossWebMetaData().getServerInstanceName() == null ? defaultServerForDeployment : warMetaData.getMergedJBossWebMetaData().getServerInstanceName(); + String hostName = hostNameOfDeployment(warMetaData, defaultHostForDeployment); + processDeployment(warMetaData, deploymentUnit, phaseContext.getServiceTarget(), deploymentName, hostName, serverInstanceName); + } + + + private String hostNameOfDeployment(final WarMetaData metaData, String defaultHost) { + Collection hostNames = null; + if (metaData.getMergedJBossWebMetaData() != null) { + hostNames = metaData.getMergedJBossWebMetaData().getVirtualHosts(); + } + if (hostNames == null || hostNames.isEmpty()) { + hostNames = Collections.singleton(defaultHost); + } + String hostName = hostNames.iterator().next(); + if (hostName == null) { + throw UndertowLogger.ROOT_LOGGER.nullHostName(); + } + return hostName; + } + + private void processDeployment(final WarMetaData warMetaData, final DeploymentUnit deploymentUnit, final ServiceTarget serviceTarget, + final String deploymentName, final String hostName, final String serverInstanceName) + throws DeploymentUnitProcessingException { + ResourceRoot deploymentResourceRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT); + final VirtualFile deploymentRoot = deploymentResourceRoot.getRoot(); + final Module module = deploymentUnit.getAttachment(Attachments.MODULE); + if (module == null) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failedToResolveModule(deploymentUnit)); + } + final JBossWebMetaData metaData = warMetaData.getMergedJBossWebMetaData(); + final List setupActions = deploymentUnit.getAttachmentList(org.jboss.as.ee.component.Attachments.WEB_SETUP_ACTIONS); + CapabilityServiceSupport capabilitySupport = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); + + ScisMetaData scisMetaData = deploymentUnit.getAttachment(ScisMetaData.ATTACHMENT_KEY); + + final Set dependentComponents = new HashSet<>(); + // see AS7-2077 + // basically we want to ignore components that have failed for whatever reason + // if they are important they will be picked up when the web deployment actually starts + final List components = deploymentUnit.getAttachmentList(WebComponentDescription.WEB_COMPONENTS); + final Set failed = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.FAILED_COMPONENTS); + for (final ServiceName component : components) { + if (!failed.contains(component)) { + dependentComponents.add(component); + } + } + String servletContainerName = metaData.getServletContainerName(); + if(servletContainerName == null) { + servletContainerName = defaultContainer; + } + + boolean componentRegistryExists = true; + ComponentRegistry componentRegistry = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.COMPONENT_REGISTRY); + if (componentRegistry == null) { + componentRegistryExists = false; + //we do this to avoid lots of other null checks + //this will only happen if the EE subsystem is not installed + componentRegistry = new ComponentRegistry(null); + } + + final WebInjectionContainer injectionContainer = new WebInjectionContainer(module.getClassLoader(), componentRegistry); + + String jaccContextId = metaData.getJaccContextID(); + + if (jaccContextId == null) { + jaccContextId = deploymentUnit.getName(); + } + if (deploymentUnit.getParent() != null) { + jaccContextId = deploymentUnit.getParent().getName() + "!" + jaccContextId; + } + + final String pathName = pathNameOfDeployment(deploymentUnit, metaData); + + boolean securityEnabled = deploymentUnit.hasAttachment(SecurityAttachments.SECURITY_ENABLED); + + String tempSecurityDomain = metaData.getSecurityDomain(); + if (tempSecurityDomain == null) { + tempSecurityDomain = getJBossAppSecurityDomain(deploymentUnit); + } + tempSecurityDomain = tempSecurityDomain == null ? defaultSecurityDomain : SecurityUtil.unprefixSecurityDomain(tempSecurityDomain); + boolean known = tempSecurityDomain != null && knownSecurityDomain.test(tempSecurityDomain); + + final String securityDomain = (securityEnabled || known) ? tempSecurityDomain : null; + + final Set additionalDependencies = new HashSet<>(); + for (final SetupAction setupAction : setupActions) { + Set dependencies = setupAction.dependencies(); + if (dependencies != null) { + additionalDependencies.addAll(dependencies); + } + } + SharedSessionManagerConfig sharedSessionManagerConfig = deploymentUnit.getParent() != null ? deploymentUnit.getParent().getAttachment(UndertowAttachments.SHARED_SESSION_MANAGER_CONFIG) : null; + + if(!deploymentResourceRoot.isUsePhysicalCodeSource()) { + try { + deploymentUnit.addToAttachmentList(ServletContextAttribute.ATTACHMENT_KEY, new ServletContextAttribute(Constants.CODE_SOURCE_ATTRIBUTE_NAME, deploymentRoot.toURL())); + } catch (MalformedURLException e) { + throw new DeploymentUnitProcessingException(e); + } + } + + deploymentUnit.addToAttachmentList(ServletContextAttribute.ATTACHMENT_KEY, new ServletContextAttribute(Constants.PERMISSION_COLLECTION_ATTRIBUTE_NAME, deploymentUnit.getAttachment(Attachments.MODULE_PERMISSIONS))); + + additionalDependencies.addAll(warMetaData.getAdditionalDependencies()); + try { + String capability = HostSingleSignOnDefinition.HOST_SSO_CAPABILITY.fromBaseCapability(serverInstanceName, hostName).getName(); + capabilitySupport.getCapabilityRuntimeAPI(capability, Object.class); + additionalDependencies.add(capabilitySupport.getCapabilityServiceName(capability)); + } catch (CapabilityServiceSupport.NoSuchCapabilityException e) { + //ignore + } + + final ServiceName hostServiceName = UndertowService.virtualHostName(serverInstanceName, hostName); + final ServiceName legacyDeploymentServiceName = UndertowService.deploymentServiceName(serverInstanceName, hostName, pathName); + final ServiceName deploymentServiceName = UndertowService.deploymentServiceName(deploymentUnit.getServiceName()); + + + TldsMetaData tldsMetaData = deploymentUnit.getAttachment(TldsMetaData.ATTACHMENT_KEY); + UndertowDeploymentInfoService undertowDeploymentInfoService = UndertowDeploymentInfoService.builder() + .setAttributes(deploymentUnit.getAttachmentList(ServletContextAttribute.ATTACHMENT_KEY)) + .setContextPath(pathName) + .setDeploymentName(deploymentName) //todo: is this deployment name concept really applicable? + .setDeploymentRoot(deploymentRoot) + .setMergedMetaData(warMetaData.getMergedJBossWebMetaData()) + .setModule(module) + .setScisMetaData(scisMetaData) + .setJaccContextId(jaccContextId) + .setSecurityDomain(securityDomain) + .setTldInfo(createTldsInfo(tldsMetaData, tldsMetaData == null ? null : tldsMetaData.getSharedTlds(deploymentUnit))) + .setSetupActions(setupActions) + .setSharedSessionManagerConfig(sharedSessionManagerConfig) + .setOverlays(warMetaData.getOverlays()) + .setExpressionFactoryWrappers(deploymentUnit.getAttachmentList(ExpressionFactoryWrapper.ATTACHMENT_KEY)) + .setPredicatedHandlers(deploymentUnit.getAttachment(UndertowHandlersDeploymentProcessor.PREDICATED_HANDLERS)) + .setInitialHandlerChainWrappers(deploymentUnit.getAttachmentList(UndertowAttachments.UNDERTOW_INITIAL_HANDLER_CHAIN_WRAPPERS)) + .setInnerHandlerChainWrappers(deploymentUnit.getAttachmentList(UndertowAttachments.UNDERTOW_INNER_HANDLER_CHAIN_WRAPPERS)) + .setOuterHandlerChainWrappers(deploymentUnit.getAttachmentList(UndertowAttachments.UNDERTOW_OUTER_HANDLER_CHAIN_WRAPPERS)) + .setThreadSetupActions(deploymentUnit.getAttachmentList(UndertowAttachments.UNDERTOW_THREAD_SETUP_ACTIONS)) + .setServletExtensions(deploymentUnit.getAttachmentList(UndertowAttachments.UNDERTOW_SERVLET_EXTENSIONS)) + .setExplodedDeployment(ExplodedDeploymentMarker.isExplodedDeployment(deploymentUnit)) + .setWebSocketDeploymentInfo(deploymentUnit.getAttachment(UndertowAttachments.WEB_SOCKET_DEPLOYMENT_INFO)) + .setTempDir(warMetaData.getTempDir()) + .setExternalResources(deploymentUnit.getAttachmentList(UndertowAttachments.EXTERNAL_RESOURCES)) + .setAllowSuspendedRequests(deploymentUnit.getAttachmentList(UndertowAttachments.ALLOW_REQUEST_WHEN_SUSPENDED)) + .createUndertowDeploymentInfoService(); + + final ServiceName deploymentInfoServiceName = deploymentServiceName.append(UndertowDeploymentInfoService.SERVICE_NAME); + final ServiceName legacyDeploymentInfoServiceName = legacyDeploymentServiceName.append(UndertowDeploymentInfoService.SERVICE_NAME); + ServiceBuilder infoBuilder = serviceTarget.addService(deploymentInfoServiceName, undertowDeploymentInfoService) + .addAliases(legacyDeploymentInfoServiceName) + .addDependency(UndertowService.SERVLET_CONTAINER.append(servletContainerName), ServletContainerService.class, undertowDeploymentInfoService.getContainer()) + .addDependency(UndertowService.UNDERTOW, UndertowService.class, undertowDeploymentInfoService.getUndertowService()) + .addDependency(hostServiceName, Host.class, undertowDeploymentInfoService.getHost()) + .addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, undertowDeploymentInfoService.getServerEnvironmentInjectedValue()) + .addDependency(SuspendController.SERVICE_NAME, SuspendController.class, undertowDeploymentInfoService.getSuspendControllerInjectedValue()) + .addDependencies(additionalDependencies); + if(securityDomain != null) { + if (known) { + infoBuilder.addDependency( + deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT) + .getCapabilityServiceName( + Capabilities.CAPABILITY_APPLICATION_SECURITY_DOMAIN, + securityDomain), + BiFunction.class, undertowDeploymentInfoService.getSecurityFunctionInjector()); + } else { + infoBuilder.addDependency(SecurityDomainService.SERVICE_NAME.append(securityDomain), SecurityDomainContext.class, undertowDeploymentInfoService.getSecurityDomainContextValue()); + } + } + + if(RequestControllerActivationMarker.isRequestControllerEnabled(deploymentUnit)){ + String topLevelName; + if(deploymentUnit.getParent() == null) { + topLevelName = deploymentUnit.getName(); + } else { + topLevelName = deploymentUnit.getParent().getName(); + } + infoBuilder.addDependency(ControlPointService.serviceName(topLevelName, UndertowExtension.SUBSYSTEM_NAME), ControlPoint.class, undertowDeploymentInfoService.getControlPointInjectedValue()); + } + final Set seenExecutors = new HashSet(); + if (metaData.getExecutorName() != null) { + final InjectedValue executor = new InjectedValue(); + infoBuilder.addDependency(IOServices.WORKER.append(metaData.getExecutorName()), Executor.class, executor); + undertowDeploymentInfoService.addInjectedExecutor(metaData.getExecutorName(), executor); + seenExecutors.add(metaData.getExecutorName()); + } + if (metaData.getServlets() != null) { + for (JBossServletMetaData servlet : metaData.getServlets()) { + if (servlet.getExecutorName() != null && !seenExecutors.contains(servlet.getExecutorName())) { + final InjectedValue executor = new InjectedValue(); + infoBuilder.addDependency(IOServices.WORKER.append(servlet.getExecutorName()), Executor.class, executor); + undertowDeploymentInfoService.addInjectedExecutor(servlet.getExecutorName(), executor); + seenExecutors.add(servlet.getExecutorName()); + } + } + } + + if (componentRegistryExists) { + infoBuilder.addDependency(ComponentRegistry.serviceName(deploymentUnit), ComponentRegistry.class, undertowDeploymentInfoService.getComponentRegistryInjectedValue()); + } else { + undertowDeploymentInfoService.getComponentRegistryInjectedValue().setValue(new ImmediateValue<>(componentRegistry)); + } + + if (sharedSessionManagerConfig != null) { + infoBuilder.addDependency(deploymentUnit.getParent().getServiceName().append(SharedSessionManagerConfig.SHARED_SESSION_MANAGER_SERVICE_NAME), SessionManagerFactory.class, undertowDeploymentInfoService.getSessionManagerFactoryInjector()); + infoBuilder.addDependency(deploymentUnit.getParent().getServiceName().append(SharedSessionManagerConfig.SHARED_SESSION_IDENTIFIER_CODEC_SERVICE_NAME), SessionIdentifierCodec.class, undertowDeploymentInfoService.getSessionIdentifierCodecInjector()); + } else { + CapabilityServiceSupport support = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); + + CapabilityServiceConfigurator factoryConfigurator = getSessionManagerFactoryServiceConfigurator(deploymentServiceName, serverInstanceName, deploymentName, module, metaData, deploymentUnit.getAttachment(UndertowAttachments.SERVLET_CONTAINER_SERVICE)); + infoBuilder.addDependency(factoryConfigurator.getServiceName(), SessionManagerFactory.class, undertowDeploymentInfoService.getSessionManagerFactoryInjector()); + + CapabilityServiceConfigurator codecConfigurator = getSessionIdentifierCodecServiceConfigurator(deploymentServiceName, serverInstanceName, deploymentName, metaData); + infoBuilder.addDependency(codecConfigurator.getServiceName(), SessionIdentifierCodec.class, undertowDeploymentInfoService.getSessionIdentifierCodecInjector()); + + for (CapabilityServiceConfigurator configurator : Arrays.asList(factoryConfigurator, codecConfigurator)) { + configurator.configure(support).build(serviceTarget).install(); + } + } + + infoBuilder.install(); + + final UndertowDeploymentService service = new UndertowDeploymentService(injectionContainer, true); + final ServiceBuilder builder = serviceTarget.addService(deploymentServiceName, service) + .addAliases(legacyDeploymentServiceName) + .addDependencies(dependentComponents) + .addDependency(UndertowService.SERVLET_CONTAINER.append(defaultContainer), ServletContainerService.class, service.getContainer()) + .addDependency(hostServiceName, Host.class, service.getHost()) + .addDependencies(deploymentUnit.getAttachmentList(Attachments.WEB_DEPENDENCIES)) + .addDependency(deploymentInfoServiceName, DeploymentInfo.class, service.getDeploymentInfoInjectedValue()); + // inject the server executor which can be used by the WebDeploymentService for blocking tasks in start/stop + // of that service + Services.addServerExecutorDependency(builder, service.getServerExecutorInjector()); + builder.install(); + + deploymentUnit.addToAttachmentList(Attachments.DEPLOYMENT_COMPLETE_SERVICES, deploymentServiceName); + + + // adding JACC service + if(securityEnabled) { + AbstractSecurityDeployer deployer = new WarJACCDeployer(); + JaccService jaccService = deployer.deploy(deploymentUnit, jaccContextId); + if (jaccService != null) { + final ServiceName jaccServiceName = deploymentUnit.getServiceName().append(JaccService.SERVICE_NAME); + ServiceBuilder jaccBuilder = serviceTarget.addService(jaccServiceName, jaccService); + if (deploymentUnit.getParent() != null) { + // add dependency to parent policy + final DeploymentUnit parentDU = deploymentUnit.getParent(); + jaccBuilder.addDependency(parentDU.getServiceName().append(JaccService.SERVICE_NAME), PolicyConfiguration.class, + jaccService.getParentPolicyInjector()); + } + // add dependency to web deployment service + jaccBuilder.addDependency(deploymentServiceName); + jaccBuilder.setInitialMode(Mode.PASSIVE).install(); + } + } + + // Process the web related mgmt information + final DeploymentResourceSupport deploymentResourceSupport = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_RESOURCE_SUPPORT); + final ModelNode node = deploymentResourceSupport.getDeploymentSubsystemModel(UndertowExtension.SUBSYSTEM_NAME); + node.get(DeploymentDefinition.CONTEXT_ROOT.getName()).set("".equals(pathName) ? "/" : pathName); + node.get(DeploymentDefinition.VIRTUAL_HOST.getName()).set(hostName); + node.get(DeploymentDefinition.SERVER.getName()).set(serverInstanceName); + processManagement(deploymentUnit, metaData); + } + + private static CapabilityServiceConfigurator getSessionManagerFactoryServiceConfigurator(ServiceName deploymentServiceName, String serverName, String deploymentName, Module module, JBossWebMetaData metaData, ServletContainerService servletContainerService) { + + Integer maxActiveSessions = metaData.getMaxActiveSessions(); + if(maxActiveSessions == null && servletContainerService != null) { + maxActiveSessions = servletContainerService.getMaxSessions(); + } + ServiceName name = deploymentServiceName.append("session"); + if (metaData.getDistributable() != null) { + if (DistributableSessionManagerFactoryServiceConfiguratorProvider.INSTANCE.isPresent()) { + DistributableSessionManagerConfiguration config = new SimpleDistributableSessionManagerConfiguration(maxActiveSessions, metaData.getReplicationConfig(), serverName, deploymentName, module); + return DistributableSessionManagerFactoryServiceConfiguratorProvider.INSTANCE.get().getServiceConfigurator(name, config); + } + // Fallback to local session manager if server does not support clustering + UndertowLogger.ROOT_LOGGER.clusteringNotSupported(); + } + return new SimpleCapabilityServiceConfigurator<>(name, (maxActiveSessions != null) ? new InMemorySessionManagerFactory(maxActiveSessions) : new InMemorySessionManagerFactory()); + } + + private static CapabilityServiceConfigurator getSessionIdentifierCodecServiceConfigurator(ServiceName deploymentServiceName, String serverName, String deploymentName, JBossWebMetaData metaData) { + ServiceName name = deploymentServiceName.append("codec"); + if (metaData.getDistributable() != null) { + if (DistributableSessionIdentifierCodecServiceConfiguratorProvider.INSTANCE.isPresent()) { + return DistributableSessionIdentifierCodecServiceConfiguratorProvider.INSTANCE.get().getDeploymentServiceConfigurator(name, serverName, deploymentName); + } + // Fallback to simple codec if server does not support clustering + } + return new SimpleSessionIdentifierCodecServiceConfigurator(name, serverName); + } + + static String pathNameOfDeployment(final DeploymentUnit deploymentUnit, final JBossWebMetaData metaData) { + String pathName; + if (metaData.getContextRoot() == null) { + final EEModuleDescription description = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION); + if (description != null) { + // if there is an EEModuleDescription we need to take into account that the module name may have been overridden + pathName = "/" + description.getModuleName(); + } else { + pathName = "/" + deploymentUnit.getName().substring(0, deploymentUnit.getName().length() - 4); + } + } else { + pathName = metaData.getContextRoot(); + if (pathName.length() > 0 && pathName.charAt(0) != '/') { + pathName = "/" + pathName; + } + } + return pathName; + } + + //todo move to UndertowDeploymentService and use all registered servlets from Deployment instead of just one found by metadata + void processManagement(final DeploymentUnit unit, JBossWebMetaData metaData) { + final DeploymentResourceSupport deploymentResourceSupport = unit.getAttachment(Attachments.DEPLOYMENT_RESOURCE_SUPPORT); + for (final JBossServletMetaData servlet : metaData.getServlets()) { + try { + final String name = servlet.getName(); + final ModelNode node = deploymentResourceSupport.getDeploymentSubModel(UndertowExtension.SUBSYSTEM_NAME, PathElement.pathElement("servlet", name)); + node.get("servlet-class").set(servlet.getServletClass()); + node.get("servlet-name").set(servlet.getServletName()); + } catch (Exception e) { + // Should a failure in creating the mgmt view also make to the deployment to fail? + continue; + } + } + + } + + /** + * Try to obtain the security domain configured in jboss-app.xml at the ear level if available + */ + private String getJBossAppSecurityDomain(final DeploymentUnit deploymentUnit) { + String securityDomain = null; + DeploymentUnit parent = deploymentUnit.getParent(); + if (parent != null) { + final EarMetaData jbossAppMetaData = parent.getAttachment(org.jboss.as.ee.structure.Attachments.EAR_METADATA); + if (jbossAppMetaData instanceof JBossAppMetaData) { + securityDomain = ((JBossAppMetaData) jbossAppMetaData).getSecurityDomain(); + } + } + return securityDomain != null ? securityDomain.trim() : null; + } + + @Override + public void undeploy(final DeploymentUnit deploymentUnit) { + deploymentUnit.removeAttachment(ServletContextAttribute.ATTACHMENT_KEY); + } + + private static HashMap createTldsInfo(final TldsMetaData tldsMetaData, List sharedTlds) { + + final HashMap ret = new HashMap<>(); + if (tldsMetaData != null) { + if (tldsMetaData.getTlds() != null) { + for (Map.Entry tld : tldsMetaData.getTlds().entrySet()) { + createTldInfo(tld.getKey(), tld.getValue(), ret); + } + } + if (sharedTlds != null) { + for (TldMetaData metaData : sharedTlds) { + + createTldInfo(null, metaData, ret); + } + } + } + + //we also register them under the new namespaces + for (String k : new HashSet<>(ret.keySet())) { + if (k != null) { + if (k.startsWith(OLD_URI_PREFIX)) { + String newUri = k.replace(OLD_URI_PREFIX, NEW_URI_PREFIX); + ret.put(newUri, ret.get(k)); + } + } + } + + return ret; + } + + + + private static TagLibraryInfo createTldInfo(final String location, final TldMetaData tldMetaData, final HashMap ret) { + String relativeLocation = location; + String jarPath = null; + if (relativeLocation != null && relativeLocation.startsWith("/WEB-INF/lib/")) { + int pos = relativeLocation.indexOf('/', "/WEB-INF/lib/".length()); + if (pos > 0) { + jarPath = relativeLocation.substring(pos); + if (jarPath.startsWith("/")) { + jarPath = jarPath.substring(1); + } + relativeLocation = relativeLocation.substring(0, pos); + } + } + + TagLibraryInfo tagLibraryInfo = new TagLibraryInfo(); + if(tldMetaData.getListeners() != null) { + for (ListenerMetaData l : tldMetaData.getListeners()) { + tagLibraryInfo.addListener(l.getListenerClass()); + } + } + tagLibraryInfo.setTlibversion(tldMetaData.getTlibVersion()); + if (tldMetaData.getJspVersion() == null) { + tagLibraryInfo.setJspversion(tldMetaData.getVersion()); + } else { + tagLibraryInfo.setJspversion(tldMetaData.getJspVersion()); + } + tagLibraryInfo.setShortname(tldMetaData.getShortName()); + tagLibraryInfo.setUri(tldMetaData.getUri()); + if (tldMetaData.getDescriptionGroup() != null) { + tagLibraryInfo.setInfo(tldMetaData.getDescriptionGroup().getDescription()); + } + // Validator + if (tldMetaData.getValidator() != null) { + TagLibraryValidatorInfo tagLibraryValidatorInfo = new TagLibraryValidatorInfo(); + tagLibraryValidatorInfo.setValidatorClass(tldMetaData.getValidator().getValidatorClass()); + if (tldMetaData.getValidator().getInitParams() != null) { + for (ParamValueMetaData paramValueMetaData : tldMetaData.getValidator().getInitParams()) { + tagLibraryValidatorInfo.addInitParam(paramValueMetaData.getParamName(), paramValueMetaData.getParamValue()); + } + } + tagLibraryInfo.setValidator(tagLibraryValidatorInfo); + } + // Tag + if (tldMetaData.getTags() != null) { + for (TagMetaData tagMetaData : tldMetaData.getTags()) { + TagInfo tagInfo = new TagInfo(); + tagInfo.setTagName(tagMetaData.getName()); + tagInfo.setTagClassName(tagMetaData.getTagClass()); + tagInfo.setTagExtraInfo(tagMetaData.getTeiClass()); + if (tagMetaData.getBodyContent() != null) { + tagInfo.setBodyContent(tagMetaData.getBodyContent().toString()); + } + tagInfo.setDynamicAttributes(tagMetaData.getDynamicAttributes()); + // Description group + if (tagMetaData.getDescriptionGroup() != null) { + DescriptionGroupMetaData descriptionGroup = tagMetaData.getDescriptionGroup(); + if (descriptionGroup.getIcons() != null && descriptionGroup.getIcons().value() != null + && (descriptionGroup.getIcons().value().length > 0)) { + Icon icon = descriptionGroup.getIcons().value()[0]; + tagInfo.setLargeIcon(icon.largeIcon()); + tagInfo.setSmallIcon(icon.smallIcon()); + } + tagInfo.setInfoString(descriptionGroup.getDescription()); + tagInfo.setDisplayName(descriptionGroup.getDisplayName()); + } + // Variable + if (tagMetaData.getVariables() != null) { + for (VariableMetaData variableMetaData : tagMetaData.getVariables()) { + TagVariableInfo tagVariableInfo = new TagVariableInfo(); + tagVariableInfo.setNameGiven(variableMetaData.getNameGiven()); + tagVariableInfo.setNameFromAttribute(variableMetaData.getNameFromAttribute()); + tagVariableInfo.setClassName(variableMetaData.getVariableClass()); + tagVariableInfo.setDeclare(variableMetaData.getDeclare()); + if (variableMetaData.getScope() != null) { + tagVariableInfo.setScope(variableMetaData.getScope().toString()); + } + tagInfo.addTagVariableInfo(tagVariableInfo); + } + } + // Attribute + if (tagMetaData.getAttributes() != null) { + for (AttributeMetaData attributeMetaData : tagMetaData.getAttributes()) { + TagAttributeInfo tagAttributeInfo = new TagAttributeInfo(); + tagAttributeInfo.setName(attributeMetaData.getName()); + tagAttributeInfo.setType(attributeMetaData.getType()); + tagAttributeInfo.setReqTime(attributeMetaData.getRtexprvalue()); + tagAttributeInfo.setRequired(attributeMetaData.getRequired()); + tagAttributeInfo.setFragment(attributeMetaData.getFragment()); + if (attributeMetaData.getDeferredValue() != null) { + tagAttributeInfo.setDeferredValue("true"); + tagAttributeInfo.setExpectedTypeName(attributeMetaData.getDeferredValue().getType()); + } else { + tagAttributeInfo.setDeferredValue("false"); + } + if (attributeMetaData.getDeferredMethod() != null) { + tagAttributeInfo.setDeferredMethod("true"); + tagAttributeInfo.setMethodSignature(attributeMetaData.getDeferredMethod().getMethodSignature()); + } else { + tagAttributeInfo.setDeferredMethod("false"); + } + tagInfo.addTagAttributeInfo(tagAttributeInfo); + } + } + tagLibraryInfo.addTagInfo(tagInfo); + } + } + // Tag files + if (tldMetaData.getTagFiles() != null) { + for (TagFileMetaData tagFileMetaData : tldMetaData.getTagFiles()) { + TagFileInfo tagFileInfo = new TagFileInfo(); + tagFileInfo.setName(tagFileMetaData.getName()); + tagFileInfo.setPath(tagFileMetaData.getPath()); + tagLibraryInfo.addTagFileInfo(tagFileInfo); + } + } + // Function + if (tldMetaData.getFunctions() != null) { + for (FunctionMetaData functionMetaData : tldMetaData.getFunctions()) { + FunctionInfo functionInfo = new FunctionInfo(); + functionInfo.setName(functionMetaData.getName()); + functionInfo.setFunctionClass(functionMetaData.getFunctionClass()); + functionInfo.setFunctionSignature(functionMetaData.getFunctionSignature()); + tagLibraryInfo.addFunctionInfo(functionInfo); + } + } + + if (jarPath == null && relativeLocation == null) { + if (!ret.containsKey(tagLibraryInfo.getUri())) { + ret.put(tagLibraryInfo.getUri(), tagLibraryInfo); + } + } else if (jarPath == null) { + tagLibraryInfo.setLocation(""); + tagLibraryInfo.setPath(relativeLocation); + if (!ret.containsKey(tagLibraryInfo.getUri())) { + ret.put(tagLibraryInfo.getUri(), tagLibraryInfo); + } + ret.put(relativeLocation, tagLibraryInfo); + } else { + tagLibraryInfo.setLocation(relativeLocation); + tagLibraryInfo.setPath(jarPath); + if (!ret.containsKey(tagLibraryInfo.getUri())) { + ret.put(tagLibraryInfo.getUri(), tagLibraryInfo); + } + if (jarPath.equals("META-INF/taglib.tld")) { + ret.put(relativeLocation, tagLibraryInfo); + } + } + return tagLibraryInfo; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowDeploymentService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,187 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.File; +import java.util.concurrent.ExecutorService; + +import io.undertow.server.HttpHandler; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; + +import javax.servlet.ServletException; + +import org.jboss.as.web.common.StartupContext; +import org.jboss.as.web.common.WebInjectionContainer; +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.Host; +import org.wildfly.extension.undertow.ServletContainerService; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Stuart Douglas + */ +public class UndertowDeploymentService implements Service { + + private final InjectedValue container = new InjectedValue<>(); + // used for blocking tasks in this Service's start/stop + private final InjectedValue serverExecutor = new InjectedValue(); + private final WebInjectionContainer webInjectionContainer; + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue deploymentInfoInjectedValue = new InjectedValue<>(); + private final boolean autostart; + + private volatile DeploymentManager deploymentManager; + + public UndertowDeploymentService(final WebInjectionContainer webInjectionContainer, boolean autostart) { + this.webInjectionContainer = webInjectionContainer; + this.autostart = autostart; + } + + @Override + public void start(final StartContext startContext) throws StartException { + if (autostart) { + // The start can trigger the web app context initialization which involves blocking tasks like + // servlet context initialization, startup servlet initialization lifecycles and such. Hence this needs to be done asynchronously + // to prevent the MSC threads from blocking + startContext.asynchronous(); + serverExecutor.getValue().submit(new Runnable() { + @Override + public void run() { + try { + startContext(); + startContext.complete(); + } catch (Throwable e) { + startContext.failed(new StartException(e)); + } + } + }); + } + } + + public void startContext() throws ServletException { + final ClassLoader old = Thread.currentThread().getContextClassLoader(); + DeploymentInfo deploymentInfo = deploymentInfoInjectedValue.getValue(); + Thread.currentThread().setContextClassLoader(deploymentInfo.getClassLoader()); + try { + StartupContext.setInjectionContainer(webInjectionContainer); + try { + deploymentManager = container.getValue().getServletContainer().addDeployment(deploymentInfo); + deploymentManager.deploy(); + HttpHandler handler = deploymentManager.start(); + Deployment deployment = deploymentManager.getDeployment(); + host.getValue().registerDeployment(deployment, handler); + } finally { + StartupContext.setInjectionContainer(null); + } + } finally { + Thread.currentThread().setContextClassLoader(old); + } + } + + @Override + public void stop(final StopContext stopContext) { + // The service stop can trigger the web app context destruction which involves blocking tasks like servlet context destruction, startup servlet + // destruction lifecycles and such. Hence this needs to be done asynchronously to prevent the MSC threads from blocking + stopContext.asynchronous(); + serverExecutor.getValue().submit(new Runnable() { + @Override + public void run() { + try { + stopContext(); + } finally { + stopContext.complete(); + } + } + }); + + } + + public void stopContext() { + final ClassLoader old = Thread.currentThread().getContextClassLoader(); + DeploymentInfo deploymentInfo = deploymentInfoInjectedValue.getValue(); + Thread.currentThread().setContextClassLoader(deploymentInfo.getClassLoader()); + try { + if (deploymentManager != null) { + Deployment deployment = deploymentManager.getDeployment(); + try { + host.getValue().unregisterDeployment(deployment); + deploymentManager.stop(); + } catch (ServletException e) { + throw new RuntimeException(e); + } + deploymentManager.undeploy(); + container.getValue().getServletContainer().removeDeployment(deploymentInfoInjectedValue.getValue()); + } + recursiveDelete(deploymentInfoInjectedValue.getValue().getTempDir()); + } finally { + Thread.currentThread().setContextClassLoader(old); + } + } + + @Override + public UndertowDeploymentService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + + public InjectedValue getContainer() { + return container; + } + + public InjectedValue getHost() { + return host; + } + + public InjectedValue getDeploymentInfoInjectedValue() { + return deploymentInfoInjectedValue; + } + + public Deployment getDeployment(){ + return deploymentManager.getDeployment(); + } + + Injector getServerExecutorInjector() { + return this.serverExecutor; + } + + private static void recursiveDelete(File file) { + if(file == null) { + return; + } + File[] files = file.listFiles(); + if (files != null){ + for(File f : files) { + recursiveDelete(f); + } + } + if(!file.delete()) { + UndertowLogger.ROOT_LOGGER.couldNotDeleteTempFile(file); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowHandlersDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowHandlersDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowHandlersDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,139 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.server.handlers.builder.PredicatedHandler; +import io.undertow.server.handlers.builder.PredicatedHandlersParser; +import org.jboss.as.server.deployment.AttachmentKey; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.javaee.spec.ParamValueMetaData; +import org.jboss.metadata.web.jboss.HttpHandlerMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleIdentifier; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * DUP that handles undertow-handlers.conf, and handlers definded in jboss-web.xml + * + * @author Stuart Douglas + */ +public class UndertowHandlersDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String WEB_INF = "WEB-INF/undertow-handlers.conf"; + private static final String META_INF = "META-INF/undertow-handlers.conf"; + + public static final AttachmentKey> PREDICATED_HANDLERS = AttachmentKey.create(List.class); + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + final Module module = deploymentUnit.getAttachment(Attachments.MODULE); + if (module == null) { + return; + } + handleInfoFile(deploymentUnit, module); + handleJbossWebXml(deploymentUnit, module); + } + + private void handleJbossWebXml(DeploymentUnit deploymentUnit, Module module) throws DeploymentUnitProcessingException { + WarMetaData warMetadata = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetadata == null) { + return; + } + JBossWebMetaData merged = warMetadata.getMergedJBossWebMetaData(); + if (merged == null) { + return; + } + List handlers = merged.getHandlers(); + if (handlers == null) { + return; + } + for (HttpHandlerMetaData hander : handlers) { + try { + ClassLoader cl = module.getClassLoader(); + if (hander.getModule() != null) { + Module handlerModule = deploymentUnit.getAttachment(Attachments.SERVICE_MODULE_LOADER).loadModule(ModuleIdentifier.fromString(hander.getModule())); + cl = handlerModule.getClassLoader(); + + } + Class handlerClass = cl.loadClass(hander.getHandlerClass()); + Map params = new HashMap<>(); + if(hander.getParams() != null) { + for(ParamValueMetaData param : hander.getParams()) { + params.put(param.getParamName(), param.getParamValue()); + } + } + deploymentUnit.addToAttachmentList(UndertowAttachments.UNDERTOW_OUTER_HANDLER_CHAIN_WRAPPERS, new ConfiguredHandlerWrapper(handlerClass, params)); + } catch (Exception e) { + throw UndertowLogger.ROOT_LOGGER.failedToConfigureHandlerClass(hander.getHandlerClass(), e); + } + } + + } + + private void handleInfoFile(DeploymentUnit deploymentUnit, Module module) { + final List handlerWrappers = new ArrayList<>(); + ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); + try { + ResourceRoot root = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT); + VirtualFile config = root.getRoot().getChild(WEB_INF); + try { + if (config.exists()) { + handlerWrappers.addAll(PredicatedHandlersParser.parse(config.openStream(), module.getClassLoader())); + } + Enumeration paths = module.getClassLoader().getResources(META_INF); + while (paths.hasMoreElements()) { + URL path = paths.nextElement(); + handlerWrappers.addAll(PredicatedHandlersParser.parse(path.openStream(), module.getClassLoader())); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + if (!handlerWrappers.isEmpty()) { + deploymentUnit.putAttachment(PREDICATED_HANDLERS, handlerWrappers); + } + + } finally { + Thread.currentThread().setContextClassLoader(oldCl); + } + } + + @Override + public void undeploy(DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSPInstanceManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSPInstanceManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSPInstanceManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,85 @@ +/* + * 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.extension.undertow.deployment; + +import java.lang.reflect.InvocationTargetException; + +import javax.naming.NamingException; + +import org.apache.jasper.runtime.HttpJspBase; +import org.apache.tomcat.InstanceManager; +import org.jboss.as.web.common.WebInjectionContainer; + +/** + * + * InstanceManager is evil and needs to go away + * + * + * We don't use web injection container for instances of org.apache.jasper.runtime.HttpJspBase, as it causes problems + * with JSP hot reload. Because a new JSP class has the same name the generated ID is exactly the same. + * + * + * @author Stuart Douglas + */ +public class UndertowJSPInstanceManager implements InstanceManager { + + private final WebInjectionContainer webInjectionContainer; + + public UndertowJSPInstanceManager(final WebInjectionContainer webInjectionContainer) { + this.webInjectionContainer = webInjectionContainer; + } + + @Override + public Object newInstance(final String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + return webInjectionContainer.newInstance(className); + } + + @Override + public Object newInstance(final String fqcn, final ClassLoader classLoader) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + return newInstance(classLoader.loadClass(fqcn)); + } + + @Override + public Object newInstance(final Class c) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException { + if(HttpJspBase.class.isAssignableFrom(c)) { + return c.newInstance(); + } + return webInjectionContainer.newInstance(c); + } + + @Override + public void newInstance(final Object o) throws IllegalAccessException, InvocationTargetException, NamingException { + if(o instanceof HttpJspBase) { + return; + } + webInjectionContainer.newInstance(o); + } + + @Override + public void destroyInstance(final Object o) throws IllegalAccessException, InvocationTargetException { + if(o instanceof HttpJspBase) { + return; + } + webInjectionContainer.destroyInstance(o); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSRWebSocketDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSRWebSocketDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowJSRWebSocketDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,246 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.websockets.jsr.JsrWebSocketLogger; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; +import org.jboss.as.controller.PathElement; +import org.jboss.as.ee.utils.ClassLoadingUtils; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentResourceSupport; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.annotation.CompositeIndex; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.dmr.ModelNode; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.modules.Module; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.websocket.ClientEndpoint; +import javax.websocket.Endpoint; +import javax.websocket.server.ServerApplicationConfig; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Deployment processor for native JSR-356 websockets + *

+ * + * @author Stuart Douglas + */ +public class UndertowJSRWebSocketDeploymentProcessor implements DeploymentUnitProcessor { + + private static final DotName SERVER_ENDPOINT = DotName.createSimple(ServerEndpoint.class.getName()); + private static final DotName CLIENT_ENDPOINT = DotName.createSimple(ClientEndpoint.class.getName()); + private static final DotName SERVER_APPLICATION_CONFIG = DotName.createSimple(ServerApplicationConfig.class.getName()); + private static final DotName ENDPOINT = DotName.createSimple(Endpoint.class.getName()); + + + @Override + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + + final Module module = deploymentUnit.getAttachment(Attachments.MODULE); + if (module == null) { + return; + } + + ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(module.getClassLoader()); + + + WarMetaData metaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (metaData == null || metaData.getMergedJBossWebMetaData() == null) { + return; + } + if(!metaData.getMergedJBossWebMetaData().isEnableWebSockets()) { + return; + } + + final Set> annotatedEndpoints = new HashSet<>(); + final Set> endpoints = new HashSet<>(); + final Set> config = new HashSet<>(); + + final CompositeIndex index = deploymentUnit.getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX); + + final List serverEndpoints = index.getAnnotations(SERVER_ENDPOINT); + if (serverEndpoints != null) { + for (AnnotationInstance endpoint : serverEndpoints) { + if (endpoint.target() instanceof ClassInfo) { + ClassInfo clazz = (ClassInfo) endpoint.target(); + try { + Class moduleClass = ClassLoadingUtils.loadClass(clazz.name().toString(), module); + if (!Modifier.isAbstract(moduleClass.getModifiers())) { + annotatedEndpoints.add(moduleClass); + } + } catch (ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.couldNotLoadWebSocketEndpoint(clazz.name().toString(), e); + } + } + } + } + + final List clientEndpoints = index.getAnnotations(CLIENT_ENDPOINT); + if (clientEndpoints != null) { + for (AnnotationInstance endpoint : clientEndpoints) { + if (endpoint.target() instanceof ClassInfo) { + ClassInfo clazz = (ClassInfo) endpoint.target(); + try { + Class moduleClass = ClassLoadingUtils.loadClass(clazz.name().toString(), module); + if (!Modifier.isAbstract(moduleClass.getModifiers())) { + annotatedEndpoints.add(moduleClass); + } + } catch (ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.couldNotLoadWebSocketEndpoint(clazz.name().toString(), e); + } + } + } + } + + final Set subclasses = index.getAllKnownImplementors(SERVER_APPLICATION_CONFIG); + + if (subclasses != null) { + for (final ClassInfo clazz : subclasses) { + try { + Class moduleClass = ClassLoadingUtils.loadClass(clazz.name().toString(), module); + if (!Modifier.isAbstract(moduleClass.getModifiers())) { + config.add((Class) moduleClass); + } + } catch (ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.couldNotLoadWebSocketConfig(clazz.name().toString(), e); + } + } + } + + final Set epClasses = index.getAllKnownSubclasses(ENDPOINT); + + if (epClasses != null) { + for (final ClassInfo clazz : epClasses) { + try { + Class moduleClass = ClassLoadingUtils.loadClass(clazz.name().toString(), module); + if (!Modifier.isAbstract(moduleClass.getModifiers())) { + endpoints.add((Class) moduleClass); + } + } catch (ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.couldNotLoadWebSocketConfig(clazz.name().toString(), e); + } + } + } + + WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); + + doDeployment(deploymentUnit, webSocketDeploymentInfo, annotatedEndpoints, config, endpoints); + + installWebsockets(phaseContext, webSocketDeploymentInfo); + + } finally { + Thread.currentThread().setContextClassLoader(oldCl); + } + + } + + private void installWebsockets(final DeploymentPhaseContext phaseContext, final WebSocketDeploymentInfo webSocketDeploymentInfo) { + DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + deploymentUnit.putAttachment(UndertowAttachments.WEB_SOCKET_DEPLOYMENT_INFO, webSocketDeploymentInfo); + } + + private void doDeployment(DeploymentUnit deploymentUnit, final WebSocketDeploymentInfo container, final Set> annotatedEndpoints, final Set> serverApplicationConfigClasses, final Set> endpoints) throws DeploymentUnitProcessingException { + + Set> allScannedEndpointImplementations = new HashSet<>(endpoints); + Set> allScannedAnnotatedEndpoints = new HashSet<>(annotatedEndpoints); + Set> newAnnotatatedEndpoints = new HashSet<>(); + Set serverEndpointConfigurations = new HashSet<>(); + + final Set configInstances = new HashSet<>(); + for (Class clazz : serverApplicationConfigClasses) { + try { + configInstances.add(clazz.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + JsrWebSocketLogger.ROOT_LOGGER.couldNotInitializeConfiguration(clazz, e); + } + } + + + if (!configInstances.isEmpty()) { + for (ServerApplicationConfig config : configInstances) { + Set> returnedEndpoints = config.getAnnotatedEndpointClasses(allScannedAnnotatedEndpoints); + if (returnedEndpoints != null) { + newAnnotatatedEndpoints.addAll(returnedEndpoints); + } + Set endpointConfigs = config.getEndpointConfigs(allScannedEndpointImplementations); + if (endpointConfigs != null) { + serverEndpointConfigurations.addAll(endpointConfigs); + } + } + } else { + newAnnotatatedEndpoints.addAll(allScannedAnnotatedEndpoints); + } + + //annotated endpoints first + for (Class endpoint : newAnnotatatedEndpoints) { + if(endpoint != null ) { + container.addEndpoint(endpoint); + ServerEndpoint annotation = endpoint.getAnnotation(ServerEndpoint.class); + if (annotation != null) { + String path = annotation.value(); + addManagementWebsocket(deploymentUnit, endpoint, path); + } + } + } + + for (final ServerEndpointConfig endpoint : serverEndpointConfigurations) { + if(endpoint != null) { + container.addEndpoint(endpoint); + addManagementWebsocket(deploymentUnit, endpoint.getEndpointClass(), endpoint.getPath()); + } + } + } + + void addManagementWebsocket(final DeploymentUnit unit, Class endpoint, String path) { + try { + final DeploymentResourceSupport deploymentResourceSupport = unit.getAttachment(Attachments.DEPLOYMENT_RESOURCE_SUPPORT); + //websockets don't have the concept of a name, however the path much be unique + final ModelNode node = deploymentResourceSupport.getDeploymentSubModel(UndertowExtension.SUBSYSTEM_NAME, PathElement.pathElement("websocket", path)); + node.get("endpoint-class").set(endpoint.getName()); + node.get("path").set(path); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.failedToRegisterWebsocket(endpoint, path, e); + } + } + + @Override + public void undeploy(final DeploymentUnit context) { + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowMetricsCollector.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowMetricsCollector.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowMetricsCollector.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,48 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.HashMap; +import java.util.Map; + +import io.undertow.server.handlers.MetricsHandler; +import io.undertow.servlet.api.MetricsCollector; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class UndertowMetricsCollector implements MetricsCollector { + private final Map metrics = new HashMap<>(); + + @Override + public void registerMetric(String name, MetricsHandler handler) { + metrics.put(name, handler); + } + + public MetricsHandler.MetricResult getMetrics(String name) { + if (metrics.containsKey(name)) { + return metrics.get(name).getMetrics(); + } + return null; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowServletContainerDependencyProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowServletContainerDependencyProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/UndertowServletContainerDependencyProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow.deployment; + +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Stuart Douglas + */ +public class UndertowServletContainerDependencyProcessor implements DeploymentUnitProcessor { + + private final String defaultServletContainer; + + public UndertowServletContainerDependencyProcessor(String defaultContainer) { + this.defaultServletContainer = defaultContainer; + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + if (warMetaData != null) { + String servletContainerName = defaultServletContainer; + final JBossWebMetaData metaData = warMetaData.getMergedJBossWebMetaData(); + if(metaData != null && metaData.getServletContainerName() != null) { + servletContainerName = metaData.getServletContainerName(); + } + phaseContext.addDeploymentDependency(UndertowService.SERVLET_CONTAINER.append(servletContainerName), UndertowAttachments.SERVLET_CONTAINER_SERVICE); + } + } + + @Override + public void undeploy(DeploymentUnit context) { + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/VirtualFileResource.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/VirtualFileResource.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/VirtualFileResource.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,276 @@ +/* + * 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.extension.undertow.deployment; + +import io.undertow.UndertowLogger; +import io.undertow.io.IoCallback; +import io.undertow.io.Sender; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.resource.Resource; +import io.undertow.util.DateUtils; +import io.undertow.util.ETag; +import io.undertow.util.MimeMappings; +import org.jboss.vfs.VirtualFile; +import org.xnio.FileAccess; +import org.xnio.IoUtils; +import org.xnio.Pooled; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author Stuart Douglas + */ +public class VirtualFileResource implements Resource { + + private final File resourceManagerRoot; + private final VirtualFile file; + private final String path; + + public VirtualFileResource(File resourceManagerRoot, final VirtualFile file, String path) { + this.resourceManagerRoot = resourceManagerRoot; + this.file = file; + this.path = path; + } + + @Override + public String getPath() { + return path; + } + + @Override + public Date getLastModified() { + return new Date(file.getLastModified()); + } + + @Override + public String getLastModifiedString() { + final Date lastModified = getLastModified(); + if (lastModified == null) { + return null; + } + return DateUtils.toDateString(lastModified); + } + + @Override + public ETag getETag() { + return null; + } + + @Override + public String getName() { + return file.getName(); + } + + @Override + public boolean isDirectory() { + return file.isDirectory(); + } + + @Override + public List list() { + final List resources = new ArrayList(); + for (VirtualFile child : file.getChildren()) { + resources.add(new VirtualFileResource(resourceManagerRoot, child, path)); + } + return resources; + } + + @Override + public String getContentType(final MimeMappings mimeMappings) { + final String fileName = file.getName(); + int index = fileName.lastIndexOf('.'); + if (index != -1 && index != fileName.length() - 1) { + return mimeMappings.getMimeType(fileName.substring(index + 1)); + } + return null; + } + + @Override + public void serve(final Sender sender, final HttpServerExchange exchange, final IoCallback callback) { + abstract class BaseFileTask implements Runnable { + protected volatile FileChannel fileChannel; + + protected boolean openFile() { + try { + fileChannel = exchange.getConnection().getWorker().getXnio().openFile(file.getPhysicalFile(), FileAccess.READ_ONLY); + } catch (FileNotFoundException e) { + exchange.setResponseCode(404); + callback.onException(exchange, sender, e); + return false; + } catch (IOException e) { + exchange.setResponseCode(500); + callback.onException(exchange, sender, e); + return false; + } + return true; + } + } + + class ServerTask extends BaseFileTask implements IoCallback { + + private Pooled pooled; + + @Override + public void run() { + if (fileChannel == null) { + if (!openFile()) { + return; + } + pooled = exchange.getConnection().getBufferPool().allocate(); + } + if (pooled != null) { + ByteBuffer buffer = pooled.getResource(); + try { + buffer.clear(); + int res = fileChannel.read(buffer); + if (res == -1) { + //we are done + pooled.free(); + IoUtils.safeClose(fileChannel); + callback.onComplete(exchange, sender); + return; + } + buffer.flip(); + sender.send(buffer, this); + } catch (IOException e) { + onException(exchange, sender, e); + } + } + + } + + @Override + public void onComplete(final HttpServerExchange exchange, final Sender sender) { + if (exchange.isInIoThread()) { + exchange.dispatch(this); + } else { + run(); + } + } + + @Override + public void onException(final HttpServerExchange exchange, final Sender sender, final IOException exception) { + UndertowLogger.REQUEST_IO_LOGGER.ioException(exception); + if (pooled != null) { + pooled.free(); + pooled = null; + } + IoUtils.safeClose(fileChannel); + if (!exchange.isResponseStarted()) { + exchange.setResponseCode(500); + } + callback.onException(exchange, sender, exception); + } + } + + class TransferTask extends BaseFileTask { + @Override + public void run() { + if (!openFile()) { + return; + } + + sender.transferFrom(fileChannel, new IoCallback() { + @Override + public void onComplete(HttpServerExchange exchange, Sender sender) { + try { + IoUtils.safeClose(fileChannel); + } finally { + callback.onComplete(exchange, sender); + } + } + + @Override + public void onException(HttpServerExchange exchange, Sender sender, IOException exception) { + try { + IoUtils.safeClose(fileChannel); + } finally { + callback.onException(exchange, sender, exception); + } + } + }); + } + } + + BaseFileTask task = new TransferTask(); + if (exchange.isInIoThread()) { + exchange.dispatch(task); + } else { + task.run(); + } + } + + @Override + public Long getContentLength() { + return file.getSize(); + } + + @Override + public String getCacheKey() { + return file.toString(); + } + + @Override + public File getFile() { + try { + return file.getPhysicalFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public File getResourceManagerRoot() { + return resourceManagerRoot; + } + + @Override + public URL getUrl() { + try { + return file.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + public Path getResourceManagerRootPath() { + return getResourceManagerRoot().toPath(); + } + + public Path getFilePath() { + if(getFile() == null) { + return null; + } + return getFile().toPath(); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarAnnotationDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarAnnotationDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarAnnotationDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,601 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.security.DeclareRoles; +import javax.annotation.security.RunAs; +import javax.servlet.annotation.MultipartConfig; +import javax.servlet.annotation.ServletSecurity; +import javax.servlet.annotation.WebFilter; +import javax.servlet.annotation.WebListener; +import javax.servlet.annotation.WebServlet; + +import org.jboss.annotation.javaee.Descriptions; +import org.jboss.annotation.javaee.DisplayNames; +import org.jboss.annotation.javaee.Icons; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.annotation.AnnotationIndexUtils; +import org.jboss.as.server.deployment.annotation.CompositeIndex; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.AnnotationValue; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Index; +import org.jboss.metadata.javaee.spec.DescriptionGroupMetaData; +import org.jboss.metadata.javaee.spec.DescriptionImpl; +import org.jboss.metadata.javaee.spec.DescriptionsImpl; +import org.jboss.metadata.javaee.spec.DisplayNameImpl; +import org.jboss.metadata.javaee.spec.DisplayNamesImpl; +import org.jboss.metadata.javaee.spec.IconImpl; +import org.jboss.metadata.javaee.spec.IconsImpl; +import org.jboss.metadata.javaee.spec.ParamValueMetaData; +import org.jboss.metadata.javaee.spec.RunAsMetaData; +import org.jboss.metadata.javaee.spec.SecurityRoleMetaData; +import org.jboss.metadata.javaee.spec.SecurityRolesMetaData; +import org.jboss.metadata.web.spec.AnnotationMetaData; +import org.jboss.metadata.web.spec.AnnotationsMetaData; +import org.jboss.metadata.web.spec.DispatcherType; +import org.jboss.metadata.web.spec.EmptyRoleSemanticType; +import org.jboss.metadata.web.spec.FilterMappingMetaData; +import org.jboss.metadata.web.spec.FilterMetaData; +import org.jboss.metadata.web.spec.FiltersMetaData; +import org.jboss.metadata.web.spec.HttpMethodConstraintMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.MultipartConfigMetaData; +import org.jboss.metadata.web.spec.ServletMappingMetaData; +import org.jboss.metadata.web.spec.ServletMetaData; +import org.jboss.metadata.web.spec.ServletSecurityMetaData; +import org.jboss.metadata.web.spec.ServletsMetaData; +import org.jboss.metadata.web.spec.TransportGuaranteeType; +import org.jboss.metadata.web.spec.WebMetaData; +import org.jboss.modules.ModuleIdentifier; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * Web annotation deployment processor. + * + * @author Emanuel Muckenhuber + * @author Remy Maucherat + */ +public class WarAnnotationDeploymentProcessor implements DeploymentUnitProcessor { + + private static final DotName webFilter = DotName.createSimple(WebFilter.class.getName()); + private static final DotName webListener = DotName.createSimple(WebListener.class.getName()); + private static final DotName webServlet = DotName.createSimple(WebServlet.class.getName()); + private static final DotName runAs = DotName.createSimple(RunAs.class.getName()); + private static final DotName declareRoles = DotName.createSimple(DeclareRoles.class.getName()); + private static final DotName multipartConfig = DotName.createSimple(MultipartConfig.class.getName()); + private static final DotName servletSecurity = DotName.createSimple(ServletSecurity.class.getName()); + + /** + * Process web annotations. + */ + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + Map annotationsMetaData = warMetaData.getAnnotationsMetaData(); + if (annotationsMetaData == null) { + annotationsMetaData = new HashMap(); + warMetaData.setAnnotationsMetaData(annotationsMetaData); + } + Map indexes = AnnotationIndexUtils.getAnnotationIndexes(deploymentUnit); + + // Process lib/*.jar + for (final Entry entry : indexes.entrySet()) { + final Index jarIndex = entry.getValue(); + annotationsMetaData.put(entry.getKey().getRootName(), processAnnotations(jarIndex)); + } + + Map additionalModelAnnotations = deploymentUnit.getAttachment(Attachments.ADDITIONAL_ANNOTATION_INDEXES_BY_MODULE); + if (additionalModelAnnotations != null) { + final List additional = new ArrayList(); + for (Entry entry : additionalModelAnnotations.entrySet()) { + for(Index index : entry.getValue().getIndexes()) { + additional.add(processAnnotations(index)); + } + } + warMetaData.setAdditionalModuleAnnotationsMetadata(additional); + } + } + + public void undeploy(final DeploymentUnit context) { + } + + /** + * Process a single index. + * + * @param index the annotation index + * + * @throws DeploymentUnitProcessingException + */ + protected WebMetaData processAnnotations(Index index) + throws DeploymentUnitProcessingException { + WebMetaData metaData = new WebMetaData(); + // @WebServlet + final List webServletAnnotations = index.getAnnotations(webServlet); + if (webServletAnnotations != null && webServletAnnotations.size() > 0) { + ServletsMetaData servlets = new ServletsMetaData(); + List servletMappings = new ArrayList(); + for (final AnnotationInstance annotation : webServletAnnotations) { + ServletMetaData servlet = new ServletMetaData(); + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebServletAnnotation(target)); + } + ClassInfo classInfo = ClassInfo.class.cast(target); + servlet.setServletClass(classInfo.toString()); + AnnotationValue nameValue = annotation.value("name"); + if (nameValue == null || nameValue.asString().isEmpty()) { + servlet.setName(classInfo.toString()); + } else { + servlet.setName(nameValue.asString()); + } + AnnotationValue loadOnStartup = annotation.value("loadOnStartup"); + if (loadOnStartup != null && loadOnStartup.asInt() >= 0) { + servlet.setLoadOnStartupInt(loadOnStartup.asInt()); + } + AnnotationValue asyncSupported = annotation.value("asyncSupported"); + if (asyncSupported != null) { + servlet.setAsyncSupported(asyncSupported.asBoolean()); + } + AnnotationValue initParamsValue = annotation.value("initParams"); + if (initParamsValue != null) { + AnnotationInstance[] initParamsAnnotations = initParamsValue.asNestedArray(); + if (initParamsAnnotations != null && initParamsAnnotations.length > 0) { + List initParams = new ArrayList(); + for (AnnotationInstance initParamsAnnotation : initParamsAnnotations) { + ParamValueMetaData initParam = new ParamValueMetaData(); + AnnotationValue initParamName = initParamsAnnotation.value("name"); + AnnotationValue initParamValue = initParamsAnnotation.value(); + if (initParamName == null || initParamValue == null) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebInitParamAnnotation(target)); + } + AnnotationValue initParamDescription = initParamsAnnotation.value("description"); + initParam.setParamName(initParamName.asString()); + initParam.setParamValue(initParamValue.asString()); + if (initParamDescription != null) { + Descriptions descriptions = getDescription(initParamDescription.asString()); + if (descriptions != null) { + initParam.setDescriptions(descriptions); + } + } + initParams.add(initParam); + } + servlet.setInitParam(initParams); + } + } + AnnotationValue descriptionValue = annotation.value("description"); + AnnotationValue displayNameValue = annotation.value("displayName"); + AnnotationValue smallIconValue = annotation.value("smallIcon"); + AnnotationValue largeIconValue = annotation.value("largeIcon"); + DescriptionGroupMetaData descriptionGroup = + getDescriptionGroup((descriptionValue == null) ? "" : descriptionValue.asString(), + (displayNameValue == null) ? "" : displayNameValue.asString(), + (smallIconValue == null) ? "" : smallIconValue.asString(), + (largeIconValue == null) ? "" : largeIconValue.asString()); + if (descriptionGroup != null) { + servlet.setDescriptionGroup(descriptionGroup); + } + ServletMappingMetaData servletMapping = new ServletMappingMetaData(); + servletMapping.setServletName(servlet.getName()); + List urlPatterns = new ArrayList(); + AnnotationValue urlPatternsValue = annotation.value("urlPatterns"); + if (urlPatternsValue != null) { + for (String urlPattern : urlPatternsValue.asStringArray()) { + urlPatterns.add(urlPattern); + } + } + urlPatternsValue = annotation.value(); + if (urlPatternsValue != null) { + for (String urlPattern : urlPatternsValue.asStringArray()) { + urlPatterns.add(urlPattern); + } + } + if (urlPatterns.size() > 0) { + servletMapping.setUrlPatterns(urlPatterns); + servletMappings.add(servletMapping); + } + servlets.add(servlet); + } + metaData.setServlets(servlets); + metaData.setServletMappings(servletMappings); + } + // @WebFilter + final List webFilterAnnotations = index.getAnnotations(webFilter); + if (webFilterAnnotations != null && webFilterAnnotations.size() > 0) { + FiltersMetaData filters = new FiltersMetaData(); + List filterMappings = new ArrayList(); + for (final AnnotationInstance annotation : webFilterAnnotations) { + FilterMetaData filter = new FilterMetaData(); + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebFilterAnnotation(target)); + } + ClassInfo classInfo = ClassInfo.class.cast(target); + filter.setFilterClass(classInfo.toString()); + AnnotationValue nameValue = annotation.value("filterName"); + if (nameValue == null || nameValue.asString().isEmpty()) { + filter.setName(classInfo.toString()); + } else { + filter.setName(nameValue.asString()); + } + AnnotationValue asyncSupported = annotation.value("asyncSupported"); + if (asyncSupported != null) { + filter.setAsyncSupported(asyncSupported.asBoolean()); + } + AnnotationValue initParamsValue = annotation.value("initParams"); + if (initParamsValue != null) { + AnnotationInstance[] initParamsAnnotations = initParamsValue.asNestedArray(); + if (initParamsAnnotations != null && initParamsAnnotations.length > 0) { + List initParams = new ArrayList(); + for (AnnotationInstance initParamsAnnotation : initParamsAnnotations) { + ParamValueMetaData initParam = new ParamValueMetaData(); + AnnotationValue initParamName = initParamsAnnotation.value("name"); + AnnotationValue initParamValue = initParamsAnnotation.value(); + if (initParamName == null || initParamValue == null) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebInitParamAnnotation(target)); + } + AnnotationValue initParamDescription = initParamsAnnotation.value("description"); + initParam.setParamName(initParamName.asString()); + initParam.setParamValue(initParamValue.asString()); + if (initParamDescription != null) { + Descriptions descriptions = getDescription(initParamDescription.asString()); + if (descriptions != null) { + initParam.setDescriptions(descriptions); + } + } + initParams.add(initParam); + } + filter.setInitParam(initParams); + } + } + AnnotationValue descriptionValue = annotation.value("description"); + AnnotationValue displayNameValue = annotation.value("displayName"); + AnnotationValue smallIconValue = annotation.value("smallIcon"); + AnnotationValue largeIconValue = annotation.value("largeIcon"); + DescriptionGroupMetaData descriptionGroup = + getDescriptionGroup((descriptionValue == null) ? "" : descriptionValue.asString(), + (displayNameValue == null) ? "" : displayNameValue.asString(), + (smallIconValue == null) ? "" : smallIconValue.asString(), + (largeIconValue == null) ? "" : largeIconValue.asString()); + if (descriptionGroup != null) { + filter.setDescriptionGroup(descriptionGroup); + } + filters.add(filter); + FilterMappingMetaData filterMapping = new FilterMappingMetaData(); + filterMapping.setFilterName(filter.getName()); + List urlPatterns = new ArrayList(); + List servletNames = new ArrayList(); + List dispatchers = new ArrayList(); + AnnotationValue urlPatternsValue = annotation.value("urlPatterns"); + if (urlPatternsValue != null) { + for (String urlPattern : urlPatternsValue.asStringArray()) { + urlPatterns.add(urlPattern); + } + } + urlPatternsValue = annotation.value(); + if (urlPatternsValue != null) { + for (String urlPattern : urlPatternsValue.asStringArray()) { + urlPatterns.add(urlPattern); + } + } + if (urlPatterns.size() > 0) { + filterMapping.setUrlPatterns(urlPatterns); + } + AnnotationValue servletNamesValue = annotation.value("servletNames"); + if (servletNamesValue != null) { + for (String servletName : servletNamesValue.asStringArray()) { + servletNames.add(servletName); + } + } + if (servletNames.size() > 0) { + filterMapping.setServletNames(servletNames); + } + AnnotationValue dispatcherTypesValue = annotation.value("dispatcherTypes"); + if (dispatcherTypesValue != null) { + for (String dispatcherValue : dispatcherTypesValue.asEnumArray()) { + dispatchers.add(DispatcherType.valueOf(dispatcherValue)); + } + } + if (dispatchers.size() > 0) { + filterMapping.setDispatchers(dispatchers); + } + if (urlPatterns.size() > 0 || servletNames.size() > 0) { + filterMappings.add(filterMapping); + } + } + metaData.setFilters(filters); + metaData.setFilterMappings(filterMappings); + } + // @WebListener + final List webListenerAnnotations = index.getAnnotations(webListener); + if (webListenerAnnotations != null && webListenerAnnotations.size() > 0) { + List listeners = new ArrayList(); + for (final AnnotationInstance annotation : webListenerAnnotations) { + ListenerMetaData listener = new ListenerMetaData(); + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebListenerAnnotation(target)); + } + ClassInfo classInfo = ClassInfo.class.cast(target); + listener.setListenerClass(classInfo.toString()); + AnnotationValue descriptionValue = annotation.value(); + if (descriptionValue != null) { + DescriptionGroupMetaData descriptionGroup = getDescriptionGroup(descriptionValue.asString()); + if (descriptionGroup != null) { + listener.setDescriptionGroup(descriptionGroup); + } + } + listeners.add(listener); + } + metaData.setListeners(listeners); + } + // @RunAs + final List runAsAnnotations = index.getAnnotations(runAs); + if (runAsAnnotations != null && runAsAnnotations.size() > 0) { + AnnotationsMetaData annotations = metaData.getAnnotations(); + if (annotations == null) { + annotations = new AnnotationsMetaData(); + metaData.setAnnotations(annotations); + } + for (final AnnotationInstance annotation : runAsAnnotations) { + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + continue; + } + ClassInfo classInfo = ClassInfo.class.cast(target); + AnnotationMetaData annotationMD = annotations.get(classInfo.toString()); + if (annotationMD == null) { + annotationMD = new AnnotationMetaData(); + annotationMD.setClassName(classInfo.toString()); + annotations.add(annotationMD); + } + if (annotation.value() == null) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidRunAsAnnotation(target)); + } + RunAsMetaData runAs = new RunAsMetaData(); + runAs.setRoleName(annotation.value().asString()); + annotationMD.setRunAs(runAs); + } + } + // @DeclareRoles + final List declareRolesAnnotations = index.getAnnotations(declareRoles); + if (declareRolesAnnotations != null && declareRolesAnnotations.size() > 0) { + SecurityRolesMetaData securityRoles = metaData.getSecurityRoles(); + if (securityRoles == null) { + securityRoles = new SecurityRolesMetaData(); + metaData.setSecurityRoles(securityRoles); + } + for (final AnnotationInstance annotation : declareRolesAnnotations) { + if (annotation.value() == null) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidDeclareRolesAnnotation(annotation.target())); + } + for (String role : annotation.value().asStringArray()) { + SecurityRoleMetaData sr = new SecurityRoleMetaData(); + sr.setRoleName(role); + securityRoles.add(sr); + } + } + } + // @MultipartConfig + final List multipartConfigAnnotations = index.getAnnotations(multipartConfig); + if (multipartConfigAnnotations != null && multipartConfigAnnotations.size() > 0) { + AnnotationsMetaData annotations = metaData.getAnnotations(); + if (annotations == null) { + annotations = new AnnotationsMetaData(); + metaData.setAnnotations(annotations); + } + for (final AnnotationInstance annotation : multipartConfigAnnotations) { + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidMultipartConfigAnnotation(target)); + } + ClassInfo classInfo = ClassInfo.class.cast(target); + AnnotationMetaData annotationMD = annotations.get(classInfo.toString()); + if (annotationMD == null) { + annotationMD = new AnnotationMetaData(); + annotationMD.setClassName(classInfo.toString()); + annotations.add(annotationMD); + } + MultipartConfigMetaData multipartConfig = new MultipartConfigMetaData(); + AnnotationValue locationValue = annotation.value("location"); + if (locationValue != null && locationValue.asString().length() > 0) { + multipartConfig.setLocation(locationValue.asString()); + } + AnnotationValue maxFileSizeValue = annotation.value("maxFileSize"); + if (maxFileSizeValue != null && maxFileSizeValue.asLong() != -1L) { + multipartConfig.setMaxFileSize(maxFileSizeValue.asLong()); + } + AnnotationValue maxRequestSizeValue = annotation.value("maxRequestSize"); + if (maxRequestSizeValue != null && maxRequestSizeValue.asLong() != -1L) { + multipartConfig.setMaxRequestSize(maxRequestSizeValue.asLong()); + } + AnnotationValue fileSizeThresholdValue = annotation.value("fileSizeThreshold"); + if (fileSizeThresholdValue != null && fileSizeThresholdValue.asInt() != 0) { + multipartConfig.setFileSizeThreshold(fileSizeThresholdValue.asInt()); + } + annotationMD.setMultipartConfig(multipartConfig); + } + } + // @ServletSecurity + final List servletSecurityAnnotations = index.getAnnotations(servletSecurity); + if (servletSecurityAnnotations != null && servletSecurityAnnotations.size() > 0) { + AnnotationsMetaData annotations = metaData.getAnnotations(); + if (annotations == null) { + annotations = new AnnotationsMetaData(); + metaData.setAnnotations(annotations); + } + for (final AnnotationInstance annotation : servletSecurityAnnotations) { + AnnotationTarget target = annotation.target(); + if (!(target instanceof ClassInfo)) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidServletSecurityAnnotation(target)); + } + ClassInfo classInfo = ClassInfo.class.cast(target); + AnnotationMetaData annotationMD = annotations.get(classInfo.toString()); + if (annotationMD == null) { + annotationMD = new AnnotationMetaData(); + annotationMD.setClassName(classInfo.toString()); + annotations.add(annotationMD); + } + ServletSecurityMetaData servletSecurity = new ServletSecurityMetaData(); + AnnotationValue httpConstraintValue = annotation.value(); + List rolesAllowed = new ArrayList(); + if (httpConstraintValue != null) { + AnnotationInstance httpConstraint = httpConstraintValue.asNested(); + AnnotationValue httpConstraintERSValue = httpConstraint.value(); + if (httpConstraintERSValue != null) { + servletSecurity.setEmptyRoleSemantic(EmptyRoleSemanticType.valueOf(httpConstraintERSValue.asEnum())); + } + AnnotationValue httpConstraintTGValue = httpConstraint.value("transportGuarantee"); + if (httpConstraintTGValue != null) { + servletSecurity.setTransportGuarantee(TransportGuaranteeType.valueOf(httpConstraintTGValue.asEnum())); + } + AnnotationValue rolesAllowedValue = httpConstraint.value("rolesAllowed"); + if (rolesAllowedValue != null) { + for (String role : rolesAllowedValue.asStringArray()) { + rolesAllowed.add(role); + } + } + } + servletSecurity.setRolesAllowed(rolesAllowed); + AnnotationValue httpMethodConstraintsValue = annotation.value("httpMethodConstraints"); + if (httpMethodConstraintsValue != null) { + AnnotationInstance[] httpMethodConstraints = httpMethodConstraintsValue.asNestedArray(); + if (httpMethodConstraints.length > 0) { + List methodConstraints = new ArrayList(); + for (AnnotationInstance httpMethodConstraint : httpMethodConstraints) { + HttpMethodConstraintMetaData methodConstraint = new HttpMethodConstraintMetaData(); + AnnotationValue httpMethodConstraintValue = httpMethodConstraint.value(); + if (httpMethodConstraintValue != null) { + methodConstraint.setMethod(httpMethodConstraintValue.asString()); + } + AnnotationValue httpMethodConstraintERSValue = httpMethodConstraint.value("emptyRoleSemantic"); + if (httpMethodConstraintERSValue != null) { + methodConstraint.setEmptyRoleSemantic(EmptyRoleSemanticType.valueOf(httpMethodConstraintERSValue.asEnum())); + } + AnnotationValue httpMethodConstraintTGValue = httpMethodConstraint.value("transportGuarantee"); + if (httpMethodConstraintTGValue != null) { + methodConstraint.setTransportGuarantee(TransportGuaranteeType.valueOf(httpMethodConstraintTGValue.asEnum())); + } + AnnotationValue rolesAllowedValue = httpMethodConstraint.value("rolesAllowed"); + rolesAllowed = new ArrayList(); + if (rolesAllowedValue != null) { + for (String role : rolesAllowedValue.asStringArray()) { + rolesAllowed.add(role); + } + } + methodConstraint.setRolesAllowed(rolesAllowed); + methodConstraints.add(methodConstraint); + } + servletSecurity.setHttpMethodConstraints(methodConstraints); + } + } + annotationMD.setServletSecurity(servletSecurity); + } + } + return metaData; + } + + protected Descriptions getDescription(String description) { + DescriptionsImpl descriptions = null; + if (description.length() > 0) { + DescriptionImpl di = new DescriptionImpl(); + di.setDescription(description); + descriptions = new DescriptionsImpl(); + descriptions.add(di); + } + return descriptions; + } + + protected DisplayNames getDisplayName(String displayName) { + DisplayNamesImpl displayNames = null; + if (displayName.length() > 0) { + DisplayNameImpl dn = new DisplayNameImpl(); + dn.setDisplayName(displayName); + displayNames = new DisplayNamesImpl(); + displayNames.add(dn); + } + return displayNames; + } + + protected Icons getIcons(String smallIcon, String largeIcon) { + IconsImpl icons = null; + if (smallIcon.length() > 0 || largeIcon.length() > 0) { + IconImpl i = new IconImpl(); + i.setSmallIcon(smallIcon); + i.setLargeIcon(largeIcon); + icons = new IconsImpl(); + icons.add(i); + } + return icons; + } + + protected DescriptionGroupMetaData getDescriptionGroup(String description) { + DescriptionGroupMetaData dg = null; + if (description.length() > 0) { + dg = new DescriptionGroupMetaData(); + Descriptions descriptions = getDescription(description); + dg.setDescriptions(descriptions); + } + return dg; + } + + protected DescriptionGroupMetaData getDescriptionGroup(String description, String displayName, String smallIcon, + String largeIcon) { + DescriptionGroupMetaData dg = null; + if (description.length() > 0 || displayName.length() > 0 || smallIcon.length() > 0 || largeIcon.length() > 0) { + dg = new DescriptionGroupMetaData(); + Descriptions descriptions = getDescription(description); + if (descriptions != null) + dg.setDescriptions(descriptions); + DisplayNames displayNames = getDisplayName(displayName); + if (displayNames != null) + dg.setDisplayNames(displayNames); + Icons icons = getIcons(smallIcon, largeIcon); + if (icons != null) + dg.setIcons(icons); + } + return dg; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarDeploymentInitializingProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarDeploymentInitializingProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarDeploymentInitializingProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,52 @@ +/* + * 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.extension.undertow.deployment; + +import java.util.Locale; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; + +/** + * Processor that marks a war deployment. + * + * @author John Bailey + * @author Thomas.Diesler@jboss.com + */ +public class WarDeploymentInitializingProcessor implements DeploymentUnitProcessor { + + public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + String deploymentName = deploymentUnit.getName().toLowerCase(Locale.ENGLISH); + if (deploymentName.endsWith(".war")) { + DeploymentTypeMarker.setType(DeploymentType.WAR, deploymentUnit); + } + } + + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarMetaDataProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarMetaDataProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarMetaDataProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,718 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.jboss.as.ee.component.DeploymentDescriptorEnvironment; +import org.jboss.as.ee.component.EEModuleDescription; +import org.jboss.as.ee.metadata.MetadataCompleteMarker; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.ear.spec.EarMetaData; +import org.jboss.metadata.javaee.spec.EmptyMetaData; +import org.jboss.metadata.javaee.spec.SecurityRolesMetaData; +import org.jboss.metadata.merge.javaee.spec.SecurityRolesMetaDataMerger; +import org.jboss.metadata.merge.web.jboss.JBossWebMetaDataMerger; +import org.jboss.metadata.merge.web.spec.WebCommonMetaDataMerger; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.AbsoluteOrderingMetaData; +import org.jboss.metadata.web.spec.OrderingElementMetaData; +import org.jboss.metadata.web.spec.WebCommonMetaData; +import org.jboss.metadata.web.spec.WebFragmentMetaData; +import org.jboss.metadata.web.spec.WebMetaData; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * Merge all metadata into a main JBossWebMetaData. + * + * @author Remy Maucherat + * @author Thomas.Diesler@jboss.com + */ +public class WarMetaDataProcessor implements DeploymentUnitProcessor { + + static final String VERSION = "4.0"; + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + + boolean isComplete = false; + WebMetaData specMetaData = warMetaData.getWebMetaData(); + if (specMetaData != null) { + isComplete = specMetaData.isMetadataComplete(); + } + + // Find all fragments that have been processed by deployers, and place + // them in a map keyed by location + LinkedList order = new LinkedList(); + List orderings = new ArrayList(); + HashSet jarsSet = new HashSet(); + Set overlays = new HashSet(); + Map scis = new HashMap(); + boolean fragmentFound = false; + Map webFragments = warMetaData.getWebFragmentsMetaData(); + List resourceRoots = deploymentUnit.getAttachmentList(Attachments.RESOURCE_ROOTS); + for (ResourceRoot resourceRoot : resourceRoots) { + if (resourceRoot.getRoot().getName().toLowerCase(Locale.ENGLISH).endsWith(".jar")) { + jarsSet.add(resourceRoot.getRootName()); + // Find overlays + VirtualFile overlay = resourceRoot.getRoot().getChild("META-INF/resources"); + if (overlay.exists()) { + overlays.add(overlay); + } + } + + + //we load SCI's directly from the war not just from jars + //not required by spec but other containers do it + //see WFLY-9081 + // Find ServletContainerInitializer services + VirtualFile sci = resourceRoot.getRoot().getChild("META-INF/services/javax.servlet.ServletContainerInitializer"); + if (sci.exists()) { + scis.put(resourceRoot.getRootName(), sci); + } + } + + if (!isComplete) { + HashSet jarsWithoutFragmentsSet = new HashSet(); + jarsWithoutFragmentsSet.addAll(jarsSet); + for (String jarName : webFragments.keySet()) { + fragmentFound = true; + WebFragmentMetaData fragmentMetaData = webFragments.get(jarName); + webFragments.put(jarName, fragmentMetaData); + WebOrdering webOrdering = new WebOrdering(); + webOrdering.setName(fragmentMetaData.getName()); + webOrdering.setJar(jarName); + jarsWithoutFragmentsSet.remove(jarName); + if (fragmentMetaData.getOrdering() != null) { + if (fragmentMetaData.getOrdering().getAfter() != null) { + for (OrderingElementMetaData orderingElementMetaData : fragmentMetaData.getOrdering().getAfter() + .getOrdering()) { + if (orderingElementMetaData.isOthers()) { + webOrdering.setAfterOthers(true); + } else { + webOrdering.addAfter(orderingElementMetaData.getName()); + } + } + } + if (fragmentMetaData.getOrdering().getBefore() != null) { + for (OrderingElementMetaData orderingElementMetaData : fragmentMetaData.getOrdering().getBefore() + .getOrdering()) { + if (orderingElementMetaData.isOthers()) { + webOrdering.setBeforeOthers(true); + } else { + webOrdering.addBefore(orderingElementMetaData.getName()); + } + } + } + } + orderings.add(webOrdering); + } + // If there is no fragment, still consider it for ordering as a + // fragment specifying no name and no order + for (String jarName : jarsWithoutFragmentsSet) { + WebOrdering ordering = new WebOrdering(); + ordering.setJar(jarName); + orderings.add(ordering); + } + + } + + if (!fragmentFound) { + // Drop the order as there is no fragment in the webapp + orderings.clear(); + } + + // Generate web fragments parsing order + AbsoluteOrderingMetaData absoluteOrderingMetaData = null; + if (!isComplete && specMetaData != null) { + absoluteOrderingMetaData = specMetaData.getAbsoluteOrdering(); + } + if (absoluteOrderingMetaData != null) { + // Absolute ordering from web.xml, any relative fragment ordering is ignored + int otherPos = -1; + int i = 0; + for (OrderingElementMetaData orderingElementMetaData : absoluteOrderingMetaData.getOrdering()) { + if (orderingElementMetaData.isOthers()) { + if (otherPos >= 0) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidMultipleOthers()); + } + otherPos = i; + } else { + boolean found = false; + for (WebOrdering ordering : orderings) { + if (orderingElementMetaData.getName().equals(ordering.getName())) { + order.add(ordering.getJar()); + jarsSet.remove(ordering.getJar()); + found = true; + break; + } + } + if (!found) { + UndertowLogger.ROOT_LOGGER.invalidAbsoluteOrdering(orderingElementMetaData.getName()); + } else { + i++; + } + } + } + if (otherPos >= 0) { + order.addAll(otherPos, jarsSet); + jarsSet.clear(); + } + } else if (orderings.size() > 0) { + // Resolve relative ordering + try { + resolveOrder(orderings, order); + } catch (IllegalStateException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrdering(), e); + } + jarsSet.clear(); + } else { + // No order specified + order.addAll(jarsSet); + jarsSet.clear(); + warMetaData.setNoOrder(true); + } + + if (UndertowLogger.ROOT_LOGGER.isDebugEnabled()) { + StringBuilder builder = new StringBuilder(); + builder.append("Resolved order: [ "); + for (String jar : order) { + builder.append(jar).append(' '); + } + builder.append(']'); + UndertowLogger.ROOT_LOGGER.debug(builder.toString()); + } + + warMetaData.setOrder(order); + warMetaData.setOverlays(overlays); + warMetaData.setScis(scis); + + Map annotationsMetaData = warMetaData.getAnnotationsMetaData(); + + // The fragments and corresponding annotations will need to be merged in order + // For each JAR in the order: + // - Merge the annotation metadata into the fragment meta data (unless the fragment exists and is meta data complete) + // - Merge the fragment metadata into merged fragment meta data + WebCommonMetaData mergedFragmentMetaData = new WebCommonMetaData(); + if (specMetaData == null) { + // If there is no web.xml, it has to be considered to be the latest version + specMetaData = new WebMetaData(); + specMetaData.setVersion(VERSION); + } + // Augment with meta data from annotations in /WEB-INF/classes + WebMetaData annotatedMetaData = annotationsMetaData.get("classes"); + if (annotatedMetaData != null) { + if (isComplete) { + // Discard @WebFilter, @WebListener and @WebServlet + annotatedMetaData.setFilters(null); + annotatedMetaData.setFilterMappings(null); + annotatedMetaData.setListeners(null); + annotatedMetaData.setServlets(null); + annotatedMetaData.setServletMappings(null); + } + WebCommonMetaDataMerger.augment(specMetaData, annotatedMetaData, null, true); + } + // Augment with meta data from fragments and annotations from the corresponding JAR + for (String jar : order) { + WebFragmentMetaData webFragmentMetaData = webFragments.get(jar); + if (webFragmentMetaData == null || isComplete) { + webFragmentMetaData = new WebFragmentMetaData(); + // Add non overriding default distributable flag + webFragmentMetaData.setDistributable(new EmptyMetaData()); + } + WebMetaData jarAnnotatedMetaData = annotationsMetaData.get(jar); + if ((isComplete || webFragmentMetaData.isMetadataComplete()) && jarAnnotatedMetaData != null) { + // Discard @WebFilter, @WebListener and @WebServlet + jarAnnotatedMetaData.setFilters(null); + jarAnnotatedMetaData.setFilterMappings(null); + jarAnnotatedMetaData.setListeners(null); + jarAnnotatedMetaData.setServlets(null); + jarAnnotatedMetaData.setServletMappings(null); + } + if (jarAnnotatedMetaData != null) { + // Merge annotations corresponding to the JAR + WebCommonMetaDataMerger.augment(webFragmentMetaData, jarAnnotatedMetaData, null, true); + } + // Merge fragment meta data according to the conflict rules + try { + WebCommonMetaDataMerger.augment(mergedFragmentMetaData, webFragmentMetaData, specMetaData, false); + } catch (Exception e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebFragment(jar), e); + } + } + // Augment with meta data from annotations from JARs excluded from the order + for (String jar : jarsSet) { + WebFragmentMetaData webFragmentMetaData = new WebFragmentMetaData(); + // Add non overriding default distributable flag + webFragmentMetaData.setDistributable(new EmptyMetaData()); + WebMetaData jarAnnotatedMetaData = annotationsMetaData.get(jar); + if (jarAnnotatedMetaData != null) { + // Discard @WebFilter, @WebListener and @WebServlet + jarAnnotatedMetaData.setFilters(null); + jarAnnotatedMetaData.setFilterMappings(null); + jarAnnotatedMetaData.setListeners(null); + jarAnnotatedMetaData.setServlets(null); + jarAnnotatedMetaData.setServletMappings(null); + } + if (jarAnnotatedMetaData != null) { + // Merge annotations corresponding to the JAR + WebCommonMetaDataMerger.augment(webFragmentMetaData, jarAnnotatedMetaData, null, true); + } + // Merge fragment meta data according to the conflict rules + try { + WebCommonMetaDataMerger.augment(mergedFragmentMetaData, webFragmentMetaData, specMetaData, false); + } catch (Exception e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.invalidWebFragment(jar), e); + } + } + + WebCommonMetaDataMerger.augment(specMetaData, mergedFragmentMetaData, null, true); + + List additional = warMetaData.getAdditionalModuleAnnotationsMetadata(); + if (additional != null && !isComplete) { + //augument with annotations from additional modules + for (WebMetaData annotations : additional) { + // Merge annotations corresponding to the JAR + WebCommonMetaDataMerger.augment(specMetaData, annotations, null, true); + } + } + + // Override with meta data (JBossWebMetaData) Create a merged view + JBossWebMetaData mergedMetaData = new JBossWebMetaData(); + JBossWebMetaData metaData = warMetaData.getJBossWebMetaData(); + JBossWebMetaDataMerger.merge(mergedMetaData, metaData, specMetaData); + + // FIXME: Incorporate any ear level overrides + warMetaData.setMergedJBossWebMetaData(mergedMetaData); + + if (mergedMetaData.isMetadataComplete()) { + MetadataCompleteMarker.setMetadataComplete(deploymentUnit, true); + } + + //now attach any JNDI binding related information to the deployment + if (mergedMetaData.getJndiEnvironmentRefsGroup() != null) { + final DeploymentDescriptorEnvironment bindings = new DeploymentDescriptorEnvironment("java:module/env/", mergedMetaData.getJndiEnvironmentRefsGroup()); + deploymentUnit.putAttachment(org.jboss.as.ee.component.Attachments.MODULE_DEPLOYMENT_DESCRIPTOR_ENVIRONMENT, bindings); + } + + //override module name if applicable + if (mergedMetaData.getModuleName() != null && !mergedMetaData.getModuleName().isEmpty()) { + final EEModuleDescription description = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION); + description.setModuleName(mergedMetaData.getModuleName()); + } + + //WFLY-3102 EJB in WAR should inherit WAR's security domain + if(mergedMetaData.getSecurityDomain() != null) { + final EEModuleDescription description = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION); + description.setDefaultSecurityDomain(mergedMetaData.getSecurityDomain()); + } + + //merge security roles from the ear + DeploymentUnit parent = deploymentUnit.getParent(); + if (parent != null) { + final EarMetaData earMetaData = parent.getAttachment(org.jboss.as.ee.structure.Attachments.EAR_METADATA); + if (earMetaData != null) { + SecurityRolesMetaData earSecurityRolesMetaData = earMetaData.getSecurityRoles(); + if(earSecurityRolesMetaData != null) { + if(mergedMetaData.getSecurityRoles() == null) { + mergedMetaData.setSecurityRoles(new SecurityRolesMetaData()); + } + SecurityRolesMetaDataMerger.merge(mergedMetaData.getSecurityRoles(), mergedMetaData.getSecurityRoles(), earSecurityRolesMetaData); + } + } + } + } + + @Override + public void undeploy(final DeploymentUnit context) { + } + + /** + * Utility class to associate the logical name with the JAR name, needed + * during the order resolving. + */ + protected static class WebOrdering implements Serializable { + + private static final long serialVersionUID = 5603203103871892211L; + + protected String jar = null; + protected String name = null; + protected List after = new ArrayList(); + protected List before = new ArrayList(); + protected boolean afterOthers = false; + protected boolean beforeOthers = false; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getAfter() { + return after; + } + + public void addAfter(String name) { + after.add(name); + } + + public List getBefore() { + return before; + } + + public void addBefore(String name) { + before.add(name); + } + + public String getJar() { + return jar; + } + + public void setJar(String jar) { + this.jar = jar; + } + + public boolean isAfterOthers() { + return afterOthers; + } + + public void setAfterOthers(boolean afterOthers) { + this.afterOthers = afterOthers; + } + + public boolean isBeforeOthers() { + return beforeOthers; + } + + public void setBeforeOthers(boolean beforeOthers) { + this.beforeOthers = beforeOthers; + } + + } + + protected static class Ordering { + protected WebOrdering ordering; + protected Set after = new HashSet(); + protected Set before = new HashSet(); + protected boolean afterOthers = false; + protected boolean beforeOthers = false; + + public boolean addAfter(Ordering ordering) { + return after.add(ordering); + } + + public boolean addBefore(Ordering ordering) { + return before.add(ordering); + } + + public void validate() { + isBefore(new Ordering()); + isAfter(new Ordering()); + } + + /** + * Check (recursively) if a fragment is before the specified fragment. + * + * @param ordering + * @return + */ + public boolean isBefore(Ordering ordering) { + return isBeforeInternal(ordering, new HashSet()); + } + + protected boolean isBeforeInternal(Ordering ordering, Set checked) { + checked.add(this); + if (before.contains(ordering)) { + return true; + } + Iterator beforeIterator = before.iterator(); + while (beforeIterator.hasNext()) { + Ordering check = beforeIterator.next(); + if (checked.contains(check)) { + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrdering(this.ordering.getJar())); + } + if (check.isBeforeInternal(ordering, checked)) { + return true; + } + } + return false; + } + + /** + * Check (recursively) if a fragment is after the specified fragment. + * + * @param ordering + * @return + */ + public boolean isAfter(Ordering ordering) { + return isAfterInternal(ordering, new HashSet()); + } + + protected boolean isAfterInternal(Ordering ordering, Set checked) { + checked.add(this); + if (after.contains(ordering)) { + return true; + } + Iterator afterIterator = after.iterator(); + while (afterIterator.hasNext()) { + Ordering check = afterIterator.next(); + if (checked.contains(check)) { + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrdering(this.ordering.getJar())); + } + if (check.isAfterInternal(ordering, checked)) { + return true; + } + } + return false; + } + + /** + * Check is a fragment marked as before others is after a fragment that + * is not. + * + * @return true if a fragment marked as before others is after a + * fragment that is not + */ + public boolean isLastBeforeOthers() { + if (!beforeOthers) { + throw new IllegalStateException(); + } + Iterator beforeIterator = before.iterator(); + while (beforeIterator.hasNext()) { + Ordering check = beforeIterator.next(); + if (!check.beforeOthers) { + return true; + } else if (check.isLastBeforeOthers()) { + return true; + } + } + return false; + } + + /** + * Check is a fragment marked as after others is before a fragment that + * is not. + * + * @return true if a fragment marked as after others is before a + * fragment that is not + */ + public boolean isFirstAfterOthers() { + if (!afterOthers) { + throw new IllegalStateException(); + } + Iterator afterIterator = after.iterator(); + while (afterIterator.hasNext()) { + Ordering check = afterIterator.next(); + if (!check.afterOthers) { + return true; + } else if (check.isFirstAfterOthers()) { + return true; + } + } + return false; + } + + } + + /** + * Generate the Jar processing order. + * + * @param webOrderings The list of orderings, as parsed from the fragments + * @param order The generated order list + */ + protected static void resolveOrder(List webOrderings, List order) { + List work = new ArrayList(); + + // Populate the work Ordering list + Iterator webOrderingsIterator = webOrderings.iterator(); + while (webOrderingsIterator.hasNext()) { + WebOrdering webOrdering = webOrderingsIterator.next(); + Ordering ordering = new Ordering(); + ordering.ordering = webOrdering; + ordering.afterOthers = webOrdering.isAfterOthers(); + ordering.beforeOthers = webOrdering.isBeforeOthers(); + if (ordering.afterOthers && ordering.beforeOthers) { + // Cannot be both after and before others + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingBeforeAndAfter(webOrdering.getJar())); + } + work.add(ordering); + } + + // Create double linked relationships between the orderings, + // and resolve names + Iterator workIterator = work.iterator(); + while (workIterator.hasNext()) { + Ordering ordering = workIterator.next(); + WebOrdering webOrdering = ordering.ordering; + Iterator after = webOrdering.getAfter().iterator(); + while (after.hasNext()) { + String name = after.next(); + Iterator workIterator2 = work.iterator(); + boolean found = false; + while (workIterator2.hasNext()) { + Ordering ordering2 = workIterator2.next(); + if (name.equals(ordering2.ordering.getName())) { + if (found) { + // Duplicate name + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingDuplicateName(webOrdering.getJar())); + } + ordering.addAfter(ordering2); + ordering2.addBefore(ordering); + found = true; + } + } + if (!found) { + // Unknown name + UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingUnknownName(webOrdering.getJar()); + } + } + Iterator before = webOrdering.getBefore().iterator(); + while (before.hasNext()) { + String name = before.next(); + Iterator workIterator2 = work.iterator(); + boolean found = false; + while (workIterator2.hasNext()) { + Ordering ordering2 = workIterator2.next(); + if (name.equals(ordering2.ordering.getName())) { + if (found) { + // Duplicate name + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingDuplicateName(webOrdering.getJar())); + } + ordering.addBefore(ordering2); + ordering2.addAfter(ordering); + found = true; + } + } + if (!found) { + // Unknown name + UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingUnknownName(webOrdering.getJar()); + } + } + } + + // Validate ordering + workIterator = work.iterator(); + while (workIterator.hasNext()) { + workIterator.next().validate(); + } + + // Create three ordered lists that will then be merged + List tempOrder = new ArrayList(); + + // Create the ordered list of fragments which are before others + workIterator = work.iterator(); + while (workIterator.hasNext()) { + Ordering ordering = workIterator.next(); + if (ordering.beforeOthers) { + // Insert at the first possible position + int insertAfter = -1; + boolean last = ordering.isLastBeforeOthers(); + int lastBeforeOthers = -1; + for (int i = 0; i < tempOrder.size(); i++) { + if (ordering.isAfter(tempOrder.get(i))) { + insertAfter = i; + } + if (tempOrder.get(i).beforeOthers) { + lastBeforeOthers = i; + } + } + int pos = insertAfter; + if (last && lastBeforeOthers > insertAfter) { + pos = lastBeforeOthers; + } + tempOrder.add(pos + 1, ordering); + } else if (ordering.afterOthers) { + // Insert at the last possible element + int insertBefore = tempOrder.size(); + boolean first = ordering.isFirstAfterOthers(); + int firstAfterOthers = tempOrder.size(); + for (int i = tempOrder.size() - 1; i >= 0; i--) { + if (ordering.isBefore(tempOrder.get(i))) { + insertBefore = i; + } + if (tempOrder.get(i).afterOthers) { + firstAfterOthers = i; + } + } + int pos = insertBefore; + if (first && firstAfterOthers < insertBefore) { + pos = firstAfterOthers; + } + tempOrder.add(pos, ordering); + } else { + // Insert according to other already inserted elements + int insertAfter = -1; + int insertBefore = tempOrder.size(); + for (int i = 0; i < tempOrder.size(); i++) { + if (ordering.isAfter(tempOrder.get(i)) || tempOrder.get(i).beforeOthers) { + insertAfter = i; + } + if (ordering.isBefore(tempOrder.get(i)) || tempOrder.get(i).afterOthers) { + insertBefore = i; + } + } + if (insertAfter > insertBefore) { + // Conflicting order (probably caught earlier) + throw new IllegalStateException(UndertowLogger.ROOT_LOGGER.invalidRelativeOrderingConflict(ordering.ordering.getJar())); + } + // Insert somewhere in the range + tempOrder.add(insertAfter + 1, ordering); + } + } + + // Create the final ordered list + Iterator tempOrderIterator = tempOrder.iterator(); + while (tempOrderIterator.hasNext()) { + Ordering ordering = tempOrderIterator.next(); + order.add(ordering.ordering.getJar()); + } + + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarStructureDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarStructureDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WarStructureDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,236 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.Closeable; +import java.io.File; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import io.undertow.util.FileUtils; +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.MountedDeploymentOverlay; +import org.jboss.as.server.deployment.PrivateSubDeploymentMarker; +import org.jboss.as.server.deployment.module.FilterSpecification; +import org.jboss.as.server.deployment.module.ModuleRootMarker; +import org.jboss.as.server.deployment.module.ModuleSpecification; +import org.jboss.as.server.deployment.module.MountHandle; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.server.deployment.module.TempFileProviderService; +import org.jboss.as.web.common.SharedTldsMetaDataBuilder; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.modules.filter.PathFilters; +import org.jboss.modules.security.ImmediatePermissionFactory; +import org.jboss.vfs.VFS; +import org.jboss.vfs.VirtualFile; +import org.jboss.vfs.VirtualFileFilter; +import org.jboss.vfs.VisitorAttributes; +import org.jboss.vfs.util.SuffixMatchFilter; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * Create and mount classpath entries in the .war deployment. + * + * @author Emanuel Muckenhuber + * @author Thomas.Diesler@jboss.com + */ +public class WarStructureDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String TEMP_DIR = "jboss.server.temp.dir"; + + public static final String WEB_INF_LIB = "WEB-INF/lib"; + public static final String WEB_INF_CLASSES = "WEB-INF/classes"; + public static final String META_INF = "META-INF"; + + private static final String WEB_INF_EXTERNAL_MOUNTS = "WEB-INF/undertow-external-mounts.conf"; + + public static final VirtualFileFilter DEFAULT_WEB_INF_LIB_FILTER = new SuffixMatchFilter(".jar", VisitorAttributes.DEFAULT); + + private final SharedTldsMetaDataBuilder sharedTldsMetaData; + + public WarStructureDeploymentProcessor(final SharedTldsMetaDataBuilder sharedTldsMetaData) { + this.sharedTldsMetaData = sharedTldsMetaData; + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + + final ResourceRoot deploymentResourceRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT); + + final VirtualFile deploymentRoot = deploymentResourceRoot.getRoot(); + if (deploymentRoot == null) { + return; + } + + // set the child first behaviour + final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION); + if (moduleSpecification == null) { + return; + } + moduleSpecification.setPrivateModule(true); + + // other sub deployments should not have access to classes in the war module + PrivateSubDeploymentMarker.mark(deploymentUnit); + + // we do not want to index the resource root, only WEB-INF/classes and WEB-INF/lib + deploymentResourceRoot.putAttachment(Attachments.INDEX_RESOURCE_ROOT, false); + + // Make sure the root does not end up in the module, only META-INF + deploymentResourceRoot.getExportFilters().add(new FilterSpecification(PathFilters.getMetaInfFilter(), true)); + deploymentResourceRoot.getExportFilters().add(new FilterSpecification(PathFilters.getMetaInfSubdirectoriesFilter(), true)); + deploymentResourceRoot.getExportFilters().add(new FilterSpecification(PathFilters.acceptAll(), false)); + ModuleRootMarker.mark(deploymentResourceRoot, true); + + // TODO: This needs to be ported to add additional resource roots the standard way + final MountHandle mountHandle = deploymentResourceRoot.getMountHandle(); + try { + // add standard resource roots, this should eventually replace ClassPathEntry + final List resourceRoots = createResourceRoots(deploymentRoot, deploymentUnit); + for (ResourceRoot root : resourceRoots) { + deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, root); + } + } catch (Exception e) { + throw new DeploymentUnitProcessingException(e); + } + // Add the war metadata + final WarMetaData warMetaData = new WarMetaData(); + deploymentUnit.putAttachment(WarMetaData.ATTACHMENT_KEY, warMetaData); + + String deploymentName; + if(deploymentUnit.getParent() == null) { + deploymentName = deploymentUnit.getName(); + } else { + deploymentName = deploymentUnit.getParent().getName() + "." + deploymentUnit.getName(); + } + + PathManager pathManager = deploymentUnit.getAttachment(Attachments.PATH_MANAGER); + + File tempDir = new File(pathManager.getPathEntry(TEMP_DIR).resolvePath(), deploymentName); + tempDir.mkdirs(); + warMetaData.setTempDir(tempDir); + + moduleSpecification.addPermissionFactory(new ImmediatePermissionFactory(new FilePermission(tempDir.getAbsolutePath() + File.separatorChar + "-", "read,write,delete"))); + + // Add the shared TLDs metadata + final TldsMetaData tldsMetaData = new TldsMetaData(); + tldsMetaData.setSharedTlds(sharedTldsMetaData); + deploymentUnit.putAttachment(TldsMetaData.ATTACHMENT_KEY, tldsMetaData); + + processExternalMounts(deploymentUnit, deploymentRoot); + } + + private void processExternalMounts(DeploymentUnit deploymentUnit, VirtualFile deploymentRoot) throws DeploymentUnitProcessingException { + VirtualFile mounts = deploymentRoot.getChild(WEB_INF_EXTERNAL_MOUNTS); + if(!mounts.exists()) { + return; + } + try (InputStream data = mounts.openStream()) { + String contents = FileUtils.readFile(data); + String[] lines = contents.split("\n"); + for(String line : lines) { + String trimmed = line; + int commentIndex = trimmed.indexOf("#"); + if(commentIndex > -1) { + trimmed = trimmed.substring(0, commentIndex); + } + trimmed = trimmed.trim(); + if(trimmed.isEmpty()) { + continue; + } + File path = new File(trimmed); + if(path.exists()) { + deploymentUnit.addToAttachmentList(UndertowAttachments.EXTERNAL_RESOURCES, path); + } else { + throw UndertowLogger.ROOT_LOGGER.couldNotFindExternalPath(path); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void undeploy(final DeploymentUnit context) { + } + + /** + * Create the resource roots for a .war deployment + * + * + * @param deploymentRoot the deployment root + * @return the resource roots + * @throws java.io.IOException for any error + */ + private List createResourceRoots(final VirtualFile deploymentRoot, final DeploymentUnit deploymentUnit) throws IOException, DeploymentUnitProcessingException { + final List entries = new ArrayList(); + // WEB-INF classes + final VirtualFile webinfClasses = deploymentRoot.getChild(WEB_INF_CLASSES); + if (webinfClasses.exists()) { + final ResourceRoot webInfClassesRoot = new ResourceRoot(webinfClasses.getName(), webinfClasses, null); + ModuleRootMarker.mark(webInfClassesRoot); + entries.add(webInfClassesRoot); + } + // WEB-INF lib + Map overlays = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_OVERLAY_LOCATIONS); + final VirtualFile webinfLib = deploymentRoot.getChild(WEB_INF_LIB); + if (webinfLib.exists()) { + final List archives = webinfLib.getChildren(DEFAULT_WEB_INF_LIB_FILTER); + for (final VirtualFile archive : archives) { + try { + + String relativeName = archive.getPathNameRelativeTo(deploymentRoot); + MountedDeploymentOverlay overlay = overlays.get(relativeName); + Closeable closable = null; + if(overlay != null) { + overlay.remountAsZip(false); + } else if (archive.isFile()) { + closable = VFS.mountZip(archive, archive, TempFileProviderService.provider()); + } else { + closable = null; + } + final ResourceRoot webInfArchiveRoot = new ResourceRoot(archive.getName(), archive, new MountHandle(closable)); + ModuleRootMarker.mark(webInfArchiveRoot); + entries.add(webInfArchiveRoot); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToProcessWebInfLib(archive), e); + } + } + } + return entries; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebComponentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebComponentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebComponentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,207 @@ +/* + * 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.extension.undertow.deployment; + +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.servlet.AsyncListener; + +import org.jboss.as.ee.component.Attachments; +import org.jboss.as.ee.component.ComponentDescription; +import org.jboss.as.ee.component.EEApplicationClasses; +import org.jboss.as.ee.component.EEModuleDescription; +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.annotation.CompositeIndex; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.as.web.common.WebComponentDescription; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.FilterMetaData; +import org.jboss.metadata.web.spec.ListenerMetaData; +import org.jboss.metadata.web.spec.ServletMetaData; +import org.jboss.metadata.web.spec.TagMetaData; +import org.jboss.metadata.web.spec.TldMetaData; + + +/** + * Processor that figures out what type of component a servlet/listener is, and registers the appropriate metadata. + * The different types are: + *

    + *
  • Managed Bean - If the servlet is annotated with the ManagedBean annotation
  • + *
  • CDI Bean - If the servlet is deployed in a bean archive
  • + *
  • EE Component - If this is an EE deployment and the servlet is not one of the above
  • + *
  • Normal Servlet - If the EE subsystem is disabled
  • + *
+ *

+ * For ManagedBean Servlets no action is necessary at this stage, as the servlet is already registered as a component. + * For CDI and EE components a component definition is added to the deployment. + *

+ * For now we are just using managed bean components as servlets. We may need a custom component type in future. + */ +public class WebComponentProcessor implements DeploymentUnitProcessor { + + /** + * Tags in these packages do not need to be computerized + */ + private static final String[] BUILTIN_TAGLIBS = {"org.apache.taglibs.standard", "com.sun.faces.taglib.jsf_core", "com.sun.faces.ext.taglib", "com.sun.faces.taglib.html_basic",}; + + /** + * Dotname for AsyncListener, which can be injected dynamically. + */ + private static final DotName ASYNC_LISTENER_INTERFACE = DotName.createSimple(AsyncListener.class.getName()); + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; + } + + final Map componentByClass = new HashMap(); + final EEModuleDescription moduleDescription = deploymentUnit.getAttachment(Attachments.EE_MODULE_DESCRIPTION); + final EEApplicationClasses applicationClassesDescription = deploymentUnit.getAttachment(Attachments.EE_APPLICATION_CLASSES_DESCRIPTION); + final CompositeIndex compositeIndex = deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.COMPOSITE_ANNOTATION_INDEX); + if (moduleDescription == null) { + return; //not an EE deployment + } + for (ComponentDescription component : moduleDescription.getComponentDescriptions()) { + componentByClass.put(component.getComponentClassName(), component); + } + + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + final TldsMetaData tldsMetaData = deploymentUnit.getAttachment(TldsMetaData.ATTACHMENT_KEY); + final Set classes = getAllComponentClasses(deploymentUnit, compositeIndex, warMetaData, tldsMetaData); + for (String clazz : classes) { + if (clazz == null || clazz.trim().isEmpty()) { + continue; + } + ComponentDescription description = componentByClass.get(clazz); + if (description != null) { + //for now just make sure it has a single view + //this will generally be a managed bean, but it could also be an EJB + //TODO: make sure the component is a managed bean + if (!(description.getViews().size() == 1)) { + throw UndertowLogger.ROOT_LOGGER.wrongComponentType(clazz); + } + } else { + //we do not make the standard tags into components, as there is no need + if (compositeIndex.getClassByName(DotName.createSimple(clazz)) == null) { + boolean found = false; + for (String pack : BUILTIN_TAGLIBS) { + if (clazz.startsWith(pack)) { + found = true; + break; + } + } + if(found) { + continue; + } + } + description = new WebComponentDescription(clazz, clazz, moduleDescription, deploymentUnit.getServiceName(), applicationClassesDescription); + moduleDescription.addComponent(description); + deploymentUnit.addToAttachmentList(WebComponentDescription.WEB_COMPONENTS, description.getStartServiceName()); + } + } + } + + @Override + public void undeploy(DeploymentUnit context) { + } + + /** + * Gets all classes that are eligible for injection etc + * + * @param metaData + * @return + */ + private Set getAllComponentClasses(DeploymentUnit deploymentUnit, CompositeIndex index, WarMetaData metaData, TldsMetaData tldsMetaData) { + final Set classes = new HashSet(); + getAllComponentClasses(metaData.getMergedJBossWebMetaData(), classes); + if (tldsMetaData == null) + return classes; + if (tldsMetaData.getSharedTlds(deploymentUnit) != null) + for (TldMetaData tldMetaData : tldsMetaData.getSharedTlds(deploymentUnit)) { + getAllComponentClasses(tldMetaData, classes); + } + if (tldsMetaData.getTlds() != null) + for (Map.Entry tldMetaData : tldsMetaData.getTlds().entrySet()) { + getAllComponentClasses(tldMetaData.getValue(), classes); + } + getAllAsyncListenerClasses(index, classes); + return classes; + } + + private void getAllComponentClasses(JBossWebMetaData metaData, Set classes) { + if (metaData.getServlets() != null) + for (ServletMetaData servlet : metaData.getServlets()) { + if (servlet.getServletClass() != null) { + classes.add(servlet.getServletClass()); + } + } + if (metaData.getFilters() != null) + for (FilterMetaData filter : metaData.getFilters()) { + classes.add(filter.getFilterClass()); + } + if (metaData.getListeners() != null) + for (ListenerMetaData listener : metaData.getListeners()) { + classes.add(listener.getListenerClass()); + } + } + + private void getAllComponentClasses(TldMetaData metaData, Set classes) { + if (metaData.getValidator() != null) { + classes.add(metaData.getValidator().getValidatorClass()); + } + if (metaData.getListeners() != null) + for (ListenerMetaData listener : metaData.getListeners()) { + classes.add(listener.getListenerClass()); + } + if (metaData.getTags() != null) + for (TagMetaData tag : metaData.getTags()) { + classes.add(tag.getTagClass()); + } + } + + private void getAllAsyncListenerClasses(CompositeIndex index, Set classes) { + if (index != null) { + Set classInfos = index.getAllKnownImplementors(ASYNC_LISTENER_INTERFACE); + for (ClassInfo classInfo : classInfos) { + if(!Modifier.isAbstract(classInfo.flags()) && !Modifier.isInterface(classInfo.flags())) { + classes.add(classInfo.name().toString()); + } + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebFragmentParsingDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebFragmentParsingDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebFragmentParsingDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,110 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.ee.structure.SpecDescriptorPropertyReplacement; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.parser.servlet.WebFragmentMetaDataParser; +import org.jboss.metadata.parser.util.NoopXMLResolver; +import org.jboss.metadata.web.spec.WebFragmentMetaData; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Remy Maucherat + */ +public class WebFragmentParsingDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String WEB_FRAGMENT_XML = "META-INF/web-fragment.xml"; + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + Map webFragments = warMetaData.getWebFragmentsMetaData(); + if (webFragments == null) { + webFragments = new HashMap(); + warMetaData.setWebFragmentsMetaData(webFragments); + } + List resourceRoots = deploymentUnit.getAttachmentList(Attachments.RESOURCE_ROOTS); + for (ResourceRoot resourceRoot : resourceRoots) { + if (resourceRoot.getRoot().getName().toLowerCase(Locale.ENGLISH).endsWith(".jar")) { + VirtualFile webFragment = resourceRoot.getRoot().getChild(WEB_FRAGMENT_XML); + if (webFragment.exists() && webFragment.isFile()) { + InputStream is = null; + try { + is = webFragment.openStream(); + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setXMLResolver(NoopXMLResolver.create()); + XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is); + + WebFragmentMetaData webFragmentMetaData = WebFragmentMetaDataParser.parse(xmlReader, SpecDescriptorPropertyReplacement.propertyReplacer(deploymentUnit)); + webFragments.put(resourceRoot.getRootName(), webFragmentMetaData); + /*Log message to inform that distributable is not set in web-fragment.xml while it is set in web.xml*/ + if (warMetaData.getWebMetaData() != null && warMetaData.getWebMetaData().getDistributable()!= null && webFragmentMetaData.getDistributable() == null) + UndertowLogger.ROOT_LOGGER.distributableDisabledInFragmentXml(deploymentUnit.getName(),resourceRoot.getRootName()); + } catch (XMLStreamException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(webFragment.toString(), e.getLocation().getLineNumber(), e.getLocation().getColumnNumber())); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(webFragment.toString()), e); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + // Ignore + } + } + } + } + } + } + + @Override + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebJBossAllParser.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebJBossAllParser.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebJBossAllParser.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,52 @@ +/* + * 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.extension.undertow.deployment; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +import org.jboss.as.ee.structure.JBossDescriptorPropertyReplacement; +import org.jboss.as.server.deployment.AttachmentKey; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.jbossallxml.JBossAllXMLParser; +import org.jboss.metadata.parser.jbossweb.JBossWebMetaDataParser; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.staxmapper.XMLExtendedStreamReader; + +/** + * The app client handler for jboss-all.xml + * + * @author Stuart Douglas + */ +public class WebJBossAllParser implements JBossAllXMLParser { + + public static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(JBossWebMetaData.class); + + public static final QName ROOT_ELEMENT = new QName("http://www.jboss.com/xml/ns/javaee", "jboss-web"); + + @Override + public JBossWebMetaData parse(final XMLExtendedStreamReader reader, final DeploymentUnit deploymentUnit) throws XMLStreamException { + return JBossWebMetaDataParser.parse(reader, JBossDescriptorPropertyReplacement.propertyReplacer(deploymentUnit)); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebParsingDeploymentProcessor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebParsingDeploymentProcessor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/deployment/WebParsingDeploymentProcessor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,155 @@ +/* + * 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.extension.undertow.deployment; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jboss.as.ee.structure.DeploymentType; +import org.jboss.as.ee.structure.DeploymentTypeMarker; +import org.jboss.as.ee.structure.SpecDescriptorPropertyReplacement; +import org.jboss.as.server.deployment.Attachments; +import org.jboss.as.server.deployment.DeploymentPhaseContext; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.as.server.deployment.DeploymentUnitProcessor; +import org.jboss.as.server.deployment.module.ResourceRoot; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.parser.servlet.WebMetaDataParser; +import org.jboss.metadata.parser.util.MetaDataElementParser; +import org.jboss.metadata.parser.util.XMLResourceResolver; +import org.jboss.metadata.parser.util.XMLSchemaValidator; +import org.jboss.metadata.web.spec.WebMetaData; +import org.jboss.vfs.VirtualFile; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.manager.WildFlySecurityManager; +import org.xml.sax.SAXException; + +/** + * @author Jean-Frederic Clere + * @author Thomas.Diesler@jboss.com + */ +public class WebParsingDeploymentProcessor implements DeploymentUnitProcessor { + + private static final String WEB_XML = "WEB-INF/web.xml"; + private final boolean schemaValidation; + + public WebParsingDeploymentProcessor() { + String property = WildFlySecurityManager.getPropertyPrivileged(XMLSchemaValidator.PROPERTY_SCHEMA_VALIDATION, "false"); + this.schemaValidation = Boolean.parseBoolean(property); + } + + @Override + public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException { + ClassLoader old = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(); + try { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(WebParsingDeploymentProcessor.class); + final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit(); + if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) { + return; // Skip non web deployments + } + final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT); + final VirtualFile alternateDescriptor = deploymentRoot.getAttachment(org.jboss.as.ee.structure.Attachments.ALTERNATE_WEB_DEPLOYMENT_DESCRIPTOR); + // Locate the descriptor + final VirtualFile webXml; + if (alternateDescriptor != null) { + webXml = alternateDescriptor; + } else { + webXml = deploymentRoot.getRoot().getChild(WEB_XML); + } + final WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY); + assert warMetaData != null; + if (webXml.exists()) { + InputStream is = null; + try { + is = webXml.openStream(); + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + + MetaDataElementParser.DTDInfo dtdInfo = new MetaDataElementParser.DTDInfo(); + inputFactory.setXMLResolver(dtdInfo); + final XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(is); + + WebMetaData webMetaData = WebMetaDataParser.parse(xmlReader, dtdInfo, SpecDescriptorPropertyReplacement.propertyReplacer(deploymentUnit)); + + if (schemaValidation && webMetaData.getSchemaLocation() != null) { + XMLSchemaValidator validator = new XMLSchemaValidator(new XMLResourceResolver()); + InputStream xmlInput = webXml.openStream(); + ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(WebMetaDataParser.class.getClassLoader()); + if (webMetaData.is23()) + validator.validate("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", xmlInput); + else if (webMetaData.is24()) + validator.validate("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", xmlInput); + else if (webMetaData.is25()) + validator.validate("http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd", xmlInput); + else if (webMetaData.is30()) + validator.validate("http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd", xmlInput); + else if (webMetaData.is31()) + validator.validate("http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd", xmlInput); + else if (webMetaData.getVersion() != null && webMetaData.getVersion().equals("4.0")) + validator.validate("http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd", xmlInput); + else + validator.validate("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", xmlInput); + } catch (SAXException e) { + throw new DeploymentUnitProcessingException("Failed to validate " + webXml, e); + } finally { + xmlInput.close(); + Thread.currentThread().setContextClassLoader(oldCl); + } + } + warMetaData.setWebMetaData(webMetaData); + + } catch (XMLStreamException e) { + Integer lineNumber = null; + Integer columnNumber = null; + if (e.getLocation() != null) { + lineNumber = e.getLocation().getLineNumber(); + columnNumber = e.getLocation().getColumnNumber(); + } + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(webXml.toString(), lineNumber, columnNumber), e); + } catch (IOException e) { + throw new DeploymentUnitProcessingException(UndertowLogger.ROOT_LOGGER.failToParseXMLDescriptor(webXml.toString()), e); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + // Ignore + } + } + } + } finally { + WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(old); + } + } + + @Override + public void undeploy(final DeploymentUnit context) { + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/BasicAuthHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/BasicAuthHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/BasicAuthHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,68 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Collection; +import java.util.Collections; + +import io.undertow.security.handlers.AuthenticationCallHandler; +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelType; + +/** + * TODO: This appears to be useless, we should probably get rid of it, or replace it with something useful + * + * + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +@Deprecated +public class BasicAuthHandler extends Filter { + + public static final BasicAuthHandler INSTANCE = new BasicAuthHandler(); + + public static final AttributeDefinition SECURITY_DOMAIN = new SimpleAttributeDefinitionBuilder("security-domain", ModelType.STRING) + .setRequired(true) + .setRestartAllServices() + .build(); + + private BasicAuthHandler() { + super("basic-auth"); + } + + @Override + public Collection getAttributes() { + return Collections.singleton(SECURITY_DOMAIN); + } + + @Override + public Class getHandlerClass() { + return AuthenticationCallHandler.class; + } + + @Override + protected Class[] getConstructorSignature() { + return new Class[] {HttpHandler.class}; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/CustomFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/CustomFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/CustomFilterDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,123 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import io.undertow.Handlers; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PropertiesAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.dmr.Property; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleIdentifier; +import org.jboss.modules.ModuleLoadException; +import org.jboss.modules.ModuleLoader; +import org.wildfly.extension.undertow.deployment.ConfiguredHandlerWrapper; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class CustomFilterDefinition extends Filter { + + public static final AttributeDefinition CLASS_NAME = new SimpleAttributeDefinitionBuilder("class-name", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + public static final AttributeDefinition MODULE = new SimpleAttributeDefinitionBuilder("module", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final PropertiesAttributeDefinition PARAMETERS = new PropertiesAttributeDefinition.Builder("parameters", true) + .setRequired(false) + .setWrapXmlElement(false) + .setXmlName("param") + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final CustomFilterDefinition INSTANCE = new CustomFilterDefinition(); + + private CustomFilterDefinition() { + super("custom-filter"); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(CLASS_NAME, MODULE, PARAMETERS); + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, ModelNode model, HttpHandler next) { + String className = model.get(CLASS_NAME.getName()).asString(); + String moduleName = model.get(MODULE.getName()).asString(); + Map params = unwrap(model); + UndertowLogger.ROOT_LOGGER.debugf("Creating http handler %s from module %s with parameters %s", className, moduleName, params); + Class clazz = getHandlerClass(className, moduleName); + ConfiguredHandlerWrapper wrapper = new ConfiguredHandlerWrapper(clazz, params); + if (predicate != null) { + return Handlers.predicate(predicate, wrapper.wrap(next), next); + } else { + return wrapper.wrap(next); + } + } + + @Override + protected Class[] getConstructorSignature() { + throw new IllegalStateException(); //should not be used, as the handler is constructed above + } + + protected Class getHandlerClass(String className, String moduleName) { + ModuleLoader moduleLoader = Module.getBootModuleLoader(); + try { + Module filterModule = moduleLoader.loadModule(ModuleIdentifier.fromString(moduleName)); + return filterModule.getClassLoader().loadClassLocal(className); + } catch (ModuleLoadException | ClassNotFoundException e) { + throw UndertowLogger.ROOT_LOGGER.couldNotLoadHandlerFromModule(className,moduleName,e); + } + } + + private Map unwrap(final ModelNode model) { + if (!model.hasDefined(PARAMETERS.getName())) { + return Collections.emptyMap(); + } + ModelNode modelProps = model.get(PARAMETERS.getName()); + Map props = new HashMap(); + for (Property p : modelProps.asPropertyList()) { + props.put(p.getName(), p.getValue().asString()); + } + return props; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ErrorPageDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ErrorPageDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ErrorPageDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,90 @@ +/* + * 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.extension.undertow.filters; + +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import io.undertow.Handlers; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.error.FileErrorPageHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class ErrorPageDefinition extends Filter{ + + public static final AttributeDefinition CODE = new SimpleAttributeDefinitionBuilder("code", ModelType.INT) + .setAllowExpression(true) + .setRequired(true) + .setRestartAllServices() + .build(); + public static final AttributeDefinition PATH = new SimpleAttributeDefinitionBuilder("path", ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setRestartAllServices() + .build(); + public static final Collection ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(CODE, PATH)); + public static final ErrorPageDefinition INSTANCE = new ErrorPageDefinition(); + + private ErrorPageDefinition() { + super(Constants.ERROR_PAGE); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + public Class getHandlerClass() { + return FileErrorPageHandler.class; + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, ModelNode model, HttpHandler next) { + int code = model.get(CODE.getName()).asInt(); + String path = model.get(PATH.getName()).asString(); + FileErrorPageHandler handler = new FileErrorPageHandler(Paths.get(path), code); + handler.setNext(next); + if(predicate == null) { + return handler; + } else { + return Handlers.predicate(predicate, handler, next); + } + + } + + @Override + protected Class[] getConstructorSignature() { + throw new IllegalStateException(); //should not be used, as the handler is constructed above + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ExpressionFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ExpressionFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ExpressionFilterDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,104 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.Handlers; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.builder.PredicatedHandler; +import io.undertow.server.handlers.builder.PredicatedHandlersParser; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.modules.Module; +import org.jboss.modules.ModuleIdentifier; +import org.jboss.modules.ModuleLoadException; +import org.jboss.modules.ModuleLoader; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class ExpressionFilterDefinition extends Filter { + + public static final AttributeDefinition EXPRESSION = new SimpleAttributeDefinitionBuilder("expression", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + public static final AttributeDefinition MODULE = new SimpleAttributeDefinitionBuilder("module", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final ExpressionFilterDefinition INSTANCE = new ExpressionFilterDefinition(); + + private ExpressionFilterDefinition() { + super("expression-filter"); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(EXPRESSION, MODULE); + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, ModelNode model, HttpHandler next) { + String expression = model.get(EXPRESSION.getName()).asString(); + String moduleName = null; + if (model.hasDefined(MODULE.getName())) { + moduleName = model.get(MODULE.getName()).asString(); + } + ClassLoader classLoader; + if (moduleName == null) { + classLoader = getClass().getClassLoader(); + } else { + try { + ModuleLoader moduleLoader = Module.getBootModuleLoader(); + Module filterModule = moduleLoader.loadModule(ModuleIdentifier.fromString(moduleName)); + classLoader = filterModule.getClassLoader(); + } catch (ModuleLoadException e) { + throw UndertowLogger.ROOT_LOGGER.couldNotLoadHandlerFromModule(expression, moduleName, e); + } + } + List handlers = PredicatedHandlersParser.parse(expression, classLoader); + UndertowLogger.ROOT_LOGGER.debugf("Creating http handler %s from module %s", expression, moduleName); + + if (predicate != null) { + return Handlers.predicate(predicate, Handlers.predicates(handlers, next), next); + } else { + return Handlers.predicates(handlers, next); + } + } + + @Override + protected Class[] getConstructorSignature() { + throw new IllegalStateException(); //should not be used, as the handler is constructed above + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FailoverStrategy.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FailoverStrategy.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FailoverStrategy.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,38 @@ +/* + * 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.extension.undertow.filters; + +/** + * @author Radoslav Husar + */ +public enum FailoverStrategy { + /** + * Failover target chosen via load balancing mechanism. + */ + LOAD_BALANCED, + /** + * Failover target chosen deterministically from the associated session identifier. + */ + DETERMINISTIC, + ; +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/Filter.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/Filter.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/Filter.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,113 @@ +/* + * 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.extension.undertow.filters; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; + +import io.undertow.Handlers; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.AbstractHandlerDefinition; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowService; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +abstract class Filter extends AbstractHandlerDefinition { + private String name; + + protected Filter(String name) { + super(name, Constants.FILTER); + this.name = name; + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + FilterAdd add = new FilterAdd(this); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + //registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(UndertowService.FILTER, add), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(UndertowService.FILTER, add), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + + } + + public HttpHandler createHttpHandler(final Predicate predicate, final ModelNode model, HttpHandler next) { + List attributes = new ArrayList<>(getAttributes()); + HttpHandler handler = createHandler(getHandlerClass(), model, attributes, next); + if (predicate != null) { + return Handlers.predicate(predicate, handler, next); + } else { + return handler; + } + } + + protected HttpHandler createHandler(Class handlerClass, final ModelNode model, List attributes, HttpHandler next) { + int numOfParams = attributes.size(); + if (next != null) { + numOfParams++; + } + try { + Constructor c = handlerClass.getDeclaredConstructor(getConstructorSignature()); + if (c.getParameterTypes().length == numOfParams) { + boolean match = true; + Object[] params = new Object[numOfParams]; + Class[] parameterTypes = c.getParameterTypes(); + int attrCounter = 0; + for (int i = 0; i < parameterTypes.length; i++) { + Class param = parameterTypes[i]; + if (param == String.class) { + params[i] = model.get(attributes.get(attrCounter).getName()).asString(); + attrCounter++; + } else if (param == Integer.class || param == int.class) { + params[i] = model.get(attributes.get(attrCounter).getName()).asInt(); + attrCounter++; + } else if (param == Long.class || param == long.class) { + params[i] = model.get(attributes.get(attrCounter).getName()).asLong(); + attrCounter++; + } else if (param == HttpHandler.class) { + params[i] = next; + } else { + match = false; + break; + } + } + if (match) { + return (HttpHandler) c.newInstance(params); + } + } + } catch (Throwable e) { + throw UndertowLogger.ROOT_LOGGER.cannotCreateHttpHandler(handlerClass, model, e); + } + throw UndertowLogger.ROOT_LOGGER.cannotCreateHttpHandler(handlerClass, model, null); + } + + protected abstract Class[] getConstructorSignature(); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,66 @@ +/* + * 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.extension.undertow.filters; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.extension.undertow.Handler; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class FilterAdd extends AbstractAddStepHandler { + + private Handler handler; + + FilterAdd(Handler handler) { + super(handler.getAttributes()); + this.handler = handler; + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final String name = context.getCurrentAddressValue(); + + final FilterService service = new FilterService(handler, getResolvedModel(context, model)); + final ServiceTarget target = context.getServiceTarget(); + target.addService(UndertowService.FILTER.append(name), service) + .setInitialMode(ServiceController.Mode.ON_DEMAND) + .install(); + } + + private ModelNode getResolvedModel(OperationContext context, ModelNode model) throws OperationFailedException { + ModelNode resolved = new ModelNode(); + for (AttributeDefinition attribute : attributes) { + resolved.get(attribute.getName()).set(attribute.resolveModelAttribute(context, model)); + } + return resolved; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterDefinitions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterDefinitions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterDefinitions.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,91 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.registry.AliasEntry; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class FilterDefinitions extends PersistentResourceDefinition { + + public static final FilterDefinitions INSTANCE = new FilterDefinitions(); + private static List FILTERS = Collections.unmodifiableList(Arrays.asList( + RequestLimitHandler.INSTANCE, + ResponseHeaderFilter.INSTANCE, + GzipFilter.INSTANCE, + ErrorPageDefinition.INSTANCE, + CustomFilterDefinition.INSTANCE, + ModClusterDefinition.INSTANCE, + ExpressionFilterDefinition.INSTANCE, + RewriteFilterDefinition.INSTANCE + )); + + private FilterDefinitions() { + super(UndertowExtension.PATH_FILTERS, + UndertowExtension.getResolver(Constants.FILTER), + new AbstractAddStepHandler(), + ReloadRequiredRemoveStepHandler.INSTANCE + ); + } + + @Override + public Collection getAttributes() { + return Collections.emptySet(); + } + + @Override + public List getChildren() { + return FILTERS; + } + + @Override + public void registerChildren(ManagementResourceRegistration resourceRegistration) { + super.registerChildren(resourceRegistration); + + PathElement targetPe = RequestLimitHandler.INSTANCE.getPathElement(); + AliasEntry aliasEntry = new AliasEntry(resourceRegistration.getSubModel(PathAddress.pathAddress(targetPe))) { + @Override + public PathAddress convertToTargetAddress(PathAddress aliasAddress, AliasContext aliasContext) { + PathElement pe = aliasAddress.getLastElement(); + + return aliasAddress.getParent().append(PathElement.pathElement(targetPe.getKey(), pe.getValue())); + } + }; + resourceRegistration.registerAlias(PathElement.pathElement("connection-limit"), aliasEntry); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRef.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRef.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRef.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,88 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.FilterLocation; +import org.wildfly.extension.undertow.UndertowFilter; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class FilterRef implements Service, UndertowFilter { + private final Predicate predicate; + private final int priority; + private final InjectedValue filter = new InjectedValue<>(); + private final InjectedValue location = new InjectedValue<>(); + + public FilterRef(Predicate predicate, int priority) { + this.predicate = predicate; + this.priority = priority; + } + + @Override + public void start(StartContext context) throws StartException { + location.getValue().addFilter(this); + } + + @Override + public void stop(StopContext context) { + location.getValue().removeFilter(this); + } + + InjectedValue getFilter() { + return filter; + } + + InjectedValue getLocation() { + return location; + } + + public HttpHandler createHttpHandler(HttpHandler next) { + return filter.getValue().createHttpHandler(predicate, next); + } + + public Predicate getPredicate() { + return predicate; + } + + public int getPriority() { + return priority; + } + + @Override + public FilterRef getValue() throws IllegalStateException { + return this; + } + + @Override + public HttpHandler wrap(HttpHandler handler) { + return filter.getValue().createHttpHandler(predicate, handler); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRefDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRefDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterRefDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,137 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Arrays; +import java.util.Collection; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.PredicateParser; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.FilterLocation; +import org.wildfly.extension.undertow.PredicateValidator; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class FilterRefDefinition extends PersistentResourceDefinition { + + public static final AttributeDefinition PREDICATE = new SimpleAttributeDefinitionBuilder("predicate", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setRestartAllServices() + .setValidator(PredicateValidator.INSTANCE) + .build(); + public static final AttributeDefinition PRIORITY = new SimpleAttributeDefinitionBuilder("priority", ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1)) + .setValidator(new IntRangeValidator(1, true, true)) + .setRestartAllServices() + .build(); + + public static final FilterRefDefinition INSTANCE = new FilterRefDefinition(); + + + private FilterRefDefinition() { + super(UndertowExtension.PATH_FILTER_REF, + UndertowExtension.getResolver(Constants.FILTER_REF), + new FilterRefAdd(), + new ServiceRemoveStepHandler(new FilterRefAdd()) { + @Override + protected ServiceName serviceName(String name, PathAddress address) { + return UndertowService.getFilterRefServiceName(address, name); + } + }); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(PREDICATE, PRIORITY); + } + + + static class FilterRefAdd extends AbstractAddStepHandler { + FilterRefAdd() { + super(FilterRefDefinition.PREDICATE, PRIORITY); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final String name = context.getCurrentAddressValue(); + + final String locationType = address.getElement(address.size() - 2).getKey(); + + ServiceName locationService; + + if(locationType.equals(Constants.HOST)) { + final PathAddress hostAddress = address.getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + locationService = context.getCapabilityServiceName(Capabilities.CAPABILITY_HOST, FilterLocation.class, serverName, hostName); + } else { + final PathAddress locationAddress = address.getParent(); + final PathAddress hostAddress = locationAddress.getParent(); + final PathAddress serverAddress = hostAddress.getParent(); + final String locationName = locationAddress.getLastElement().getValue(); + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + locationService = context.getCapabilityServiceName(Capabilities.CAPABILITY_LOCATION, FilterLocation.class, serverName, hostName, locationName); + } + + Predicate predicate = null; + if (model.hasDefined(PREDICATE.getName())) { + String predicateString = model.get(PREDICATE.getName()).asString(); + predicate = PredicateParser.parse(predicateString, getClass().getClassLoader()); + } + + int priority = PRIORITY.resolveModelAttribute(context, operation).asInt(); + final FilterRef service = new FilterRef(predicate, priority); + final ServiceTarget target = context.getServiceTarget(); + target.addService(UndertowService.getFilterRefServiceName(address, name), service) + .addDependency(UndertowService.FILTER.append(name), FilterService.class, service.getFilter()) + .addDependency(locationService, FilterLocation.class, service.getLocation()) + .setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/FilterService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,64 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.wildfly.extension.undertow.Handler; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class FilterService implements Service { + private final Handler handler; + private final ModelNode model; + + FilterService(Handler handler, ModelNode model) { + this.handler = handler; + this.model = model; + } + + @Override + public void start(StartContext context) throws StartException { + + } + + @Override + public void stop(StopContext context) { + + } + + public HttpHandler createHttpHandler(final Predicate predicate, HttpHandler next) { + return handler.createHttpHandler(predicate, model, next); + } + + @Override + public FilterService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilter.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilter.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/GzipFilter.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,57 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.predicate.Predicate; +import io.undertow.predicate.Predicates; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.encoding.ContentEncodingRepository; +import io.undertow.server.handlers.encoding.EncodingHandler; +import io.undertow.server.handlers.encoding.GzipEncodingProvider; +import org.jboss.dmr.ModelNode; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +public class GzipFilter extends Filter { + + + public static final GzipFilter INSTANCE = new GzipFilter(); + + private GzipFilter() { + super("gzip"); + } + + @Override + public HttpHandler createHttpHandler(final Predicate predicate, ModelNode model, HttpHandler next) { + EncodingHandler encodingHandler = new EncodingHandler(new ContentEncodingRepository() + .addEncodingHandler("gzip", new GzipEncodingProvider(), 50, predicate != null ? predicate : Predicates.truePredicate())); + encodingHandler.setNext(next); + return encodingHandler; + } + + @Override + protected Class[] getConstructorSignature() { + throw new IllegalStateException(); //should not be used, as the handler is constructed above + } +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,189 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.AttributeDefinition; +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.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * Runtime representation of a mod_cluster balancer + * + * @author Stuart Douglas + */ +class ModClusterBalancerDefinition extends SimpleResourceDefinition { + + public static ModClusterBalancerDefinition INSTANCE = new ModClusterBalancerDefinition(); + + public static final AttributeDefinition STICKY_SESSION_COOKIE = new SimpleAttributeDefinitionBuilder(Constants.STICKY_SESSION_COOKIE, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition STICKY_SESSION_PATH = new SimpleAttributeDefinitionBuilder(Constants.STICKY_SESSION_PATH, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition MAX_ATTEMPTS = new SimpleAttributeDefinitionBuilder(Constants.MAX_ATTEMPTS, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition WAIT_WORKER = new SimpleAttributeDefinitionBuilder(Constants.WAIT_WORKER, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition STICKY_SESSION = new SimpleAttributeDefinitionBuilder(Constants.STICKY_SESSION, ModelType.BOOLEAN) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition STICKY_SESSION_FORCE = new SimpleAttributeDefinitionBuilder(Constants.STICKY_SESSION_FORCE, ModelType.BOOLEAN) + .setRequired(false) + .setStorageRuntime() + .build(); + + + public static final AttributeDefinition STICKY_SESSION_REMOVE = new SimpleAttributeDefinitionBuilder(Constants.STICKY_SESSION_REMOVE, ModelType.BOOLEAN) + .setRequired(false) + .setStorageRuntime() + .build(); + + + private ModClusterBalancerDefinition() { + super(new Parameters(UndertowExtension.BALANCER, UndertowExtension.getResolver("handler", "mod-cluster", "balancer")) + .setRuntime()); + } + + @Override + public void registerChildren(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerSubModel(ModClusterNodeDefinition.INSTANCE); + resourceRegistration.registerSubModel(ModClusterLoadBalancingGroupDefinition.INSTANCE); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerReadOnlyAttribute(MAX_ATTEMPTS, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getMaxAttempts())); + } + }); + resourceRegistration.registerReadOnlyAttribute(STICKY_SESSION_COOKIE, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + final String stickySessionCookie = ctx.getStickySessionCookie(); + if(stickySessionCookie == null) { + context.getResult().set(new ModelNode()); + } else { + context.getResult().set(new ModelNode(stickySessionCookie)); + } + } + }); + + resourceRegistration.registerReadOnlyAttribute(STICKY_SESSION_PATH, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + final String stickySessionPath = ctx.getStickySessionPath(); + if(stickySessionPath == null) { + context.getResult().set(new ModelNode()); + } else { + context.getResult().set(new ModelNode(stickySessionPath)); + } + } + }); + + resourceRegistration.registerReadOnlyAttribute(WAIT_WORKER, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getWaitWorker())); + } + }); + + resourceRegistration.registerReadOnlyAttribute(STICKY_SESSION, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isStickySession())); + } + }); + resourceRegistration.registerReadOnlyAttribute(STICKY_SESSION_REMOVE, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isStickySessionRemove())); + } + }); + resourceRegistration.registerReadOnlyAttribute(STICKY_SESSION_FORCE, new AbstractBalancerOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isStickySessionForce())); + } + }); + } + + + private abstract class AbstractBalancerOperation implements OperationStepHandler { + + @Override + public final void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + PathAddress address = context.getCurrentAddress(); + int current = address.size() - 1; + String balancerName = address.getElement(current--).getValue(); + String modClusterName = address.getElement(current--).getValue(); + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.LoadBalancer balancer = service.getModCluster().getController().getStatus().getLoadBalancer(balancerName); + if (balancer == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + handleNode(context, balancer, operation); + } + + protected abstract void handleNode(OperationContext context, ModClusterStatus.LoadBalancer ctx, ModelNode operation) throws OperationFailedException ; + } + +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerResource.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerResource.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterBalancerResource.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,240 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModCluster; +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.PlaceholderResource; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import static org.wildfly.extension.undertow.Constants.LOAD_BALANCING_GROUP; +import static org.wildfly.extension.undertow.Constants.NODE; + +public class ModClusterBalancerResource implements Resource.ResourceEntry { + + private final String name; + private final String modClusterName; + private ModelNode model = new ModelNode(); + + public ModClusterBalancerResource(String name, String modClusterName) { + this.name = name; + this.modClusterName = modClusterName; + } + + @Override + public ModelNode getModel() { + return model; + } + + @Override + public void writeModel(final ModelNode newModel) { + this.model = newModel; + } + + @Override + public boolean isModelDefined() { + return true; + } + + @Override + public boolean hasChild(final PathElement element) { + if (NODE.equals(element.getKey())) { + return getChildrenNames(NODE).contains(element.getValue()); + } else if (LOAD_BALANCING_GROUP.equals(element.getKey())) { + return getChildrenNames(LOAD_BALANCING_GROUP).contains(element.getValue()); + } + return false; + } + + @Override + public Resource getChild(final PathElement element) { + if (NODE.equals(element.getKey())) { + if (getChildrenNames(NODE).contains(element.getValue())) { + return new ModClusterNodeResource(element.getValue(), this.name, modClusterName); + } + return null; + } else if (LOAD_BALANCING_GROUP.equals(element.getKey())) { + if (getChildrenNames(LOAD_BALANCING_GROUP).contains(element.getValue())) { + return new ModClusterNodeResource(element.getValue(), this.name, modClusterName); + } + return null; + } + return null; + } + + @Override + public Resource requireChild(final PathElement element) { + if (NODE.equals(element.getKey())) { + if (getChildrenNames(NODE).contains(element.getValue())) { + return new ModClusterNodeResource(element.getValue(), this.name, modClusterName); + } + throw new NoSuchResourceException(element); + } else if (LOAD_BALANCING_GROUP.equals(element.getKey())) { + if (getChildrenNames(LOAD_BALANCING_GROUP).contains(element.getValue())) { + return new ModClusterNodeResource(element.getValue(), this.name, modClusterName); + } + throw new NoSuchResourceException(element); + } + throw new NoSuchResourceException(element); + } + + @Override + public boolean hasChildren(final String childType) { + if (NODE.equals(childType)) { + return !getChildrenNames(NODE).isEmpty(); + } else if (LOAD_BALANCING_GROUP.equals(childType)) { + return !getChildrenNames(LOAD_BALANCING_GROUP).isEmpty(); + } + return false; + } + + @Override + public Resource navigate(final PathAddress address) { + final String element = address.getElement(0).getKey(); + if (address.size() > 0 && (NODE.equals(element) || LOAD_BALANCING_GROUP.equals(element))) { + final Resource subResource = requireChild(address.getElement(0)); + if(address.size() == 1) { + return subResource; + } else { + return subResource.navigate(address.subAddress(1)); + } + } + throw new NoSuchResourceException(address.getElement(0)); + } + + @Override + public Set getChildTypes() { + return Collections.singleton(NODE); + } + + @Override + public Set getChildrenNames(final String childType) { + if (NODE.equals(childType)) { + + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + return Collections.emptySet(); + } + ModCluster modCluster = service.getModCluster(); + ModClusterStatus status = modCluster.getController().getStatus(); + final Set result = new LinkedHashSet<>(); + ModClusterStatus.LoadBalancer balancer = status.getLoadBalancer(this.name); + for (ModClusterStatus.Node node : balancer.getNodes()) { + result.add(node.getName()); + } + return result; + } else if(LOAD_BALANCING_GROUP.equals(childType)) { + + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + return Collections.emptySet(); + } + ModCluster modCluster = service.getModCluster(); + ModClusterStatus status = modCluster.getController().getStatus(); + final Set result = new LinkedHashSet<>(); + ModClusterStatus.LoadBalancer balancer = status.getLoadBalancer(this.name); + for (ModClusterStatus.Node node : balancer.getNodes()) { + result.add(node.getDomain()); + } + return result; + } + return null; + } + + @Override + public Set getChildren(final String childType) { + if (NODE.equals(childType)) { + final Set names = getChildrenNames(childType); + final Set result = new LinkedHashSet<>(names.size()); + for (String name : names) { + result.add(new ModClusterNodeResource(name, this.name, modClusterName)); + } + return result; + } else if(LOAD_BALANCING_GROUP.equals(childType)) { + final Set names = getChildrenNames(childType); + final Set result = new LinkedHashSet<>(names.size()); + for (String name : names) { + result.add(new PlaceholderResource.PlaceholderResourceEntry(PathElement.pathElement(LOAD_BALANCING_GROUP, name))); + } + return result; + } + return Collections.emptySet(); + } + + @Override + public void registerChild(final PathElement address, final Resource resource) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + + @Override + public void registerChild(PathElement address, int index, Resource resource) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + + @Override + public Resource removeChild(final PathElement address) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRemoveResourceOfType(type); + } + + @Override + public boolean isRuntime() { + return true; + } + + @Override + public boolean isProxy() { + return false; + } + + @Override + public Set getOrderedChildTypes() { + return Collections.emptySet(); + } + + @Override + public Resource clone() { + return new ModClusterBalancerResource(name, modClusterName); + } + + @Override + public String getName() { + return name; + } + + @Override + public PathElement getPathElement() { + return PathElement.pathElement(Constants.BALANCER, name); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterContextDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterContextDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterContextDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,155 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.AttributeDefinition; +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.PathAddress; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinition; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * Runtime representation of a mod_cluster context + * + * @author Stuart Douglas + */ +class ModClusterContextDefinition extends SimpleResourceDefinition { + + public static ModClusterContextDefinition INSTANCE = new ModClusterContextDefinition(); + + + private static final AttributeDefinition STATUS = new SimpleAttributeDefinitionBuilder(Constants.STATUS, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + private static final AttributeDefinition REQUESTS = new SimpleAttributeDefinitionBuilder(Constants.REQUESTS, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + + private final OperationDefinition ENABLE = new SimpleOperationDefinition(Constants.ENABLE, getResourceDescriptionResolver()); + private final OperationDefinition DISABLE = new SimpleOperationDefinition(Constants.DISABLE, getResourceDescriptionResolver()); + private final OperationDefinition STOP = new SimpleOperationDefinition(Constants.STOP, getResourceDescriptionResolver()); + + private ModClusterContextDefinition() { + super(new Parameters(UndertowExtension.CONTEXT, UndertowExtension.getResolver("handler", "mod-cluster", "balancer", "node", "context")) + .setRuntime()); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + super.registerAttributes(resourceRegistration); + resourceRegistration.registerReadOnlyAttribute(STATUS, new AbstractContextOperation() { + + @Override + public void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isEnabled() ? "enabled" : ctx.isStopped() ? "stopped" : "disabled")); + } + }); + resourceRegistration.registerReadOnlyAttribute(REQUESTS, new AbstractContextOperation() { + + @Override + public void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getRequests())); + } + }); + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerOperationHandler(ENABLE, new AbstractContextOperation() { + + @Override + protected void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException { + ctx.enable(); + } + }); + resourceRegistration.registerOperationHandler(DISABLE, new AbstractContextOperation() { + + @Override + protected void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException { + ctx.disable(); + } + }); + resourceRegistration.registerOperationHandler(STOP, new AbstractContextOperation() { + + @Override + protected void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException { + ctx.stop(); + } + }); + } + + private abstract class AbstractContextOperation implements OperationStepHandler { + + @Override + public final void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + PathAddress address = context.getCurrentAddress(); + int current = address.size() - 1; + String contextName = address.getElement(current--).getValue(); + String nodeName = address.getElement(current--).getValue(); + String balancerName = address.getElement(current--).getValue(); + String modClusterName = address.getElement(current--).getValue(); + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.LoadBalancer balancer = service.getModCluster().getController().getStatus().getLoadBalancer(balancerName); + if (balancer == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.Node node = balancer.getNode(nodeName); + if (node == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.Context ctx = node.getContext(contextName); + if(ctx == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + handleContext(context, ctx, operation); + } + + protected abstract void handleContext(OperationContext context, ModClusterStatus.Context ctx, ModelNode operation) throws OperationFailedException ; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,357 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.UndertowOptions; +import io.undertow.predicate.Predicate; +import io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel; +import io.undertow.protocols.http2.Http2Channel; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.proxy.ProxyHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.operations.validation.EnumValidator; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.io.OptionAttributeDefinition; +import org.wildfly.extension.undertow.AbstractHandlerDefinition; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.PredicateValidator; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowService; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import static org.jboss.as.controller.PathElement.pathElement; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_MOD_CLUSTER_FILTER; +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; + + +/** + * mod_cluster front end handler. This acts like a filter, but does not re-use a lot of the filter code as it + * needs to inject various services. + * + * @author Stuart Douglas + */ +public class ModClusterDefinition extends AbstractHandlerDefinition { + + + static final RuntimeCapability MOD_CLUSTER_FILTER_CAPABILITY = RuntimeCapability + .Builder.of(CAPABILITY_MOD_CLUSTER_FILTER, true, FilterService.class) + //.addDynamicOptionalRequirements(REF_SSL_CONTEXT) -- has no function so don't use it + .build(); + + public static final AttributeDefinition MANAGEMENT_SOCKET_BINDING = new SimpleAttributeDefinitionBuilder(Constants.MANAGEMENT_SOCKET_BINDING, ModelType.STRING) + .setAllowExpression(true) + .setRequired(true) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(Capabilities.REF_SOCKET_BINDING) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition ADVERTISE_SOCKET_BINDING = new SimpleAttributeDefinitionBuilder(Constants.ADVERTISE_SOCKET_BINDING, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(Capabilities.REF_SOCKET_BINDING) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition SECURITY_KEY = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_KEY, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition ADVERTISE_PROTOCOL = new SimpleAttributeDefinitionBuilder(Constants.ADVERTISE_PROTOCOL, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setDefaultValue(new ModelNode("http")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition ADVERTISE_PATH = new SimpleAttributeDefinitionBuilder(Constants.ADVERTISE_PATH, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setDefaultValue(new ModelNode("/")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition ADVERTISE_FREQUENCY = new SimpleAttributeDefinitionBuilder(Constants.ADVERTISE_FREQUENCY, ModelType.INT) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setRequired(false) + .setDefaultValue(new ModelNode(10000)) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition FAILOVER_STRATEGY = new SimpleAttributeDefinitionBuilder(Constants.FAILOVER_STRATEGY, ModelType.STRING) + .setRequired(false) + .setValidator(new EnumValidator<>(FailoverStrategy.class, true, true)) + .setRestartAllServices() + .setDefaultValue(new ModelNode(FailoverStrategy.LOAD_BALANCED.name())) + .build(); + + public static final AttributeDefinition HEALTH_CHECK_INTERVAL = new SimpleAttributeDefinitionBuilder(Constants.HEALTH_CHECK_INTERVAL, ModelType.INT) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setRequired(false) + .setDefaultValue(new ModelNode(10000)) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition BROKEN_NODE_TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.BROKEN_NODE_TIMEOUT, ModelType.INT) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setRequired(false) + .setDefaultValue(new ModelNode(60000)) //TODO: what is a good default? + .setRestartAllServices() + .build(); + + public static final AttributeDefinition WORKER = new SimpleAttributeDefinitionBuilder(Constants.WORKER, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setDefaultValue(new ModelNode("default")) + .setCapabilityReference(Capabilities.REF_IO_WORKER) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition MAX_REQUEST_TIME = new SimpleAttributeDefinitionBuilder(Constants.MAX_REQUEST_TIME, ModelType.INT) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.MILLISECONDS) + .setRequired(false) + .setDefaultValue(new ModelNode(-1)) + .setRestartAllServices() + .build(); + + + public static final AttributeDefinition MANAGEMENT_ACCESS_PREDICATE = new SimpleAttributeDefinitionBuilder(Constants.MANAGEMENT_ACCESS_PREDICATE, ModelType.STRING) + .setAllowExpression(true) + .setRequired(false) + .setRestartAllServices() + .setValidator(PredicateValidator.INSTANCE) + .build(); + + public static final AttributeDefinition CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(40)) + .setRestartAllServices() + .build(); + + + public static final AttributeDefinition CACHED_CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CACHED_CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(40)) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition CONNECTION_IDLE_TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.CONNECTION_IDLE_TIMEOUT, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setDefaultValue(new ModelNode(60)) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition REQUEST_QUEUE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.REQUEST_QUEUE_SIZE, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1000)) + .setRestartAllServices() + .build(); + + public static final SimpleAttributeDefinition SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.SSL_CONTEXT, ModelType.STRING, true) + .setAlternatives(Constants.SECURITY_REALM) + .setCapabilityReference(REF_SSL_CONTEXT) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SSL_REF) + .build(); + + public static final SimpleAttributeDefinition SECURITY_REALM = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_REALM, ModelType.STRING) + .setAlternatives(Constants.SSL_CONTEXT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SECURITY_REALM_REF) + .setDeprecated(ModelVersion.create(4, 0, 0)) + .build(); + + public static final SimpleAttributeDefinition USE_ALIAS = new SimpleAttributeDefinitionBuilder(Constants.USE_ALIAS, ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(new ModelNode(false)) + .setRestartAllServices() + .build(); + + + public static final SimpleAttributeDefinition ENABLE_HTTP2 = new SimpleAttributeDefinitionBuilder(Constants.ENABLE_HTTP2, ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(new ModelNode(false)) + .setRestartAllServices() + .build(); + + public static final SimpleAttributeDefinition MAX_AJP_PACKET_SIZE = new SimpleAttributeDefinitionBuilder(Constants.MAX_AJP_PACKET_SIZE, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setMeasurementUnit(MeasurementUnit.BYTES) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(AjpClientRequestClientStreamSinkChannel.DEFAULT_MAX_DATA_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + + public static final OptionAttributeDefinition HTTP2_ENABLE_PUSH = OptionAttributeDefinition.builder("http2-enable-push", UndertowOptions.HTTP2_SETTINGS_ENABLE_PUSH) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode(true)) + .build(); + + public static final OptionAttributeDefinition HTTP2_HEADER_TABLE_SIZE = OptionAttributeDefinition.builder("http2-header-table-size", UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE_DEFAULT)) + .setValidator(new IntRangeValidator(1)) + .build(); + + public static final OptionAttributeDefinition HTTP2_INITIAL_WINDOW_SIZE = OptionAttributeDefinition.builder("http2-initial-window-size", UndertowOptions.HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_INITIAL_WINDOW_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + public static final OptionAttributeDefinition HTTP2_MAX_CONCURRENT_STREAMS = OptionAttributeDefinition.builder("http2-max-concurrent-streams", UndertowOptions.HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setValidator(new IntRangeValidator(1)) + .build(); + + public static final OptionAttributeDefinition HTTP2_MAX_FRAME_SIZE = OptionAttributeDefinition.builder("http2-max-frame-size", UndertowOptions.HTTP2_SETTINGS_MAX_FRAME_SIZE) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setDefaultValue(new ModelNode(Http2Channel.DEFAULT_MAX_FRAME_SIZE)) + .setValidator(new IntRangeValidator(1)) + .build(); + + public static final OptionAttributeDefinition HTTP2_MAX_HEADER_LIST_SIZE = OptionAttributeDefinition.builder("http2-max-header-list-size", UndertowOptions.HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setMeasurementUnit(MeasurementUnit.BYTES) + .setValidator(new IntRangeValidator(1)) + .build(); + + public static final AttributeDefinition MAX_RETRIES = new SimpleAttributeDefinitionBuilder(Constants.MAX_RETRIES, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1L)) + .build(); + + public static final Collection ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(MANAGEMENT_SOCKET_BINDING, ADVERTISE_SOCKET_BINDING, SECURITY_KEY, ADVERTISE_PROTOCOL, + ADVERTISE_PATH, ADVERTISE_FREQUENCY, FAILOVER_STRATEGY, HEALTH_CHECK_INTERVAL, BROKEN_NODE_TIMEOUT, WORKER, MAX_REQUEST_TIME, MANAGEMENT_ACCESS_PREDICATE, + CONNECTIONS_PER_THREAD, CACHED_CONNECTIONS_PER_THREAD, CONNECTION_IDLE_TIMEOUT, REQUEST_QUEUE_SIZE, SECURITY_REALM, SSL_CONTEXT, USE_ALIAS, ENABLE_HTTP2, MAX_AJP_PACKET_SIZE, + HTTP2_MAX_HEADER_LIST_SIZE, HTTP2_MAX_FRAME_SIZE, HTTP2_MAX_CONCURRENT_STREAMS, HTTP2_INITIAL_WINDOW_SIZE, HTTP2_HEADER_TABLE_SIZE, HTTP2_ENABLE_PUSH, MAX_RETRIES)); + public static final ModClusterDefinition INSTANCE = new ModClusterDefinition(); + + private ModClusterDefinition() { + super(new Parameters(pathElement(Constants.MOD_CLUSTER), UndertowExtension.getResolver(Constants.HANDLER, Constants.MOD_CLUSTER)) + .setAddHandler(new ModClusterAdd()) + .setRemoveHandler(new ServiceRemoveStepHandler(UndertowService.FILTER, new ModClusterAdd())) + .setCapabilities(MOD_CLUSTER_FILTER_CAPABILITY) + ); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } + + @Override + public Class getHandlerClass() { + return ProxyHandler.class; + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, ModelNode model, HttpHandler next) { + throw new IllegalStateException(); //this is not used for mod_cluster, as it required injection and socket binding + + } + + @Override + public void registerChildren(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerSubModel(ModClusterBalancerDefinition.INSTANCE); + } + + static class ModClusterAdd extends AbstractAddStepHandler { + ModClusterAdd() { + super(ATTRIBUTES); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final String name = context.getCurrentAddressValue(); + ModClusterService.install(name, context.getCapabilityServiceTarget(), model, context); + } + + @Override + protected Resource createResource(OperationContext context, ModelNode operation) { + if (context.isDefaultRequiresRuntime()) { + // Wrap a standard Resource impl in our custom variant that understands runtime-only children + Resource delegate = Resource.Factory.create(); + Resource result = new ModClusterResource(delegate, context.getCurrentAddressValue()); + context.addResource(PathAddress.EMPTY_ADDRESS, result); + return result; + } else { + return super.createResource(context, operation); + } + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterLoadBalancingGroupDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterLoadBalancingGroupDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterLoadBalancingGroupDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,133 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +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.PathAddress; +import org.jboss.as.controller.SimpleOperationDefinition; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * Runtime representation of a mod_cluster context + * + * @author Stuart Douglas + */ +public class ModClusterLoadBalancingGroupDefinition extends SimpleResourceDefinition { + + public static ModClusterLoadBalancingGroupDefinition INSTANCE = new ModClusterLoadBalancingGroupDefinition(); + + + public final OperationDefinition ENABLE_NODES = new SimpleOperationDefinition(Constants.ENABLE_NODES, getResourceDescriptionResolver()); + public final OperationDefinition DISABLE_NODES = new SimpleOperationDefinition(Constants.DISABLE_NODES, getResourceDescriptionResolver()); + public final OperationDefinition STOP_NODES = new SimpleOperationDefinition(Constants.STOP_NODES, getResourceDescriptionResolver()); + + ModClusterLoadBalancingGroupDefinition() { + super(new Parameters(UndertowExtension.LOAD_BALANCING_GROUP, UndertowExtension.getResolver("handler", "mod-cluster", "balancer", "load-balancing-group")) + .setRuntime()); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + super.registerAttributes(resourceRegistration); + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerOperationHandler(ENABLE_NODES, new AbstractGroupOperation() { + + @Override + protected void handleGroup(OperationContext context, ModClusterStatus.LoadBalancer balancer, String groupName, ModelNode operation) { + for(ModClusterStatus.Node node : balancer.getNodes()) { + if(groupName.equals(node.getDomain())) { + for(ModClusterStatus.Context n : node.getContexts()) { + n.enable(); + } + } + } + } + }); + resourceRegistration.registerOperationHandler(DISABLE_NODES, new AbstractGroupOperation() { + + @Override + protected void handleGroup(OperationContext context, ModClusterStatus.LoadBalancer balancer, String groupName, ModelNode operation) { + for(ModClusterStatus.Node node : balancer.getNodes()) { + if(groupName.equals(node.getDomain())) { + for(ModClusterStatus.Context n : node.getContexts()) { + n.disable(); + } + } + } + } + }); + resourceRegistration.registerOperationHandler(STOP_NODES, new AbstractGroupOperation() { + + @Override + protected void handleGroup(OperationContext context, ModClusterStatus.LoadBalancer balancer, String groupName, ModelNode operation) { + for(ModClusterStatus.Node node : balancer.getNodes()) { + if(groupName.equals(node.getDomain())) { + for(ModClusterStatus.Context n : node.getContexts()) { + n.stop(); + } + } + } + } + }); + } + + private abstract class AbstractGroupOperation implements OperationStepHandler { + + @Override + public final void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)); + int current = address.size() - 1; + String groupName = address.getElement(current--).getValue(); + String balancerName = address.getElement(current--).getValue(); + String modClusterName = address.getElement(current--).getValue(); + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.LoadBalancer balancer = service.getModCluster().getController().getStatus().getLoadBalancer(balancerName); + if (balancer == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + handleGroup(context, balancer, groupName, operation); + } + + protected abstract void handleGroup(OperationContext context, ModClusterStatus.LoadBalancer balancer, String groupName, ModelNode operation); + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,354 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.AttributeDefinition; +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.PathAddress; +import org.jboss.as.controller.PrimitiveListAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleOperationDefinition; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * Runtime representation of a mod_cluster node + * + * @author Stuart Douglas + */ +public class ModClusterNodeDefinition extends SimpleResourceDefinition { + + public static ModClusterNodeDefinition INSTANCE = new ModClusterNodeDefinition(); + + + public static final AttributeDefinition LOAD = new SimpleAttributeDefinitionBuilder(Constants.LOAD, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition STATUS = new SimpleAttributeDefinitionBuilder(Constants.STATUS, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition LOAD_BALANCING_GROUP = new SimpleAttributeDefinitionBuilder(Constants.LOAD_BALANCING_GROUP, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition CACHE_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.CACHE_CONNECTIONS, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition MAX_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.MAX_CONNECTIONS, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition OPEN_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.OPEN_CONNECTIONS, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition PING = new SimpleAttributeDefinitionBuilder(Constants.PING, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition READ = new SimpleAttributeDefinitionBuilder(Constants.READ, ModelType.LONG) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition REQUEST_QUEUE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.REQUEST_QUEUE_SIZE, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.TIMEOUT, ModelType.INT) + .setRequired(false) + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition WRITTEN = new SimpleAttributeDefinitionBuilder(Constants.WRITTEN, ModelType.LONG) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition TTL = new SimpleAttributeDefinitionBuilder(Constants.TTL, ModelType.LONG) + .setRequired(false) + .setStorageRuntime() + .build(); + + + public static final AttributeDefinition FLUSH_PACKETS = new SimpleAttributeDefinitionBuilder(Constants.FLUSH_PACKETS, ModelType.BOOLEAN) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition QUEUE_NEW_REQUESTS = new SimpleAttributeDefinitionBuilder(Constants.QUEUE_NEW_REQUESTS, ModelType.BOOLEAN) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition URI = new SimpleAttributeDefinitionBuilder(Constants.URI, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + public static final AttributeDefinition ALIASES = new PrimitiveListAttributeDefinition.Builder(Constants.ALIASES, ModelType.STRING) + .setRequired(false) + .setStorageRuntime() + .build(); + + + public static final AttributeDefinition ELECTED = new SimpleAttributeDefinitionBuilder(Constants.ELECTED, ModelType.INT) + .setRequired(false) + .setStorageRuntime() + .build(); + + public final OperationDefinition ENABLE = new SimpleOperationDefinition(Constants.ENABLE, getResourceDescriptionResolver()); + public final OperationDefinition DISABLE = new SimpleOperationDefinition(Constants.DISABLE, getResourceDescriptionResolver()); + public final OperationDefinition STOP = new SimpleOperationDefinition(Constants.STOP, getResourceDescriptionResolver()); + + + ModClusterNodeDefinition() { + super(new Parameters(UndertowExtension.NODE, UndertowExtension.getResolver("handler", "mod-cluster", "balancer", "node")) + .setRuntime()); + } + + @Override + public void registerChildren(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerSubModel(ModClusterContextDefinition.INSTANCE); + } + + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerOperationHandler(ENABLE, new AbstractNodeOperation() { + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + for (ModClusterStatus.Context n : ctx.getContexts()) { + n.enable(); + } + } + }); + resourceRegistration.registerOperationHandler(DISABLE, new AbstractNodeOperation() { + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + for (ModClusterStatus.Context n : ctx.getContexts()) { + n.disable(); + } + } + }); + resourceRegistration.registerOperationHandler(STOP, new AbstractNodeOperation() { + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + for (ModClusterStatus.Context n : ctx.getContexts()) { + n.stop(); + } + } + }); + } + + @Override + public void registerAttributes(ManagementResourceRegistration resourceRegistration) { + resourceRegistration.registerReadOnlyAttribute(LOAD, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getLoad())); + } + }); + + resourceRegistration.registerReadOnlyAttribute(STATUS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getStatus().name())); + } + }); + resourceRegistration.registerReadOnlyAttribute(LOAD_BALANCING_GROUP, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + final String domain = ctx.getDomain(); + if (domain == null) { + context.getResult().set(new ModelNode()); + } else { + context.getResult().set(new ModelNode(domain)); + } + } + }); + resourceRegistration.registerReadOnlyAttribute(CACHE_CONNECTIONS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getCacheConnections())); + } + }); + resourceRegistration.registerReadOnlyAttribute(MAX_CONNECTIONS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getMaxConnections())); + } + }); + resourceRegistration.registerReadOnlyAttribute(OPEN_CONNECTIONS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getOpenConnections())); + } + }); + resourceRegistration.registerReadOnlyAttribute(PING, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getPing())); + } + }); + resourceRegistration.registerReadOnlyAttribute(READ, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getRead())); + } + }); + resourceRegistration.registerReadOnlyAttribute(REQUEST_QUEUE_SIZE, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getRequestQueueSize())); + } + }); + resourceRegistration.registerReadOnlyAttribute(TIMEOUT, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getTimeout())); + } + }); + resourceRegistration.registerReadOnlyAttribute(WRITTEN, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getTransferred())); + } + }); + resourceRegistration.registerReadOnlyAttribute(TTL, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getTtl())); + } + }); + resourceRegistration.registerReadOnlyAttribute(FLUSH_PACKETS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isFlushPackets())); + } + }); + resourceRegistration.registerReadOnlyAttribute(QUEUE_NEW_REQUESTS, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.isQueueNewRequests())); + } + }); + resourceRegistration.registerReadOnlyAttribute(URI, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getUri().toString())); + } + }); + resourceRegistration.registerReadOnlyAttribute(ALIASES, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + final ModelNode result = new ModelNode(); + for (String alias : ctx.getAliases()) { + UndertowLogger.ROOT_LOGGER.tracef("Adding alias %s", alias); + result.add(alias); + } + context.getResult().set(result); + } + }); + resourceRegistration.registerReadOnlyAttribute(ELECTED, new AbstractNodeOperation() { + + @Override + protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException { + context.getResult().set(new ModelNode(ctx.getElected())); + } + }); + } + + private abstract class AbstractNodeOperation implements OperationStepHandler { + + @Override + public final void execute(OperationContext context, ModelNode operation) throws OperationFailedException { + PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)); + int current = address.size() - 1; + String nodeName = address.getElement(current--).getValue(); + String balancerName = address.getElement(current--).getValue(); + String modClusterName = address.getElement(current--).getValue(); + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.LoadBalancer balancer = service.getModCluster().getController().getStatus().getLoadBalancer(balancerName); + if (balancer == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + ModClusterStatus.Node node = balancer.getNode(nodeName); + if (node == null) { + context.getResult().set(new ModelNode()); + context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER); + return; + } + handleNode(context, node, operation); + } + + protected abstract void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeResource.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeResource.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterNodeResource.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,201 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModCluster; +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.PlaceholderResource; +import org.jboss.as.controller.registry.Resource; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import static org.wildfly.extension.undertow.Constants.CONTEXT; + +public class ModClusterNodeResource implements Resource.ResourceEntry { + + private final String name; + private final String balancerName; + private final String modClusterName; + private ModelNode model = new ModelNode(); + + public ModClusterNodeResource(String name, String balancerName, String modClusterName) { + this.name = name; + this.balancerName = balancerName; + this.modClusterName = modClusterName; + } + + @Override + public ModelNode getModel() { + return model; + } + + @Override + public void writeModel(final ModelNode newModel) { + this.model = newModel; + } + + @Override + public boolean isModelDefined() { + return true; + } + + @Override + public boolean hasChild(final PathElement element) { + if (CONTEXT.equals(element.getKey())) { + return getChildrenNames(CONTEXT).contains(element.getValue()); + } + return false; + } + + @Override + public Resource getChild(final PathElement element) { + if (CONTEXT.equals(element.getKey())) { + if (getChildrenNames(CONTEXT).contains(element.getValue())) { + return PlaceholderResource.INSTANCE; + } + return null; + } + return null; + } + + @Override + public Resource requireChild(final PathElement element) { + if (CONTEXT.equals(element.getKey())) { + if (getChildrenNames(CONTEXT).contains(element.getValue())) { + return PlaceholderResource.INSTANCE; + } + throw new NoSuchResourceException(element); + } + throw new NoSuchResourceException(element); + } + + @Override + public boolean hasChildren(final String childType) { + if (CONTEXT.equals(childType)) { + return !getChildrenNames(CONTEXT).isEmpty(); + } + return false; + } + + @Override + public Resource navigate(final PathAddress address) { + if (address.size() == 1 && CONTEXT.equals(address.getElement(0).getKey())) { + return requireChild(address.getElement(0)); + } + throw new NoSuchResourceException(address.getElement(0)); + } + + @Override + public Set getChildTypes() { + return Collections.singleton(CONTEXT); + } + + @Override + public Set getChildrenNames(final String childType) { + if (CONTEXT.equals(childType)) { + + ModClusterService service = ModClusterResource.service(modClusterName); + if (service == null) { + return Collections.emptySet(); + } + ModCluster modCluster = service.getModCluster(); + ModClusterStatus status = modCluster.getController().getStatus(); + final Set result = new LinkedHashSet<>(); + ModClusterStatus.LoadBalancer balancer = status.getLoadBalancer(this.balancerName); + ModClusterStatus.Node node = balancer.getNode(this.name); + for (ModClusterStatus.Context context : node.getContexts()) { + result.add(context.getName()); + } + return result; + } + return null; + } + + @Override + public Set getChildren(final String childType) { + if (CONTEXT.equals(childType)) { + final Set names = getChildrenNames(childType); + final Set result = new LinkedHashSet<>(names.size()); + for (String name : names) { + result.add(new PlaceholderResource.PlaceholderResourceEntry(PathElement.pathElement(CONTEXT, name))); + } + return result; + } + return Collections.emptySet(); + } + + @Override + public void registerChild(final PathElement address, final Resource resource) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + + @Override + public void registerChild(PathElement address, int index, Resource resource) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + + @Override + public Resource removeChild(final PathElement address) { + final String type = address.getKey(); + throw UndertowLogger.ROOT_LOGGER.cannotRemoveResourceOfType(type); + } + + @Override + public boolean isRuntime() { + return true; + } + + @Override + public boolean isProxy() { + return false; + } + + @Override + public Set getOrderedChildTypes() { + return Collections.emptySet(); + } + + @Override + public Resource clone() { + return new ModClusterNodeResource(name, balancerName, modClusterName); + } + + @Override + public String getName() { + return name; + } + + @Override + public PathElement getPathElement() { + return PathElement.pathElement(Constants.NODE, name); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterResource.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterResource.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterResource.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,226 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.server.handlers.proxy.mod_cluster.ModCluster; +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterController; +import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.registry.Resource; +import org.jboss.as.server.CurrentServiceContainer; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceContainer; +import org.jboss.msc.service.ServiceController; +import org.wildfly.extension.undertow.UndertowService; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import static org.wildfly.extension.undertow.Constants.BALANCER; + + +public class ModClusterResource implements Resource { + + private final Resource delegate; + private final String name; + + public ModClusterResource(Resource delegate, String name) { + this.delegate = delegate; + this.name = name; + } + + @Override + public ModelNode getModel() { + return delegate.getModel(); + } + + @Override + public void writeModel(final ModelNode newModel) { + delegate.writeModel(newModel); + } + + @Override + public boolean isModelDefined() { + return delegate.isModelDefined(); + } + + @Override + public boolean hasChild(final PathElement element) { + if (BALANCER.equals(element.getKey())) { + return getChildrenNames(BALANCER).contains(element.getValue()); + } + return delegate.hasChild(element); + } + + @Override + public Resource getChild(final PathElement element) { + if (BALANCER.equals(element.getKey())) { + if (getChildrenNames(BALANCER).contains(element.getValue())) { + return new ModClusterBalancerResource(element.getValue(), name); + } + return null; + } + return delegate.getChild(element); + } + + @Override + public Resource requireChild(final PathElement element) { + if (BALANCER.equals(element.getKey())) { + if (getChildrenNames(BALANCER).contains(element.getValue())) { + return new ModClusterBalancerResource(element.getValue(), name); + } + throw new NoSuchResourceException(element); + } + return delegate.requireChild(element); + } + + @Override + public boolean hasChildren(final String childType) { + if (BALANCER.equals(childType)) { + return !getChildrenNames(BALANCER).isEmpty(); + } + return delegate.hasChildren(childType); + } + + @Override + public Resource navigate(final PathAddress address) { + if (address.size() > 0 && BALANCER.equals(address.getElement(0).getKey())) { + final Resource modClusterBalancerResource = requireChild(address.getElement(0)); + if(address.size() == 1) { + return modClusterBalancerResource; + } else { + return modClusterBalancerResource.navigate(address.subAddress(1)); + } + } + return delegate.navigate(address); + } + + @Override + public Set getChildTypes() { + final Set result = new LinkedHashSet<>(delegate.getChildTypes()); + result.add(BALANCER); + return result; + } + + @Override + public Set getChildrenNames(final String childType) { + if (BALANCER.equals(childType)) { + + ModClusterService service = service(name); + if(service == null) { + return Collections.emptySet(); + } + ModCluster modCluster = service.getModCluster(); + if(modCluster == null) { + return Collections.emptySet(); + } + ModClusterController controller = modCluster.getController(); + if(controller == null) { + return Collections.emptySet(); + } + ModClusterStatus status = controller.getStatus(); + final Set result = new LinkedHashSet<>(); + for (ModClusterStatus.LoadBalancer balancer : status.getLoadBalancers()) { + result.add(balancer.getName()); + } + return result; + } + return delegate.getChildrenNames(childType); + } + + @Override + public Set getChildren(final String childType) { + if (BALANCER.equals(childType)) { + final Set names = getChildrenNames(childType); + final Set result = new LinkedHashSet<>(names.size()); + for (String name : names) { + result.add(new ModClusterBalancerResource(name, this.name)); + } + return result; + } + return delegate.getChildren(childType); + } + + @Override + public void registerChild(final PathElement address, final Resource resource) { + final String type = address.getKey(); + if (BALANCER.equals(type)) { + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + delegate.registerChild(address, resource); + } + + @Override + public void registerChild(PathElement address, int index, Resource resource) { + final String type = address.getKey(); + if (BALANCER.equals(type)) { + throw UndertowLogger.ROOT_LOGGER.cannotRegisterResourceOfType(type); + } + delegate.registerChild(address, index, resource); + } + + @Override + public Resource removeChild(final PathElement address) { + final String type = address.getKey(); + if (BALANCER.equals(type)) { + throw UndertowLogger.ROOT_LOGGER.cannotRemoveResourceOfType(type); + } + return delegate.removeChild(address); + } + + @Override + public boolean isRuntime() { + return delegate.isRuntime(); + } + + @Override + public boolean isProxy() { + return delegate.isProxy(); + } + + @Override + public Set getOrderedChildTypes() { + return Collections.emptySet(); + } + + @Override + public Resource clone() { + return new ModClusterResource(delegate.clone(), name); + } + + static ModClusterService service(String name) { + final ServiceContainer serviceContainer = CurrentServiceContainer.getServiceContainer(); + if(serviceContainer == null) { + //for tests + return null; + } + ServiceController cluster = serviceContainer.getService(UndertowService.FILTER.append(name)); + if(cluster == null) { + return null; + } + return (ModClusterService) cluster.getService(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ModClusterService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,317 @@ +/* + * 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.extension.undertow.filters; + +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; +import io.undertow.Handlers; +import io.undertow.UndertowOptions; +import io.undertow.client.UndertowClient; +import io.undertow.predicate.PredicateParser; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.CapabilityServiceTarget; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.domain.management.SecurityRealm; +import org.jboss.as.network.SocketBinding; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.io.IOServices; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.UndertowService; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.xnio.OptionMap; +import org.xnio.Options; +import org.xnio.XnioWorker; + +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.PredicateHandler; +import io.undertow.server.handlers.proxy.mod_cluster.MCMPConfig; +import io.undertow.server.handlers.proxy.mod_cluster.ModCluster; +import org.xnio.ssl.XnioSsl; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.InetAddress; + +/** + * filter service for the mod cluster frontend. This requires various injections, and as a result can't use the + * standard filter service + * + * @author Stuart Douglas + */ +public class ModClusterService extends FilterService { + + private final InjectedValue workerInjectedValue = new InjectedValue<>(); + private final InjectedValue managementSocketBinding = new InjectedValue<>(); + private final InjectedValue advertiseSocketBinding = new InjectedValue<>(); + private final InjectedValue securityRealm = new InjectedValue<>(); + private final InjectedValue sslContext = new InjectedValue<>(); + private final long healthCheckInterval; + private final int maxRequestTime; + private final long removeBrokenNodes; + private final int advertiseFrequency; + private final String advertisePath; + private final String advertiseProtocol; + private final String securityKey; + private final Predicate managementAccessPredicate; + private final int connectionsPerThread; + private final int cachedConnections; + private final int connectionIdleTimeout; + private final int requestQueueSize; + private final boolean useAlias; + private final int maxRetries; + private final FailoverStrategy failoverStrategy; + + private ModCluster modCluster; + private MCMPConfig config; + private final OptionMap clientOptions; + + ModClusterService(ModelNode model, + long healthCheckInterval, + int maxRequestTime, + long removeBrokenNodes, + int advertiseFrequency, + String advertisePath, + String advertiseProtocol, + String securityKey, + Predicate managementAccessPredicate, + int connectionsPerThread, + int cachedConnections, + int connectionIdleTimeout, + int requestQueueSize, + boolean useAlias, + int maxRetries, + FailoverStrategy failoverStrategy, + OptionMap clientOptions) { + super(ModClusterDefinition.INSTANCE, model); + this.healthCheckInterval = healthCheckInterval; + this.maxRequestTime = maxRequestTime; + this.removeBrokenNodes = removeBrokenNodes; + this.advertiseFrequency = advertiseFrequency; + this.advertisePath = advertisePath; + this.advertiseProtocol = advertiseProtocol; + this.securityKey = securityKey; + this.managementAccessPredicate = managementAccessPredicate; + this.connectionsPerThread = connectionsPerThread; + this.cachedConnections = cachedConnections; + this.connectionIdleTimeout = connectionIdleTimeout; + this.requestQueueSize = requestQueueSize; + this.useAlias = useAlias; + this.maxRetries = maxRetries; + this.failoverStrategy = failoverStrategy; + this.clientOptions = clientOptions; + } + + @Override + public synchronized void start(StartContext context) throws StartException { + super.start(context); + + SSLContext sslContext = this.sslContext.getOptionalValue(); + if (sslContext == null) { + SecurityRealm realm = securityRealm.getOptionalValue(); + if (realm != null) { + sslContext = realm.getSSLContext(); + } + } + + //TODO: SSL support for the client + final ModCluster.Builder modClusterBuilder; + final XnioWorker worker = workerInjectedValue.getValue(); + if(sslContext == null) { + modClusterBuilder = ModCluster.builder(worker); + } else { + OptionMap.Builder builder = OptionMap.builder(); + builder.set(Options.USE_DIRECT_BUFFERS, true); + OptionMap combined = builder.getMap(); + + XnioSsl xnioSsl = new UndertowXnioSsl(worker.getXnio(), combined, sslContext); + modClusterBuilder = ModCluster.builder(worker, UndertowClient.getInstance(), xnioSsl); + } + modClusterBuilder + .setMaxRetries(maxRetries) + .setClientOptions(clientOptions) + .setHealthCheckInterval(healthCheckInterval) + .setMaxRequestTime(maxRequestTime) + .setCacheConnections(cachedConnections) + .setQueueNewRequests(requestQueueSize > 0) + .setRequestQueueSize(requestQueueSize) + .setRemoveBrokenNodes(removeBrokenNodes) + .setTtl(connectionIdleTimeout) + .setMaxConnections(connectionsPerThread) + .setUseAlias(useAlias); + + if (FailoverStrategy.DETERMINISTIC.equals(failoverStrategy)) { + modClusterBuilder.setDeterministicFailover(true); + } + + modCluster = modClusterBuilder.build(); + + MCMPConfig.Builder builder = MCMPConfig.builder(); + final SocketBinding advertiseBinding = advertiseSocketBinding.getOptionalValue(); + if (advertiseBinding != null) { + InetAddress multicastAddress = advertiseBinding.getMulticastAddress(); + if (multicastAddress == null) { + throw UndertowLogger.ROOT_LOGGER.advertiseSocketBindingRequiresMulticastAddress(); + } + if (advertiseFrequency > 0) { + builder.enableAdvertise() + .setAdvertiseAddress(advertiseBinding.getSocketAddress().getAddress().getHostAddress()) + .setAdvertiseGroup(multicastAddress.getHostAddress()) + .setAdvertisePort(advertiseBinding.getMulticastPort()) + .setAdvertiseFrequency(advertiseFrequency) + .setPath(advertisePath) + .setProtocol(advertiseProtocol) + .setSecurityKey(securityKey); + } + } + builder.setManagementHost(managementSocketBinding.getValue().getSocketAddress().getHostString()); + builder.setManagementPort(managementSocketBinding.getValue().getSocketAddress().getPort()); + + config = builder.build(); + + + if (advertiseBinding != null && advertiseFrequency > 0) { + try { + modCluster.advertise(config); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + modCluster.start(); + } + + @Override + public synchronized void stop(StopContext context) { + super.stop(context); + modCluster.stop(); + modCluster = null; + config = null; + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, final HttpHandler next) { + //this is a bit of a hack at the moment. Basically we only want to create a single mod_cluster instance + //not matter how many filter refs use it, also mod_cluster at this point has no way + //to specify the next handler. To get around this we invoke the mod_proxy handler + //and then if it has not dispatched or handled the request then we know that we can + //just pass it on to the next handler + final HttpHandler proxyHandler = modCluster.createProxyHandler(next); + final HttpHandler realNext = new HttpHandler() { + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + proxyHandler.handleRequest(exchange); + if(!exchange.isDispatched() && !exchange.isComplete()) { + exchange.setStatusCode(200); + next.handleRequest(exchange); + } + } + }; + final HttpHandler mcmp = managementAccessPredicate != null ? Handlers.predicate(managementAccessPredicate, config.create(modCluster, realNext), next) : config.create(modCluster, realNext); + + UndertowLogger.ROOT_LOGGER.debug("HttpHandler for mod_cluster MCMP created."); + if (predicate != null) { + return new PredicateHandler(predicate, mcmp, next); + } else { + return mcmp; + } + } + + static void install(String name, CapabilityServiceTarget serviceTarget, ModelNode model, OperationContext operationContext) throws OperationFailedException { + String securityKey = null; + ModelNode securityKeyNode = ModClusterDefinition.SECURITY_KEY.resolveModelAttribute(operationContext, model); + if(securityKeyNode.isDefined()) { + securityKey = securityKeyNode.asString(); + } + + String managementAccessPredicateString = null; + ModelNode managementAccessPredicateNode = ModClusterDefinition.MANAGEMENT_ACCESS_PREDICATE.resolveModelAttribute(operationContext, model); + if(managementAccessPredicateNode.isDefined()) { + managementAccessPredicateString = managementAccessPredicateNode.asString(); + } + Predicate managementAccessPredicate = null; + if(managementAccessPredicateString != null) { + managementAccessPredicate = PredicateParser.parse(managementAccessPredicateString, ModClusterService.class.getClassLoader()); + } + final ModelNode sslContext = ModClusterDefinition.SSL_CONTEXT.resolveModelAttribute(operationContext, model); + final ModelNode securityRealm = ModClusterDefinition.SECURITY_REALM.resolveModelAttribute(operationContext, model); + + final ModelNode packetSizeNode = ModClusterDefinition.MAX_AJP_PACKET_SIZE.resolveModelAttribute(operationContext, model); + OptionMap.Builder builder = OptionMap.builder(); + if(packetSizeNode.isDefined()) { + builder.set(UndertowOptions.MAX_AJP_PACKET_SIZE, packetSizeNode.asInt()); + } + builder.set(UndertowOptions.ENABLE_HTTP2, ModClusterDefinition.ENABLE_HTTP2.resolveModelAttribute(operationContext, model).asBoolean()); + ModClusterDefinition.HTTP2_ENABLE_PUSH.resolveOption(operationContext, model, builder); + ModClusterDefinition.HTTP2_HEADER_TABLE_SIZE.resolveOption(operationContext, model, builder); + ModClusterDefinition.HTTP2_INITIAL_WINDOW_SIZE.resolveOption(operationContext, model, builder); + ModClusterDefinition.HTTP2_MAX_CONCURRENT_STREAMS.resolveOption(operationContext, model, builder); + ModClusterDefinition.HTTP2_MAX_FRAME_SIZE.resolveOption(operationContext, model, builder); + ModClusterDefinition.HTTP2_MAX_HEADER_LIST_SIZE.resolveOption(operationContext, model, builder); + + ModClusterService service = new ModClusterService(model, + ModClusterDefinition.HEALTH_CHECK_INTERVAL.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.MAX_REQUEST_TIME.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.BROKEN_NODE_TIMEOUT.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.ADVERTISE_FREQUENCY.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.ADVERTISE_PATH.resolveModelAttribute(operationContext, model).asString(), + ModClusterDefinition.ADVERTISE_PROTOCOL.resolveModelAttribute(operationContext, model).asString(), + securityKey, managementAccessPredicate, + ModClusterDefinition.CONNECTIONS_PER_THREAD.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.CACHED_CONNECTIONS_PER_THREAD.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.CONNECTION_IDLE_TIMEOUT.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.REQUEST_QUEUE_SIZE.resolveModelAttribute(operationContext, model).asInt(), + ModClusterDefinition.USE_ALIAS.resolveModelAttribute(operationContext, model).asBoolean(), + ModClusterDefinition.MAX_RETRIES.resolveModelAttribute(operationContext, model).asInt(), + Enum.valueOf(FailoverStrategy.class, ModClusterDefinition.FAILOVER_STRATEGY.resolveModelAttribute(operationContext, model).asString()), + builder.getMap()); + + final String mgmtSocketBindingRef = ModClusterDefinition.MANAGEMENT_SOCKET_BINDING.resolveModelAttribute(operationContext, model).asString(); + final ModelNode advertiseSocketBindingRef = ModClusterDefinition.ADVERTISE_SOCKET_BINDING.resolveModelAttribute(operationContext, model); + final String workerRef = ModClusterDefinition.WORKER.resolveModelAttribute(operationContext, model).asString(); + CapabilityServiceBuilder serviceBuilder = serviceTarget.addCapability(ModClusterDefinition.MOD_CLUSTER_FILTER_CAPABILITY, service); + serviceBuilder.addCapabilityRequirement(Capabilities.REF_SOCKET_BINDING, SocketBinding.class, service.managementSocketBinding, mgmtSocketBindingRef); + if (advertiseSocketBindingRef.isDefined()) { + serviceBuilder.addCapabilityRequirement(Capabilities.REF_SOCKET_BINDING, SocketBinding.class, service.advertiseSocketBinding, advertiseSocketBindingRef.asString()); + } + serviceBuilder.addCapabilityRequirement(IOServices.IO_WORKER_CAPABILITY_NAME,XnioWorker.class, service.workerInjectedValue, workerRef); + + if (sslContext.isDefined()) { + serviceBuilder.addCapabilityRequirement(REF_SSL_CONTEXT, SSLContext.class, service.sslContext, sslContext.asString()); + } + if(securityRealm.isDefined()) { + SecurityRealm.ServiceUtil.addDependency(serviceBuilder, service.securityRealm, securityRealm.asString()); + } + serviceBuilder.addAliases(UndertowService.FILTER.append(name)); + serviceBuilder.install(); + } + + public ModCluster getModCluster() { + return modCluster; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RequestLimitHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,83 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Arrays; +import java.util.Collection; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.RequestLimitingHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.operations.validation.IntRangeValidator; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class RequestLimitHandler extends Filter { + + public static final RequestLimitHandler INSTANCE = new RequestLimitHandler(); + + public static final AttributeDefinition MAX_CONCURRENT_REQUESTS = new SimpleAttributeDefinitionBuilder("max-concurrent-requests", ModelType.INT) + .setValidator(new IntRangeValidator(1, false, true)) + .setAllowExpression(true) + .setRequired(true) + .setRestartAllServices() + .build(); + + + public static final AttributeDefinition QUEUE_SIZE = new SimpleAttributeDefinitionBuilder("queue-size", ModelType.INT) + .setValidator(new IntRangeValidator(0, true, true)) + .setAllowExpression(true) + .setRequired(false) + .setDefaultValue(new ModelNode(0)) + .setRestartAllServices() + .build(); + + + /* + + */ + + private RequestLimitHandler() { + super("request-limit"); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(MAX_CONCURRENT_REQUESTS, QUEUE_SIZE); + } + + + @Override + public Class getHandlerClass() { + return RequestLimitingHandler.class; + } + + @Override + protected Class[] getConstructorSignature() { + return new Class[] {int.class, int.class, HttpHandler.class}; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilter.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilter.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/ResponseHeaderFilter.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,71 @@ +/* + * 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.extension.undertow.filters; + +import java.util.Arrays; +import java.util.Collection; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.SetHeaderHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class ResponseHeaderFilter extends Filter { + + public static final AttributeDefinition NAME = new SimpleAttributeDefinitionBuilder("header-name", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + public static final AttributeDefinition VALUE = new SimpleAttributeDefinitionBuilder("header-value", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final ResponseHeaderFilter INSTANCE = new ResponseHeaderFilter(); + + private ResponseHeaderFilter() { + super("response-header"); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(NAME, VALUE); + } + + @Override + public Class getHandlerClass() { + return SetHeaderHandler.class; + } + + + @Override + protected Class[] getConstructorSignature() { + return new Class[] {HttpHandler.class, String.class, String.class}; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RewriteFilterDefinition.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RewriteFilterDefinition.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/filters/RewriteFilterDefinition.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,93 @@ +/* + * 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.extension.undertow.filters; + +import io.undertow.Handlers; +import io.undertow.attribute.ExchangeAttributes; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.RedirectHandler; +import io.undertow.server.handlers.SetAttributeHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; + +import java.util.Arrays; +import java.util.Collection; + +/** + * @author Stuart Douglas + */ +public class RewriteFilterDefinition extends Filter { + + public static final AttributeDefinition TARGET = new SimpleAttributeDefinitionBuilder("target", ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + + public static final AttributeDefinition REDIRECT = new SimpleAttributeDefinitionBuilder("redirect", ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(new ModelNode(false)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final RewriteFilterDefinition INSTANCE = new RewriteFilterDefinition(); + + private RewriteFilterDefinition() { + super(Constants.REWRITE); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(TARGET, REDIRECT); + } + + @Override + public HttpHandler createHttpHandler(Predicate predicate, ModelNode model, HttpHandler next) { + String expression = model.get(TARGET.getName()).asString(); + boolean redirect = model.get(REDIRECT.getName()).asBoolean(); + if(predicate == null) { + return create(next, expression, redirect); + } else { + return Handlers.predicate(predicate, create(next, expression, redirect), next); + } + } + + public HttpHandler create(HttpHandler next, String expression, boolean redirect) { + if(redirect) { + return new RedirectHandler(expression); + } else { + return new SetAttributeHandler(next, ExchangeAttributes.relativePath(), ExchangeAttributes.parser(getClass().getClassLoader()).parse(expression)); + } + } + + @Override + protected Class[] getConstructorSignature() { + throw new IllegalStateException(); //should not be used, as the handler is constructed above + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/FileHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,130 @@ +/* + * 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.extension.undertow.handlers; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.resource.PathResourceManager; +import io.undertow.server.handlers.resource.ResourceHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.StringListAttributeDefinition; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class FileHandler extends Handler { + + public static final FileHandler INSTANCE = new FileHandler(); + + /**/ + public static final AttributeDefinition PATH = new SimpleAttributeDefinitionBuilder(Constants.PATH, ModelType.STRING) + .setRequired(true) + .setAllowExpression(true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CACHE_BUFFER_SIZE = new SimpleAttributeDefinitionBuilder("cache-buffer-size", ModelType.LONG) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1024)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CACHE_BUFFERS = new SimpleAttributeDefinitionBuilder("cache-buffers", ModelType.LONG) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1024)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition DIRECTORY_LISTING = new SimpleAttributeDefinitionBuilder(Constants.DIRECTORY_LISTING, ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition FOLLOW_SYMLINK = new SimpleAttributeDefinitionBuilder("follow-symlink", ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(false)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final StringListAttributeDefinition SAFE_SYMLINK_PATHS = new StringListAttributeDefinition.Builder("safe-symlink-paths") + .setRequired(false) + .setAllowExpression(true) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition CASE_SENSITIVE = new SimpleAttributeDefinitionBuilder("case-sensitive", ModelType.BOOLEAN) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(true)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + private FileHandler() { + super(Constants.FILE); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(PATH, CACHE_BUFFER_SIZE, CACHE_BUFFERS, DIRECTORY_LISTING, FOLLOW_SYMLINK, CASE_SENSITIVE, SAFE_SYMLINK_PATHS); + } + + @Override + public HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException { + final String path = PATH.resolveModelAttribute(context, model).asString(); + final boolean directoryListing = DIRECTORY_LISTING.resolveModelAttribute(context, model).asBoolean(); + final boolean followSymlink = FOLLOW_SYMLINK.resolveModelAttribute(context, model).asBoolean(); + final boolean caseSensitive = CASE_SENSITIVE.resolveModelAttribute(context, model).asBoolean(); + final int cacheBufferSize = CACHE_BUFFER_SIZE.resolveModelAttribute(context, model).asInt(); + final int cacheBuffers = CACHE_BUFFERS.resolveModelAttribute(context, model).asInt(); + final List safePaths = SAFE_SYMLINK_PATHS.unwrap(context, model); + final String[] paths = safePaths.toArray(new String[safePaths.size()]); + + UndertowLogger.ROOT_LOGGER.creatingFileHandler(path, directoryListing, followSymlink, caseSensitive, safePaths); + Path base; + try { + base = Paths.get(path).normalize().toRealPath(); //workaround for JBEAP-10231 + } catch (IOException e) { + throw new OperationFailedException(UndertowLogger.ROOT_LOGGER.unableAddHandlerForPath(path)); + } + PathResourceManager resourceManager = new PathResourceManager(base, cacheBufferSize * cacheBuffers, caseSensitive, followSymlink, paths); + ResourceHandler handler = new ResourceHandler(resourceManager); + handler.setDirectoryListingEnabled(directoryListing); + return handler; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/Handler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/Handler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/Handler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,83 @@ +/* + * 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.extension.undertow.handlers; + +import java.util.List; + +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.access.constraint.SensitivityClassification; +import org.jboss.as.controller.access.management.AccessConstraintDefinition; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.dmr.ModelNode; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.UndertowService; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +abstract class Handler extends PersistentResourceDefinition { + + static final RuntimeCapability CAPABILITY = RuntimeCapability.Builder.of(Capabilities.CAPABILITY_HANDLER, true, HttpHandler.class) + //.addRuntimeOnlyRequirements(Capabilities.REF_REQUEST_CONTROLLER) -- has no function so don't use it + .build(); + + private static final List CONSTRAINTS = new SensitiveTargetAccessConstraintDefinition( + new SensitivityClassification(UndertowExtension.SUBSYSTEM_NAME, "undertow-handler", false, false, false) + ).wrapAsList(); + + + protected Handler(String name) { + super(PathElement.pathElement(name), UndertowExtension.getResolver(Constants.HANDLER, name)); + } + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + HandlerAdd add = new HandlerAdd(this); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(UndertowService.HANDLER, add, Handler.CAPABILITY), OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + + } + + @Override + public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { + super.registerCapabilities(resourceRegistration); + resourceRegistration.registerCapability(CAPABILITY); + } + @Override + public List getAccessConstraints() { + return CONSTRAINTS; + } + + abstract HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException; +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerAdd.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerAdd.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerAdd.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,62 @@ +/* + * 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.extension.undertow.handlers; + +import io.undertow.server.HttpHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.wildfly.extension.requestcontroller.RequestController; +import org.wildfly.extension.undertow.Capabilities; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +class HandlerAdd extends AbstractAddStepHandler { + private Handler handler; + + HandlerAdd(Handler handler) { + super(handler.getAttributes()); + this.handler = handler; + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final String name = context.getCurrentAddressValue(); + + final HandlerService service = new HandlerService(handler.createHandler(context, model), name); + + CapabilityServiceBuilder builder = context.getCapabilityServiceTarget().addCapability(Handler.CAPABILITY, service) + .setInitialMode(ServiceController.Mode.ON_DEMAND); + final RuntimeCapability newCapability = Handler.CAPABILITY.fromBaseCapability(context.getCurrentAddress()); + if (context.hasOptionalCapability(Capabilities.REF_REQUEST_CONTROLLER, newCapability.getName(), null)) { + builder.addCapabilityRequirement(Capabilities.REF_REQUEST_CONTROLLER, RequestController.class, service.getRequestControllerInjectedValue()); + } + + builder.install(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinitions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinitions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerDefinitions.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,65 @@ +/* + * 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.extension.undertow.handlers; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class HandlerDefinitions extends PersistentResourceDefinition { + + public static final HandlerDefinitions INSTANCE = new HandlerDefinitions(); + private static List HANDLERS = Collections.unmodifiableList(Arrays.asList( + FileHandler.INSTANCE, + ReverseProxyHandler.INSTANCE + )); + + private HandlerDefinitions() { + super(UndertowExtension.PATH_HANDLERS, + UndertowExtension.getResolver(Constants.HANDLER), + new AbstractAddStepHandler(), + ReloadRequiredRemoveStepHandler.INSTANCE + ); + } + + @Override + public Collection getAttributes() { + return Collections.emptySet(); + } + + @Override + public List getChildren() { + return HANDLERS; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/HandlerService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,80 @@ +/* + * 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.extension.undertow.handlers; + +import java.util.Collections; + +import io.undertow.server.HttpHandler; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.requestcontroller.ControlPoint; +import org.wildfly.extension.requestcontroller.RequestController; +import org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Tomaz Cerar (c) 2013 Red Hat Inc. + */ +public class HandlerService implements Service { + private final HttpHandler httpHandler; + private final InjectedValue requestControllerInjectedValue = new InjectedValue<>(); + private volatile ControlPoint controlPoint; + private volatile HttpHandler realHandler; + private final String name; + + public HandlerService(HttpHandler httpHandler, final String name) { + this.httpHandler = httpHandler; + this.name = name; + } + + @Override + public void start(StartContext context) throws StartException { + UndertowLogger.ROOT_LOGGER.tracef("starting handler: %s", httpHandler); + if(requestControllerInjectedValue.getOptionalValue() != null) { + controlPoint = requestControllerInjectedValue.getValue().getControlPoint("org.wildfly.extension.undertow.handlers", name); + realHandler = new GlobalRequestControllerHandler(httpHandler, controlPoint, Collections.emptyList()); + } else { + realHandler = httpHandler; + } + } + + @Override + public void stop(StopContext context) { + if(controlPoint != null) { + requestControllerInjectedValue.getValue().removeControlPoint(controlPoint); + controlPoint = null; + } + } + + @Override + public HttpHandler getValue() throws IllegalStateException, IllegalArgumentException { + return realHandler; + } + + public InjectedValue getRequestControllerInjectedValue() { + return requestControllerInjectedValue; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,159 @@ +/* + * 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.extension.undertow.handlers; + +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.ResponseCodeHandler; +import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; +import io.undertow.server.handlers.proxy.ProxyHandler; +import io.undertow.util.Headers; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.client.helpers.MeasurementUnit; +import org.jboss.as.controller.registry.AttributeAccess; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.wildfly.extension.undertow.Constants; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Stuart Douglas + */ +public class ReverseProxyHandler extends Handler { + + + public static final AttributeDefinition PROBLEM_SERVER_RETRY = new SimpleAttributeDefinitionBuilder(Constants.PROBLEM_SERVER_RETRY, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(30)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition SESSION_COOKIE_NAMES = new SimpleAttributeDefinitionBuilder(Constants.SESSION_COOKIE_NAMES, ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("JSESSIONID")) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + public static final AttributeDefinition CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(40)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition MAX_REQUEST_TIME = new SimpleAttributeDefinitionBuilder(Constants.MAX_REQUEST_TIME, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(-1)) + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition REQUEST_QUEUE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.REQUEST_QUEUE_SIZE, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(10)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + + public static final AttributeDefinition CACHED_CONNECTIONS_PER_THREAD = new SimpleAttributeDefinitionBuilder(Constants.CACHED_CONNECTIONS_PER_THREAD, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(5)) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition CONNECTION_IDLE_TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.CONNECTION_IDLE_TIMEOUT, ModelType.INT) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode(60L)) + .setMeasurementUnit(MeasurementUnit.SECONDS) + .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES) + .build(); + + public static final AttributeDefinition MAX_RETRIES = new SimpleAttributeDefinitionBuilder(Constants.MAX_RETRIES, ModelType.INT) + .setRequired(false) + .setRestartAllServices() + .setAllowExpression(true) + .setDefaultValue(new ModelNode(1L)) + .build(); + + public static final ReverseProxyHandler INSTANCE = new ReverseProxyHandler(); + + private ReverseProxyHandler() { + super(Constants.REVERSE_PROXY); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(CONNECTIONS_PER_THREAD, SESSION_COOKIE_NAMES, + PROBLEM_SERVER_RETRY, REQUEST_QUEUE_SIZE, MAX_REQUEST_TIME, + CACHED_CONNECTIONS_PER_THREAD, CONNECTION_IDLE_TIMEOUT, + MAX_RETRIES); + } + + @Override + protected List getChildren() { + return Collections.singletonList(ReverseProxyHandlerHost.INSTANCE); + } + + @Override + public HttpHandler createHandler(final OperationContext context, ModelNode model) throws OperationFailedException { + + String sessionCookieNames = SESSION_COOKIE_NAMES.resolveModelAttribute(context, model).asString(); + int connectionsPerThread = CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + int problemServerRetry = PROBLEM_SERVER_RETRY.resolveModelAttribute(context, model).asInt(); + int maxTime = MAX_REQUEST_TIME.resolveModelAttribute(context, model).asInt(); + int requestQueueSize = REQUEST_QUEUE_SIZE.resolveModelAttribute(context, model).asInt(); + int cachedConnectionsPerThread = CACHED_CONNECTIONS_PER_THREAD.resolveModelAttribute(context, model).asInt(); + int connectionIdleTimeout = CONNECTION_IDLE_TIMEOUT.resolveModelAttribute(context, model).asInt(); + int maxRetries = MAX_RETRIES.resolveModelAttribute(context, model).asInt(); + + + final LoadBalancingProxyClient lb = new LoadBalancingProxyClient(exchange -> { + //we always create a new connection for upgrade requests + return exchange.getRequestHeaders().contains(Headers.UPGRADE); + }) + .setConnectionsPerThread(connectionsPerThread) + .setMaxQueueSize(requestQueueSize) + .setSoftMaxConnectionsPerThread(cachedConnectionsPerThread) + .setTtl(connectionIdleTimeout) + .setProblemServerRetry(problemServerRetry); + String[] sessionIds = sessionCookieNames.split(","); + for (String id : sessionIds) { + lb.addSessionCookieName(id); + } + + ProxyHandler handler = new ProxyHandler(lb, maxTime, ResponseCodeHandler.HANDLE_404, false, false, maxRetries); + return handler; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHost.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHost.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/handlers/ReverseProxyHandlerHost.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,274 @@ +/* + * 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.extension.undertow.handlers; + +import static org.wildfly.extension.undertow.Capabilities.REF_OUTBOUND_SOCKET; +import static org.wildfly.extension.undertow.Capabilities.REF_SSL_CONTEXT; +import static org.wildfly.extension.undertow.Capabilities.CAPABILITY_REVERSE_PROXY_HANDLER_HOST; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collection; +import javax.net.ssl.SSLContext; + +import io.undertow.UndertowOptions; +import io.undertow.protocols.ssl.UndertowXnioSsl; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; +import io.undertow.server.handlers.proxy.ProxyHandler; +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.CapabilityServiceBuilder; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ServiceRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.operations.validation.StringLengthValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.as.domain.management.SecurityRealm; +import org.jboss.as.network.OutboundSocketBinding; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Constants; +import org.wildfly.extension.undertow.UndertowExtension; +import org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler; +import org.xnio.OptionMap; +import org.xnio.Options; +import org.xnio.Xnio; +import org.xnio.ssl.XnioSsl; + +/** + * @author Stuart Douglas + * @author Tomaz Cerar + */ +public class ReverseProxyHandlerHost extends PersistentResourceDefinition { + + private static final RuntimeCapability REVERSE_PROXY_HOST_RUNTIME_CAPABILITY = + RuntimeCapability.Builder.of(CAPABILITY_REVERSE_PROXY_HANDLER_HOST, true, ReverseProxyHostService.class) + .setDynamicNameMapper(path -> new String[]{ + path.getParent().getLastElement().getValue(), + path.getLastElement().getValue()}) + .build(); + + public static final SimpleAttributeDefinition OUTBOUND_SOCKET_BINDING = new SimpleAttributeDefinitionBuilder("outbound-socket-binding", ModelType.STRING, true) + .setRequired(true) + .setValidator(new StringLengthValidator(1, false)) + .setAllowExpression(true) + .setRestartAllServices() + .addAccessConstraint(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF) + .setCapabilityReference(REF_OUTBOUND_SOCKET) + .build(); + + public static final AttributeDefinition SCHEME = new SimpleAttributeDefinitionBuilder("scheme", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("http")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition PATH = new SimpleAttributeDefinitionBuilder("path", ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setDefaultValue(new ModelNode("/")) + .setRestartAllServices() + .build(); + + public static final AttributeDefinition INSTANCE_ID = new SimpleAttributeDefinitionBuilder(Constants.INSTANCE_ID, ModelType.STRING) + .setRequired(false) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + + public static final SimpleAttributeDefinition SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.SSL_CONTEXT, ModelType.STRING, true) + .setAlternatives(Constants.SECURITY_REALM) + .setCapabilityReference(REF_SSL_CONTEXT) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SSL_REF) + .build(); + + public static final SimpleAttributeDefinition SECURITY_REALM = new SimpleAttributeDefinitionBuilder(Constants.SECURITY_REALM, ModelType.STRING) + .setAlternatives(Constants.SSL_CONTEXT) + .setRequired(false) + .setRestartAllServices() + .setValidator(new StringLengthValidator(1)) + .setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SECURITY_REALM_REF) + .build(); + + public static final SimpleAttributeDefinition ENABLE_HTTP2 = new SimpleAttributeDefinitionBuilder(Constants.ENABLE_HTTP2, ModelType.BOOLEAN) + .setRequired(false) + .setDefaultValue(new ModelNode(false)) + .setRestartAllServices() + .build(); + + + public static final ReverseProxyHandlerHost INSTANCE = new ReverseProxyHandlerHost(); + + private ReverseProxyHandlerHost() { + super(new Parameters(PathElement.pathElement(Constants.HOST), UndertowExtension.getResolver(Constants.HANDLER, Constants.REVERSE_PROXY, Constants.HOST)) + .setCapabilities(REVERSE_PROXY_HOST_RUNTIME_CAPABILITY) + ); + } + + @Override + public Collection getAttributes() { + return Arrays.asList(OUTBOUND_SOCKET_BINDING, SCHEME, INSTANCE_ID, PATH, SSL_CONTEXT, SECURITY_REALM, ENABLE_HTTP2); + } + + + @Override + public void registerOperations(ManagementResourceRegistration resourceRegistration) { + super.registerOperations(resourceRegistration); + ReverseProxyHostAdd add = new ReverseProxyHostAdd(); + registerAddOperation(resourceRegistration, add, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + registerRemoveOperation(resourceRegistration, new ServiceRemoveStepHandler(add) { + @Override + protected ServiceName serviceName(String name, final PathAddress address) { + return REVERSE_PROXY_HOST_RUNTIME_CAPABILITY.getCapabilityServiceName(address); + } + }, OperationEntry.Flag.RESTART_RESOURCE_SERVICES); + } + + private final class ReverseProxyHostAdd extends AbstractAddStepHandler { + public ReverseProxyHostAdd() { + super(getAttributes()); + } + + @Override + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { + final PathAddress address = context.getCurrentAddress(); + final String proxyName = address.getElement(address.size() - 2).getValue(); + final String socketBinding = OUTBOUND_SOCKET_BINDING.resolveModelAttribute(context, model).asString(); + final String scheme = SCHEME.resolveModelAttribute(context, model).asString(); + final String path = PATH.resolveModelAttribute(context, model).asString(); + final boolean enableHttp2 = ENABLE_HTTP2.resolveModelAttribute(context, model).asBoolean(); + final String jvmRoute; + final ModelNode securityRealm = SECURITY_REALM.resolveModelAttribute(context, model); + final ModelNode sslContext = SSL_CONTEXT.resolveModelAttribute(context, model); + if (model.hasDefined(Constants.INSTANCE_ID)) { + jvmRoute = INSTANCE_ID.resolveModelAttribute(context, model).asString(); + } else { + jvmRoute = null; + } + ReverseProxyHostService service = new ReverseProxyHostService(scheme, jvmRoute, path, enableHttp2); + CapabilityServiceBuilder builder = context.getCapabilityServiceTarget() + .addCapability(REVERSE_PROXY_HOST_RUNTIME_CAPABILITY, service) + .addCapabilityRequirement(Capabilities.CAPABILITY_HANDLER, HttpHandler.class, service.proxyHandler, proxyName) + .addCapabilityRequirement(Capabilities.REF_OUTBOUND_SOCKET, OutboundSocketBinding.class, service.socketBinding, socketBinding); + + if (sslContext.isDefined()) { + builder.addCapabilityRequirement(REF_SSL_CONTEXT, SSLContext.class, service.sslContext, sslContext.asString()); + } + if(securityRealm.isDefined()) { + SecurityRealm.ServiceUtil.addDependency(builder, service.securityRealm, securityRealm.asString()); + } + builder.install(); + } + } + + private static final class ReverseProxyHostService implements Service { + + private final InjectedValue proxyHandler = new InjectedValue<>(); + private final InjectedValue socketBinding = new InjectedValue<>(); + private final InjectedValue securityRealm = new InjectedValue<>(); + private final InjectedValue sslContext = new InjectedValue<>(); + + private final String instanceId; + private final String scheme; + private final String path; + private final boolean enableHttp2; + + private ReverseProxyHostService(String scheme, String instanceId, String path, boolean enableHttp2) { + this.instanceId = instanceId; + this.scheme = scheme; + this.path = path; + this.enableHttp2 = enableHttp2; + } + private URI getUri() throws URISyntaxException { + OutboundSocketBinding binding = socketBinding.getValue(); + return new URI(scheme, null, binding.getUnresolvedDestinationAddress(), binding.getDestinationPort(), path, null, null); + } + + @Override + public void start(StartContext startContext) throws StartException { + //todo: this is a bit of a hack, as the proxy handler may be wrapped by a request controller handler for graceful shutdown + ProxyHandler proxyHandler = (ProxyHandler) (this.proxyHandler.getValue() instanceof GlobalRequestControllerHandler ? ((GlobalRequestControllerHandler)this.proxyHandler.getValue()).getNext() : this.proxyHandler.getValue()); + + final LoadBalancingProxyClient client = (LoadBalancingProxyClient) proxyHandler.getProxyClient(); + try { + SSLContext sslContext = this.sslContext.getOptionalValue(); + if (sslContext == null) { + SecurityRealm securityRealm = this.securityRealm.getOptionalValue(); + if (securityRealm != null) { + sslContext = securityRealm.getSSLContext(); + } + } + + if (sslContext == null) { + client.addHost(getUri(), instanceId, null, OptionMap.create(UndertowOptions.ENABLE_HTTP2, enableHttp2)); + } else { + OptionMap.Builder builder = OptionMap.builder(); + builder.set(Options.USE_DIRECT_BUFFERS, true); + OptionMap combined = builder.getMap(); + + XnioSsl xnioSsl = new UndertowXnioSsl(Xnio.getInstance(), combined, sslContext); + client.addHost(getUri(), instanceId, xnioSsl, OptionMap.create(UndertowOptions.ENABLE_HTTP2, enableHttp2)); + } + } catch (URISyntaxException e) { + throw new StartException(e); + } + } + + @Override + public void stop(StopContext stopContext) { + ProxyHandler proxyHandler = (ProxyHandler) (this.proxyHandler.getValue() instanceof GlobalRequestControllerHandler ? ((GlobalRequestControllerHandler)this.proxyHandler.getValue()).getNext() : this.proxyHandler.getValue()); + final LoadBalancingProxyClient client = (LoadBalancingProxyClient) proxyHandler.getProxyClient(); + try { + client.removeHost(getUri()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); //impossible + } + } + + @Override + public ReverseProxyHostService getValue() throws IllegalStateException, IllegalArgumentException { + return this; + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/logging/UndertowLogger.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/logging/UndertowLogger.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/logging/UndertowLogger.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,413 @@ +/* + * 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.extension.undertow.logging; + +import static org.jboss.logging.Logger.Level.ERROR; +import static org.jboss.logging.Logger.Level.INFO; +import static org.jboss.logging.Logger.Level.WARN; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.DeploymentUnitProcessingException; +import org.jboss.dmr.ModelNode; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassInfo; +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.Cause; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartException; +import org.jboss.vfs.VirtualFile; + +/** + * @author James R. Perkins + */ +@MessageLogger(projectCode = "WFLYUT", length = 4) +public interface UndertowLogger extends BasicLogger { + + /** + * A root logger with the category of the package name. + */ + UndertowLogger ROOT_LOGGER = Logger.getMessageLogger(UndertowLogger.class, "org.wildfly.extension.undertow"); + + + /* + UNDERTOW messages start + */ + + @LogMessage(level = Logger.Level.ERROR) + @Message(id = 1, value = "Could not initialize JSP") + void couldNotInitJsp(@Cause ClassNotFoundException e); + + // @LogMessage(level = ERROR) + // @Message(id = 2, value = "Failed to purge EL cache.") + // void couldNotPurgeELCache(@Cause Exception exception); + + @LogMessage(level = INFO) + @Message(id = 3, value = "Undertow %s starting") + void serverStarting(String version); + + @LogMessage(level = INFO) + @Message(id = 4, value = "Undertow %s stopping") + void serverStopping(String version); + + @LogMessage(level = WARN) + @Message(id = 5, value = "Secure listener for protocol: '%s' not found! Using non secure port!") + void secureListenerNotAvailableForPort(String protocol); + + /** + * Creates an exception indicating the class, represented by the {@code className} parameter, cannot be accessed. + * + * @param name name of the listener + * @param address socket address + */ + @LogMessage(level = INFO) + @Message(id = 6, value = "Undertow %s listener %s listening on %s:%d") + void listenerStarted(String type, String name, String address, int port); + + @LogMessage(level = INFO) + @Message(id = 7, value = "Undertow %s listener %s stopped, was bound to %s:%d") + void listenerStopped(String type, String name, String address, int port); + + @LogMessage(level = INFO) + @Message(id = 8, value = "Undertow %s listener %s suspending") + void listenerSuspend(String type, String name); + + @LogMessage(level = INFO) + @Message(id = 9, value = "Could not load class designated by HandlesTypes [%s].") + void cannotLoadDesignatedHandleTypes(ClassInfo classInfo, @Cause Exception e); + + @LogMessage(level = WARN) + @Message(id = 10, value = "Could not load web socket endpoint %s.") + void couldNotLoadWebSocketEndpoint(String s, @Cause Exception e); + + @LogMessage(level = WARN) + @Message(id = 11, value = "Could not load web socket application config %s.") + void couldNotLoadWebSocketConfig(String s, @Cause Exception e); + + @LogMessage(level = INFO) + @Message(id = 12, value = "Started server %s.") + void startedServer(String name); + + @LogMessage(level = WARN) + @Message(id = 13, value = "Could not create redirect URI.") + void invalidRedirectURI(@Cause Throwable cause); + + @LogMessage(level = INFO) + @Message(id = 14, value = "Creating file handler for path '%s' with options [directory-listing: '%s', follow-symlink: '%s', case-sensitive: '%s', safe-symlink-paths: '%s']") + void creatingFileHandler(String path, boolean directoryListing, boolean followSymlink, boolean caseSensitive, List safePaths); + + // @LogMessage(level = TRACE) + // @Message(id = 15, value = "registering handler %s under path '%s'") + // void registeringHandler(HttpHandler value, String locationPath); + + @LogMessage(level = WARN) + @Message(id = 16, value = "Could not resolve name in absolute ordering: %s") + void invalidAbsoluteOrdering(String name); + + @LogMessage(level = WARN) + @Message(id = 17, value = "Could not delete servlet temp file %s") + void couldNotDeleteTempFile(File file); + + @LogMessage(level = INFO) + @Message(id = 18, value = "Host %s starting") + void hostStarting(String version); + + @LogMessage(level = INFO) + @Message(id = 19, value = "Host %s stopping") + void hostStopping(String version); + + @LogMessage(level = WARN) + @Message(id = 20, value = "Clustering not supported, falling back to non-clustered session manager") + void clusteringNotSupported(); + + + @LogMessage(level = INFO) + @Message(id = 21, value = "Registered web context: '%s' for server '%s'") + void registerWebapp(String webappPath, String serverName); + + @LogMessage(level = INFO) + @Message(id = 22, value = "Unregistered web context: '%s' from server '%s'") + void unregisterWebapp(String webappPath, String serverName); + + @LogMessage(level = INFO) + @Message(id = 23, value = "Skipped SCI for jar: %s.") + void skippedSCI(String jar, @Cause Exception e); + + @LogMessage(level = Logger.Level.WARN) + @Message(id = 24, value = "Failed to persist session attribute %s with value %s for session %s") + void failedToPersistSessionAttribute(String attributeName, Object value, String sessionID, @Cause Exception e); + + @LogMessage(level = ERROR) + @Message(id = 25, value = "Failed to register policy context handler for key %s") + void failedToRegisterPolicyContextHandler(String key, @Cause Exception e); + + // @Message(id = 26, value = "Unknown handler '%s' encountered") + // XMLStreamException unknownHandler(String name, @Param Location location); + + @Message(id = 27, value = "Failed to parse XML descriptor %s at [%s,%s]") + String failToParseXMLDescriptor(String xmlFile, Integer line, Integer column); + + @Message(id = 28, value = "Failed to parse XML descriptor %s") + String failToParseXMLDescriptor(String xmlFile); + + @Message(id = 29, value = "@WebServlet is only allowed at class level %s") + String invalidWebServletAnnotation(AnnotationTarget target); + + @Message(id = 30, value = "@WebInitParam requires name and value on %s") + String invalidWebInitParamAnnotation(AnnotationTarget target); + + @Message(id = 31, value = "@WebFilter is only allowed at class level %s") + String invalidWebFilterAnnotation(AnnotationTarget target); + + @Message(id = 32, value = "@WebListener is only allowed at class level %s") + String invalidWebListenerAnnotation(AnnotationTarget target); + + @Message(id = 33, value = "@RunAs needs to specify a role name on %s") + String invalidRunAsAnnotation(AnnotationTarget target); + + @Message(id = 34, value = "@DeclareRoles needs to specify role names on %s") + String invalidDeclareRolesAnnotation(AnnotationTarget target); + + @Message(id = 35, value = "@MultipartConfig is only allowed at class level %s") + String invalidMultipartConfigAnnotation(AnnotationTarget target); + + @Message(id = 36, value = "@ServletSecurity is only allowed at class level %s") + String invalidServletSecurityAnnotation(AnnotationTarget target); + + @Message(id = 37, value = "%s has the wrong component type, it cannot be used as a web component") + RuntimeException wrongComponentType(String clazz); + + @Message(id = 38, value = "TLD file %s not contained in root %s") + String tldFileNotContainedInRoot(String tldPath, String rootPath); + + @Message(id = 39, value = "Failed to resolve module for deployment %s") + DeploymentUnitProcessingException failedToResolveModule(DeploymentUnit deploymentUnit); + + @Message(id = 40, value = "Duplicate others in absolute ordering") + String invalidMultipleOthers(); + + @Message(id = 41, value = "Invalid relative ordering") + String invalidRelativeOrdering(); + + @Message(id = 42, value = "Conflict occurred processing web fragment in JAR: %s") + String invalidWebFragment(String jar); + + @Message(id = 43, value = "Relative ordering processing error with JAR: %s") + String invalidRelativeOrdering(String jar); + + @Message(id = 44, value = "Ordering includes both before and after others in JAR: %s") + String invalidRelativeOrderingBeforeAndAfter(String jar); + + @Message(id = 45, value = "Duplicate name declared in JAR: %s") + String invalidRelativeOrderingDuplicateName(String jar); + + @LogMessage(level = WARN) + @Message(id = 46, value = "Unknown web fragment name declared in JAR: %s") + void invalidRelativeOrderingUnknownName(String jar); + + @Message(id = 47, value = "Relative ordering conflict with JAR: %s") + String invalidRelativeOrderingConflict(String jar); + + @Message(id = 48, value = "Failed to process WEB-INF/lib: %s") + String failToProcessWebInfLib(VirtualFile xmlFile); + + @Message(id = 49, value = "Error loading SCI from module: %s") + DeploymentUnitProcessingException errorLoadingSCIFromModule(String identifier, @Cause Exception e); + + @Message(id = 50, value = "Unable to resolve annotation index for deployment unit: %s") + DeploymentUnitProcessingException unableToResolveAnnotationIndex(DeploymentUnit deploymentUnit); + + @Message(id = 51, value = "Deployment error processing SCI for jar: %s") + DeploymentUnitProcessingException errorProcessingSCI(String jar, @Cause Exception e); + + @Message(id = 52, value = "Security context creation failed") + RuntimeException failToCreateSecurityContext(@Cause Throwable t); + + @Message(id = 53, value = "No security context found") + IllegalStateException noSecurityContext(); + + @Message(id = 54, value = "Unknown metric %s") + String unknownMetric(Object metric); + + @Message(id = 55, value = "Null default host") + IllegalArgumentException nullDefaultHost(); + + @Message(id = 56, value = "Null host name") + IllegalStateException nullHostName(); + + @Message(id = 57, value = "Null parameter %s") + IllegalArgumentException nullParamter(String id); + + @Message(id = 58, value = "Cannot activate context: %s") + IllegalStateException cannotActivateContext(@Cause Throwable th, ServiceName service); + + @Message(id = 59, value = "Could not construct handler for class: %s. with parameters %s") + RuntimeException cannotCreateHttpHandler(Class handlerClass, ModelNode parameters, @Cause Throwable cause); + + @Message(id = 60, value = "Invalid persistent sessions directory %s") + StartException invalidPersistentSessionDir(File baseDir); + + @Message(id = 61, value = "Failed to create persistent sessions dir %s") + StartException failedToCreatePersistentSessionDir(File baseDir); + + @Message(id = 62, value = "Could not create log directory: %s") + StartException couldNotCreateLogDirectory(Path directory, @Cause IOException e); + + @Message(id = 63, value = "Could not find the port number listening for protocol %s") + IllegalStateException noPortListeningForProtocol(final String protocol); + + @Message(id = 64, value = "Failed to configure handler %s") + RuntimeException failedToConfigureHandler(Class handlerClass, @Cause Exception e); + + @Message(id = 65, value = "Handler class %s was not a handler or a wrapper") + IllegalArgumentException handlerWasNotAHandlerOrWrapper(Class handlerClass); + + @Message(id = 66, value = "Failed to configure handler %s") + RuntimeException failedToConfigureHandlerClass(String handlerClass, @Cause Exception e); + + @Message(id = 67, value = "Servlet class not defined for servlet %s") + IllegalArgumentException servletClassNotDefined(final String servletName); + + @LogMessage(level = ERROR) + @Message(id = 68, value = "Error obtaining authorization helper") + void noAuthorizationHelper(@Cause Exception e); + + @LogMessage(level = ERROR) + @Message(id = 69, value = "Ignoring shared-session-config in jboss-all.xml in deployment %s. This entry is only valid in top level deployments.") + void sharedSessionConfigNotInRootDeployment(String deployment); + + @Message(id = 70, value = "Could not load handler %s from %s module") + RuntimeException couldNotLoadHandlerFromModule(String className, String moduleName, @Cause Exception e); + + @LogMessage(level = WARN) + @Message(id = 71, value = "No ALPN provider found, HTTP/2 will not be enabled. To remove this message set enable-http2 to false on the listener %s in the Undertow subsystem.") + void alpnNotFound(String listener); + + @Message(id = 72, value = "Could not find configured external path %s") + DeploymentUnitProcessingException couldNotFindExternalPath(File path); + + @Message(id = 73, value = "mod_cluster advertise socket binding requires multicast address to be set") + StartException advertiseSocketBindingRequiresMulticastAddress(); + + @LogMessage(level = ERROR) + @Message(id = 74, value = "Could not find TLD %s") + void tldNotFound(String location); + + @Message(id = 75, value = "Cannot register resource of type %s") + IllegalArgumentException cannotRegisterResourceOfType(String type); + + @Message(id = 76, value = "Cannot remove resource of type %s") + IllegalArgumentException cannotRemoveResourceOfType(String type); + + @LogMessage(level = ERROR) + @Message(id = 78, value = "Failed to register management view for websocket %s at %s") + void failedToRegisterWebsocket(Class endpoint, String path, @Cause Exception e); + + @LogMessage(level = ERROR) + @Message(id = 77, value = "Error invoking secure response") + void errorInvokingSecureResponse(@Cause Exception e); + + @Message(id = 79, value = "No SSL Context available from security realm '%s'. Either the realm is not configured for SSL, or the server has not been reloaded since the SSL config was added.") + IllegalStateException noSslContextInSecurityRealm(String securityRealm); + + @LogMessage(level = WARN) + @Message(id = 80, value = "Valves are no longer supported, %s is not activated.") + void unsupportedValveFeature(String valve); + + @LogMessage(level = WARN) + @Message(id = 81, value = "The deployment %s will not be distributable because this feature is disabled in web-fragment.xml of the module %s.") + void distributableDisabledInFragmentXml(String deployment, String module); + + @Message(id = 82, value = "Could not start '%s' listener.") + StartException couldNotStartListener(String name, @Cause IOException e); + + @Message(id = 83, value = "%s is not allowed to be null") + String nullNotAllowed(String name); + + //@Message(id = 84, value = "There are no mechanisms available from the HttpAuthenticationFactory.") + //IllegalStateException noMechanismsAvailable(); + + //@Message(id = 85, value = "The required mechanism '%s' is not available in mechanisms %s from the HttpAuthenticationFactory.") + //IllegalStateException requiredMechanismNotAvailable(String mechanismName, Collection availableMechanisms); + + //@Message(id = 86, value = "No authentication mechanisms have been selected.") + //IllegalStateException noMechanismsSelected(); + + @Message(id = 87, value = "Duplicate default web module '%s' configured on server '%s', host '%s'") + IllegalArgumentException duplicateDefaultWebModuleMapping(String defaultDeploymentName, String serverName, String hostName); + +// @LogMessage(level = WARN) +// @Message(id = 88, value = "HTTP/2 will not be enabled as TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 is not enabled. You may need to install JCE to enable strong ciphers to allow HTTP/2 to function.") +// void noStrongCiphers(); + + @Message(id = 89, value = "Predicate %s was not valid, message was: %s") + String predicateNotValid(String predicate, String error); + + @Message(id = 90, value = "Key alias %s does not exist in the configured key store") + IllegalArgumentException missingKeyStoreEntry(String alias); + + @Message(id = 91, value = "Key store entry %s is not a private key entry") + IllegalArgumentException keyStoreEntryNotPrivate(String alias); + + @Message(id = 92, value = "Credential alias %s does not exist in the configured credential store") + IllegalArgumentException missingCredential(String alias); + + @Message(id = 93, value = "Credential %s is not a clear text password") + IllegalArgumentException credentialNotClearPassword(String alias); + + @Message(id = 94, value = "Configuration option [%s] ignored when using Elytron subsystem") + @LogMessage(level = WARN) + void configurationOptionIgnoredWhenUsingElytron(String option); + + @Message(id = 95, value = "the path ['%s'] doesn't exist on file system") + String unableAddHandlerForPath(String path); + + //@Message(id = 96, value = "Unable to obtain identity for name %s") + //IllegalStateException unableToObtainIdentity(String name, @Cause Throwable cause); + + @Message(id = 97, value = "If http-upgrade is enabled, remoting worker and http(s) worker must be the same. Please adjust values if need be.") + String workerValueInHTTPListenerMustMatchRemoting(); + + @LogMessage(level = ERROR) + @Message(id = 98, value = "Unexpected Authentication Error: %s") + void unexceptedAuthentificationError(String errorMessage, @Cause Throwable t); + + @Message(id = 99, value = "Session manager not available") + OperationFailedException sessionManagerNotAvailable(); + + @Message(id = 100, value = "Session %s not found") + OperationFailedException sessionNotFound(String sessionId); + + @LogMessage(level = WARN) + @Message(id = 101, value = "Duplicate servlet mapping %s found") + void duplicateServletMapping(String mapping); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AccountImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AccountImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AccountImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,165 @@ +/* + * 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.extension.undertow.security; + +import java.io.Serializable; +import java.security.Principal; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import io.undertow.security.idm.Account; + +/** + * + * @author Stuart Douglas + * @author Darran Lofthouse + */ +public class AccountImpl implements Account, Serializable { + + private static final long serialVersionUID = 1L; + + private final String name; + private final Set roles = new CopyOnWriteArraySet<>(); + private final Principal principal; + private final Object credential; + + private final Principal originalPrincipal; + + public AccountImpl(final String name) { + this.name = name; + this.principal = new AccountPrincipal(name); + this.credential = null; + this.originalPrincipal = null; + } + + public AccountImpl(final Principal principal) { + this.principal = principal; + this.name = principal.getName(); + this.credential = null; + this.originalPrincipal = null; + } + public AccountImpl(final Principal principal, Set roles, final Object credential, Principal originalPrincipal) { + this.principal = principal; + this.credential = credential; + this.originalPrincipal = originalPrincipal; + this.name = principal.getName(); + this.roles.addAll(roles); + } + + public AccountImpl(final Principal principal, Set roles, final Object credential) { + this.principal = principal; + this.credential = credential; + this.originalPrincipal = null; + this.name = principal.getName(); + this.roles.addAll(roles); + } + + void setRoles(final Set roles) { + this.roles.clear(); + roles.addAll(roles); + } + + @Override + public boolean equals(final Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + final AccountImpl account = (AccountImpl) o; + + if (name != null ? !name.equals(account.name) : account.name != null) + return false; + + return true; + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 0; + } + + @Override + public Principal getPrincipal() { + return principal; + } + + @Override + public Set getRoles() { + return Collections.unmodifiableSet(roles); + } + + /** + * If the original principal was set then this will be returned, otherwise + * it will return the current principal. + * + * If principal mapping is used the principal for the verified account can be different + * to the principal that need to be used for authentication. When calling + * {@link io.undertow.security.idm.IdentityManager#verify(io.undertow.security.idm.Account)} + * for an existing account this is the principal that must be used. + * + * see UNDERTOW-273 + * @return The original principal + */ + public Principal getOriginalPrincipal() { + if (originalPrincipal != null) { + return originalPrincipal; + } + return principal; + } + + public Object getCredential() { + return credential; + } + + private static class AccountPrincipal implements Principal, Serializable { + + private static final long serialVersionUID = 1L; + private String name; + + public AccountPrincipal(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof AccountPrincipal ? equals((AccountPrincipal) obj) : false; + } + + private boolean equals(AccountPrincipal other) { + return name.equals(other.getName()); + } + + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AuditNotificationReceiver.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AuditNotificationReceiver.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/AuditNotificationReceiver.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,120 @@ +/* + * 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.extension.undertow.security; + +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import io.undertow.security.api.NotificationReceiver; +import io.undertow.security.api.SecurityNotification; +import io.undertow.security.api.SecurityNotification.EventType; +import io.undertow.security.idm.Account; +import io.undertow.servlet.handlers.ServletRequestContext; +import org.jboss.security.audit.AuditEvent; +import org.jboss.security.audit.AuditLevel; +import org.jboss.security.audit.AuditManager; + +/** + * A {@link NotificationReceiver} implementation responsible for recording audit events for authentication attempts. + * + * @author Darran Lofthouse + */ +public class AuditNotificationReceiver implements NotificationReceiver { + + private final AuditManager auditManager; + + public AuditNotificationReceiver(final AuditManager auditManager) { + this.auditManager = auditManager; + } + + @Override + public void handleNotification(SecurityNotification notification) { + EventType event = notification.getEventType(); + if (event == EventType.AUTHENTICATED || event == EventType.FAILED_AUTHENTICATION) { + AuditEvent auditEvent = new AuditEvent(event == EventType.AUTHENTICATED ? AuditLevel.SUCCESS : AuditLevel.FAILURE); + Map ctxMap = new HashMap(); + Account account = notification.getAccount(); + if (account != null) { + ctxMap.put("principal", account.getPrincipal().getName()); + } + ctxMap.put("message", notification.getMessage()); + + ServletRequestContext src = notification.getExchange().getAttachment(ServletRequestContext.ATTACHMENT_KEY); + if(src != null) { + ServletRequest hsr = src.getServletRequest(); + if (hsr instanceof HttpServletRequest) { + ctxMap.put("request", deriveUsefulInfo((HttpServletRequest) hsr)); + } + } + ctxMap.put("Source", getClass().getCanonicalName()); + auditEvent.setContextMap(ctxMap); + auditManager.audit(auditEvent); + + } + } + + /** + * Obtain debug information from the servlet request object + * + * @param httpRequest + * @return + */ + private static String deriveUsefulInfo(HttpServletRequest httpRequest) { + StringBuilder sb = new StringBuilder(); + sb.append("[").append(httpRequest.getContextPath()); + sb.append(":cookies=").append(Arrays.toString(httpRequest.getCookies())).append(":headers="); + // Append Header information + Enumeration en = httpRequest.getHeaderNames(); + while (en.hasMoreElements()) { + String headerName = (String) en.nextElement(); + sb.append(headerName).append("="); + // Ensure HTTP Basic Password is not logged + if (!headerName.contains("authorization")) { sb.append(httpRequest.getHeader(headerName)).append(","); } + } + sb.append("]"); + // Append Request parameter information + sb.append("[parameters="); + Enumeration enparam = httpRequest.getParameterNames(); + while (enparam.hasMoreElements()) { + String paramName = (String) enparam.nextElement(); + String[] paramValues = httpRequest.getParameterValues(paramName); + int len = paramValues != null ? paramValues.length : 0; + for (int i = 0; i < len; i++) { sb.append(paramValues[i]).append("::"); } + sb.append(","); + } + sb.append("][attributes="); + // Append Request attribute information + Enumeration enu = httpRequest.getAttributeNames(); + while (enu.hasMoreElements()) { + String attrName = (String) enu.nextElement(); + sb.append(attrName).append("="); + sb.append(httpRequest.getAttribute(attrName)).append(","); + } + sb.append("]"); + return sb.toString(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/DigestCredentialImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/DigestCredentialImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/DigestCredentialImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,60 @@ +/* + * 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.extension.undertow.security; + +import java.util.UUID; + +import org.jboss.as.security.DigestCredential; + +/** + * Implementation to map from the Undertow variant to the WildFly variant. + * + * @author Darran Lofthouse + */ +final class DigestCredentialImpl implements DigestCredential { + + private final String uniqueValue = UUID.randomUUID().toString(); + private final io.undertow.security.idm.DigestCredential wrapped; + + DigestCredentialImpl(final io.undertow.security.idm.DigestCredential wrapped) { + this.wrapped = wrapped; + } + + @Override + public boolean verifyHA1(byte[] ha1) { + return wrapped.verifyHA1(ha1); + } + + @Override + public String getRealm() { + return wrapped.getRealm(); + } + + @Override + public String toString() { + // Not actually used for validation in a correctly configured installation, however a randomly generated UUID is + // returned for bad configurations. + return uniqueValue; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JAASIdentityManagerImpl.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JAASIdentityManagerImpl.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JAASIdentityManagerImpl.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,177 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.security.idm.Account; +import io.undertow.security.idm.Credential; + +import org.wildfly.extension.undertow.security.digest.DigestCredential; + +import io.undertow.security.idm.IdentityManager; +import io.undertow.security.idm.PasswordCredential; +import io.undertow.security.idm.X509CertificateCredential; + +import java.security.Principal; +import java.security.acl.Group; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.jboss.as.security.plugins.SecurityDomainContext; +import org.jboss.security.AuthenticationManager; +import org.jboss.security.AuthorizationManager; +import org.jboss.security.SecurityConstants; +import org.jboss.security.SecurityContext; +import org.jboss.security.auth.callback.CallbackHandlerPolicyContextHandler; +import org.jboss.security.auth.callback.DigestCallbackHandler; +import org.jboss.security.callbacks.SecurityContextCallbackHandler; +import org.jboss.security.identity.Role; +import org.jboss.security.identity.RoleGroup; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * @author Stuart Douglas + * @author Darran Lofthouse + */ +public class JAASIdentityManagerImpl implements IdentityManager { + + private final SecurityDomainContext securityDomainContext; + + public JAASIdentityManagerImpl(final SecurityDomainContext securityDomainContext) { + this.securityDomainContext = securityDomainContext; + } + + @Override + public Account verify(Account account) { + // This method is called for previously verfified accounts so just accept it for the moment. + if (!(account instanceof AccountImpl)) { + UndertowLogger.ROOT_LOGGER.tracef("Account is not an AccountImpl", account); + return null; + } + AccountImpl accountImpl = (AccountImpl) account; + return verifyCredential(accountImpl, accountImpl.getCredential()); + } + + @Override + public Account verify(String id, Credential credential) { + AccountImpl account = getAccount(id); + if (credential instanceof DigestCredential) { + DigestCredential digestCredential = (DigestCredential) credential; + DigestCallbackHandler handler = new DigestCallbackHandler(id, digestCredential.getNonce(), digestCredential.getNonceCount(), + digestCredential.getClientNonce(), digestCredential.getQop(), digestCredential.getRealm(), + digestCredential.getHA2()); + CallbackHandlerPolicyContextHandler.setCallbackHandler(handler); + + return verifyCredential(account, digestCredential.getClientDigest()); + } else if(credential instanceof PasswordCredential) { + final char[] password = ((PasswordCredential) credential).getPassword(); + // The original array may be cleared, this integration relies on it being cached for use later. + final char[] duplicate = Arrays.copyOf(password, password.length); + return verifyCredential(account, duplicate); + } else { + return verifyCredential(account, credential); + } + } + + @Override + public Account verify(Credential credential) { + if (credential instanceof X509CertificateCredential) { + X509CertificateCredential certCredential = (X509CertificateCredential) credential; + X509Certificate certificate = certCredential.getCertificate(); + AccountImpl account = getAccount(certificate.getSubjectDN().getName()); + + return verifyCredential(account, certificate); + } + throw new IllegalArgumentException("Parameter must be a X509CertificateCredential"); + } + + private AccountImpl getAccount(final String id) { + return new AccountImpl(id); + } + + private Account verifyCredential(final AccountImpl account, final Object credential) { + final AuthenticationManager authenticationManager = securityDomainContext.getAuthenticationManager(); + final AuthorizationManager authorizationManager = securityDomainContext.getAuthorizationManager(); + final SecurityContext sc = SecurityActions.getSecurityContext(); + Principal incomingPrincipal = account.getOriginalPrincipal(); + Subject subject = new Subject(); + try { + boolean isValid = authenticationManager.isValid(incomingPrincipal, credential, subject); + if (isValid) { + UndertowLogger.ROOT_LOGGER.tracef("User: %s is authenticated", incomingPrincipal); + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + Principal userPrincipal = getPrincipal(subject); + sc.getUtil().createSubjectInfo(incomingPrincipal, credential, subject); + SecurityContextCallbackHandler scb = new SecurityContextCallbackHandler(sc); + RoleGroup roles = authorizationManager.getSubjectRoles(subject, scb); + Set roleSet = new HashSet<>(); + for (Role role : roles.getRoles()) { + roleSet.add(role.getRoleName()); + } + return new AccountImpl(userPrincipal, roleSet, credential, account.getOriginalPrincipal()); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + + /** + * Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is + * considered or the single principal inside the CallerPrincipal group. + * + * @param subject + * @return the authenticated principal + */ + private Principal getPrincipal(Subject subject) { + Principal principal = null; + Principal callerPrincipal = null; + if (subject != null) { + Set principals = subject.getPrincipals(); + if (principals != null && !principals.isEmpty()) { + for (Principal p : principals) { + if (!(p instanceof Group) && principal == null) { + principal = p; + } + if (p instanceof Group) { + Group g = Group.class.cast(p); + if (g.getName().equals(SecurityConstants.CALLER_PRINCIPAL_GROUP) && callerPrincipal == null) { + Enumeration e = g.members(); + if (e.hasMoreElements()) + callerPrincipal = e.nextElement(); + } + } + } + } + } + return callerPrincipal == null ? principal : callerPrincipal; + } + + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JbossAuthorizationManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JbossAuthorizationManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/JbossAuthorizationManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,231 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.security.idm.Account; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.api.AuthorizationManager; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.SecurityRoleRef; +import io.undertow.servlet.api.ServletInfo; +import io.undertow.servlet.api.SingleConstraintMatch; +import io.undertow.servlet.api.TransportGuaranteeType; +import io.undertow.servlet.handlers.ServletRequestContext; +import org.jboss.as.core.security.SimplePrincipal; +import org.jboss.security.SecurityContext; +import org.jboss.security.authorization.ResourceKeys; +import org.jboss.security.javaee.AbstractWebAuthorizationHelper; +import org.jboss.security.javaee.SecurityHelperFactory; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.security.auth.Subject; +import javax.security.jacc.PolicyContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Stuart Douglas + */ +public class JbossAuthorizationManager implements AuthorizationManager { + + private final AuthorizationManager delegate; + + public JbossAuthorizationManager(AuthorizationManager delegate) { + this.delegate = delegate; + } + + @Override + public boolean isUserInRole(String role, Account account, ServletInfo servletInfo, HttpServletRequest request, Deployment deployment) { + boolean authzDecision = true; + boolean baseDecision = delegate.isUserInRole(role, account, servletInfo, request, deployment); + // if the RealmBase check has passed, then we can go to authz framework + if (baseDecision) { + String servletName = servletInfo.getName(); + String roleName = role; + List roleRefs = servletInfo.getSecurityRoleRefs(); + if (roleRefs != null) { + for (SecurityRoleRef ref : roleRefs) { + if (ref.getLinkedRole().equals(role)) { + roleName = ref.getRole(); + break; + } + } + } + + SecurityContext sc = SecurityActions.getSecurityContext(); + AbstractWebAuthorizationHelper helper = null; + try { + helper = SecurityHelperFactory.getWebAuthorizationHelper(sc); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.noAuthorizationHelper(e); + return false; + + } + Subject callerSubject = sc.getUtil().getSubject(); + //if (callerSubject == null) { + // // During hasResourcePermission check, Catalina calls hasRole. But we have not established + // // a subject yet in the security context. So we will get the subject from the cached principal + // callerSubject = getSubjectFromRequestPrincipal(principal); + //} + + authzDecision = helper.hasRole(roleName, account.getPrincipal(), servletName, getPrincipalRoles(account), + PolicyContext.getContextID(), callerSubject, new ArrayList(account.getRoles())); + } + boolean finalDecision = baseDecision && authzDecision; + UndertowLogger.ROOT_LOGGER.tracef("hasRole:RealmBase says: %s ::Authz framework says: %s :final= %s", baseDecision, authzDecision, finalDecision); + //TODO: do we need audit for this? + /* + if (finalDecision) { + if (!disableAudit) { + Map entries = new HashMap(); + entries.put("Step", "hasRole"); + successAudit(principal, entries); + } + } else { + if (!disableAudit) { + Map entries = new HashMap(); + entries.put("Step", "hasRole"); + failureAudit(principal, entries); + } + } + */ + + return finalDecision; + } + + private Set getPrincipalRoles(Account account) { + final Set roles = new HashSet<>(); + for (String role : account.getRoles()) { + roles.add(new SimplePrincipal(role)); + } + return roles; + } + + @Override + public boolean canAccessResource(List mappedConstraints, Account account, ServletInfo servletInfo, HttpServletRequest request, Deployment deployment) { + ServletRequestContext src = ServletRequestContext.current(); + boolean baseDecision = delegate.canAccessResource(mappedConstraints, account, servletInfo, request, deployment); + boolean authzDecision = false; + // if the RealmBase check has passed, then we can go to authz framework + if (baseDecision) { + SecurityContext sc = SecurityActions.getSecurityContext(); + Subject caller = sc.getUtil().getSubject(); + //if (caller == null) { + // caller = getSubjectFromRequestPrincipal(request.getPrincipal()); + //} + Map contextMap = new HashMap(); + contextMap.put(ResourceKeys.RESOURCE_PERM_CHECK, Boolean.TRUE); + contextMap.put("securityConstraints", mappedConstraints); //TODO? What should this be? + + AbstractWebAuthorizationHelper helper = null; + try { + helper = SecurityHelperFactory.getWebAuthorizationHelper(sc); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.noAuthorizationHelper(e); + return false; + } + + ArrayList roles = new ArrayList(); + if(account != null) { + roles.addAll(account.getRoles()); + } + authzDecision = helper.checkResourcePermission(contextMap, request, src.getServletResponse(), caller, PolicyContext.getContextID(), + requestURI(src.getExchange()), roles); + } + boolean finalDecision = baseDecision && authzDecision && hasUserDataPermission(request, src.getOriginalResponse(), account, mappedConstraints); + + UndertowLogger.ROOT_LOGGER.tracef("hasResourcePermission:RealmBase says: %s ::Authz framework says: %s :final= %s", baseDecision, authzDecision, finalDecision); + //TODO: audit? + + return finalDecision; + + } + + + public boolean hasUserDataPermission(HttpServletRequest request, HttpServletResponse response, Account account, List constraints) { + Map map = new HashMap(); + map.put("securityConstraints", constraints); + map.put(ResourceKeys.USERDATA_PERM_CHECK, Boolean.TRUE); + + SecurityContext sc = SecurityActions.getSecurityContext(); + AbstractWebAuthorizationHelper helper = null; + try { + helper = SecurityHelperFactory.getWebAuthorizationHelper(sc); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.noAuthorizationHelper(e); + return false; + } + + Subject callerSubject = sc.getUtil().getSubject(); + // JBAS-6419:CallerSubject has no bearing on the user data permission check + if (callerSubject == null) { + callerSubject = new Subject(); + } + + ArrayList roles = new ArrayList(); + if(account != null) { + roles.addAll(account.getRoles()); + } + boolean ok = helper.hasUserDataPermission(map, request, response, PolicyContext.getContextID(), callerSubject, + roles); + + //If the status of the response has already been changed (it is different from the default Response.SC_OK) we should not attempt to change it. + if (!ok && response.getStatus() == HttpServletResponse.SC_OK) { + try { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return ok; + } + + @Override + public TransportGuaranteeType transportGuarantee(TransportGuaranteeType currentConnectionGuarantee, TransportGuaranteeType configuredRequiredGuarantee, HttpServletRequest request) { + return delegate.transportGuarantee(currentConnectionGuarantee, configuredRequiredGuarantee, request); + } + + + /** + * Get the canonical request URI from the request mapping data requestPath + * + * @param request + * @return the request URI path + */ + protected String requestURI(HttpServerExchange request) { + String uri = request.getRelativePath(); + if (uri == null || uri.equals("/")) { + uri = ""; + } + return uri; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/LogoutNotificationReceiver.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/LogoutNotificationReceiver.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/LogoutNotificationReceiver.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,72 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.security.api.NotificationReceiver; +import io.undertow.security.api.SecurityNotification; +import io.undertow.security.idm.Account; +import org.jboss.security.AuthenticationManager; + +import javax.security.auth.Subject; +import java.security.Principal; + +/** + * Undertow security listener that invokes {@code AuthenticationManager.logout()} on logout, flushing the principal from + * the cache if a security cache is being used. + * + * @author Stuart Douglas + */ +public class LogoutNotificationReceiver implements NotificationReceiver { + + private final AuthenticationManager manager; + private final String securityDomain; + + public LogoutNotificationReceiver(AuthenticationManager manager, String securityDomain) { + this.manager = manager; + this.securityDomain = securityDomain; + } + + @Override + public void handleNotification(SecurityNotification notification) { + if (notification.getEventType() == SecurityNotification.EventType.LOGGED_OUT) { + Account account = notification.getAccount(); + Principal principal = (account instanceof AccountImpl) ? ((AccountImpl) account).getOriginalPrincipal() : + account.getPrincipal(); + if (principal != null) { + // perform the logout of the principal using the subject currently set in the security context. + Subject subject = SecurityActions.getSubject(); + this.manager.logout(principal, subject); + } + + // Clear old context + SecurityActions.clearSecurityContext(); + SecurityActions.setSecurityRoles(null); + + // Set a new one in case re-authentication is done within the same thread + org.jboss.security.SecurityContext securityContext = SecurityActions.createSecurityContext(securityDomain); + notification.getExchange().putAttachment(UndertowSecurityAttachments.SECURITY_CONTEXT_ATTACHMENT, securityContext); + + SecurityActions.setSecurityContextOnAssociation(securityContext); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/RunAsLifecycleInterceptor.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/RunAsLifecycleInterceptor.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/RunAsLifecycleInterceptor.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,96 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.servlet.api.FilterInfo; +import io.undertow.servlet.api.LifecycleInterceptor; +import io.undertow.servlet.api.ServletInfo; +import org.jboss.metadata.javaee.jboss.RunAsIdentityMetaData; +import org.jboss.security.RunAs; +import org.jboss.security.RunAsIdentity; +import org.jboss.security.SecurityContext; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import java.util.Map; + +public class RunAsLifecycleInterceptor implements LifecycleInterceptor { + + private final Map runAsIdentityMetaDataMap; + + public RunAsLifecycleInterceptor(final Map runAsIdentityMetaDataMap) { + this.runAsIdentityMetaDataMap = runAsIdentityMetaDataMap; + } + + private void handle(ServletInfo servletInfo, LifecycleContext context) throws ServletException { + RunAsIdentityMetaData identity = null; + RunAs old = null; + SecurityContext sc = SecurityActions.getSecurityContext(); + if (sc == null) { + context.proceed(); + return; + } + try { + identity = runAsIdentityMetaDataMap.get(servletInfo.getName()); + RunAsIdentity runAsIdentity = null; + if (identity != null) { + UndertowLogger.ROOT_LOGGER.tracef("%s, runAs: %s", servletInfo.getName(), identity); + runAsIdentity = new RunAsIdentity(identity.getRoleName(), identity.getPrincipalName(), identity.getRunAsRoles()); + } + old = SecurityActions.setRunAsIdentity(runAsIdentity, sc); + + // Perform the request + context.proceed(); + } finally { + if (identity != null) { + SecurityActions.setRunAsIdentity(old, sc); + } + } + } + + @Override + public void init(ServletInfo servletInfo, Servlet servlet, LifecycleContext context) throws ServletException { + if (servletInfo.getRunAs() != null) { + handle(servletInfo, context); + } else { + context.proceed(); + } + } + + @Override + public void init(FilterInfo filterInfo, Filter filter, LifecycleContext context) throws ServletException { + context.proceed(); + } + + @Override + public void destroy(ServletInfo servletInfo, Servlet servlet, LifecycleContext context) throws ServletException { + handle(servletInfo, context); + } + + @Override + public void destroy(FilterInfo filterInfo, Filter filter, LifecycleContext context) throws ServletException { + context.proceed(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityActions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityActions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityActions.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,241 @@ +/* + * 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.extension.undertow.security; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.Set; + +import org.jboss.security.RunAs; +import org.jboss.security.SecurityContext; +import org.jboss.security.SecurityContextAssociation; +import org.jboss.security.SecurityContextFactory; +import org.jboss.security.SecurityRolesAssociation; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.security.manager.WildFlySecurityManager; + +import javax.security.auth.Subject; + +import static java.security.AccessController.doPrivileged; + +/** + * Privileged Actions + * + * @author Anil.Saldhana@redhat.com + * @since Jan 12, 2011 + */ +class SecurityActions { + + public static final String AUTH_EXCEPTION_KEY = "org.jboss.security.exception"; + + /** + * Create a JBoss Security Context with the given security domain name + * + * @param domain the security domain name (such as "other" ) + * @return an instanceof {@code SecurityContext} + */ + static SecurityContext createSecurityContext(final String domain) { + if (WildFlySecurityManager.isChecking()) { + return WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + @Override + public SecurityContext run() { + try { + return SecurityContextFactory.createSecurityContext(domain); + } catch (Exception e) { + throw UndertowLogger.ROOT_LOGGER.failToCreateSecurityContext(e); + } + } + }); + } else { + try { + return SecurityContextFactory.createSecurityContext(domain); + } catch (Exception e) { + throw UndertowLogger.ROOT_LOGGER.failToCreateSecurityContext(e); + } + } + } + + /** + * Set the {@code SecurityContext} on the {@code SecurityContextAssociation} + * + * @param sc the security context + */ + static void setSecurityContextOnAssociation(final SecurityContext sc) { + if (WildFlySecurityManager.isChecking()) { + WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + @Override + public Void run() { + SecurityContextAssociation.setSecurityContext(sc); + return null; + } + }); + } else { + SecurityContextAssociation.setSecurityContext(sc); + } + } + + /** + * Get the current {@code SecurityContext} + * + * @return an instance of {@code SecurityContext} + */ + static SecurityContext getSecurityContext() { + if (WildFlySecurityManager.isChecking()) { + return WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + public SecurityContext run() { + return SecurityContextAssociation.getSecurityContext(); + } + }); + } else { + return SecurityContextAssociation.getSecurityContext(); + } + } + + /** + * Clears current {@code SecurityContext} + */ + static void clearSecurityContext() { + if (WildFlySecurityManager.isChecking()) { + WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + public Void run() { + SecurityContextAssociation.clearSecurityContext(); + return null; + } + }); + } else { + SecurityContextAssociation.clearSecurityContext(); + } + } + + static void setSecurityRoles(final Map> roles) { + if(WildFlySecurityManager.isChecking()) { + + WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + public Void run() { + SecurityRolesAssociation.setSecurityRoles(roles); + return null; + } + }); + } else { + SecurityRolesAssociation.setSecurityRoles(roles); + } + } + + /** + * Sets the run as identity + * + * @param principal the identity + */ + static RunAs setRunAsIdentity(final RunAs principal, final SecurityContext sc) { + if (WildFlySecurityManager.isChecking()) { + return WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + + @Override + public RunAs run() { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + RunAs old = sc.getOutgoingRunAs(); + sc.setOutgoingRunAs(principal); + return old; + } + }); + } else { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + RunAs old = sc.getOutgoingRunAs(); + sc.setOutgoingRunAs(principal); + return old; + } + } + + /** + * Removes the run as identity + * + * @return the identity removed + */ + static RunAs popRunAsIdentity(final SecurityContext sc) { + if (WildFlySecurityManager.isChecking()) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public RunAs run() { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + RunAs principal = sc.getOutgoingRunAs(); + sc.setOutgoingRunAs(null); + return principal; + } + }); + } else { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + RunAs principal = sc.getOutgoingRunAs(); + sc.setOutgoingRunAs(null); + return principal; + } + } + + public static RunAs getRunAsIdentity(final SecurityContext sc) { + if (WildFlySecurityManager.isChecking()) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public RunAs run() { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + return sc.getOutgoingRunAs(); + } + }); + } else { + if (sc == null) { + throw UndertowLogger.ROOT_LOGGER.noSecurityContext(); + } + return sc.getOutgoingRunAs(); + } + } + static Subject getSubject() { + if (WildFlySecurityManager.isChecking()) { + return doPrivileged(new PrivilegedAction() { + public Subject run() { + Subject subject = null; + SecurityContext sc = getSecurityContext(); + if (sc != null) { + subject = sc.getUtil().getSubject(); + } + return subject; + } + }); + } else { + Subject subject = null; + SecurityContext sc = getSecurityContext(); + if (sc != null) { + subject = sc.getUtil().getSubject(); + } + return subject; + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextAssociationHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextAssociationHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextAssociationHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,108 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.predicate.Predicates; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.PredicateHandler; +import io.undertow.servlet.handlers.ServletChain; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.servlet.predicate.DispatcherTypePredicate; +import org.jboss.metadata.javaee.jboss.RunAsIdentityMetaData; +import org.jboss.security.RunAs; +import org.jboss.security.RunAsIdentity; +import org.jboss.security.SecurityContext; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; + +import javax.servlet.ServletRequest; + +public class SecurityContextAssociationHandler implements HttpHandler { + + private final Map runAsIdentityMetaDataMap; + private final HttpHandler next; + + private static final PrivilegedAction CURRENT_CONTEXT = new PrivilegedAction() { + @Override + public ServletRequestContext run() { + return ServletRequestContext.current(); + } + }; + + public SecurityContextAssociationHandler(final Map runAsIdentityMetaDataMap, final HttpHandler next) { + this.runAsIdentityMetaDataMap = runAsIdentityMetaDataMap; + this.next = next; + } + + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception { + SecurityContext sc = exchange.getAttachment(UndertowSecurityAttachments.SECURITY_CONTEXT_ATTACHMENT); + RunAsIdentityMetaData identity = null; + RunAs old = null; + try { + final ServletChain servlet = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getCurrentServlet(); + identity = runAsIdentityMetaDataMap.get(servlet.getManagedServlet().getServletInfo().getName()); + RunAsIdentity runAsIdentity = null; + if (identity != null) { + UndertowLogger.ROOT_LOGGER.tracef("%s, runAs: %s", servlet.getManagedServlet().getServletInfo().getName(), identity); + runAsIdentity = new RunAsIdentity(identity.getRoleName(), identity.getPrincipalName(), identity.getRunAsRoles()); + } + old = SecurityActions.setRunAsIdentity(runAsIdentity, sc); + + // Perform the request + next.handleRequest(exchange); + } finally { + if (identity != null) { + SecurityActions.setRunAsIdentity(old, sc); + } + } + } + + public static HandlerWrapper wrapper(final Map runAsIdentityMetaDataMap) { + return new HandlerWrapper() { + @Override + public HttpHandler wrap(final HttpHandler handler) { + //we only run this on REQUEST or ASYNC invocations + return new PredicateHandler(Predicates.or(DispatcherTypePredicate.REQUEST, DispatcherTypePredicate.ASYNC), new SecurityContextAssociationHandler(runAsIdentityMetaDataMap, handler), handler); + } + }; + } + + public static ServletRequest getActiveRequest() { + ServletRequestContext current; + if(System.getSecurityManager() == null) { + current = ServletRequestContext.current(); + } else { + current = AccessController.doPrivileged(CURRENT_CONTEXT); + } + if(current == null) { + return null; + } + return current.getServletRequest(); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextThreadSetupAction.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextThreadSetupAction.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/SecurityContextThreadSetupAction.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,116 @@ +/* + * 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.extension.undertow.security; + +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.Set; + +import org.jboss.as.security.plugins.SecurityDomainContext; +import org.jboss.security.SecurityContext; +import org.jboss.security.SecurityRolesAssociation; +import org.jboss.security.identity.RoleGroup; +import org.jboss.security.mapping.MappingContext; +import org.jboss.security.mapping.MappingManager; +import org.jboss.security.mapping.MappingType; +import org.wildfly.security.manager.WildFlySecurityManager; +import io.undertow.servlet.api.ThreadSetupHandler; + +/** + * Thread setup action that sets up the security context. If it already exists then it will be re-used, otherwise + * a new one is created. + * + * @author Stuart Douglas + */ +public class SecurityContextThreadSetupAction implements ThreadSetupHandler { + + private final String securityDomain; + private final SecurityDomainContext securityDomainContext; + private final Map> principleVsRoleMap; + + private static final PrivilegedAction TEAR_DOWN_PA = new PrivilegedAction() { + @Override + public Object run() { + SecurityActions.clearSecurityContext(); + SecurityRolesAssociation.setSecurityRoles(null); + return null; + } + }; + + public SecurityContextThreadSetupAction(final String securityDomain, SecurityDomainContext securityDomainContext, Map> principleVsRoleMap) { + this.securityDomain = securityDomain; + this.securityDomainContext = securityDomainContext; + this.principleVsRoleMap = principleVsRoleMap; + + } + + @Override + public Action create(Action action) { + return (exchange, context) -> { + SecurityContext sc = null; + if (exchange != null) { + sc = exchange.getAttachment(UndertowSecurityAttachments.SECURITY_CONTEXT_ATTACHMENT); + } + if (sc == null) { + sc = SecurityActions.createSecurityContext(securityDomain); + if (exchange != null) { + exchange.putAttachment(UndertowSecurityAttachments.SECURITY_CONTEXT_ATTACHMENT, sc); + } + } + SecurityActions.setSecurityContextOnAssociation(sc); + final MappingManager mappingManager = securityDomainContext.getMappingManager(); + + if (mappingManager != null) { + if (WildFlySecurityManager.isChecking()) { + WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + @Override + public Object run() { + // if there are mapping modules let them handle the role mapping + MappingContext mc = mappingManager.getMappingContext(MappingType.ROLE.name()); + if (mc != null && mc.hasModules()) { + SecurityRolesAssociation.setSecurityRoles(principleVsRoleMap); + } + return null; + } + }); + } else { + // if there are mapping modules let them handle the role mapping + MappingContext mc = mappingManager.getMappingContext(MappingType.ROLE.name()); + if (mc != null && mc.hasModules()) { + SecurityRolesAssociation.setSecurityRoles(principleVsRoleMap); + } + } + } + try { + return action.call(exchange, context); + } finally { + if (WildFlySecurityManager.isChecking()) { + WildFlySecurityManager.doUnchecked(TEAR_DOWN_PA); + } else { + SecurityActions.clearSecurityContext(); + SecurityRolesAssociation.setSecurityRoles(null); + } + } + }; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/UndertowSecurityAttachments.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/UndertowSecurityAttachments.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/UndertowSecurityAttachments.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,35 @@ +/* + * 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.extension.undertow.security; + +import io.undertow.util.AttachmentKey; +import org.jboss.security.SecurityContext; + +/** + * @author Stuart Douglas + */ +public class UndertowSecurityAttachments { + + public static final AttachmentKey SECURITY_CONTEXT_ATTACHMENT = AttachmentKey.create(SecurityContext.class); + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanism.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanism.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanism.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,519 @@ +/* + * 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.extension.undertow.security.digest; + +import static io.undertow.UndertowLogger.REQUEST_LOGGER; +import static io.undertow.UndertowMessages.MESSAGES; +import static io.undertow.security.impl.DigestAuthorizationToken.parseHeader; +import static io.undertow.util.Headers.AUTHORIZATION; +import static io.undertow.util.Headers.DIGEST; +import static io.undertow.util.Headers.WWW_AUTHENTICATE; +import static io.undertow.util.StatusCodes.UNAUTHORIZED; +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.NonceManager; +import io.undertow.security.api.SecurityContext; +import io.undertow.security.idm.Account; +import io.undertow.security.idm.DigestAlgorithm; +import io.undertow.security.idm.IdentityManager; +import io.undertow.security.impl.DigestAuthorizationToken; +import io.undertow.security.impl.DigestQop; +import io.undertow.security.impl.SimpleNonceManager; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.AttachmentKey; +import io.undertow.util.HeaderMap; +import io.undertow.util.Headers; +import io.undertow.util.HexConverter; +import io.undertow.util.StatusCodes; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.wildfly.extension.undertow.logging.UndertowLogger; + +/** + * {@link io.undertow.server.HttpHandler} to handle HTTP Digest authentication, both according to RFC-2617 and draft update to allow additional + * algorithms to be used. + * + * @author Darran Lofthouse + */ +public class DigestAuthenticationMechanism implements AuthenticationMechanism { + + private static final String DEFAULT_NAME = "DIGEST"; + private static final String DIGEST_PREFIX = DIGEST + " "; + private static final int PREFIX_LENGTH = DIGEST_PREFIX.length(); + private static final String OPAQUE_VALUE = "00000000000000000000000000000000"; + private static final byte COLON = ':'; + + private final String mechanismName; + private final IdentityManager identityManager; + private final boolean validateDigestUrl; + + private static final Set MANDATORY_REQUEST_TOKENS; + + static { + Set mandatoryTokens = new HashSet<>(); + mandatoryTokens.add(DigestAuthorizationToken.USERNAME); + mandatoryTokens.add(DigestAuthorizationToken.REALM); + mandatoryTokens.add(DigestAuthorizationToken.NONCE); + mandatoryTokens.add(DigestAuthorizationToken.DIGEST_URI); + mandatoryTokens.add(DigestAuthorizationToken.RESPONSE); + + MANDATORY_REQUEST_TOKENS = Collections.unmodifiableSet(mandatoryTokens); + } + + /** + * The {@link List} of supported algorithms, this is assumed to be in priority order. + */ + private final List supportedAlgorithms; + private final List supportedQops; + private final String qopString; + private final String realmName; // TODO - Will offer choice once backing store API/SPI is in. + private final String domain; + private final NonceManager nonceManager; + + // Where do session keys fit? Do we just hang onto a session key or keep visiting the user store to check if the password + // has changed? + // Maybe even support registration of a session so it can be invalidated? + // 2013-05-29 - Session keys will be cached, where a cached key is used the IdentityManager is still given the + // opportunity to check the Account is still valid. + + public DigestAuthenticationMechanism(final List supportedAlgorithms, final List supportedQops, + final String realmName, final String domain, final NonceManager nonceManager, boolean validateUri) { + this(supportedAlgorithms, supportedQops, realmName, domain, nonceManager, DEFAULT_NAME, validateUri); + } + + public DigestAuthenticationMechanism(final List supportedAlgorithms, final List supportedQops, + final String realmName, final String domain, final NonceManager nonceManager, final String mechanismName, boolean validateUri) { + this(supportedAlgorithms, supportedQops, realmName, domain, nonceManager, mechanismName, null, validateUri); + } + + public DigestAuthenticationMechanism(final List supportedAlgorithms, final List supportedQops, + final String realmName, final String domain, final NonceManager nonceManager, final String mechanismName, final IdentityManager identityManager, boolean validateUri) { + this.supportedAlgorithms = supportedAlgorithms; + this.supportedQops = supportedQops; + this.realmName = realmName; + this.domain = domain; + this.nonceManager = nonceManager; + this.mechanismName = mechanismName; + this.identityManager = identityManager; + this.validateDigestUrl = validateUri; + + if (!supportedQops.isEmpty()) { + StringBuilder sb = new StringBuilder(); + Iterator it = supportedQops.iterator(); + sb.append(it.next().getToken()); + while (it.hasNext()) { + sb.append(",").append(it.next().getToken()); + } + qopString = sb.toString(); + } else { + qopString = null; + } + } + + public DigestAuthenticationMechanism(final String realmName, final String domain, final String mechanismName, boolean validateUri) { + this(realmName, domain, mechanismName, null, validateUri); + } + + public DigestAuthenticationMechanism(final String realmName, final String domain, final String mechanismName, final IdentityManager identityManager, boolean validateUri) { + this(Collections.singletonList(DigestAlgorithm.MD5), Collections.singletonList(DigestQop.AUTH), realmName, domain, new SimpleNonceManager(), DEFAULT_NAME, identityManager, validateUri); + } + + @SuppressWarnings("deprecation") + private IdentityManager getIdentityManager(SecurityContext securityContext) { + return identityManager != null ? identityManager : securityContext.getIdentityManager(); + } + + @Override + public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, + final SecurityContext securityContext) { + List authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION); + if (authHeaders != null) { + for (String current : authHeaders) { + if (current.startsWith(DIGEST_PREFIX)) { + String digestChallenge = current.substring(PREFIX_LENGTH); + + try { + DigestContext context = new DigestContext(); + Map parsedHeader = parseHeader(digestChallenge); + context.setMethod(exchange.getRequestMethod().toString()); + context.setParsedHeader(parsedHeader); + // Some form of Digest authentication is going to occur so get the DigestContext set on the exchange. + exchange.putAttachment(DigestContext.ATTACHMENT_KEY, context); + + return handleDigestHeader(exchange, securityContext); + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.unexceptedAuthentificationError(e.getLocalizedMessage(), e); + } + } + + // By this point we had a header we should have been able to verify but for some reason + // it was not correctly structured. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + } + + // No suitable header has been found in this request, + return AuthenticationMechanismOutcome.NOT_ATTEMPTED; + } + + public AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) { + DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); + Map parsedHeader = context.getParsedHeader(); + // Step 1 - Verify the set of tokens received to ensure valid values. + Set mandatoryTokens = new HashSet<>(MANDATORY_REQUEST_TOKENS); + if (!supportedAlgorithms.contains(DigestAlgorithm.MD5)) { + // If we don't support MD5 then the client must choose an algorithm as we can not fall back to MD5. + mandatoryTokens.add(DigestAuthorizationToken.ALGORITHM); + } + if (!supportedQops.isEmpty() && !supportedQops.contains(DigestQop.AUTH)) { + // If we do not support auth then we are mandating auth-int so force the client to send a QOP + mandatoryTokens.add(DigestAuthorizationToken.MESSAGE_QOP); + } + + DigestQop qop = null; + // This check is early as is increases the list of mandatory tokens. + if (parsedHeader.containsKey(DigestAuthorizationToken.MESSAGE_QOP)) { + qop = DigestQop.forName(parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP)); + if (qop == null || !supportedQops.contains(qop)) { + // We are also ensuring the client is not trying to force a qop that has been disabled. + REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.MESSAGE_QOP.getName(), + parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP)); + // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + context.setQop(qop); + mandatoryTokens.add(DigestAuthorizationToken.CNONCE); + mandatoryTokens.add(DigestAuthorizationToken.NONCE_COUNT); + } + + // Check all mandatory tokens are present. + mandatoryTokens.removeAll(parsedHeader.keySet()); + if (mandatoryTokens.size() > 0) { + for (DigestAuthorizationToken currentToken : mandatoryTokens) { + // TODO - Need a better check and possible concatenate the list of tokens - however + // even having one missing token is not something we should routinely expect. + REQUEST_LOGGER.missingAuthorizationToken(currentToken.getName()); + } + // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + + // Perform some validation of the remaining tokens. + if (!realmName.equals(parsedHeader.get(DigestAuthorizationToken.REALM))) { + REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.REALM.getName(), + parsedHeader.get(DigestAuthorizationToken.REALM)); + // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + + if (validateDigestUrl) { + if (parsedHeader.containsKey(DigestAuthorizationToken.DIGEST_URI)) { + String uri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI); + String requestURI = exchange.getRequestURI(); + if (!exchange.getQueryString().isEmpty()) { + requestURI = requestURI + "?" + exchange.getQueryString(); + } + if (!uri.equals(requestURI)) { + //it is possible we were given an absolute URI + //we reconstruct the URI from the host header to make sure they match up + //I am not sure if this is overly strict, however I think it is better + //to be safe than sorry + requestURI = exchange.getRequestURL(); + if (!exchange.getQueryString().isEmpty()) { + requestURI = requestURI + "?" + exchange.getQueryString(); + } + if (!uri.equals(requestURI)) { + //just end the auth process + exchange.setStatusCode(StatusCodes.BAD_REQUEST); + exchange.endExchange(); + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + } + } else { + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + } + + if (parsedHeader.containsKey(DigestAuthorizationToken.OPAQUE)) { + if (!OPAQUE_VALUE.equals(parsedHeader.get(DigestAuthorizationToken.OPAQUE))) { + REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.OPAQUE.getName(), + parsedHeader.get(DigestAuthorizationToken.OPAQUE)); + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + } + + DigestAlgorithm algorithm; + if (parsedHeader.containsKey(DigestAuthorizationToken.ALGORITHM)) { + algorithm = DigestAlgorithm.forName(parsedHeader.get(DigestAuthorizationToken.ALGORITHM)); + if (algorithm == null || !supportedAlgorithms.contains(algorithm)) { + // We are also ensuring the client is not trying to force an algorithm that has been disabled. + REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.ALGORITHM.getName(), + parsedHeader.get(DigestAuthorizationToken.ALGORITHM)); + // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + } else { + // We know this is safe as the algorithm token was made mandatory + // if MD5 is not supported. + algorithm = DigestAlgorithm.MD5; + } + + try { + context.setAlgorithm(algorithm); + } catch (NoSuchAlgorithmException e) { + /* + * This should not be possible in a properly configured installation. + */ + REQUEST_LOGGER.exceptionProcessingRequest(e); + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + + final String userName = parsedHeader.get(DigestAuthorizationToken.USERNAME); + final IdentityManager identityManager = getIdentityManager(securityContext); + final Account account; + + if (algorithm.isSession()) { + /* This can follow one of the following: - + * 1 - New session so use DigestCredentialImpl with the IdentityManager to + * create a new session key. + * 2 - Obtain the existing session key from the session store and validate it, just use + * IdentityManager to validate account is still active and the current role assignment. + */ + throw new IllegalStateException("Not yet implemented."); + } else { + final DigestCredential credential = new DigestCredentialImpl(context); + account = identityManager.verify(userName, credential); + } + + if (account == null) { + // Authentication has failed, this could either be caused by the user not-existing or it + // could be caused due to an invalid hash. + securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), mechanismName); + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + + // Step 3 - Verify that the nonce was eligible to be used. + if (!validateNonceUse(context, parsedHeader, exchange)) { + // TODO - This is the right place to make use of the decision but the check needs to be much much sooner + // otherwise a failure server + // side could leave a packet that could be 're-played' after the failed auth. + // The username and password verification passed but for some reason we do not like the nonce. + context.markStale(); + // We do not mark as a failure on the security context as this is not quite a failure, a client with a cached nonce + // can easily hit this point. + return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + } + + // We have authenticated the remote user. + + //sendAuthenticationInfoHeader(exchange); + securityContext.authenticationComplete(account, mechanismName, true); + return AuthenticationMechanismOutcome.AUTHENTICATED; + + // Step 4 - Set up any QOP related requirements. + + // TODO - Do QOP + } + + private boolean validateNonceUse(DigestContext context, Map parsedHeader, final HttpServerExchange exchange) { + String suppliedNonce = parsedHeader.get(DigestAuthorizationToken.NONCE); + int nonceCount = -1; + if (parsedHeader.containsKey(DigestAuthorizationToken.NONCE_COUNT)) { + String nonceCountHex = parsedHeader.get(DigestAuthorizationToken.NONCE_COUNT); + + nonceCount = Integer.parseInt(nonceCountHex, 16); + } + + context.setNonce(suppliedNonce); + // TODO - A replay attempt will need an exception. + return (nonceManager.validateNonce(suppliedNonce, nonceCount, exchange)); + } + + private byte[] createHA2Auth(final DigestContext context, Map parsedHeader) { + byte[] method = context.getMethod().getBytes(StandardCharsets.UTF_8); + byte[] digestUri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI).getBytes(StandardCharsets.UTF_8); + + MessageDigest digest = context.getDigest(); + try { + digest.update(method); + digest.update(COLON); + digest.update(digestUri); + + return HexConverter.convertToHexBytes(digest.digest()); + } finally { + digest.reset(); + } + } + + @Override + public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { + DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY); + boolean stale = context == null ? false : context.isStale(); + + StringBuilder rb = new StringBuilder(DIGEST_PREFIX); + rb.append(Headers.REALM.toString()).append("=\"").append(realmName).append("\","); + rb.append(Headers.DOMAIN.toString()).append("=\"").append(domain).append("\","); + // based on security constraints. + rb.append(Headers.NONCE.toString()).append("=\"").append(nonceManager.nextNonce(null, exchange)).append("\","); + // Not currently using OPAQUE as it offers no integrity, used for session data leaves it vulnerable to + // session fixation type issues as well. + rb.append(Headers.OPAQUE.toString()).append("=\"00000000000000000000000000000000\""); + if (stale) { + rb.append(",stale=true"); + } + if (supportedAlgorithms.size() > 0) { + // This header will need to be repeated once for each algorithm. + rb.append(",").append(Headers.ALGORITHM.toString()).append("=%s"); + } + if (qopString != null) { + rb.append(",").append(Headers.QOP.toString()).append("=\"").append(qopString).append("\""); + } + + String theChallenge = rb.toString(); + HeaderMap responseHeader = exchange.getResponseHeaders(); + if (supportedAlgorithms.isEmpty()) { + responseHeader.add(WWW_AUTHENTICATE, theChallenge); + } else { + for (DigestAlgorithm current : supportedAlgorithms) { + responseHeader.add(WWW_AUTHENTICATE, String.format(theChallenge, current.getToken())); + } + } + + return new ChallengeResult(true, UNAUTHORIZED); + } + + private static class DigestContext { + + static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(DigestContext.class); + + private String method; + private String nonce; + private DigestQop qop; + private MessageDigest digest; + private boolean stale = false; + Map parsedHeader; + + String getMethod() { + return method; + } + + void setMethod(String method) { + this.method = method; + } + + boolean isStale() { + return stale; + } + + void markStale() { + this.stale = true; + } + + String getNonce() { + return nonce; + } + + void setNonce(String nonce) { + this.nonce = nonce; + } + + DigestQop getQop() { + return qop; + } + + void setQop(DigestQop qop) { + this.qop = qop; + } + + void setAlgorithm(DigestAlgorithm algorithm) throws NoSuchAlgorithmException { + digest = algorithm.getMessageDigest(); + } + + MessageDigest getDigest() { + return digest; + } + + Map getParsedHeader() { + return parsedHeader; + } + + void setParsedHeader(Map parsedHeader) { + this.parsedHeader = parsedHeader; + } + + } + + private class DigestCredentialImpl implements DigestCredential { + + private final DigestContext context; + + private DigestCredentialImpl(final DigestContext digestContext) { + this.context = digestContext; + } + + @Override + public String getClientDigest() { + return context.getParsedHeader().get(DigestAuthorizationToken.RESPONSE); + } + + @Override + public String getNonce() { + return context.getParsedHeader().get(DigestAuthorizationToken.NONCE); + } + + @Override + public String getNonceCount() { + return context.getParsedHeader().get(DigestAuthorizationToken.NONCE_COUNT); + } + + @Override + public String getClientNonce() { + return context.getParsedHeader().get(DigestAuthorizationToken.CNONCE); + } + + @Override + public String getQop() { + return context.getQop().getToken(); + } + + @Override + public String getRealm() { + return realmName; + } + + @Override + public String getHA2() { + byte[] ha2 = createHA2Auth(context, context.getParsedHeader()); + return new String(ha2, StandardCharsets.UTF_8); + } + + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanismFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanismFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestAuthenticationMechanismFactory.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,48 @@ +/* + * 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.extension.undertow.security.digest; + +import java.util.Map; + +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.AuthenticationMechanismFactory; +import io.undertow.server.handlers.form.FormParserFactory; + +/** + * A {@link AuthenticationMechanismFactory} for the custom WildFly implementation of Digest. + * + * @author Darran Lofthouse + */ +public class DigestAuthenticationMechanismFactory implements AuthenticationMechanismFactory { + + public static final AuthenticationMechanismFactory FACTORY = new DigestAuthenticationMechanismFactory(); + + private DigestAuthenticationMechanismFactory() { + } + + @Override + public AuthenticationMechanism create(String mechanismName, FormParserFactory formParserFactory, Map properties) { + return new DigestAuthenticationMechanism(properties.get(REALM), properties.get(CONTEXT_PATH), mechanismName, + Boolean.parseBoolean(System.getProperty("jboss.security.validate-digest-url", "true"))); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestCredential.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestCredential.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/digest/DigestCredential.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,83 @@ +/* + * 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.extension.undertow.security.digest; + +import io.undertow.security.idm.Credential; + +/** + * An alternative {@link Credential} for Digest based authentication to pass over additional + * information for authentication. + * + * @author Darran Lofthouse + */ +public interface DigestCredential extends Credential { + + /** + * Get the digest received from the client. + * + * @return The digest received from the client. + */ + String getClientDigest(); + + /** + * Get the nonce that was used for this request. + * + * @return The nonce that was used for this request. + */ + String getNonce(); + + /** + * Get the nonce count for the request or {@code null} if none was used. + * + * @return The nonce count for the request or {@code null} if none was used. + */ + String getNonceCount(); + + /** + * Get the client nonce for the request or {@code null} if none was used. + * + * @return The client nonce for the request or {@code null} if none was used. + */ + String getClientNonce(); + + /** + * Get the QOP for the request or {@code null} if none was specified. + * + * @return The QOP for the request or {@code null} if none was specified. + */ + String getQop(); + + /** + * Get the name of the realm used for this request. + * + * @return The name of the realm used for this request. + */ + String getRealm(); + + /** + * Get the hashed representation of A2. + * + * @return The hashed representation of A2. + */ + String getHA2(); + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/HttpServletRequestPolicyContextHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/HttpServletRequestPolicyContextHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/HttpServletRequestPolicyContextHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,59 @@ +/* + * 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.extension.undertow.security.jacc; + +import org.jboss.security.SecurityConstants; +import org.wildfly.extension.undertow.security.SecurityContextAssociationHandler; + +import javax.security.jacc.PolicyContextException; +import javax.security.jacc.PolicyContextHandler; + +/** + * A PolicyContextHandler for the active HttpServletRequest + * + * @author Scott.Stark@jboss.org + * @author Marcus Moyses + */ +public class HttpServletRequestPolicyContextHandler implements PolicyContextHandler { + + /** {@inheritDoc} */ + @Override + public Object getContext(String key, Object data) throws PolicyContextException { + if (!key.equalsIgnoreCase(SecurityConstants.WEB_REQUEST_KEY)) + return null; + return SecurityContextAssociationHandler.getActiveRequest(); + } + + /** {@inheritDoc} */ + @Override + public String[] getKeys() throws PolicyContextException { + String[] keys = { SecurityConstants.WEB_REQUEST_KEY }; + return keys; + } + + /** {@inheritDoc} */ + @Override + public boolean supports(String key) throws PolicyContextException { + return key.equalsIgnoreCase(SecurityConstants.WEB_REQUEST_KEY); + } +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCAuthorizationManager.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCAuthorizationManager.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCAuthorizationManager.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,166 @@ +/* + * 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.extension.undertow.security.jacc; + +import static java.security.AccessController.doPrivileged; + +import java.security.CodeSource; +import java.security.Permission; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.jacc.WebResourcePermission; +import javax.security.jacc.WebRoleRefPermission; +import javax.security.jacc.WebUserDataPermission; +import javax.servlet.http.HttpServletRequest; + +import io.undertow.security.idm.Account; +import io.undertow.servlet.api.AuthorizationManager; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.ServletInfo; +import io.undertow.servlet.api.SingleConstraintMatch; +import io.undertow.servlet.api.TransportGuaranteeType; +import org.wildfly.security.manager.WildFlySecurityManager; + +/** + *

+ * An implementation of {@link AuthorizationManager} that uses JACC permissions to grant or deny access to web resources. + *

+ * + * @author Stefan Guilhen + */ +public class JACCAuthorizationManager implements AuthorizationManager { + + public static final AuthorizationManager INSTANCE = new JACCAuthorizationManager(); + + @Override + public boolean isUserInRole(final String roleName, final Account account, final ServletInfo servletInfo, final HttpServletRequest request, final Deployment deployment) { + return hasPermission(account, deployment, servletInfo, new WebRoleRefPermission(servletInfo.getName(), roleName)); + } + + @Override + public boolean canAccessResource(List constraints, final Account account, final ServletInfo servletInfo, final HttpServletRequest request, Deployment deployment) { + return hasPermission(account, deployment, servletInfo, new WebResourcePermission(request)); + } + + @Override + public TransportGuaranteeType transportGuarantee(TransportGuaranteeType currentConnGuarantee, TransportGuaranteeType configuredRequiredGuarantee, final HttpServletRequest request) { + final ProtectionDomain domain = new ProtectionDomain(null, null, null, null); + final String[] httpMethod = new String[] {request.getMethod()}; + final String canonicalURI = getCanonicalURI(request); + + switch (currentConnGuarantee) { + case NONE: { + // unprotected connection - create a WebUserDataPermission without any transport guarantee. + WebUserDataPermission permission = new WebUserDataPermission(canonicalURI, httpMethod, null); + + // if permission was implied then the unprotected connection is ok. + if (hasPermission(domain, permission)) { + return TransportGuaranteeType.NONE; + } + else { + permission = new WebUserDataPermission(canonicalURI, httpMethod, TransportGuaranteeType.CONFIDENTIAL.name()); + // permission is only granted with CONFIDENTIAL + if (hasPermission(domain, permission)) { + return TransportGuaranteeType.CONFIDENTIAL; + } + //either way we just don't have permission, let the request proceed and be rejected later + return TransportGuaranteeType.NONE; + } + } + case INTEGRAL: + case CONFIDENTIAL: { + // we will try using both transport guarantees (CONFIDENTIAL and INTEGRAL) as SSL provides both. + WebUserDataPermission permission = new WebUserDataPermission(canonicalURI, httpMethod, + TransportGuaranteeType.CONFIDENTIAL.name()); + + if (hasPermission(domain, permission)) { + return TransportGuaranteeType.CONFIDENTIAL; + } + else { + // try with the INTEGRAL connection guarantee type. + permission = new WebUserDataPermission(canonicalURI, httpMethod, TransportGuaranteeType.INTEGRAL.name()); + if (hasPermission(domain, permission)) { + return TransportGuaranteeType.INTEGRAL; + } + else { + return TransportGuaranteeType.REJECTED; + } + } + } + default: + return TransportGuaranteeType.REJECTED; + } + } + + /** + *

+ * Gets the canonical request URI - that is, the request URI minus the context path. + *

+ * + * @param request the {@link HttpServletRequest} for which we want the canonical URI. + * @return the constructed canonical URI. + */ + private String getCanonicalURI(HttpServletRequest request) { + String canonicalURI = request.getRequestURI().substring(request.getContextPath().length()); + if (canonicalURI == null || canonicalURI.equals("/")) + canonicalURI = ""; + return canonicalURI; + } + + private boolean hasPermission(Account account, Deployment deployment, ServletInfo servletInfo, Permission permission) { + CodeSource codeSource = servletInfo.getServletClass().getProtectionDomain().getCodeSource(); + ProtectionDomain domain = new ProtectionDomain(codeSource, null, null, getGrantedRoles(account, deployment)); + return hasPermission(domain, permission); + } + + private boolean hasPermission(ProtectionDomain domain, Permission permission) { + Policy policy = WildFlySecurityManager.isChecking() ? doPrivileged((PrivilegedAction) Policy::getPolicy) : Policy.getPolicy(); + return policy.implies(domain, permission); + } + + private Principal[] getGrantedRoles(Account account, Deployment deployment) { + if (account == null) { + return new Principal[] {}; + } + + Set roles = new HashSet<>(account.getRoles()); + Map> principalVersusRolesMap = deployment.getDeploymentInfo().getPrincipalVersusRolesMap(); + + roles.addAll(principalVersusRolesMap.getOrDefault(account.getPrincipal().getName(), Collections.emptySet())); + + Principal[] principals = new Principal[roles.size()]; + int index = 0; + for (String role : roles) { + principals[index++] = () -> role; + } + return principals; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCContextIdHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCContextIdHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/JACCContextIdHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,112 @@ +/* + * 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.extension.undertow.security.jacc; + +import java.security.PrivilegedAction; + +import javax.security.jacc.PolicyContext; + +import io.undertow.predicate.Predicates; +import io.undertow.server.HandlerWrapper; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.PredicateHandler; +import io.undertow.servlet.predicate.DispatcherTypePredicate; +import org.wildfly.security.manager.WildFlySecurityManager; + +/** + *

+ * A {@link HttpHandler} that sets the web application JACC contextId in the {@link PolicyContext}. Any previously registered + * contextId is suspended for the duration of the request and is restored when this handler is done. + *

+ * + * @author Stefan Guilhen + */ +public class JACCContextIdHandler implements HttpHandler { + + private final PrivilegedAction setContextIdAction; + private final HttpHandler next; + + public JACCContextIdHandler(String contextId, HttpHandler next) { + this.setContextIdAction = new SetContextIDAction(contextId); + this.next = next; + } + + @Override + public void handleRequest(final HttpServerExchange exchange) throws Exception { + // set JACC contextID and forward the request to the next handler. + String previousContextID = null; + try { + previousContextID = setContextID(setContextIdAction); + next.handleRequest(exchange); + } + finally { + // restore the previous JACC contextID. + if(WildFlySecurityManager.isChecking()) { + setContextID(new SetContextIDAction(previousContextID)); + } else { + PolicyContext.setContextID(previousContextID); + } + } + } + + /** + *

+ * A {@link PrivilegedAction} that sets the contextId in the {@link PolicyContext}. + *

+ */ + private static class SetContextIDAction implements PrivilegedAction { + + private final String contextID; + + SetContextIDAction(String contextID) { + this.contextID = contextID; + } + + @Override + public String run() { + String currentContextID = PolicyContext.getContextID(); + PolicyContext.setContextID(this.contextID); + return currentContextID; + } + } + + private String setContextID(PrivilegedAction action) { + if(WildFlySecurityManager.isChecking()) { + return WildFlySecurityManager.doUnchecked(action); + }else { + return action.run(); + } + } + + public static HandlerWrapper wrapper(final String contextId) { + return new HandlerWrapper() { + @Override + public HttpHandler wrap(final HttpHandler handler) { + //we only run this on REQUEST or ASYNC invocations + return new PredicateHandler(Predicates.or(DispatcherTypePredicate.REQUEST, DispatcherTypePredicate.ASYNC), new JACCContextIdHandler(contextId, handler), handler); + } + }; + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCDeployer.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCDeployer.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCDeployer.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,53 @@ +/* + * 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.extension.undertow.security.jacc; + +import org.jboss.as.security.deployment.AbstractSecurityDeployer; +import org.jboss.as.security.service.JaccService; +import org.jboss.as.server.deployment.AttachmentKey; +import org.jboss.as.web.common.WarMetaData; + +/** + * Handles war deployments + * + * @author Marcus Moyses + */ +public class WarJACCDeployer extends AbstractSecurityDeployer { + + /** + * {@inheritDoc} + */ + @Override + protected AttachmentKey getMetaDataType() { + return WarMetaData.ATTACHMENT_KEY; + } + + /** + * {@inheritDoc} + */ + @Override + protected JaccService createService(String contextId, WarMetaData metaData, Boolean standalone) { + return new WarJACCService(contextId, metaData, standalone); + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCService.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCService.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jacc/WarJACCService.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,856 @@ +/* + * 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.extension.undertow.security.jacc; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.security.jacc.PolicyConfiguration; +import javax.security.jacc.PolicyContextException; +import javax.security.jacc.WebResourcePermission; +import javax.security.jacc.WebRoleRefPermission; +import javax.security.jacc.WebUserDataPermission; + +import org.jboss.as.security.service.JaccService; +import org.jboss.as.web.common.WarMetaData; +import org.jboss.metadata.javaee.spec.SecurityRoleRefMetaData; +import org.jboss.metadata.javaee.spec.SecurityRoleRefsMetaData; +import org.jboss.metadata.web.jboss.JBossServletMetaData; +import org.jboss.metadata.web.jboss.JBossServletsMetaData; +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.spec.EmptyRoleSemanticType; +import org.jboss.metadata.web.spec.HttpMethodConstraintMetaData; +import org.jboss.metadata.web.spec.SecurityConstraintMetaData; +import org.jboss.metadata.web.spec.ServletMappingMetaData; +import org.jboss.metadata.web.spec.ServletSecurityMetaData; +import org.jboss.metadata.web.spec.UserDataConstraintMetaData; +import org.jboss.metadata.web.spec.WebResourceCollectionMetaData; +import org.jboss.metadata.web.spec.WebResourceCollectionsMetaData; + +/** + * A service that creates JACC permissions for a web deployment + * @author Scott.Stark@jboss.org + * @author Anil.Saldhana@jboss.org + * @author Marcus Moyses + */ +public class WarJACCService extends JaccService { + + /** A prefix pattern "/prefix/*" */ + private static final int PREFIX = 1; + + /** An extension pattern "*.ext" */ + private static final int EXTENSION = 2; + + /** The "/" default pattern */ + private static final int DEFAULT = 3; + + /** A prefix pattern "/prefix/*" */ + private static final int EXACT = 4; + + private static final String ANY_AUTHENTICATED_USER_ROLE = "**"; + + public WarJACCService(String contextId, WarMetaData metaData, Boolean standalone) { + super(contextId, metaData, standalone); + } + + /** {@inheritDoc} */ + @Override + public void createPermissions(WarMetaData metaData, PolicyConfiguration pc) throws PolicyContextException { + + JBossWebMetaData jbossWebMetaData = metaData.getMergedJBossWebMetaData(); + HashMap patternMap = qualifyURLPatterns(jbossWebMetaData); + + List secConstraints = jbossWebMetaData.getSecurityConstraints(); + + if (secConstraints != null) { + for (SecurityConstraintMetaData secConstraint : secConstraints) { + WebResourceCollectionsMetaData resourceCollectionsMetaData = secConstraint.getResourceCollections(); + UserDataConstraintMetaData userDataConstraintMetaData = secConstraint.getUserDataConstraint(); + + if (resourceCollectionsMetaData != null) { + if (secConstraint.isExcluded() || secConstraint.isUnchecked()) { + // Process the permissions for the excluded/unchecked resources + for (WebResourceCollectionMetaData resourceCollectionMetaData : resourceCollectionsMetaData) { + List httpMethods = new ArrayList<>(resourceCollectionMetaData.getHttpMethods()); + List ommisions = resourceCollectionMetaData.getHttpMethodOmissions(); + if(httpMethods.isEmpty() && !ommisions.isEmpty()) { + httpMethods.addAll(WebResourceCollectionMetaData.ALL_HTTP_METHODS); + httpMethods.removeAll(ommisions); + } + List urlPatterns = resourceCollectionMetaData.getUrlPatterns(); + for (String urlPattern : urlPatterns) { + PatternInfo info = patternMap.get(urlPattern); + info.descriptor=true; + // Add the excluded methods + if (secConstraint.isExcluded()) { + info.addExcludedMethods(httpMethods); + } + + // SECURITY-63: Missing auth-constraint needs unchecked policy + if (secConstraint.isUnchecked() && httpMethods.isEmpty()) { + info.isMissingAuthConstraint = true; + } else { + info.missingAuthConstraintMethods.addAll(httpMethods); + } + } + } + } else { + // Process the permission for the resources x roles + for (WebResourceCollectionMetaData resourceCollectionMetaData : resourceCollectionsMetaData) { + List httpMethods = new ArrayList<>(resourceCollectionMetaData.getHttpMethods()); + List methodOmissions = resourceCollectionMetaData.getHttpMethodOmissions(); + if(httpMethods.isEmpty() && !methodOmissions.isEmpty()) { + httpMethods.addAll(WebResourceCollectionMetaData.ALL_HTTP_METHODS); + httpMethods.removeAll(methodOmissions); + } + List urlPatterns = resourceCollectionMetaData.getUrlPatterns(); + for (String urlPattern : urlPatterns) { + // Get the qualified url pattern + PatternInfo info = patternMap.get(urlPattern); + info.descriptor=true; + HashSet mappedRoles = new HashSet(); + secConstraint.getAuthConstraint().getRoleNames(); + List authRoles = secConstraint.getAuthConstraint().getRoleNames(); + for (String role : authRoles) { + if ("*".equals(role)) { + // The wildcard ref maps to all declared security-role names + mappedRoles.addAll(jbossWebMetaData.getSecurityRoleNames()); + } + else { + mappedRoles.add(role); + } + } + info.addRoles(mappedRoles, httpMethods); + // Add the transport to methods + if (userDataConstraintMetaData != null && userDataConstraintMetaData.getTransportGuarantee() != null) + info.addTransport(userDataConstraintMetaData.getTransportGuarantee().name(), httpMethods); + } + } + } + } + } + } + + JBossServletsMetaData servlets = jbossWebMetaData.getServlets(); + List mappings = jbossWebMetaData.getServletMappings(); + if(servlets != null && mappings != null) { + + Map> servletMappingMap = new HashMap<>(); + for(ServletMappingMetaData mapping : mappings) { + List list = servletMappingMap.get(mapping.getServletName()); + if(list == null) { + servletMappingMap.put(mapping.getServletName(), list = new ArrayList<>()); + } + list.addAll(mapping.getUrlPatterns()); + } + if(!jbossWebMetaData.isMetadataComplete()) { + for (JBossServletMetaData servlet : servlets) { + ServletSecurityMetaData security = servlet.getServletSecurity(); + if (security != null) { + List servletMappings = servletMappingMap.get(servlet.getServletName()); + if (servletMappings != null) { + + if (security.getHttpMethodConstraints() != null) { + for (HttpMethodConstraintMetaData s : security.getHttpMethodConstraints()) { + if (s.getRolesAllowed() == null || s.getRolesAllowed().isEmpty()) { + for (String urlPattern : servletMappings) { + // Get the qualified url pattern + PatternInfo info = patternMap.get(urlPattern); + if (info.descriptor) { + continue; + } + // Add the excluded methods + if (s.getEmptyRoleSemantic() == null || s.getEmptyRoleSemantic() == EmptyRoleSemanticType.PERMIT) { + info.missingAuthConstraintMethods.add(s.getMethod()); + } else { + info.addExcludedMethods(Collections.singletonList(s.getMethod())); + } + // Add the transport to methods + if (s.getTransportGuarantee() != null) + info.addTransport(s.getTransportGuarantee().name(), Collections.singletonList(s.getMethod())); + } + } else { + for (String urlPattern : servletMappings) { + // Get the qualified url pattern + PatternInfo info = patternMap.get(urlPattern); + if (info.descriptor) { + continue; + } + HashSet mappedRoles = new HashSet(); + List authRoles = s.getRolesAllowed(); + for (String role : authRoles) { + if ("*".equals(role)) { + // The wildcard ref maps to all declared security-role names + mappedRoles.addAll(jbossWebMetaData.getSecurityRoleNames()); + } else { + mappedRoles.add(role); + } + } + info.addRoles(mappedRoles, Collections.singletonList(s.getMethod())); + // Add the transport to methods + if (s.getTransportGuarantee() != null) + info.addTransport(s.getTransportGuarantee().name(), Collections.singletonList(s.getMethod())); + } + } + } + } + if (security.getRolesAllowed() == null || security.getRolesAllowed().isEmpty()) { + for (String urlPattern : servletMappings) { + // Get the qualified url pattern + PatternInfo info = patternMap.get(urlPattern); + if (info.descriptor) { + continue; + } + // Add the excluded methods + if (security.getEmptyRoleSemantic() == null || security.getEmptyRoleSemantic() == EmptyRoleSemanticType.PERMIT) { + info.isMissingAuthConstraint = true; + } else { + Set methods = new HashSet<>(WebResourceCollectionMetaData.ALL_HTTP_METHODS); + if (security.getHttpMethodConstraints() != null) { + for (HttpMethodConstraintMetaData method : security.getHttpMethodConstraints()) { + methods.remove(method.getMethod()); + } + } + info.addExcludedMethods(new ArrayList<>(methods)); + } + // Add the transport to methods + if (security.getTransportGuarantee() != null) + info.addTransport(security.getTransportGuarantee().name(), Collections.emptyList()); + } + } else { + for (String urlPattern : servletMappings) { + // Get the qualified url pattern + PatternInfo info = patternMap.get(urlPattern); + if (info.descriptor) { + continue; + } + HashSet mappedRoles = new HashSet(); + List authRoles = security.getRolesAllowed(); + for (String role : authRoles) { + if ("*".equals(role)) { + // The wildcard ref maps to all declared security-role names + mappedRoles.addAll(jbossWebMetaData.getSecurityRoleNames()); + } else { + mappedRoles.add(role); + } + } + info.addRoles(mappedRoles, Collections.emptyList()); + // Add the transport to methods + if (security.getTransportGuarantee() != null) + info.addTransport(security.getTransportGuarantee().name(), Collections.emptyList()); + } + } + } + } + } + } + } + + // Create the permissions + for (PatternInfo info : patternMap.values()) { + String qurl = info.getQualifiedPattern(); + if (info.isOverridden) { + continue; + } + // Create the excluded permissions + String[] httpMethods = info.getExcludedMethods(); + if (httpMethods != null) { + // There were excluded security-constraints + WebResourcePermission wrp = new WebResourcePermission(qurl, httpMethods); + WebUserDataPermission wudp = new WebUserDataPermission(qurl, httpMethods, null); + pc.addToExcludedPolicy(wrp); + pc.addToExcludedPolicy(wudp); + + } + + // Create the role permissions + Iterator>> roles = info.getRoleMethods(); + Set seenMethods = new HashSet<>(); + while (roles.hasNext()) { + Map.Entry> roleMethods = roles.next(); + String role = roleMethods.getKey(); + Set methods = roleMethods.getValue(); + seenMethods.addAll(methods); + httpMethods = methods.toArray(new String[methods.size()]); + pc.addToRole(role, new WebResourcePermission(qurl, httpMethods)); + + } + + //there are totally 7 http methods from the jacc spec (See WebResourceCollectionMetaData.ALL_HTTP_METHOD_NAMES) + final int NUMBER_OF_HTTP_METHODS = 7; + // JACC 1.1: create !(httpmethods) in unchecked perms + if(jbossWebMetaData.getDenyUncoveredHttpMethods() == null) { + if (seenMethods.size() != NUMBER_OF_HTTP_METHODS) { + WebResourcePermission wrpUnchecked = new WebResourcePermission(qurl, "!" + + getCommaSeparatedString(seenMethods.toArray(new String[seenMethods.size()]))); + pc.addToUncheckedPolicy(wrpUnchecked); + } + } + if (jbossWebMetaData.getDenyUncoveredHttpMethods() == null) { + // Create the unchecked permissions + String[] missingHttpMethods = info.getMissingMethods(); + int length = missingHttpMethods.length; + roles = info.getRoleMethods(); + if (length > 0 && !roles.hasNext()) { + // Create the unchecked permissions WebResourcePermissions + WebResourcePermission wrp = new WebResourcePermission(qurl, missingHttpMethods); + pc.addToUncheckedPolicy(wrp); + } else if (!roles.hasNext()) { + pc.addToUncheckedPolicy(new WebResourcePermission(qurl, (String) null)); + } + + // SECURITY-63: Missing auth-constraint needs unchecked policy + if (info.isMissingAuthConstraint) { + pc.addToUncheckedPolicy(new WebResourcePermission(qurl, (String) null)); + } else if (!info.allMethods.containsAll(WebResourceCollectionMetaData.ALL_HTTP_METHODS)) { + List methods = new ArrayList<>(WebResourceCollectionMetaData.ALL_HTTP_METHODS); + methods.removeAll(info.allMethods); + pc.addToUncheckedPolicy(new WebResourcePermission(qurl, methods.toArray(new String[methods.size()]))); + + } + if (!info.missingAuthConstraintMethods.isEmpty()) { + pc.addToUncheckedPolicy(new WebResourcePermission(qurl, info.missingAuthConstraintMethods.toArray(new String[info.missingAuthConstraintMethods.size()]))); + } + } + + // Create the unchecked permissions WebUserDataPermissions + Iterator>> transportConstraints = info.getTransportMethods(); + while (transportConstraints.hasNext()) { + Map.Entry> transportMethods = transportConstraints.next(); + String transport = transportMethods.getKey(); + Set methods = transportMethods.getValue(); + httpMethods = new String[methods.size()]; + methods.toArray(httpMethods); + WebUserDataPermission wudp = new WebUserDataPermission(qurl, httpMethods, transport); + pc.addToUncheckedPolicy(wudp); + + // If the transport is "NONE", then add an exclusive WebUserDataPermission + // with the url pattern and null + if ("NONE".equals(transport)) { + WebUserDataPermission wudp1 = new WebUserDataPermission(qurl, null); + pc.addToUncheckedPolicy(wudp1); + } else { + // JACC 1.1: Transport is CONFIDENTIAL/INTEGRAL, add a !(http methods) + WebUserDataPermission wudpNonNull = new WebUserDataPermission(qurl, "!" + + getCommaSeparatedString(httpMethods)); + pc.addToUncheckedPolicy(wudpNonNull); + } + } + } + + Set declaredRoles = jbossWebMetaData.getSecurityRoleNames(); + declaredRoles.add(ANY_AUTHENTICATED_USER_ROLE); + + /* + * Create WebRoleRefPermissions for all servlet/security-role-refs along with all the cross product of servlets and + * security-role elements that are not referenced via a security-role-ref as described in JACC section 3.1.3.2 + */ + JBossServletsMetaData servletsMetaData = jbossWebMetaData.getServlets(); + for (JBossServletMetaData servletMetaData : servletsMetaData) { + Set unrefRoles = new HashSet(declaredRoles); + String servletName = servletMetaData.getName(); + SecurityRoleRefsMetaData roleRefsMetaData = servletMetaData.getSecurityRoleRefs(); + // Perform the unreferenced roles processing for every servlet name + if (roleRefsMetaData != null) { + for (SecurityRoleRefMetaData roleRefMetaData : roleRefsMetaData) { + String roleRef = roleRefMetaData.getRoleLink(); + String roleName = roleRefMetaData.getRoleName(); + WebRoleRefPermission wrrp = new WebRoleRefPermission(servletName, roleName); + pc.addToRole(roleRef, wrrp); + + // Remove the role from the unreferencedRoles + unrefRoles.remove(roleName); + } + } + // Spec 3.1.3.2: For each servlet element in the deployment descriptor + // a WebRoleRefPermission must be added to each security-role of the + // application whose name does not appear as the rolename + // in a security-role-ref within the servlet element. + for (String unrefRole : unrefRoles) { + WebRoleRefPermission unrefP = new WebRoleRefPermission(servletName, unrefRole); + pc.addToRole(unrefRole, unrefP); + } + } + + // JACC 1.1:Spec 3.1.3.2: For each security-role defined in the deployment descriptor, an + // additional WebRoleRefPermission must be added to the corresponding role by + // calling the addToRole method on the PolicyConfiguration object. The + // name of all such permissions must be the empty string, and the actions of each + // such permission must be the role-name of the corresponding role. + for (String role : declaredRoles) { + WebRoleRefPermission wrrep = new WebRoleRefPermission("", role); + pc.addToRole(role, wrrep); + } + } + + static String getCommaSeparatedString(String[] str) { + int len = str.length; + Arrays.sort(str); + + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < len; i++) { + if (i > 0) + buf.append(","); + buf.append(str[i]); + } + return buf.toString(); + } + + /** + * Determine the url-pattern type + * + * @param urlPattern - the raw url-pattern value + * @return one of EXACT, EXTENSION, PREFIX, DEFAULT + */ + static int getPatternType(String urlPattern) { + int type = EXACT; + if (urlPattern.startsWith("*.")) + type = EXTENSION; + else if (urlPattern.startsWith("/") && urlPattern.endsWith("/*")) + type = PREFIX; + else if (urlPattern.equals("/")) + type = DEFAULT; + return type; + } + + /** + * JACC url pattern Qualified URL Pattern Names. + * + * The rules for qualifying a URL pattern are dependent on the rules for determining if one URL pattern matches another as + * defined in Section 3.1.3.3, Servlet URL-Pattern Matching Rules, and are described as follows: - If the pattern is a path + * prefix pattern, it must be qualified by every path-prefix pattern in the deployment descriptor matched by and different + * from the pattern being qualified. The pattern must also be qualified by every exact pattern appearing in the deployment + * descriptor that is matched by the pattern being qualified. - If the pattern is an extension pattern, it must be qualified + * by every path-prefix pattern appearing in the deployment descriptor and every exact pattern in the deployment descriptor + * that is matched by the pattern being qualified. - If the pattern is the default pattern, "/", it must be qualified by + * every other pattern except the default pattern appearing in the deployment descriptor. - If the pattern is an exact + * pattern, its qualified form must not contain any qualifying patterns. + * + * URL patterns are qualified by appending to their String representation, a colon separated representation of the list of + * patterns that qualify the pattern. Duplicates must not be included in the list of qualifying patterns, and any qualifying + * pattern matched by another qualifying pattern may5 be dropped from the list. + * + * Any pattern, qualified by a pattern that matches it, is overridden and made irrelevant (in the translation) by the + * qualifying pattern. Specifically, all extension patterns and the default pattern are made irrelevant by the presence of + * the path prefix pattern "/*" in a deployment descriptor. Patterns qualified by the "/*" pattern violate the + * URLPatternSpec constraints of WebResourcePermission and WebUserDataPermission names and must be rejected by the + * corresponding permission constructors. + * + * @param metaData - the web deployment metadata + * @return HashMap + */ + static HashMap qualifyURLPatterns(JBossWebMetaData metaData) { + ArrayList prefixList = new ArrayList(); + ArrayList extensionList = new ArrayList(); + ArrayList exactList = new ArrayList(); + HashMap patternMap = new HashMap(); + PatternInfo defaultInfo = null; + + List constraints = metaData.getSecurityConstraints(); + if (constraints != null) { + for (SecurityConstraintMetaData constraint : constraints) { + WebResourceCollectionsMetaData resourceCollectionsMetaData = constraint.getResourceCollections(); + if (resourceCollectionsMetaData != null) { + for (WebResourceCollectionMetaData resourceCollectionMetaData : resourceCollectionsMetaData) { + List urlPatterns = resourceCollectionMetaData.getUrlPatterns(); + for (String url : urlPatterns) { + int type = getPatternType(url); + PatternInfo info = patternMap.get(url); + if (info == null) { + info = new PatternInfo(url, type); + patternMap.put(url, info); + switch (type) { + case PREFIX: + prefixList.add(info); + break; + case EXTENSION: + extensionList.add(info); + break; + case EXACT: + exactList.add(info); + break; + case DEFAULT: + defaultInfo = info; + break; + } + } + } + } + } + } + } + JBossServletsMetaData servlets = metaData.getServlets(); + List mappings = metaData.getServletMappings(); + if(!metaData.isMetadataComplete() && servlets != null && mappings != null) { + + Map> servletMappingMap = new HashMap<>(); + for(ServletMappingMetaData mapping : mappings) { + List list = servletMappingMap.get(mapping.getServletName()); + if(list == null) { + servletMappingMap.put(mapping.getServletName(), list = new ArrayList<>()); + } + list.addAll(mapping.getUrlPatterns()); + } + for (JBossServletMetaData servlet : servlets) { + ServletSecurityMetaData security = servlet.getServletSecurity(); + if(security != null) { + List servletMappings = servletMappingMap.get(servlet.getServletName()); + if(servletMappings != null) { + for (String url : servletMappings) { + int type = getPatternType(url); + PatternInfo info = patternMap.get(url); + if (info == null) { + info = new PatternInfo(url, type); + patternMap.put(url, info); + switch (type) { + case PREFIX: + prefixList.add(info); + break; + case EXTENSION: + extensionList.add(info); + break; + case EXACT: + exactList.add(info); + break; + case DEFAULT: + defaultInfo = info; + break; + } + } + } + } + } + } + } + + // Qualify all prefix patterns + for (int i = 0; i < prefixList.size(); i++) { + PatternInfo info = prefixList.get(i); + // Qualify by every other prefix pattern matching this pattern + for (int j = 0; j < prefixList.size(); j++) { + if (i == j) + continue; + PatternInfo other = prefixList.get(j); + if (info.matches(other)) + info.addQualifier(other); + } + // Qualify by every exact pattern that is matched by this pattern + for (PatternInfo other : exactList) { + if (info.matches(other)) + info.addQualifier(other); + } + } + + // Qualify all extension patterns + for (PatternInfo info : extensionList) { + // Qualify by every path prefix pattern + for (PatternInfo other : prefixList) { + // Any extension + info.addQualifier(other); + } + // Qualify by every matching exact pattern + for (PatternInfo other : exactList) { + if (info.isExtensionFor(other)) + info.addQualifier(other); + } + } + + // Qualify the default pattern + if (defaultInfo == null) { + defaultInfo = new PatternInfo("/", DEFAULT); + patternMap.put("/", defaultInfo); + } + for (PatternInfo info : patternMap.values()) { + if (info == defaultInfo) + continue; + defaultInfo.addQualifier(info); + } + + return patternMap; + } + + /** + * A representation of all security-constraint mappings for a unique url-pattern + */ + static class PatternInfo { + + static final HashMap> ALL_TRANSPORTS = new HashMap>(); + + static { + ALL_TRANSPORTS.put("NONE", WebResourceCollectionMetaData.ALL_HTTP_METHODS); + } + + /** The raw url-pattern string from the web.xml */ + String pattern; + + /** The qualified url pattern as determined by qualifyURLPatterns */ + String qpattern; + + /** The list of qualifying patterns as determined by qualifyURLPatterns */ + ArrayList qualifiers = new ArrayList(); + + /** One of PREFIX, EXTENSION, DEFAULT, EXACT */ + int type; + + /** HashSet Union of all http methods seen in excluded statements */ + HashSet excludedMethods; + + /** HashMap> role to http methods */ + HashMap> roles; + + /** HashMap> transport to http methods */ + HashMap> transports; + + /** The url pattern to http methods for patterns for */ + HashSet allMethods = new HashSet(); + + /** + * Does a qualifying pattern match this pattern and make this pattern obsolete? + */ + boolean isOverridden; + + /** + * A Security Constraint is missing an + */ + boolean isMissingAuthConstraint; + + Set missingAuthConstraintMethods = new HashSet<>(); + + boolean descriptor = false; + + /** + * @param pattern - the url-pattern value + * @param type - one of EXACT, EXTENSION, PREFIX, DEFAULT + */ + PatternInfo(String pattern, int type) { + this.pattern = pattern; + this.type = type; + } + + /** + * Augment the excluded methods associated with this url + * + * @param httpMethods the list of excluded methods + */ + void addExcludedMethods(List httpMethods) { + Collection methods = httpMethods; + if (methods.size() == 0) + methods = WebResourceCollectionMetaData.ALL_HTTP_METHODS; + if (excludedMethods == null) + excludedMethods = new HashSet(); + excludedMethods.addAll(methods); + allMethods.addAll(methods); + } + + /** + * Get the list of excluded http methods + * + * @return excluded http methods if the exist, null if there were no excluded security constraints + */ + public String[] getExcludedMethods() { + String[] httpMethods = null; + if (excludedMethods != null) { + httpMethods = new String[excludedMethods.size()]; + excludedMethods.toArray(httpMethods); + } + return httpMethods; + } + + /** + * Update the role to http methods mapping for this url. + * + * @param mappedRoles - the role-name values for the auth-constraint + * @param httpMethods - the http-method values for the web-resource-collection + */ + public void addRoles(HashSet mappedRoles, List httpMethods) { + Collection methods = httpMethods; + if (methods.size() == 0) + methods = WebResourceCollectionMetaData.ALL_HTTP_METHODS; + allMethods.addAll(methods); + if (roles == null) + roles = new HashMap>(); + + for (String role : mappedRoles) { + Set roleMethods = roles.get(role); + if (roleMethods == null) { + roleMethods = new HashSet(); + roles.put(role, roleMethods); + } + roleMethods.addAll(methods); + } + } + + /** + * Get the role to http method mappings + * + * @return Iterator>> for the role to http method mappings. + */ + public Iterator>> getRoleMethods() { + HashMap> tmp = roles; + if (tmp == null) + tmp = new HashMap>(0); + return tmp.entrySet().iterator(); + } + + /** + * Update the role to http methods mapping for this url. + * + * @param transport - the transport-guarantee value + * @param httpMethods - the http-method values for the web-resource-collection + */ + void addTransport(String transport, List httpMethods) { + Collection methods = httpMethods; + if (methods.size() == 0) + methods = WebResourceCollectionMetaData.ALL_HTTP_METHODS; + if (transports == null) + transports = new HashMap>(); + + Set transportMethods = transports.get(transport); + if (transportMethods == null) { + transportMethods = new HashSet(); + transports.put(transport, transportMethods); + } + transportMethods.addAll(methods); + } + + /** + * Get the transport to http method mappings + * + * @return Iterator>> for the transport to http method mappings. + */ + public Iterator>> getTransportMethods() { + HashMap> tmp = transports; + if (tmp == null) + tmp = ALL_TRANSPORTS; + return tmp.entrySet().iterator(); + } + + /** + * Get the list of http methods that were not associated with an excluded or role based mapping of this url. + * + * @return the subset of http methods that should be unchecked + */ + public String[] getMissingMethods() { + String[] httpMethods = {}; + if (allMethods.size() == 0) { + // There were no excluded or role based security-constraints + httpMethods = WebResourceCollectionMetaData.ALL_HTTP_METHOD_NAMES; + } else { + httpMethods = WebResourceCollectionMetaData.getMissingHttpMethods(allMethods); + } + return httpMethods; + } + + /** + * Add the qualifying pattern. If info is a prefix pattern that matches this pattern, it overrides this pattern and will + * exclude it from inclusion in the policy. + * + * @param info - a url pattern that should qualify this pattern + */ + void addQualifier(PatternInfo info) { + if (qualifiers.contains(info) == false) { + // See if this pattern is matched by the qualifier + if (info.type == PREFIX && info.matches(this)) + isOverridden = true; + qualifiers.add(info); + } + } + + /** + * Get the url pattern with its qualifications + * + * @return the qualified form of the url pattern + */ + public String getQualifiedPattern() { + if (qpattern == null) { + StringBuilder tmp = new StringBuilder(pattern); + for (int n = 0; n < qualifiers.size(); n++) { + tmp.append(':'); + PatternInfo info = qualifiers.get(n); + tmp.append(info.pattern); + } + qpattern = tmp.toString(); + } + return qpattern; + } + + public int hashCode() { + return pattern.hashCode(); + } + + public boolean equals(Object obj) { + PatternInfo pi = (PatternInfo) obj; + return pattern.equals(pi.pattern); + } + + /** + * See if this pattern is matches the other pattern + * + * @param other - another pattern + * @return true if the other pattern starts with this pattern less the "/*", false otherwise + */ + public boolean matches(PatternInfo other) { + int matchLength = pattern.length() - 2; + boolean matches = pattern.regionMatches(0, other.pattern, 0, matchLength); + return matches; + } + + /** + * See if this is an extension pattern that matches other + * + * @param other - another pattern + * @return true if is an extension pattern and other ends with this pattern + */ + public boolean isExtensionFor(PatternInfo other) { + int offset = other.pattern.lastIndexOf('.'); + int length = pattern.length() - 1; + boolean isExtensionFor = false; + if (offset > 0) { + isExtensionFor = pattern.regionMatches(1, other.pattern, offset, length); + } + return isExtensionFor; + } + + public String toString() { + StringBuilder tmp = new StringBuilder("PatternInfo["); + tmp.append("pattern="); + tmp.append(pattern); + tmp.append(",type="); + tmp.append(type); + tmp.append(",isOverridden="); + tmp.append(isOverridden); + tmp.append(",qualifiers="); + tmp.append(qualifiers); + tmp.append("]"); + return tmp.toString(); + } + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICAuthenticationMechanism.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICAuthenticationMechanism.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICAuthenticationMechanism.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,304 @@ +/* + * 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.extension.undertow.security.jaspi; + +import io.undertow.security.api.AuthenticatedSessionManager; +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.SecurityContext; +import io.undertow.security.idm.Account; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.servlet.handlers.security.ServletFormAuthenticationMechanism; +import io.undertow.util.AttachmentKey; + +import io.undertow.util.StatusCodes; +import org.jboss.security.SecurityConstants; +import org.jboss.security.SimpleGroup; +import org.jboss.security.SimplePrincipal; +import org.jboss.security.auth.callback.JBossCallbackHandler; +import org.jboss.security.auth.message.GenericMessageInfo; +import org.jboss.security.identity.plugins.SimpleRole; +import org.jboss.security.identity.plugins.SimpleRoleGroup; +import org.jboss.security.plugins.auth.JASPIServerAuthenticationManager; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.security.AccountImpl; + +import javax.security.auth.Subject; +import javax.security.auth.message.AuthException; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.jboss.security.SecurityConstants.ROLES_IDENTIFIER; + +import java.security.Principal; +import java.security.acl.Group; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jboss.security.auth.callback.JASPICallbackHandler; +import org.jboss.security.identity.Role; +import org.jboss.security.identity.RoleGroup; +import org.wildfly.extension.undertow.security.UndertowSecurityAttachments; + +/** + *

+ * {@link AuthenticationMechanism} implementation that enables JASPI-based authentication. + *

+ * + * @author Pedro Igor + * @author Stefan Guilhen + */ +public class JASPICAuthenticationMechanism implements AuthenticationMechanism { + + + static final String JASPI_HTTP_SERVLET_LAYER = "HttpServlet"; + private static final String MECHANISM_NAME = "JASPIC"; + private static final String JASPI_AUTH_TYPE = "javax.servlet.http.authType"; + private static final String JASPI_REGISTER_SESSION = "javax.servlet.http.registerSession"; + + public static final AttachmentKey HTTP_SERVER_EXCHANGE_ATTACHMENT_KEY = AttachmentKey.create(HttpServerExchange.class); + public static final AttachmentKey SECURITY_CONTEXT_ATTACHMENT_KEY = AttachmentKey.create(SecurityContext.class); + + public static final AttachmentKey AUTH_RUN = AttachmentKey.create(Boolean.class); + public static final int DEFAULT_ERROR_CODE = StatusCodes.UNAUTHORIZED; + + private final String securityDomain; + private final String configuredAuthMethod; + + public JASPICAuthenticationMechanism(final String securityDomain, final String configuredAuthMethod) { + this.securityDomain = securityDomain; + this.configuredAuthMethod = configuredAuthMethod; + } + + @Override + public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext sc) { + exchange.putAttachment(AUTH_RUN, true); + final ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + final JASPIServerAuthenticationManager sam = createJASPIAuthenticationManager(); + final GenericMessageInfo messageInfo = createMessageInfo(exchange, sc); + final String applicationIdentifier = buildApplicationIdentifier(requestContext); + final JASPICallbackHandler cbh = new JASPICallbackHandler(); + exchange.putAttachment(JASPICContext.ATTACHMENT_KEY, new JASPICContext(messageInfo, sam, cbh)); + UndertowLogger.ROOT_LOGGER.debugf("validateRequest for layer [%s] and applicationContextIdentifier [%s]", JASPI_HTTP_SERVLET_LAYER, applicationIdentifier); + + Account cachedAccount = null; + final JASPICSecurityContext jaspicSecurityContext = (JASPICSecurityContext) exchange.getSecurityContext(); + final AuthenticatedSessionManager sessionManager = exchange.getAttachment(AuthenticatedSessionManager.ATTACHMENT_KEY); + + if (sessionManager != null) { + AuthenticatedSessionManager.AuthenticatedSession authSession = sessionManager.lookupSession(exchange); + if(authSession != null) { + cachedAccount = authSession.getAccount(); + // if there is a cached account we set it in the security context so that the principal is available to + // SAM modules via request.getUserPrincipal(). + if (cachedAccount != null) { + jaspicSecurityContext.setCachedAuthenticatedAccount(cachedAccount); + } + } + } + + AuthenticationMechanismOutcome outcome = AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + Account authenticatedAccount = null; + + boolean isValid = sam.isValid(messageInfo, new Subject(), JASPI_HTTP_SERVLET_LAYER, applicationIdentifier, cbh); + jaspicSecurityContext.setCachedAuthenticatedAccount(null); + + if (isValid) { + // The CBH filled in the JBOSS SecurityContext, we need to create an Undertow account based on that + org.jboss.security.SecurityContext jbossSct = SecurityActions.getSecurityContext(); + authenticatedAccount = createAccount(cachedAccount, jbossSct); + updateSubjectRoles(jbossSct); + } + + // authType resolution (check message info first, then check for the configured auth method, then use mech-specific name). + String authType = (String) messageInfo.getMap().get(JASPI_AUTH_TYPE); + if (authType == null) + authType = this.configuredAuthMethod != null ? this.configuredAuthMethod : MECHANISM_NAME; + + if (isValid && authenticatedAccount != null) { + outcome = AuthenticationMechanismOutcome.AUTHENTICATED; + + Object registerObj = messageInfo.getMap().get(JASPI_REGISTER_SESSION); + boolean cache = false; + if(registerObj != null && (registerObj instanceof String)) { + cache = Boolean.valueOf((String)registerObj); + } + sc.authenticationComplete(authenticatedAccount, authType, cache); + } else if (isValid && authenticatedAccount == null && !isMandatory(requestContext)) { + outcome = AuthenticationMechanismOutcome.NOT_ATTEMPTED; + } else { + outcome = AuthenticationMechanismOutcome.NOT_AUTHENTICATED; + sc.authenticationFailed("JASPIC authentication failed.", authType); + + // make sure we don't return status OK if the AuthException was thrown except for FORM authentication + if (wasAuthExceptionThrown(exchange) && !statusIndicatesError(exchange) && !isFormAuthentication(exchange)) { + exchange.setResponseCode(DEFAULT_ERROR_CODE); + } + } + + // A SAM can wrap the HTTP request/response objects - update the servlet request context with the values found in the message info. + ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + servletRequestContext.setServletRequest((HttpServletRequest) messageInfo.getRequestMessage()); + servletRequestContext.setServletResponse((HttpServletResponse) messageInfo.getResponseMessage()); + + return outcome; + + } + + @Override + public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { + return new ChallengeResult(true); + } + + private JASPIServerAuthenticationManager createJASPIAuthenticationManager() { + return new JASPIServerAuthenticationManager(this.securityDomain, new JBossCallbackHandler()); + } + + static String buildApplicationIdentifier(final ServletRequestContext attachment) { + ServletRequest servletRequest = attachment.getServletRequest(); + return servletRequest.getServletContext().getVirtualServerName() + " " + servletRequest.getServletContext().getContextPath(); + } + + private GenericMessageInfo createMessageInfo(final HttpServerExchange exchange, final SecurityContext securityContext) { + ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + + GenericMessageInfo messageInfo = new GenericMessageInfo(); + + messageInfo.setRequestMessage(servletRequestContext.getServletRequest()); + messageInfo.setResponseMessage(servletRequestContext.getServletResponse()); + + messageInfo.getMap().put("javax.security.auth.message.MessagePolicy.isMandatory", isMandatory(servletRequestContext).toString()); + + // additional context data, useful to provide access to Undertow resources during the modules processing + messageInfo.getMap().put(SECURITY_CONTEXT_ATTACHMENT_KEY, securityContext); + messageInfo.getMap().put(HTTP_SERVER_EXCHANGE_ATTACHMENT_KEY, exchange); + + return messageInfo; + } + + private void updateSubjectRoles(final org.jboss.security.SecurityContext jbossSct){ + if (jbossSct == null) { + throw UndertowLogger.ROOT_LOGGER.nullParamter("org.jboss.security.SecurityContext"); + } + + RoleGroup contextRoleGroup = jbossSct.getUtil().getRoles(); + + if(contextRoleGroup == null){ + return; + } + + Collection contextRoles = contextRoleGroup.getRoles(); + + if(contextRoles.isEmpty()){ + return; + } + + Subject subject = jbossSct.getUtil().getSubject(); + Set groupPrincipals = subject.getPrincipals(Group.class); + Group subjectRoleGroup = null; + + for (Group candidate : groupPrincipals) { + if (candidate.getName().equals(ROLES_IDENTIFIER)) { + subjectRoleGroup = candidate; + break; + } + } + if (subjectRoleGroup == null) { + subjectRoleGroup = new SimpleGroup(ROLES_IDENTIFIER); + subject.getPrincipals().add(subjectRoleGroup); + } + for (Role role : contextRoles) { + Principal rolePrincipal = new SimplePrincipal(role.getRoleName()); + subjectRoleGroup.addMember(rolePrincipal); + } + } + + private Account createAccount(final Account cachedAccount, final org.jboss.security.SecurityContext jbossSct) { + if (jbossSct == null) { + throw UndertowLogger.ROOT_LOGGER.nullParamter("org.jboss.security.SecurityContext"); + } + + // null principal: SAM has opted out of the authentication process. + Principal userPrincipal = jbossSct.getUtil().getUserPrincipal(); + if (userPrincipal == null) { + return null; + } + + // SAM handled the same principal found in the cached account: indicates we must use the cached account. + if (cachedAccount != null && cachedAccount.getPrincipal() == userPrincipal) { + // populate the security context using the cached account data. + jbossSct.getUtil().createSubjectInfo(userPrincipal, ((AccountImpl) cachedAccount).getCredential(), jbossSct.getUtil().getSubject()); + RoleGroup roleGroup = new SimpleRoleGroup(SecurityConstants.ROLES_IDENTIFIER); + for (String role : cachedAccount.getRoles()) + roleGroup.addRole(new SimpleRole(role)); + jbossSct.getUtil().setRoles(roleGroup); + return cachedAccount; + } + + // SAM handled a different principal or there is no cached account: build a new account. + Set stringRoles = new HashSet(); + RoleGroup roleGroup = jbossSct.getUtil().getRoles(); + if (roleGroup != null) { + for (Role role : roleGroup.getRoles()) { + stringRoles.add(role.getRoleName()); + } + } + Object credential = jbossSct.getUtil().getCredential(); + Principal original = null; + if(cachedAccount != null) { + original = cachedAccount.getPrincipal(); + } + return new AccountImpl(userPrincipal, stringRoles, credential, original); + } + + /** + *

The authentication is mandatory if the servlet has http constraints (eg.: {@link + * javax.servlet.annotation.HttpConstraint}).

+ * + * @param attachment + * @return + */ + private Boolean isMandatory(final ServletRequestContext attachment) { + return attachment.getExchange().getSecurityContext() != null && attachment.getExchange().getSecurityContext().isAuthenticationRequired(); + } + + private boolean statusIndicatesError(HttpServerExchange exchange) { + return exchange.getResponseCode() != StatusCodes.OK; + } + + + static boolean wasAuthExceptionThrown(HttpServerExchange exchange) { + return exchange.getAttachment(UndertowSecurityAttachments.SECURITY_CONTEXT_ATTACHMENT).getData().get(AuthException.class.getName()) != null; + } + + static boolean isFormAuthentication(HttpServerExchange exchange) { + ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + List mechanisms = src.getDeployment().getAuthenticationMechanisms(); + for (AuthenticationMechanism mech : mechanisms) { + if (mech instanceof ServletFormAuthenticationMechanism) return true; + } + return false; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICContext.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICContext.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICContext.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,59 @@ +/* + * 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.extension.undertow.security.jaspi; + +import io.undertow.util.AttachmentKey; +import org.jboss.security.auth.callback.JASPICallbackHandler; +import org.jboss.security.plugins.auth.JASPIServerAuthenticationManager; + +import javax.security.auth.message.MessageInfo; + +/** + * @author Stuart Douglas + */ +public class JASPICContext { + + public static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(JASPICContext.class); + + private final MessageInfo messageInfo; + private final JASPIServerAuthenticationManager sam; + private final JASPICallbackHandler cbh; + + public JASPICContext(MessageInfo messageInfo, JASPIServerAuthenticationManager sam, JASPICallbackHandler cbh) { + this.messageInfo = messageInfo; + this.sam = sam; + this.cbh = cbh; + } + + public MessageInfo getMessageInfo() { + return messageInfo; + } + + public JASPIServerAuthenticationManager getSam() { + return sam; + } + + public JASPICallbackHandler getCbh() { + return cbh; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecureResponseHandler.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecureResponseHandler.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecureResponseHandler.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,70 @@ +/* + * 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.extension.undertow.security.jaspi; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletRequestContext; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.security.auth.Subject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author Stuart Douglas + */ +public class JASPICSecureResponseHandler implements HttpHandler { + + private final HttpHandler next; + + public JASPICSecureResponseHandler(HttpHandler next) { + this.next = next; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + try { + next.handleRequest(exchange); + } finally { + try { + JASPICContext context = exchange.getAttachment(JASPICContext.ATTACHMENT_KEY); + + if (!JASPICAuthenticationMechanism.wasAuthExceptionThrown(exchange) && context != null) { + ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + String applicationIdentifier = JASPICAuthenticationMechanism.buildApplicationIdentifier(requestContext); + UndertowLogger.ROOT_LOGGER.debugf("secureResponse for layer [%s] and applicationContextIdentifier [%s].", JASPICAuthenticationMechanism.JASPI_HTTP_SERVLET_LAYER, applicationIdentifier); + context.getSam().secureResponse(context.getMessageInfo(), new Subject(), JASPICAuthenticationMechanism.JASPI_HTTP_SERVLET_LAYER, applicationIdentifier, context.getCbh()); + + // A SAM can unwrap the HTTP request/response objects - update the servlet request context with the values found in the message info. + ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + servletRequestContext.setServletRequest((HttpServletRequest) context.getMessageInfo().getRequestMessage()); + servletRequestContext.setServletResponse((HttpServletResponse) context.getMessageInfo().getResponseMessage()); + } + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.errorInvokingSecureResponse(e); + } + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContext.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContext.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContext.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,199 @@ +/* + * 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.extension.undertow.security.jaspi; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.message.MessageInfo; +import javax.security.auth.message.config.AuthConfigFactory; +import javax.security.auth.message.config.AuthConfigProvider; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; + +import io.undertow.security.api.AuthenticationMode; +import io.undertow.security.idm.Account; +import io.undertow.security.idm.IdentityManager; +import io.undertow.security.impl.SecurityContextImpl; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletRequestContext; +import org.jboss.security.auth.callback.JASPICallbackHandler; +import org.jboss.security.auth.callback.JBossCallbackHandler; +import org.jboss.security.auth.message.GenericMessageInfo; +import org.jboss.security.plugins.auth.JASPIServerAuthenticationManager; + +/** + *

+ * A {@link io.undertow.security.api.SecurityContext} that implements the {@code login} and {@code logout} methods + * according to the JASPIC 1.1 specification. + *

+ * + * @author Stefan Guilhen + */ +class JASPICSecurityContext extends SecurityContextImpl { + + private static final String layer = "HttpServlet"; + private static final CallbackHandler handler = new JASPICallbackHandler(); + + private final HttpServerExchange exchange; + private final JASPIServerAuthenticationManager manager; + private Account cachedAuthenticatedAccount; + + public JASPICSecurityContext(final HttpServerExchange exchange, final AuthenticationMode mode, final IdentityManager identityManager, + final String securityDomain) { + super (exchange, mode, identityManager); + this.exchange = exchange; + this.manager = new JASPIServerAuthenticationManager(securityDomain, new JBossCallbackHandler()); + } + + /** + *

+ * JASPIC 1.1 specification: if there is an {@code AuthConfigProvider} for the {@code HttpServlet} layer and + * application context, then @{@code login} must throw a {@code ServletException} which may convey that the + * exception was caused by an incompatibility between the {@code login} method and the configured authentication + * mechanism. If there is no such provider, then the container must proceed with the regular {@code login} processing. + *

+ * + * @param username The username + * @param password The password + * @return true if the login succeeded, false otherwise + * @throws SecurityException if login is called when JASPIC is enabled for application context and layer. + */ + @Override + public boolean login(final String username, final String password) { + // if there is an AuthConfigProvider for the HttpServlet layer and appContext, this method must throw an exception. + String appContext = this.buildAppContext(); + AuthConfigProvider provider = AuthConfigFactory.getFactory().getConfigProvider(layer, appContext, null); + if (provider != null) { + ServletException se = new ServletException("login is not supported by the JASPIC mechanism"); + throw new SecurityException(se); + } + return super.login(username, password); + } + + /** + *

+ * JASPIC 1.1 specification: if there is an {@code AuthConfigProvider} for the {@code HttpServlet} layer and + * application context, then @{@code logout} must acquire a {@code ServerAuthContext} and call {@code cleanSubject} + * on the acquired context. + *

+ *

+ * The specified {@code Subject} should be non-null and should be the {@code Subject} returning from the most recent + * call to {@code validateRequest}. In our case, that {@code Subject} is set in the underlying security context, so + * we must retrieve it from there before calling {@code cleanSubject}. + *

+ *

+ * Once {@code cleanSubject} returns, {@code logout} must perform the regular (non-JASPIC) {@code logout} processing. + *

+ */ + @Override + public void logout() { + if (!isAuthenticated()) + return; + + // call cleanSubject() if there is an AuthConfigProvider for the HttpServlet layer and appContext. + String appContext = this.buildAppContext(); + if (AuthConfigFactory.getFactory().getConfigProvider(layer, appContext, null) != null) { + Subject authenticatedSubject = this.getAuthenticatedSubject(); + MessageInfo messageInfo = this.buildMessageInfo(); + this.manager.cleanSubject(messageInfo, authenticatedSubject, layer, appContext, handler); + } + + // following the return from cleanSubject(), logout must perform the regular logout processing. + super.logout(); + } + + /** + *

+ * Overrides the parent method to return the cached authenticated account (that is, the account that was set in the + * session as a result of a SAM setting the {@code javax.servlet.http.registerSession} property) when the regular + * account is null. This allows a SAM to retrieve the cached account principal by calling {@code getUserPrincipal()} + * on {@code HttpServletRequest}. + *

+ * + * @return the authenticated account (or cached account when it is null). + */ + @Override + public Account getAuthenticatedAccount() { + Account account = super.getAuthenticatedAccount(); + if (account == null) + account = this.cachedAuthenticatedAccount; + return account; + } + + /** + *

+ * Sets the cached authenticated account. This is set by the JASPIC mechanism when it detects an existing account + * in the session. + *

+ * + * @param account the cached authenticated account. + */ + public void setCachedAuthenticatedAccount(final Account account) { + this.cachedAuthenticatedAccount = account; + } + + /** + *

+ * Builds the JASPIC application context. + *

+ * + * @return a {@code String} representing the application context. + */ + private String buildAppContext() { + final ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + ServletRequest servletRequest = requestContext.getServletRequest(); + return servletRequest.getServletContext().getVirtualServerName() + " " + servletRequest.getServletContext().getContextPath(); + } + + /** + *

+ * Builds the {@code MessageInfo} instance for the {@code cleanSubject()} call. + *

+ * + * @return the constructed {@code MessageInfo} object. + */ + private MessageInfo buildMessageInfo() { + ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + GenericMessageInfo messageInfo = new GenericMessageInfo(); + messageInfo.setRequestMessage(servletRequestContext.getServletRequest()); + messageInfo.setResponseMessage(servletRequestContext.getServletResponse()); + // when calling cleanSubject, isMandatory must be set to true. + messageInfo.getMap().put("javax.security.auth.message.MessagePolicy.isMandatory", "true"); + return messageInfo; + + } + + /** + *

+ * Retrieves the authenticated subject from the underlying security context. + *

+ * + * @return a reference to the authenticated subject. + */ + private Subject getAuthenticatedSubject() { + Subject subject = null; + org.jboss.security.SecurityContext picketBoxContext = SecurityActions.getSecurityContext(); + if (picketBoxContext != null && picketBoxContext.getSubjectInfo() != null) + subject = picketBoxContext.getSubjectInfo().getAuthenticatedSubject(); + return subject != null ? subject : new Subject(); + } +} \ No newline at end of file Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContextFactory.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContextFactory.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/JASPICSecurityContextFactory.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,59 @@ +/* + * 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.extension.undertow.security.jaspi; + +import io.undertow.security.api.AuthenticationMode; +import io.undertow.security.api.SecurityContext; +import io.undertow.security.api.SecurityContextFactory; +import io.undertow.security.idm.IdentityManager; +import io.undertow.server.HttpServerExchange; + +/** + *

+ * A {@link io.undertow.security.api.SecurityContextFactory} implementation that creates {@link JASPICSecurityContext} + * instances. + *

+ */ +public class JASPICSecurityContextFactory implements SecurityContextFactory { + + private final String securityDomain; + + /** + *

+ * Creates an instance of {@code JASPICSecurityContextFactory} with the specified security domain. + *

+ * + * @param securityDomain the security domain that is to be set in all created {@link JASPICSecurityContext} instances. + */ + public JASPICSecurityContextFactory(final String securityDomain) { + this.securityDomain = securityDomain; + } + + @Override + public SecurityContext createSecurityContext(final HttpServerExchange exchange, final AuthenticationMode mode, + final IdentityManager identityManager, final String programmaticMechName) { + JASPICSecurityContext context = new JASPICSecurityContext(exchange, mode, identityManager, this.securityDomain); + if (programmaticMechName != null) + context.setProgramaticMechName(programmaticMechName); + return context; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/SecurityActions.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/SecurityActions.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/SecurityActions.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,58 @@ +/* + * 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.extension.undertow.security.jaspi; + +import java.security.PrivilegedAction; + +import org.jboss.security.SecurityContext; +import org.jboss.security.SecurityContextAssociation; +import org.wildfly.security.manager.WildFlySecurityManager; + +/** + * Privileged Actions + * + * @author Anil.Saldhana@redhat.com + * @since Jan 12, 2011 + */ +class SecurityActions { + + + /** + * Get the current {@code SecurityContext} + * + * @return an instance of {@code SecurityContext} + */ + public static SecurityContext getSecurityContext() { + if (WildFlySecurityManager.isChecking()) { + return WildFlySecurityManager.doUnchecked(new PrivilegedAction() { + @Override + public SecurityContext run() { + return SecurityContextAssociation.getSecurityContext(); + } + }); + } else { + return SecurityContextAssociation.getSecurityContext(); + } + } + +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/modules/HTTPSchemeServerAuthModule.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/modules/HTTPSchemeServerAuthModule.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/jaspi/modules/HTTPSchemeServerAuthModule.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,132 @@ +/* + * 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.extension.undertow.security.jaspi.modules; + +import io.undertow.security.api.AuthenticationMechanism; +import io.undertow.security.api.SecurityContext; +import io.undertow.server.HttpServerExchange; +import io.undertow.servlet.handlers.ServletRequestContext; +import org.wildfly.extension.undertow.logging.UndertowLogger; +import org.wildfly.extension.undertow.security.jaspi.JASPICAuthenticationMechanism; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.message.AuthException; +import javax.security.auth.message.AuthStatus; +import javax.security.auth.message.MessageInfo; +import javax.security.auth.message.MessagePolicy; +import javax.security.auth.message.module.ServerAuthModule; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; + +import static io.undertow.security.api.AuthenticationMechanism.AuthenticationMechanismOutcome.AUTHENTICATED; +import static io.undertow.security.api.AuthenticationMechanism.AuthenticationMechanismOutcome.NOT_AUTHENTICATED; +import static javax.security.auth.message.AuthStatus.SEND_CONTINUE; +import static javax.security.auth.message.AuthStatus.SUCCESS; + +/** + *

This class implements a JASPI {@code ServerAuthModule} that handles the standards HTTP Authentication + * Schemes.

+ * + * @author Pedro Igor + */ +public class HTTPSchemeServerAuthModule implements ServerAuthModule { + + private final String securityDomain; + private AuthenticationMechanism authenticationMechanism; + + public HTTPSchemeServerAuthModule(String securityDomain) { + this.securityDomain = securityDomain; + } + + @Override + public void initialize(final MessagePolicy messagePolicy, final MessagePolicy messagePolicy2, final CallbackHandler callbackHandler, final Map map) throws AuthException { + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) + throws AuthException { + // do nothing, just return SUCCESS. + return SUCCESS; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + HttpServerExchange exchange = (HttpServerExchange) messageInfo.getMap().get(JASPICAuthenticationMechanism.HTTP_SERVER_EXCHANGE_ATTACHMENT_KEY); + SecurityContext securityContext = (SecurityContext) messageInfo.getMap().get(JASPICAuthenticationMechanism.SECURITY_CONTEXT_ATTACHMENT_KEY); + ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + List mechanisms = src.getDeployment().getAuthenticationMechanisms(); + + try { + boolean success = false; + for (AuthenticationMechanism mechanism : mechanisms) { + AuthenticationMechanism.AuthenticationMechanismOutcome result = mechanism.authenticate(exchange, securityContext); + if (result == AUTHENTICATED) { + success = true; + break; + } else if (result == NOT_AUTHENTICATED) { + break; + } + } + + if (!success) { + String mandatory = (String) messageInfo.getMap().get("javax.security.auth.message.MessagePolicy.isMandatory"); + if(mandatory != null && mandatory.toLowerCase().equals("false")) { + return SUCCESS; + } else { + for (AuthenticationMechanism mechanism : mechanisms) { + AuthenticationMechanism.ChallengeResult challengeResult = mechanism.sendChallenge(exchange, securityContext); + if (challengeResult.getDesiredResponseCode() != null) { + exchange.setResponseCode(challengeResult.getDesiredResponseCode()); + } + if (exchange.isResponseComplete()) { + break; + } + } + return SEND_CONTINUE; + } + } + } catch (Exception e) { + UndertowLogger.ROOT_LOGGER.debug(e); + throw new AuthException("Could not validateRequest using mechanisms [" + mechanisms + "."); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return new Class[]{ServletRequest.class, ServletResponse.class, + HttpServletRequest.class, HttpServletResponse.class}; + } + + @Override + public void cleanSubject(final MessageInfo messageInfo, final Subject subject) throws AuthException { + //TODO: is necessary to clean the subject here ? + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableHostSingleSignOnManagerServiceConfiguratorProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableHostSingleSignOnManagerServiceConfiguratorProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableHostSingleSignOnManagerServiceConfiguratorProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,50 @@ +/* + * 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.extension.undertow.security.sso; + +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; + +import io.undertow.security.impl.SingleSignOnManager; + +/** + * Builds a distrubutable {@link SingleSignOnManagerFactory} service. + * @author Paul Ferraro + */ +public interface DistributableHostSingleSignOnManagerServiceConfiguratorProvider { + + Optional INSTANCE = StreamSupport.stream(ServiceLoader.load(DistributableHostSingleSignOnManagerServiceConfiguratorProvider.class, DistributableHostSingleSignOnManagerServiceConfiguratorProvider.class.getClassLoader()).spliterator(), false).findFirst(); + + /** + * Returns a builder of a SingleSignOnManagerFactory service for a host. + * @param name the service name + * @param serverName the name of the target server + * @param hostName the name of the target host + * @return builder for a service providing a {@link SingleSignOnManager} + */ + CapabilityServiceConfigurator getServiceConfigurator(ServiceName name, String serverName, String hostName); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/security/sso/DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,50 @@ +/* + * 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.extension.undertow.security.sso; + +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; +import org.wildfly.security.http.util.sso.SingleSignOnManager; + +import io.undertow.server.session.SessionIdGenerator; + +/** + * @author Paul Ferraro + */ +public interface DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider { + + Optional INSTANCE = StreamSupport.stream(ServiceLoader.load(DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.class, DistributableSecurityDomainSingleSignOnManagerServiceConfiguratorProvider.class.getClassLoader()).spliterator(), false).findFirst(); + + /** + * Returns a builder of a SingleSignOnManagerFactory service for a security domain. + * @param name the service name + * @param securityDomainName the name of the target security domain + * @param generator a generator of unique identifiers + * @return builder for a service providing a {@link SingleSignOnManager} + */ + CapabilityServiceConfigurator getServiceConfigurator(ServiceName name, String securityDomainName, SessionIdGenerator generator); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfig.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,79 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.as.web.session.SessionIdentifierCodec; + +import io.undertow.server.HttpServerExchange; +import io.undertow.server.session.SessionConfig; +import io.undertow.util.AttachmentKey; + +/** + * {@link SessionConfig} decorator that performs encoding/decoding of the session identifier. + * In this way, routing is completely opaque to the request, session, and session manager. + * @author Paul Ferraro + */ +public class CodecSessionConfig implements SessionConfig { + + private final SessionConfig config; + private final SessionIdentifierCodec codec; + private static final AttachmentKey SESSION_ID_SET = AttachmentKey.create(Boolean.class); + + public CodecSessionConfig(SessionConfig config, SessionIdentifierCodec codec) { + this.config = config; + this.codec = codec; + } + + @Override + public void setSessionId(HttpServerExchange exchange, String sessionId) { + exchange.putAttachment(SESSION_ID_SET, Boolean.TRUE); + this.config.setSessionId(exchange, this.codec.encode(sessionId)); + } + + @Override + public void clearSession(HttpServerExchange exchange, String sessionId) { + this.config.clearSession(exchange, this.codec.encode(sessionId)); + } + + @Override + public String findSessionId(HttpServerExchange exchange) { + String encodedSessionId = this.config.findSessionId(exchange); + if (encodedSessionId == null) return null; + String sessionId = this.codec.decode(encodedSessionId); + // Check if the encoding for this session has changed + String reencodedSessionId = this.codec.encode(sessionId); + if (!reencodedSessionId.equals(encodedSessionId) && exchange.getAttachment(SESSION_ID_SET) == null) { + this.config.setSessionId(exchange, reencodedSessionId); + } + return sessionId; + } + + @Override + public SessionCookieSource sessionCookieSource(HttpServerExchange exchange) { + return this.config.sessionCookieSource(exchange); + } + + @Override + public String rewriteUrl(String originalUrl, String sessionId) { + return this.config.rewriteUrl(originalUrl, this.codec.encode(sessionId)); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfigWrapper.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfigWrapper.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/CodecSessionConfigWrapper.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,47 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.as.web.session.SessionIdentifierCodec; + +import io.undertow.server.session.SessionConfig; +import io.undertow.servlet.api.Deployment; +import io.undertow.servlet.api.SessionConfigWrapper; + +/** + * Adds session identifier encoding/decoding to a {@link SessionConfig}. + * @author Paul Ferraro + */ +public class CodecSessionConfigWrapper implements SessionConfigWrapper { + + private final SessionIdentifierCodec codec; + + public CodecSessionConfigWrapper(SessionIdentifierCodec codec) { + this.codec = codec; + } + + @Override + public SessionConfig wrap(SessionConfig config, Deployment deployment) { + return new CodecSessionConfig(config, this.codec); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionIdentifierCodecServiceConfiguratorProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionIdentifierCodecServiceConfiguratorProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionIdentifierCodecServiceConfiguratorProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,56 @@ +/* + * 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.extension.undertow.session; + +import java.util.Collection; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.web.session.SessionIdentifierCodec; +import org.jboss.msc.service.ServiceName; + +/** + * Builds a {@link SessionIdentifierCodec} service. + * @author Paul Ferraro + */ +public interface DistributableSessionIdentifierCodecServiceConfiguratorProvider { + + Optional INSTANCE = StreamSupport.stream(ServiceLoader.load(DistributableSessionIdentifierCodecServiceConfiguratorProvider.class, DistributableSessionIdentifierCodecServiceConfiguratorProvider.class.getClassLoader()).spliterator(), false).findFirst(); + + /** + * Builds a {@link SessionIdentifierCodec} service. + * @param target a service target + * @param name a service name + * @param deploymentServiceName the service name of the deployment + * @return a service builder + */ + CapabilityServiceConfigurator getDeploymentServiceConfigurator(ServiceName name, String serverName, String deploymentName); + + /** + * Builds cross-deployment dependencies needed for route handling + * @param target the service target + * @return a service builder + */ + Collection getServerServiceConfigurators(String serverName); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerConfiguration.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerConfiguration.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerConfiguration.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,39 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.metadata.web.jboss.ReplicationGranularity; +import org.jboss.modules.Module; + +public interface DistributableSessionManagerConfiguration { + int getMaxActiveSessions(); + + ReplicationGranularity getGranularity(); + + String getServerName(); + + String getDeploymentName(); + + Module getModule(); + + String getCacheName(); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerFactoryServiceConfiguratorProvider.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerFactoryServiceConfiguratorProvider.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/DistributableSessionManagerFactoryServiceConfiguratorProvider.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,51 @@ +/* + * 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.extension.undertow.session; + +import io.undertow.servlet.api.SessionManagerFactory; + +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.msc.service.ServiceName; + +/** + * SPI for building a factory for creating a distributable session manager. + * @author Paul Ferraro + */ +public interface DistributableSessionManagerFactoryServiceConfiguratorProvider { + + Optional INSTANCE = StreamSupport.stream(ServiceLoader.load(DistributableSessionManagerFactoryServiceConfiguratorProvider.class, DistributableSessionManagerFactoryServiceConfiguratorProvider.class.getClassLoader()).spliterator(), false).findFirst(); + + /** + * Builds a {@link SessionManagerFactory} service. + * @param target the service target + * @param name the service name of the {@link SessionManagerFactory} service + * @param deploymentServiceName service name of the web application + * @param module the deployment module + * @param metaData the web application meta data + * @return a session manager factory service builder + */ + CapabilityServiceConfigurator getServiceConfigurator(ServiceName name, DistributableSessionManagerConfiguration configuration); +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser_1_0.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser_1_0.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionConfigParser_1_0.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,152 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.as.controller.parsing.ParseUtils; +import org.jboss.as.ee.structure.JBossDescriptorPropertyReplacement; +import org.jboss.as.server.logging.ServerLogger; +import org.jboss.as.server.deployment.DeploymentUnit; +import org.jboss.as.server.deployment.jbossallxml.JBossAllXMLParser; +import org.jboss.metadata.parser.jbossweb.ReplicationConfigParser; +import org.jboss.metadata.parser.servlet.SessionConfigMetaDataParser; +import org.jboss.metadata.property.PropertyReplacer; +import org.jboss.staxmapper.XMLExtendedStreamReader; +import org.wildfly.extension.undertow.logging.UndertowLogger; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.HashMap; +import java.util.Map; + +/** + * Parse shared session manager config + * + * @author Stuart Douglas + */ +public class SharedSessionConfigParser_1_0 implements JBossAllXMLParser { + + public static final String NAMESPACE_1_0 = "urn:jboss:shared-session-config:1.0"; + public static final QName ROOT_ELEMENT = new QName(NAMESPACE_1_0, "shared-session-config"); + + public static final SharedSessionConfigParser_1_0 INSTANCE = new SharedSessionConfigParser_1_0(); + + @Override + public SharedSessionManagerConfig parse(XMLExtendedStreamReader reader, DeploymentUnit deploymentUnit) throws XMLStreamException { + if(deploymentUnit.getParent() != null) { + UndertowLogger.ROOT_LOGGER.sharedSessionConfigNotInRootDeployment(deploymentUnit.getName()); + return null; + } + SharedSessionManagerConfig result = new SharedSessionManagerConfig(); + PropertyReplacer propertyReplacer = JBossDescriptorPropertyReplacement.propertyReplacer(deploymentUnit); + + readElement(reader, result, propertyReplacer); + return result; + } + + enum Element { + MAX_ACTIVE_SESSIONS, + REPLICATION_CONFIG, + SESSION_CONFIG, + + // default unknown element + UNKNOWN; + + private static final Map elements; + + static { + Map elementsMap = new HashMap(); + elementsMap.put(new QName(NAMESPACE_1_0, "max-active-sessions"), Element.MAX_ACTIVE_SESSIONS); + elementsMap.put(new QName(NAMESPACE_1_0, "replication-config"), Element.REPLICATION_CONFIG); + elementsMap.put(new QName(NAMESPACE_1_0, "session-config"), Element.SESSION_CONFIG); + elements = elementsMap; + } + + static Element of(QName qName) { + QName name; + if (qName.getNamespaceURI().equals("")) { + name = new QName(NAMESPACE_1_0, qName.getLocalPart()); + } else { + name = qName; + } + final Element element = elements.get(name); + return element == null ? UNKNOWN : element; + } + } + + + enum Version { + UNDERTOW_SHARED_1_0, + UNKNOWN + } + + private SharedSessionConfigParser_1_0() { + } + + public void readElement(final XMLExtendedStreamReader reader, final SharedSessionManagerConfig result, PropertyReplacer propertyReplacer) throws XMLStreamException { + final int count = reader.getAttributeCount(); + if (count != 0) { + throw ParseUtils.unexpectedAttribute(reader, 0); + } + // xsd:sequence + while (reader.hasNext()) { + switch (reader.nextTag()) { + case XMLStreamConstants.END_ELEMENT: { + return; + } + case XMLStreamConstants.START_ELEMENT: { + final Element element = Element.of(reader.getName()); + switch (element) { + case MAX_ACTIVE_SESSIONS: + final String value = getElementText(reader, propertyReplacer); + result.setMaxActiveSessions(Integer.parseInt(value)); + break; + case REPLICATION_CONFIG: + result.setReplicationConfig(ReplicationConfigParser.parse(reader, propertyReplacer)); + break; + case SESSION_CONFIG: + result.setSessionConfig(SessionConfigMetaDataParser.parse(reader, propertyReplacer)); + break; + default: + throw ParseUtils.unexpectedElement(reader); + } + break; + } + default: { + throw ParseUtils.unexpectedElement(reader); + } + } + } + throw endOfDocument(reader.getLocation()); + } + + private static String getElementText(final XMLStreamReader reader, final PropertyReplacer propertyReplacer) throws XMLStreamException { + return propertyReplacer.replaceProperties(reader.getElementText()); + } + + private static XMLStreamException endOfDocument(final Location location) { + return ServerLogger.ROOT_LOGGER.unexpectedEndOfDocument(location); + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionManagerConfig.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionManagerConfig.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SharedSessionManagerConfig.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,64 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.metadata.web.jboss.ReplicationConfig; +import org.jboss.metadata.web.spec.SessionConfigMetaData; +import org.jboss.msc.service.ServiceName; + +/** + * @author Stuart Douglas + */ +public class SharedSessionManagerConfig { + + public static final ServiceName SHARED_SESSION_MANAGER_SERVICE_NAME = ServiceName.of("undertow", "shared-session-manager"); + public static final ServiceName SHARED_SESSION_IDENTIFIER_CODEC_SERVICE_NAME = SHARED_SESSION_MANAGER_SERVICE_NAME.append("codec"); + + private int maxActiveSessions = -1; + private ReplicationConfig replicationConfig; + private SessionConfigMetaData sessionConfig; + + public int getMaxActiveSessions() { + return maxActiveSessions; + } + + public void setMaxActiveSessions(int maxActiveSessions) { + this.maxActiveSessions = maxActiveSessions; + } + + public ReplicationConfig getReplicationConfig() { + return replicationConfig; + } + + public void setReplicationConfig(ReplicationConfig replicationConfig) { + this.replicationConfig = replicationConfig; + } + + public SessionConfigMetaData getSessionConfig() { + return sessionConfig; + } + + public void setSessionConfig(SessionConfigMetaData sessionConfig) { + this.sessionConfig = sessionConfig; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleDistributableSessionManagerConfiguration.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleDistributableSessionManagerConfiguration.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleDistributableSessionManagerConfiguration.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,86 @@ +/* + * 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.extension.undertow.session; + +import org.jboss.metadata.web.jboss.JBossWebMetaData; +import org.jboss.metadata.web.jboss.ReplicationConfig; +import org.jboss.metadata.web.jboss.ReplicationGranularity; +import org.jboss.modules.Module; + +/** + * Simple {@link DistributableSessionManagerConfiguration} implementation that delegates to {@link JBossWebMetaData}. + * @author Paul Ferraro + */ +public class SimpleDistributableSessionManagerConfiguration implements DistributableSessionManagerConfiguration { + + private final Integer maxActiveSessions; + private final ReplicationConfig replicationConfig; + private final String serverName; + private final String deploymentName; + private final Module module; + + public SimpleDistributableSessionManagerConfiguration(JBossWebMetaData metaData, String serverName, String deploymentName, Module module) { + this(metaData.getMaxActiveSessions(), metaData.getReplicationConfig(), serverName, deploymentName, module); + } + + public SimpleDistributableSessionManagerConfiguration(SharedSessionManagerConfig config, String serverName, String deploymentName, Module module) { + this(config.getMaxActiveSessions(), config.getReplicationConfig(), serverName, deploymentName, module); + } + + public SimpleDistributableSessionManagerConfiguration(Integer maxActiveSessions, ReplicationConfig replicationConfig, String serverName, String deploymentName, Module module) { + this.maxActiveSessions = maxActiveSessions; + this.replicationConfig = replicationConfig; + this.serverName = serverName; + this.deploymentName = deploymentName; + this.module = module; + } + + @Override + public int getMaxActiveSessions() { + return (this.maxActiveSessions != null) ? this.maxActiveSessions.intValue() : -1; + } + + @Override + public ReplicationGranularity getGranularity() { + return ((this.replicationConfig != null) && (this.replicationConfig.getReplicationGranularity() != null)) ? this.replicationConfig.getReplicationGranularity() : ReplicationGranularity.SESSION; + } + + @Override + public String getServerName() { + return this.serverName; + } + + @Override + public String getDeploymentName() { + return this.deploymentName; + } + + @Override + public Module getModule() { + return this.module; + } + + @Override + public String getCacheName() { + return (this.replicationConfig != null) ? this.replicationConfig.getCacheName() : null; + } +} Index: 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleSessionIdentifierCodecServiceConfigurator.java =================================================================== diff -u --- 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleSessionIdentifierCodecServiceConfigurator.java (revision 0) +++ 3rdParty_sources/undertow/org/wildfly/extension/undertow/session/SimpleSessionIdentifierCodecServiceConfigurator.java (revision 7888422dedc5a048743723a09465df0a3d0d201b) @@ -0,0 +1,81 @@ +/* + * 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.extension.undertow.session; + +import java.util.function.Consumer; +import java.util.function.Function; + +import org.jboss.as.clustering.controller.CapabilityServiceConfigurator; +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.web.session.RoutingSupport; +import org.jboss.as.web.session.SessionIdentifierCodec; +import org.jboss.as.web.session.SimpleRoutingSupport; +import org.jboss.as.web.session.SimpleSessionIdentifierCodec; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.service.FunctionalService; +import org.wildfly.clustering.service.ServiceConfigurator; +import org.wildfly.clustering.service.ServiceSupplierDependency; +import org.wildfly.clustering.service.SimpleServiceNameProvider; +import org.wildfly.clustering.service.SupplierDependency; +import org.wildfly.extension.undertow.Capabilities; +import org.wildfly.extension.undertow.Server; + +/** + * Service providing a non-distributable {@link SessionIdentifierCodec} implementation. + * @author Paul Ferraro + */ +public class SimpleSessionIdentifierCodecServiceConfigurator extends SimpleServiceNameProvider implements CapabilityServiceConfigurator, Function { + + private final String serverName; + private final RoutingSupport routing = new SimpleRoutingSupport(); + + private volatile SupplierDependency server; + + public SimpleSessionIdentifierCodecServiceConfigurator(ServiceName name, String serverName) { + super(name); + this.serverName = serverName; + } + + @Override + public SessionIdentifierCodec apply(Server server) { + return new SimpleSessionIdentifierCodec(this.routing, server.getRoute()); + } + + @Override + public ServiceConfigurator configure(CapabilityServiceSupport support) { + this.server = new ServiceSupplierDependency<>(support.getCapabilityServiceName(Capabilities.CAPABILITY_SERVER, this.serverName)); + return this; + } + + @Override + public ServiceBuilder build(ServiceTarget target) { + ServiceBuilder builder = target.addService(this.getServiceName()); + Consumer codec = this.server.register(builder).provides(this.getServiceName()); + Service service = new FunctionalService<>(codec, this, this.server); + return builder.setInstance(service).setInitialMode(ServiceController.Mode.ON_DEMAND); + } +}