diff --git a/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/RoleManagerImpl.java b/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/RoleManagerImpl.java index a73e22e73..ed712b4ed 100644 --- a/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/RoleManagerImpl.java +++ b/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/RoleManagerImpl.java @@ -47,6 +47,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @@ -54,6 +55,7 @@ import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.CursorDirection.FORWARD; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.DISPLAY_NAME; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.GROUPS; +import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.ORG_ADMINISTRATOR_ROLE; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.ORG_CREATOR_ROLE; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.PERMISSIONS; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.USERS; @@ -90,7 +92,8 @@ public class RoleManagerImpl implements RoleManager { @Override public Role createRole(String organizationId, Role role) throws OrganizationManagementException { - if (!StringUtils.equals(ORG_CREATOR_ROLE, role.getDisplayName())) { + if (!StringUtils.equals(ORG_CREATOR_ROLE, role.getDisplayName()) && + !StringUtils.equals(ORG_ADMINISTRATOR_ROLE, role.getDisplayName())) { validateOrganizationRoleAllowedToAccess(organizationId); } role.setId(generateUniqueID()); @@ -189,7 +192,7 @@ public Role patchRole(String organizationId, String roleId, List validateOrganizationRoleAllowedToAccess(organizationId); validateOrganizationId(organizationId); validateRoleId(organizationId, roleId); - if (!isRoleModifiable(organizationId, roleId)) { + if (!isPatchOperationAllowed(organizationId, roleId, patchOperations)) { throw handleClientException(ERROR_CODE_ROLE_IS_UNMODIFIABLE, roleId); } for (PatchOperation patchOperation : patchOperations) { @@ -229,7 +232,7 @@ public Role putRole(String organizationId, String roleId, Role role) throws Orga validateOrganizationRoleAllowedToAccess(organizationId); validateOrganizationId(organizationId); validateRoleId(organizationId, roleId); - if (!isRoleModifiable(organizationId, roleId)) { + if (!isPutOperationAllowed(organizationId, roleId, role)) { throw handleClientException(ERROR_CODE_ROLE_IS_UNMODIFIABLE, roleId); } if (StringUtils.isBlank(role.getDisplayName())) { @@ -257,7 +260,7 @@ public void deleteRole(String organizationId, String roleId) throws Organization validateOrganizationRoleAllowedToAccess(organizationId); validateOrganizationId(organizationId); validateRoleId(organizationId, roleId); - if (!isRoleModifiable(organizationId, roleId)) { + if (!isDeleteOperationAllowed(organizationId, roleId)) { throw handleClientException(ERROR_CODE_ROLE_IS_UNMODIFIABLE, roleId); } roleManagementDAO.deleteRole(organizationId, roleId); @@ -363,20 +366,73 @@ private void validateUsers(List userIdList, String organizationId) throw } /** - * Check whether the role is allowed for modification. + * Check whether the role is allowed to be deleted. * * @param organizationId Organization Id. * @param roleId Role Id. - * @return Whether role can be modified. + * @return Whether role can be deleted. * @throws OrganizationManagementServerException Error while retrieving role. */ - private boolean isRoleModifiable(String organizationId, String roleId) throws OrganizationManagementException { + private boolean isDeleteOperationAllowed(String organizationId, String roleId) + throws OrganizationManagementException { + + Role role = roleManagementDAO.getRoleById(organizationId, roleId); + if (role == null) { + throw handleClientException(ERROR_CODE_INVALID_ROLE, roleId); + } + // The org-creator role assigned during org creation, is not allowed to be deleted. + return !ORG_CREATOR_ROLE.equalsIgnoreCase(role.getDisplayName()) + && !ORG_ADMINISTRATOR_ROLE.equalsIgnoreCase(role.getDisplayName()); + } + + /** + * Check whether the incoming updates are allowed for the role. + * + * @param organizationId Organization Id. + * @param roleId Role Id. + * @param modifiedRole Incoming updated role. + * @return Whether put operation on the role is allowed with incoming values. + * @throws OrganizationManagementServerException Error while retrieving role. + */ + private boolean isPutOperationAllowed(String organizationId, String roleId, Role modifiedRole) + throws OrganizationManagementException { + + Role role = roleManagementDAO.getRoleById(organizationId, roleId); + if (role == null) { + throw handleClientException(ERROR_CODE_INVALID_ROLE, roleId); + } + // The Administrator role permissions and display name are not allowed to be updated. + if (ORG_ADMINISTRATOR_ROLE.equalsIgnoreCase(role.getDisplayName())) { + return new HashSet<>(role.getPermissions()).equals(new HashSet<>(modifiedRole.getPermissions())) + && ORG_ADMINISTRATOR_ROLE.equalsIgnoreCase(modifiedRole.getDisplayName()); + } + // The org-creator role assigned during org creation, is not allowed to be updated. + return !ORG_CREATOR_ROLE.equalsIgnoreCase(role.getDisplayName()); + } + + /** + * Check whether the incoming patch operations are allowed for the role. + * + * @param organizationId Organization Id. + * @param roleId Role Id. + * @param patchOperations Incoming patch operations with updated values. + * @return Whether incoming patch operations are allowed on the role. + * @throws OrganizationManagementServerException Error while retrieving role. + */ + private boolean isPatchOperationAllowed(String organizationId, String roleId, List patchOperations) + throws OrganizationManagementException { Role role = roleManagementDAO.getRoleById(organizationId, roleId); if (role == null) { throw handleClientException(ERROR_CODE_INVALID_ROLE, roleId); } - // The org-creator role assigned during org creation, is not allowed for update / delete. + // The Administrator role permissions and display name are not allowed to be patched. + if (ORG_ADMINISTRATOR_ROLE.equalsIgnoreCase(role.getDisplayName())) { + return !patchOperations.stream().anyMatch(patchOperation -> + PERMISSIONS.equals(patchOperation.getPath()) || + DISPLAY_NAME.equals(patchOperation.getPath())); + } + // The org-creator role assigned during org creation, is not allowed to be patched. return !ORG_CREATOR_ROLE.equalsIgnoreCase(role.getDisplayName()); } diff --git a/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/constant/RoleManagementConstants.java b/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/constant/RoleManagementConstants.java index 2c053168d..d6d2d394a 100644 --- a/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/constant/RoleManagementConstants.java +++ b/components/org.wso2.carbon.identity.organization.management.role.management.service/src/main/java/org/wso2/carbon/identity/organization/management/role/management/service/constant/RoleManagementConstants.java @@ -42,6 +42,7 @@ public class RoleManagementConstants { public static final String UNION_SEPARATOR = " UNION ALL "; public static final String ORG_CREATOR_ROLE = "org-creator"; + public static final String ORG_ADMINISTRATOR_ROLE = "Administrator"; /** * Enum for cursor based pagination direction. diff --git a/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/Constants.java b/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/Constants.java index 52e0c98cb..95a96a31e 100644 --- a/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/Constants.java +++ b/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/Constants.java @@ -44,6 +44,7 @@ public class Constants { public static final String CLAIM_META_DATA_MGT_VIEW_PERMISSION = "/permission/admin/manage/identity/claimmgt/metadata/view"; public static final String USER_MGT_CREATE_PERMISSION = "/permission/admin/manage/identity/usermgt/create"; + public static final String ADMINISTRATOR_ROLE_PERMISSION = "/permission"; /* Minimum permissions required for org creator to logged in to the console and view user, groups, roles, SP, diff --git a/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/listeners/TenantAssociationManagementListener.java b/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/listeners/TenantAssociationManagementListener.java index 41460bf77..cda2e560a 100644 --- a/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/listeners/TenantAssociationManagementListener.java +++ b/components/org.wso2.carbon.identity.organization.management.tenant.association/src/main/java/org/wso2/carbon/identity/organization/management/tenant/association/listeners/TenantAssociationManagementListener.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Collections; +import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.ORG_ADMINISTRATOR_ROLE; import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.ORG_CREATOR_ROLE; import static org.wso2.carbon.identity.organization.management.tenant.association.Constants.MINIMUM_PERMISSIONS_REQUIRED_FOR_ORG_CREATOR_VIEW; @@ -91,7 +92,9 @@ public void onTenantCreate(TenantInfoBean tenantInfo) { return; } Role organizationCreatorRole = buildOrgCreatorRole(adminUUID); + Role administratorRole = buildAdministratorRole(adminUUID); TenantAssociationDataHolder.getRoleManager().createRole(organizationID, organizationCreatorRole); + TenantAssociationDataHolder.getRoleManager().createRole(organizationID, administratorRole); } catch (UserStoreException | OrganizationManagementException e) { String error = "Error occurred while adding user-tenant association for the tenant id: " + tenantId; LOG.error(error, e); @@ -120,4 +123,18 @@ private Role buildOrgCreatorRole(String adminUUID) { organizationCreatorRole.setPermissions(orgCreatorRolePermissions); return organizationCreatorRole; } + + private Role buildAdministratorRole(String adminUUID) { + + Role organizationAdministratorRole = new Role(); + organizationAdministratorRole.setDisplayName(ORG_ADMINISTRATOR_ROLE); + User orgAdministrator = new User(adminUUID); + organizationAdministratorRole.setUsers(Collections.singletonList(orgAdministrator)); + // Set permissions for org-administrator role. + ArrayList orgAdministratorRolePermissions = new ArrayList<>(); + // Setting all administrative permissions for the Administrator role + orgAdministratorRolePermissions.add(Constants.ADMINISTRATOR_ROLE_PERMISSION); + organizationAdministratorRole.setPermissions(orgAdministratorRolePermissions); + return organizationAdministratorRole; + } }