ImpersonationServlet.java 13.1 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.xss.XSSFilter
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.servlet.ServletException
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.ReferenceCardinality
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.api.security.user.Authorizable
 *  org.apache.jackrabbit.api.security.user.Query
 *  org.apache.jackrabbit.api.security.user.QueryBuilder
 *  org.apache.jackrabbit.api.security.user.User
 *  org.apache.jackrabbit.api.security.user.UserManager
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.request.RequestParameter
 *  org.apache.sling.api.request.RequestParameterMap
 *  org.apache.sling.api.request.RequestPathInfo
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.servlets.HtmlResponse
 *  org.apache.sling.commons.json.JSONException
 *  org.apache.sling.commons.json.io.JSONWriter
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.security.user.internal.servlets;

import com.adobe.granite.security.user.UserPropertiesManager;
import com.adobe.granite.security.user.UserPropertiesService;
import com.adobe.granite.security.user.internal.servlets.AbstractServlet;
import com.adobe.granite.security.user.util.AuthorizableJSONWriter;
import com.adobe.granite.security.user.util.ImpersonationNotifier;
import com.adobe.granite.xss.XSSFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Query;
import org.apache.jackrabbit.api.security.user.QueryBuilder;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.request.RequestParameterMap;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HtmlResponse;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=0)
@Service
@Properties(value={@Property(name="sling.servlet.paths", value={"rep/User/impersonate.json.GET.servlet", "rep/SystemUser/impersonate.json.GET.servlet", "rep/User/impersonators.html.POST.servlet", "rep/SystemUser/impersonators.html.POST.servlet"})})
public class ImpersonationServlet
extends AbstractServlet {
    private static final Logger log = LoggerFactory.getLogger(ImpersonationServlet.class);
    private static final String SELECTOR_IMPERSONATE = "impersonate";
    private static final String SELECTOR_IMPERSONATORS = "impersonators";
    private static final String PARAM_IMPERSONATE = "impersonate";
    private static final String SLING_PARAM_SUDO = "sudo=";
    private static final String SLING_PARAM_REDIRECT = "sling.auth.redirect=";
    @Reference
    private UserPropertiesService service;
    @Reference
    private XSSFilter xss;
    @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY)
    private ImpersonationNotifier notifier;

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        block14 : {
            HtmlResponse errorResponse = null;
            Resource resource = request.getResource();
            ResourceResolver resolver = request.getResourceResolver();
            User user = (User)resource.adaptTo(User.class);
            UserManager umgr = (UserManager)resolver.adaptTo(UserManager.class);
            try {
                if (user == null || umgr == null) {
                    errorResponse = ImpersonationServlet.createErrorResponse(404, "Cannot resolve to user or user manager (" + resource.getPath() + ")");
                    break block14;
                }
                Session session = (Session)resolver.adaptTo(Session.class);
                String selector = request.getRequestPathInfo().getSelectors()[0];
                RequestParameterMap params = request.getRequestParameterMap();
                String userID = user.getID();
                if ("impersonate".equals(selector)) {
                    if (!userID.equals(session.getUserID())) {
                        errorResponse = ImpersonationServlet.createErrorResponse(400, "User does not match editing session. Cannot handle impersonation request.");
                    } else if (!params.containsKey((Object)"impersonate")) {
                        errorResponse = ImpersonationServlet.createErrorResponse(400, "Command missing in request ('impersonate' parameter expected).");
                    } else {
                        String impersonate = params.getValue("impersonate").getString();
                        log.debug("Set parameter to impersonate {} as {}", (Object)userID, (Object)impersonate);
                        this.notifyImpersonation(impersonate, userID);
                        String redirectTo = params.containsKey((Object)"path") ? params.getValue("path").getString() : "/";
                        StringBuilder sb = new StringBuilder();
                        sb.append("?").append("sling.auth.redirect=");
                        sb.append(URLEncoder.encode(redirectTo, "utf-8")).append("&");
                        sb.append("sudo=").append(URLEncoder.encode(impersonate, "utf-8"));
                        ImpersonationServlet.setJsonResponseHeader((HttpServletResponse)response);
                        response.sendRedirect(sb.toString());
                    }
                    break block14;
                }
                errorResponse = ImpersonationServlet.createErrorResponse(400, "Invalid selector " + selector);
            }
            catch (RepositoryException e) {
                errorResponse = ImpersonationServlet.createErrorResponse((Exception)e);
            }
            catch (Exception e) {
                errorResponse = ImpersonationServlet.createErrorResponse(e);
            }
            finally {
                if (errorResponse != null) {
                    errorResponse.send((HttpServletResponse)response, true);
                }
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        block13 : {
            HtmlResponse errorResponse = null;
            Resource resource = request.getResource();
            ResourceResolver resolver = request.getResourceResolver();
            final User user = (User)resource.adaptTo(User.class);
            UserManager umgr = (UserManager)resolver.adaptTo(UserManager.class);
            try {
                if (user == null || umgr == null) {
                    errorResponse = ImpersonationServlet.createErrorResponse(404, "Cannot resolve to user or user manager (" + resource.getPath() + ")");
                    break block13;
                }
                Session session = (Session)resolver.adaptTo(Session.class);
                String selector = request.getRequestPathInfo().getSelectors()[0];
                RequestParameterMap params = request.getRequestParameterMap();
                final String userID = user.getID();
                if ("impersonators".equals(selector)) {
                    final String paramQuery = request.getParameter("query");
                    final long paramOffset = ImpersonationServlet.getNonNegativeValue(params, "offset", 0);
                    final long paramMaxResult = ImpersonationServlet.getNonNegativeValue(params, "max", -1);
                    Query q = new Query(){

                        public void build(QueryBuilder qb) {
                            if (paramQuery == null) {
                                qb.setCondition(user.isAdmin() ? qb.not(qb.nameMatches(userID)) : qb.impersonates(userID));
                            } else {
                                String pattern = paramQuery.replaceAll("'", "''").replaceAll("\\\\", "\\\\\\\\") + "%";
                                String profilePath = "profile/";
                                String givenNamePath = profilePath + "givenName";
                                String familyNamePath = profilePath + "familyName";
                                String displayNamePath = profilePath + "displayName";
                                qb.setCondition(qb.and(user.isAdmin() ? qb.not(qb.nameMatches(userID)) : qb.impersonates(userID), qb.or(qb.nameMatches(pattern), qb.or(qb.like(givenNamePath, pattern), qb.or(qb.like(familyNamePath, pattern), qb.like(displayNamePath, pattern))))));
                            }
                            qb.setSelector(User.class);
                            qb.setLimit(paramOffset, paramMaxResult);
                        }
                    };
                    Iterator resultSet = umgr.findAuthorizables(q);
                    ImpersonationServlet.setJsonResponseHeader((HttpServletResponse)response);
                    JSONWriter writer = new JSONWriter((Writer)response.getWriter());
                    writer.object();
                    writer.key("authorizables");
                    writer.array();
                    UserPropertiesManager mgr = this.service.createUserPropertiesManager(session, resolver);
                    AuthorizableJSONWriter authWriter = new AuthorizableJSONWriter(mgr, resolver, session, ImpersonationServlet.getProps(params), this.xss);
                    long cnt = 0;
                    while (resultSet.hasNext()) {
                        authWriter.write(writer, (Authorizable)resultSet.next());
                        ++cnt;
                    }
                    writer.endArray();
                    writer.key("Total".toLowerCase()).value(cnt);
                    writer.endObject();
                    break block13;
                }
                errorResponse = ImpersonationServlet.createErrorResponse(400, "Invalid selector " + selector);
            }
            catch (RepositoryException e) {
                errorResponse = ImpersonationServlet.createErrorResponse((Exception)e);
            }
            catch (JSONException e) {
                errorResponse = ImpersonationServlet.createErrorResponse((Exception)e);
            }
            catch (Exception e) {
                errorResponse = ImpersonationServlet.createErrorResponse(e);
            }
            finally {
                if (errorResponse != null) {
                    errorResponse.send((HttpServletResponse)response, true);
                }
            }
        }
    }

    private void notifyImpersonation(String impersonate, String userID) {
        if (this.notifier != null) {
            if ("-".equals(impersonate)) {
                this.notifier.notify(new Date(), userID, "revert", Collections.<String, Object>emptyMap());
            } else {
                Map<String, Object> args = Collections.singletonMap("sudo", impersonate);
                this.notifier.notify(new Date(), userID, "sudo", args);
            }
        }
    }

    protected void bindService(UserPropertiesService userPropertiesService) {
        this.service = userPropertiesService;
    }

    protected void unbindService(UserPropertiesService userPropertiesService) {
        if (this.service == userPropertiesService) {
            this.service = null;
        }
    }

    protected void bindXss(XSSFilter xSSFilter) {
        this.xss = xSSFilter;
    }

    protected void unbindXss(XSSFilter xSSFilter) {
        if (this.xss == xSSFilter) {
            this.xss = null;
        }
    }

    protected void bindNotifier(ImpersonationNotifier impersonationNotifier) {
        this.notifier = impersonationNotifier;
    }

    protected void unbindNotifier(ImpersonationNotifier impersonationNotifier) {
        if (this.notifier == impersonationNotifier) {
            this.notifier = null;
        }
    }

}