diff --git a/common/src/main/kotlin/com/cosmotech/common/config/CsmPlatformProperties.kt b/common/src/main/kotlin/com/cosmotech/common/config/CsmPlatformProperties.kt index 01b71cf87..0d4df9db5 100644 --- a/common/src/main/kotlin/com/cosmotech/common/config/CsmPlatformProperties.kt +++ b/common/src/main/kotlin/com/cosmotech/common/config/CsmPlatformProperties.kt @@ -73,6 +73,9 @@ data class CsmPlatformProperties( /** The JWT Claim where the mail information is stored */ val mailJwtClaim: String = "preferred_username", + /** The JWT Claim where the groups information are stored */ + val groupJwtClaim: String = "groups", + /** The JWT Claim where the roles information is stored */ val rolesJwtClaim: String = "roles", diff --git a/common/src/main/kotlin/com/cosmotech/common/rbac/CsmRbac.kt b/common/src/main/kotlin/com/cosmotech/common/rbac/CsmRbac.kt index c52e95a46..107d5c18e 100644 --- a/common/src/main/kotlin/com/cosmotech/common/rbac/CsmRbac.kt +++ b/common/src/main/kotlin/com/cosmotech/common/rbac/CsmRbac.kt @@ -8,6 +8,7 @@ import com.cosmotech.common.exceptions.CsmClientException import com.cosmotech.common.exceptions.CsmResourceNotFoundException import com.cosmotech.common.rbac.model.RbacAccessControl import com.cosmotech.common.rbac.model.RbacSecurity +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -29,7 +30,8 @@ open class CsmRbac( val accessControls = mutableListOf() objectSecurity.accessControlList.forEach { if (accessControls.contains(it.id)) { - throw IllegalArgumentException("User ${it.id} is referenced multiple times in the security") + throw IllegalArgumentException( + "Entity ${it.id} is referenced multiple times in the security") } accessControls.add(it.id) } @@ -63,17 +65,19 @@ open class CsmRbac( permission: String, rolesDefinition: RolesDefinition = getCommonRolesDefinition() ): Boolean { - logger.info("RBAC ${rbacSecurity.id} - Verifying permission $permission for user") + logger.info("RBAC ${rbacSecurity.id} - Verifying permission $permission for entity") if (!this.csmPlatformProperties.rbac.enabled) { logger.debug("RBAC ${rbacSecurity.id} - RBAC check not enabled") return true } - var userIsAdminOrHasPermission = this.isAdmin(rbacSecurity, rolesDefinition) - if (!userIsAdminOrHasPermission) { - val user = getCurrentAccountIdentifier(this.csmPlatformProperties) - userIsAdminOrHasPermission = this.verifyRbac(rbacSecurity, permission, rolesDefinition, user) + var entityIsAdminOrHasPermission = this.isAdmin(rbacSecurity, rolesDefinition) + if (!entityIsAdminOrHasPermission) { + val entity = getCurrentAccountIdentifier(this.csmPlatformProperties) + val groups = getCurrentAccountGroups(this.csmPlatformProperties) + entityIsAdminOrHasPermission = + this.verifyRbac(rbacSecurity, permission, rolesDefinition, entity, groups) } - return userIsAdminOrHasPermission + return entityIsAdminOrHasPermission } fun setDefault( @@ -89,33 +93,35 @@ open class CsmRbac( return rbacSecurity } - fun addUserRole( + fun addEntityRole( parentRbacSecurity: RbacSecurity, rbacSecurity: RbacSecurity, - userId: String, + entityId: String, role: String, rolesDefinition: RolesDefinition = getCommonRolesDefinition() ): RbacSecurity { if (!isAdmin(rbacSecurity, rolesDefinition)) { - this.checkUserExists( + this.checkEntityExists( parentRbacSecurity, - userId, - "User $userId not found in parent ${parentRbacSecurity.id} component") + entityId, + "Entity $entityId not found in parent ${parentRbacSecurity.id} component") } - return setUserRole(rbacSecurity, userId, role, rolesDefinition) + return setEntityRole(rbacSecurity, entityId, role, rolesDefinition) } - fun setUserRole( + fun setEntityRole( rbacSecurity: RbacSecurity, - userId: String, + entityId: String, role: String, rolesDefinition: RolesDefinition = getCommonRolesDefinition() ): RbacSecurity { - logger.info("RBAC ${rbacSecurity.id} - Setting user $userId roles") + logger.info("RBAC ${rbacSecurity.id} - Setting entity $entityId roles") this.verifyRoleOrThrow(rbacSecurity, role, rolesDefinition) val currentACLRole = - rbacSecurity.accessControlList.firstOrNull { it.id.lowercase() == userId.lowercase() }?.role + rbacSecurity.accessControlList + .firstOrNull { it.id.lowercase() == entityId.lowercase() } + ?.role val adminRole = this.getAdminRole(rolesDefinition) if (currentACLRole == adminRole && role != adminRole && @@ -124,48 +130,48 @@ open class CsmRbac( "RBAC ${rbacSecurity.id} - It is forbidden to unset the last administrator") } val accessList = rbacSecurity.accessControlList - val userAccess = accessList.find { it.id == userId } - if (userAccess == null) { - accessList.add(RbacAccessControl(userId, role)) + val entityAccess = accessList.find { it.id == entityId } + if (entityAccess == null) { + accessList.add(RbacAccessControl(entityId, role)) } else { - userAccess.role = role + entityAccess.role = role } return rbacSecurity } - fun getUsers(rbacSecurity: RbacSecurity): List { + fun getEntities(rbacSecurity: RbacSecurity): List { return (rbacSecurity.accessControlList.map { it.id }) } - fun getAccessControl(rbacSecurity: RbacSecurity, userId: String): RbacAccessControl { - return rbacSecurity.accessControlList.find { it.id == userId } + fun getAccessControl(rbacSecurity: RbacSecurity, entityId: String): RbacAccessControl { + return rbacSecurity.accessControlList.find { it.id == entityId } ?: throw CsmResourceNotFoundException( - "User $userId not found in ${rbacSecurity.id} component") + "Entity $entityId not found in ${rbacSecurity.id} component") } - fun checkUserExists( + fun checkEntityExists( rbacSecurity: RbacSecurity, - userId: String, - exceptionUserNotFoundMessage: String + entityId: String, + exceptionEntityNotFoundMessage: String ): RbacAccessControl { - return rbacSecurity.accessControlList.find { it.id == userId } - ?: throw CsmResourceNotFoundException(exceptionUserNotFoundMessage) + return rbacSecurity.accessControlList.find { it.id == entityId } + ?: throw CsmResourceNotFoundException(exceptionEntityNotFoundMessage) } - fun removeUser( + fun removeEntity( rbacSecurity: RbacSecurity, - userId: String, + entityId: String, rolesDefinition: RolesDefinition = getCommonRolesDefinition() ): RbacSecurity { - logger.info("RBAC ${rbacSecurity.id} - Removing user $userId from security") - checkUserExists(rbacSecurity, userId, "User $userId not found") - val role = this.getUserRole(rbacSecurity, userId) + logger.info("RBAC ${rbacSecurity.id} - Removing entity $entityId from security") + checkEntityExists(rbacSecurity, entityId, "Entity $entityId not found") + val role = this.getEntityRole(rbacSecurity, entityId) if (role == (this.getAdminRole(rolesDefinition)) && this.getAdminCount(rbacSecurity, rolesDefinition) == 1) { throw CsmAccessForbiddenException( "RBAC ${rbacSecurity.id} - It is forbidden to remove the last administrator") } - rbacSecurity.accessControlList.removeIf { it.id == userId } + rbacSecurity.accessControlList.removeIf { it.id == entityId } return rbacSecurity } @@ -173,7 +179,8 @@ open class CsmRbac( var isAdmin = this.isAdminToken(rbacSecurity) if (!isAdmin) { val user = getCurrentAccountIdentifier(this.csmPlatformProperties) - isAdmin = this.verifyAdminRole(rbacSecurity, user, rolesDefinition) + val groups = getCurrentAccountGroups(this.csmPlatformProperties) + isAdmin = this.verifyAdminRole(rbacSecurity, user, groups, rolesDefinition) } return isAdmin } @@ -181,10 +188,18 @@ open class CsmRbac( internal fun verifyAdminRole( rbacSecurity: RbacSecurity, user: String, + groups: List, rolesDefinition: RolesDefinition ): Boolean { logger.debug("RBAC ${rbacSecurity.id} - Verifying if $user has default admin rbac role") - val isAdmin = this.getUserRole(rbacSecurity, user) == this.getAdminRole(rolesDefinition) + val isAdmin = + if (rbacSecurity.accessControlList.any() { it.id == user }) { + this.getEntityRole(rbacSecurity, user) == this.getAdminRole(rolesDefinition) + } else { + groups.any { + this.getEntityRole(rbacSecurity, it) == this.getAdminRole(rolesDefinition) + } || rbacSecurity.default == this.getAdminRole(rolesDefinition) + } logger.debug("RBAC ${rbacSecurity.id} - $user has default admin rbac role: $isAdmin") return isAdmin } @@ -193,11 +208,18 @@ open class CsmRbac( rbacSecurity: RbacSecurity, permission: String, rolesDefinition: RolesDefinition, - user: String + user: String, + groups: List ): Boolean { logger.debug("RBAC ${rbacSecurity.id} - Verifying $user has permission in ACL: $permission") val isAuthorized = - this.verifyPermissionFromRole(permission, getUserRole(rbacSecurity, user), rolesDefinition) + if (rbacSecurity.accessControlList.any() { it.id == user }) { + verifyPermissionFromRole(permission, getEntityRole(rbacSecurity, user), rolesDefinition) + } else { + groups.any { + verifyPermissionFromRole(permission, getEntityRole(rbacSecurity, it), rolesDefinition) + } || verifyPermissionFromRole(permission, rbacSecurity.default, rolesDefinition) + } logger.debug("RBAC ${rbacSecurity.id} - $user has permission $permission in ACL: $isAuthorized") return isAuthorized } @@ -219,10 +241,11 @@ open class CsmRbac( rbacSecurity: RbacSecurity, permission: String, rolesDefinition: RolesDefinition, - user: String + user: String, + groups: List ): Boolean { return (this.verifyDefault(rbacSecurity, permission, rolesDefinition) || - this.verifyUser(rbacSecurity, permission, rolesDefinition, user)) + this.verifyUser(rbacSecurity, permission, rolesDefinition, user, groups)) } internal fun verifyPermissionFromRole( @@ -241,9 +264,9 @@ open class CsmRbac( return rolesDefinition[role] ?: listOf() } - internal fun getUserRole(rbacSecurity: RbacSecurity, user: String): String { + internal fun getEntityRole(rbacSecurity: RbacSecurity, entity: String): String { return rbacSecurity.accessControlList - .firstOrNull { it.id.lowercase() == user.lowercase() } + .firstOrNull { it.id.lowercase() == entity.lowercase() } ?.role ?: rbacSecurity.default } @@ -263,8 +286,8 @@ open class CsmRbac( throw CsmClientException("RBAC ${rbacSecurity.id} - Role $role does not exist") } - internal fun verifyPermission(permission: String, userPermissions: List): Boolean { - return userPermissions.contains(permission) + internal fun verifyPermission(permission: String, entityPermissions: List): Boolean { + return entityPermissions.contains(permission) } internal fun verifyPermissionFromRoles( @@ -276,9 +299,9 @@ open class CsmRbac( } internal fun isAdminToken(rbacSecurity: RbacSecurity): Boolean { - logger.debug("RBAC ${rbacSecurity.id} - Verifying if user has platform admin role in token") + logger.debug("RBAC ${rbacSecurity.id} - Verifying if entity has platform admin role in token") val isAdmin = csmAdmin.verifyCurrentRolesAdmin() - logger.debug("RBAC ${rbacSecurity.id} - user has platform admin role in token: $isAdmin") + logger.debug("RBAC ${rbacSecurity.id} - entity has platform admin role in token: $isAdmin") return isAdmin } diff --git a/common/src/main/kotlin/com/cosmotech/common/utils/SecurityUtils.kt b/common/src/main/kotlin/com/cosmotech/common/utils/SecurityUtils.kt index cf0074236..626d397bc 100644 --- a/common/src/main/kotlin/com/cosmotech/common/utils/SecurityUtils.kt +++ b/common/src/main/kotlin/com/cosmotech/common/utils/SecurityUtils.kt @@ -55,6 +55,17 @@ fun getCurrentAccountIdentifier(configuration: CsmPlatformProperties): String { } } +fun getCurrentAccountGroups(configuration: CsmPlatformProperties): List { + return (getValueFromAuthenticatedToken(configuration) { + try { + val jwt = JWTParser.parse(it) + jwt.jwtClaimsSet.getStringListClaim(configuration.authorization.groupJwtClaim) + } catch (e: ParseException) { + JSONObjectUtils.parse(it)[configuration.authorization.groupJwtClaim] as List + } + } ?: emptyList()) +} + fun getCurrentAuthenticatedRoles(configuration: CsmPlatformProperties): List { return (getValueFromAuthenticatedToken(configuration) { try { diff --git a/common/src/test/kotlin/com/cosmotech/common/rbac/CsmRbacTests.kt b/common/src/test/kotlin/com/cosmotech/common/rbac/CsmRbacTests.kt index 8674d6a33..e50268e89 100644 --- a/common/src/test/kotlin/com/cosmotech/common/rbac/CsmRbacTests.kt +++ b/common/src/test/kotlin/com/cosmotech/common/rbac/CsmRbacTests.kt @@ -46,6 +46,12 @@ const val USER_ADMIN_2 = "usertestadmin2@cosmotech.com" const val USER_NOTIN = "usertestnotin@cosmotech.com" const val USER_MAIL_TOKEN = "john.doe@cosmotech.com" +const val GROUP_NONE = "group_none" +const val GROUP_READER = "group_reader" +const val GROUP_USER = "group_user" +const val GROUP_EDITOR = "group_editor" +const val GROUP_ADMIN = "group_admin" + const val USER_NEW_READER = "usertestnew@cosmotech.com" const val APP_REG_ID = "f6fbd519-9a53-4c6b-aabb-dfre52s16742" @@ -99,6 +105,7 @@ class CsmRbacTests { every { csmPlatformProperties.rbac.enabled } answers { true } every { csmPlatformProperties.authorization.rolesJwtClaim } answers { "roles" } every { csmPlatformProperties.authorization.mailJwtClaim } answers { "upn" } + every { csmPlatformProperties.authorization.groupJwtClaim } answers { "user_groups" } every { csmPlatformProperties.authorization.applicationIdJwtClaim } answers { "oid" } every { csmPlatformProperties.identityProvider } answers { DEFAULT_IDENTITY_PROVIDER } rolesDefinition = @@ -146,6 +153,8 @@ class CsmRbacTests { mockkStatic(::getCurrentAuthenticatedRoles) every { getCurrentAccountIdentifier(csmPlatformProperties) } returns USER_NOTIN + every { getCurrentAccountGroups(csmPlatformProperties) } returns + listOf(GROUP_NONE, GROUP_READER, GROUP_USER, GROUP_EDITOR, GROUP_ADMIN) } @Test @@ -255,27 +264,28 @@ class CsmRbacTests { @Test fun `find role for user from resource security`() { - assertEquals(ROLE_READER, rbac.getUserRole(rbacSecurity, USER_READER)) + assertEquals(ROLE_READER, rbac.getEntityRole(rbacSecurity, USER_READER)) } @Test fun `find roles for admin from resource security`() { - assertEquals(ROLE_ADMIN, rbac.getUserRole(rbacSecurity, USER_ADMIN)) + assertEquals(ROLE_ADMIN, rbac.getEntityRole(rbacSecurity, USER_ADMIN)) } @Test fun `verify permission read for user writer OK`() { - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_READER)) + assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_READER, emptyList())) } @Test fun `verify permission write for user writer KO`() { - assertFalse(rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_READER)) + assertFalse( + rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_READER, emptyList())) } @Test fun `verify permission read for user none KO`() { - assertFalse(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NONE)) + assertFalse(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NONE, emptyList())) } @Test @@ -290,20 +300,22 @@ class CsmRbacTests { @Test fun `add new reader user and verify read permission OK`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `add new reader user and verify write permission KO`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - assertFalse(rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + assertFalse( + rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `adding a user with role none throws exception`() { assertThrows { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, ROLE_NONE, rolesDefinition) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, ROLE_NONE, rolesDefinition) } } @@ -313,7 +325,7 @@ class CsmRbacTests { every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) assertThrows { - rbac.addUserRole( + rbac.addEntityRole( parentRbacSecurity, rbacSecurity, USER_NOTIN, USER_READER_ROLE, rolesDefinition) } } @@ -324,9 +336,10 @@ class CsmRbacTests { every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) val rbacSecurity = - rbac.addUserRole( + rbac.addEntityRole( parentRbacSecurity, rbacSecurity, USER_IN_PARENT, USER_READER_ROLE, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_IN_PARENT)) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_IN_PARENT, emptyList())) } @Test @@ -334,65 +347,70 @@ class CsmRbacTests { every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_PLATFORM_ADMIN) val rbacSecurity = - rbac.addUserRole( + rbac.addEntityRole( parentRbacSecurity, rbacSecurity, USER_NOTIN, USER_READER_ROLE, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NOTIN)) + assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NOTIN, emptyList())) } @Test fun `remove new reader user and verify read permission KO with default none`() { rbacSecurity = RbacSecurity(COMPONENT_ID, ROLE_NONE, mutableListOf()) - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - rbac.removeUser(rbacSecurity, USER_NEW_READER, rolesDefinition) - assertFalse(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_NEW_READER, rolesDefinition) + assertFalse( + rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `remove new reader user and verify read permission OK with default reader`() { rbacSecurity = RbacSecurity(COMPONENT_ID, ROLE_READER, mutableListOf()) - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - rbac.removeUser(rbacSecurity, USER_NEW_READER, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_NEW_READER, rolesDefinition) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `remove new reader user and verify read permission OK with default admin`() { rbacSecurity = RbacSecurity(COMPONENT_ID, ROLE_ADMIN, mutableListOf()) - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - rbac.removeUser(rbacSecurity, USER_NEW_READER, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_ADMIN, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_NEW_READER, rolesDefinition) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_ADMIN, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `update existing new user and verify write permission OK`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_WRITER_ROLE, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_WRITER_ROLE, rolesDefinition) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_WRITE, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `update existing new user and verify read permission OK`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) - assertTrue(rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER)) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_READER_ROLE, rolesDefinition) + assertTrue( + rbac.verifyUser(rbacSecurity, PERM_READ, rolesDefinition, USER_NEW_READER, emptyList())) } @Test fun `user with no roles has default read permission`() { - assertTrue(rbac.verifyRbac(rbacSecurity, PERM_READ, rolesDefinition, USER_NONE)) + assertTrue(rbac.verifyRbac(rbacSecurity, PERM_READ, rolesDefinition, USER_NONE, emptyList())) } @Test fun `update default security to no roles and verify read OK for reader user`() { rbac.setDefault(rbacSecurity, USER_READER_ROLE, rolesDefinition) - assertTrue(rbac.verifyRbac(rbacSecurity, PERM_READ, rolesDefinition, USER_READER)) + assertTrue(rbac.verifyRbac(rbacSecurity, PERM_READ, rolesDefinition, USER_READER, emptyList())) } @Test fun `update default security to writer role and verify write OK for reader user`() { rbac.setDefault(rbacSecurity, USER_WRITER_ROLE, rolesDefinition) - assertTrue(rbac.verifyRbac(rbacSecurity, PERM_WRITE, rolesDefinition, USER_READER)) + assertTrue(rbac.verifyRbac(rbacSecurity, PERM_WRITE, rolesDefinition, USER_READER, emptyList())) } @Test @@ -529,14 +547,14 @@ class CsmRbacTests { fun `user has admin role`() { every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) - assertTrue(rbac.verifyAdminRole(rbacSecurity, USER_ADMIN, rolesDefinition)) + assertTrue(rbac.verifyAdminRole(rbacSecurity, USER_ADMIN, emptyList(), rolesDefinition)) } @Test fun `user has not admin role`() { every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) - assertFalse(rbac.verifyAdminRole(rbacSecurity, USER_READER, rolesDefinition)) + assertFalse(rbac.verifyAdminRole(rbacSecurity, USER_READER, emptyList(), rolesDefinition)) } @Test @@ -569,37 +587,37 @@ class CsmRbacTests { @Test fun `get count of users with new admin role`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_ADMIN_ROLE, rolesDefinition) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_ADMIN_ROLE, rolesDefinition) assertEquals(2, rbac.getAdminCount(rbacSecurity, rolesDefinition)) } @Test fun `throw exception if last admin deleted`() { assertThrows { - rbac.removeUser(rbacSecurity, USER_ADMIN, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_ADMIN, rolesDefinition) } } @Test fun `throw exception if last admin from two is deleted`() { - rbac.setUserRole(rbacSecurity, USER_NEW_READER, USER_ADMIN_ROLE, rolesDefinition) - rbac.removeUser(rbacSecurity, USER_NEW_READER, rolesDefinition) + rbac.setEntityRole(rbacSecurity, USER_NEW_READER, USER_ADMIN_ROLE, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_NEW_READER, rolesDefinition) assertThrows { - rbac.removeUser(rbacSecurity, USER_ADMIN, rolesDefinition) + rbac.removeEntity(rbacSecurity, USER_ADMIN, rolesDefinition) } } @Test fun `throw exception if last admin removed from setRole`() { assertThrows { - rbac.setUserRole(rbacSecurity, USER_ADMIN, USER_READER_ROLE, rolesDefinition) + rbac.setEntityRole(rbacSecurity, USER_ADMIN, USER_READER_ROLE, rolesDefinition) } } @Test fun `throw exception if role does not exist with setRole`() { assertThrows { - rbac.setUserRole(rbacSecurity, USER_READER, ROLE_NOTIN, rolesDefinition) + rbac.setEntityRole(rbacSecurity, USER_READER, ROLE_NOTIN, rolesDefinition) } } @@ -607,7 +625,7 @@ class CsmRbacTests { fun `get user list`() { assertEquals( listOf(USER_WRITER, USER_READER, USER_NONE, USER_ADMIN, USER_MAIL_TOKEN, APP_REG_ID), - rbac.getUsers(rbacSecurity)) + rbac.getEntities(rbacSecurity)) } @Test @@ -679,7 +697,7 @@ class CsmRbacTests { val customRolePermissions = listOf(PERMISSION_READ, customPermission) definition.permissions.put(customRole, customRolePermissions) val rbacTest = CsmRbac(csmPlatformProperties, admin) - rbacTest.setUserRole(rbacSecurity, USER_NEW_READER, customRole, definition) + rbacTest.setEntityRole(rbacSecurity, USER_NEW_READER, customRole, definition) every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) every { getCurrentAccountIdentifier(csmPlatformProperties) } returns USER_NEW_READER @@ -691,7 +709,7 @@ class CsmRbacTests { fun `can add resource id and resource security in a second step`() { val definition = getCommonRolesDefinition() val rbacTest = CsmRbac(csmPlatformProperties, admin) - rbacTest.setUserRole(rbacSecurity, USER_READER, ROLE_VIEWER, definition) + rbacTest.setEntityRole(rbacSecurity, USER_READER, ROLE_VIEWER, definition) every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns listOf(ROLE_ORGANIZATION_USER) every { getCurrentAccountIdentifier(csmPlatformProperties) } returns USER_READER @@ -711,7 +729,7 @@ class CsmRbacTests { mutableListOf( RbacAccessControl(id = "test.user@test.com", role = ROLE_ADMIN))) val newUserId = "whatever.user@test.com" - rbac.setUserRole(rbacDefinition, newUserId, role, getCommonRolesDefinition()) + rbac.setEntityRole(rbacDefinition, newUserId, role, getCommonRolesDefinition()) assertTrue(rbacDefinition.accessControlList.size == 2) assertTrue( rbacDefinition.accessControlList.contains( @@ -734,14 +752,14 @@ class CsmRbacTests { if (shouldThrows) { val assertThrows = assertThrows { - rbac.setUserRole(rbacDefinition, userId, role, getCommonRolesDefinition()) + rbac.setEntityRole(rbacDefinition, userId, role, getCommonRolesDefinition()) } assertEquals( "RBAC ${rbacDefinition.id} - It is forbidden to unset the last administrator", assertThrows.message) } else { assertDoesNotThrow { - rbac.setUserRole(rbacDefinition, userId, role, getCommonRolesDefinition()) + rbac.setEntityRole(rbacDefinition, userId, role, getCommonRolesDefinition()) assertTrue(rbacDefinition.accessControlList.size == 1) assertTrue( rbacDefinition.accessControlList.contains( @@ -765,7 +783,7 @@ class CsmRbacTests { mutableListOf(RbacAccessControl(id = userId, role = ROLE_ADMIN))) val assertThrows = assertThrows { - rbac.removeUser(rbacDefinition, userId, getCommonRolesDefinition()) + rbac.removeEntity(rbacDefinition, userId, getCommonRolesDefinition()) } assertEquals( "RBAC ${rbacDefinition.id} - It is forbidden to remove the last administrator", @@ -788,7 +806,7 @@ class CsmRbacTests { RbacAccessControl(id = USER_ADMIN, role = ROLE_ADMIN), RbacAccessControl(id = userId, role = role))) assertDoesNotThrow { - rbac.removeUser(rbacDefinition, userId, getCommonRolesDefinition()) + rbac.removeEntity(rbacDefinition, userId, getCommonRolesDefinition()) assertTrue(rbacDefinition.accessControlList.size == 1) assertTrue( rbacDefinition.accessControlList.contains( @@ -919,7 +937,7 @@ class CsmRbacTests { @Test fun `when removing throw 404 if user not exists`() { - assertThrows { rbac.removeUser(rbacSecurity, USER_NOTIN) } + assertThrows { rbac.removeEntity(rbacSecurity, USER_NOTIN) } } @Test @@ -969,7 +987,8 @@ class CsmRbacTests { listOf(ROLE_ORGANIZATION_USER) every { getCurrentAccountIdentifier(csmPlatformProperties) } returns APP_REG_ID assertTrue( - rbac.verifyRbac(rbacSecurity, PERMISSION_READ, getCommonRolesDefinition(), APP_REG_ID)) + rbac.verifyRbac( + rbacSecurity, PERMISSION_READ, getCommonRolesDefinition(), APP_REG_ID, emptyList())) } @Test @@ -1021,4 +1040,34 @@ class CsmRbacTests { RbacAccessControl(USER_NOTIN, ROLE_ADMIN))), security) } + + @Test + fun `user with multiple group permissions use the highest one`() { + every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns + listOf(ROLE_ORGANIZATION_USER) + rbacSecurity = + RbacSecurity( + COMPONENT_ID, + ROLE_NONE, + mutableListOf( + RbacAccessControl(GROUP_ADMIN, ROLE_ADMIN), + RbacAccessControl(GROUP_EDITOR, ROLE_EDITOR), + RbacAccessControl(GROUP_READER, ROLE_READER), + RbacAccessControl(GROUP_NONE, ROLE_NONE))) + assertTrue(rbac.check(rbacSecurity, PERMISSION_WRITE_SECURITY, getCommonRolesDefinition())) + } + + @Test + fun `user with both groups and mail permissions use the more precise one`() { + every { getCurrentAuthenticatedRoles(csmPlatformProperties) } returns + listOf(ROLE_ORGANIZATION_USER) + rbacSecurity = + RbacSecurity( + COMPONENT_ID, + ROLE_NONE, + mutableListOf( + RbacAccessControl(GROUP_EDITOR, ROLE_EDITOR), + RbacAccessControl(USER_NOTIN, ROLE_NONE))) + assertFalse(rbac.check(rbacSecurity, PERMISSION_READ, getCommonRolesDefinition())) + } } diff --git a/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceIntegrationTest.kt b/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceIntegrationTest.kt index 086f8eb72..f8be664d0 100644 --- a/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceIntegrationTest.kt +++ b/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceIntegrationTest.kt @@ -11,6 +11,7 @@ import com.cosmotech.common.rbac.ROLE_EDITOR import com.cosmotech.common.rbac.ROLE_NONE import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -119,6 +120,7 @@ class DatasetServiceIntegrationTest() : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceRBACTest.kt b/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceRBACTest.kt index 615f9bb65..3252f3725 100644 --- a/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceRBACTest.kt +++ b/dataset/src/integrationTest/kotlin/com/cosmotech/dataset/service/DatasetServiceRBACTest.kt @@ -16,6 +16,7 @@ import com.cosmotech.common.rbac.ROLE_NONE import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -110,6 +111,7 @@ class DatasetServiceRBACTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/dataset/src/main/kotlin/com/cosmotech/dataset/service/DatasetServiceImpl.kt b/dataset/src/main/kotlin/com/cosmotech/dataset/service/DatasetServiceImpl.kt index 0719624b3..23c1cdd87 100644 --- a/dataset/src/main/kotlin/com/cosmotech/dataset/service/DatasetServiceImpl.kt +++ b/dataset/src/main/kotlin/com/cosmotech/dataset/service/DatasetServiceImpl.kt @@ -121,7 +121,7 @@ class DatasetServiceImpl( require(!users.contains(datasetAccessControl.id)) { "User is already in this Dataset security" } val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( dataset.security.toGenericSecurity(datasetId), datasetAccessControl.id, datasetAccessControl.role) @@ -227,7 +227,7 @@ class DatasetServiceImpl( val dataset = getVerifiedDataset(organizationId, workspaceId, datasetId, PERMISSION_READ_SECURITY) - return csmRbac.getUsers(dataset.security.toGenericSecurity(datasetId)) + return csmRbac.getEntities(dataset.security.toGenericSecurity(datasetId)) } override fun listDatasets( @@ -285,7 +285,8 @@ class DatasetServiceImpl( val dataset = getVerifiedDataset(organizationId, workspaceId, datasetId, PERMISSION_WRITE_SECURITY) - val rbacSecurity = csmRbac.removeUser(dataset.security.toGenericSecurity(datasetId), identityId) + val rbacSecurity = + csmRbac.removeEntity(dataset.security.toGenericSecurity(datasetId), identityId) dataset.security = rbacSecurity.toResourceSecurity() save(dataset) } @@ -373,12 +374,12 @@ class DatasetServiceImpl( val dataset = getVerifiedDataset(organizationId, workspaceId, datasetId, PERMISSION_WRITE_SECURITY) - csmRbac.checkUserExists( + csmRbac.checkEntityExists( dataset.security.toGenericSecurity(datasetId), identityId, "User '$identityId' not found in dataset $datasetId") val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( dataset.security.toGenericSecurity(datasetId), identityId, datasetRole.role) dataset.security = rbacSecurity.toResourceSecurity() save(dataset) diff --git a/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceIntegrationTest.kt b/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceIntegrationTest.kt index a1189a00c..e021c7e97 100644 --- a/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceIntegrationTest.kt +++ b/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceIntegrationTest.kt @@ -23,6 +23,7 @@ import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.security.ROLE_ORGANIZATION_USER import com.cosmotech.common.security.ROLE_PLATFORM_ADMIN import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -84,6 +85,7 @@ class OrganizationServiceIntegrationTest : CsmTestBase() { var startTime: Long = 0 val defaultName = "my.account-tester@cosmotech.com" + val defaultGroup = listOf("myTestGroup") @BeforeAll fun globalSetup() { @@ -94,6 +96,7 @@ class OrganizationServiceIntegrationTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns defaultName + every { getCurrentAccountGroups(any()) } returns defaultGroup every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "my.account-tester" every { getCurrentAuthenticatedRoles(any()) } returns listOf() rediSearchIndexer.createIndexFor(Organization::class.java) @@ -2229,6 +2232,7 @@ class OrganizationServiceIntegrationTest : CsmTestBase() { mockkStatic(::getCurrentAuthentication) every { getCurrentAuthentication() } returns mockk() every { getCurrentAccountIdentifier(any()) } returns TEST_USER_ID + every { getCurrentAccountGroups(any()) } returns defaultGroup every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf(ROLE_ORGANIZATION_USER) } @@ -2238,6 +2242,7 @@ class OrganizationServiceIntegrationTest : CsmTestBase() { mockkStatic(::getCurrentAuthentication) every { getCurrentAuthentication() } returns mockk() every { getCurrentAccountIdentifier(any()) } returns TEST_ADMIN_USER_ID + every { getCurrentAccountGroups(any()) } returns defaultGroup every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.admin" every { getCurrentAuthenticatedRoles(any()) } returns listOf(ROLE_PLATFORM_ADMIN) } @@ -2245,6 +2250,7 @@ class OrganizationServiceIntegrationTest : CsmTestBase() { /** Run a test with different Organization.User */ private fun runAsDifferentOrganizationUser() { every { getCurrentAccountIdentifier(any()) } returns OTHER_TEST_USER_ID + every { getCurrentAccountGroups(any()) } returns defaultGroup every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.other.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf(ROLE_ORGANIZATION_USER) } diff --git a/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceRBACTest.kt b/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceRBACTest.kt index f21a53040..7924b6462 100644 --- a/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceRBACTest.kt +++ b/organization/src/integrationTest/kotlin/com/cosmotech/organization/service/OrganizationServiceRBACTest.kt @@ -16,6 +16,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VALIDATOR import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -69,6 +70,7 @@ class OrganizationServiceRBACTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns TEST_USER_MAIL + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "my.account-tester" every { getCurrentAuthenticatedRoles(any()) } returns listOf() rediSearchIndexer.createIndexFor(Organization::class.java) diff --git a/organization/src/main/kotlin/com/cosmotech/organization/service/OrganizationServiceImpl.kt b/organization/src/main/kotlin/com/cosmotech/organization/service/OrganizationServiceImpl.kt index b131912f7..55cef6800 100644 --- a/organization/src/main/kotlin/com/cosmotech/organization/service/OrganizationServiceImpl.kt +++ b/organization/src/main/kotlin/com/cosmotech/organization/service/OrganizationServiceImpl.kt @@ -184,7 +184,7 @@ class OrganizationServiceImpl( } val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( organization.security.toGenericSecurity(organizationId), organizationAccessControl.id, organizationAccessControl.role) @@ -202,12 +202,12 @@ class OrganizationServiceImpl( organizationRole: OrganizationRole ): OrganizationAccessControl { val organization = getVerifiedOrganization(organizationId, PERMISSION_WRITE_SECURITY) - csmRbac.checkUserExists( + csmRbac.checkEntityExists( organization.security.toGenericSecurity(organizationId), identityId, "User '$identityId' not found in organization $organizationId") val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( organization.security.toGenericSecurity(organizationId), identityId, organizationRole.role) @@ -222,14 +222,14 @@ class OrganizationServiceImpl( override fun deleteOrganizationAccessControl(organizationId: String, identityId: String) { val organization = getVerifiedOrganization(organizationId, PERMISSION_WRITE_SECURITY) val rbacSecurity = - csmRbac.removeUser(organization.security.toGenericSecurity(organizationId), identityId) + csmRbac.removeEntity(organization.security.toGenericSecurity(organizationId), identityId) organization.security = rbacSecurity.toResourceSecurity() save(organization) } override fun listOrganizationSecurityUsers(organizationId: String): List { val organization = getVerifiedOrganization(organizationId, PERMISSION_READ_SECURITY) - return csmRbac.getUsers(organization.security.toGenericSecurity(organizationId)) + return csmRbac.getEntities(organization.security.toGenericSecurity(organizationId)) } override fun getVerifiedOrganization( diff --git a/organization/src/test/kotlin/com/cosmotech/organization/service/OrganizationServiceImplTests.kt b/organization/src/test/kotlin/com/cosmotech/organization/service/OrganizationServiceImplTests.kt index 1127e900a..152d8a497 100644 --- a/organization/src/test/kotlin/com/cosmotech/organization/service/OrganizationServiceImplTests.kt +++ b/organization/src/test/kotlin/com/cosmotech/organization/service/OrganizationServiceImplTests.kt @@ -16,6 +16,7 @@ import com.cosmotech.common.rbac.ROLE_VALIDATOR import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.rbac.model.RbacAccessControl import com.cosmotech.common.rbac.model.RbacSecurity +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -67,6 +68,7 @@ class OrganizationServiceImplTests { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns USER_ID + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "my.account-tester" every { getCurrentAuthenticatedRoles(any()) } returns listOf() @@ -85,8 +87,8 @@ class OrganizationServiceImplTests { val rbacAccessControl = RbacAccessControl(USER_ID, ROLE_ADMIN) every { organizationRepository.findByIdOrNull(any()) } returns organization every { csmRbac.verify(any(), any()) } returns Unit - every { csmRbac.checkUserExists(any(), any(), any()) } returns rbacAccessControl - every { csmRbac.setUserRole(any(), any(), any()) } returns rbacSecurity + every { csmRbac.checkEntityExists(any(), any(), any()) } returns rbacAccessControl + every { csmRbac.setEntityRole(any(), any(), any()) } returns rbacSecurity assertEquals(organization.security.default, rbacSecurity.default) assertEquals( @@ -108,7 +110,7 @@ class OrganizationServiceImplTests { val organization = getMockOrganization() every { organizationRepository.findByIdOrNull(any()) } returns organization every { csmRbac.verify(any(), any()) } returns Unit - every { csmRbac.checkUserExists(any(), any(), any()) } throws + every { csmRbac.checkEntityExists(any(), any(), any()) } throws mockk() val organizationRole = OrganizationRole(role = ROLE_VIEWER) assertThrows { diff --git a/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt b/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt index b987b7383..2dec54c9e 100644 --- a/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt +++ b/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt @@ -8,6 +8,7 @@ import com.cosmotech.common.events.RunStart import com.cosmotech.common.rbac.ROLE_ADMIN import com.cosmotech.common.rbac.ROLE_NONE import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -113,6 +114,7 @@ class RunServiceIntegrationTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt index 4bb614b17..6d848416a 100644 --- a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt +++ b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt @@ -19,6 +19,7 @@ import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.security.ROLE_ORGANIZATION_USER import com.cosmotech.common.security.ROLE_PLATFORM_ADMIN import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -142,6 +143,7 @@ class RunnerServiceIntegrationTest : CsmTestBase() { every { containerRegistryService.getImageLabel(any(), any(), any()) } returns null mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf(ROLE_ORGANIZATION_USER) @@ -929,7 +931,7 @@ class RunnerServiceIntegrationTest : CsmTestBase() { datasetApiService.getDatasetAccessControl( organizationSaved.id, workspaceSaved.id, retrievedDataset.id, "id") } - assertEquals("User id not found in ${retrievedDataset.id} component", exception.message) + assertEquals("Entity id not found in ${retrievedDataset.id} component", exception.message) } @Test diff --git a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceRBACTest.kt b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceRBACTest.kt index b85e3a3f7..52c0e839d 100644 --- a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceRBACTest.kt +++ b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceRBACTest.kt @@ -18,6 +18,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VALIDATOR import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -97,6 +98,7 @@ class RunnerServiceRBACTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf() diff --git a/runner/src/main/kotlin/com/cosmotech/runner/service/RunnerService.kt b/runner/src/main/kotlin/com/cosmotech/runner/service/RunnerService.kt index 57bcaa534..a792525a0 100644 --- a/runner/src/main/kotlin/com/cosmotech/runner/service/RunnerService.kt +++ b/runner/src/main/kotlin/com/cosmotech/runner/service/RunnerService.kt @@ -681,7 +681,7 @@ class RunnerService( // create a rbacSecurity object from runner Rbac by adding user with id and role in // runnerAccessControl val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( this.runner.getRbac(), runnerAccessControl.id, runnerAccessControl.role, @@ -709,14 +709,14 @@ class RunnerService( fun deleteAccessControlFor(userId: String) { // create a rbacSecurity object from runner Rbac by removing user - val rbacSecurity = csmRbac.removeUser(this.getRbacSecurity(), userId, this.roleDefinition) + val rbacSecurity = csmRbac.removeEntity(this.getRbacSecurity(), userId, this.roleDefinition) this.setRbacSecurity(rbacSecurity) this.removeAccessControlToDatasetParameter(userId) } fun checkUserExists(userId: String) { - csmRbac.checkUserExists( + csmRbac.checkEntityExists( runner.getRbac(), userId, "User '$userId' not found in runner ${runner.id}") } @@ -862,7 +862,7 @@ class RunnerService( } fun getUsers(): List { - return csmRbac.getUsers(this.getRbacSecurity()) + return csmRbac.getEntities(this.getRbacSecurity()) } fun setDefaultSecurity(role: String) { diff --git a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt index 0072e6a54..b0aa8ea51 100644 --- a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt +++ b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt @@ -13,6 +13,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.security.ROLE_PLATFORM_ADMIN import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -87,6 +88,7 @@ class SolutionServiceIntegrationTest : CsmTestBase() { solutionApiService, "containerRegistryService", containerRegistryService) every { containerRegistryService.getImageLabel(any(), any(), any()) } returns null every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceRBACTest.kt b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceRBACTest.kt index 0041a37f0..4bc84925e 100644 --- a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceRBACTest.kt +++ b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceRBACTest.kt @@ -18,6 +18,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.tests.CsmTestBase import com.cosmotech.common.utils.ResourceScanner +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -88,6 +89,8 @@ class SolutionServiceRBACTest : CsmTestBase() { solutionApiService, "containerRegistryService", containerRegistryService) every { containerRegistryService.getImageLabel(any(), any(), any()) } returns null every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") + every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/solution/src/main/kotlin/com/cosmotech/solution/service/SolutionServiceImpl.kt b/solution/src/main/kotlin/com/cosmotech/solution/service/SolutionServiceImpl.kt index 579304f29..13dcb4a7c 100644 --- a/solution/src/main/kotlin/com/cosmotech/solution/service/SolutionServiceImpl.kt +++ b/solution/src/main/kotlin/com/cosmotech/solution/service/SolutionServiceImpl.kt @@ -357,7 +357,7 @@ class SolutionServiceImpl( } val rbacSecurity = - csmRbac.addUserRole( + csmRbac.addEntityRole( organization.security.toGenericSecurity(organizationId), solution.security.toGenericSecurity(solutionId), solutionAccessControl.id, @@ -551,12 +551,12 @@ class SolutionServiceImpl( solutionRole: SolutionRole ): SolutionAccessControl { val solution = getVerifiedSolution(organizationId, solutionId, PERMISSION_WRITE_SECURITY) - csmRbac.checkUserExists( + csmRbac.checkEntityExists( solution.security.toGenericSecurity(solutionId), identityId, "User '$identityId' not found in solution $solutionId") val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( solution.security.toGenericSecurity(solutionId), identityId, solutionRole.role) solution.security = rbacSecurity.toResourceSecurity() save(solution) @@ -572,14 +572,14 @@ class SolutionServiceImpl( ) { val solution = getVerifiedSolution(organizationId, solutionId, PERMISSION_WRITE_SECURITY) val rbacSecurity = - csmRbac.removeUser(solution.security.toGenericSecurity(solutionId), identityId) + csmRbac.removeEntity(solution.security.toGenericSecurity(solutionId), identityId) solution.security = rbacSecurity.toResourceSecurity() save(solution) } override fun listSolutionSecurityUsers(organizationId: String, solutionId: String): List { val solution = getVerifiedSolution(organizationId, solutionId, PERMISSION_READ_SECURITY) - return csmRbac.getUsers(solution.security.toGenericSecurity(solutionId)) + return csmRbac.getEntities(solution.security.toGenericSecurity(solutionId)) } override fun getVerifiedSolution( diff --git a/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceIntegrationTest.kt b/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceIntegrationTest.kt index f1e9df573..50515266b 100644 --- a/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceIntegrationTest.kt +++ b/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceIntegrationTest.kt @@ -7,6 +7,7 @@ import com.cosmotech.common.exceptions.CsmAccessForbiddenException import com.cosmotech.common.exceptions.CsmResourceNotFoundException import com.cosmotech.common.rbac.* import com.cosmotech.common.tests.CsmTestBase +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -86,6 +87,7 @@ class WorkspaceServiceIntegrationTest : CsmTestBase() { fun setUp() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf("user") diff --git a/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceRBACTest.kt b/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceRBACTest.kt index 04c7319fa..313e7e569 100644 --- a/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceRBACTest.kt +++ b/workspace/src/integrationTest/kotlin/com/cosmotech/workspace/service/WorkspaceServiceRBACTest.kt @@ -18,6 +18,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.tests.CsmTestBase import com.cosmotech.common.utils.ResourceScanner +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -96,6 +97,7 @@ class WorkspaceServiceRBACTest : CsmTestBase() { ReflectionTestUtils.setField(workspaceApiService, "s3Template", s3Template) every { containerRegistryService.getImageLabel(any(), any(), any()) } returns null every { getCurrentAccountIdentifier(any()) } returns CONNECTED_ADMIN_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "test.user" every { getCurrentAuthenticatedRoles(any()) } returns listOf() diff --git a/workspace/src/main/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImpl.kt b/workspace/src/main/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImpl.kt index aa0aa72b6..3d5fb730b 100644 --- a/workspace/src/main/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImpl.kt +++ b/workspace/src/main/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImpl.kt @@ -433,12 +433,12 @@ internal class WorkspaceServiceImpl( ): WorkspaceAccessControl { val organization = organizationService.getVerifiedOrganization(organizationId) val workspace = getVerifiedWorkspace(organizationId, workspaceId, PERMISSION_WRITE_SECURITY) - val users = csmRbac.getUsers(workspace.security.toGenericSecurity(workspaceId)) + val users = csmRbac.getEntities(workspace.security.toGenericSecurity(workspaceId)) require(!users.contains(workspaceAccessControl.id)) { "User is already in this Workspace security" } val rbacSecurity = - csmRbac.addUserRole( + csmRbac.addEntityRole( organization.security.toGenericSecurity(organizationId), workspace.security.toGenericSecurity(workspaceId), workspaceAccessControl.id, @@ -458,12 +458,12 @@ internal class WorkspaceServiceImpl( workspaceRole: WorkspaceRole ): WorkspaceAccessControl { val workspace = getVerifiedWorkspace(organizationId, workspaceId, PERMISSION_WRITE_SECURITY) - csmRbac.checkUserExists( + csmRbac.checkEntityExists( workspace.security.toGenericSecurity(workspaceId), identityId, "User '$identityId' not found in workspace $workspaceId") val rbacSecurity = - csmRbac.setUserRole( + csmRbac.setEntityRole( workspace.security.toGenericSecurity(workspaceId), identityId, workspaceRole.role) workspace.security = rbacSecurity.toResourceSecurity() save(workspace) @@ -479,7 +479,7 @@ internal class WorkspaceServiceImpl( ) { val workspace = getVerifiedWorkspace(organizationId, workspaceId, PERMISSION_WRITE_SECURITY) val rbacSecurity = - csmRbac.removeUser(workspace.security.toGenericSecurity(workspaceId), identityId) + csmRbac.removeEntity(workspace.security.toGenericSecurity(workspaceId), identityId) workspace.security = rbacSecurity.toResourceSecurity() save(workspace) } @@ -489,7 +489,7 @@ internal class WorkspaceServiceImpl( workspaceId: String ): List { val workspace = getVerifiedWorkspace(organizationId, workspaceId, PERMISSION_READ_SECURITY) - return csmRbac.getUsers(workspace.security.toGenericSecurity(workspaceId)) + return csmRbac.getEntities(workspace.security.toGenericSecurity(workspaceId)) } fun updateSecurityVisibility(workspace: Workspace): Workspace { diff --git a/workspace/src/test/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImplTests.kt b/workspace/src/test/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImplTests.kt index 932a125f1..4e644b252 100644 --- a/workspace/src/test/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImplTests.kt +++ b/workspace/src/test/kotlin/com/cosmotech/workspace/service/WorkspaceServiceImplTests.kt @@ -17,6 +17,7 @@ import com.cosmotech.common.rbac.ROLE_USER import com.cosmotech.common.rbac.ROLE_VALIDATOR import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.common.utils.ResourceScanner +import com.cosmotech.common.utils.getCurrentAccountGroups import com.cosmotech.common.utils.getCurrentAccountIdentifier import com.cosmotech.common.utils.getCurrentAuthenticatedRoles import com.cosmotech.common.utils.getCurrentAuthenticatedUserName @@ -112,6 +113,7 @@ class WorkspaceServiceImplTests { fun beforeEach() { mockkStatic("com.cosmotech.common.utils.SecurityUtilsKt") every { getCurrentAccountIdentifier(any()) } returns CONNECTED_DEFAULT_USER + every { getCurrentAccountGroups(any()) } returns listOf("myTestGroup") every { getCurrentAuthenticatedUserName(csmPlatformProperties) } returns "my.account-tester" every { getCurrentAuthenticatedRoles(any()) } returns listOf()