Skip to content

Commit dd5c804

Browse files
committed
adding get alerts rbac IT
1 parent 37b82bf commit dd5c804

File tree

4 files changed

+169
-6
lines changed

4 files changed

+169
-6
lines changed

alerting/src/main/kotlin/org/opensearch/alerting/alertsv2/AlertV2Mover.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.opensearch.alerting.modelv2.MonitorV2
2323
import org.opensearch.alerting.modelv2.MonitorV2.Companion.MONITOR_V2_TYPE
2424
import org.opensearch.alerting.opensearchapi.suspendUntil
2525
import org.opensearch.alerting.settings.AlertingSettings.Companion.ALERT_V2_HISTORY_ENABLED
26+
import org.opensearch.alerting.util.MAX_SEARCH_SIZE
2627
import org.opensearch.cluster.ClusterChangedEvent
2728
import org.opensearch.cluster.ClusterStateListener
2829
import org.opensearch.cluster.service.ClusterService
@@ -138,7 +139,7 @@ class AlertV2Mover(
138139
// first collect all active alerts
139140
val allAlertsSearchQuery = SearchSourceBuilder.searchSource()
140141
.query(QueryBuilders.matchAllQuery())
141-
.size(10000)
142+
.size(MAX_SEARCH_SIZE)
142143
.version(true)
143144
val activeAlertsRequest = SearchRequest(ALERT_V2_INDEX)
144145
.source(allAlertsSearchQuery)
@@ -154,7 +155,7 @@ class AlertV2Mover(
154155
// now collect all triggers and their expire durations
155156
val monitorV2sSearchQuery = SearchSourceBuilder.searchSource()
156157
.query(QueryBuilders.existsQuery(MONITOR_V2_TYPE))
157-
.size(10000)
158+
.size(MAX_SEARCH_SIZE)
158159
.version(true)
159160
val monitorV2sRequest = SearchRequest(SCHEDULED_JOBS_INDEX)
160161
.source(monitorV2sSearchQuery)
@@ -333,7 +334,7 @@ class AlertV2Mover(
333334

334335
val alertsSearchQuery = SearchSourceBuilder.searchSource()
335336
.query(boolQuery)
336-
.size(10000)
337+
.size(MAX_SEARCH_SIZE)
337338
.version(true)
338339
val activeAlertsRequest = SearchRequest(ALERT_V2_INDEX)
339340
.source(alertsSearchQuery)

alerting/src/main/kotlin/org/opensearch/alerting/transportv2/TransportGetAlertsV2Action.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import org.opensearch.alerting.alertsv2.AlertV2Indices
2121
import org.opensearch.alerting.core.settings.AlertingV2Settings.Companion.ALERTING_V2_ENABLED
2222
import org.opensearch.alerting.modelv2.AlertV2
2323
import org.opensearch.alerting.modelv2.AlertV2.Companion.MONITOR_V2_NAME_FIELD
24+
import org.opensearch.alerting.modelv2.AlertV2.Companion.MONITOR_V2_USER_FIELD
2425
import org.opensearch.alerting.modelv2.AlertV2.Companion.TRIGGER_V2_NAME_FIELD
2526
import org.opensearch.alerting.opensearchapi.addFilter
2627
import org.opensearch.alerting.settings.AlertingSettings
@@ -32,7 +33,6 @@ import org.opensearch.common.settings.Settings
3233
import org.opensearch.common.xcontent.LoggingDeprecationHandler
3334
import org.opensearch.common.xcontent.XContentHelper
3435
import org.opensearch.common.xcontent.XContentType
35-
import org.opensearch.commons.alerting.model.Alert.Companion.MONITOR_USER_FIELD
3636
import org.opensearch.commons.alerting.util.AlertingException
3737
import org.opensearch.commons.authuser.User
3838
import org.opensearch.commons.authuser.User.BACKEND_ROLES_FIELD
@@ -163,7 +163,7 @@ class TransportGetAlertsV2Action @Inject constructor(
163163
if (user != null && doFilterForUser(user)) {
164164
// if security is enabled and filterby is enabled, add search filter
165165
log.info("Filtering result by: ${user.backendRoles}")
166-
addFilter(user, searchSourceBuilder, "$MONITOR_USER_FIELD.$BACKEND_ROLES_FIELD.keyword")
166+
addFilter(user, searchSourceBuilder, "$MONITOR_V2_USER_FIELD.$BACKEND_ROLES_FIELD.keyword")
167167
}
168168

169169
search(alertIndex, searchSourceBuilder, actionListener)

alerting/src/test/kotlin/org/opensearch/alerting/AlertingRestTestCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ abstract class AlertingRestTestCase : ODFERestTestCase() {
929929
protected fun getAlertV2s(): Response {
930930
val response = client().makeRequest(
931931
"GET",
932-
"$MONITOR_V2_BASE_URI/alerts?",
932+
"$MONITOR_V2_BASE_URI/alerts",
933933
null,
934934
BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json")
935935
)

alerting/src/test/kotlin/org/opensearch/alerting/resthandler/SecureMonitorV2RestApiIT.kt

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,26 @@ import org.opensearch.alerting.AlertingPlugin.Companion.MONITOR_V2_BASE_URI
1818
import org.opensearch.alerting.AlertingRestTestCase
1919
import org.opensearch.alerting.PPL_FULL_ACCESS_ROLE
2020
import org.opensearch.alerting.ROLE_TO_PERMISSION_MAPPING
21+
import org.opensearch.alerting.TEST_INDEX_MAPPINGS
2122
import org.opensearch.alerting.TEST_INDEX_NAME
2223
import org.opensearch.alerting.core.settings.AlertingV2Settings
2324
import org.opensearch.alerting.makeRequest
25+
import org.opensearch.alerting.modelv2.PPLSQLMonitor
26+
import org.opensearch.alerting.modelv2.PPLSQLTrigger.ConditionType
27+
import org.opensearch.alerting.modelv2.PPLSQLTrigger.NumResultsCondition
28+
import org.opensearch.alerting.modelv2.PPLSQLTrigger.TriggerMode
2429
import org.opensearch.alerting.randomPPLMonitor
30+
import org.opensearch.alerting.randomPPLTrigger
2531
import org.opensearch.client.ResponseException
2632
import org.opensearch.client.RestClient
2733
import org.opensearch.common.settings.Settings
2834
import org.opensearch.common.xcontent.XContentType
35+
import org.opensearch.commons.alerting.model.IntervalSchedule
2936
import org.opensearch.commons.rest.SecureRestClientBuilder
3037
import org.opensearch.core.rest.RestStatus
3138
import org.opensearch.index.query.QueryBuilders
3239
import org.opensearch.search.builder.SearchSourceBuilder
40+
import java.time.temporal.ChronoUnit.MINUTES
3341

3442
/***
3543
* Tests Alerting V2 CRUD with role-based access control
@@ -618,6 +626,160 @@ class SecureMonitorV2RestApiIT : AlertingRestTestCase() {
618626
}
619627
}
620628

629+
fun `test RBAC get alerts v2 as user without correct backend roles fails`() {
630+
enableFilterBy()
631+
if (!isHttps()) {
632+
return
633+
}
634+
635+
createIndex(TEST_INDEX_NAME, Settings.EMPTY, TEST_INDEX_MAPPINGS)
636+
indexDocFromSomeTimeAgo(2, MINUTES, "abc", 5)
637+
638+
val pplMonitorConfig = createRandomPPLMonitor(
639+
randomPPLMonitor(
640+
enabled = true,
641+
schedule = IntervalSchedule(interval = 1, unit = MINUTES),
642+
lookBackWindow = null,
643+
triggers = listOf(
644+
randomPPLTrigger(
645+
throttleDuration = null,
646+
expireDuration = 5,
647+
mode = TriggerMode.RESULT_SET,
648+
conditionType = ConditionType.NUMBER_OF_RESULTS,
649+
numResultsCondition = NumResultsCondition.GREATER_THAN,
650+
numResultsValue = 0L,
651+
customCondition = null
652+
)
653+
),
654+
query = "source = $TEST_INDEX_NAME | head 10"
655+
)
656+
)
657+
658+
createUserWithRoles(
659+
user,
660+
listOf(ALERTING_FULL_ACCESS_ROLE, PPL_FULL_ACCESS_ROLE),
661+
listOf("backend_role_a", "backend_role_b"),
662+
false
663+
)
664+
665+
val pplMonitor = createMonitorV2WithClient(
666+
userClient!!,
667+
pplMonitorConfig,
668+
null
669+
) as PPLSQLMonitor
670+
671+
val executeResponse = executeMonitorV2(pplMonitor.id)
672+
val triggered = isTriggered(pplMonitor, executeResponse)
673+
assertTrue(triggered)
674+
675+
// the get alerts user should be able to see the alerts
676+
val getAlertsUser = "getAlertsUser"
677+
createUserWithRoles(
678+
getAlertsUser,
679+
listOf(ALERTING_FULL_ACCESS_ROLE, PPL_FULL_ACCESS_ROLE),
680+
listOf("backend_role_c"),
681+
true
682+
)
683+
684+
val getAlertsUserClient = SecureRestClientBuilder(clusterHosts.toTypedArray(), isHttps(), getAlertsUser, password)
685+
.setSocketTimeout(60000)
686+
.setConnectionRequestTimeout(180000)
687+
.build()
688+
689+
val getAlertsResponse = getAlertsUserClient!!.makeRequest(
690+
"GET",
691+
"$MONITOR_V2_BASE_URI/alerts",
692+
null,
693+
BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json")
694+
)
695+
assertEquals("Get alerts v2 failed", RestStatus.OK, getAlertsResponse.restStatus())
696+
697+
val alertsGenerated = numAlerts(getAlertsResponse) > 0
698+
assert(!alertsGenerated)
699+
700+
// cleanup
701+
getAlertsUserClient.close()
702+
}
703+
704+
fun `test RBAC get alerts v2 as user with correct backend roles succeeds`() {
705+
enableFilterBy()
706+
if (!isHttps()) {
707+
return
708+
}
709+
710+
createIndex(TEST_INDEX_NAME, Settings.EMPTY, TEST_INDEX_MAPPINGS)
711+
indexDocFromSomeTimeAgo(2, MINUTES, "abc", 5)
712+
713+
val pplMonitorConfig = createRandomPPLMonitor(
714+
randomPPLMonitor(
715+
enabled = true,
716+
schedule = IntervalSchedule(interval = 1, unit = MINUTES),
717+
lookBackWindow = null,
718+
triggers = listOf(
719+
randomPPLTrigger(
720+
throttleDuration = null,
721+
expireDuration = 5,
722+
mode = TriggerMode.RESULT_SET,
723+
conditionType = ConditionType.NUMBER_OF_RESULTS,
724+
numResultsCondition = NumResultsCondition.GREATER_THAN,
725+
numResultsValue = 0L,
726+
customCondition = null
727+
)
728+
),
729+
query = "source = $TEST_INDEX_NAME | head 10"
730+
)
731+
)
732+
733+
createUserWithRoles(
734+
user,
735+
listOf(ALERTING_FULL_ACCESS_ROLE, PPL_FULL_ACCESS_ROLE),
736+
listOf("backend_role_a", "backend_role_b"),
737+
false
738+
)
739+
740+
val pplMonitor = createMonitorV2WithClient(
741+
userClient!!,
742+
pplMonitorConfig,
743+
null
744+
) as PPLSQLMonitor
745+
746+
val executeResponse = executeMonitorV2(pplMonitor.id)
747+
val triggered = isTriggered(pplMonitor, executeResponse)
748+
assertTrue(triggered)
749+
750+
// TODO: creating this user overrides the ALERTING_FULL_ACCESS mapping and displaces "user"
751+
// TODO: above, even though passing in isExistingRole = true should trigger an update
752+
// TODO: role mappings call. doesn't block the test because "user" isn't used for the
753+
// TODO: rest of the test, but this could lead to unexpected behavior for future test writers
754+
// the get alerts user should be able to see the alerts
755+
val getAlertsUser = "getAlertsUser"
756+
createUserWithRoles(
757+
getAlertsUser,
758+
listOf(ALERTING_FULL_ACCESS_ROLE, PPL_FULL_ACCESS_ROLE),
759+
listOf("backend_role_a"),
760+
true
761+
)
762+
763+
val getAlertsUserClient = SecureRestClientBuilder(clusterHosts.toTypedArray(), isHttps(), getAlertsUser, password)
764+
.setSocketTimeout(60000)
765+
.setConnectionRequestTimeout(180000)
766+
.build()
767+
768+
val getAlertsResponse = getAlertsUserClient!!.makeRequest(
769+
"GET",
770+
"$MONITOR_V2_BASE_URI/alerts",
771+
null,
772+
BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json")
773+
)
774+
assertEquals("Get alerts v2 failed", RestStatus.OK, getAlertsResponse.restStatus())
775+
776+
val alertsGenerated = numAlerts(getAlertsResponse) > 0
777+
assert(alertsGenerated)
778+
779+
// cleanup
780+
getAlertsUserClient.close()
781+
}
782+
621783
fun `test RBAC delete monitorV2 as user with correct backend roles succeeds`() {
622784
enableFilterBy()
623785
if (!isHttps()) {

0 commit comments

Comments
 (0)