/* * #%L * ACS AEM Commons Bundle * %% * Copyright (C) 2017 - Adobe * %% * 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. * #L% */ package com.adobe.acs.commons.audit_log_search.impl; import com.adobe.acs.commons.audit_log_search.AuditLogSearchRequest; import org.apache.commons.lang.StringUtils; import org.apache.felix.scr.annotations.sling.SlingServlet; 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.ValueMap; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.commons.json.JSONArray; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; import javax.servlet.ServletException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.text.ParseException; import java.util.Date; import java.util.HashSet; import java.util.Set; @SlingServlet(label = "ACS AEM Commons - Audit Log Search Servlet", methods = { "GET" }, resourceTypes = { "acs-commons/components/utilities/audit-log-search" }, selectors = { "auditlogsearch" }, extensions = { "json" }, metatype = true) public class AuditLogSearchServlet extends SlingSafeMethodsServlet { private static final long serialVersionUID = 7661105540626580845L; private static final Logger log = LoggerFactory.getLogger(AuditLogSearchServlet.class); /* * (non-Javadoc) * * @see * org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache. * sling.api.SlingHttpServletRequest, * org.apache.sling.api.SlingHttpServletResponse) */ @Override protected final void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { log.trace("doGet"); AuditLogSearchRequest req = null; try { JSONObject result = new JSONObject(); boolean succeeded = true; try { req = new AuditLogSearchRequest(request); log.debug("Loaded search request: {}", req); int limit = -1; if (StringUtils.isNotEmpty(request.getParameter("limit"))) { limit = Integer.parseInt(request.getParameter("limit"), 10); log.debug("Limiting to {} results", limit); } JSONArray results = new JSONArray(); long count = 0; String queryStr = "SELECT * FROM [cq:AuditEvent] AS s WHERE " + req.getQueryParameters(); log.debug("Finding audit events with: {}", queryStr); ResourceResolver resolver = request.getResourceResolver(); QueryManager queryManager = resolver.adaptTo(Session.class).getWorkspace().getQueryManager(); Query query = queryManager.createQuery(queryStr, Query.JCR_SQL2); query.setLimit(limit); NodeIterator nodes = query.execute().getNodes(); log.debug("Query execution complete!"); while (nodes.hasNext()) { results.put(serializeAuditEvent(resolver.getResource(nodes.nextNode().getPath()), req)); count++; } result.put("count", count); result.put("events", results); log.debug("Found {} audit events", count); } catch (ParseException e) { log.warn("Encountered exception parsing start / end date", e); succeeded = false; } catch (RepositoryException e) { log.warn("Encountered respository exception attempting to retrieve audit events", e); succeeded = false; } catch (ClassNotFoundException e) { log.warn("Encountered exception deserializing attributes", e); succeeded = false; } result.put("succeeded", succeeded); response.setContentType("application/json"); response.getWriter().write(result.toString()); } catch (JSONException e) { throw new ServletException("Failed to serialize JSON", e); } } private JSONObject serializeAuditEvent(Resource auditEventResource, AuditLogSearchRequest request) throws JSONException, RepositoryException, IOException, ClassNotFoundException { JSONObject auditEvent = new JSONObject(); ValueMap properties = auditEventResource.getValueMap(); auditEvent.put("category", properties.get("cq:category", String.class)); auditEvent.put("eventPath", auditEventResource.getPath()); auditEvent.put("path", properties.get("cq:path", String.class)); auditEvent.put("type", properties.get("cq:type", String.class)); String userId = properties.get("cq:userid", String.class); auditEvent.put("userId", userId); auditEvent.put("userName", request.getUserName(auditEventResource.getResourceResolver(), userId)); auditEvent.put("userPath", request.getUserPath(auditEventResource.getResourceResolver(), userId)); auditEvent.put("time", properties.get("cq:time", new Date()).getTime()); JSONArray modified = getModifiedProperties(properties); if (properties.get("above", String.class) != null) { modified.put("above=" + properties.get("above", String.class)); } if (properties.get("destination", String.class) != null) { modified.put("destination=" + properties.get("destination", String.class)); } if (properties.get("versionId", String.class) != null) { modified.put("versionId=" + properties.get("versionId", String.class)); } if (modified.length() != 0) { auditEvent.put("modified", modified); } return auditEvent; } @SuppressWarnings("unchecked") private JSONArray getModifiedProperties(ValueMap properties) throws IOException { JSONArray modifiedProperties = new JSONArray(); InputStream is = properties.get("cq:properties", InputStream.class); if (is != null) { ObjectInputStream ois = new ObjectInputStream(is); ois.readInt(); while (ois.available() != -1) { try { Object obj = ois.readObject(); if (obj instanceof HashSet) { Set<String> propertiesSet = (Set<String>) obj; for (String property : propertiesSet) { modifiedProperties.put(property); } break; } } catch (Exception e) { break; } } } return modifiedProperties; } }