Skip to content

Commit

Permalink
Merge pull request #34 from AnuradhaSK/tenant-state-check
Browse files Browse the repository at this point in the history
Stop issuing token for deactivated sub orgs in organization switch
  • Loading branch information
sadilchamishka authored May 17, 2024
2 parents 56c7845 + 530ec61 commit 3436d0c
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException;
import org.wso2.carbon.identity.application.common.model.ApplicationBasicInfo;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.dao.OAuthAppDO;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException;
Expand All @@ -50,9 +52,12 @@
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.tenant.TenantManager;

import java.util.Arrays;

import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_ERROR_RESOLVING_TENANT_DOMAIN_FROM_ORGANIZATION_DOMAIN;
import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_ORGANIZATION_NOT_FOUND_FOR_TENANT;

import static java.util.Objects.nonNull;
Expand All @@ -73,6 +78,11 @@ public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws Id

String token = extractParameter(OrganizationSwitchGrantConstants.Params.TOKEN_PARAM, tokReqMsgCtx);
String accessingOrgId = extractParameter(OrganizationSwitchGrantConstants.Params.ORG_PARAM, tokReqMsgCtx);
boolean isActiveOrg = isActiveOrganization(accessingOrgId);
if (!isActiveOrg) {
throw new IdentityOAuth2ClientException(OAuth2ErrorCodes.INVALID_REQUEST,
"The switching organization is in deactivated state.");
}
OAuth2TokenValidationResponseDTO validationResponseDTO = validateToken(token);
if (!validationResponseDTO.isValid()) {
LOG.debug("Access token validation failed.");
Expand Down Expand Up @@ -134,6 +144,26 @@ public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws Id
return true;
}

private boolean isActiveOrganization(String organizationId) throws IdentityOAuth2Exception {

try {
boolean organizationExistById = OrganizationSwitchGrantDataHolder.getInstance().getOrganizationManager()
.isOrganizationExistById(organizationId);
if (!organizationExistById) {
throw new IdentityOAuth2Exception(OAuth2ErrorCodes.INVALID_REQUEST,
"Invalid organization id: " + organizationId);
}
String tenantDomain = getTenantDomainFromOrgId(organizationId);
TenantManager tenantManager =
OrganizationSwitchGrantDataHolder.getInstance().getRealmService().getTenantManager();
return tenantManager.isTenantActive(IdentityTenantUtil.getTenantId(tenantDomain));
} catch (OrganizationManagementException e) {
throw new IdentityOAuth2Exception("Error while checking organization exist with ID: " + organizationId , e);
} catch (UserStoreException e) {
throw new IdentityOAuth2Exception("Error while validating whether the organization is active.", e);
}
}

private boolean isInSameBranch(String currentOrgId, String switchOrgId) throws IdentityOAuth2ClientException,
OrganizationManagementServerException {

Expand Down Expand Up @@ -225,6 +255,17 @@ private String getOrganizationIdFromTenantDomain(String tenantDomain) throws Org
}
}

private String getTenantDomainFromOrgId(String organizationId) throws OrganizationSwitchGrantException {

try {
return OrganizationSwitchGrantDataHolder.getInstance().getOrganizationManager()
.resolveTenantDomain(organizationId);
} catch (OrganizationManagementException e) {
throw OrganizationSwitchGrantUtil.handleServerException(
ERROR_CODE_ERROR_RESOLVING_TENANT_DOMAIN_FROM_ORGANIZATION_DOMAIN, e);
}
}

private OrganizationManager getOrganizationManager() {

return OrganizationSwitchGrantDataHolder.getInstance().getOrganizationManager();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService;
import org.wso2.carbon.user.core.service.RealmService;

/**
* Organization switch grant data holder.
Expand All @@ -36,6 +37,7 @@ public class OrganizationSwitchGrantDataHolder {
private OrganizationManager organizationManager;
private OrgApplicationManager orgApplicationManager;
private ApplicationManagementService applicationManagementService;
private RealmService realmService;

public static OrganizationSwitchGrantDataHolder getInstance() {

Expand Down Expand Up @@ -132,4 +134,24 @@ public void setApplicationManagementService(ApplicationManagementService applica

this.applicationManagementService = applicationManagementService;
}

/**
* Get {@link RealmService}.
*
* @return Realm service {@link RealmService}.
*/
public RealmService getRealmService() {

return realmService;
}

/**
* Set {@link RealmService}.
*
* @param realmService Instance of {@link RealmService}.
*/
public void setRealmService(RealmService realmService) {

this.realmService = realmService;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.wso2.carbon.identity.organization.management.application.internal.OrgApplicationMgtDataHolder;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService;
import org.wso2.carbon.user.core.service.RealmService;

/**
* This class contains the service component of the organization switching grant type.
Expand Down Expand Up @@ -164,4 +165,22 @@ protected void unsetApplicationManagementService(ApplicationManagementService ap

OrganizationSwitchGrantDataHolder.getInstance().setApplicationManagementService(null);
}

@Reference(
name = "realm.service",
service = RealmService.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
unbind = "unsetRealmService")
protected void setRealmService(RealmService realmService) {

OrganizationSwitchGrantDataHolder.getInstance().setRealmService(realmService);
LOG.debug("Realm service set in OrganizationSwitchGrantDataHolder.");
}

protected void unsetRealmService(RealmService realmService) {

OrganizationSwitchGrantDataHolder.getInstance().setRealmService(null);
LOG.debug("Realm service unset in OrganizationSwitchGrantDataHolder.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.common.testng.WithCarbonHome;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.dao.OAuthAppDO;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
Expand All @@ -50,11 +51,15 @@
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementServerException;
import org.wso2.carbon.identity.organization.management.service.util.Utils;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.tenant.TenantManager;

import java.util.ArrayList;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -85,38 +90,57 @@ public class OrganizationSwitchGrantTest {
private OrganizationSwitchGrant organizationSwitchGrant;
private AccessTokenDO mockAccessTokenDO;
private AuthenticatedUser mockAuthenticatedUser;
private TenantManager mockTenantManager;
private RealmService mockRealmService;
private MockedStatic<OAuth2Util> mockedOAuth2Util;
private MockedStatic<Utils> mockOrgUtil;
private MockedStatic<IdentityTenantUtil> mockIdentityTenantUtil;

@BeforeClass
public void setup() throws IdentityApplicationManagementException {
public void setup() throws Exception {

mockAccessTokenDO = mock(AccessTokenDO.class);
mockAuthenticatedUser = mock(AuthenticatedUser.class);
mockedOAuth2Util = Mockito.mockStatic(OAuth2Util.class);
mockOrgUtil = Mockito.mockStatic(Utils.class);
mockedOAuth2Util.when(() -> OAuth2Util.findAccessToken(nullable(String.class), anyBoolean())).thenReturn(mockAccessTokenDO);
mockIdentityTenantUtil = Mockito.mockStatic(IdentityTenantUtil.class);
mockedOAuth2Util.when(() -> OAuth2Util.findAccessToken(nullable(String.class), anyBoolean()))
.thenReturn(mockAccessTokenDO);
mockOrgUtil.when(Utils::getSubOrgStartLevel).thenReturn(2);
mockIdentityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(nullable(String.class))).thenReturn(1);

mockOAuth2TokenValidationService = mock(OAuth2TokenValidationService.class);
mockOAuth2ClientApplicationDTO = mock(OAuth2ClientApplicationDTO.class);
mockOAuthAppDO = mock(OAuthAppDO.class);
mockOAuth2TokenValidationResponseDTO = mock(OAuth2TokenValidationResponseDTO.class);
OrganizationSwitchGrantDataHolder.getInstance().setOAuth2TokenValidationService(mockOAuth2TokenValidationService);
when(mockOAuth2TokenValidationService.findOAuthConsumerIfTokenIsValid(any())).thenReturn(mockOAuth2ClientApplicationDTO);
when(mockOAuth2ClientApplicationDTO.getAccessTokenValidationResponse()).thenReturn(mockOAuth2TokenValidationResponseDTO);
OrganizationSwitchGrantDataHolder.getInstance()
.setOAuth2TokenValidationService(mockOAuth2TokenValidationService);
when(mockOAuth2TokenValidationService.findOAuthConsumerIfTokenIsValid(any())).thenReturn(
mockOAuth2ClientApplicationDTO);
when(mockOAuth2ClientApplicationDTO.getAccessTokenValidationResponse()).thenReturn(
mockOAuth2TokenValidationResponseDTO);

mockOrganizationManager = mock(OrganizationManager.class);
OrganizationSwitchGrantDataHolder.getInstance().setOrganizationManager(mockOrganizationManager);
when(mockOrganizationManager.isOrganizationExistById(anyString())).thenReturn(true);

mockOrgApplicationManager = mock(OrgApplicationManager.class);
OrganizationSwitchGrantDataHolder.getInstance().setOrgApplicationManager(mockOrgApplicationManager);
mockApplicationManagementService = mock(ApplicationManagementService.class);
OrganizationSwitchGrantDataHolder.getInstance().setApplicationManagementService(mockApplicationManagementService);
OrganizationSwitchGrantDataHolder.getInstance()
.setApplicationManagementService(mockApplicationManagementService);

mockApplicationBasicInfo = mock(ApplicationBasicInfo.class);
when(mockOAuthAppDO.getApplicationName()).thenReturn(APPLICATION_NAME);
when(mockApplicationManagementService.getApplicationBasicInfoByName(anyString(),anyString())).thenReturn(mockApplicationBasicInfo);
when(mockApplicationManagementService.getApplicationBasicInfoByName(anyString(), anyString())).thenReturn(
mockApplicationBasicInfo);
when(mockApplicationBasicInfo.getApplicationResourceId()).thenReturn(APPLICATION_ID);

mockRealmService = mock(RealmService.class);
mockTenantManager = mock(TenantManager.class);
OrganizationSwitchGrantDataHolder.getInstance().setRealmService(mockRealmService);
when(mockRealmService.getTenantManager()).thenReturn(mockTenantManager);
when(mockTenantManager.isTenantActive(anyInt())).thenReturn(true);
}

@BeforeMethod
Expand Down Expand Up @@ -146,7 +170,22 @@ public void testWhenSwitchingOrgIsInvalid() throws IdentityOAuth2Exception, Orga
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID, SWITCHING_ORG_ID)).thenReturn(-1);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID,
SWITCHING_ORG_ID)).thenReturn(-1);
organizationSwitchGrant.validateGrant(oAuthTokenReqMessageContext);
}

@Test(expectedExceptions = IdentityOAuth2ClientException.class)
public void testWhenSwitchingOrgIsInactive()
throws OrganizationManagementException, IdentityOAuth2Exception, UserStoreException {

when(mockOAuth2TokenValidationResponseDTO.isValid()).thenReturn(true);
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockTenantManager.isTenantActive(anyInt())).thenReturn(false);
organizationSwitchGrant.validateGrant(oAuthTokenReqMessageContext);
}

Expand All @@ -158,6 +197,7 @@ public void testSwitchSubOrgInSameTree()
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID, SWITCHING_ORG_ID)).thenReturn(1);
when(mockAuthenticatedUser.getUserId()).thenReturn("12345");
when(mockOrgApplicationManager.isApplicationSharedWithGivenOrganization(anyString(),anyString(),anyString())).
Expand All @@ -183,6 +223,7 @@ public void testSwitchSubOrgInDifferentTree()
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID, SWITCHING_ORG_ID)).thenReturn(-1);
organizationSwitchGrant.validateGrant(oAuthTokenReqMessageContext);
}
Expand All @@ -195,6 +236,7 @@ public void testSwitchOrgWhereAppNotShared()
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID, SWITCHING_ORG_ID)).thenReturn(1);
when(mockOrgApplicationManager.isApplicationSharedWithGivenOrganization(anyString(),anyString(),anyString())).
thenReturn(false);
Expand All @@ -211,6 +253,7 @@ public void testSameBindingSetForSwitchedToken()
when(mockAccessTokenDO.getAuthzUser()).thenReturn(mockAuthenticatedUser);
when(mockAuthenticatedUser.getTenantDomain()).thenReturn(TOKEN_ISSUED_TENANT_DOMAIN);
when(mockOrganizationManager.resolveOrganizationId(TOKEN_ISSUED_TENANT_DOMAIN)).thenReturn(TOKEN_ISSUED_ORG_ID);
when(mockOrganizationManager.resolveOrganizationId(SWITCHING_ORG_ID)).thenReturn(SWITCHING_ORG_TENANT_DOMAIN);
when(mockOrganizationManager.getRelativeDepthBetweenOrganizationsInSameBranch(TOKEN_ISSUED_ORG_ID, SWITCHING_ORG_ID)).thenReturn(2);
when(mockAuthenticatedUser.getUserId()).thenReturn("12345");
when(mockAccessTokenDO.getTokenBinding()).thenReturn(tokenBinding);
Expand Down

0 comments on commit 3436d0c

Please sign in to comment.