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

Manage application name update of fragment apps. #269

Merged
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 @@ -706,7 +706,7 @@ private ServiceProvider prepareSharedApplication(ServiceProvider mainApplication

ServiceProvider delegatedApplication = new ServiceProvider();
delegatedApplication.setApplicationName(oAuthConsumerApp.getApplicationName());
delegatedApplication.setDescription("Delegated access from: " + mainApplication.getApplicationName());
delegatedApplication.setDescription(mainApplication.getDescription());
delegatedApplication.setInboundAuthenticationConfig(inboundAuthConfig);
appendFragmentAppProperties(delegatedApplication);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.wso2.carbon.identity.organization.management.application.listener;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -47,13 +48,17 @@
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementClientException;
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.RoleManagementService;
import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementException;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static java.lang.String.format;
Expand All @@ -75,6 +80,8 @@
public class FragmentApplicationMgtListener extends AbstractApplicationMgtListener {

private static final Log LOG = LogFactory.getLog(FragmentApplicationMgtListener.class);
private static final String IS_APP_NAME_UPDATED = "isAppNameUpdated";
private final ExecutorService executorService = Executors.newFixedThreadPool(5);

@Override
public int getDefaultOrderId() {
Expand Down Expand Up @@ -128,11 +135,28 @@ public boolean doPreCreateApplication(ServiceProvider serviceProvider, String te
public boolean doPreUpdateApplication(ServiceProvider serviceProvider, String tenantDomain,
String userName) throws IdentityApplicationManagementException {

ServiceProvider existingApplication =
getApplicationByResourceId(serviceProvider.getApplicationResourceId(), tenantDomain);
try {
if (!OrganizationManagementUtil.isOrganization(tenantDomain)) {
if (existingApplication != null &&
!existingApplication.getApplicationName().equals(serviceProvider.getApplicationName())) {
IdentityUtil.threadLocalProperties.get().put(IS_APP_NAME_UPDATED, true);
}
} else if (!isInternalProcess(tenantDomain)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic need not be inside else if block. You can have as a normal if condition by checking the application update by internal process of root org. If name is different, can throw the exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

only sub organizations name update using external process should be blocked. therfore added the else if block

if (existingApplication != null &&
!existingApplication.getApplicationName().equals(serviceProvider.getApplicationName())) {
throw new IdentityApplicationManagementClientException(
"Application name modification is not allowed for this organization.");
ChanikaRuchini marked this conversation as resolved.
Show resolved Hide resolved
}
}
} catch (OrganizationManagementException e) {
throw new IdentityApplicationManagementException(
String.format("Error while resolving the organization for the tenant %s .", tenantDomain), e);
}
/* If the application is a fragment application, only certain configurations are allowed to be updated since
the organization login authenticator needs some configurations unchanged. Hence, the listener will override
any configs changes that are required for organization login. */
ServiceProvider existingApplication =
getApplicationByResourceId(serviceProvider.getApplicationResourceId(), tenantDomain);
if (existingApplication != null && Arrays.stream(existingApplication.getSpProperties())
.anyMatch(p -> IS_FRAGMENT_APP.equalsIgnoreCase(p.getName()) && Boolean.parseBoolean(p.getValue()))) {
serviceProvider.setSpProperties(existingApplication.getSpProperties());
Expand Down Expand Up @@ -166,6 +190,28 @@ public boolean doPreUpdateApplication(ServiceProvider serviceProvider, String te
return super.doPreUpdateApplication(serviceProvider, tenantDomain, userName);
}

@Override
public boolean doPostUpdateApplication(ServiceProvider serviceProvider, String tenantDomain, String userName)
throws IdentityApplicationManagementException {

try {
if (!OrganizationManagementUtil.isOrganization(tenantDomain)) {
Object isAppNameUpdated = IdentityUtil.threadLocalProperties.get().get(IS_APP_NAME_UPDATED);
if (isAppNameUpdated != null && (Boolean) isAppNameUpdated) {
handleApplicationNameUpdate(serviceProvider.getApplicationResourceId(), tenantDomain, userName,
serviceProvider.getApplicationName());
}
}
} catch (OrganizationManagementException e) {
throw new IdentityApplicationManagementException(
String.format("Error while updating the application name related to application %s update.",
serviceProvider.getApplicationID()), e);
} finally {
IdentityUtil.threadLocalProperties.get().remove(IS_APP_NAME_UPDATED);
}
return super.doPostUpdateApplication(serviceProvider, tenantDomain, userName);
}

@Override
public boolean doPostGetServiceProvider(ServiceProvider serviceProvider, String applicationName,
String tenantDomain) throws IdentityApplicationManagementException {
Expand Down Expand Up @@ -410,4 +456,66 @@ private boolean isSharedAppFromInternalProcess(ServiceProvider serviceProvider,
Boolean.parseBoolean(property.getValue())) &&
!StringUtils.equals(IdentityTenantUtil.getTenantDomainFromContext(), tenantDomain);
}

/**
* Check whether the application name update for a sub-organization by an internal process.
* In that process, request initiated tenant domain and the service provider belonging tenant domain would be
* different.
*
* @param tenantDomain The tenant domain which the service provider app is belongs to.
* @return True if the request initiated by an internal process.
*/
private boolean isInternalProcess(String tenantDomain) {

return !StringUtils.equals(IdentityTenantUtil.getTenantDomainFromContext(), tenantDomain);
}

/**
* Update the application names of fragment applications of the given main application.
*
* @param applicationId The application id of the main application.
* @param tenantDomain The tenant domain which the service provider app is belongs to.
* @param username The username of the user who initiated the update.
* @param updatedApplicationName The updated application name.
*/
private void handleApplicationNameUpdate(String applicationId, String tenantDomain, String username,
String updatedApplicationName) throws OrganizationManagementException {

String mainAppOrgId = getOrganizationManager().resolveOrganizationId(tenantDomain);
List<SharedApplicationDO>
sharedApplications = getOrgApplicationMgtDAO().getSharedApplications(mainAppOrgId, applicationId);
if (CollectionUtils.isEmpty(sharedApplications)) {
return;
}
for (SharedApplicationDO sharedApplication : sharedApplications) {
ChanikaRuchini marked this conversation as resolved.
Show resolved Hide resolved
String sharedAppOrgId = sharedApplication.getOrganizationId();
CompletableFuture.runAsync(() -> {
try {
updateFragmentApplication(sharedAppOrgId, sharedApplication.getFragmentApplicationId(),
updatedApplicationName, username);
} catch (IdentityApplicationManagementException | OrganizationManagementException e) {
LOG.error(String.format("Error in updating application: %s in organization: %s",
applicationId, sharedAppOrgId), e);
}
}, executorService);
}
}

private void updateFragmentApplication(String sharedAppOrgId, String fragmentApplicationId,
String updatedApplicationName, String username)
throws OrganizationManagementException, IdentityApplicationManagementException {

try {
String sharedAppTenantDomain = getOrganizationManager().resolveTenantDomain(sharedAppOrgId);
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(sharedAppTenantDomain, true);
ServiceProvider fragmentApp = getApplicationMgtService().getApplicationByResourceId(
fragmentApplicationId, sharedAppTenantDomain);
fragmentApp.setApplicationName(updatedApplicationName);
getApplicationMgtService().updateApplicationByResourceId(
fragmentApplicationId, fragmentApp, sharedAppTenantDomain, username);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
}
Loading