Skip to content

Commit

Permalink
Fls dls field masking tests (#2258)
Browse files Browse the repository at this point in the history
Adds integration tests for FLS DLS field masking

Signed-off-by: Kacper Trochimiak <kacper.trochimiak@eliatra.com>
  • Loading branch information
kt-eliatra authored Dec 15, 2022
1 parent cc45b04 commit 5116d99
Show file tree
Hide file tree
Showing 24 changed files with 1,584 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,14 @@ public CrossClusterSearchTests(Boolean ccsMinimizeRoundtrips) {
@BeforeClass
public static void createTestData() {
try(Client client = remoteCluster.getInternalNodeClient()){
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0]).get();
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_6R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[5]).get();
client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_3R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1]).get();
client.prepareIndex(LIMITED_USER_INDEX_NAME).setId(SONG_ID_5R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[4]).get();
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get();
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_6R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[5].asMap()).get();
client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_3R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1].asMap()).get();
client.prepareIndex(LIMITED_USER_INDEX_NAME).setId(SONG_ID_5R).setRefreshPolicy(IMMEDIATE).setSource(SONGS[4].asMap()).get();
}
try(Client client = cluster.getInternalNodeClient()){
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_2L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2]).get();
client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_4L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[3]).get();
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_2L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2].asMap()).get();
client.prepareIndex(PROHIBITED_SONG_INDEX_NAME).setId(SONG_ID_4L).setRefreshPolicy(IMMEDIATE).setSource(SONGS[3].asMap()).get();
}
try(TestRestClient client = cluster.getRestClient(ADMIN_USER)) {
client.assignRoleToUser(LIMITED_USER.getName(), LIMITED_ROLE.getName()).assertStatusCode(200);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ public class DoNotFailOnForbiddenTests {
@BeforeClass
public static void createTestData() {
try(Client client = cluster.getInternalNodeClient()) {
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_1).source(SONGS[0])).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_2).source(SONGS[1])).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_3).source(SONGS[2])).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_1).source(SONGS[0].asMap())).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_2).source(SONGS[1].asMap())).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(MARVELOUS_SONGS).id(ID_3).source(SONGS[2].asMap())).actionGet();

client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(HORRIBLE_SONGS).id(ID_4).source(SONGS[3])).actionGet();
client.index(new IndexRequest().setRefreshPolicy(IMMEDIATE).index(HORRIBLE_SONGS).id(ID_4).source(SONGS[3].asMap())).actionGet();

client.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(new IndicesAliasesRequest.AliasActions(ADD).indices(
MARVELOUS_SONGS, HORRIBLE_SONGS).alias(BOTH_INDEX_ALIAS))).actionGet();
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

35 changes: 27 additions & 8 deletions src/integrationTest/java/org/opensearch/security/Song.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,19 @@ public class Song {
public static final String QUERY_TITLE_POISON = FIELD_TITLE + ":" + TITLE_POISON;
public static final String QUERY_TITLE_MAGNUM_OPUS = FIELD_TITLE + ":" + TITLE_MAGNUM_OPUS;

public static final Map[] SONGS = {
new Song(ARTIST_FIRST, TITLE_MAGNUM_OPUS ,LYRICS_1, 1, GENRE_ROCK).asMap(),
new Song(ARTIST_STRING, TITLE_SONG_1_PLUS_1, LYRICS_2, 2, GENRE_BLUES).asMap(),
new Song(ARTIST_TWINS, TITLE_NEXT_SONG, LYRICS_3, 3, GENRE_JAZZ).asMap(),
new Song(ARTIST_NO, TITLE_POISON, LYRICS_4, 4, GENRE_ROCK).asMap(),
new Song(ARTIST_YES, TITLE_AFFIRMATIVE,LYRICS_5, 5, GENRE_BLUES).asMap(),
new Song(ARTIST_UNKNOWN, TITLE_CONFIDENTIAL, LYRICS_6, 6, GENRE_JAZZ).asMap()
public static final Song[] SONGS = {
new Song(ARTIST_FIRST, TITLE_MAGNUM_OPUS ,LYRICS_1, 1, GENRE_ROCK),
new Song(ARTIST_STRING, TITLE_SONG_1_PLUS_1, LYRICS_2, 2, GENRE_BLUES),
new Song(ARTIST_TWINS, TITLE_NEXT_SONG, LYRICS_3, 3, GENRE_JAZZ),
new Song(ARTIST_NO, TITLE_POISON, LYRICS_4, 4, GENRE_ROCK),
new Song(ARTIST_YES, TITLE_AFFIRMATIVE,LYRICS_5, 5, GENRE_BLUES),
new Song(ARTIST_UNKNOWN, TITLE_CONFIDENTIAL, LYRICS_6, 6, GENRE_JAZZ)
};

private final String artist;
private final String title;
private final String lyrics;
private final Integer stars;

private final String genre;

public Song(String artist, String title, String lyrics, Integer stars, String genre) {
Expand All @@ -74,6 +73,26 @@ public Song(String artist, String title, String lyrics, Integer stars, String ge
this.genre = Objects.requireNonNull(genre, "Genre field is required");
}

public String getArtist() {
return artist;
}

public String getTitle() {
return title;
}

public String getLyrics() {
return lyrics;
}

public Integer getStars() {
return stars;
}

public String getGenre() {
return genre;
}

public Map<String, Object> asMap() {
return Map.of(FIELD_ARTIST, artist,
FIELD_TITLE, title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ protected LocalCluster getCluster() {
@BeforeClass
public static void createTestData() {
try(Client client = cluster.getInternalNodeClient()){
client.prepareIndex(PERSONAL_INDEX_NAME_SPOCK).setId(ID_ONE_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0]).get();
client.prepareIndex(PERSONAL_INDEX_NAME_KIRK).setId(ID_TWO_2).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1]).get();
client.prepareIndex(PERSONAL_INDEX_NAME_SPOCK).setId(ID_ONE_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get();
client.prepareIndex(PERSONAL_INDEX_NAME_KIRK).setId(ID_TWO_2).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1].asMap()).get();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public class JwtAuthenticationTests {
@BeforeClass
public static void createTestData() {
try (Client client = cluster.getInternalNodeClient()) {
client.prepareIndex(QA_SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0]).get();
client.prepareIndex(QA_SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get();
}
try(TestRestClient client = cluster.getRestClient(ADMIN_USER)){
client.createRoleMapping(ROLE_VP, DEPARTMENT_SONG_LISTENER_ROLE.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ public class LdapTlsAuthenticationTest {
@BeforeClass
public static void createTestData() {
try(Client client = cluster.getInternalNodeClient()){
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0]).get();
client.prepareIndex(PERSONAL_INDEX_NAME_SPOCK).setId(SONG_ID_2).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1]).get();
client.prepareIndex(PERSONAL_INDEX_NAME_KIRK).setId(SONG_ID_3).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2]).get();
client.prepareIndex(SONG_INDEX_NAME).setId(SONG_ID_1).setRefreshPolicy(IMMEDIATE).setSource(SONGS[0].asMap()).get();
client.prepareIndex(PERSONAL_INDEX_NAME_SPOCK).setId(SONG_ID_2).setRefreshPolicy(IMMEDIATE).setSource(SONGS[1].asMap()).get();
client.prepareIndex(PERSONAL_INDEX_NAME_KIRK).setId(SONG_ID_3).setRefreshPolicy(IMMEDIATE).setSource(SONGS[2].asMap()).get();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ public final class SearchRequestFactory {
private SearchRequestFactory() {

}

public static SearchRequest queryByIdsRequest(String indexName, String... ids) {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.idsQuery().addIds(ids));
searchRequest.source(searchSourceBuilder);
return searchRequest;
}

public static SearchRequest queryStringQueryRequest(String indexName, String queryString) {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ public HttpResponse assignRoleToUser(String username, String roleName) {
return patch("_plugins/_security/api/internalusers/" + username, body);
}

public HttpResponse createRole(String roleName, ToXContentObject role) {
Objects.requireNonNull(roleName, "Role name is required");
Objects.requireNonNull(role, "Role is required");
return putJson("_plugins/_security/api/roles/" + roleName, role);
}

public HttpResponse createUser(String userName, ToXContentObject user) {
Objects.requireNonNull(userName, "User name is required");
Objects.requireNonNull(user, "User is required");
return putJson("_plugins/_security/api/internalusers/" + userName, user);
}

public HttpResponse executeRequest(HttpUriRequest uriRequest, Header... requestSpecificHeaders) {
try(CloseableHttpClient httpClient = getHTTPClient()) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.test.framework.matcher;

import java.util.Set;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import org.opensearch.action.fieldcaps.FieldCapabilitiesResponse;

import static java.util.Objects.isNull;

class ContainsExactlyIndicesMatcher extends TypeSafeDiagnosingMatcher<FieldCapabilitiesResponse> {

private final Set<String> expectedIndices;

ContainsExactlyIndicesMatcher(String... expectedIndices) {
if (isNull(expectedIndices) || expectedIndices.length == 0) {
throw new IllegalArgumentException("expectedIndices cannot be null or empty");
}
this.expectedIndices = Set.of(expectedIndices);
}

@Override
protected boolean matchesSafely(FieldCapabilitiesResponse response, Description mismatchDescription) {
Set<String> actualIndices = Set.of(response.getIndices());
if (!expectedIndices.equals(actualIndices)) {
mismatchDescription.appendText("Actual indices: ").appendValue(actualIndices);
return false;
}
return true;
}

@Override
public void describeTo(Description description) {
description.appendText("Response contains indices: ").appendValue(expectedIndices);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.test.framework.matcher;

import java.util.Map;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import org.opensearch.action.fieldcaps.FieldCapabilities;
import org.opensearch.action.fieldcaps.FieldCapabilitiesResponse;

import static java.util.Objects.requireNonNull;

class ContainsFieldWithTypeMatcher extends TypeSafeDiagnosingMatcher<FieldCapabilitiesResponse> {

private final String expectedFieldName;
private final String expectedFieldType;

ContainsFieldWithTypeMatcher(String expectedFieldName, String expectedFieldType) {
this.expectedFieldName = requireNonNull(expectedFieldName, "Field name is required");;
this.expectedFieldType = requireNonNull(expectedFieldType, "Field type is required");;
}

@Override
protected boolean matchesSafely(FieldCapabilitiesResponse response, Description mismatchDescription) {
Map<String, Map<String, FieldCapabilities>> fieldCapabilitiesMap = response.get();
if (!fieldCapabilitiesMap.containsKey(expectedFieldName)) {
mismatchDescription.appendText("Response does not contain field with name ").appendText(expectedFieldName);
return false;
}
if (!fieldCapabilitiesMap.get(expectedFieldName).containsKey(expectedFieldType)) {
mismatchDescription.appendText("Field type does not match ").appendText(expectedFieldType);
return false;
}
return true;
}

@Override
public void describeTo(Description description) {
description.appendText("Response contains field with name ").appendValue(expectedFieldName)
.appendText(" and type ").appendValue(expectedFieldType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.test.framework.matcher;

import org.hamcrest.Matcher;

import org.opensearch.action.fieldcaps.FieldCapabilitiesResponse;

public class FieldCapabilitiesResponseMatchers {

private FieldCapabilitiesResponseMatchers() {}

public static Matcher<FieldCapabilitiesResponse> containsExactlyIndices(String... expectedIndices) {
return new ContainsExactlyIndicesMatcher(expectedIndices);
}

public static Matcher<FieldCapabilitiesResponse> containsFieldWithNameAndType(String expectedFieldName, String expectedFieldType) {
return new ContainsFieldWithTypeMatcher(expectedFieldName, expectedFieldType);
}

public static Matcher<FieldCapabilitiesResponse> numberOfFieldsIsEqualTo(int expectedNumberOfFields) {
return new NumberOfFieldsIsEqualToMatcher(expectedNumberOfFields);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

import static java.util.Objects.requireNonNull;

class GetResponseDocumentIdMatcher extends TypeSafeDiagnosingMatcher<GetResponse> {
class GetResponseContainsDocumentWithIdMatcher extends TypeSafeDiagnosingMatcher<GetResponse> {

private final String indexName;
private final String documentId;

public GetResponseDocumentIdMatcher(String indexName, String documentId) {
public GetResponseContainsDocumentWithIdMatcher(String indexName, String documentId) {
this.indexName = requireNonNull(indexName, "Index name is required");
this.documentId = requireNonNull(documentId, "Document id is required");
}
Expand All @@ -40,6 +40,10 @@ protected boolean matchesSafely(GetResponse response, Description mismatchDescri
mismatchDescription.appendText("Document does not exist or is inaccessible");
return false;
}
if(response.isSourceEmpty()) {
mismatchDescription.appendText("Document source is empty");
return false;
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.test.framework.matcher;

import java.util.Map;
import java.util.Set;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import org.opensearch.action.get.GetResponse;

import static java.util.Objects.isNull;

class GetResponseDocumentContainsExactlyFieldsWithNamesMatcher extends TypeSafeDiagnosingMatcher<GetResponse> {

private final Set<String> expectedFieldsNames;

GetResponseDocumentContainsExactlyFieldsWithNamesMatcher(String... expectedFieldsNames) {
if (isNull(expectedFieldsNames) || expectedFieldsNames.length == 0) {
throw new IllegalArgumentException("expectedFieldsNames cannot be null or empty");
}
this.expectedFieldsNames = Set.of(expectedFieldsNames);
}

@Override
protected boolean matchesSafely(GetResponse response, Description mismatchDescription) {
Map<String, Object> sourceMap = response.getSourceAsMap();
Set<String> actualFieldsNames = sourceMap.keySet();
if (!expectedFieldsNames.equals(actualFieldsNames)) {
mismatchDescription.appendValue("Document with id ").appendValue(response.getId())
.appendText(" contains fields with names: ").appendValue(actualFieldsNames);
return false;
}
return true;
}

@Override
public void describeTo(Description description) {
description.appendText("Document contain exactly fields with names: ").appendValue(expectedFieldsNames);
}
}
Loading

0 comments on commit 5116d99

Please sign in to comment.