|  | 
|  | 1 | +/* | 
|  | 2 | + * SPDX-License-Identifier: Apache-2.0 | 
|  | 3 | + * | 
|  | 4 | + * The OpenSearch Contributors require contributions made to | 
|  | 5 | + * this file be licensed under the Apache-2.0 license or a | 
|  | 6 | + * compatible open source license. | 
|  | 7 | + * | 
|  | 8 | + * Modifications Copyright OpenSearch Contributors. See | 
|  | 9 | + * GitHub history for details. | 
|  | 10 | + */ | 
|  | 11 | +package org.opensearch.security.privileges; | 
|  | 12 | + | 
|  | 13 | +import java.util.ArrayList; | 
|  | 14 | +import java.util.Arrays; | 
|  | 15 | +import java.util.HashSet; | 
|  | 16 | +import java.util.List; | 
|  | 17 | +import java.util.Map; | 
|  | 18 | +import java.util.Set; | 
|  | 19 | +import java.util.concurrent.TimeUnit; | 
|  | 20 | + | 
|  | 21 | +import org.opensearch.action.ActionRequest; | 
|  | 22 | +import org.opensearch.action.admin.indices.segments.PitSegmentsRequest; | 
|  | 23 | +import org.opensearch.action.search.CreatePitRequest; | 
|  | 24 | +import org.opensearch.action.search.DeletePitRequest; | 
|  | 25 | +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; | 
|  | 26 | +import org.opensearch.cluster.service.ClusterService; | 
|  | 27 | +import org.opensearch.common.unit.TimeValue; | 
|  | 28 | +import org.opensearch.security.OpenSearchSecurityPlugin; | 
|  | 29 | +import org.opensearch.security.resolver.IndexResolverReplacer; | 
|  | 30 | +import org.opensearch.security.securityconf.SecurityRoles; | 
|  | 31 | +import org.opensearch.security.user.User; | 
|  | 32 | + | 
|  | 33 | + | 
|  | 34 | +/** | 
|  | 35 | + * This class evaluates privileges for point in time (Delete and List all) operations. | 
|  | 36 | + * For aliases - users must have either alias permission or backing index permissions | 
|  | 37 | + * For data streams - users must have access to backing indices permission + data streams permission. | 
|  | 38 | + */ | 
|  | 39 | +public class PitPrivilegesEvaluator { | 
|  | 40 | + | 
|  | 41 | +    public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final ClusterService clusterService, | 
|  | 42 | +                                                final User user, final SecurityRoles securityRoles, final String action, | 
|  | 43 | +                                                final IndexNameExpressionResolver resolver, | 
|  | 44 | +                                                final PrivilegesEvaluatorResponse presponse, | 
|  | 45 | +                                                final IndexResolverReplacer irr) { | 
|  | 46 | + | 
|  | 47 | +        if(!(request instanceof DeletePitRequest || request instanceof PitSegmentsRequest)) { | 
|  | 48 | +            return presponse; | 
|  | 49 | +        } | 
|  | 50 | +        List<String> pitIds = new ArrayList<>(); | 
|  | 51 | + | 
|  | 52 | +        if (request instanceof DeletePitRequest) { | 
|  | 53 | +            DeletePitRequest deletePitRequest = (DeletePitRequest) request; | 
|  | 54 | +            pitIds = deletePitRequest.getPitIds(); | 
|  | 55 | +        } else if(request instanceof PitSegmentsRequest) { | 
|  | 56 | +            PitSegmentsRequest pitSegmentsRequest = (PitSegmentsRequest) request; | 
|  | 57 | +            pitIds = pitSegmentsRequest.getPitIds(); | 
|  | 58 | +        } | 
|  | 59 | +        // if request is for all PIT IDs, skip custom pit ids evaluation | 
|  | 60 | +        if (pitIds.size() == 1 && "_all".equals(pitIds.get(0))) { | 
|  | 61 | +            return presponse; | 
|  | 62 | +        } else { | 
|  | 63 | +            return handlePitsAccess(pitIds, clusterService, user, securityRoles, | 
|  | 64 | +                    action, resolver, presponse, irr); | 
|  | 65 | +        } | 
|  | 66 | +    } | 
|  | 67 | + | 
|  | 68 | +    /** | 
|  | 69 | +     * Handle access for delete operation / pit segments operation where PIT IDs are explicitly passed | 
|  | 70 | +     */ | 
|  | 71 | +    private PrivilegesEvaluatorResponse handlePitsAccess(List<String> pitIds, ClusterService clusterService, | 
|  | 72 | +                                                         User user, SecurityRoles securityRoles, final String action, | 
|  | 73 | +                                                         IndexNameExpressionResolver resolver, PrivilegesEvaluatorResponse presponse, | 
|  | 74 | +                                                         final IndexResolverReplacer irr) { | 
|  | 75 | +        Map<String, String[]> pitToIndicesMap = OpenSearchSecurityPlugin. | 
|  | 76 | +                GuiceHolder.getPitService().getIndicesForPits(pitIds); | 
|  | 77 | +        Set<String> pitIndices = new HashSet<>(); | 
|  | 78 | +        // add indices across all PITs to a set and evaluate if user has access to all indices | 
|  | 79 | +        for(String[] indices: pitToIndicesMap.values()) { | 
|  | 80 | +            pitIndices.addAll(Arrays.asList(indices)); | 
|  | 81 | +        } | 
|  | 82 | +        Set<String> allPermittedIndices = getPermittedIndices(pitIndices, clusterService, user, | 
|  | 83 | +                securityRoles, action, resolver, irr); | 
|  | 84 | +        // Only if user has access to all PIT's indices, allow operation, otherwise continue evaluation in PrivilegesEvaluator. | 
|  | 85 | +        if(allPermittedIndices.containsAll(pitIndices)) { | 
|  | 86 | +            presponse.allowed = true; | 
|  | 87 | +            presponse.markComplete(); | 
|  | 88 | +        } | 
|  | 89 | +        return presponse; | 
|  | 90 | +    } | 
|  | 91 | + | 
|  | 92 | +    /** | 
|  | 93 | +     * This method returns list of permitted indices for the PIT indices passed | 
|  | 94 | +     */ | 
|  | 95 | +    private Set<String> getPermittedIndices(Set<String> pitIndices, ClusterService clusterService, | 
|  | 96 | +                                            User user, SecurityRoles securityRoles, final String action, | 
|  | 97 | +                                            IndexNameExpressionResolver resolver, final IndexResolverReplacer irr) { | 
|  | 98 | +        String[] indicesArr = new String[pitIndices.size()]; | 
|  | 99 | +        CreatePitRequest req = new CreatePitRequest(new TimeValue(1, TimeUnit.DAYS), true, | 
|  | 100 | +                pitIndices.toArray(indicesArr)); | 
|  | 101 | +        final IndexResolverReplacer.Resolved pitResolved = irr.resolveRequest(req); | 
|  | 102 | +        return securityRoles.reduce(pitResolved, | 
|  | 103 | +                user, new String[]{action}, resolver, clusterService); | 
|  | 104 | +    } | 
|  | 105 | +} | 
0 commit comments