Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Administrator role for creator and restrict Administrator role modification and deletion #191

Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@
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;

import static org.wso2.carbon.identity.organization.management.role.management.service.constant.RoleManagementConstants.CursorDirection.BACKWARD;
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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -189,7 +192,7 @@ public Role patchRole(String organizationId, String roleId, List<PatchOperation>
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) {
Expand Down Expand Up @@ -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())) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -363,20 +366,73 @@ private void validateUsers(List<String> 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.
RushanNanayakkara marked this conversation as resolved.
Show resolved Hide resolved
* @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()))
AnuradhaSK marked this conversation as resolved.
Show resolved Hide resolved
&& 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.
*/
RushanNanayakkara marked this conversation as resolved.
Show resolved Hide resolved
private boolean isPatchOperationAllowed(String organizationId, String roleId, List<PatchOperation> 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 ->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This anyMatch function is replaced by noneMatch function in the following PR
#208

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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<String> orgAdministratorRolePermissions = new ArrayList<>();
RushanNanayakkara marked this conversation as resolved.
Show resolved Hide resolved
// Setting all administrative permissions for the Administrator role
orgAdministratorRolePermissions.add(Constants.ADMINISTRATOR_ROLE_PERMISSION);
organizationAdministratorRole.setPermissions(orgAdministratorRolePermissions);
return organizationAdministratorRole;
}
}