Skip to content

Commit f652815

Browse files
add role verification for security visibility + tests in scenario service
1 parent efee3fd commit f652815

File tree

8 files changed

+147
-28
lines changed

8 files changed

+147
-28
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIGXDCCBESgAwIBAgIRAOkH5f+AdSJBCZB9ZyjKABAwDQYJKoZIhvcNAQEMBQAw
3+
gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK
4+
ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD
5+
VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIz
6+
MDgwMjAwMDAwMFoXDTMzMDgwMTIzNTk1OVowVjELMAkGA1UEBhMCRlIxDjAMBgNV
7+
BAoTBUdhbmRpMTcwNQYDVQQDEy5HYW5kaSBSU0EgRG9tYWluIFZhbGlkYXRpb24g
8+
U2VjdXJlIFNlcnZlciBDQSAzMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC
9+
AYEAwrwuXKdKIiD9eu4fsNjLN0mS8HsTdDFyPPB5F5uUd6SJGutc7sqDd3T/p+gn
10+
VoAZERvzAz8+OEux1GN1UJ+Gd8s5btXJCbDV5DpvzJOhfztk5JmFKz2XBka+MvDA
11+
giyiZKs3G6yoMk8lEOu6NOsK3X8D1w0E6/C/ROa6Ml0ROnKm7vHGNVTfXTP5IqiN
12+
h2JXmp4vD23gemf8nfuI2FngayMNsjm6SwpVYWfT3S8jn5el52FKzwo+uKVZAjNH
13+
1ulgWoyO8p+PCsP+CvaEGDId3leSUVhPBBPRsxL42jjqo9aOKREgmrGco39JGf4O
14+
ImxM8vKxQ9AjDrRTRETB9V9jbRf3v3Tojt3vBBwa3xQelVp9xUWQxo/5dV73g/c7
15+
WWAvZ628XUw6k6vn6bY7qWuhehUO02plRLd5zP8nBORCbPmFCI97lZAnDYLprB4e
16+
9IgCPJp+0zQDLr9o+eNKtR0a2Txb6nzGahIPi3a7QCH6+Yq4iwYVEQm+e6KBJZOm
17+
+YiLAgMBAAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNm
18+
yzAdBgNVHQ4EFgQUgRGS3mYypbBbMz1lQ4X81AQt8a4wDgYDVR0PAQH/BAQDAgGG
19+
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
20+
BwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAhowCAYGZ4EMAQIBMFAGA1UdHwRJ
21+
MEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FD
22+
ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYB
23+
BQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFD
24+
QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJ
25+
KoZIhvcNAQEMBQADggIBADvVncOMStREyA00ZSRUmrkmR3KzAlHVz06X1ydG9EpZ
26+
z+JTQMWO809buLbDnr6t9z9jVnsDTQnWcMG4qiIkwhJVLxOVXUO+LFSBMskOe1SP
27+
BtHwHS42DeZ8QTgbRlW9p/Ey9wIo+MS2tryQ9eaDTkc2FBed/82VjrdsQoeoTyuD
28+
dp4tqarixjM/iJMgyEAMCpTkx4EqXJ/z7qgXusacsxMzt6NLv7FYcaKGbwjKqzrR
29+
vEk/+ZYnZc5mxnautf0uwRCcOe0kCOh1fd+g6Tyd+cSj6oGcJY/f/Db0sxELpzGq
30+
jRkbXan+eMojQfsgIe1n7SVyI5Yxz2RnQQL5ZT5K1mBcucqsTqkk3C7L3hF4hkwC
31+
/Otm+badymHQcnbE1Pmz6ymqj2vtwT0mEQzetQdbvv3jc3ey4YcxirAM1ihxtXeI
32+
NsEP1ndUV/0v+qqmk9iCoIjZQce8vAdziZqBYxO3NiZwTRAtqseiZWLJqQ077fy3
33+
ebdjmw6y5U+DhDW2kxF/e+FJnu53DuY5/bE+oUneY770A7BfCuH+6uhEOaMNsn21
34+
AHymLr1xlRPQYR0DMgHmsGTqdINcQfot1mlIXr05HQUK0b84CPgEU0zvVQL+j9dc
35+
/4rh2sR6rl//tjG01Q+zQKStnR2NlNNrElDUC9IDmvL9JcF20cvOlE4R0lfTXa1k
36+
-----END CERTIFICATE-----

build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ val springWebVersion = "6.1.4"
5454

5555
// Implementation
5656
val kotlinJvmTarget = 21
57-
val cosmotechApiCommonVersion = "1.0.6"
57+
val cosmotechApiCommonVersion = "1.0.7-SNAPSHOT"
5858
val cosmotechApiAzureVersion = "1.0.1"
5959
val jedisVersion = "4.4.6"
6060
val springOauthVersion = "6.2.2"
@@ -132,6 +132,7 @@ allprojects {
132132
configurations { all { resolutionStrategy { force("com.redis.om:redis-om-spring:0.9.1") } } }
133133

134134
repositories {
135+
mavenLocal()
135136
maven {
136137
name = "GitHubPackages"
137138
url = uri("https://maven.pkg.github.com/Cosmo-Tech/cosmotech-api-common")

doc/.openapi-generator/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.3.0
1+
7.8.0

runner/src/main/kotlin/com/cosmotech/runner/service/RunnerApiServiceImpl.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ import com.cosmotech.api.rbac.PERMISSION_WRITE
1212
import com.cosmotech.api.rbac.PERMISSION_WRITE_SECURITY
1313
import com.cosmotech.api.rbac.getScenarioRolesDefinition
1414
import com.cosmotech.api.utils.constructPageRequest
15-
import com.cosmotech.api.utils.getCurrentAccountIdentifier
1615
import com.cosmotech.runner.RunnerApiServiceInterface
17-
import com.cosmotech.runner.domain.CreatedRun
1816
import com.cosmotech.runner.domain.Runner
1917
import com.cosmotech.runner.domain.RunnerAccessControl
2018
import com.cosmotech.runner.domain.RunnerRole
@@ -38,12 +36,7 @@ internal class RunnerApiServiceImpl(
3836
.inWorkspace(workspaceId)
3937
.userHasPermissionOnWorkspace(PERMISSION_CREATE_CHILDREN)
4038
val runnerInstance =
41-
runnerService
42-
.getNewInstance()
43-
.setValueFrom(runner)
44-
.initSecurity(runner)
45-
.initParameters()
46-
.initDatasetList()
39+
runnerService.getNewInstance().setValueFrom(runner).initSecurity(runner).initParameters()
4740

4841
return runnerService.saveInstance(runnerInstance)
4942
}

scenario/src/integrationTest/kotlin/com/cosmotech/scenario/service/ScenarioServiceIntegrationTest.kt

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
445445
scenarioList =
446446
scenarioApiService.findAllScenarios(
447447
organizationSaved.id!!, workspaceSaved.id!!, 0, expectedSize)
448-
assertEquals(scenarioList.size, expectedSize)
448+
assertEquals(expectedSize, scenarioList.size)
449449

450450
logger.info("should find all Scenarios and assert it returns the second / last page")
451451
scenarioList =
@@ -1083,6 +1083,64 @@ class ScenarioServiceIntegrationTest : CsmRedisTestBase() {
10831083
assertEquals(ROLE_VIEWER, datasetAC.role)
10841084
}
10851085

1086+
@Test
1087+
fun `As a viewer, I can only see my information in security property for findScenarioById`() {
1088+
organization = makeOrganization(userName = TEST_USER_MAIL)
1089+
organizationSaved = organizationApiService.registerOrganization(organization)
1090+
solution = makeSolution(organizationId = organizationSaved.id!!)
1091+
solutionSaved = solutionApiService.createSolution(organizationSaved.id!!, solution)
1092+
workspace = makeWorkspace(organizationId = organizationSaved.id!!, userName = TEST_USER_MAIL)
1093+
workspaceSaved = workspaceApiService.createWorkspace(organizationSaved.id!!, workspace)
1094+
dataset = makeDataset(organizationId = organizationSaved.id!!)
1095+
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
1096+
scenario
1097+
scenario =
1098+
makeScenario(
1099+
organizationId = organizationSaved.id!!, userName = TEST_USER_MAIL, role = ROLE_VIEWER)
1100+
scenarioSaved =
1101+
scenarioApiService.createScenario(organizationSaved.id!!, workspaceSaved.id!!, scenario)
1102+
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
1103+
1104+
scenarioSaved =
1105+
scenarioApiService.findScenarioById(
1106+
organizationSaved.id!!, workspaceSaved.id!!, scenarioSaved.id!!)
1107+
assertEquals(
1108+
ScenarioSecurity(
1109+
default = ROLE_NONE, mutableListOf(ScenarioAccessControl(TEST_USER_MAIL, ROLE_VIEWER))),
1110+
scenarioSaved.security)
1111+
assertEquals(1, scenarioSaved.security!!.accessControlList.size)
1112+
}
1113+
1114+
@Test
1115+
fun `As a viewer, I can only see my information in security property for findAllScenarios`() {
1116+
organization = makeOrganization(userName = TEST_USER_MAIL)
1117+
organizationSaved = organizationApiService.registerOrganization(organization)
1118+
solution = makeSolution(organizationId = organizationSaved.id!!)
1119+
solutionSaved = solutionApiService.createSolution(organizationSaved.id!!, solution)
1120+
workspace = makeWorkspace(organizationId = organizationSaved.id!!, userName = TEST_USER_MAIL)
1121+
workspaceSaved = workspaceApiService.createWorkspace(organizationSaved.id!!, workspace)
1122+
dataset = makeDataset(organizationId = organizationSaved.id!!)
1123+
datasetSaved = datasetApiService.createDataset(organizationSaved.id!!, dataset)
1124+
scenario
1125+
scenario =
1126+
makeScenario(
1127+
organizationId = organizationSaved.id!!, userName = TEST_USER_MAIL, role = ROLE_VIEWER)
1128+
scenarioSaved =
1129+
scenarioApiService.createScenario(organizationSaved.id!!, workspaceSaved.id!!, scenario)
1130+
every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL
1131+
1132+
val scenarios =
1133+
scenarioApiService.findAllScenarios(organizationSaved.id!!, workspaceSaved.id!!, null, null)
1134+
scenarios.forEach {
1135+
assertEquals(
1136+
ScenarioSecurity(
1137+
default = ROLE_NONE,
1138+
mutableListOf(ScenarioAccessControl(TEST_USER_MAIL, ROLE_VIEWER))),
1139+
it.security)
1140+
assertEquals(1, it.security!!.accessControlList.size)
1141+
}
1142+
}
1143+
10861144
private fun makeWorkspaceEventHubInfo(eventHubAvailable: Boolean): WorkspaceEventHubInfo {
10871145
return WorkspaceEventHubInfo(
10881146
eventHubNamespace = "eventHubNamespace",

scenario/src/integrationTest/kotlin/com/cosmotech/scenario/service/ScenarioServiceRBACTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,7 +4480,7 @@ class ScenarioServiceRBACTest : CsmRedisTestBase() {
44804480
@TestFactory
44814481
fun `test Scenario RBAC getScenarioPermissions`() =
44824482
mapOf(
4483-
ROLE_VIEWER to false,
4483+
ROLE_VIEWER to true,
44844484
ROLE_EDITOR to false,
44854485
ROLE_VALIDATOR to false,
44864486
ROLE_NONE to true,
@@ -4802,7 +4802,7 @@ class ScenarioServiceRBACTest : CsmRedisTestBase() {
48024802
@TestFactory
48034803
fun `test Scenario RBAC getScenarioSecurity`() =
48044804
mapOf(
4805-
ROLE_VIEWER to false,
4805+
ROLE_VIEWER to true,
48064806
ROLE_EDITOR to false,
48074807
ROLE_VALIDATOR to false,
48084808
ROLE_NONE to true,
@@ -5902,7 +5902,7 @@ class ScenarioServiceRBACTest : CsmRedisTestBase() {
59025902
@TestFactory
59035903
fun `test Scenario RBAC getScenarioAccessControl`() =
59045904
mapOf(
5905-
ROLE_VIEWER to false,
5905+
ROLE_VIEWER to true,
59065906
ROLE_EDITOR to false,
59075907
ROLE_VALIDATOR to false,
59085908
ROLE_NONE to true,
@@ -6986,7 +6986,7 @@ class ScenarioServiceRBACTest : CsmRedisTestBase() {
69866986
@TestFactory
69876987
fun `test Scenario RBAC getScenarioSecurityUsers`() =
69886988
mapOf(
6989-
ROLE_VIEWER to false,
6989+
ROLE_VIEWER to true,
69906990
ROLE_EDITOR to false,
69916991
ROLE_VALIDATOR to false,
69926992
ROLE_NONE to true,

scenario/src/main/kotlin/com/cosmotech/scenario/service/ScenarioServiceImpl.kt

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import com.cosmotech.dataset.DatasetApiServiceInterface
4343
import com.cosmotech.dataset.domain.IngestionStatusEnum
4444
import com.cosmotech.dataset.domain.SubDatasetGraphQuery
4545
import com.cosmotech.dataset.service.getRbac
46+
import com.cosmotech.organization.service.getRbac
4647
import com.cosmotech.scenario.ScenarioApiServiceInterface
4748
import com.cosmotech.scenario.domain.Scenario
4849
import com.cosmotech.scenario.domain.ScenarioAccessControl
@@ -432,15 +433,21 @@ internal class ScenarioServiceImpl(
432433
workspaceService.getVerifiedWorkspace(organizationId, workspaceId)
433434
val defaultPageSize = csmPlatformProperties.twincache.scenario.defaultPageSize
434435
val pageable = constructPageRequest(page, size, defaultPageSize)
436+
var scenarios = listOf<Scenario>()
435437
if (pageable != null) {
436-
return this.findPaginatedScenariosStateOption(
437-
organizationId, workspaceId, pageable.pageNumber, pageable.pageSize, true)
438-
}
439-
return findAllPaginated(defaultPageSize) {
440-
this.findPaginatedScenariosStateOption(
441-
organizationId, workspaceId, it.pageNumber, it.pageSize, true)
442-
.toMutableList()
438+
scenarios =
439+
this.findPaginatedScenariosStateOption(
440+
organizationId, workspaceId, pageable.pageNumber, pageable.pageSize, true)
441+
} else {
442+
scenarios =
443+
findAllPaginated(defaultPageSize) {
444+
this.findPaginatedScenariosStateOption(
445+
organizationId, workspaceId, it.pageNumber, it.pageSize, true)
446+
.toMutableList()
447+
}
443448
}
449+
scenarios.forEach { it.security = updateSecurityVisibility(it).security }
450+
return scenarios
444451
}
445452

446453
override fun findAllScenariosByValidationStatus(
@@ -590,7 +597,8 @@ internal class ScenarioServiceImpl(
590597
scenarioId: String
591598
): Scenario {
592599
checkInternalResultDataServiceConfiguration()
593-
return findScenarioById(organizationId, workspaceId, scenarioId, withState = true)
600+
val scenario = findScenarioById(organizationId, workspaceId, scenarioId, withState = true)
601+
return updateSecurityVisibility(scenario)
594602
}
595603

596604
override fun findScenarioById(
@@ -1167,4 +1175,24 @@ internal class ScenarioServiceImpl(
11671175
throw NotImplementedException(notImplementedExceptionMessage)
11681176
}
11691177
}
1178+
1179+
fun updateSecurityVisibility(scenario: Scenario): Scenario {
1180+
if (csmRbac.check(scenario.getRbac(), PERMISSION_READ_SECURITY).not()) {
1181+
val username = getCurrentAccountIdentifier(csmPlatformProperties)
1182+
val retrievedAC = scenario.security!!.accessControlList.firstOrNull { it.id == username }
1183+
return if (retrievedAC != null) {
1184+
scenario.copy(
1185+
security =
1186+
ScenarioSecurity(
1187+
default = scenario.security!!.default,
1188+
accessControlList = mutableListOf(retrievedAC)))
1189+
} else {
1190+
scenario.copy(
1191+
security =
1192+
ScenarioSecurity(
1193+
default = scenario.security!!.default, accessControlList = mutableListOf()))
1194+
}
1195+
}
1196+
return scenario
1197+
}
11701198
}

solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ class SolutionServiceIntegrationTest : CsmRedisTestBase() {
126126
runTemplates =
127127
mutableListOf(RunTemplate(id = "one", name = "name_one"), RunTemplate(id = "two")))
128128
// Assert that no runTemplate were deleted
129-
assertEquals(expectedSolution.runTemplates.size, endTemplates.size)
130-
assertEquals(expectedSolution.runTemplates, endTemplates)
129+
assertEquals(expectedSolution.runTemplates!!.size, endTemplates.size)
130+
assertEquals(expectedSolution.runTemplates!!, endTemplates)
131131
}
132132

133133
@Test
@@ -389,7 +389,7 @@ class SolutionServiceIntegrationTest : CsmRedisTestBase() {
389389

390390
assertNotNull(solutionWithNullRunTemplatesSaved)
391391
assertNotNull(solutionWithNullRunTemplatesSaved.runTemplates)
392-
assertEquals(0, solutionWithNullRunTemplatesSaved.runTemplates.size)
392+
assertEquals(0, solutionWithNullRunTemplatesSaved.runTemplates!!.size)
393393
}
394394

395395
@Test
@@ -402,7 +402,7 @@ class SolutionServiceIntegrationTest : CsmRedisTestBase() {
402402

403403
assertNotNull(solutionWithNullRunTemplatesSaved)
404404
assertNotNull(solutionWithNullRunTemplatesSaved.runTemplates)
405-
assertEquals(0, solutionWithNullRunTemplatesSaved.runTemplates.size)
405+
assertEquals(0, solutionWithNullRunTemplatesSaved.runTemplates!!.size)
406406
}
407407

408408
@Test
@@ -531,7 +531,10 @@ class SolutionServiceIntegrationTest : CsmRedisTestBase() {
531531
@Test
532532
fun `test update solution with runTemplates null`() {
533533

534-
val baseSolution = makeSolution(organizationSaved.id!!, runTemplates = null)
534+
val baseSolution =
535+
makeSolution(
536+
organizationSaved.id!!,
537+
)
535538
val baseSolutionSaved = solutionApiService.createSolution(organizationSaved.id!!, baseSolution)
536539

537540
val assertThrows =

0 commit comments

Comments
 (0)