Skip to content

Commit e05cb36

Browse files
committed
Adding filtering the reports based on tenants.
When user=null or tenant=null, tenant is considered "" The APIs match for tenant info from user context
1 parent 0bbab87 commit e05cb36

File tree

12 files changed

+93
-21
lines changed

12 files changed

+93
-21
lines changed

reports-scheduler/src/main/config/reports-scheduler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ opendistro.reports:
3030
# adminAccess values:
3131
## Standard -> Admin user access follows standard user
3232
## AllReports -> Admin user with "all_access" role can see all reports of all users.
33-
filterBy: "NoFilter"
33+
filterBy: "NoFilter" # Applied when tenant != __user__
3434
# filterBy values:
3535
## NoFilter -> everyone see each other's reports
3636
## User -> reports are visible to only themselves

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/action/ReportDefinitionActions.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ internal object ReportDefinitionActions {
5454
val reportDefinitionDetails = ReportDefinitionDetails("ignore",
5555
currentTime,
5656
currentTime,
57+
UserAccessManager.getUserTenant(user),
5758
UserAccessManager.getAllAccessInfo(user),
5859
request.reportDefinition
5960
)
@@ -74,13 +75,14 @@ internal object ReportDefinitionActions {
7475
val currentReportDefinitionDetails = ReportDefinitionsIndex.getReportDefinition(request.reportDefinitionId)
7576
currentReportDefinitionDetails
7677
?: throw ElasticsearchStatusException("Report Definition ${request.reportDefinitionId} not found", RestStatus.NOT_FOUND)
77-
if (!UserAccessManager.doesUserHasAccess(user, currentReportDefinitionDetails.access)) {
78+
if (!UserAccessManager.doesUserHasAccess(user, currentReportDefinitionDetails.tenant, currentReportDefinitionDetails.access)) {
7879
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportDefinitionId}", RestStatus.FORBIDDEN)
7980
}
8081
val currentTime = Instant.now()
8182
val reportDefinitionDetails = ReportDefinitionDetails(request.reportDefinitionId,
8283
currentTime,
8384
currentReportDefinitionDetails.createdTime,
85+
UserAccessManager.getUserTenant(user),
8486
currentReportDefinitionDetails.access,
8587
request.reportDefinition
8688
)
@@ -101,7 +103,7 @@ internal object ReportDefinitionActions {
101103
val reportDefinitionDetails = ReportDefinitionsIndex.getReportDefinition(request.reportDefinitionId)
102104
reportDefinitionDetails
103105
?: throw ElasticsearchStatusException("Report Definition ${request.reportDefinitionId} not found", RestStatus.NOT_FOUND)
104-
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.access)) {
106+
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.tenant, reportDefinitionDetails.access)) {
105107
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportDefinitionId}", RestStatus.FORBIDDEN)
106108
}
107109
return GetReportDefinitionResponse(reportDefinitionDetails, UserAccessManager.hasAllInfoAccess(user))
@@ -118,7 +120,7 @@ internal object ReportDefinitionActions {
118120
val reportDefinitionDetails = ReportDefinitionsIndex.getReportDefinition(request.reportDefinitionId)
119121
reportDefinitionDetails
120122
?: throw ElasticsearchStatusException("Report Definition ${request.reportDefinitionId} not found", RestStatus.NOT_FOUND)
121-
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.access)) {
123+
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.tenant, reportDefinitionDetails.access)) {
122124
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportDefinitionId}", RestStatus.FORBIDDEN)
123125
}
124126
if (!ReportDefinitionsIndex.deleteReportDefinition(request.reportDefinitionId)) {
@@ -135,7 +137,8 @@ internal object ReportDefinitionActions {
135137
fun getAll(request: GetAllReportDefinitionsRequest, user: User?): GetAllReportDefinitionsResponse {
136138
log.info("$LOG_PREFIX:ReportDefinition-getAll fromIndex:${request.fromIndex} maxItems:${request.maxItems}")
137139
UserAccessManager.validateUser(user)
138-
val reportDefinitionsList = ReportDefinitionsIndex.getAllReportDefinitions(UserAccessManager.getSearchAccessInfo(user),
140+
val reportDefinitionsList = ReportDefinitionsIndex.getAllReportDefinitions(UserAccessManager.getUserTenant(user),
141+
UserAccessManager.getSearchAccessInfo(user),
139142
request.fromIndex,
140143
request.maxItems)
141144
return GetAllReportDefinitionsResponse(reportDefinitionsList, UserAccessManager.hasAllInfoAccess(user))

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/action/ReportInstanceActions.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ internal object ReportInstanceActions {
6161
currentTime,
6262
request.beginTime,
6363
request.endTime,
64+
UserAccessManager.getUserTenant(user),
6465
UserAccessManager.getAllAccessInfo(user),
6566
request.reportDefinitionDetails,
6667
Status.Success, // TODO: Revert to request.status when background job execution supported
@@ -84,7 +85,7 @@ internal object ReportInstanceActions {
8485
val reportDefinitionDetails = ReportDefinitionsIndex.getReportDefinition(request.reportDefinitionId)
8586
reportDefinitionDetails
8687
?: throw ElasticsearchStatusException("Report Definition ${request.reportDefinitionId} not found", RestStatus.NOT_FOUND)
87-
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.access)) {
88+
if (!UserAccessManager.doesUserHasAccess(user, reportDefinitionDetails.tenant, reportDefinitionDetails.access)) {
8889
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportDefinitionId}", RestStatus.FORBIDDEN)
8990
}
9091
val beginTime: Instant = currentTime.minus(reportDefinitionDetails.reportDefinition.format.duration)
@@ -95,6 +96,7 @@ internal object ReportInstanceActions {
9596
currentTime,
9697
beginTime,
9798
endTime,
99+
UserAccessManager.getUserTenant(user),
98100
reportDefinitionDetails.access,
99101
reportDefinitionDetails,
100102
currentStatus)
@@ -115,7 +117,7 @@ internal object ReportInstanceActions {
115117
val currentReportInstance = ReportInstancesIndex.getReportInstance(request.reportInstanceId)
116118
currentReportInstance
117119
?: throw ElasticsearchStatusException("Report Instance ${request.reportInstanceId} not found", RestStatus.NOT_FOUND)
118-
if (!UserAccessManager.doesUserHasAccess(user, currentReportInstance.access)) {
120+
if (!UserAccessManager.doesUserHasAccess(user, currentReportInstance.tenant, currentReportInstance.access)) {
119121
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportInstanceId}", RestStatus.FORBIDDEN)
120122
}
121123
if (request.status == Status.Scheduled) { // Don't allow changing status to Scheduled
@@ -142,7 +144,7 @@ internal object ReportInstanceActions {
142144
val reportInstance = ReportInstancesIndex.getReportInstance(request.reportInstanceId)
143145
reportInstance
144146
?: throw ElasticsearchStatusException("Report Instance ${request.reportInstanceId} not found", RestStatus.NOT_FOUND)
145-
if (!UserAccessManager.doesUserHasAccess(user, reportInstance.access)) {
147+
if (!UserAccessManager.doesUserHasAccess(user, reportInstance.tenant, reportInstance.access)) {
146148
throw ElasticsearchStatusException("Permission denied for Report Definition ${request.reportInstanceId}", RestStatus.FORBIDDEN)
147149
}
148150
return GetReportInstanceResponse(reportInstance, UserAccessManager.hasAllInfoAccess(user))
@@ -156,7 +158,8 @@ internal object ReportInstanceActions {
156158
fun getAll(request: GetAllReportInstancesRequest, user: User?): GetAllReportInstancesResponse {
157159
log.info("$LOG_PREFIX:ReportInstance-getAll fromIndex:${request.fromIndex} maxItems:${request.maxItems}")
158160
UserAccessManager.validateUser(user)
159-
val reportInstanceList = ReportInstancesIndex.getAllReportInstances(UserAccessManager.getSearchAccessInfo(user),
161+
val reportInstanceList = ReportInstancesIndex.getAllReportInstances(UserAccessManager.getUserTenant(user),
162+
UserAccessManager.getSearchAccessInfo(user),
160163
request.fromIndex,
161164
request.maxItems)
162165
return GetAllReportInstancesResponse(reportInstanceList, UserAccessManager.hasAllInfoAccess(user))

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/index/ReportDefinitionsIndex.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.amazon.opendistroforelasticsearch.reportsscheduler.ReportsSchedulerPl
2020
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.ReportDefinitionDetails
2121
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.ReportDefinitionDetailsSearchResults
2222
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.ACCESS_LIST_FIELD
23+
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.TENANT_FIELD
2324
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.UPDATED_TIME_FIELD
2425
import com.amazon.opendistroforelasticsearch.reportsscheduler.settings.PluginSettings
2526
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.SecureIndexClient
@@ -147,21 +148,28 @@ internal object ReportDefinitionsIndex {
147148

148149
/**
149150
* Query index for report definition for given access details
151+
* @param tenant the tenant of the user
150152
* @param access the list of access details to search reports for.
151153
* @param from the paginated start index
152154
* @param maxItems the max items to query
153155
* @return search result of Report definition details
154156
*/
155-
fun getAllReportDefinitions(access: List<String>, from: Int, maxItems: Int): ReportDefinitionDetailsSearchResults {
157+
fun getAllReportDefinitions(tenant: String, access: List<String>, from: Int, maxItems: Int): ReportDefinitionDetailsSearchResults {
156158
createIndex()
157159
val sourceBuilder = SearchSourceBuilder()
158160
.timeout(TimeValue(PluginSettings.operationTimeoutMs, TimeUnit.MILLISECONDS))
159161
.sort(UPDATED_TIME_FIELD)
160162
.size(maxItems)
161163
.from(from)
164+
val tenantQuery = QueryBuilders.termsQuery(TENANT_FIELD, tenant)
162165
if (access.isNotEmpty()) {
163-
val query = QueryBuilders.termsQuery(ACCESS_LIST_FIELD, access)
166+
val accessQuery = QueryBuilders.termsQuery(ACCESS_LIST_FIELD, access)
167+
val query = QueryBuilders.boolQuery()
168+
query.filter(tenantQuery)
169+
query.filter(accessQuery)
164170
sourceBuilder.query(query)
171+
} else {
172+
sourceBuilder.query(tenantQuery)
165173
}
166174
val searchRequest = SearchRequest()
167175
.indices(REPORT_DEFINITIONS_INDEX_NAME)

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/index/ReportInstancesIndex.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.amazon.opendistroforelasticsearch.reportsscheduler.model.ReportInstan
2323
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.ReportInstanceSearchResults
2424
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.ACCESS_LIST_FIELD
2525
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.STATUS_FIELD
26+
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.TENANT_FIELD
2627
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.UPDATED_TIME_FIELD
2728
import com.amazon.opendistroforelasticsearch.reportsscheduler.settings.PluginSettings
2829
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.SecureIndexClient
@@ -151,21 +152,28 @@ internal object ReportInstancesIndex {
151152

152153
/**
153154
* Query index for report instance for given access details
155+
* @param tenant the tenant of the user
154156
* @param access the list of access details to search reports for.
155157
* @param from the paginated start index
156158
* @param maxItems the max items to query
157159
* @return search result of Report instance details
158160
*/
159-
fun getAllReportInstances(access: List<String>, from: Int, maxItems: Int): ReportInstanceSearchResults {
161+
fun getAllReportInstances(tenant: String, access: List<String>, from: Int, maxItems: Int): ReportInstanceSearchResults {
160162
createIndex()
161163
val sourceBuilder = SearchSourceBuilder()
162164
.timeout(TimeValue(PluginSettings.operationTimeoutMs, TimeUnit.MILLISECONDS))
163165
.sort(UPDATED_TIME_FIELD)
164166
.size(maxItems)
165167
.from(from)
168+
val tenantQuery = QueryBuilders.termsQuery(TENANT_FIELD, tenant)
166169
if (access.isNotEmpty()) {
167-
val query = QueryBuilders.termsQuery(ACCESS_LIST_FIELD, access)
170+
val accessQuery = QueryBuilders.termsQuery(ACCESS_LIST_FIELD, access)
171+
val query = QueryBuilders.boolQuery()
172+
query.filter(tenantQuery)
173+
query.filter(accessQuery)
168174
sourceBuilder.query(query)
175+
} else {
176+
sourceBuilder.query(tenantQuery)
169177
}
170178
val searchRequest = SearchRequest()
171179
.indices(REPORT_INSTANCES_INDEX_NAME)

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/model/ReportDefinitionDetails.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.ACCE
2424
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.CREATED_TIME_FIELD
2525
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.ID_FIELD
2626
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.REPORT_DEFINITION_FIELD
27+
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.TENANT_FIELD
2728
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.UPDATED_TIME_FIELD
29+
import com.amazon.opendistroforelasticsearch.reportsscheduler.security.UserAccessManager.DEFAULT_TENANT
2830
import com.amazon.opendistroforelasticsearch.reportsscheduler.settings.PluginSettings
2931
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.logger
3032
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.stringList
@@ -44,7 +46,8 @@ import java.time.Instant
4446
* "id":"id",
4547
* "lastUpdatedTimeMs":1603506908773,
4648
* "createdTimeMs":1603506908773,
47-
* "access":["u:user", "r:sample_role", "ber:sample_backend_role"]
49+
* "tenant":"__user__",
50+
* "access":["User:user", "Role:sample_role", "BERole:sample_backend_role"]
4851
* "reportDefinition":{
4952
* // refer [com.amazon.opendistroforelasticsearch.reportsscheduler.model.ReportDefinition]
5053
* }
@@ -55,6 +58,7 @@ internal data class ReportDefinitionDetails(
5558
val id: String,
5659
val updatedTime: Instant,
5760
val createdTime: Instant,
61+
val tenant: String,
5862
val access: List<String>,
5963
val reportDefinition: ReportDefinition
6064
) : ScheduledJobParameter {
@@ -71,6 +75,7 @@ internal data class ReportDefinitionDetails(
7175
var id: String? = useId
7276
var updatedTime: Instant? = null
7377
var createdTime: Instant? = null
78+
var tenant: String? = null
7479
var access: List<String> = listOf()
7580
var reportDefinition: ReportDefinition? = null
7681
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser)
@@ -81,6 +86,7 @@ internal data class ReportDefinitionDetails(
8186
ID_FIELD -> id = parser.text()
8287
UPDATED_TIME_FIELD -> updatedTime = Instant.ofEpochMilli(parser.longValue())
8388
CREATED_TIME_FIELD -> createdTime = Instant.ofEpochMilli(parser.longValue())
89+
TENANT_FIELD -> tenant = parser.text()
8490
ACCESS_LIST_FIELD -> access = parser.stringList()
8591
REPORT_DEFINITION_FIELD -> reportDefinition = ReportDefinition.parse(parser)
8692
else -> {
@@ -92,10 +98,12 @@ internal data class ReportDefinitionDetails(
9298
id ?: throw IllegalArgumentException("$ID_FIELD field absent")
9399
updatedTime ?: throw IllegalArgumentException("$UPDATED_TIME_FIELD field absent")
94100
createdTime ?: throw IllegalArgumentException("$CREATED_TIME_FIELD field absent")
101+
tenant = tenant ?: DEFAULT_TENANT
95102
reportDefinition ?: throw IllegalArgumentException("$REPORT_DEFINITION_FIELD field absent")
96103
return ReportDefinitionDetails(id,
97104
updatedTime,
98105
createdTime,
106+
tenant,
99107
access,
100108
reportDefinition)
101109
}
@@ -121,6 +129,7 @@ internal data class ReportDefinitionDetails(
121129
}
122130
builder.field(UPDATED_TIME_FIELD, updatedTime.toEpochMilli())
123131
.field(CREATED_TIME_FIELD, createdTime.toEpochMilli())
132+
.field(TENANT_FIELD, tenant)
124133
if (params?.paramAsBoolean(ACCESS_LIST_FIELD, true) == true && access.isNotEmpty()) {
125134
builder.field(ACCESS_LIST_FIELD, access)
126135
}

reports-scheduler/src/main/kotlin/com/amazon/opendistroforelasticsearch/reportsscheduler/model/ReportInstance.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.IN_C
2727
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.REPORT_DEFINITION_DETAILS_FIELD
2828
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.STATUS_FIELD
2929
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.STATUS_TEXT_FIELD
30+
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.TENANT_FIELD
3031
import com.amazon.opendistroforelasticsearch.reportsscheduler.model.RestTag.UPDATED_TIME_FIELD
32+
import com.amazon.opendistroforelasticsearch.reportsscheduler.security.UserAccessManager.DEFAULT_TENANT
3133
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.logger
3234
import com.amazon.opendistroforelasticsearch.reportsscheduler.util.stringList
3335
import org.elasticsearch.common.xcontent.ToXContent
@@ -48,7 +50,8 @@ import java.time.Instant
4850
* "createdTimeMs":1603506908773,
4951
* "beginTimeMs":1603506908773,
5052
* "endTimeMs":1603506908773,
51-
* "access":["u:user", "r:sample_role", "ber:sample_backend_role"]
53+
* "tenant":"__user__",
54+
* "access":["User:user", "Role:sample_role", "BERole:sample_backend_role"]
5255
* "reportDefinitionDetails":{
5356
* // refer [com.amazon.opendistroforelasticsearch.reportsscheduler.model.reportDefinitionDetails]
5457
* },
@@ -64,6 +67,7 @@ internal data class ReportInstance(
6467
val createdTime: Instant,
6568
val beginTime: Instant,
6669
val endTime: Instant,
70+
val tenant: String,
6771
val access: List<String>,
6872
val reportDefinitionDetails: ReportDefinitionDetails?,
6973
val status: Status,
@@ -86,6 +90,7 @@ internal data class ReportInstance(
8690
var createdTime: Instant? = null
8791
var beginTime: Instant? = null
8892
var endTime: Instant? = null
93+
var tenant: String? = null
8994
var access: List<String> = listOf()
9095
var reportDefinitionDetails: ReportDefinitionDetails? = null
9196
var status: Status? = null
@@ -101,6 +106,7 @@ internal data class ReportInstance(
101106
CREATED_TIME_FIELD -> createdTime = Instant.ofEpochMilli(parser.longValue())
102107
BEGIN_TIME_FIELD -> beginTime = Instant.ofEpochMilli(parser.longValue())
103108
END_TIME_FIELD -> endTime = Instant.ofEpochMilli(parser.longValue())
109+
TENANT_FIELD -> tenant = parser.text()
104110
ACCESS_LIST_FIELD -> access = parser.stringList()
105111
REPORT_DEFINITION_DETAILS_FIELD -> reportDefinitionDetails = ReportDefinitionDetails.parse(parser)
106112
STATUS_FIELD -> status = Status.valueOf(parser.text())
@@ -117,12 +123,14 @@ internal data class ReportInstance(
117123
createdTime ?: throw IllegalArgumentException("$CREATED_TIME_FIELD field absent")
118124
beginTime ?: throw IllegalArgumentException("$BEGIN_TIME_FIELD field absent")
119125
endTime ?: throw IllegalArgumentException("$END_TIME_FIELD field absent")
126+
tenant = tenant ?: DEFAULT_TENANT
120127
status ?: throw IllegalArgumentException("$STATUS_FIELD field absent")
121128
return ReportInstance(id,
122129
updatedTime,
123130
createdTime,
124131
beginTime,
125132
endTime,
133+
tenant,
126134
access,
127135
reportDefinitionDetails,
128136
status,
@@ -153,6 +161,7 @@ internal data class ReportInstance(
153161
.field(CREATED_TIME_FIELD, createdTime.toEpochMilli())
154162
.field(BEGIN_TIME_FIELD, beginTime.toEpochMilli())
155163
.field(END_TIME_FIELD, endTime.toEpochMilli())
164+
.field(TENANT_FIELD, tenant)
156165
if (params?.paramAsBoolean(ACCESS_LIST_FIELD, true) == true && access.isNotEmpty()) {
157166
builder.field(ACCESS_LIST_FIELD, access)
158167
}

0 commit comments

Comments
 (0)