blob: 4e9f48f401a0ad738288374a629b88a743f16ace [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.sling.jcr.repoinit.impl;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.jcr.Session;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.felix.webconsole.AbstractWebConsolePlugin;
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
import org.apache.sling.repoinit.parser.RepoInitParser;
import org.apache.sling.repoinit.parser.RepoInitParsingException;
import org.apache.sling.repoinit.parser.operations.Operation;
import org.apache.sling.xss.XSSAPI;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Servlet.class, property = {
Constants.SERVICE_DESCRIPTION + "=Apache Sling Service User Manager Web Console Plugin",
WebConsoleConstants.PLUGIN_LABEL + "=" + RepoInitWebConsole.LABEL,
WebConsoleConstants.PLUGIN_TITLE + "=" + RepoInitWebConsole.TITLE,
WebConsoleConstants.PLUGIN_CATEGORY + "=Sling" })
public class RepoInitWebConsole extends AbstractWebConsolePlugin {
private static final Logger log = LoggerFactory.getLogger(RepoInitWebConsole.class);
@Reference(policyOption = ReferencePolicyOption.GREEDY)
private XSSAPI xss;
@Reference
private RepoInitParser parser;
@Reference
private JcrRepoInitOpsProcessor processor;
@Reference(policyOption = ReferencePolicyOption.GREEDY)
private ResourceResolverFactory resolverFactory;
private static final long serialVersionUID = 1L;
public static final String LABEL = "repoinit";
public static final String TITLE = "RepoInit";
private static final String PN_STATEMENTS = "statements";
private static final String PN_EXECUTE = "execute";
@Override
public String getLabel() {
return LABEL;
}
@Override
public String getTitle() {
return TITLE;
}
@Override
protected void renderContent(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Map<String, String> parameters = readRequest(request);
parameters.put("result", "");
writeResponse(response, parameters);
}
private Map<String, String> readRequest(HttpServletRequest request) {
Map<String, String> parameters = new HashMap<>();
String statements = Optional.ofNullable(request.getParameter(PN_STATEMENTS)).orElse("");
parameters.put(PN_STATEMENTS, xss.encodeForHTML(statements));
parameters.put(PN_EXECUTE, "true".equals(request.getParameter(PN_EXECUTE)) ? "checked" : "");
return parameters;
}
private void writeResponse(HttpServletResponse response, Map<String, String> parameters) throws IOException {
String consoleHtml = IOUtils.toString(this.getBundle().getEntry("console.html").openStream(),
StandardCharsets.UTF_8);
StrSubstitutor sub = new StrSubstitutor(parameters);
IOUtils.write(sub.replace(consoleHtml), response.getWriter());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Map<String, String> parameters = readRequest(request);
StringReader statements = Optional.ofNullable(request.getParameter(PN_STATEMENTS)).map(StringReader::new)
.orElse(new StringReader(""));
List<String> messages = new ArrayList<>();
List<Operation> operations = null;
try {
operations = parser.parse(statements);
messages.add("PARSING SUCCEEDED: ");
operations.stream().map(Operation::toString).forEach(messages::add);
} catch (RepoInitParsingException e) {
messages.add("PARSING FAILED: ");
messages.add(e.toString());
}
if (operations != null && "true".equals(request.getParameter(PN_EXECUTE))) {
messages.add("");
Session session;
try {
session = getResourceResolver(request).adaptTo(Session.class);
processor.apply(session, operations);
session.save();
messages.add("EXECUTION SUCCEEDED!");
} catch (Exception e) {
messages.add("EXECUTION FAILED: ");
messages.add(e.toString());
}
}
parameters.put("result", messages.stream().collect(Collectors.joining("\n")));
PrintWriter pw = startResponse(request, response);
renderTopNavigation(request, pw);
pw.println("<div id='content'>");
writeResponse(response, parameters);
pw.println("</div>");
endResponse(pw);
}
private boolean needsAdministrativeResolver(HttpServletRequest request) {
Object resolver = request.getAttribute("org.apache.sling.auth.core.ResourceResolver");
return !(resolver instanceof ResourceResolver);
}
@SuppressWarnings("deprecation")
private ResourceResolver getResourceResolver(HttpServletRequest request) throws LoginException {
ResourceResolver resolver = null;
if (needsAdministrativeResolver(request)) {
try {
log.warn("Resource resolver not available in request, falling back to adminstrative resource resolver");
resolver = resolverFactory.getAdministrativeResourceResolver(null);
} catch (LoginException le) {
throw new LoginException(
"Unable to get Administrative Resource Resolver, add the bundle org.apache.sling.jcr.repoinit.parser.webconsole in the Apache Sling Login Admin Whitelist",
le);
}
} else {
resolver = (ResourceResolver) request.getAttribute("org.apache.sling.auth.core.ResourceResolver");
}
return resolver;
}
}