001/*
002 * (C) Copyright 2015-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Benoit Delbosc
018 */
019package org.nuxeo.elasticsearch.http.readonly.filter;
020
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Map;
026import java.util.Set;
027
028import javax.validation.constraints.NotNull;
029
030import org.apache.commons.lang3.StringUtils;
031import org.json.JSONArray;
032import org.json.JSONException;
033import org.json.JSONObject;
034import org.nuxeo.ecm.core.api.NuxeoPrincipal;
035import org.nuxeo.ecm.core.security.SecurityService;
036import org.nuxeo.elasticsearch.ElasticSearchConstants;
037import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
038import org.nuxeo.runtime.api.Framework;
039
040/**
041 * Validate request inputs.
042 *
043 * @since 7.3
044 */
045public class RequestValidator {
046    final private Map<String, List<String>> indexTypes;
047
048    public RequestValidator() {
049        ElasticSearchAdmin esa = Framework.getService(ElasticSearchAdmin.class);
050        indexTypes = new HashMap<>();
051        for (String name : esa.getRepositoryNames()) {
052            List<String> types = new ArrayList<>();
053            types.add(ElasticSearchConstants.DOC_TYPE);
054            indexTypes.put(esa.getIndexNameForRepository(name), types);
055        }
056    }
057
058    public void checkValidDocumentId(String documentId) {
059        if (documentId == null) {
060            throw new IllegalArgumentException("Invalid document id");
061        }
062    }
063
064
065    /**
066     * @deprecated since 11.4, types have been removed since Elasticsearch 7.x
067     */
068    @Deprecated(since = "11.4", forRemoval = true)
069    public @NotNull String getTypes(String indices, String types) {
070        Set<String> validTypes = new HashSet<>();
071        for (String index : indices.split(",")) {
072            validTypes.addAll(indexTypes.get(index));
073        }
074        if (types == null || "*".equals(types) || "_all".equals(types)) {
075            return StringUtils.join(validTypes, ',');
076        }
077        for (String type : types.split(",")) {
078            if (!validTypes.contains(type)) {
079                throw new IllegalArgumentException("Invalid index type: " + type);
080            }
081        }
082        return types;
083    }
084
085    public @NotNull String getIndices(String indices) {
086        if (indices == null || "*".equals(indices) || "_all".equals(indices)) {
087            return StringUtils.join(indexTypes.keySet(), ',');
088        }
089
090        for (String index : indices.split(",")) {
091            if (!indexTypes.containsKey(index)) {
092                throw new IllegalArgumentException("Invalid index submitted: " + index);
093            }
094        }
095        return indices;
096    }
097
098    public void checkAccess(NuxeoPrincipal principal, String docAcl) {
099        try {
100            JSONObject docAclJson = new JSONObject(docAcl);
101            JSONArray acl = docAclJson.getJSONObject("fields").getJSONArray("ecm:acl");
102            String[] principals = SecurityService.getPrincipalsToCheck(principal);
103            for (int i = 0; i < acl.length(); i++)
104                for (String name : principals) {
105                    if (name.equals(acl.getString(i))) {
106                        return;
107                    }
108                }
109        } catch (JSONException e) {
110            // throw a securityException
111        }
112        throw new SecurityException("Unauthorized access");
113    }
114}