diff --git a/build.gradle b/build.gradle index 3b435bd2ae..dfe1778c5d 100644 --- a/build.gradle +++ b/build.gradle @@ -584,6 +584,8 @@ dependencies { implementation 'com.nimbusds:nimbus-jose-jwt:9.40' implementation 'com.rfksystems:blake2b:2.0.0' implementation 'com.password4j:password4j:1.8.2' + implementation 'com.selectivem:checklists:1.1.0' + //JWT implementation "io.jsonwebtoken:jjwt-api:${jjwt_version}" implementation "io.jsonwebtoken:jjwt-impl:${jjwt_version}" diff --git a/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java b/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java index 41845f08d8..21021b7e8f 100644 --- a/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java +++ b/src/main/java/org/opensearch/security/privileges/ActionPrivileges.java @@ -37,6 +37,8 @@ import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.support.WildcardMatcher; +import com.selectivem.check.CheckTable; + /** * This class converts role configuration into pre-computed, optimized data structures for checking privileges. * @@ -565,7 +567,7 @@ PrivilegesEvaluatorResponse providesPrivilege( return PrivilegesEvaluatorResponse.ok(); } - ImmutableSet availableIndices = checkTable.getCompleteRows(); + Set availableIndices = checkTable.getCompleteRows(); if (!availableIndices.isEmpty()) { return PrivilegesEvaluatorResponse.partiallyOk(availableIndices, checkTable, context); diff --git a/src/main/java/org/opensearch/security/privileges/CheckTable.java b/src/main/java/org/opensearch/security/privileges/CheckTable.java deleted file mode 100644 index 02498cbf1a..0000000000 --- a/src/main/java/org/opensearch/security/privileges/CheckTable.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ -package org.opensearch.security.privileges; - -import java.util.Comparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.google.common.collect.ImmutableSet; - -/** - * A specialized data structure which represents a matrix of checkmarks. During construction, you can specify its rows - * and columns. Initially, all cells of the matrix are unchecked. You can use the check() method to set particular - * cells to checked(). There are various methods to query the state of the whole matrix, of columns and rows. - * - * The state of the matrix can be visualized with the toTableString() method: - * - *
- *          | indices:data/read/search |
- * index_a11| ok                       |
- * index_a12| MISSING                  |
- * index_a13| MISSING                  |
- * index_a14| MISSING                  |
- * 
- * - * TODO: This is for now just a minimalistic, inefficient and non-production-ready implementation. A better replacement is - * necessary. - */ -public class CheckTable { - private HashSet checked = new HashSet<>(); - private Set rows; - private Set columns; - private int size; - - public boolean check(R row, C column) { - if (!checked.contains(row + "::" + column)) { - checked.add(row + "::" + column); - } - - return isComplete(); - } - - public boolean isChecked(R row, C column) { - return checked.contains(row + "::" + column); - } - - public boolean isComplete() { - return size == checked.size(); - } - - public boolean isRowComplete(R row) { - for (C column : this.columns) { - boolean checked = this.isChecked(row, column); - - if (!checked) { - return false; - } - } - - return true; - } - - public boolean isColumnComplete(C column) { - for (R row : this.rows) { - boolean checked = this.isChecked(row, column); - - if (!checked) { - return false; - } - } - - return true; - } - - public ImmutableSet getCompleteRows() { - if (isComplete()) { - return ImmutableSet.copyOf(rows); - } else if (size == 0) { - return ImmutableSet.of(); - } else { - return this.rows.stream().filter(r -> this.isRowComplete(r)).collect(ImmutableSet.toImmutableSet()); - } - } - - public ImmutableSet getIncompleteColumns() { - if (isComplete()) { - return ImmutableSet.of(); - } else if (size == 0) { - return ImmutableSet.copyOf(columns); - } else { - return this.columns.stream().filter(c -> !this.isColumnComplete(c)).collect(ImmutableSet.toImmutableSet()); - } - } - - public Iterable iterateUncheckedRows(C column) { - return new Iterable() { - @Override - public Iterator iterator() { - Iterator rowIter = rows.iterator(); - - return new Iterator() { - R next = null; - - @Override - public boolean hasNext() { - if (next == null) { - init(); - } - return next != null; - } - - @Override - public R next() { - if (next == null) { - init(); - } - R result = next; - next = null; - return result; - } - - private void init() { - while (rowIter.hasNext()) { - R candidate = rowIter.next(); - - if (!isChecked(candidate, column)) { - next = candidate; - break; - } - } - } - }; - } - }; - } - - @Override - public String toString() { - return toTableString("x", ""); - } - - public String toTableString(String checkedIndicator, String uncheckedIndicator) { - StringBuilder result = new StringBuilder(); - - int rowHeaderWidth = rows.stream().map((r) -> r.toString().length()).max(Comparator.naturalOrder()).get(); - - result.append(padEnd("", rowHeaderWidth, ' ')); - result.append("|"); - - int[] columnWidth = new int[columns.size()]; - - int i = 0; - for (C column : columns) { - String columnLabel = column.toString(); - - if (columnLabel.length() > 40) { - columnLabel = columnLabel.substring(0, 40); - } - - columnWidth[i] = columnLabel.length(); - i++; - result.append(" ").append(columnLabel).append(" |"); - } - - result.append("\n"); - - for (R row : rows) { - - result.append(padEnd(row.toString(), rowHeaderWidth, ' ')); - result.append("|"); - - i = 0; - for (C column : columns) { - - String v = isChecked(row, column) ? checkedIndicator : uncheckedIndicator; - - result.append(" ").append(padEnd(v, columnWidth[i], ' ')).append(" |"); - i++; - } - result.append("\n"); - - } - - return result.toString(); - } - - static String padEnd(String string, int width, char paddingChar) { - if (string.length() > width) { - return string; - } - - StringBuilder result = new StringBuilder(string); - - while (result.length() < width) { - result.append(paddingChar); - } - - return result.toString(); - } - - private CheckTable(Set rows, Set columns) { - this.rows = rows; - this.columns = columns; - this.size = rows.size() * columns.size(); - } - - public static CheckTable create(Set rows, Set columns) { - return new CheckTable<>(rows, columns); - } -} diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index e2b072f09a..ad0dcd72ef 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -97,6 +97,7 @@ import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.DashboardSignInOption; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.ActionGroupsV7; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.user.User; @@ -199,7 +200,11 @@ public PrivilegesEvaluator( if (rolesConfiguration != null) { FlattenedActionGroups flattenedActionGroups = actionGroupsConfiguration != null - ? new FlattenedActionGroups(DynamicConfigFactory.addStatics(actionGroupsConfiguration.deepClone())) + ? new FlattenedActionGroups( + (SecurityDynamicConfiguration) DynamicConfigFactory.addStatics( + actionGroupsConfiguration.deepClone() + ) + ) : FlattenedActionGroups.EMPTY; ActionPrivileges actionPrivileges = new ActionPrivileges( DynamicConfigFactory.addStatics(rolesConfiguration.deepClone()), @@ -501,23 +506,23 @@ public PrivilegesEvaluatorResponse evaluate( // // Thus, I am inclined to remove the following logic and rely on the processing on // the get/search/tv level. - Set reduced = securityRoles.reduce( - requestedResolved, - user, - new String[] { action0 }, - resolver, - clusterService - ); - - if (reduced.isEmpty()) { - presponse.allowed = false; - return presponse; - } - - if (irr.replace(request, true, reduced.toArray(new String[0]))) { - presponse.allowed = true; - return presponse; - } + // Set reduced = securityRoles.reduce( + // requestedResolved, + // user, + // new String[] { action0 }, + // resolver, + // clusterService + // ); + // + // if (reduced.isEmpty()) { + // presponse.allowed = false; + // return presponse; + // } + // + // if (irr.replace(request, true, reduced.toArray(new String[0]))) { + // presponse.allowed = true; + // return presponse; + // } } if (isDebugEnabled) { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java index c982d71e1a..26aaefe796 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluatorResponse.java @@ -36,6 +36,8 @@ import org.opensearch.security.resolver.IndexResolverReplacer.Resolved; import org.opensearch.security.securityconf.EvaluatedDlsFlsConfig; +import com.selectivem.check.CheckTable; + public class PrivilegesEvaluatorResponse { boolean allowed = false; Set missingSecurityRoles = new HashSet<>(); @@ -44,7 +46,7 @@ public class PrivilegesEvaluatorResponse { PrivilegesEvaluatorResponseState state = PrivilegesEvaluatorResponseState.PENDING; Resolved resolved; CreateIndexRequestBuilder createIndexRequestBuilder; - private ImmutableSet onlyAllowedForIndices = ImmutableSet.of(); + private Set onlyAllowedForIndices = ImmutableSet.of(); private CheckTable indexToActionCheckTable; private String reason; @@ -66,7 +68,7 @@ public boolean isPartiallyOk() { return !this.onlyAllowedForIndices.isEmpty(); } - public ImmutableSet getAvailableIndices() { + public Set getAvailableIndices() { return this.onlyAllowedForIndices; }