From 4a4332e634975b7344979d66ee514c42c0ef511a Mon Sep 17 00:00:00 2001 From: Shan Chathusanda Jayathilaka Date: Fri, 1 Nov 2024 18:37:33 +0530 Subject: [PATCH] Allow OAuth2 application management through DCR in sub organizations --- .../pom.xml | 6 +- .../identity/oauth/dcr/DCRMConstants.java | 3 +- .../oauth/dcr/internal/DCRDataHolder.java | 13 +- .../dcr/internal/DCRServiceComponent.java | 21 ++- .../oauth/dcr/service/DCRMService.java | 127 +++++++++++++++--- .../identity/oauth/dcr/util/DCRMUtils.java | 1 - .../identity/oauth/OAuthAdminService.java | 18 +++ .../identity/oauth/OAuthAdminServiceImpl.java | 22 +++ .../identity/oauth/dao/OAuthAppDAO.java | 34 +++++ .../identity/oauth2/util/OAuth2Util.java | 66 ++++++++- pom.xml | 2 +- 11 files changed, 282 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index 07f853c3006..dcaa2a193c1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -126,7 +126,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.configuration.mgt.core - + + org.wso2.carbon.identity.organization.management.core + org.wso2.carbon.identity.organization.management.service + @@ -165,6 +168,7 @@ org.wso2.carbon.identity.application.common.model;version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.application.mgt.*;version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.application.authentication.framework.*;version="${carbon.identity.framework.imp.pkg.version.range}", + org.wso2.carbon.identity.organization.management.service.*; version="${carbon.identity.organization.management.core.version.range}", javax.servlet.http; version="${imp.pkg.version.javax.servlet}", org.wso2.carbon.user.api; version="${carbon.user.api.imp.pkg.version.range}", org.wso2.carbon.identity.oauth.*;version="${identity.inbound.auth.oauth.imp.pkg.version.range}", diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java index 83b32bb5e0d..8eabb696ce1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java @@ -60,7 +60,8 @@ public enum ErrorMessages { SIGNATURE_VALIDATION_FAILED("Signature validation failed for the software statement"), MANDATORY_SOFTWARE_STATEMENT("Mandatory software statement is missing"), FAILED_TO_READ_SSA("Error occurred while reading the software statement"), - ADDITIONAL_ATTRIBUTE_ERROR("Error occurred while handling additional attributes"); + ADDITIONAL_ATTRIBUTE_ERROR("Error occurred while handling additional attributes"), + FAILED_TO_RESOLVE_TENANT_DOMAIN("Error while resolving tenant domain from the organization id: %s"); private final String message; private final String errorCode; diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java index eaaf88e4f68..25bf98dbe34 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java @@ -23,6 +23,7 @@ import org.wso2.carbon.identity.oauth.dcr.handler.RegistrationHandler; import org.wso2.carbon.identity.oauth.dcr.handler.UnRegistrationHandler; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,6 @@ * This was deprecated as part of deprecating the legacy identity/register DCR endpoint. * The recommendation is to use /identity/oauth2/dcr/v1.1 instead. */ -@Deprecated public class DCRDataHolder { private static DCRDataHolder thisInstance = new DCRDataHolder(); @@ -42,6 +42,7 @@ public class DCRDataHolder { private List unRegistrationHandlerList = new ArrayList<>(); private List tokenBinders = new ArrayList<>(); private ConfigurationManager configurationManager; + private OrganizationManager organizationManager; private DCRDataHolder() { @@ -111,4 +112,14 @@ public void setConfigurationManager(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; } + + public OrganizationManager getOrganizationManager() { + + return organizationManager; + } + + public void setOrganizationManager(OrganizationManager organizationManager) { + + this.organizationManager = organizationManager; + } } diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java index fedd5a94b7f..6a0b63318a1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java @@ -42,6 +42,7 @@ import org.wso2.carbon.identity.oauth.dcr.processor.DCRProcessor; import org.wso2.carbon.identity.oauth.dcr.service.DCRMService; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; /** * OAuth DCRM service component. @@ -52,7 +53,6 @@ name = "identity.oauth.dcr", immediate = true ) -@Deprecated public class DCRServiceComponent { private static final Log log = LogFactory.getLog(DCRServiceComponent.class); @@ -254,4 +254,23 @@ protected void unregisterConfigurationManager(ConfigurationManager configuration log.debug("Unregistering the ConfigurationManager in DCR Service Component."); DCRDataHolder.getInstance().setConfigurationManager(null); } + + @Reference( + name = "organization.service", + service = OrganizationManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetOrganizationManager" + ) + protected void setOrganizationManager(OrganizationManager organizationManager) { + + DCRDataHolder.getInstance().setOrganizationManager(organizationManager); + log.debug("Set the organization management service."); + } + + protected void unsetOrganizationManager(OrganizationManager organizationManager) { + + DCRDataHolder.getInstance().setOrganizationManager(null); + log.debug("Unset organization management service."); + } } diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java index 8e2c9c147f7..6fb2c8f7992 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java @@ -64,6 +64,7 @@ import org.wso2.carbon.identity.oauth2.OAuth2Constants; import org.wso2.carbon.identity.oauth2.util.JWTSignatureValidationUtils; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; import org.wso2.carbon.user.api.UserStoreException; import java.lang.reflect.InvocationTargetException; @@ -105,12 +106,23 @@ public class DCRMService { */ public Application getApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } + validateRequestTenantDomain(clientId, tenantDomain); OAuthConsumerAppDTO consumerAppDTO = getApplicationById( - clientId, DCRMUtils.isApplicationRolePermissionRequired()); + clientId, DCRMUtils.isApplicationRolePermissionRequired(), tenantDomain); // Get the jwksURI from the service provider. String applicationName = consumerAppDTO.getApplicationName(); - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); ServiceProvider serviceProvider = getServiceProvider(applicationName, tenantDomain); String jwksURI = serviceProvider.getJwksUri(); if (StringUtils.isNotEmpty(jwksURI)) { @@ -157,6 +169,17 @@ public Application getApplicationByName(String clientName) throws DCRMException } String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } if (!isServiceProviderExist(clientName, tenantDomain)) { throw DCRMUtils.generateClientException( DCRMConstants.ErrorMessages.NOT_FOUND_APPLICATION_WITH_NAME, clientName); @@ -203,10 +226,21 @@ public Application registerApplication(ApplicationRegistrationRequest registrati */ public void deleteApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); - OAuthConsumerAppDTO appDTO = getApplicationById(clientId); - String applicationOwner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); + String applicationOwner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String spName; try { spName = DCRDataHolder.getInstance().getApplicationManagementService() @@ -241,9 +275,22 @@ public void deleteApplication(String clientId) throws DCRMException { */ public Application updateApplication(ApplicationUpdateRequest updateRequest, String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); - OAuthConsumerAppDTO appDTO = getApplicationById(clientId); String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + boolean isSubOrgApp = false; + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + isSubOrgApp = true; + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); String applicationOwner = StringUtils.isNotBlank(updateRequest.getExtApplicationOwner()) ? updateRequest.getExtApplicationOwner() : PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -303,7 +350,7 @@ public Application updateApplication(ApplicationUpdateRequest updateRequest, Str } // Update the service provider properties list with the display name property. - updateServiceProviderPropertyList(sp, updateRequest.getExtApplicationDisplayName()); + updateServiceProviderPropertyList(sp, updateRequest.getExtApplicationDisplayName(), isSubOrgApp); // Update jwksURI. if (StringUtils.isNotEmpty(updateRequest.getJwksURI())) { sp.setJwksUri(updateRequest.getJwksURI()); @@ -426,7 +473,7 @@ public Application updateApplication(ApplicationUpdateRequest updateRequest, Str throw DCRMUtils.generateServerException( DCRMConstants.ErrorMessages.FAILED_TO_UPDATE_APPLICATION, clientId, e); } - OAuthConsumerAppDTO oAuthConsumerAppDTO = getApplicationById(clientId); + OAuthConsumerAppDTO oAuthConsumerAppDTO = getApplicationById(clientId, tenantDomain); // Setting the jwksURI to be sent in the response. oAuthConsumerAppDTO.setJwksURI(updateRequest.getJwksURI()); Application application = buildResponse(oAuthConsumerAppDTO, tenantDomain); @@ -448,11 +495,22 @@ public Application updateApplication(ApplicationUpdateRequest updateRequest, Str * @param serviceProvider Service provider. * @param applicationDisplayName Application display name. */ - private void updateServiceProviderPropertyList(ServiceProvider serviceProvider, String applicationDisplayName) { + private void updateServiceProviderPropertyList(ServiceProvider serviceProvider, String applicationDisplayName, + boolean isSubOrgApp) { // Retrieve existing service provider properties. ServiceProviderProperty[] serviceProviderProperties = serviceProvider.getSpProperties(); + boolean isSubOrgAppPropSet = Arrays.stream(serviceProviderProperties) + .anyMatch(property -> property.getName().equals("isSubOrgApp")); + if (!isSubOrgAppPropSet) { + ServiceProviderProperty isSubOrgAppProp = new ServiceProviderProperty(); + isSubOrgAppProp.setName("isSubOrgApp"); + isSubOrgAppProp.setValue(String.valueOf(isSubOrgApp)); + serviceProviderProperties = (ServiceProviderProperty[]) ArrayUtils.add(serviceProviderProperties, + isSubOrgAppProp); + } + boolean isDisplayNameSet = Arrays.stream(serviceProviderProperties) .anyMatch(property -> property.getName().equals(APP_DISPLAY_NAME)); if (!isDisplayNameSet) { @@ -489,12 +547,13 @@ private String getDisplayNameProperty(ServiceProvider serviceProvider) { return displayNameProperty.map(ServiceProviderProperty::getValue).orElse(null); } - private OAuthConsumerAppDTO getApplicationById(String clientId) throws DCRMException { + private OAuthConsumerAppDTO getApplicationById(String clientId, String tenantDomain) throws DCRMException { - return getApplicationById(clientId, true); + return getApplicationById(clientId, true, tenantDomain); } - private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplicationRolePermissionRequired) + private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplicationRolePermissionRequired, + String tenantDomain) throws DCRMException { if (StringUtils.isEmpty(clientId)) { @@ -504,7 +563,7 @@ private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplic } try { - OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId); + OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId, tenantDomain); if (dto == null || StringUtils.isEmpty(dto.getApplicationName())) { throw DCRMUtils.generateClientException( DCRMConstants.ErrorMessages.NOT_FOUND_APPLICATION_WITH_ID, clientId); @@ -531,6 +590,20 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + boolean isSubOrgApp = false; + + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + isSubOrgApp = true; + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } /* * ApplicationOwner will be null and a server error is thrown when creating an app, if the api authentication/ @@ -566,7 +639,7 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist } if (StringUtils.isNotEmpty(registrationRequest.getConsumerKey()) && isClientIdExist( - registrationRequest.getConsumerKey())) { + registrationRequest.getConsumerKey(), tenantDomain)) { throw DCRMUtils.generateClientException(DCRMConstants.ErrorMessages.CONFLICT_EXISTING_CLIENT_ID, registrationRequest.getConsumerKey()); } @@ -636,7 +709,8 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist } // Update the service provider properties list with the display name property. - updateServiceProviderPropertyList(serviceProvider, registrationRequest.getExtApplicationDisplayName()); + updateServiceProviderPropertyList(serviceProvider, registrationRequest.getExtApplicationDisplayName(), + isSubOrgApp); // Store jwksURI. if (StringUtils.isNotEmpty(registrationRequest.getJwksURI())) { serviceProvider.setJwksUri(registrationRequest.getJwksURI()); @@ -941,10 +1015,10 @@ private boolean isServiceProviderExist(String serviceProviderName, String tenant * @return true if application exists with the client id. * @throws DCRMException in case of failure. */ - private boolean isClientIdExist(String clientId) throws DCRMException { + private boolean isClientIdExist(String clientId, String tenantDomain) throws DCRMException { try { - OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId); + OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId, tenantDomain); return dto != null && StringUtils.isNotBlank(dto.getApplicationName()); } catch (IdentityOAuthAdminException e) { if (e.getCause() instanceof InvalidOAuthClientException) { @@ -1145,6 +1219,17 @@ private boolean isUserAuthorized(String clientId) throws DCRMServerException { try { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } String spName = DCRDataHolder.getInstance().getApplicationManagementService() .getServiceProviderNameByClientId(clientId, DCRMConstants.OAUTH2, tenantDomain); String threadLocalUserName = CarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -1176,10 +1261,10 @@ private static boolean clientIdMatchesRegex(String clientId, String clientIdVali * @param clientId Consumer key of application. * @throws DCRMException DCRMException */ - private void validateRequestTenantDomain(String clientId) throws DCRMException { + private void validateRequestTenantDomain(String clientId, String tenantDomain) throws DCRMException { try { - String tenantDomainOfApp = OAuth2Util.getTenantDomainOfOauthApp(clientId); + String tenantDomainOfApp = OAuth2Util.getTenantDomainOfOauthApp(clientId, tenantDomain); OAuth2Util.validateRequestTenantDomain(tenantDomainOfApp); } catch (InvalidOAuthClientException e) { throw new DCRMClientException(DCRMConstants.ErrorMessages.TENANT_DOMAIN_MISMATCH.getErrorCode(), diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java index 7e2df76179e..beb611f1de1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java @@ -37,7 +37,6 @@ * This was deprecated as part of deprecating the legacy identity/register DCR endpoint. * The recommendation is to use /identity/oauth2/dcr/v1.1 instead. */ -@Deprecated public class DCRMUtils { private static final Log log = LogFactory.getLog(DCRMUtils.class); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java index a21135cb428..369ab4f6fd8 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java @@ -88,6 +88,24 @@ public OAuthConsumerAppDTO getOAuthApplicationData(String consumerKey) throws Id } } + /** + * Get OAuth application data by the consumer key and tenant domain. + * + * @param consumerKey Consumer Key. + * @param tenantDomain Tenant Domain. + * @return OAuthConsumerAppDTO with application information. + * @throws IdentityOAuthAdminException Error when reading application information from persistence store. + */ + public OAuthConsumerAppDTO getOAuthApplicationData(String consumerKey, String tenantDomain) + throws IdentityOAuthAdminException { + + try { + return oAuthAdminServiceImpl.getOAuthApplicationData(consumerKey, tenantDomain); + } catch (IdentityOAuthAdminException ex) { + throw handleError(ex); + } + } + /** * Get OAuth application data by the application name. * diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java index 878c0450c9d..a0a70732831 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java @@ -783,6 +783,17 @@ void updateConsumerApplication(OAuthConsumerAppDTO consumerAppDTO, boolean enabl } String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw handleError("Error while resolving tenant domain from the organization id: " + + applicationResidentOrgId, e); + } + } OAuthAppDAO dao = new OAuthAppDAO(); OAuthAppDO oAuthAppDO; @@ -2342,6 +2353,17 @@ AuthenticatedUser getAppOwner(OAuthConsumerAppDTO application, // Since the app owner sent in OAuthConsumerAppDTO is a valid one we set the appOwner to be // the one sent in the OAuthConsumerAppDTO. String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw handleError("Error while resolving tenant domain from the organization id: " + + applicationResidentOrgId, e); + } + } Optional maybeAppOwner = OAuthUtil.getUser(tenantDomain, tenantAwareAppOwnerInRequest); if (maybeAppOwner.isPresent()) { appOwner = new AuthenticatedUser(maybeAppOwner.get()); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java index f11815a74a4..f5f2cdb6dac 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java @@ -158,6 +158,16 @@ public void addOAuthApplication(OAuthAppDO consumerAppDO) throws IdentityOAuthAd AuthenticatedUser appOwner = consumerAppDO.getAppOwner(); String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw handleError("Error occurred while resolving tenant domain for organization id: " + + appOrgId, e); + } + } int spTenantId = IdentityTenantUtil.getTenantId(tenantDomain); String userStoreDomain = appOwner.getUserStoreDomain(); if (!isDuplicateApplication(appOwner.getUserName(), spTenantId, userStoreDomain, consumerAppDO)) { @@ -681,6 +691,18 @@ public OAuthAppDO getAppInformationByAppName(String appName) throws try (Connection connection = IdentityDatabaseUtil.getDBConnection(false)) { int tenantID = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + String tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + tenantID = IdentityTenantUtil.getTenantId(tenantDomain); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error occurred while resolving tenant domain for " + + "organization id: " + appOrgId, e); + } + } String sqlQuery = SQLQueries.OAuthAppDAOSQLQueries.GET_APP_INFO_BY_APP_NAME_WITH_PKCE; try (PreparedStatement prepStmt = connection.prepareStatement(sqlQuery)) { @@ -872,6 +894,18 @@ private void setValuesToStatementWithPKCEAndOwnerUpdate(OAuthAppDO oauthAppDO, P prepStmt.setString(11, oauthAppDO.getAppOwner().getUserStoreDomain()); prepStmt.setString(12, persistenceProcessor.getProcessedClientId(oauthAppDO.getOauthConsumerKey())); prepStmt.setInt(13, IdentityTenantUtil.getLoginTenantId()); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + String tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + prepStmt.setInt(13, IdentityTenantUtil.getTenantId(tenantDomain)); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error occurred while resolving tenant domain for " + + "organization id: " + appOrgId, e); + } + } } private void setValuesToStatementWithPKCENoOwnerUpdate(OAuthAppDO oauthAppDO, PreparedStatement prepStmt) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java index 52e1855fdb5..3efb0e95101 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java @@ -2427,9 +2427,18 @@ public static OauthTokenIssuer getOAuthTokenIssuerForOAuthApp(String clientId) OAuthAppDO appDO; try { - appDO = getAppInformationByClientId(clientId); + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } + appDO = getAppInformationByClientId(clientId, tenantDomain); } catch (IdentityOAuth2Exception e) { throw new IdentityOAuth2Exception("Error while retrieving app information for clientId: " + clientId, e); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error while resolving tenant domain from the organization id: ", e); } return getOAuthTokenIssuerForOAuthApp(appDO); } @@ -2605,6 +2614,32 @@ public static String getTenantDomainOfOauthApp(String clientId) return getTenantDomainOfOauthApp(oAuthAppDO); } + /** + * This is used to get the tenant domain of an application by clientId. Internally it uses the tenant present in + * the carbon context. + * + * @param clientId Consumer key of Application. + * @return Tenant Domain. + * @throws IdentityOAuth2Exception Error while retrieving the application. + * @throws InvalidOAuthClientException If an application not found for the given client ID. + */ + public static String getTenantDomainOfOauthApp(String clientId, String tenantDomain) + throws IdentityOAuth2Exception, InvalidOAuthClientException { + + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error while resolving tenant domain for the organization ID: " + + appOrgId, e); + } + } + OAuthAppDO oAuthAppDO = getAppInformationByClientId(clientId, tenantDomain); + return getTenantDomainOfOauthApp(oAuthAppDO); + } + /** * Get all the OAuth applications for the client ID. * @@ -3850,9 +3885,9 @@ public static ServiceProvider getServiceProvider(String clientId, public static ServiceProvider getServiceProvider(String clientId) throws IdentityOAuth2Exception { ApplicationManagementService applicationMgtService = OAuth2ServiceComponentHolder.getApplicationMgtService(); - String tenantDomain = null; + String tenantDomain = IdentityTenantUtil.getTenantDomain(IdentityTenantUtil.getLoginTenantId()); try { - tenantDomain = getTenantDomainOfOauthApp(clientId); + tenantDomain = getTenantDomainOfOauthApp(clientId, tenantDomain); // Get the Service Provider. return applicationMgtService.getServiceProviderByClientId( clientId, IdentityApplicationConstants.OAuth2.NAME, tenantDomain); @@ -4324,7 +4359,8 @@ public static String getIdTokenIssuer(String tenantDomain) throws IdentityOAuth2 public static String getIdTokenIssuer(String tenantDomain, boolean isMtlsRequest) throws IdentityOAuth2Exception { - if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { + if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled() && StringUtils.isEmpty(PrivilegedCarbonContext. + getThreadLocalCarbonContext().getApplicationResidentOrganizationId())) { try { return isMtlsRequest ? OAuthURL.getOAuth2MTLSTokenEPUrl() : ServiceURLBuilder.create().addPath(OAUTH2_TOKEN_EP_URL).build().getAbsolutePublicURL(); @@ -4966,6 +5002,17 @@ public static void validateRequestTenantDomain(String tenantDomainOfApp) throws if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { String tenantDomainFromContext = IdentityTenantUtil.resolveTenantDomain(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext(). + getApplicationResidentOrganizationId(); + if (StringUtils.isNotBlank(appOrgId)) { + try { + tenantDomainFromContext = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw new InvalidOAuthClientException("Error while resolving tenant domain from organization id: " + + appOrgId, e); + } + } if (!StringUtils.equals(tenantDomainFromContext, tenantDomainOfApp)) { // This means the tenant domain sent in the request and app's tenant domain do not match. if (log.isDebugEnabled()) { @@ -5313,6 +5360,17 @@ public static boolean isFapiConformantApp(String clientId) return false; } String tenantDomain = IdentityTenantUtil.resolveTenantDomain(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw new InvalidOAuthClientException("Error while resolving tenant domain for the organization ID: " + + appOrgId, e); + } + } OAuthAppDO oAuthAppDO = OAuth2Util.getAppInformationByClientId(clientId, tenantDomain); return oAuthAppDO.isFapiConformanceEnabled(); } diff --git a/pom.xml b/pom.xml index c5abec5a116..c8838f07e86 100644 --- a/pom.xml +++ b/pom.xml @@ -933,7 +933,7 @@ 1.2.4 - 4.10.22 + 4.10.24 4.10.22 [4.10.22, 5.0.0) [1.0.1, 2.0.0)