Skip to content

Commit

Permalink
Restrict shared apps to only use shared roles when shared apps are ac…
Browse files Browse the repository at this point in the history
…cessed
  • Loading branch information
ShanChathusanda93 committed Feb 3, 2025
1 parent 5938f4d commit b4a3e8b
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
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.carbon.identity.role.v2.mgt.core.model.RoleProperty;
import org.wso2.carbon.identity.role.v2.mgt.core.model.UserBasicInfo;

import java.util.ArrayList;
Expand Down Expand Up @@ -447,6 +448,11 @@ public void preGetRoleIdListOfUser(String userId, String tenantDomain) throws Id
public void postGetRoleIdListOfUser(List<String> roleIds, String userId, String tenantDomain)
throws IdentityRoleManagementException {

if (!isFragmentApplication()) {
return;
}

filterAndRemoveNonSharedRoles(roleIds, tenantDomain);
}

@Override
Expand All @@ -459,6 +465,45 @@ public void preGetRoleIdListOfGroups(List<String> groupIds, String tenantDomain)
public void postGetRoleIdListOfGroups(List<String> roleIds, String tenantDomain)
throws IdentityRoleManagementException {

if (!isFragmentApplication()) {
return;
}

filterAndRemoveNonSharedRoles(roleIds, tenantDomain);
}

private static boolean isFragmentApplication() {

boolean isFragmentApp = false;
if (IdentityUtil.threadLocalProperties.get().get(ApplicationConstants.IS_FRAGMENT_APP) != null) {
isFragmentApp = Boolean.parseBoolean(IdentityUtil.threadLocalProperties.get().
get(ApplicationConstants.IS_FRAGMENT_APP).toString());
}

return isFragmentApp;
}

private boolean isSharedRole (List<RoleProperty> roleProperties) {

if (CollectionUtils.isEmpty(roleProperties)) {
return false;
}
return roleProperties.stream().anyMatch(property -> "isSharedRole".equals(property.getName())
&& Boolean.parseBoolean(property.getValue()));
}

private void filterAndRemoveNonSharedRoles(List<String> roleIds, String tenantDomain)
throws IdentityRoleManagementException {

Iterator<String> iterator = roleIds.iterator();
while (iterator.hasNext()) {
String roleId = iterator.next();
Role role = ApplicationManagementServiceComponentHolder.getInstance().getRoleManagementServiceV2()
.getRole(roleId, tenantDomain);
if (role.getRoleProperties() != null && !isSharedRole(role.getRoleProperties())) {
iterator.remove();
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.application.common.model.ServiceProviderProperty;
import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponentHolder;
import org.wso2.carbon.identity.application.mgt.listener.DefaultRoleManagementListener;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementClientException;
import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementServerException;
import org.wso2.carbon.identity.role.v2.mgt.core.model.Role;
import org.wso2.carbon.identity.role.v2.mgt.core.model.RoleProperty;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.mockito.ArgumentMatchers.anyString;
Expand Down Expand Up @@ -81,6 +86,15 @@ public Object[][] fragmentAppPropertyProvider() {
};
}

@DataProvider(name = "fragmentAppBooleanProvider")
public Object[][] fragmentAppBooleanProvider() {

return new Object[][] {
{false},
{true}
};
}

@Test(priority = 1, dataProvider = "fragmentAppPropertyProvider")
public void testPreAddRoleForFragmentApp(boolean isFragmentApp, ServiceProvider application) throws Exception {

Expand Down Expand Up @@ -250,6 +264,86 @@ public void testPreAddRoleWithApplicationRetrievingException() throws Exception
}
}

@Test(priority = 8, dataProvider = "fragmentAppBooleanProvider")
public void testPostGetRoleIdListOfUser(boolean isFragmentApp) throws Exception {

List<String> roleIds = new ArrayList<>();
roleIds.add("role1-uuid");
roleIds.add("role2-uuid");

Map<String, Object> threadLocalProps = new HashMap<>();
if (isFragmentApp) {
RoleManagementService roleManagementService = mock(RoleManagementService.class);
ApplicationManagementServiceComponentHolder.getInstance().setRoleManagementServiceV2(roleManagementService);

// Creating a non-shared role object.
Role role1 = new Role();
role1.setId("role1-uuid");
RoleProperty roleProperty1 = new RoleProperty();
roleProperty1.setName("isSharedRole");
roleProperty1.setValue(Boolean.FALSE.toString());
role1.setRoleProperty(roleProperty1);

// Creating a shared role object.
Role role2 = new Role();
role2.setId("role2-uuid");
RoleProperty roleProperty2 = new RoleProperty();
roleProperty2.setName("isSharedRole");
roleProperty2.setValue(Boolean.TRUE.toString());
role2.setRoleProperty(roleProperty2);

when(roleManagementService.getRole("role1-uuid", TENANT_DOMAIN)).thenReturn(role1);
when(roleManagementService.getRole("role2-uuid", TENANT_DOMAIN)).thenReturn(role2);

threadLocalProps.put(IS_FRAGMENT_APP, isFragmentApp);
}
IdentityUtil.threadLocalProperties.set(threadLocalProps);
defaultRoleManagementListener.postGetRoleIdListOfUser(roleIds, "user1-uuid", TENANT_DOMAIN);

// Clearing the thread local properties.
IdentityUtil.threadLocalProperties.set(new HashMap<>());
}

@Test(priority = 9, dataProvider = "fragmentAppBooleanProvider")
public void testPostGetRoleIdListOfGroups(boolean isFragmentApp) throws Exception {

List<String> roleIds = new ArrayList<>();
roleIds.add("role1-uuid");
roleIds.add("role2-uuid");

Map<String, Object> threadLocalProps = new HashMap<>();
if (isFragmentApp) {
RoleManagementService roleManagementService = mock(RoleManagementService.class);
ApplicationManagementServiceComponentHolder.getInstance().setRoleManagementServiceV2(roleManagementService);

// Creating a non-shared role object.
Role role1 = new Role();
role1.setId("role1-uuid");
RoleProperty roleProperty1 = new RoleProperty();
roleProperty1.setName("isSharedRole");
roleProperty1.setValue(Boolean.FALSE.toString());
role1.setRoleProperty(roleProperty1);

// Creating a shared role object.
Role role2 = new Role();
role2.setId("role2-uuid");
RoleProperty roleProperty2 = new RoleProperty();
roleProperty2.setName("isSharedRole");
roleProperty2.setValue(Boolean.TRUE.toString());
role2.setRoleProperty(roleProperty2);

when(roleManagementService.getRole("role1-uuid", TENANT_DOMAIN)).thenReturn(role1);
when(roleManagementService.getRole("role2-uuid", TENANT_DOMAIN)).thenReturn(role2);

threadLocalProps.put(IS_FRAGMENT_APP, isFragmentApp);
}
IdentityUtil.threadLocalProperties.set(threadLocalProps);
defaultRoleManagementListener.postGetRoleIdListOfGroups(roleIds, TENANT_DOMAIN);

// Clearing the thread local properties.
IdentityUtil.threadLocalProperties.set(new HashMap<>());
}

private static ServiceProviderProperty buildServiceProviderProperty(String name, String value) {

ServiceProviderProperty isFragmentAppSpProp = new ServiceProviderProperty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
import org.wso2.carbon.identity.application.common.model.IdPGroup;
import org.wso2.carbon.identity.application.common.model.IdentityProvider;
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.ApplicationConstants;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementException;
Expand Down Expand Up @@ -61,6 +65,7 @@
import static org.wso2.carbon.identity.application.authentication.framework.handler.approles.constant.AppRolesConstants.ErrorMessages.ERROR_CODE_RETRIEVING_LOCAL_USER_GROUPS;
import static org.wso2.carbon.identity.application.authentication.framework.handler.approles.constant.AppRolesConstants.ErrorMessages.ERROR_CODE_USER_NULL;
import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.InternalRoleDomains.APPLICATION_DOMAIN;
import static org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants.Error.INVALID_AUDIENCE;
import static org.wso2.carbon.user.mgt.UserMgtConstants.INTERNAL_ROLE;

/**
Expand Down Expand Up @@ -128,18 +133,43 @@ public String[] getAppAssociatedRolesOfFederatedUser(Map<ClaimMapping, String> f
private String[] getAppAssociatedRolesForLocalUser(AuthenticatedUser authenticatedUser, String applicationId)
throws ApplicationRolesException {

Set<String> userRoleIds = getAllRolesOfLocalUser(authenticatedUser);
List<RoleV2> rolesAssociatedWithApp = getRolesAssociatedWithApplication(applicationId,
authenticatedUser.getTenantDomain());
if (StringUtils.isNotEmpty(authenticatedUser.getSharedUserId())) {
// Add the shared role details to the roles list which are associated with the application.
addSharedRoleAssociations(authenticatedUser, rolesAssociatedWithApp, userRoleIds);
}
ServiceProvider app = null;
try {
app = ApplicationManagementService.getInstance()
.getApplicationByResourceId(applicationId, authenticatedUser.getTenantDomain());

return rolesAssociatedWithApp.stream()
.filter(role -> userRoleIds.contains(role.getId()))
.map(role -> appendInternalDomain(role.getName()))
.toArray(String[]::new);
if (app == null) {
throw new ApplicationRolesException(INVALID_AUDIENCE.getCode(),
"Invalid audience. No application found with application id: " + applicationId +
" and tenant domain : " + authenticatedUser.getTenantDomain());
}
if (IdentityUtil.threadLocalProperties.get().get(ApplicationConstants.IS_FRAGMENT_APP) != null) {
IdentityUtil.threadLocalProperties.get().remove(ApplicationConstants.IS_FRAGMENT_APP);
}
if (app.getSpProperties() != null && Arrays.stream(app.getSpProperties())
.anyMatch(property -> ApplicationConstants.IS_FRAGMENT_APP.equals(property.getName())
&& Boolean.parseBoolean(property.getValue()))) {
IdentityUtil.threadLocalProperties.get().put(ApplicationConstants.IS_FRAGMENT_APP, Boolean.TRUE);
}

Set<String> userRoleIds = getAllRolesOfLocalUser(authenticatedUser);
List<RoleV2> rolesAssociatedWithApp = getRolesAssociatedWithApplication(applicationId,
authenticatedUser.getTenantDomain());
if (StringUtils.isNotEmpty(authenticatedUser.getSharedUserId())) {
// Add the shared role details to the roles list which are associated with the application.
addSharedRoleAssociations(authenticatedUser, rolesAssociatedWithApp, userRoleIds);
}

return rolesAssociatedWithApp.stream()
.filter(role -> userRoleIds.contains(role.getId()))
.map(role -> appendInternalDomain(role.getName()))
.toArray(String[]::new);
} catch (IdentityApplicationManagementException e) {
throw new ApplicationRolesException("Error occurred while extracting the application for application : "
+ applicationId, e.getErrorCode());
} finally {
IdentityUtil.threadLocalProperties.get().remove(ApplicationConstants.IS_FRAGMENT_APP);
}
}

private void addSharedRoleAssociations(AuthenticatedUser authenticatedUser, List<RoleV2> rolesAssociatedWithApp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ public List<String> getRoleIdListOfGroups(List<String> groupIds, String tenantDo
List<String> roles = roleDAO.getRoleIdListOfGroups(groupIds, tenantDomain);
for (RoleManagementListener roleManagementListener : roleManagementListenerList) {
if (roleManagementListener.isEnable()) {
roleManagementListener.postGetRoleIdListOfGroups(groupIds, tenantDomain);
roleManagementListener.postGetRoleIdListOfGroups(roles, tenantDomain);
}
}
return roles;
Expand Down

0 comments on commit b4a3e8b

Please sign in to comment.