From 9d3535c61a0af049dacfd0176f78f6682710447f Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Mon, 27 Jan 2025 00:56:03 +0530 Subject: [PATCH 1/3] add console role listner --- .../common/listner/ConsoleRoleListener.java | 284 ++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java diff --git a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java new file mode 100644 index 00000000000..2ab63eaff01 --- /dev/null +++ b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java @@ -0,0 +1,284 @@ +package org.wso2.identity.apps.common.listner; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.api.resource.collection.mgt.APIResourceCollectionManagerImpl; +import org.wso2.carbon.identity.api.resource.collection.mgt.exception.APIResourceCollectionMgtException; +import org.wso2.carbon.identity.api.resource.collection.mgt.internal.APIResourceCollectionMgtServiceDataHolder; +import org.wso2.carbon.identity.api.resource.collection.mgt.model.APIResourceCollection; +import org.wso2.carbon.identity.api.resource.collection.mgt.model.APIResourceCollectionSearchResult; +import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtException; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.ApplicationBasicInfo; +import org.wso2.carbon.identity.application.common.model.Scope; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants; +import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService; +import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementException; +import org.wso2.carbon.identity.role.v2.mgt.core.listener.AbstractRoleManagementListener; +import org.wso2.carbon.identity.role.v2.mgt.core.model.Permission; +import org.wso2.carbon.identity.role.v2.mgt.core.model.Role; +import org.wso2.carbon.identity.role.v2.mgt.core.model.RoleBasicInfo; +import org.wso2.identity.apps.common.internal.AppsCommonDataHolder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.wso2.carbon.identity.api.resource.collection.mgt.constant.APIResourceCollectionManagementConstants.APIResourceCollectionConfigBuilderConstants.EDIT_FEATURE_SCOPE_SUFFIX; +import static org.wso2.carbon.identity.api.resource.collection.mgt.constant.APIResourceCollectionManagementConstants.APIResourceCollectionConfigBuilderConstants.VIEW_FEATURE_SCOPE_SUFFIX; +import static org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants.CONSOLE_APP_AUDIENCE_NAME; +import static org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants.CONSOLE_ORG_SCOPE_PREFIX; +import static org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants.CONSOLE_SCOPE_PREFIX; + +/** + * Console role listener to populate organization console application roles permissions. + */ +public class ConsoleRoleListener extends AbstractRoleManagementListener { + + @Override + public int getDefaultOrderId() { + + return 87; + } + + @Override + public boolean isEnable() { + + return true; + } + + @Override + public void preAddRole(String roleName, List userList, List groupList, List permissions, + String audience, String audienceId, String tenantDomain) + throws IdentityRoleManagementException { + + if (isConsoleApp(audience, audienceId, tenantDomain)) { + List consoleFeaturePermissions = getConsoleFeaturePermissions(permissions); + if (consoleFeaturePermissions != null && !consoleFeaturePermissions.isEmpty()) { + // If console features are added to the role, then we need to we only need to persist the console + // permissions. + permissions.retainAll(consoleFeaturePermissions); + } + } + } + + @Override + public void postGetRole(Role role, String roleId, String tenantDomain) throws IdentityRoleManagementException { + + + if (!RoleConstants.ADMINISTRATOR.equals(role.getName()) && + role.getAudienceName().equals(CONSOLE_APP_AUDIENCE_NAME)) { + // Get updated console role permissions with newly added read and write scopes from API resource collection. + List rolePermissions = getUpgradedPermissions(role.getPermissions(), tenantDomain); + role.setPermissions(rolePermissions); + } + } + + @Override + public void postGetPermissionListOfRole(List permissionListOfRole, String roleId, String tenantDomain) + throws IdentityRoleManagementException { + + if (isConsoleRole(roleId, tenantDomain)) { + List rolePermissions = getUpgradedPermissions(permissionListOfRole, tenantDomain); + permissionListOfRole.clear(); + permissionListOfRole.addAll(rolePermissions); + } + } + + @Override + public void postGetPermissionListOfRoles(List permissions, List roleIds, String tenantDomain) + throws IdentityRoleManagementException { + + boolean isConsolePermissionsContains = isConsolePermissionsContains(permissions); + boolean isConsoleFeaturePermissionsContains = isConsoleFeaturePermissionsContains(permissions); + if (isConsolePermissionsContains || isConsoleFeaturePermissionsContains) { + List resolvedRolePermissions = new ArrayList<>(); + List systemPermissions = getSystemPermission(tenantDomain); + permissions.forEach(permission -> { + Optional newPermission = systemPermissions.stream() + .filter(permission1 -> permission1.getName().equals(permission)) + .findFirst(); + newPermission.ifPresent(resolvedRolePermissions::add); + }); + List rolePermissions = getUpgradedPermissions(resolvedRolePermissions, tenantDomain); + permissions.clear(); + permissions.addAll(rolePermissions.stream().map(Permission::getName).collect(Collectors.toList())); + } + } + + @Override + public void preUpdatePermissionsForRole(String roleId, List addedPermissions, + List deletedPermissions, String audience, String audienceId, + String tenantDomain) throws IdentityRoleManagementException { + + if (isConsoleApp(audience, audienceId, tenantDomain)) { + List consoleFeaturePermissions = getConsoleFeaturePermissions(addedPermissions); + if (consoleFeaturePermissions != null && !consoleFeaturePermissions.isEmpty()) { + // If console features are added to the role, then we need to we only need to persist the console + // permissions. + addedPermissions.retainAll(consoleFeaturePermissions); + } + } + } + + private List getUpgradedPermissions(List rolePermissions, String tenantDomain) + throws IdentityRoleManagementException { + + // Fetch all system scopes to resolve permission details from permission name. + List systemPermissions = getSystemPermission(tenantDomain); + List apiResourceCollections = getAPIResourceCollections(tenantDomain); + List consoleFeaturePermissions = getConsoleFeaturePermissions(rolePermissions); + if (!consoleFeaturePermissions.isEmpty()) { + // This is where we handle the new console roles (console roles created after 7.0.0) permissions. + // We check whether the role has the view feature scope or edit feature scope. If the role has the + // view feature scope, then we add all the read scopes. If the role has the edit feature scope, then we + // add all the write scopes. + consoleFeaturePermissions.forEach(permission -> { + apiResourceCollections.forEach(apiResourceCollection -> { + // If the role has the edit feature scope, then we add all the write and read scopes. + if (apiResourceCollection.getEditFeatureScope() != null && + apiResourceCollection.getEditFeatureScope().equals(permission.getName())) { + apiResourceCollection.getWriteScopes().forEach(writeScope -> { + Optional newPermission = systemPermissions.stream() + .filter(permission1 -> permission1.getName().equals(writeScope)) + .findFirst(); + newPermission.ifPresent(rolePermissions::add); + }); + } + if (apiResourceCollection.getViewFeatureScope() != null && + apiResourceCollection.getViewFeatureScope().equals(permission.getName())) { + apiResourceCollection.getReadScopes().forEach(readScope -> { + Optional newPermission = systemPermissions.stream() + .filter(permission1 -> permission1.getName().equals(readScope)) + .findFirst(); + newPermission.ifPresent(rolePermissions::add); + }); + } + }); + }); + } else { + // This is where we handle the initial console roles (console roles created in 7.0.0) permissions. + // Here we assume these role only contains legacy feature scope not the new feature scopes. + List consolePermissions = getConsolePermissions(rolePermissions); + consolePermissions.forEach(permission -> { + apiResourceCollections.forEach(apiResourceCollection -> { + // Match the permission with the collection. + if (apiResourceCollection.getReadScopes().contains(permission.getName())) { + // Add new read scopes since we have the feature scope. + apiResourceCollection.getReadScopes().forEach(newReadScope -> { + Optional newPermission = systemPermissions.stream() + .filter(permission1 -> permission1.getName().equals(newReadScope)) + .findFirst(); + newPermission.ifPresent(rolePermissions::add); + }); + List legacyWriteScopes = apiResourceCollection.getLegacyWriteScopes(); + // if all the writeScopes are in the role's permission list, then add new write scopes. + if (rolePermissions.stream().anyMatch(rolePermission -> + legacyWriteScopes.contains(rolePermission.getName()))) { + apiResourceCollection.getWriteScopes().forEach(newWriteScope -> { + Optional newPermission = systemPermissions.stream() + .filter(permission1 -> permission1.getName().equals(newWriteScope)) + .findFirst(); + newPermission.ifPresent(rolePermissions::add); + }); + } + } + }); + }); + } + return rolePermissions; + } + + private boolean isConsoleRole(String roleId, String tenantDomain) throws IdentityRoleManagementException { + + RoleManagementService roleManagementService = AppsCommonDataHolder.getInstance() + .getRoleManagementServiceV2(); + RoleBasicInfo role = roleManagementService.getRoleBasicInfoById(roleId, tenantDomain); + return !RoleConstants.ADMINISTRATOR.equals(role.getName()) && + role.getAudienceName().equals(CONSOLE_APP_AUDIENCE_NAME); + } + + private boolean isConsoleApp(String audience, String audienceId, String tenantDomain) + throws IdentityRoleManagementException { + + if (!RoleConstants.APPLICATION.equals(audience)) { + return false; + } + ApplicationManagementService applicationManagementService = AppsCommonDataHolder.getInstance() + .getApplicationManagementService(); + try { + ApplicationBasicInfo applicationBasicInfo = applicationManagementService + .getApplicationBasicInfoByResourceId(audienceId, tenantDomain); + return applicationBasicInfo != null && CONSOLE_APP_AUDIENCE_NAME + .equals(applicationBasicInfo.getApplicationName()); + } catch (IdentityApplicationManagementException e) { + throw new IdentityRoleManagementException("Error while retrieving application basic info for application " + + "id : " + audienceId, e); + } + } + + private List getAPIResourceCollections(String tenantDomain) + throws IdentityRoleManagementException { + + try { + List requiredAttributes = new ArrayList<>(); + requiredAttributes.add("apiResources"); + APIResourceCollectionSearchResult apiResourceCollectionSearchResult = APIResourceCollectionManagerImpl + .getInstance().getAPIResourceCollections("", requiredAttributes, tenantDomain); + return apiResourceCollectionSearchResult.getAPIResourceCollections(); + + } catch (APIResourceCollectionMgtException e) { + throw new IdentityRoleManagementException("Error while retrieving api collection for tenant : " + + tenantDomain, e); + } + } + + private List getConsoleFeaturePermissions(List rolePermissions) { + + return rolePermissions.stream().filter(permission -> permission != null && + permission.getName() != null && (permission.getName().startsWith(CONSOLE_SCOPE_PREFIX) + || permission.getName().startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && + (permission.getName().endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || + permission.getName().endsWith(EDIT_FEATURE_SCOPE_SUFFIX))) + .collect(Collectors.toList()); + } + + private List getConsolePermissions(List rolePermissions) { + + return rolePermissions.stream().filter(permission -> permission != null && + permission.getName() != null && (permission.getName().startsWith(CONSOLE_SCOPE_PREFIX) + || permission.getName().startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && + !(permission.getName().endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || + permission.getName().endsWith(EDIT_FEATURE_SCOPE_SUFFIX))) + .collect(Collectors.toList()); + } + + private boolean isConsoleFeaturePermissionsContains(List rolePermissions) { + + return rolePermissions.stream().anyMatch(permission -> StringUtils.isNotBlank(permission) && + (permission.startsWith(CONSOLE_SCOPE_PREFIX) || permission.startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && + (permission.endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || permission.endsWith(EDIT_FEATURE_SCOPE_SUFFIX))); + } + + private boolean isConsolePermissionsContains(List rolePermissions) { + + return rolePermissions.stream().anyMatch(permission -> StringUtils.isNotBlank(permission) && + (permission.startsWith(CONSOLE_SCOPE_PREFIX) || permission.startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && + !(permission.endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || permission.endsWith(EDIT_FEATURE_SCOPE_SUFFIX))); + } + + private List getSystemPermission(String tenantDomain) throws IdentityRoleManagementException { + List systemScopes; + try { + systemScopes = APIResourceCollectionMgtServiceDataHolder.getInstance() + .getAPIResourceManagementService().getSystemAPIScopes(tenantDomain); + } catch (APIResourceMgtException e) { + throw new IdentityRoleManagementException("Error while retrieving internal scopes for tenant " + + "domain : " + tenantDomain, e); + } + return systemScopes.stream().map(scope -> new Permission(scope.getName(), scope.getDisplayName(), + scope.getApiID())).collect(Collectors.toList()); + } +} + From ed789e19ec3433b5b1d09e23284896c96aadcb34 Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Mon, 27 Jan 2025 11:43:11 +0530 Subject: [PATCH 2/3] improve resolving roles --- .../org.wso2.identity.apps.common/pom.xml | 11 +- .../common/internal/AppsCommonDataHolder.java | 22 +++ .../internal/AppsCommonServiceComponent.java | 22 +++ .../common/listner/ConsoleRoleListener.java | 130 +++++++++++++----- identity-apps-core/pom.xml | 7 +- 5 files changed, 158 insertions(+), 34 deletions(-) diff --git a/identity-apps-core/components/org.wso2.identity.apps.common/pom.xml b/identity-apps-core/components/org.wso2.identity.apps.common/pom.xml index 27c7a28da42..178f75ea6a0 100644 --- a/identity-apps-core/components/org.wso2.identity.apps.common/pom.xml +++ b/identity-apps-core/components/org.wso2.identity.apps.common/pom.xml @@ -88,6 +88,14 @@ org.wso2.carbon.identity.organization.management org.wso2.carbon.identity.organization.management.application + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.api.resource.mgt + + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.api.resource.collection.mgt + xalan @@ -141,7 +149,8 @@ org.wso2.carbon.identity.role.v2.mgt.core.*; version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.organization.management.service.*; version="${identity.org.mgt.core.version.range}", org.wso2.carbon.identity.organization.management.application.*; version="${identity.org.mgt.application.version.range}", - org.wso2.carbon.identity.api.resource.mgt.*; version="${carbon.identity.framework.imp.pkg.version.range}" + org.wso2.carbon.identity.api.resource.mgt.*; version="${carbon.identity.framework.imp.pkg.version.range}", + org.wso2.carbon.identity.api.resource.collection.mgt.*; version="${carbon.identity.framework.imp.pkg.version.range}" * diff --git a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonDataHolder.java b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonDataHolder.java index 7f2787cffd0..1c7c79c7560 100644 --- a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonDataHolder.java +++ b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonDataHolder.java @@ -18,6 +18,7 @@ package org.wso2.identity.apps.common.internal; +import org.wso2.carbon.identity.api.resource.collection.mgt.APIResourceCollectionManager; import org.wso2.carbon.identity.api.resource.mgt.APIResourceManager; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; @@ -47,6 +48,7 @@ public class AppsCommonDataHolder { private RoleManagementService roleManagementService; private APIResourceManager apiResourceManager; + private APIResourceCollectionManager apiResourceCollectionManager; private Set systemAppConsumerKeys = new HashSet<>(); @@ -222,6 +224,26 @@ public APIResourceManager getAPIResourceManager() { return apiResourceManager; } + /** + * Set API resource collection manager. + * + * @param apiResourceCollectionManager APIResourceCollectionManager. + */ + public void setAPIResourceCollectionManager(APIResourceCollectionManager apiResourceCollectionManager) { + + this.apiResourceCollectionManager = apiResourceCollectionManager; + } + + /** + * Get API resource collection manager. + * + * @return apiResourceCollectionManager. + */ + public APIResourceCollectionManager getApiResourceCollectionManager() { + + return apiResourceCollectionManager; + } + /** * Set default applications. diff --git a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonServiceComponent.java b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonServiceComponent.java index e02c15d4eaa..70e2e7bb633 100644 --- a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonServiceComponent.java +++ b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/internal/AppsCommonServiceComponent.java @@ -29,6 +29,7 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.core.ServerStartupObserver; +import org.wso2.carbon.identity.api.resource.collection.mgt.APIResourceCollectionManager; import org.wso2.carbon.identity.api.resource.mgt.APIResourceManager; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.common.model.InboundAuthenticationRequestConfig; @@ -48,6 +49,7 @@ import org.wso2.identity.apps.common.listner.AppPortalOAuthAppMgtListener; import org.wso2.identity.apps.common.listner.AppPortalRoleManagementListener; import org.wso2.identity.apps.common.listner.AppPortalTenantMgtListener; +import org.wso2.identity.apps.common.listner.ConsoleRoleListener; import org.wso2.identity.apps.common.util.AppPortalUtils; import java.util.HashSet; @@ -109,6 +111,10 @@ protected void activate(BundleContext bundleContext) { RoleManagementListener roleManagementListener = new AppPortalRoleManagementListener(true); bundleContext.registerService(RoleManagementListener.class.getName(), roleManagementListener, null); log.debug("AppPortalRoleManagementListener registered successfully."); + + RoleManagementListener consoleRoleListener = new ConsoleRoleListener(); + bundleContext.registerService(RoleManagementListener.class.getName(), consoleRoleListener, null); + log.debug("ConsoleRoleListener registered successfully."); } if (!CarbonConstants.ENABLE_LEGACY_AUTHZ_RUNTIME) { @@ -266,6 +272,22 @@ protected void unsetAPIResourceManager(APIResourceManager apiResourceManager) { AppsCommonDataHolder.getInstance().setAPIResourceManager(null); } + @Reference( + name = "api.resource.collection.mgt.service", + service = APIResourceCollectionManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetAPIResourceCollectionManager") + protected void setAPIResourceManager(APIResourceCollectionManager apiResourceCollectionManager) { + + AppsCommonDataHolder.getInstance().setAPIResourceCollectionManager(apiResourceCollectionManager); + } + + protected void unsetAPIResourceCollectionManager(APIResourceCollectionManager apiResourceCollectionManager) { + + AppsCommonDataHolder.getInstance().setAPIResourceCollectionManager(null); + } + private boolean skipPortalInitialization() { return System.getProperty(SYSTEM_PROP_SKIP_SERVER_INITIALIZATION) != null; diff --git a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java index 2ab63eaff01..19bec8d63f5 100644 --- a/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java +++ b/identity-apps-core/components/org.wso2.identity.apps.common/src/main/java/org/wso2/identity/apps/common/listner/ConsoleRoleListener.java @@ -1,9 +1,24 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.identity.apps.common.listner; -import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.api.resource.collection.mgt.APIResourceCollectionManagerImpl; import org.wso2.carbon.identity.api.resource.collection.mgt.exception.APIResourceCollectionMgtException; -import org.wso2.carbon.identity.api.resource.collection.mgt.internal.APIResourceCollectionMgtServiceDataHolder; import org.wso2.carbon.identity.api.resource.collection.mgt.model.APIResourceCollection; import org.wso2.carbon.identity.api.resource.collection.mgt.model.APIResourceCollectionSearchResult; import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtException; @@ -21,8 +36,10 @@ import org.wso2.identity.apps.common.internal.AppsCommonDataHolder; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import static org.wso2.carbon.identity.api.resource.collection.mgt.constant.APIResourceCollectionManagementConstants.APIResourceCollectionConfigBuilderConstants.EDIT_FEATURE_SCOPE_SUFFIX; @@ -53,7 +70,7 @@ public void preAddRole(String roleName, List userList, List grou String audience, String audienceId, String tenantDomain) throws IdentityRoleManagementException { - if (isConsoleApp(audience, audienceId, tenantDomain)) { + if (isConsoleApp(audience, audienceId, tenantDomain) && !RoleConstants.ADMINISTRATOR.equals(roleName)) { List consoleFeaturePermissions = getConsoleFeaturePermissions(permissions); if (consoleFeaturePermissions != null && !consoleFeaturePermissions.isEmpty()) { // If console features are added to the role, then we need to we only need to persist the console @@ -90,9 +107,14 @@ public void postGetPermissionListOfRole(List permissionListOfRole, S public void postGetPermissionListOfRoles(List permissions, List roleIds, String tenantDomain) throws IdentityRoleManagementException { - boolean isConsolePermissionsContains = isConsolePermissionsContains(permissions); - boolean isConsoleFeaturePermissionsContains = isConsoleFeaturePermissionsContains(permissions); - if (isConsolePermissionsContains || isConsoleFeaturePermissionsContains) { + boolean isConsoleRole = false; + for (String roleId : roleIds) { + if (isConsoleRole(roleId, tenantDomain)) { + isConsoleRole = true; + break; + } + } + if (isConsoleRole) { List resolvedRolePermissions = new ArrayList<>(); List systemPermissions = getSystemPermission(tenantDomain); permissions.forEach(permission -> { @@ -112,7 +134,7 @@ public void preUpdatePermissionsForRole(String roleId, List addedPer List deletedPermissions, String audience, String audienceId, String tenantDomain) throws IdentityRoleManagementException { - if (isConsoleApp(audience, audienceId, tenantDomain)) { + if (isConsoleRole(roleId, tenantDomain)) { List consoleFeaturePermissions = getConsoleFeaturePermissions(addedPermissions); if (consoleFeaturePermissions != null && !consoleFeaturePermissions.isEmpty()) { // If console features are added to the role, then we need to we only need to persist the console @@ -122,6 +144,15 @@ public void preUpdatePermissionsForRole(String roleId, List addedPer } } + /** + * This method resolves the new permissions for the console roles. In this method, we resolve two type of console + * roles. 1. Console roles created after 7.0.0. 2. Console roles created in 7.0.0. + * + * @param rolePermissions List of permissions of the role. + * @param tenantDomain Tenant domain. + * @return List of resolved permissions. + * @throws IdentityRoleManagementException If an error occurs while resolving the permissions. + */ private List getUpgradedPermissions(List rolePermissions, String tenantDomain) throws IdentityRoleManagementException { @@ -134,6 +165,7 @@ private List getUpgradedPermissions(List rolePermissions // We check whether the role has the view feature scope or edit feature scope. If the role has the // view feature scope, then we add all the read scopes. If the role has the edit feature scope, then we // add all the write scopes. + List resolvedRolePermissions = new ArrayList<>(); consoleFeaturePermissions.forEach(permission -> { apiResourceCollections.forEach(apiResourceCollection -> { // If the role has the edit feature scope, then we add all the write and read scopes. @@ -143,7 +175,7 @@ private List getUpgradedPermissions(List rolePermissions Optional newPermission = systemPermissions.stream() .filter(permission1 -> permission1.getName().equals(writeScope)) .findFirst(); - newPermission.ifPresent(rolePermissions::add); + newPermission.ifPresent(resolvedRolePermissions::add); }); } if (apiResourceCollection.getViewFeatureScope() != null && @@ -152,14 +184,16 @@ private List getUpgradedPermissions(List rolePermissions Optional newPermission = systemPermissions.stream() .filter(permission1 -> permission1.getName().equals(readScope)) .findFirst(); - newPermission.ifPresent(rolePermissions::add); + newPermission.ifPresent(resolvedRolePermissions::add); }); } }); }); + return resolvedRolePermissions; } else { // This is where we handle the initial console roles (console roles created in 7.0.0) permissions. // Here we assume these role only contains legacy feature scope not the new feature scopes. + Set resolvedRolePermissions = new HashSet<>(new ArrayList<>(rolePermissions)); List consolePermissions = getConsolePermissions(rolePermissions); consolePermissions.forEach(permission -> { apiResourceCollections.forEach(apiResourceCollection -> { @@ -170,7 +204,7 @@ private List getUpgradedPermissions(List rolePermissions Optional newPermission = systemPermissions.stream() .filter(permission1 -> permission1.getName().equals(newReadScope)) .findFirst(); - newPermission.ifPresent(rolePermissions::add); + newPermission.ifPresent(resolvedRolePermissions::add); }); List legacyWriteScopes = apiResourceCollection.getLegacyWriteScopes(); // if all the writeScopes are in the role's permission list, then add new write scopes. @@ -180,16 +214,24 @@ private List getUpgradedPermissions(List rolePermissions Optional newPermission = systemPermissions.stream() .filter(permission1 -> permission1.getName().equals(newWriteScope)) .findFirst(); - newPermission.ifPresent(rolePermissions::add); + newPermission.ifPresent(resolvedRolePermissions::add); }); } } }); }); + return new ArrayList<>(resolvedRolePermissions); } - return rolePermissions; } + /** + * Check whether the role is a console role. We consider all the console roles except the administrator role. + * + * @param roleId Role id. + * @param tenantDomain Tenant domain. + * @return True if the role is a console role. + * @throws IdentityRoleManagementException If an error occurs while checking the role. + */ private boolean isConsoleRole(String roleId, String tenantDomain) throws IdentityRoleManagementException { RoleManagementService roleManagementService = AppsCommonDataHolder.getInstance() @@ -199,10 +241,19 @@ private boolean isConsoleRole(String roleId, String tenantDomain) throws Identit role.getAudienceName().equals(CONSOLE_APP_AUDIENCE_NAME); } + /** + * Check whether the app is a console application based in audience. + * + * @param audience Audience. + * @param audienceId Audience id. + * @param tenantDomain Tenant domain. + * @return True if the app is a console application. + * @throws IdentityRoleManagementException If an error occurs while checking the app. + */ private boolean isConsoleApp(String audience, String audienceId, String tenantDomain) throws IdentityRoleManagementException { - if (!RoleConstants.APPLICATION.equals(audience)) { + if (!RoleConstants.APPLICATION.equalsIgnoreCase(audience)) { return false; } ApplicationManagementService applicationManagementService = AppsCommonDataHolder.getInstance() @@ -218,14 +269,23 @@ private boolean isConsoleApp(String audience, String audienceId, String tenantDo } } + /** + * Get API resource collections for the tenant. This will return all the tenant and organization specific API + * collections. + * + * @param tenantDomain Tenant domain. + * @return List of API resource collections. + * @throws IdentityRoleManagementException If an error occurs while retrieving the API resource collections. + */ private List getAPIResourceCollections(String tenantDomain) throws IdentityRoleManagementException { try { List requiredAttributes = new ArrayList<>(); requiredAttributes.add("apiResources"); - APIResourceCollectionSearchResult apiResourceCollectionSearchResult = APIResourceCollectionManagerImpl - .getInstance().getAPIResourceCollections("", requiredAttributes, tenantDomain); + APIResourceCollectionSearchResult apiResourceCollectionSearchResult = AppsCommonDataHolder + .getInstance().getApiResourceCollectionManager() + .getAPIResourceCollections("", requiredAttributes, tenantDomain); return apiResourceCollectionSearchResult.getAPIResourceCollections(); } catch (APIResourceCollectionMgtException e) { @@ -234,6 +294,12 @@ private List getAPIResourceCollections(String tenantDomai } } + /** + * Get console feature permissions from the role permissions. + * + * @param rolePermissions Role permissions. + * @return List of console feature permissions. + */ private List getConsoleFeaturePermissions(List rolePermissions) { return rolePermissions.stream().filter(permission -> permission != null && @@ -244,6 +310,12 @@ private List getConsoleFeaturePermissions(List rolePermi .collect(Collectors.toList()); } + /** + * Get console permissions (old ones) from the role permissions. + * + * @param rolePermissions Role permissions. + * @return List of console permissions. + */ private List getConsolePermissions(List rolePermissions) { return rolePermissions.stream().filter(permission -> permission != null && @@ -254,25 +326,19 @@ private List getConsolePermissions(List rolePermissions) .collect(Collectors.toList()); } - private boolean isConsoleFeaturePermissionsContains(List rolePermissions) { - - return rolePermissions.stream().anyMatch(permission -> StringUtils.isNotBlank(permission) && - (permission.startsWith(CONSOLE_SCOPE_PREFIX) || permission.startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && - (permission.endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || permission.endsWith(EDIT_FEATURE_SCOPE_SUFFIX))); - } - - private boolean isConsolePermissionsContains(List rolePermissions) { - - return rolePermissions.stream().anyMatch(permission -> StringUtils.isNotBlank(permission) && - (permission.startsWith(CONSOLE_SCOPE_PREFIX) || permission.startsWith(CONSOLE_ORG_SCOPE_PREFIX)) && - !(permission.endsWith(VIEW_FEATURE_SCOPE_SUFFIX) || permission.endsWith(EDIT_FEATURE_SCOPE_SUFFIX))); - } - + /** + * Get system permissions for the tenant. + * + * @param tenantDomain Tenant domain. + * @return List of system permissions. + * @throws IdentityRoleManagementException If an error occurs while retrieving the system permissions. + */ private List getSystemPermission(String tenantDomain) throws IdentityRoleManagementException { List systemScopes; + try { - systemScopes = APIResourceCollectionMgtServiceDataHolder.getInstance() - .getAPIResourceManagementService().getSystemAPIScopes(tenantDomain); + systemScopes = AppsCommonDataHolder.getInstance() + .getAPIResourceManager().getSystemAPIScopes(tenantDomain); } catch (APIResourceMgtException e) { throw new IdentityRoleManagementException("Error while retrieving internal scopes for tenant " + "domain : " + tenantDomain, e); diff --git a/identity-apps-core/pom.xml b/identity-apps-core/pom.xml index 9dafc067517..baea4ee37dd 100644 --- a/identity-apps-core/pom.xml +++ b/identity-apps-core/pom.xml @@ -401,6 +401,11 @@ org.wso2.carbon.identity.api.resource.mgt ${carbon.identity.framework.version} + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.api.resource.collection.mgt + ${carbon.identity.framework.version} + org.wso2.carbon.identity.governance org.wso2.carbon.identity.captcha @@ -729,7 +734,7 @@ 3.0.0 5.1.5 1.0.8 - 7.2.30 + 7.7.142-SNAPSHOT [5.0.0, 8.0.0) 1.0.77 From 7972123a2b7a17e255391c9b3f6a9d1124c93449 Mon Sep 17 00:00:00 2001 From: Thilina Shashimal Senarath Date: Fri, 31 Jan 2025 19:57:03 +0530 Subject: [PATCH 3/3] add changeest --- .changeset/kind-eyes-mix.md | 5 +++++ identity-apps-core/pom.xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/kind-eyes-mix.md diff --git a/.changeset/kind-eyes-mix.md b/.changeset/kind-eyes-mix.md new file mode 100644 index 00000000000..d0d0c4683ff --- /dev/null +++ b/.changeset/kind-eyes-mix.md @@ -0,0 +1,5 @@ +--- +"@wso2is/identity-apps-core": patch +--- + +introduce console listener diff --git a/identity-apps-core/pom.xml b/identity-apps-core/pom.xml index baea4ee37dd..6442cf0bd61 100644 --- a/identity-apps-core/pom.xml +++ b/identity-apps-core/pom.xml @@ -734,7 +734,7 @@ 3.0.0 5.1.5 1.0.8 - 7.7.142-SNAPSHOT + 7.7.176 [5.0.0, 8.0.0) 1.0.77