Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3bfffc7
add setting for filter by backend roles access strategy
markdboyd Jan 26, 2026
7573a66
stub out logic for checking resource access by filter by backend role…
markdboyd Jan 26, 2026
35e758f
adding integration test for getting monitor for user with multiple ba…
markdboyd Mar 6, 2026
9bee231
simplify code for testing
markdboyd Mar 6, 2026
d7a1e37
update logic for comparing backend roles when evaluating access to co…
markdboyd Mar 6, 2026
e1a2101
remove debugging code
markdboyd Mar 6, 2026
148ef21
add tests for access to monitors when filterByAccessStrategy is all
markdboyd Mar 6, 2026
3b55599
integrate filterbyAccessStrategy setting into transport classes
markdboyd Mar 6, 2026
9d17d0c
add filterByAccessStrategy setting to plugin
markdboyd Mar 6, 2026
f8b3d3a
use enum and validator for filter_by_backend_roles_access_strategy se…
markdboyd Mar 6, 2026
706f0a1
update code to use enum for filter by access strategy settings when c…
markdboyd Mar 6, 2026
3bd3af4
update integration test to set filter by backend roles strategy
markdboyd Mar 6, 2026
2736855
update test names
markdboyd Mar 6, 2026
b8f2615
add test for get monitor access denied when filter by access strategy…
markdboyd Mar 6, 2026
0b80269
rename checkUserBackendRolesAccess -> doUserBackendRolesMatchResource…
markdboyd Mar 11, 2026
f20c064
fix typo in SecureTransPortAction.doUserBackendRolesMatchResource() l…
markdboyd Mar 11, 2026
d2b10ae
add check for filter by backend roles access strategy setting in aler…
markdboyd Mar 11, 2026
5af7b91
add new filter by backend roles strategy of "exact" where backend rol…
markdboyd Mar 31, 2026
e37ced2
fix code formatting errors
markdboyd Mar 31, 2026
fb7ac5d
add new logic for handling filter by backend roles strategy of ALL
markdboyd Mar 31, 2026
8f8e1d1
update tests to clarify testing of filter by backend roles access str…
markdboyd Mar 31, 2026
cb7b9bb
add tests for filter by backend roles access strategy of all
markdboyd Mar 31, 2026
23ab66c
update test setup to verify that filter by backend roles strategy of …
markdboyd Mar 31, 2026
fef3f4e
add unit tests for FilterByBackendRolesAccessStrategyValidator
markdboyd Mar 31, 2026
519f414
simplify tests in FilterByBackendRolesAccessStrategyValidatorTests
markdboyd Mar 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, R
AlertingSettings.COMMENTS_MAX_CONTENT_SIZE,
AlertingSettings.MAX_COMMENTS_PER_ALERT,
AlertingSettings.MAX_COMMENTS_PER_NOTIFICATION,
AlertingSettings.NOTIFICATION_CONTEXT_RESULTS_ALLOWED_ROLES
AlertingSettings.NOTIFICATION_CONTEXT_RESULTS_ALLOWED_ROLES,
AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,5 +302,13 @@ class AlertingSettings {
Setting.Property.NodeScope,
Setting.Property.Dynamic
)

val FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY = Setting.simpleString(
"plugins.alerting.filter_by_backend_roles_access_strategy",
FilterByBackendRolesAccessStrategy.INTERSECT.strategy,
FilterByBackendRolesAccessStrategyValidator(),
Setting.Property.NodeScope,
Setting.Property.Dynamic
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.alerting.settings

/**
* Defines the FilterByBackendRolesAccessStrategy
*/
enum class FilterByBackendRolesAccessStrategy(val strategy: String) {
/**
* User backend roles must contain all resource backend roles to have access
*/
ALL("all"),

/**
* Backend roles must be exactly equal to have access
*/
EXACT("exact"),

/**
* Backend roles must intersect to have access
*/
INTERSECT("intersect"),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.alerting.settings

import org.opensearch.common.settings.Setting

class FilterByBackendRolesAccessStrategyValidator : Setting.Validator<String> {
override fun validate(strategy: String) {
val allStrategies: List<String> = FilterByBackendRolesAccessStrategy.entries.map { it.strategy }

when (strategy) {
FilterByBackendRolesAccessStrategy.ALL.strategy,
FilterByBackendRolesAccessStrategy.EXACT.strategy,
FilterByBackendRolesAccessStrategy.INTERSECT.strategy -> {}
else -> throw IllegalArgumentException(
"Setting value must be one of [$allStrategies]"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.opensearch.alerting.transport
import org.apache.logging.log4j.LogManager
import org.opensearch.OpenSearchStatusException
import org.opensearch.alerting.settings.AlertingSettings
import org.opensearch.alerting.settings.FilterByBackendRolesAccessStrategy
import org.opensearch.cluster.service.ClusterService
import org.opensearch.commons.ConfigConstants
import org.opensearch.commons.alerting.util.AlertingException
Expand Down Expand Up @@ -38,9 +39,13 @@ private val log = LogManager.getLogger(SecureTransportAction::class.java)
interface SecureTransportAction {

var filterByEnabled: Boolean
var filterByAccessStrategy: String

fun listenFilterBySettingChange(clusterService: ClusterService) {
clusterService.clusterSettings.addSettingsUpdateConsumer(AlertingSettings.FILTER_BY_BACKEND_ROLES) { filterByEnabled = it }
clusterService.clusterSettings.addSettingsUpdateConsumer(AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY) {
filterByAccessStrategy = it
}
}

fun readUserFromThreadContext(client: Client): User? {
Expand Down Expand Up @@ -100,6 +105,21 @@ interface SecureTransportAction {
return true
}

fun doUserBackendRolesMatchResource(userBackendRoles: List<String>, resourceBackendRoles: List<String>): Boolean {
if (filterByAccessStrategy == FilterByBackendRolesAccessStrategy.ALL.strategy) {
return userBackendRoles.containsAll(resourceBackendRoles)
} else if (filterByAccessStrategy == FilterByBackendRolesAccessStrategy.INTERSECT.strategy) {
return resourceBackendRoles.any { it in userBackendRoles }
} else if (filterByAccessStrategy == FilterByBackendRolesAccessStrategy.EXACT.strategy) {
return resourceBackendRoles.sorted().equals(userBackendRoles.sorted())
}
// Not sure if this is necessary, since there is a validator
// on the setting itself
throw IllegalArgumentException(
"Invalid filter by access strategy: $filterByAccessStrategy"
)
}

/**
* If FilterBy is enabled, this function verifies that the requester user has FilterBy permissions to access
* the resource. If FilterBy is disabled, we will assume the user has permissions and return true.
Expand All @@ -122,7 +142,7 @@ interface SecureTransportAction {
if (
resourceBackendRoles == null ||
requesterBackendRoles == null ||
resourceBackendRoles.intersect(requesterBackendRoles).isEmpty()
!doUserBackendRolesMatchResource(requesterBackendRoles, resourceBackendRoles)
) {
actionListener.onFailure(
AlertingException.wrap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class TransportDeleteAlertingCommentAction @Inject constructor(

@Volatile private var alertingCommentsEnabled = AlertingSettings.ALERTING_COMMENTS_ENABLED.get(settings)
@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
clusterService.clusterSettings.addSettingsUpdateConsumer(AlertingSettings.ALERTING_COMMENTS_ENABLED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class TransportDeleteMonitorAction @Inject constructor(
SecureTransportAction {

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class TransportDeleteWorkflowAction @Inject constructor(
private val log = LogManager.getLogger(javaClass)

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class TransportDocLevelMonitorFanOutAction

@Volatile
override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

override fun doExecute(
task: Task,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class TransportGetAlertsAction @Inject constructor(

@Volatile
override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class TransportGetDestinationsAction @Inject constructor(
SecureTransportAction {

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class TransportGetFindingsSearchAction @Inject constructor(
SecureTransportAction {

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class TransportGetMonitorAction @Inject constructor(

@Volatile
override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class TransportGetRemoteIndexesAction @Inject constructor(
SecureTransportAction {

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

@Volatile private var remoteMonitoringEnabled = CROSS_CLUSTER_MONITORING_ENABLED.get(settings)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class TransportGetWorkflowAction @Inject constructor(
private val log = LogManager.getLogger(javaClass)

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class TransportGetWorkflowAlertsAction @Inject constructor(
@Volatile
override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)

@Volatile
override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

@Volatile
private var isAlertHistoryEnabled = AlertingSettings.ALERT_HISTORY_ENABLED.get(settings)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ constructor(
@Volatile private var indexTimeout = INDEX_TIMEOUT.get(settings)

@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
clusterService.clusterSettings.addSettingsUpdateConsumer(ALERTING_COMMENTS_ENABLED) { alertingCommentsEnabled = it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class TransportIndexMonitorAction @Inject constructor(
@Volatile private var maxActionThrottle = MAX_ACTION_THROTTLE_VALUE.get(settings)
@Volatile private var allowList = ALLOW_LIST.get(settings)
@Volatile override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
clusterService.clusterSettings.addSettingsUpdateConsumer(ALERTING_MAX_MONITORS) { maxMonitors = it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ class TransportIndexWorkflowAction @Inject constructor(
@Volatile
override var filterByEnabled = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)

@Volatile
override var filterByAccessStrategy = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
clusterService.clusterSettings.addSettingsUpdateConsumer(ALERTING_MAX_MONITORS) { maxMonitors = it }
clusterService.clusterSettings.addSettingsUpdateConsumer(REQUEST_TIMEOUT) { requestTimeout = it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class TransportSearchAlertingCommentAction @Inject constructor(

@Volatile private var alertingCommentsEnabled = AlertingSettings.ALERTING_COMMENTS_ENABLED.get(settings)
@Volatile override var filterByEnabled: Boolean = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile override var filterByAccessStrategy: String = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
clusterService.clusterSettings.addSettingsUpdateConsumer(AlertingSettings.ALERTING_COMMENTS_ENABLED) {
alertingCommentsEnabled = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class TransportSearchMonitorAction @Inject constructor(
SecureTransportAction {
@Volatile
override var filterByEnabled: Boolean = AlertingSettings.FILTER_BY_BACKEND_ROLES.get(settings)
@Volatile
override var filterByAccessStrategy: String = AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.get(settings)

init {
listenFilterBySettingChange(clusterService)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,20 @@ abstract class AlertingRestTestCase : ODFERestTestCase() {
assertEquals(updateResponse.statusLine.toString(), 200, updateResponse.statusLine.statusCode)
}

fun setFilterByBackendRolesStrategy(strategy: String) {
val updateResponse = client().makeRequest(
"PUT", "_cluster/settings",
emptyMap(),
StringEntity(
XContentFactory.jsonBuilder().startObject().field("persistent")
.startObject().field(AlertingSettings.FILTER_BY_BACKEND_ROLES_ACCESS_STRATEGY.key, strategy).endObject()
.endObject().string(),
ContentType.APPLICATION_JSON
)
)
assertEquals(updateResponse.statusLine.toString(), 200, updateResponse.statusLine.statusCode)
}

fun disableFilterBy() {
val updateResponse = client().makeRequest(
"PUT", "_cluster/settings",
Expand Down
Loading
Loading