001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     <a href="mailto:grenard@nuxeo.com">Guillaume Renard</a>
016 *
017 */
018
019package org.nuxeo.ecm.platform.routing.core.audit.es;
020
021import java.util.ArrayList;
022import java.util.List;
023
024import org.json.JSONArray;
025import org.json.JSONException;
026import org.json.JSONObject;
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.NuxeoPrincipal;
029import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
030import org.nuxeo.ecm.platform.routing.api.DocumentRoute;
031import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants;
032import org.nuxeo.ecm.platform.routing.api.DocumentRoutingService;
033import org.nuxeo.elasticsearch.ElasticSearchConstants;
034import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
035import org.nuxeo.elasticsearch.http.readonly.filter.AuditRequestFilter;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * Define a elasticsearch passthrough filter for audit_wf index view. Restrict to 'Routing' event category and, if the
040 * user is not an administrator, to the list of workflow model on which the user has the 'Data Visualization'
041 * permission.
042 *
043 * @since 7.4
044 */
045public class RoutingAuditRequestFilter extends AuditRequestFilter {
046
047    private CoreSession session;
048
049    @Override
050    public void init(CoreSession session, String indices, String types, String rawQuery, String payload) {
051        this.session = session;
052        principal = (NuxeoPrincipal) session.getPrincipal();
053        ElasticSearchAdmin esa = Framework.getService(ElasticSearchAdmin.class);
054        this.indices = esa.getIndexNameForType(ElasticSearchConstants.ENTRY_TYPE);
055        this.types = ElasticSearchConstants.ENTRY_TYPE;
056        this.rawQuery = rawQuery;
057        this.payload = payload;
058        if (payload == null && !principal.isAdministrator()) {
059            // here we turn the UriSearch query_string into a body search
060            extractPayloadFromQuery();
061        }
062    }
063
064    @Override
065    public String getPayload() throws JSONException {
066        if (filteredPayload == null) {
067            if (payload.contains("\\")) {
068                // JSONObject removes backslash so we need to hide them
069                payload = payload.replaceAll("\\\\", BACKSLASH_MARKER);
070            }
071            JSONObject payloadJson = new JSONObject(payload);
072            JSONObject query;
073            if (payloadJson.has("query")) {
074                query = payloadJson.getJSONObject("query");
075
076                payloadJson.remove("query");
077            } else {
078                query = new JSONObject("{\"match_all\":{}}");
079            }
080            JSONObject categoryFilter = new JSONObject().put("term", new JSONObject().put(
081                    DocumentEventContext.CATEGORY_PROPERTY_KEY, DocumentRoutingConstants.ROUTING_CATEGORY));
082
083            JSONArray fs = new JSONArray().put(categoryFilter);
084
085            if (!principal.isAdministrator()) {
086                DocumentRoutingService documentRoutingService = Framework.getService(DocumentRoutingService.class);
087                List<DocumentRoute> wfModels = documentRoutingService.getAvailableDocumentRouteModel(session);
088                List<String> modelNames = new ArrayList<String>();
089                for (DocumentRoute model : wfModels) {
090                    if (session.hasPermission(model.getDocument().getRef(), DocumentRoutingConstants.CAN_DATA_VISU)) {
091                        modelNames.add(model.getModelName());
092                    }
093                }
094
095                JSONObject wfModelFilter = new JSONObject().put("terms",
096                        new JSONObject().put("extended.modelName", modelNames.toArray(new String[modelNames.size()])));
097
098                fs.put(wfModelFilter);
099            }
100
101            JSONObject filter = new JSONObject().put("bool", new JSONObject().put("must", fs));
102
103            JSONObject newQuery = new JSONObject().put("filtered",
104                    new JSONObject().put("query", query).put("filter", filter));
105            payloadJson.put("query", newQuery);
106            filteredPayload = payloadJson.toString();
107            if (filteredPayload.contains(BACKSLASH_MARKER)) {
108                filteredPayload = filteredPayload.replaceAll(BACKSLASH_MARKER, "\\\\");
109            }
110
111        }
112        return filteredPayload;
113    }
114
115}