From f1420ad0b72603226cf0abd76ca850d024c13eee Mon Sep 17 00:00:00 2001 From: Shan Chathusanda Jayathilaka Date: Fri, 3 Jan 2025 17:16:42 +0530 Subject: [PATCH] Allow OAuth2 application management through DCR in sub organizations --- .../pom.xml | 7 +- .../identity/oauth/dcr/DCRMConstants.java | 3 +- .../oauth/dcr/internal/DCRDataHolder.java | 13 +- .../dcr/internal/DCRServiceComponent.java | 21 ++- .../oauth/dcr/service/DCRMService.java | 64 ++++++--- .../identity/oauth/dcr/util/DCRMUtils.java | 1 - .../oauth/dcr/service/DCRMServiceTest.java | 29 ++-- .../identity/oauth/OAuthAdminService.java | 18 +++ .../identity/oauth/OAuthAdminServiceImpl.java | 21 ++- .../identity/oauth/dao/OAuthAppDAO.java | 34 +++++ .../identity/oauth2/util/OAuth2Util.java | 68 ++++++++- .../identity/oauth/dao/OAuthAppDAOTest.java | 134 ++++++++++++++++++ .../AuthorizationHandlerManagerTest.java | 8 ++ .../handlers/CodeResponseTypeHandlerTest.java | 9 ++ .../TokenResponseTypeHandlerTest.java | 31 +++- ...AbstractAuthorizationGrantHandlerTest.java | 7 + .../identity/oauth2/util/OAuth2UtilTest.java | 10 +- pom.xml | 2 +- 18 files changed, 420 insertions(+), 60 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index b46cf5b86bc..cf6bec28c7d 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,8 @@ 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}", + org.wso2.carbon.identity.organization.management.service.exception; 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..e0b95d33387 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,12 @@ public class DCRMService { */ public Application getApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); + String tenantDomain = getTenantDomain(); + 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)) { @@ -156,7 +157,7 @@ public Application getApplicationByName(String clientName) throws DCRMException DCRMConstants.ErrorMessages.BAD_REQUEST_INSUFFICIENT_DATA, null); } - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); if (!isServiceProviderExist(clientName, tenantDomain)) { throw DCRMUtils.generateClientException( DCRMConstants.ErrorMessages.NOT_FOUND_APPLICATION_WITH_NAME, clientName); @@ -203,10 +204,10 @@ public Application registerApplication(ApplicationRegistrationRequest registrati */ public void deleteApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); - OAuthConsumerAppDTO appDTO = getApplicationById(clientId); + String tenantDomain = getTenantDomain(); + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); String applicationOwner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); String spName; try { spName = DCRDataHolder.getInstance().getApplicationManagementService() @@ -241,9 +242,9 @@ 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(); + String tenantDomain = getTenantDomain(); + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); String applicationOwner = StringUtils.isNotBlank(updateRequest.getExtApplicationOwner()) ? updateRequest.getExtApplicationOwner() : PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -426,7 +427,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); @@ -489,12 +490,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 +506,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); @@ -529,8 +531,7 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist String applicationOwner = StringUtils.isNotBlank(registrationRequest.getExtApplicationOwner()) ? registrationRequest.getExtApplicationOwner() : PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); /* * ApplicationOwner will be null and a server error is thrown when creating an app, if the api authentication/ @@ -566,7 +567,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()); } @@ -941,10 +942,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) { @@ -1144,7 +1145,7 @@ private String escapeQueryParamsIfPresent(String redirectURI) { private boolean isUserAuthorized(String clientId) throws DCRMServerException { try { - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); String spName = DCRDataHolder.getInstance().getApplicationManagementService() .getServiceProviderNameByClientId(clientId, DCRMConstants.OAUTH2, tenantDomain); String threadLocalUserName = CarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -1176,10 +1177,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(), @@ -1275,4 +1276,21 @@ private void addSPProperties(Map spProperties, ServiceProvider s } serviceProvider.setSpProperties(serviceProviderProperties); } + + private static String getTenantDomain() throws DCRMServerException { + + 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); + } + } + return tenantDomain; + } } 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.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java b/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java index 87c456aaf23..1678df7280b 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java @@ -199,12 +199,12 @@ public void getApplicationEmptyClientIdTest() throws DCRMException { public void getApplicationNullDTOTest(String dtoStatus) throws Exception { if (dtoStatus == null) { - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(null); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(null); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); } else { OAuthConsumerAppDTO dto = new OAuthConsumerAppDTO(); dto.setApplicationName(""); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()) .thenReturn(new OAuthConsumerAppDTO[]{dto}); } @@ -222,7 +222,7 @@ public void getApplicationNullDTOTest(String dtoStatus) throws Exception { public void getApplicationDTOTestWithIOAException() throws Exception { doThrow(new IdentityOAuthAdminException("")).when(mockOAuthAdminService) - .getOAuthApplicationData(dummyConsumerKey); + .getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); @@ -239,7 +239,7 @@ public void getApplicationDTOTestWithIOAException() throws Exception { public void getApplicationDTOTestWithIOCException() throws Exception { doThrow(new IdentityOAuthAdminException("", new InvalidOAuthClientException(""))).when(mockOAuthAdminService) - .getOAuthApplicationData(dummyConsumerKey); + .getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); @@ -256,7 +256,7 @@ public void getApplicationDTOTestWithIOCException() throws Exception { public void getApplicationDTOTestUserUnauthorized() throws Exception { setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); try { @@ -276,7 +276,7 @@ public void isUserAuthorizedTestWithIAMException() throws IdentityOAuthAdminExce UserStoreException, NoSuchFieldException, IllegalAccessException { setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); try { @@ -304,7 +304,7 @@ public void getApplicationDTOTest(String roleAudience) throws Exception { dto.setCallbackUrl(dummyCallbackUrl); dto.setUsername(dummyUserName.concat("@").concat(dummyTenantDomain)); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUserRealm(mockedUserRealm); when(mockedUserRealm.getUserStoreManager()).thenReturn(mockedUserStoreManager); @@ -328,7 +328,8 @@ public void getApplicationDTOTest(String roleAudience) throws Exception { public void validateRequestTenantDomainTestWitInvalidOAuthClientException() throws IdentityOAuth2Exception, InvalidOAuthClientException { - when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey)).thenThrow(new InvalidOAuthClientException("")); + when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey, dummyTenantDomain)). + thenThrow(new InvalidOAuthClientException("")); try { dcrmService.getApplication(dummyConsumerKey); } catch (DCRMException ex) { @@ -343,7 +344,8 @@ public void validateRequestTenantDomainTestWitInvalidOAuthClientException() public void validateRequestTenantDomainTestWitIdentityOAuth2Exception() throws IdentityOAuth2Exception, InvalidOAuthClientException { - when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey)).thenThrow(new IdentityOAuth2Exception("")); + when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey, dummyTenantDomain)). + thenThrow(new IdentityOAuth2Exception("")); try { dcrmService.getApplication(dummyConsumerKey); } catch (DCRMException ex) { @@ -535,7 +537,7 @@ public void registerApplicationTestWithExistClientId() throws Exception { applicationRegistrationRequest.setGrantTypes(dummyGrantTypes); applicationRegistrationRequest.setConsumerKey(dummyConsumerKey); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)) + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)) .thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); @@ -915,7 +917,8 @@ public void isClientIdExistTestWithIdentityOAuthAdminException() throws Exceptio setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); IdentityOAuthAdminException identityOAuthAdminException = mock(IdentityOAuthAdminException.class); - doThrow(identityOAuthAdminException).when(mockOAuthAdminService).getOAuthApplicationData(dummyConsumerKey); + doThrow(identityOAuthAdminException).when(mockOAuthAdminService).getOAuthApplicationData(dummyConsumerKey, + dummyTenantDomain); try { dcrmService.registerApplication(applicationRegistrationRequest); } catch (IdentityException ex) { @@ -974,7 +977,7 @@ private OAuthConsumerAppDTO registerApplicationTestWithFailedToUpdateSP() throws lenient().when(mockOAuthAdminService .getOAuthApplicationDataByAppName(dummyClientName)).thenReturn(oAuthConsumerApp); lenient().when(mockOAuthAdminService - .getOAuthApplicationData("dummyConsumerKey")).thenReturn(oAuthConsumerApp); + .getOAuthApplicationData("dummyConsumerKey", dummyTenantDomain)).thenReturn(oAuthConsumerApp); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()) .thenReturn(new OAuthConsumerAppDTO[]{oAuthConsumerApp}); lenient().when(mockOAuthAdminService.registerAndRetrieveOAuthApplicationData(any(OAuthConsumerAppDTO.class))). @@ -1107,7 +1110,7 @@ private OAuthConsumerAppDTO updateApplication() dto.setCallbackUrl(dummyCallbackUrl); dto.setUsername(dummyUserName.concat("@").concat(dummyTenantDomain)); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); ServiceProvider serviceProvider = new ServiceProvider(); 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 2e3c6414c72..739ee3aa55e 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 @@ -800,7 +800,7 @@ void updateConsumerApplication(OAuthConsumerAppDTO consumerAppDTO, boolean enabl throw handleClientError(INVALID_REQUEST, errorMessage); } - String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getAppTenantDomain(); OAuthAppDAO dao = new OAuthAppDAO(); OAuthAppDO oAuthAppDO; @@ -2391,7 +2391,7 @@ AuthenticatedUser getAppOwner(OAuthConsumerAppDTO application, try { // 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 tenantDomain = getAppTenantDomain(); Optional maybeAppOwner = OAuthUtil.getUser(tenantDomain, tenantAwareAppOwnerInRequest); if (maybeAppOwner.isPresent()) { appOwner = new AuthenticatedUser(maybeAppOwner.get()); @@ -2925,4 +2925,21 @@ private boolean isAccessTokenClaimsSeparationEnabledForApp(String consumerKey, S return OAuth2Util.isAppVersionAllowed(serviceProvider.getApplicationVersion(), ApplicationConstants.ApplicationVersion.APP_VERSION_V2); } + + private static String getAppTenantDomain() throws IdentityOAuthAdminException { + + 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); + } + } + return tenantDomain; + } } 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 30a2b40d2d0..43656059ba3 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 @@ -157,6 +157,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)) { @@ -687,6 +697,18 @@ public OAuthAppDO getAppInformationByAppName(String appName, int tenantID) OAuthAppDO oauthApp; try (Connection connection = IdentityDatabaseUtil.getDBConnection(false)) { + 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)) { @@ -878,6 +900,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 08982d55aa5..6503a0cd59c 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 @@ -2441,7 +2441,8 @@ public static OauthTokenIssuer getOAuthTokenIssuerForOAuthApp(String clientId) OAuthAppDO appDO; try { - appDO = getAppInformationByClientId(clientId); + String tenantDomain = getTenantDomain(); + appDO = getAppInformationByClientId(clientId, tenantDomain); } catch (IdentityOAuth2Exception e) { throw new IdentityOAuth2Exception("Error while retrieving app information for clientId: " + clientId, e); } @@ -2619,6 +2620,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. * @@ -3864,9 +3891,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); @@ -4338,7 +4365,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(); @@ -4979,7 +5007,18 @@ public static void validateRequestTenantDomain(String tenantDomainOfApp) throws if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { - String tenantDomainFromContext = IdentityTenantUtil.resolveTenantDomain(); + String tenantDomainFromContext = getTenantDomain(); + 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()) { @@ -5326,7 +5365,7 @@ public static boolean isFapiConformantApp(String clientId) if (!Boolean.parseBoolean(IdentityUtil.getProperty(OAuthConstants.ENABLE_FAPI))) { return false; } - String tenantDomain = IdentityTenantUtil.resolveTenantDomain(); + String tenantDomain = getTenantDomain(); OAuthAppDO oAuthAppDO = OAuth2Util.getAppInformationByClientId(clientId, tenantDomain); return oAuthAppDO.isFapiConformanceEnabled(); } @@ -5662,4 +5701,21 @@ public static boolean isAppVersionAllowed(String appVersion, String allowedAppVe } return true; } + + private static String getTenantDomain() throws InvalidOAuthClientException { + + String tenantDomain = IdentityTenantUtil.resolveTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw new InvalidOAuthClientException("Error while resolving tenant domain from the organization " + + "id: ", e); + } + } + return tenantDomain; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java index c85de96151a..43313c7c55e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java @@ -20,6 +20,7 @@ import org.apache.commons.lang.StringUtils; import org.mockito.Mock; import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -41,6 +42,8 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.test.utils.CommonTestUtils; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.core.common.AbstractUserStoreManager; @@ -85,6 +88,7 @@ public class OAuthAppDAOTest extends TestOAuthDAOBase { private static final String USER_STORE_DOMAIN = "USER_STORE_DOMAIN_NAME"; private static final String TENANT_DOMAIN = "TENANT_DOMAIN"; private static final String TENANT_DOMAIN_2 = "TENANT_DOMAIN_2"; + private static final String TENANT_DOMAIN_2_ORG_ID = "1234-1234"; private static final String CONSUMER_KEY = "ca19a540f544777860e44e75f605d927"; private static final String CONSUMER_SECRET = "87n9a540f544777860e44e75f605d435"; private static final String APP_NAME = "myApp"; @@ -137,6 +141,9 @@ public class OAuthAppDAOTest extends TestOAuthDAOBase { @Mock OAuthComponentServiceHolder mockOAuthComponentServiceHolder; + @Mock + OrganizationManager mockOrganizationManager; + @BeforeClass public void setUp() throws Exception { initMocks(this); @@ -173,6 +180,34 @@ public void testAddOAuthApplication() throws Exception { } } + @Test + public void testAddOAuthApplicationWithAppResidentOrgId() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + OAuthAppDO appDO = getDefaultOAuthAppDO(); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + addOAuthApplication(appDO, TENANT_ID_2); + } + } finally { + resetPrivilegedCarbonContext(); + } + } + /** * Add an OAuth app. This method will be reused in other tests where an OAuth app is required to be present * before the actual test can take place. @@ -290,6 +325,35 @@ public void testAddOAuthApplicationWithExceptions() throws Exception { } } + @Test(expectedExceptions = IdentityOAuthAdminException.class) + public void testAddOAuthApplicationWithAppResidentOrgIdAndWithExceptions() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)). + thenThrow(new OrganizationManagementException("Error while resolving tenant domain.")); + OAuthAppDO appDO = getDefaultOAuthAppDO(); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + new OAuthAppDAO().addOAuthApplication(appDO); + } + } finally { + resetPrivilegedCarbonContext(); + Mockito.reset(mockOrganizationManager); + } + } + @Test public void testAddOAuthConsumer() throws Exception { @@ -1004,6 +1068,41 @@ public void testGetAppInformationByAppName() throws Exception { } } + @Test + public void testGetAppInformationByAppNameWithAppResidentOrgId() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + + OAuthAppDO oAuthAppDO = getDefaultOAuthAppDO(); + new OAuthAppDAO().addOAuthApplication(oAuthAppDO); + + OAuthAppDO actualAppDO = new OAuthAppDAO().getAppInformationByAppName(APP_NAME, TENANT_ID); + assertNotNull(actualAppDO); + assertEquals(actualAppDO.getApplicationName(), APP_NAME); + assertEquals(actualAppDO.getOauthConsumerKey(), CONSUMER_KEY); + assertEquals(actualAppDO.getOauthConsumerSecret(), CONSUMER_SECRET); + } + } finally { + resetPrivilegedCarbonContext(); + } + } + @Test(expectedExceptions = IdentityOAuth2Exception.class) public void testGetAppInformationByAppNameWithExceptions() throws Exception { @@ -1030,6 +1129,41 @@ public void testGetAppInformationByAppNameWithExceptions() throws Exception { } } + @Test(expectedExceptions = IdentityOAuth2Exception.class) + public void testGetAppInformationByAppNameWithAppResidentOrgIdAndWithException() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + try (Connection connection = getConnection(DB_NAME)) { + + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + OAuthAppDO oAuthAppDO = getDefaultOAuthAppDO(); + OAuthAppDAO appDAO = new OAuthAppDAO(); + appDAO.addOAuthApplication(oAuthAppDO); + + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenThrow( + new OrganizationManagementException("Error while resolving tenant domain.")); + appDAO.getAppInformationByAppName(APP_NAME, TENANT_ID); + } + } finally { + resetPrivilegedCarbonContext(); + Mockito.reset(mockOrganizationManager); + } + } + private OAuthAppDO getDefaultOAuthAppDO() { AuthenticatedUser authenticatedUser = new AuthenticatedUser(); authenticatedUser.setUserName(USER_NAME); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java index d2612c2abb5..79895798fb3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java @@ -16,6 +16,7 @@ package org.wso2.carbon.identity.oauth2.authz; import org.apache.oltu.oauth2.common.error.OAuthError; +import org.mockito.MockedStatic; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -37,11 +38,13 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.testutil.IdentityBaseTest; import org.wso2.carbon.user.api.UserStoreException; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; @WithCarbonHome @@ -56,6 +59,7 @@ public class AuthorizationHandlerManagerTest extends IdentityBaseTest { private AuthorizationHandlerManager authorizationHandlerManager; private OAuth2AuthorizeReqDTO authzReqDTO = new OAuth2AuthorizeReqDTO(); private ServiceProvider serviceProvider; + private MockedStatic mockedAuthzUtil; @BeforeClass public void setUp() throws Exception { @@ -70,12 +74,16 @@ public void setUp() throws Exception { when(applicationManagementService.getServiceProviderByClientId(anyString(), anyString(), anyString())) .thenReturn(serviceProvider); authorizationHandlerManager = AuthorizationHandlerManager.getInstance(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass public void tearDown() { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); + mockedAuthzUtil.close(); + } @BeforeMethod diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java index 2765c5ad189..5f09858950d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.oauth2.authz.handlers; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -41,8 +43,10 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; /** * Test class covering CodeResponseTypeHandler @@ -62,6 +66,7 @@ public class CodeResponseTypeHandlerTest { OAuthAuthzReqMessageContext authAuthzReqMessageContext; OAuth2AuthorizeReqDTO authorizationReqDTO; + private MockedStatic mockedAuthzUtil; @BeforeClass public void init() throws IdentityOAuthAdminException { @@ -69,6 +74,9 @@ public void init() throws IdentityOAuthAdminException { IdentityEventService identityEventService = mock(IdentityEventService.class); CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(identityEventService); new OAuthAppDAO().addOAuthApplication(getDefaultOAuthAppDO()); + Mockito.clearAllCaches(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass @@ -76,6 +84,7 @@ public void clear() throws IdentityOAuthAdminException { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); new OAuthAppDAO().removeConsumerApplication(TEST_CONSUMER_KEY); + mockedAuthzUtil.close(); } @BeforeMethod diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java index 40cabbd9e50..6f4e3ee3bea 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.oauth2.authz.handlers; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeTest; @@ -27,6 +28,7 @@ import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.common.testng.WithH2Database; import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.oauth.cache.AppInfoCache; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.dao.OAuthAppDAO; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; @@ -38,14 +40,21 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.test.common.testng.utils.MockAuthenticatedUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + /** * Unit test covering TokenResponseTypeHandler class */ @WithCarbonHome @WithRealmService(injectToSingletons = OAuthComponentServiceHolder.class) -@WithH2Database(files = { "dbScripts/identity.sql" }) +@WithH2Database(files = { "dbScripts/identity.sql", "dbScripts/insert_local_idp.sql" }) public class TokenResponseTypeHandlerTest { private static final String TEST_CLIENT_ID_1 = "SDSDSDS23131231"; @@ -57,6 +66,7 @@ public class TokenResponseTypeHandlerTest { public void setUp() throws Exception { OAuthEventInterceptor interceptor = Mockito.mock(OAuthEventInterceptor.class); OAuthComponentServiceHolder.getInstance().addOauthEventInterceptorProxy(interceptor); + Mockito.clearAllCaches(); } /** @@ -105,10 +115,19 @@ public void testIssue(boolean isIDPIdColumnEnabled, String clientId) throws Exce new OAuthAppDAO().addOAuthApplication(oAuthAppDO); - OAuth2AuthorizeRespDTO auth2AuthorizeReqDTO = tokenResponseTypeHandler. - issue(authAuthzReqMessageContext); - Assert.assertNotNull(auth2AuthorizeReqDTO.getAccessToken()); - Assert.assertTrue(auth2AuthorizeReqDTO.getValidityPeriod() > 1, - "Access Token should be valid, i.e. not expired."); + try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class); + MockedStatic mockedAuthzUtil = mockStatic(AuthzUtil.class)) { + + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); + AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); + appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); + doNothing().when(mockAppInfoCache).addToCache(anyString(), any(OAuthAppDO.class)); + + OAuth2AuthorizeRespDTO auth2AuthorizeReqDTO = tokenResponseTypeHandler. + issue(authAuthzReqMessageContext); + Assert.assertNotNull(auth2AuthorizeReqDTO.getAccessToken()); + Assert.assertTrue(auth2AuthorizeReqDTO.getValidityPeriod() > 1, + "Access Token should be valid, i.e. not expired."); + } } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java index 7661ddf35fa..b23e74675a9 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java @@ -20,6 +20,7 @@ import org.mockito.Mock; import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -59,6 +60,7 @@ import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeHandler; @@ -104,6 +106,7 @@ public class AbstractAuthorizationGrantHandlerTest { "org.wso2.carbon.identity.oauth.callback.DefaultCallbackHandler"; private static final String PASSWORD_GRANT = "password"; private OAuthAppDO oAuthAppDO; + private MockedStatic mockedAuthzUtil; @BeforeMethod public void setUp() throws IdentityOAuth2Exception, IdentityOAuthAdminException, ActionExecutionException { @@ -144,12 +147,16 @@ public void setUpMocks() { IdentityEventService identityEventService = mock(IdentityEventService.class); CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(identityEventService); + Mockito.clearAllCaches(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass public void tearDown() { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); + mockedAuthzUtil.close(); } @Test(dataProvider = "IssueWithRenewDataProvider", expectedExceptions = IdentityOAuth2Exception.class) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index 16b1a61d69c..7f05221ccf6 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -2232,12 +2232,13 @@ public void testGetOAuthTokenIssuerForOAuthApp(String tokenType) throws Exceptio appDO.setTokenType(tokenType); AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)).thenReturn(appDO); + when(mockAppInfoCache.getValueFromCache(clientId, clientTenantDomain)).thenReturn(appDO); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); OauthTokenIssuer oauthTokenIssuer = mock(OauthTokenIssuer.class); when(oauthServerConfigurationMock.getIdentityOauthTokenIssuer()).thenReturn(oauthTokenIssuer); + identityTenantUtil.when(IdentityTenantUtil::resolveTenantDomain).thenReturn(clientTenantDomain); assertEquals(OAuth2Util.getOAuthTokenIssuerForOAuthApp(clientId), oauthTokenIssuer); } } @@ -2247,11 +2248,12 @@ public void testGetOAuthTokenIssuerForOAuthAppWithException() { try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class)) { AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)). + when(mockAppInfoCache.getValueFromCache(clientId, clientTenantDomain)). thenAnswer(i -> { throw new IdentityOAuth2Exception("IdentityOAuth2Exception"); }); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); + identityTenantUtil.when(IdentityTenantUtil::resolveTenantDomain).thenReturn(clientTenantDomain); try { OAuth2Util.getOAuthTokenIssuerForOAuthApp(clientId); @@ -2603,7 +2605,7 @@ private void setCache(MockedStatic appInfoCache) { appDO.setUser(user); AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - lenient().when(mockAppInfoCache.getValueFromCache(clientId)).thenReturn(appDO); + lenient().when(mockAppInfoCache.getValueFromCache(clientId, SUPER_TENANT_DOMAIN_NAME)).thenReturn(appDO); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); } @@ -2612,7 +2614,7 @@ public void testGetServiceProviderWithIdentityInvalidOAuthClientException() { try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class)) { AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)). + when(mockAppInfoCache.getValueFromCache(clientId, SUPER_TENANT_DOMAIN_NAME)). thenAnswer(i -> { throw new InvalidOAuthClientException("InvalidOAuthClientException"); }); diff --git a/pom.xml b/pom.xml index b1bdc187c3c..f4eede74804 100644 --- a/pom.xml +++ b/pom.xml @@ -938,7 +938,7 @@ 1.2.4 - 4.10.22 + 4.10.26 4.10.22 [4.10.22, 5.0.0) [1.0.1, 2.0.0)