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

Resolve role sharing conflicts in app sharing #413

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.application.mgt</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.central.log.mgt</artifactId>
</dependency>
<!--Test Dependencies-->
<dependency>
<groupId>org.testng</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2024, 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
Expand All @@ -26,6 +26,9 @@
import org.wso2.carbon.identity.application.common.model.ApplicationBasicInfo;
import org.wso2.carbon.identity.application.common.model.RoleV2;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.central.log.mgt.utils.LogConstants;
import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.event.IdentityEventConstants;
import org.wso2.carbon.identity.event.IdentityEventException;
import org.wso2.carbon.identity.event.event.Event;
Expand All @@ -42,9 +45,11 @@
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 org.wso2.carbon.utils.AuditLog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -72,6 +77,9 @@
case IdentityEventConstants.Event.POST_ADD_ROLE_V2_EVENT:
createSharedRolesOnNewRoleCreation(eventProperties);
break;
case OrgApplicationMgtConstants.EVENT_PRE_SHARE_APPLICATION:
checkSharingRoleConflicts(eventProperties);
break;
default:
if (LOG.isDebugEnabled()) {
LOG.debug("Unsupported event: " + eventName);
Expand Down Expand Up @@ -271,13 +279,31 @@
for (BasicOrganization organization : applicationSharedOrganizations) {
String shareAppTenantDomain =
getOrganizationManager().resolveTenantDomain(organization.getId());
RoleBasicInfo sharedRoleInfo = getRoleManagementServiceV2().addRole(mainRoleName,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(), RoleConstants.ORGANIZATION, organization.getId(),
shareAppTenantDomain);
getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(mainRoleUUID,
sharedRoleInfo.getId(), roleTenantDomain, shareAppTenantDomain);
if (!getRoleManagementServiceV2().isExistingRoleName(mainRoleName, RoleConstants.ORGANIZATION,
organization.getId(), shareAppTenantDomain)) {
RoleBasicInfo sharedRoleInfo = getRoleManagementServiceV2().addRole(mainRoleName,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(), RoleConstants.ORGANIZATION, organization.getId(),

Check warning on line 287 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L283-L287

Added lines #L283 - L287 were not covered by tests
shareAppTenantDomain);
getRoleManagementServiceV2().addMainRoleToSharedRoleRelationship(mainRoleUUID,
sharedRoleInfo.getId(), roleTenantDomain, shareAppTenantDomain);
} else {

Check warning on line 291 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L289-L291

Added lines #L289 - L291 were not covered by tests
if (LoggerUtils.isEnableV2AuditLogs()) {
String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().
getTenantDomain();
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
IdentityUtil.getInitiatorId(username, tenantDomain),
LoggerUtils.Target.User.name(), mainRoleName, LoggerUtils.Target.Role.name(),

Check warning on line 298 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L293-L298

Added lines #L293 - L298 were not covered by tests
LogConstants.UserManagement.ADD_ROLE_ACTION)
.data(buildAuditData(roleOrgId, null, organization.getId(), mainRoleName,

Check warning on line 300 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L300

Added line #L300 was not covered by tests
mainRoleUUID, "Role conflict"));
LoggerUtils.triggerAuditLogEvent(auditLogBuilder, true);

Check warning on line 302 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L302

Added line #L302 was not covered by tests
}
LOG.warn(String.format("Organization %s has a non shared role with name %s, ",
organization.getId(), mainRoleName));

Check warning on line 305 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L304-L305

Added lines #L304 - L305 were not covered by tests
}
}
break;
default:
Expand All @@ -289,6 +315,60 @@
}
}

private void checkSharingRoleConflicts(Map<String, Object> 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);
if (RoleConstants.ORGANIZATION.equals(allowedAudienceForRoleAssociationInMainApp.toLowerCase())) {
List<RoleV2> associatedRolesOfApplication = getApplicationMgtService().
getAssociatedRolesOfApplication(parentApplicationId, mainAppTenantDomain);
for (RoleV2 roleV2 : associatedRolesOfApplication) {
boolean roleExistsInSharedOrg = getRoleManagementServiceV2().isExistingRoleName(roleV2.getName(),
RoleConstants.ORGANIZATION, sharedOrganizationId, sharedAppTenantDomain);
Map<String, String> mainRoleToSharedRoleMappingInSharedOrg =
getRoleManagementServiceV2().getMainRoleToSharedRoleMappingsBySubOrg(
Collections.singletonList(roleV2.getId()), sharedAppTenantDomain);
boolean roleRelationshipExistsInSharedOrg =
MapUtils.isNotEmpty(mainRoleToSharedRoleMappingInSharedOrg);
if (roleExistsInSharedOrg && !roleRelationshipExistsInSharedOrg) {
// If the role exists in the shared org, but the relationship does not exist then this role is
// created directly in the sub organization level. So this is a conflict to share the role
// with same name and organization audience to the sub organization.
if (LoggerUtils.isEnableV2AuditLogs()) {
String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().
getTenantDomain();
AuditLog.AuditLogBuilder auditLogBuilder = new AuditLog.AuditLogBuilder(
IdentityUtil.getInitiatorId(username, tenantDomain),
LoggerUtils.Target.User.name(), roleV2.getName(), LoggerUtils.Target.Role.name(),
LogConstants.ApplicationManagement.CREATE_APPLICATION_ACTION).
data(buildAuditData(parentOrganizationId, parentApplicationId,
sharedOrganizationId, roleV2.getName(), roleV2.getId(), "Role conflict"));
LoggerUtils.triggerAuditLogEvent(auditLogBuilder, true);
}
throw new IdentityEventException(String.format("Organization %s has a non shared role with " +
"name %s, ", sharedOrganizationId, roleV2.getName()));
}
}
}
} catch (OrganizationManagementException | IdentityRoleManagementException |

Check warning on line 365 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L365

Added line #L365 was not covered by tests
IdentityApplicationManagementException e) {
throw new IdentityEventException(String.format("Error while sharing roles related to application %s.",

Check warning on line 367 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/SharedRoleMgtHandler.java#L367

Added line #L367 was not covered by tests
sharedApplicationId), e);
}
}

private static RoleManagementService getRoleManagementServiceV2() {

return OrganizationManagementHandlerDataHolder.getInstance().getRoleManagementServiceV2();
Expand All @@ -308,4 +388,18 @@

return OrganizationManagementHandlerDataHolder.getInstance().getApplicationManagementService();
}

private Map<String, String> buildAuditData(String parentOrganizationId, String parentApplicationId,
String sharedOrganizationId, String roleName, String roleId,
String failureReason) {

Map<String, String> auditData = new HashMap<>();
auditData.put(RoleConstants.PARENT_ORG_ID, parentOrganizationId);
auditData.put("parentApplicationId", parentApplicationId);
auditData.put(RoleConstants.SHARED_ORG_ID, sharedOrganizationId);
auditData.put("roleId", roleId);
auditData.put("roleName", roleName);
auditData.put(RoleConstants.FAILURE_REASON, failureReason);
return auditData;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2024, 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
Expand Down Expand Up @@ -608,11 +608,13 @@
throws IdentityApplicationManagementException {

try {
if (!OrganizationManagementUtil.isOrganization(tenantDomain)) {
String mainAppId = applicationManagementService.getMainAppId(applicationUUID);

Check warning on line 611 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java#L611

Added line #L611 was not covered by tests
// If the main application id is null, then this is the main application. We can skip this operation based
// on that.
if (StringUtils.isEmpty(mainAppId)) {
return true;
}
// Resolve the associated roles of shared application from main application details.
String mainAppId = applicationManagementService.getMainAppId(applicationUUID);
int mainAppTenantId = applicationManagementService.getTenantIdByApp(mainAppId);
String mainAppTenantDomain = IdentityTenantUtil.getTenantDomain(mainAppTenantId);
List<RoleV2> resolvedAssociatedRolesFromMainApp =
Expand Down Expand Up @@ -641,7 +643,7 @@
.collect(Collectors.toList());
associatedRolesOfApplication.clear();
associatedRolesOfApplication.addAll(associatedRolesOfSharedApplication);
} catch (OrganizationManagementException | IdentityRoleManagementException e) {
} catch (IdentityRoleManagementException e) {

Check warning on line 646 in components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java

View check run for this annotation

Codecov / codecov/patch

components/org.wso2.carbon.identity.organization.management.handler/src/main/java/org/wso2/carbon/identity/organization/management/handler/listener/SharedRoleMgtListener.java#L646

Added line #L646 was not covered by tests
throw new IdentityApplicationManagementException(String.format(
"Error while fetching the allowed audience for role association of application with: %s.",
applicationUUID), e);
Expand Down
Loading
Loading