diff --git a/components/org.wso2.carbon.identity.organization.management.handler/pom.xml b/components/org.wso2.carbon.identity.organization.management.handler/pom.xml
index f7a98876f..6510e80a7 100644
--- a/components/org.wso2.carbon.identity.organization.management.handler/pom.xml
+++ b/components/org.wso2.carbon.identity.organization.management.handler/pom.xml
@@ -56,7 +56,22 @@
org.wso2.carbon.identity.governance
org.wso2.carbon.identity.governance
-
+
+ org.wso2.carbon.identity.organization.management
+ org.wso2.carbon.identity.organization.management.application
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.event
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.role.v2.mgt.core
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.application.mgt
+
org.testng
@@ -115,6 +130,15 @@
org.wso2.carbon.identity.event.services; version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.recovery.*; version="${identity.governance.imp.pkg.version.range}",
org.wso2.carbon.identity.governance; version="${identity.governance.imp.pkg.version.range}",
+ org.wso2.carbon.identity.role.v2.mgt.core.*; version="${carbon.identity.package.import.version.range}",
+ org.wso2.carbon.identity.organization.management.application.*;
+ version="${org.wso2.identity.organization.mgt.imp.pkg.version.range}",
+ org.wso2.carbon.identity.application.mgt.*;
+ version="${carbon.identity.package.import.version.range}",
+ org.wso2.carbon.identity.application.common.*;
+ version="${carbon.identity.package.import.version.range}",
+ org.wso2.carbon.identity.core.util;version="${carbon.identity.package.import.version.range}",
+ org.wso2.carbon.context;version="${carbon.kernel.package.import.version.range}",
diff --git a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java
new file mode 100644
index 000000000..01fb38905
--- /dev/null
+++ b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2023, 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.carbon.identity.organization.management.handler;
+
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
+import org.wso2.carbon.identity.application.common.model.RoleV2;
+import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
+import org.wso2.carbon.identity.event.IdentityEventConstants;
+import org.wso2.carbon.identity.event.IdentityEventException;
+import org.wso2.carbon.identity.event.event.Event;
+import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
+import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager;
+import org.wso2.carbon.identity.organization.management.application.constant.OrgApplicationMgtConstants;
+import org.wso2.carbon.identity.organization.management.application.model.SharedApplication;
+import org.wso2.carbon.identity.organization.management.handler.internal.OrganizationManagementHandlerDataHolder;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
+import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
+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.model.RoleBasicInfo;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Event handler to manage shared roles in sub-organizations.
+ */
+public class SharedRoleMgtHandler extends AbstractEventHandler {
+
+ private static final Log LOG = LogFactory.getLog(SharedRoleMgtHandler.class);
+ private final ExecutorService executorService = Executors.newFixedThreadPool(5);
+
+ @Override
+ public void handleEvent(Event event) throws IdentityEventException {
+
+ String eventName = event.getEventName();
+ Map eventProperties = event.getEventProperties();
+ switch (eventName) {
+ case OrgApplicationMgtConstants.EVENT_POST_SHARE_APPLICATION:
+ createSharedRolesOnApplicationSharing(eventProperties);
+ break;
+ case IdentityEventConstants.Event.POST_ADD_ROLE_V2_EVENT:
+ createSharedRolesOnNewRoleCreation(eventProperties);
+ break;
+ default:
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unsupported event: " + eventName);
+ }
+ break;
+ }
+ }
+
+ private void createSharedRolesOnApplicationSharing(Map eventProperties)
+ throws IdentityEventException {
+
+ String parentOrganizationId =
+ (String) eventProperties.get(OrgApplicationMgtConstants.EVENT_PROP_PARENT_ORGANIZATION_ID);
+ String parentApplicationId =
+ (String) eventProperties.get(OrgApplicationMgtConstants.EVENT_PROP_PARENT_APPLICATION_ID);
+ String sharedOrganizationId =
+ (String) eventProperties.get(OrgApplicationMgtConstants.EVENT_PROP_SHARED_ORGANIZATION_ID);
+ String sharedApplicationId =
+ (String) eventProperties.get(OrgApplicationMgtConstants.EVENT_PROP_SHARED_APPLICATION_ID);
+ try {
+ String sharedAppTenantDomain = getOrganizationManager().resolveTenantDomain(sharedOrganizationId);
+ String mainAppTenantDomain = getOrganizationManager().resolveTenantDomain(parentOrganizationId);
+ String allowedAudienceForRoleAssociationInMainApp =
+ getApplicationMgtService().getAllowedAudienceForRoleAssociation(parentApplicationId,
+ mainAppTenantDomain);
+ switch (allowedAudienceForRoleAssociationInMainApp) {
+ case RoleConstants.APPLICATION:
+ // Create the roles, and add the relationship.
+ createSharedRolesWithAppAudience(parentApplicationId, mainAppTenantDomain, sharedApplicationId,
+ sharedAppTenantDomain);
+ break;
+ default:
+ // Create the role if not exists, and add the relationship.
+ List associatedRolesOfApplication =
+ getApplicationMgtService().getAssociatedRolesOfApplication(
+ parentApplicationId, mainAppTenantDomain);
+ createSharedRolesWithOrgAudience(associatedRolesOfApplication, mainAppTenantDomain,
+ sharedOrganizationId);
+ break;
+ }
+ } catch (OrganizationManagementException | IdentityRoleManagementException |
+ IdentityApplicationManagementException e) {
+ throw new IdentityEventException(
+ String.format("Error while sharing roles related to application %s.", sharedApplicationId), e);
+ }
+ }
+
+ private void createSharedRolesWithOrgAudience(List rolesList, String mainAppTenantDomain,
+ String sharedAppOrgId)
+ throws IdentityRoleManagementException, OrganizationManagementException {
+
+ if (rolesList == null) {
+ return;
+ }
+ String sharedAppTenantDomain = getOrganizationManager().resolveTenantDomain(sharedAppOrgId);
+ for (RoleV2 role : rolesList) {
+ // Check if the role exists in the application shared org.
+ boolean roleExistsInSharedOrg =
+ getRoleManagementServiceV2().isExistingRoleName(role.getName(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ Map mainRoleToSharedRoleMappingInSharedOrg =
+ getRoleManagementServiceV2().getMainRoleToSharedRoleMappingsBySubOrg(
+ Collections.singletonList(role.getId()), sharedAppTenantDomain);
+ boolean roleRelationshipExistsInSharedOrg =
+ MapUtils.isNotEmpty(mainRoleToSharedRoleMappingInSharedOrg);
+ if (roleExistsInSharedOrg && !roleRelationshipExistsInSharedOrg) {
+ // Add relationship between main role and shared role.
+ String roleIdInSharedOrg =
+ getRoleManagementServiceV2().getRoleIdByName(role.getName(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(role.getId(),
+ roleIdInSharedOrg, mainAppTenantDomain, sharedAppTenantDomain);
+ } else if (!roleExistsInSharedOrg && !roleRelationshipExistsInSharedOrg) {
+ // Create the role in the shared org.
+ RoleBasicInfo sharedRole =
+ getRoleManagementServiceV2().addRole(role.getName(), Collections.emptyList(),
+ Collections.emptyList(), Collections.emptyList(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ // Add relationship between main role and shared role.
+ getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(role.getId(),
+ sharedRole.getId(), mainAppTenantDomain, sharedAppTenantDomain);
+ }
+ }
+ }
+
+ private void createSharedRolesWithAppAudience(String mainAppId, String mainAppTenantDomain, String sharedAppId,
+ String sharedAppTenantDomain) throws IdentityRoleManagementException {
+
+ // Get parent organization's roles which has application audience.
+ String filter = RoleConstants.AUDIENCE_ID + " " + RoleConstants.EQ + " " + mainAppId;
+ List parentOrgRoles =
+ getRoleManagementServiceV2().getRoles(filter, null, 0, null, null, mainAppTenantDomain);
+ for (RoleBasicInfo parentOrgRole : parentOrgRoles) {
+ String parentOrgRoleName = parentOrgRole.getName();
+ // Create the role in the shared org.
+ RoleBasicInfo subOrgRole = getRoleManagementServiceV2().addRole(parentOrgRoleName, Collections.emptyList(),
+ Collections.emptyList(), Collections.emptyList(), RoleConstants.APPLICATION, sharedAppId,
+ sharedAppTenantDomain);
+ // Add relationship between main role and the shared role.
+ getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(parentOrgRole.getId(), subOrgRole.getId(),
+ mainAppTenantDomain, sharedAppTenantDomain);
+ }
+ }
+
+ private void createSharedRolesOnNewRoleCreation(Map eventProperties)
+ throws IdentityEventException {
+
+ try {
+ String mainRoleUUID = (String) eventProperties.get(IdentityEventConstants.EventProperty.ROLE_ID);
+ String mainRoleName = (String) eventProperties.get(IdentityEventConstants.EventProperty.ROLE_NAME);
+ String roleTenantDomain = (String) eventProperties.get(IdentityEventConstants.EventProperty.TENANT_DOMAIN);
+ String roleAudienceType = (String) eventProperties.get(IdentityEventConstants.EventProperty.AUDIENCE);
+ String roleAudienceId = (String) eventProperties.get(IdentityEventConstants.EventProperty.AUDIENCE_ID);
+ String roleOrgId = getOrganizationManager().resolveOrganizationId(roleTenantDomain);
+ if (OrganizationManagementUtil.isOrganization(roleTenantDomain)) {
+ return;
+ }
+ switch (roleAudienceType) {
+ case RoleConstants.APPLICATION:
+ /*
+ If the audienced application is a shared application, create the role in
+ the shared apps' org space.
+ */
+ List sharedApplications =
+ getOrgApplicationManager().getSharedApplications(roleOrgId, roleAudienceId);
+ int noOfSharedApps = sharedApplications.size();
+ for (int i = 0; i < noOfSharedApps; i++) {
+ final int taskId = i;
+ CompletableFuture.runAsync(() -> {
+ try {
+ String sharedApplicationId = sharedApplications.get(taskId).getSharedApplicationId();
+ String sharedOrganizationId = sharedApplications.get(taskId).getOrganizationId();
+ String shareAppTenantDomain =
+ getOrganizationManager().resolveTenantDomain(sharedOrganizationId);
+ RoleBasicInfo sharedRoleInfo =
+ getRoleManagementServiceV2().addRole(mainRoleName, Collections.emptyList(),
+ Collections.emptyList(),
+ Collections.emptyList(), RoleConstants.APPLICATION, sharedApplicationId,
+ shareAppTenantDomain);
+ // Add relationship between main role and shared role.
+ getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(mainRoleUUID,
+ sharedRoleInfo.getId(), roleTenantDomain, shareAppTenantDomain);
+ } catch (IdentityRoleManagementException | OrganizationManagementException e) {
+ LOG.error("Error occurred while creating shared role in organization with id: " +
+ sharedApplications.get(taskId).getOrganizationId(), e);
+ }
+ }, executorService).exceptionally(throwable -> {
+ LOG.error(String.format(
+ "Exception occurred during creating a shared role: %s in organization: %s",
+ mainRoleName, sharedApplications.get(taskId).getOrganizationId()), throwable);
+ return null;
+ });
+ }
+ break;
+ case RoleConstants.ORGANIZATION:
+ /*
+ Organization audience roles can't be attached to an application at the same time of role creation.
+ Organization audience role get shared to other application only if that role is associated with any
+ shared application in the organization. So nothing do in this case.
+ */
+ break;
+ default:
+ LOG.error("Unsupported audience type: " + roleAudienceType);
+ }
+ } catch (OrganizationManagementException e) {
+ throw new IdentityEventException("Error occurred while retrieving shared applications.", e);
+ }
+ }
+
+ private static RoleManagementService getRoleManagementServiceV2() {
+
+ return OrganizationManagementHandlerDataHolder.getInstance().getRoleManagementServiceV2();
+ }
+
+ private static OrganizationManager getOrganizationManager() {
+
+ return OrganizationManagementHandlerDataHolder.getInstance().getOrganizationManager();
+ }
+
+ private static OrgApplicationManager getOrgApplicationManager() {
+
+ return OrganizationManagementHandlerDataHolder.getInstance().getOrgApplicationManager();
+ }
+
+ private static ApplicationManagementService getApplicationMgtService() {
+
+ return OrganizationManagementHandlerDataHolder.getInstance().getApplicationManagementService();
+ }
+}
diff --git a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerDataHolder.java b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerDataHolder.java
index dddbba7b9..41f1d52a3 100644
--- a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerDataHolder.java
+++ b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerDataHolder.java
@@ -18,9 +18,12 @@
package org.wso2.carbon.identity.organization.management.handler.internal;
+import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.event.services.IdentityEventService;
import org.wso2.carbon.identity.governance.IdentityGovernanceService;
+import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
/**
* Organization management handler data holder.
@@ -31,10 +34,11 @@ public class OrganizationManagementHandlerDataHolder {
new OrganizationManagementHandlerDataHolder();
private IdentityEventService identityEventService;
-
private IdentityGovernanceService identityGovernanceService;
-
private OrganizationManager organizationManager;
+ private RoleManagementService roleManagementServiceV2;
+ private OrgApplicationManager orgApplicationManager;
+ private ApplicationManagementService applicationManagementService;
public static OrganizationManagementHandlerDataHolder getInstance() {
@@ -100,5 +104,66 @@ public void setOrganizationManager(OrganizationManager organizationManager) {
this.organizationManager = organizationManager;
}
+
+ /**
+ * Set {@link RoleManagementService}.
+ *
+ * @param roleManagementServiceV2 Instance of {@link RoleManagementService}.
+ */
+ public void setRoleManagementServiceV2(RoleManagementService roleManagementServiceV2) {
+
+ this.roleManagementServiceV2 = roleManagementServiceV2;
+ }
+
+ /**
+ * Get {@link RoleManagementService}.
+ *
+ * @return role management service instance {@link RoleManagementService}.
+ */
+ public RoleManagementService getRoleManagementServiceV2() {
+
+ return roleManagementServiceV2;
+ }
+
+ /**
+ * Get {@link OrgApplicationManager}.
+ *
+ * @return Org application manager instance {@link OrgApplicationManager}.
+ */
+ public OrgApplicationManager getOrgApplicationManager() {
+
+ return orgApplicationManager;
+ }
+
+ /**
+ * Set {@link OrgApplicationManager}.
+ *
+ * @param orgApplicationManager Instance of {@link OrgApplicationManager}.
+ */
+ public void setOrgApplicationManager(OrgApplicationManager orgApplicationManager) {
+
+ this.orgApplicationManager = orgApplicationManager;
+ }
+
+ /**
+ * Get {@link ApplicationManagementService}.
+ *
+ * @return Application management instance {@link ApplicationManagementService}.
+ */
+ public ApplicationManagementService getApplicationManagementService() {
+
+ return applicationManagementService;
+ }
+
+ /**
+ * Set {@link ApplicationManagementService}.
+ *
+ * @param applicationManagementService Instance of {@link ApplicationManagementService}.
+ */
+ public void setApplicationManagementService(
+ ApplicationManagementService applicationManagementService) {
+
+ this.applicationManagementService = applicationManagementService;
+ }
}
diff --git a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerServiceComponent.java b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerServiceComponent.java
index d2e77840c..742934cdf 100644
--- a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerServiceComponent.java
+++ b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/internal/OrganizationManagementHandlerServiceComponent.java
@@ -27,11 +27,17 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
+import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
+import org.wso2.carbon.identity.application.mgt.listener.ApplicationMgtListener;
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
import org.wso2.carbon.identity.event.services.IdentityEventService;
import org.wso2.carbon.identity.governance.IdentityGovernanceService;
+import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager;
import org.wso2.carbon.identity.organization.management.handler.GovernanceConfigUpdateHandler;
+import org.wso2.carbon.identity.organization.management.handler.SharedRoleMgtHandler;
+import org.wso2.carbon.identity.organization.management.handler.listener.SharedRoleMgtListener;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
/**
* Organization management handler service component.
@@ -54,8 +60,9 @@ protected void activate(ComponentContext componentContext) {
try {
BundleContext bundleContext = componentContext.getBundleContext();
- bundleContext.registerService(AbstractEventHandler.class, new GovernanceConfigUpdateHandler(),
- null);
+ bundleContext.registerService(AbstractEventHandler.class, new GovernanceConfigUpdateHandler(), null);
+ bundleContext.registerService(AbstractEventHandler.class, new SharedRoleMgtHandler(), null);
+ bundleContext.registerService(ApplicationMgtListener.class.getName(), new SharedRoleMgtListener(), null);
LOG.debug("Organization management handler component activated successfully.");
} catch (Throwable e) {
LOG.error("Error while activating organization management handler module.", e);
@@ -110,5 +117,59 @@ protected void unsetOrganizationManager(OrganizationManager organizationManager)
OrganizationManagementHandlerDataHolder.getInstance().setOrganizationManager(null);
}
-}
+ @Reference(
+ name = "org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService",
+ service = org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetRoleManagementServiceV2")
+ protected void setRoleManagementServiceV2(RoleManagementService roleManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance().setRoleManagementServiceV2(roleManagementService);
+ LOG.debug("RoleManagementServiceV2 set in OrganizationManagementHandlerService bundle.");
+ }
+
+ protected void unsetRoleManagementServiceV2(RoleManagementService roleManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance().setRoleManagementServiceV2(null);
+ LOG.debug("RoleManagementServiceV2 unset in OrganizationManagementHandlerService bundle.");
+ }
+
+ @Reference(
+ name = "org.wso2.carbon.identity.organization.management.application.OrgApplicationManager",
+ service = org.wso2.carbon.identity.organization.management.application.OrgApplicationManager.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetOrgApplicationManagementService")
+ protected void setOrgApplicationManagementService(OrgApplicationManager orgApplicationManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance().setOrgApplicationManager(orgApplicationManagementService);
+ LOG.debug("OrgApplication management service set in OrganizationManagementHandlerService bundle.");
+ }
+
+ protected void unsetOrgApplicationManagementService(OrgApplicationManager orgApplicationManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance().setOrgApplicationManager(null);
+ LOG.debug("OrgApplication management service unset in OrganizationManagementHandlerService bundle.");
+ }
+
+ @Reference(
+ name = "org.wso2.carbon.identity.application.mgt.ApplicationManagementService",
+ service = org.wso2.carbon.identity.application.mgt.ApplicationManagementService.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetApplicationManagementService")
+ protected void setApplicationManagementService(ApplicationManagementService applicationManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance()
+ .setApplicationManagementService(applicationManagementService);
+ LOG.debug("Application management service set in OrganizationManagementHandlerService bundle.");
+ }
+
+ protected void unsetApplicationManagementService(ApplicationManagementService applicationManagementService) {
+
+ OrganizationManagementHandlerDataHolder.getInstance().setApplicationManagementService(null);
+ LOG.debug("Application management service unset in OrganizationManagementHandlerService bundle.");
+ }
+}
diff --git a/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java
new file mode 100644
index 000000000..b873b34f9
--- /dev/null
+++ b/components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2023, 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.carbon.identity.organization.management.handler.listener;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
+import org.wso2.carbon.identity.application.common.model.RoleV2;
+import org.wso2.carbon.identity.application.common.model.ServiceProvider;
+import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
+import org.wso2.carbon.identity.application.mgt.listener.AbstractApplicationMgtListener;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
+import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager;
+import org.wso2.carbon.identity.organization.management.application.model.SharedApplication;
+import org.wso2.carbon.identity.organization.management.handler.internal.OrganizationManagementHandlerDataHolder;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
+import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
+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.model.RoleBasicInfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.SUPER_ORG_ID;
+
+/**
+ * Application management listener to handle shared roles in organizations.
+ */
+public class SharedRoleMgtListener extends AbstractApplicationMgtListener {
+
+ private static final Log LOG = LogFactory.getLog(SharedRoleMgtListener.class);
+ private static final String REMOVED_APPLICATION_AUDIENCE_ROLES = "removedApplicationAudienceRoles";
+ private static final String ADDED_APPLICATION_AUDIENCE_ROLES = "addedApplicationAudienceRoles";
+ private static final String REMOVED_ORGANIZATION_AUDIENCE_ROLES = "removedOrganizationAudienceRoles";
+ private static final String ADDED_ORGANIZATION_AUDIENCE_ROLES = "addedOrganizationAudienceRoles";
+
+ ApplicationManagementService applicationManagementService =
+ OrganizationManagementHandlerDataHolder.getInstance().getApplicationManagementService();
+ OrganizationManager organizationManager =
+ OrganizationManagementHandlerDataHolder.getInstance().getOrganizationManager();
+ OrgApplicationManager orgApplicationManager =
+ OrganizationManagementHandlerDataHolder.getInstance().getOrgApplicationManager();
+ RoleManagementService roleManagementService =
+ OrganizationManagementHandlerDataHolder.getInstance().getRoleManagementServiceV2();
+ private final ExecutorService executorService = Executors.newFixedThreadPool(5);
+
+ @Override
+ public int getDefaultOrderId() {
+
+ return 49;
+ }
+
+ @Override
+ public boolean doPreUpdateApplication(ServiceProvider serviceProvider, String tenantDomain, String userName)
+ throws IdentityApplicationManagementException {
+
+ // Associated role changes on main applications in tenant need to be handled here.
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantDomain)) {
+ return true;
+ }
+ String applicationResourceId = serviceProvider.getApplicationResourceId();
+ // Get the currently associated roles set from DB/cache.
+ String existingAllowedAudienceForRoleAssociation =
+ applicationManagementService.getAllowedAudienceForRoleAssociation(applicationResourceId,
+ tenantDomain);
+ List existingAssociatedRolesList =
+ applicationManagementService.getAssociatedRolesOfApplication(applicationResourceId, tenantDomain);
+
+ String updatedAllowedAudienceForRoleAssociation =
+ serviceProvider.getAssociatedRolesConfig() == null ? RoleConstants.ORGANIZATION :
+ serviceProvider.getAssociatedRolesConfig().getAllowedAudience();
+
+ List updatedAssociatedRolesList;
+ if (serviceProvider.getAssociatedRolesConfig() != null &&
+ serviceProvider.getAssociatedRolesConfig().getRoles() != null) {
+ updatedAssociatedRolesList = Arrays.asList(serviceProvider.getAssociatedRolesConfig().getRoles());
+ } else {
+ updatedAssociatedRolesList = new ArrayList<>();
+ }
+
+ if (CollectionUtils.isEmpty(existingAssociatedRolesList) &&
+ CollectionUtils.isEmpty(updatedAssociatedRolesList)) {
+ // No change in roles list.
+ return true;
+ }
+
+ /*
+ if old and new audiences are equals, need to handle the role diff.
+ */
+ if (existingAllowedAudienceForRoleAssociation.equalsIgnoreCase(updatedAllowedAudienceForRoleAssociation)) {
+ switch (updatedAllowedAudienceForRoleAssociation) {
+ case RoleConstants.APPLICATION:
+ List addedApplicationAudienceRoles = updatedAssociatedRolesList.stream()
+ .filter(updatedRole -> !existingAssociatedRolesList.contains(updatedRole))
+ .collect(Collectors.toList());
+
+ List removedApplicationAudienceRoles = existingAssociatedRolesList.stream()
+ .filter(existingRole -> !updatedAssociatedRolesList.contains(existingRole))
+ .collect(Collectors.toList());
+ // Add to threadLocal.
+ IdentityUtil.threadLocalProperties.get()
+ .put(ADDED_APPLICATION_AUDIENCE_ROLES, addedApplicationAudienceRoles);
+ IdentityUtil.threadLocalProperties.get()
+ .put(REMOVED_APPLICATION_AUDIENCE_ROLES, removedApplicationAudienceRoles);
+ return true;
+ default:
+ if (existingAssociatedRolesList.equals(updatedAssociatedRolesList)) {
+ // Nothing to change in shared applications' organizations.
+ return true;
+ }
+ // Get the added roles and removed roles.
+ List addedOrganizationAudienceRoles = updatedAssociatedRolesList.stream()
+ .filter(updatedRole -> !existingAssociatedRolesList.contains(updatedRole))
+ .collect(Collectors.toList());
+
+ List removedOrganizationAudienceRoles = existingAssociatedRolesList.stream()
+ .filter(existingRole -> !updatedAssociatedRolesList.contains(existingRole))
+ .collect(Collectors.toList());
+ // Add to threadLocal.
+ IdentityUtil.threadLocalProperties.get()
+ .put(ADDED_ORGANIZATION_AUDIENCE_ROLES, addedOrganizationAudienceRoles);
+ IdentityUtil.threadLocalProperties.get()
+ .put(REMOVED_ORGANIZATION_AUDIENCE_ROLES, removedOrganizationAudienceRoles);
+ return true;
+ }
+ }
+
+ /*
+ If audience has changed from application to organization, all previous associated roles will be deleted.
+ For updated organization roles, create shared role in organizations below if applicable.
+ */
+ if (RoleConstants.APPLICATION.equalsIgnoreCase(existingAllowedAudienceForRoleAssociation) &&
+ RoleConstants.ORGANIZATION.equalsIgnoreCase(updatedAllowedAudienceForRoleAssociation)) {
+
+ // Add to thread local.
+ IdentityUtil.threadLocalProperties.get()
+ .put(REMOVED_APPLICATION_AUDIENCE_ROLES, existingAssociatedRolesList);
+ IdentityUtil.threadLocalProperties.get()
+ .put(ADDED_ORGANIZATION_AUDIENCE_ROLES, updatedAssociatedRolesList);
+ return true;
+ }
+
+ /*
+ If audience has changed from organization to application, need to remove the organization roles.
+ Nothing to handle in application audience roles because they will be added/deleted in shared orgs
+ based on role creation/deletion.
+ */
+ if (RoleConstants.ORGANIZATION.equalsIgnoreCase(existingAllowedAudienceForRoleAssociation) &&
+ RoleConstants.APPLICATION.equalsIgnoreCase(updatedAllowedAudienceForRoleAssociation)) {
+
+ // Add to thread local.
+ IdentityUtil.threadLocalProperties.get()
+ .put(REMOVED_ORGANIZATION_AUDIENCE_ROLES, existingAssociatedRolesList);
+ return true;
+ }
+ } catch (OrganizationManagementException e) {
+ throw new IdentityApplicationManagementException(
+ String.format("Error while checking shared roles to be updated related to application %s update.",
+ serviceProvider.getApplicationID()), e);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean doPostUpdateApplication(ServiceProvider serviceProvider, String tenantDomain, String userName)
+ throws IdentityApplicationManagementException {
+
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantDomain)) {
+ return true;
+ }
+ Object addedAppRoles = IdentityUtil.threadLocalProperties.get().get(ADDED_APPLICATION_AUDIENCE_ROLES);
+ if (addedAppRoles != null) {
+ List addedAppRolesList = (List) addedAppRoles;
+ handleAddedApplicationAudienceRolesOnAppUpdate(addedAppRolesList, serviceProvider, tenantDomain);
+ }
+
+ Object removedAppRoles = IdentityUtil.threadLocalProperties.get().get(REMOVED_APPLICATION_AUDIENCE_ROLES);
+ if (removedAppRoles != null) {
+ List removedAppRolesList = (List) removedAppRoles;
+ handleRemovedApplicationAudienceRolesOnAppUpdate(removedAppRolesList, tenantDomain);
+ }
+
+ Object addedOrgRoles = IdentityUtil.threadLocalProperties.get().get(ADDED_ORGANIZATION_AUDIENCE_ROLES);
+ if (addedOrgRoles != null) {
+ List addedOrgRolesList = (List) addedOrgRoles;
+ List namesResolvedAddedRolesList = addedOrgRolesList.stream()
+ .map(role -> {
+ try {
+ String roleName = roleManagementService.getRoleNameByRoleId(role.getId(), tenantDomain);
+ if (roleName != null) {
+ return new RoleV2(role.getId(), roleName);
+ }
+ return null;
+ } catch (Exception e) {
+ LOG.error("Failed to resolve role name of role id: " + role.getId());
+ return null;
+ }
+ })
+ .filter(Objects::nonNull) // Filter out null values (roles that couldn't be resolved)
+ .collect(Collectors.toList());
+
+ handleAddedOrganizationAudienceRolesOnAppUpdate(namesResolvedAddedRolesList, serviceProvider,
+ tenantDomain);
+ }
+
+ Object removedOrgRoles = IdentityUtil.threadLocalProperties.get().get(REMOVED_ORGANIZATION_AUDIENCE_ROLES);
+ if (removedOrgRoles != null) {
+ List removedOrgRolesList = (List) removedOrgRoles;
+ handleRemovedOrganizationAudienceRolesOnAppUpdate(removedOrgRolesList, serviceProvider, tenantDomain);
+ }
+ } catch (OrganizationManagementException | IdentityRoleManagementException e) {
+ throw new IdentityApplicationManagementException(
+ String.format("Error while updating shared roles related to application %s update.",
+ serviceProvider.getApplicationID()), e);
+ } finally {
+ IdentityUtil.threadLocalProperties.get().remove(ADDED_APPLICATION_AUDIENCE_ROLES);
+ IdentityUtil.threadLocalProperties.get().remove(REMOVED_APPLICATION_AUDIENCE_ROLES);
+ IdentityUtil.threadLocalProperties.get().remove(ADDED_ORGANIZATION_AUDIENCE_ROLES);
+ IdentityUtil.threadLocalProperties.get().remove(REMOVED_ORGANIZATION_AUDIENCE_ROLES);
+ }
+ return true;
+ }
+
+ private void handleRemovedOrganizationAudienceRolesOnAppUpdate(List removedOrgRolesList,
+ ServiceProvider serviceProvider, String tenantDomain)
+ throws OrganizationManagementException, IdentityRoleManagementException {
+
+ if (CollectionUtils.isEmpty(removedOrgRolesList)) {
+ return;
+ }
+ String mainAppId = serviceProvider.getApplicationResourceId();
+ String mainAppOrgId = organizationManager.resolveOrganizationId(tenantDomain);
+ List sharedApplications =
+ orgApplicationManager.getSharedApplications(mainAppOrgId, mainAppId);
+ if (CollectionUtils.isEmpty(sharedApplications)) {
+ return;
+ }
+ for (SharedApplication sharedApplication : sharedApplications) {
+ CompletableFuture.runAsync(() -> {
+ String sharedAppOrgId = sharedApplication.getOrganizationId();
+ try {
+ handleOrganizationAudiencedSharedRoleDeletion(removedOrgRolesList,
+ serviceProvider.getApplicationResourceId(),
+ tenantDomain, sharedAppOrgId);
+ } catch (IdentityRoleManagementException | OrganizationManagementException e) {
+ LOG.error(String.format("Exception occurred during deleting roles from organization %s",
+ sharedApplication.getOrganizationId()), e);
+ }
+ }, executorService).exceptionally(throwable -> {
+ LOG.error(String.format("Exception occurred during deleting roles from organization %s",
+ sharedApplication.getOrganizationId()), throwable);
+ return null;
+ });
+ }
+ }
+
+ private void handleAddedOrganizationAudienceRolesOnAppUpdate(List addedOrgRolesList,
+ ServiceProvider serviceProvider, String tenantDomain)
+ throws OrganizationManagementException, IdentityRoleManagementException {
+
+ if (CollectionUtils.isEmpty(addedOrgRolesList)) {
+ return;
+ }
+ String mainAppId = serviceProvider.getApplicationResourceId();
+ String mainAppOrgId = organizationManager.resolveOrganizationId(tenantDomain);
+ List sharedApplications =
+ orgApplicationManager.getSharedApplications(mainAppOrgId, mainAppId);
+ if (CollectionUtils.isEmpty(sharedApplications)) {
+ return;
+ }
+
+ for (SharedApplication sharedApplication : sharedApplications) {
+ CompletableFuture.runAsync(() -> {
+ String sharedAppOrgId = sharedApplication.getOrganizationId();
+ try {
+ createSharedRolesWithOrgAudience(addedOrgRolesList, tenantDomain, sharedAppOrgId);
+ } catch (IdentityRoleManagementException | OrganizationManagementException e) {
+ LOG.error(String.format("Exception occurred while adding shared roles to organization: %s",
+ sharedApplication.getOrganizationId()), e);
+ }
+ }, executorService).exceptionally(throwable -> {
+ LOG.error(String.format("Exception occurred while adding shared roles to organization: %s",
+ sharedApplication.getOrganizationId()), throwable);
+ return null;
+ });
+ }
+ }
+
+ private void createSharedRolesWithOrgAudience(List rolesList, String mainAppTenantDomain,
+ String sharedAppOrgId)
+ throws IdentityRoleManagementException, OrganizationManagementException {
+
+ if (rolesList == null) {
+ return;
+ }
+ String sharedAppTenantDomain = organizationManager.resolveTenantDomain(sharedAppOrgId);
+ for (RoleV2 role : rolesList) {
+ // Check if the role exists in the application shared org.
+ boolean roleExistsInSharedOrg =
+ roleManagementService.isExistingRoleName(role.getName(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ Map mainRoleToSharedRoleMappingInSharedOrg =
+ roleManagementService.getMainRoleToSharedRoleMappingsBySubOrg(
+ Collections.singletonList(role.getId()), sharedAppTenantDomain);
+ boolean roleRelationshipExistsInSharedOrg =
+ MapUtils.isNotEmpty(mainRoleToSharedRoleMappingInSharedOrg);
+ if (roleExistsInSharedOrg && !roleRelationshipExistsInSharedOrg) {
+ // Add relationship between main role and shared role.
+ String roleIdInSharedOrg =
+ roleManagementService.getRoleIdByName(role.getName(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ roleManagementService.addMainRoleToSharedRoleRelationship(role.getId(),
+ roleIdInSharedOrg, mainAppTenantDomain, sharedAppTenantDomain);
+ } else if (!roleExistsInSharedOrg && !roleRelationshipExistsInSharedOrg) {
+ // Create the role in the shared org.
+ RoleBasicInfo sharedRole = roleManagementService.addRole(role.getName(), Collections.emptyList(),
+ Collections.emptyList(), Collections.emptyList(), RoleConstants.ORGANIZATION,
+ sharedAppOrgId, sharedAppTenantDomain);
+ // Add relationship between main role and shared role.
+ roleManagementService.addMainRoleToSharedRoleRelationship(role.getId(),
+ sharedRole.getId(), mainAppTenantDomain, sharedAppTenantDomain);
+ }
+ }
+ }
+
+ private void handleRemovedApplicationAudienceRolesOnAppUpdate(List removedAppRolesList, String tenantDomain)
+ throws IdentityRoleManagementException {
+
+ if (CollectionUtils.isEmpty(removedAppRolesList)) {
+ return;
+ }
+ /*
+ Delete the application audience roles from parent organization. Deleting their shared roles also handled inside.
+ */
+ for (RoleV2 removedRole : removedAppRolesList) {
+ roleManagementService.deleteRole(removedRole.getId(), tenantDomain);
+ }
+ }
+
+ private void handleAddedApplicationAudienceRolesOnAppUpdate(List addedAppRolesList,
+ ServiceProvider serviceProvider, String tenantDomain)
+ throws OrganizationManagementException, IdentityRoleManagementException {
+
+ if (CollectionUtils.isEmpty(addedAppRolesList)) {
+ return;
+ }
+ // Get shared applications of the given main app, and share the role.
+ String mainAppId = serviceProvider.getApplicationResourceId();
+ String mainAppOrgId = organizationManager.resolveOrganizationId(tenantDomain);
+
+ List sharedApplications =
+ orgApplicationManager.getSharedApplications(mainAppOrgId, mainAppId);
+ if (CollectionUtils.isEmpty(sharedApplications)) {
+ return;
+ }
+
+ for (RoleV2 parentRole : addedAppRolesList) {
+ for (SharedApplication sharedApplication : sharedApplications) {
+ String sharedAppOrgId = sharedApplication.getOrganizationId();
+ String sharedAppTenantDomain = organizationManager.resolveTenantDomain(sharedAppOrgId);
+ String parentAppRoleName = parentRole.getName();
+ // Create the role in the shared org.
+ RoleBasicInfo subOrgRole =
+ roleManagementService.addRole(parentAppRoleName, Collections.emptyList(),
+ Collections.emptyList(), Collections.emptyList(), RoleConstants.APPLICATION,
+ sharedApplication.getSharedApplicationId(),
+ sharedAppTenantDomain);
+ // Add relationship between main role and the shared role.
+ roleManagementService.addMainRoleToSharedRoleRelationship(parentRole.getId(), subOrgRole.getId(),
+ tenantDomain, sharedAppTenantDomain);
+ }
+ }
+ }
+
+ @Override
+ public boolean doPreDeleteApplication(String applicationName, String tenantDomain, String userName)
+ throws IdentityApplicationManagementException {
+
+ try {
+ // If the deleting application is an application of tenant(i.e primary org) nothing to do here.
+ if (!OrganizationManagementUtil.isOrganization(tenantDomain)) {
+ return true;
+ }
+
+ ServiceProvider sharedApplication = getApplicationByName(applicationName, tenantDomain);
+ if (sharedApplication == null) {
+ return false;
+ }
+ String sharedAppId = sharedApplication.getApplicationResourceId();
+ String sharedAppOrgId = organizationManager.resolveOrganizationId(tenantDomain);
+ // Resolve the main application details.
+ String mainAppId = orgApplicationManager.getMainApplicationIdForGivenSharedApp(sharedAppId, sharedAppOrgId);
+ if (mainAppId == null) {
+ return false;
+ }
+ int mainAppTenantId = applicationManagementService.getTenantIdByApp(mainAppId);
+ String mainAppTenantDomain = IdentityTenantUtil.getTenantDomain(mainAppTenantId);
+
+ String allowedAudienceForRoleAssociationInMainApp =
+ applicationManagementService.getAllowedAudienceForRoleAssociation(mainAppId, mainAppTenantDomain);
+ boolean hasAppAudiencedRoles =
+ RoleConstants.APPLICATION.equalsIgnoreCase(allowedAudienceForRoleAssociationInMainApp);
+ if (hasAppAudiencedRoles) {
+ // Handle role deletion in application deletion post actions.
+ return true;
+ }
+
+ // Handing organization audienced roles associated case.
+ List associatedRolesOfMainApplication = applicationManagementService
+ .getAssociatedRolesOfApplication(mainAppId, mainAppTenantDomain);
+ handleOrganizationAudiencedSharedRoleDeletion(associatedRolesOfMainApplication, mainAppId,
+ mainAppTenantDomain, sharedAppOrgId);
+ } catch (OrganizationManagementException | IdentityRoleManagementException e) {
+ throw new IdentityApplicationManagementException(
+ "Error while deleting organization roles associated to the app.", e);
+ }
+ return super.doPreDeleteApplication(applicationName, tenantDomain, userName);
+ }
+
+ private void handleOrganizationAudiencedSharedRoleDeletion(List rolesList, String mainApplicationId,
+ String mainApplicationTenantDomain,
+ String sharedAppOrgId)
+ throws IdentityRoleManagementException, OrganizationManagementException {
+
+ String mainApplicationOrgId = organizationManager.resolveOrganizationId(mainApplicationTenantDomain);
+ if (mainApplicationOrgId == null) {
+ mainApplicationOrgId = SUPER_ORG_ID;
+ }
+ String sharedAppTenantDomain = organizationManager.resolveTenantDomain(sharedAppOrgId);
+ List mainAppRoleIds =
+ rolesList.stream().map(RoleV2::getId).collect(Collectors.toList());
+ Map mainRoleToSharedRoleMappingsInSubOrg =
+ roleManagementService.getMainRoleToSharedRoleMappingsBySubOrg(mainAppRoleIds, sharedAppTenantDomain);
+
+ // Get each role associated applications.
+ for (String mainAppRoleId : mainAppRoleIds) {
+ List associatedApplicationsIds =
+ roleManagementService.getAssociatedApplicationByRoleId(mainAppRoleId,
+ mainApplicationTenantDomain);
+ String sharedRoleId = mainRoleToSharedRoleMappingsInSubOrg.get(mainAppRoleId);
+ if (StringUtils.isBlank(sharedRoleId)) {
+ // There is no role available in the shared org. May be due to role creation issue.
+ continue;
+ }
+ /*
+ If this private method is called from application update post listener, the role already removed
+ from the application. associatedApplicationsIds is empty means there are no any other applications.
+
+ If this private method is called from application deletion post listener,
+ and if the only associated application is the main app in this flow, this condition is satisfied.
+ Hence, deleting the shared roles.
+ */
+ if (CollectionUtils.isEmpty(associatedApplicationsIds) || (associatedApplicationsIds.size() == 1 &&
+ mainApplicationId.equals(associatedApplicationsIds.get(0)))) {
+ try {
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(sharedAppTenantDomain, true);
+ roleManagementService.deleteRole(sharedRoleId, sharedAppTenantDomain);
+ } finally {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ } else if (associatedApplicationsIds.size() > 1) {
+ boolean isRoleUsedByAnotherSharedApp = false;
+ for (String associatedApplicationId : associatedApplicationsIds) {
+ if (associatedApplicationId.equals(mainApplicationId)) {
+ continue;
+ }
+ boolean applicationSharedWithGivenOrganization =
+ orgApplicationManager.isApplicationSharedWithGivenOrganization(associatedApplicationId,
+ mainApplicationOrgId, sharedAppOrgId);
+ if (applicationSharedWithGivenOrganization) {
+ isRoleUsedByAnotherSharedApp = true;
+ break;
+ }
+ }
+ if (!isRoleUsedByAnotherSharedApp) {
+ // Delete the role in org.
+ roleManagementService.deleteRole(sharedRoleId, sharedAppTenantDomain);
+ break;
+ }
+ }
+ }
+ }
+
+ private ServiceProvider getApplicationByName(String name, String tenantDomain)
+ throws IdentityApplicationManagementException {
+
+ return applicationManagementService.getServiceProvider(name, tenantDomain);
+ }
+}
diff --git a/pom.xml b/pom.xml
index b145e912c..8d0fb2bb9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -240,7 +240,11 @@
org.wso2.carbon.identity.governance
${org.wso2.carbon.identity.governance.version}
-
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.role.v2.mgt.core
+ ${carbon.identity.framework.version}
+
com.google.code.findbugs
annotations
@@ -499,7 +503,7 @@
[4.7.0,5.0.0)
- 5.25.400
+ 5.25.426
[5.20.0, 7.0.0)