@@ -18,18 +18,26 @@ import org.opensearch.alerting.AlertingPlugin.Companion.MONITOR_V2_BASE_URI
1818import org.opensearch.alerting.AlertingRestTestCase
1919import org.opensearch.alerting.PPL_FULL_ACCESS_ROLE
2020import org.opensearch.alerting.ROLE_TO_PERMISSION_MAPPING
21+ import org.opensearch.alerting.TEST_INDEX_MAPPINGS
2122import org.opensearch.alerting.TEST_INDEX_NAME
2223import org.opensearch.alerting.core.settings.AlertingV2Settings
2324import 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
2429import org.opensearch.alerting.randomPPLMonitor
30+ import org.opensearch.alerting.randomPPLTrigger
2531import org.opensearch.client.ResponseException
2632import org.opensearch.client.RestClient
2733import org.opensearch.common.settings.Settings
2834import org.opensearch.common.xcontent.XContentType
35+ import org.opensearch.commons.alerting.model.IntervalSchedule
2936import org.opensearch.commons.rest.SecureRestClientBuilder
3037import org.opensearch.core.rest.RestStatus
3138import org.opensearch.index.query.QueryBuilders
3239import 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