Version 1

    Issue analysis and design document for the feature request from the JDG team to allow registration of custom request handling on the WildFly http management interface.

     

    Overview

     

    Allow JDG to register contexts on the WildFly http management interface to serve static content (i.e. the content that provides their own console) and to provide more JDG-user-friendly URLs for management requests.

     

    Background

     

    WildFly allows custom extensions. One thing extensions may wish to do is to add additional functionality to WildFly's remote management interface, particularly to its HTTP management interface. An addition to the management interface can be a complex thing though, as it requires integration with Undertow (for the http handling), the kernel management layer (if the request eventually involves kernel management) and the security layer. WildFly provides long term compatibility guarantees, so any general purpose integration API for additional http management functionality needs to be carefully designed so it can be supported for the long term.

     

    For WildFly Core 3 / WildFly 11, the security layer is undergoing significant rework, so it's not feasible to design a stable generic integration API. But the JDG team has made a couple of fairly specific integration requests, where the security aspects seem to be something that align with the existing HTTP contexts WildFly supports, so it should be possible to create an integration facility for their needs, one that is not supported for general use.

     

    Issue Metadata

     

    EAP ISSUE: https://issues.jboss.org/browse/EAP7-614

     

    RELATED ISSUES: [WFCORE-1742] Allow registering a custom handler for management interface - JBoss Issue Tracker

     

    DEV CONTACTS: Brian Stansberry

     

    QE CONTACTS:

     

    AFFECTED PROJECTS OR COMPONENTS: WildFly Core kernel, JDG

     

    OTHER INTERESTED PARTIES:

     

    Requirements

     

    Hard Requirements

     

    These items must be satisfied in order to have a satisfactory feature.

     

    • Ability for an extension to register that the HTTP management interface should provide a context that serves static content. The registration call will provide an Undertow ResourceManager implementation that will provide the content.
      • The context name cannot conflict with any of the standard context names provided by WildFly (console, management, management-upload, logout, error)
      • The context will have semantics equivalent to those provided for the "console" context that provides the HAL console:
        • Unsecured (anyone can read the static content)
        • Responses include the HTTP header "X-Frame-Options" with value "SAMEORIGIN" (anti-clickjacking)
        • Directory listings are not allowed
        • Resources with names ending in the following suffixes are not cachable:
        • Otherwise, responses include the HTTP header "Cache-Control" with value "public, max-age=XXX" where XXX is the number of seconds equivalent to 31 days
        • If a security realm is associated with the interface, during boot until that realm is started any request to the context will be redirected to the /error context
    • Ability for an extension to register that the HTTP management interface should provide a context that delegates to the standard handler for the /management context. The registration call will provide an implementation of a "PathRemapper" interface. For any call to this context, the server will extract the portion of the request URL that follows the context name and pass it to the PathRemapper, which will reply with a String that represents a URL segment that would be valid relative to the '/management' context. The server will take that return value, alter the state of the incoming request, and delegate the call to the normal handling for '/management' context requests.
      • If the PathRemapper returns null, the response to the client will be a 404.
      • If the request is a POST, the response to the client will be a 405. (For POST requests to '/management' the relevant resource address is encoded in the request entity, not in the URL, so there is no benefit to doing URL munging for POST requests. Munging the request entity is not feasible at this time.)
      • Otherwise there is no special handling for this context. The call is delegated to the '/management' context and all handling normally applied to that context will be applied to the request.
    • Ability for an extension to unregister previously registered custom contexts.
    • Registrations and unregistrations take immediate effect.

     

    Nice-to-Have Requirements

     

    These items are not required but would be nice to have if possible. Before the design phase completes it should be decided a) whether dev intends to meet the requirement, b) whether QE will test the requirement and c) what will happen if the requirement is met but not tested.

     

    None

     

    Non-Requirements

     

    These are items that are explicitly not required.

     

    • Long term support for this integration API. Support will be maintained throughout any EAP minor release in which this appears, and all reasonable efforts will be made to support it throughout EAP 7. If support needs to be dropped during the course of EAP 7, an alternative mechanism that provides largely equivalent functionality will be provided and the JDG team will be notified well in advance of any WildFly Core .CR release where the change is made.

     

    Design Details

     

    See the topic branch for WFCORE-1742

     

    If the HTTP management interface is configured by the user, WildFly Core exposes a capability named org.wildfly.management.http.extensible. This capability provides an MSC Service with a value type of ExtensibleHttpManagement, the API for which is:

     

    public interface ExtensibleHttpManagement extends HttpManagement {
    
       /**
      * Add a context that serves static resources
      * @param contextName the name of the context. Cannot be {@code null} or empty
      * @param resourceManager manager to provide resources for the context. Cannot be {@code null}
      *
      * @throws IllegalArgumentException if either parameter is invalid
      * @throws IllegalStateException if there is already a context present named the same as {@code contextName}, either
      * added via this interface or otherwise
      */
       void addStaticContext(String contextName, ResourceManager resourceManager);
    
       /**
      * Add a context that remaps GET request paths to paths appropriate to the normal {@code /management}
      * context and then dispatches the request to the normal handling for the {@code /management} context.
      * POST requests result in a 405.
      * @param contextName the name of the context. Cannot be {@code null} or empty
      * @param remapper object that converts request paths
      *
      * @throws IllegalArgumentException if either parameter is invalid
      * @throws IllegalStateException if there is already a context present named the same as {@code contextName}, either
      * added via this interface or otherwise
      */
       void addManagementGetRemapContext(String contextName, PathRemapper remapper);
    
       /**
      * Remove a previously added context
      * @param contextName the name of the context. Cannot be {@code null} or empty
      *
      * @throws IllegalArgumentException if {@code contextName} is {@code null} or empty
      * @throws IllegalStateException if no context present named {@code contextName} was added via this interface
      */
       void removeContext(String contextName);
    
       /**
      * Converts a {@link HttpServerExchange#getRelativePath() context relative path} to a
      * path appropriate for use with the {@code /management} context. The context portion of
      * the path is not involved.
      */
       interface PathRemapper {
       /**
      * Converts {@code originalPath} to a path appropriate for use with the {@code /management} context.
      * The context portion of the path is not involved.
      * @param originalPath the original request path, relative to the context
      * @return the remapped path, which should be relative to the target context
      */
       String remapPath(String originalPath);
      }
    }