All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.wcm.foundation.forms.FormsHandlingServletHelper Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~ Copyright 2016 Adobe Systems Incorporated
 ~
 ~ Licensed under the Apache License, Version 2.0 (the "License");
 ~ you may not use this file except in compliance with the License.
 ~ You may obtain a copy of the License at
 ~
 ~     http://www.apache.org/licenses/LICENSE-2.0
 ~
 ~ Unless required by applicable law or agreed to in writing, software
 ~ distributed under the License is distributed on an "AS IS" BASIS,
 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ~ See the License for the specific language governing permissions and
 ~ limitations under the License.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.day.cq.wcm.foundation.forms;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ResourceWrapper;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.wcm.foundation.security.SaferSlingPostValidator;

/**
 * A helper for form handling.
 *
 * Note: this helper class needs to be publicly available as it is being used in the Core Component code base
 * (in com.adobe.cq.wcm.core.components.internal.servlets.CoreFormHandlingServlet)
 */
public class FormsHandlingServletHelper {

    protected final Logger logger = LoggerFactory.getLogger(getClass());
    protected static final String ATTR_RESOURCE = FormsHandlingServletHelper.class.getName() + "/resource";

    private String[] parameterNameWhitelist;
    private boolean allowExpressions;
    private SaferSlingPostValidator validator;
    private Set formResourceTypes;
    private FormStructureHelperFactory formStructureHelperFactory;

    /**
     * A helper class for handling form POSTS.
     * @param parameterNameWhitelist Parameter names that will pass request validation. A validation error will occur if
     *                               any posted parameters are not in the whitelist and not defined on the form.
     * @param validator {@link SaferSlingPostValidator}
     * @param formResourceTypes sling resource types of forms which this class can handle
     * @param allowExpressions True to evaluate expressions on form submissions.
     *                         For details see {@link FormsHelper#allowExpressions(SlingHttpServletRequest)}
     * @param formStructureHelperFactory Form structure helper
     */
    public FormsHandlingServletHelper(final String[] parameterNameWhitelist, final SaferSlingPostValidator validator,
                                      final Set formResourceTypes, final boolean allowExpressions,
                                      final FormStructureHelperFactory formStructureHelperFactory) {
        this.parameterNameWhitelist = parameterNameWhitelist;
        this.validator = validator;
        this.formResourceTypes = formResourceTypes;
        this.allowExpressions = allowExpressions;
        this.formStructureHelperFactory = formStructureHelperFactory;
    }

    /**
     * Helper method which validates the submitted form and then forwards request to appropriate action handler.
     * @param request {@link SlingHttpServletRequest}
     * @param response {@link SlingHttpServletResponse}
     * @throws IOException if post caused an error
     * @throws ServletException if post caused an error
     */
    public void doPost(SlingHttpServletRequest request, final SlingHttpServletResponse response)
            throws IOException, ServletException {
        if (validator.reject(request, parameterNameWhitelist)) {
            response.sendError(400);
            return;
        }

        if (ResourceUtil.isNonExistingResource(request.getResource())
                || request.getAttribute(ATTR_RESOURCE) == null) {
            logger.debug("Received fake request!");
            response.setStatus(500);
            return;
        }

        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Validating POST request with form definition stored at {}.", request.getResource().getPath());
        }

        SlingHttpServletRequest formsRequest = new FormsHandlingRequest(request);
        SlingHttpServletResponse formsResponse = new FormsHandlingResponse(response);

        request.setAttribute(FormsHelper.REQ_ATTR_EXPRESSIONS_ENABLED, allowExpressions);

        // validate form
        final Resource formResource = request.getResource();
        // initialize request attributes
        FormsHelper.getFormId(request);

        ValidationInfo info;
        validate(formsRequest, formsResponse, formResource);
        final ValueMap properties = ResourceUtil.getValueMap(formResource);
        // check action type
        final String actionType = (properties == null ? "" : properties.get(FormsConstants.START_PROPERTY_ACTION_TYPE, ""));
        if (actionType.length() == 0) {
            info = ValidationInfo.createValidationInfo(request);
            info.addErrorMessage(null, "Unable to process the form: missing " + FormsConstants.START_PROPERTY_ACTION_TYPE);
        } else {
            // run any validations defined by the action type
            // these validations are a good place to protect against malicious content
            request.setAttribute(FormsHelper.REQ_ATTR_PROP_WHITELIST, parameterNameWhitelist);
            FormsHelper.runAction(actionType, FormsConstants.SCRIPT_FORM_SERVER_VALIDATION, formResource, formsRequest,
                    formsResponse);
            info = ValidationInfo.getValidationInfo(request);
        }

        if (info != null) {
            this.logger.debug("Form {} is not valid: {}", formResource.getPath(), info);
            // get real resource from request attribute
            final Resource rsrc = (Resource) request.getAttribute(ATTR_RESOURCE);
            request.removeAttribute(ATTR_RESOURCE);

            request.getRequestDispatcher(rsrc).forward(formsRequest, response);
            return;
        }

        // create forward path by invoking action script
        FormsHelper.runAction(actionType, "forward", formResource, formsRequest, formsResponse);

        String forwardPath = FormsHelper.getForwardPath(request);
        if (forwardPath != null && forwardPath.length() > 0) {
            // check for redirect flag
            if (FormsHelper.isRedirectToReferrer(request)) {
                if (request.getParameter(FormsConstants.REQUEST_PROPERTY_REDIRECT) == null) {
                    String referrerPath = getReferrerPath(request);
                    request = new RedirectRequest(request, referrerPath);
                }
            }
            String redirect = FormsHelper.getForwardRedirect(request);
            if (redirect != null) {
                request = new RedirectRequest(request, redirect);
            }
            if (forwardPath.endsWith("/")) {
                forwardPath = forwardPath + '*';
            }
            // now forward
            final Resource forwardResource = request.getResourceResolver().resolve(forwardPath);
            request.getRequestDispatcher(forwardResource, FormsHelper.getForwardOptions(request)).forward(request, response);
            //cleanup
            FormsHelper.runAction(actionType, "cleanup", formResource, formsRequest, formsResponse);
            return;
        }

        // if no forward path is set, we "forward" to the post script
        FormsHelper.runAction(actionType, "post", formResource, request, response);
    }

    private boolean checkFormResourceType(Resource resource, ResourceResolver resolver) {
        boolean isForm = false;
        for (String resourceType : formResourceTypes) {
            if (resolver.isResourceType(resource, resourceType)) {
                isForm = true;
                break;
            }
        }
        return isForm;
    }

    /**
     * Checks if resource in request if form type. If yes, then adds passed selector and extension to the request.
     * @param request {@link ServletRequest}
     * @param response {@link ServletResponse}
     * @param chain {@link FilterChain}
     * @param extensionToAdd extension to be added to request eg. "html"
     * @param selectorToAdd selector to be added to request.
     * @throws IOException {@link IOException}
     * @throws ServletException {@link ServletException}
     */
    public void handleFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain,
                         final String extensionToAdd, final String selectorToAdd)
            throws IOException, ServletException {
        // check if this is a post to a form
        if (request instanceof SlingHttpServletRequest) {
            final SlingHttpServletRequest req = (SlingHttpServletRequest) request;
            if ("POST".equalsIgnoreCase(req.getMethod())
                    && req.getParameter(FormsConstants.REQUEST_PROPERTY_FORM_START) != null) {
                final ResourceResolver resolver = req.getResourceResolver();
                final String formPath = req.getParameter(FormsConstants.REQUEST_PROPERTY_FORM_START);
                final Resource formResource = ((SlingHttpServletRequest) request).getResourceResolver().getResource(formPath);
                //CQ-3620: only forward request if formPath exists AND is a form/start resource
                if (formResource != null && checkFormResourceType(formResource, resolver)) {
                    // store original resource as request attribute
                    req.setAttribute(ATTR_RESOURCE, req.getResource());
                    req.setAttribute(FormsHelper.REQ_ATTR_FORM_STRUCTURE_HELPER,
                            formStructureHelperFactory.getFormStructureHelper(formResource));
                    final StringBuilder sb = new StringBuilder();
                    if (!formPath.startsWith("/")) {
                        sb.append(req.getResource().getPath());
                        sb.append('/');
                    }

                    sb.append(formPath);
                    sb.append('.');
                    sb.append(selectorToAdd);
                    sb.append('.');
                    sb.append(extensionToAdd);
                    // forward to forms handling servlet
                    final String forwardPath = sb.toString();
                    req.getRequestDispatcher(forwardPath).forward(request, response);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }

    private String getReferrerPath(SlingHttpServletRequest request) {
        String referrerPath = null;
        String referrer = FormsHelper.getReferrer(request);
        try {
            if (referrer != null) {
                URI referrerUri = new URI(referrer);
                referrerPath = referrerUri.getPath();
            }
        } catch (URISyntaxException e) {
            logger.warn("given redirect target ({}) is not a valid uri: {}", referrer, e);
            return null;
        }
        return referrerPath;
    }

    private ValidationInfo validate(final SlingHttpServletRequest request,
                                    final SlingHttpServletResponse response,
                                    final Resource formResource)
            throws ServletException, IOException {
        FormStructureHelper formStructureHelper = formStructureHelperFactory.getFormStructureHelper(formResource);
        // we have to validate all elements
        final Iterable formElements = formStructureHelper.getFormElements(formResource);
        for (Resource formField : formElements) {
            FieldHelper.initializeField(request, response, formField);
            FormsHelper.includeResource(request, response, formField, FormsConstants.SCRIPT_SERVER_VALIDATION);
        }

        // in addition we check for a global validation RT
        // configured at the form resource
        final ValueMap properties = ResourceUtil.getValueMap(formResource);
        final String valScriptRT = properties.get(FormsConstants.START_PROPERTY_VALIDATION_RT, formResource.getResourceType());
        if (valScriptRT != null && valScriptRT.length() > 0) {
            Resource valScriptResource = formResource;
            if (!formResource.getResourceType().equals(valScriptRT)) {
                valScriptResource = new ResourceWrapper(formResource) {
                    @Override
                    public String getResourceType() {
                        return valScriptRT;
                    }

                    @Override
                    public String getResourceSuperType() {
                        return formResource.getResourceType();
                    }

                };
            }
            FormsHelper.includeResource(request, response, valScriptResource, FormsConstants.SCRIPT_FORM_SERVER_VALIDATION);
        }

        return ValidationInfo.getValidationInfo(request);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy