diff --git a/modules/integration/tests-common/jacoco-report-generator/dependency-reduced-pom.xml b/modules/integration/tests-common/jacoco-report-generator/dependency-reduced-pom.xml
new file mode 100644
index 00000000000..b6895e7eef6
--- /dev/null
+++ b/modules/integration/tests-common/jacoco-report-generator/dependency-reduced-pom.xml
@@ -0,0 +1,66 @@
+
+
+
+ identity-integration-tests
+ org.wso2.is
+ 7.1.0-m2-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ jacoco-report-generator
+
+
+
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ package
+
+ shade
+
+
+
+
+ org.jacoco:org.jacoco.core
+ org.jacoco:org.jacoco.report
+ org.codehaus.plexus:plexus-utils
+ org.ow2.asm:asm
+ org.ow2.asm:asm-tree
+ org.ow2.asm:asm-commons
+
+
+
+
+ org.wso2.carbon.identity.jacoco.ReportGenerator
+
+
+
+
+
+
+
+
+
+
+ org.wso2.carbon.identity.inbound.auth.sts
+ org.wso2.carbon.identity.sts.passive.stub
+ 5.11.9
+ compile
+
+
+ org.wso2.carbon.automationutils
+ org.wso2.carbon.integration.common.extensions
+ 4.5.4
+ compile
+
+
+
+ 11
+ 11
+ 3.2.4
+ UTF-8
+ 0.8.12
+ 4.0.1
+
+
diff --git a/modules/integration/tests-integration/tests-backend/pom.xml b/modules/integration/tests-integration/tests-backend/pom.xml
index c1cd3f0b3fa..98f6c252222 100644
--- a/modules/integration/tests-integration/tests-backend/pom.xml
+++ b/modules/integration/tests-integration/tests-backend/pom.xml
@@ -589,8 +589,8 @@
org.apache.maven.plugins
maven-compiler-plugin
- 1.8
- 1.8
+ 11
+ 11
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
index a5100fae8a4..a79a26d387a 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
@@ -1177,6 +1177,43 @@ public void authorizeSystemAPIs(String applicationId, List apiIdentifier
});
}
+ /**
+ * Authorize list of SYSTEM APIs to an application registered in sub organization.
+ *
+ * @param applicationId Application id.
+ * @param apiIdentifiers API identifiers to authorize.
+ * @throws Exception Error occured while authorizing APIs.
+ */
+ public void authorizeSystemAPIsToSubOrganizationApp(String applicationId, List apiIdentifiers,
+ String switchedM2MToken) {
+
+ apiIdentifiers.stream().forEach(apiIdentifier -> {
+ try {
+ List filteredAPIResource =
+ restClient.getAPIResourcesWithFilteringFromSubOrganization("identifier+eq+" + apiIdentifier,
+ switchedM2MToken);
+ if (filteredAPIResource == null || filteredAPIResource.isEmpty()) {
+ return;
+ }
+ String apiId = filteredAPIResource.get(0).getId();
+ // Get API scopes.
+ List apiResourceScopes = restClient.getAPIResourceScopesInSubOrganization(apiId,
+ switchedM2MToken);
+ AuthorizedAPICreationModel authorizedAPICreationModel = new AuthorizedAPICreationModel();
+ authorizedAPICreationModel.setId(apiId);
+ authorizedAPICreationModel.setPolicyIdentifier("RBAC");
+ apiResourceScopes.forEach(scope -> {
+ authorizedAPICreationModel.addScopesItem(scope.getName());
+ });
+ restClient.addAPIAuthorizationToSubOrgApplication(applicationId, authorizedAPICreationModel,
+ switchedM2MToken);
+ } catch (Exception e) {
+ throw new RuntimeException("Error while authorizing system API " + apiIdentifier + " to application "
+ + applicationId, e);
+ }
+ });
+ }
+
public String getRoleV2ResourceId(String roleName, String audienceType, String OrganizationId) throws Exception {
List roles = restClient.getRoles(roleName, audienceType, OrganizationId);
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/OrganizationOAuth2ApplicationManagementSuccessTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/OrganizationOAuth2ApplicationManagementSuccessTest.java
new file mode 100644
index 00000000000..7bbf16a247f
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/OrganizationOAuth2ApplicationManagementSuccessTest.java
@@ -0,0 +1,189 @@
+package org.wso2.identity.integration.test.rest.api.server.application.management.v1;
+
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
+import com.nimbusds.oauth2.sdk.ResourceOwnerPasswordCredentialsGrant;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.TokenResponse;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import org.json.JSONObject;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AssociatedRolesConfig;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocolListItem;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocols;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
+import org.wso2.identity.integration.test.rest.api.server.organization.management.v1.OrganizationManagementBaseTest;
+import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Audience;
+import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Permission;
+import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.RoleV2;
+import org.wso2.identity.integration.test.restclients.OAuth2RestClient;
+import org.wso2.identity.integration.test.restclients.OrgMgtRestClient;
+import org.wso2.identity.integration.test.utils.OAuth2Constant;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class OrganizationOAuth2ApplicationManagementSuccessTest extends OrganizationManagementBaseTest {
+
+ private static final String AUTHORIZED_APIS_JSON = "org-based-authorized-apis.json";
+ private static final String SUB_ORG_NAME = "subOrg";
+
+ private OrgMgtRestClient orgMgtRestClient;
+ private OAuth2RestClient oAuth2RestClient;
+ private String subOrgId;
+ private String switchedM2MToken;
+ private String subOrgAppToken;
+
+ @Factory(dataProvider = "restAPIUserConfigProvider")
+ public OrganizationOAuth2ApplicationManagementSuccessTest(TestUserMode userMode) throws Exception {
+
+ super.init(userMode);
+ this.context = isServer;
+ this.authenticatingUserName = context.getContextTenant().getTenantAdmin().getUserName();
+ this.authenticatingCredential = context.getContextTenant().getTenantAdmin().getPassword();
+ this.tenant = context.getContextTenant().getDomain();
+ }
+
+ @BeforeClass(alwaysRun = true)
+ public void initClass() throws Exception {
+
+ super.testInit("v1", swaggerDefinition, tenant);
+ oAuth2RestClient = new OAuth2RestClient(serverURL, tenantInfo);
+
+ orgMgtRestClient = new OrgMgtRestClient(isServer, tenantInfo, serverURL,
+ new JSONObject(readResource(AUTHORIZED_APIS_JSON, this.getClass())));
+ subOrgId = orgMgtRestClient.addOrganization(SUB_ORG_NAME);
+ switchedM2MToken = orgMgtRestClient.switchM2MToken(subOrgId);
+ orgMgtRestClient.addOrganizationUser("sub-org-user", "SubOrgUser@123");
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void atEnd() throws Exception {
+
+ orgMgtRestClient.deleteOrganization(subOrgId);
+ orgMgtRestClient.closeHttpClient();
+ oAuth2RestClient.closeHttpClient();
+ }
+
+ @Test
+ public void testCreateOAuth2ApplicationInOrganization() throws Exception {
+
+ String body = readResource("create-basic-oauth2-application.json", this.getClass());
+
+ oAuth2RestClient.createApplicationInSubOrganization(body, switchedM2MToken);
+ System.out.println("Sub Organization Application ID : " + oAuth2RestClient.getAppIdUsingAppNameInOrganization("My SAMPLE APP", switchedM2MToken));
+ String subOrganizationAppId = oAuth2RestClient.getAppIdUsingAppNameInOrganization("My SAMPLE APP",
+ switchedM2MToken);
+
+ // Authorizing the APIs to the sub organization application
+ authorizeSystemAPIsToSubOrganizationApp(oAuth2RestClient, subOrganizationAppId,
+ new ArrayList<>(Arrays.asList("/o/scim2/Roles", "/o/oauth2/introspect")), switchedM2MToken);
+
+ // Creating an application role for the sub organization application
+ RoleV2 role;
+ String displayName;
+ List schemas = Collections.emptyList();
+ List permissions = new ArrayList<>();
+ permissions.add(new Permission("internal_org_role_mgt_create"));
+ permissions.add(new Permission("internal_org_role_mgt_view"));
+ displayName = "Application Role";
+ Audience roleAudience = new Audience("APPLICATION", subOrganizationAppId);
+ role = new RoleV2(roleAudience, displayName, permissions, schemas);
+ oAuth2RestClient.createV2RolesInSubOrganization(role, switchedM2MToken);
+ ApplicationResponseModel subOrgAppModel = oAuth2RestClient.getSubOrgApplication(subOrganizationAppId,
+ switchedM2MToken);
+
+ // Validate application details
+ Assert.assertEquals(subOrgAppModel.getName(), "My SAMPLE APP");
+
+ // Validate application role audience and roles
+ AssociatedRolesConfig associatedRolesConfig = subOrgAppModel.getAssociatedRoles();
+ Assert.assertEquals(associatedRolesConfig.getAllowedAudience().toString(), "APPLICATION");
+ Assert.assertEquals(associatedRolesConfig.getRoles().get(0).getName(), "Application Role");
+
+ // Validate application inbound protocols
+ List inboundProtocols = subOrgAppModel.getInboundProtocols();
+ Assert.assertEquals(inboundProtocols.size(), 1);
+ }
+
+ @Test(dependsOnMethods = "testCreateOAuth2ApplicationInOrganization")
+ public void testIssueAccessTokenFromSubOrgApplicationFromCCGrant() throws Exception {
+
+ String subOrganizationAppId = oAuth2RestClient.getAppIdUsingAppNameInOrganization("My SAMPLE APP",
+ switchedM2MToken);
+ OpenIDConnectConfiguration oidcConfig = oAuth2RestClient.getOIDCInboundDetailsForSubOrgApplications(
+ subOrganizationAppId, switchedM2MToken);
+ String subOrgAppClientId = oidcConfig.getClientId();
+ String clientSecret = oidcConfig.getClientSecret();
+
+ // Issue access token from sub organization application
+ AccessTokenResponse accessTokenResponse = getSubOrgApplicationToken("client_credentials", subOrgAppClientId, clientSecret, subOrgId);
+ subOrgAppToken = accessTokenResponse.getTokens().getAccessToken().getValue();
+ Assert.assertNotNull(subOrgAppToken);
+ String scopes = accessTokenResponse.getTokens().getAccessToken().getScope().toString();
+ String[] scopeArray = scopes.split(" ");
+ Assert.assertEquals(scopeArray.length, 6);
+ Assert.assertTrue(Arrays.asList(scopeArray).contains("internal_org_role_mgt_create"));
+ Assert.assertTrue(Arrays.asList(scopeArray).contains("internal_org_role_mgt_view"));
+ Assert.assertTrue(Arrays.asList(scopeArray).contains("internal_org_role_mgt_update"));
+ Assert.assertTrue(Arrays.asList(scopeArray).contains("internal_org_role_mgt_delete"));
+ }
+
+ public void testAccessResourcesFromTokensIssuedFromSubOrgApplication() throws Exception {
+
+ // Access resources from tokens issued from sub organization application
+ oAuth2RestClient.getRoles(subOrgAppToken);
+ }
+
+ private AccessTokenResponse getSubOrgApplicationToken(String grantType, String clientId, String clientSecretStr, String orgId) throws Exception {
+
+ URI tokenEndpoint = new URI("https://localhost:9853/t/carbon.super/o/" + orgId + "/oauth2/token");
+
+ ClientID clientID = new ClientID(clientId);
+ Secret clientSecret = new Secret(clientSecretStr);
+ ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);
+
+ AuthorizationGrant authorizationGrant;
+ switch (grantType) {
+ case OAuth2Constant.OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS:
+ authorizationGrant = new ClientCredentialsGrant();
+ break;
+ case OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER:
+ authorizationGrant = new ResourceOwnerPasswordCredentialsGrant(null, null);
+ break;
+ default:
+ throw new Exception("Unsupported grant type");
+ }
+ Scope scope = new Scope("SYSTEM");
+
+ TokenRequest request = new TokenRequest(tokenEndpoint, clientAuth, authorizationGrant, scope);
+ HTTPResponse tokenHTTPResp = request.toHTTPRequest().send();
+ TokenResponse tokenResponse = TokenResponse.parse(tokenHTTPResp);
+ return tokenResponse.toSuccessResponse();
+ }
+
+ @DataProvider(name = "restAPIUserConfigProvider")
+ public static Object[][] restAPIUserConfigProvider() {
+
+ return new Object[][]{
+ {TestUserMode.SUPER_TENANT_ADMIN}
+// {TestUserMode.TENANT_ADMIN}
+ };
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/organization/management/v1/OrganizationManagementBaseTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/organization/management/v1/OrganizationManagementBaseTest.java
index 0f395b9a8ec..380dd520b6f 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/organization/management/v1/OrganizationManagementBaseTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/organization/management/v1/OrganizationManagementBaseTest.java
@@ -30,9 +30,12 @@
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
+import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.APIResourceListItem;
+import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.ScopeGetModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AdvancedApplicationConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationSharePOSTRequest;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthorizedAPICreationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocols;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.rest.api.server.common.RESTAPIServerTestBase;
@@ -173,12 +176,26 @@ protected String getAppClientId(String applicationId) throws Exception {
return oidcConfig.getClientId();
}
+ protected String getSubOrgAppClientId(String applicationId, String switchedToken) throws Exception {
+
+ OpenIDConnectConfiguration oidcConfig = oAuth2RestClient.getOIDCInboundDetailsForSubOrgApplications(
+ applicationId, switchedToken);
+ return oidcConfig.getClientId();
+ }
+
protected String getAppClientSecret(String applicationId) throws Exception {
OpenIDConnectConfiguration oidcConfig = oAuth2RestClient.getOIDCInboundDetails(applicationId);
return oidcConfig.getClientSecret();
}
+ protected String getSubOrgAppClientSecret(String applicationId, String switchedM2MToken) throws Exception {
+
+ OpenIDConnectConfiguration oidcConfig = oAuth2RestClient.getOIDCInboundDetailsForSubOrgApplications(
+ applicationId, switchedM2MToken);
+ return oidcConfig.getClientSecret();
+ }
+
protected String buildGetRequestURL(String endpointURL, String tenantDomain, List queryParams) {
String authorizeEndpoint = getTenantQualifiedURL(endpointURL, tenantDomain);
@@ -259,4 +276,41 @@ protected String createB2BUser(String switchedM2MToken) throws Exception {
Assert.assertNotNull(b2bUserID, "B2B user creation failed.");
return b2bUserID;
}
+
+ /**
+ * Authorize list of SYSTEM APIs to an application registered in sub organization.
+ *
+ * @param applicationId Application id.
+ * @param apiIdentifiers API identifiers to authorize.
+ * @throws Exception Error occured while authorizing APIs.
+ */
+ public void authorizeSystemAPIsToSubOrganizationApp(OAuth2RestClient restClient, String applicationId, List apiIdentifiers,
+ String switchedM2MToken) {
+
+ apiIdentifiers.stream().forEach(apiIdentifier -> {
+ try {
+ List filteredAPIResource =
+ restClient.getAPIResourcesWithFilteringFromSubOrganization("identifier+eq+" + apiIdentifier,
+ switchedM2MToken);
+ if (filteredAPIResource == null || filteredAPIResource.isEmpty()) {
+ return;
+ }
+ String apiId = filteredAPIResource.get(0).getId();
+ // Get API scopes.
+ List apiResourceScopes = restClient.getAPIResourceScopesInSubOrganization(apiId,
+ switchedM2MToken);
+ AuthorizedAPICreationModel authorizedAPICreationModel = new AuthorizedAPICreationModel();
+ authorizedAPICreationModel.setId(apiId);
+ authorizedAPICreationModel.setPolicyIdentifier("RBAC");
+ apiResourceScopes.forEach(scope -> {
+ authorizedAPICreationModel.addScopesItem(scope.getName());
+ });
+ restClient.addAPIAuthorizationToSubOrgApplication(applicationId, authorizedAPICreationModel,
+ switchedM2MToken);
+ } catch (Exception e) {
+ throw new RuntimeException("Error while authorizing system API " + apiIdentifier + " to application "
+ + applicationId, e);
+ }
+ });
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
index 6b7c4be2bd0..8005be92630 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
@@ -78,7 +78,9 @@ public class OAuth2RestClient extends RestBaseClient {
private final String applicationManagementApiBasePath;
private final String subOrgApplicationManagementApiBasePath;
private final String apiResourceManagementApiBasePath;
+ private final String subOrgApiResourceManagementApiBasePath;
private final String roleV2ApiBasePath;
+ private final String subOrgRoleV2ApiBasePath;
private final String username;
private final String password;
@@ -91,7 +93,9 @@ public OAuth2RestClient(String backendUrl, Tenant tenantInfo) {
applicationManagementApiBasePath = getApplicationsPath(backendUrl, tenantDomain);
subOrgApplicationManagementApiBasePath = getSubOrgApplicationsPath(backendUrl, tenantDomain);
apiResourceManagementApiBasePath = getAPIResourcesPath(backendUrl, tenantDomain);
+ subOrgApiResourceManagementApiBasePath = getSubOrgAPIResourcesPath(backendUrl, tenantDomain);
roleV2ApiBasePath = getSCIM2RoleV2Path(backendUrl, tenantDomain);
+ subOrgRoleV2ApiBasePath = getSubOrgSCIM2RoleV2Path(backendUrl, tenantDomain);
}
/**
@@ -118,6 +122,27 @@ public String createApplication(ApplicationModel application) throws IOException
}
}
+ /**
+ * Create an Application in sub organization.
+ *
+ * @param jsonRequest Application Model with application creation details.
+ * @return Id of the created application.
+ * @throws IOException If an error occurred while creating an application.
+ */
+ public String createApplicationInSubOrganization(String jsonRequest, String switchedM2MToken) throws IOException {
+
+ try (CloseableHttpResponse response = getResponseOfHttpPost(subOrgApplicationManagementApiBasePath, jsonRequest,
+ getHeadersWithBearerToken(switchedM2MToken))) {
+
+ if (response.getStatusLine().getStatusCode() >= 400) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ throw new RuntimeException("Error occurred while creating the application. Response: " + responseBody);
+ }
+ String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR);
+ return locationElements[locationElements.length - 1];
+ }
+ }
+
/**
* To create V2 roles.
*
@@ -135,6 +160,27 @@ public String createV2Roles(RoleV2 role) throws IOException {
}
}
+ /**
+ * To create V2 roles in sub organization.
+ *
+ * @param role an instance of RoleV2
+ * @return the roleID
+ * @throws IOException throws if an error occurs while creating the role.
+ */
+ public String createV2RolesInSubOrganization(RoleV2 role, String switchedM2MToken) throws IOException {
+
+ String jsonRequest = toJSONString(role);
+ try (CloseableHttpResponse response = getResponseOfHttpPost(subOrgRoleV2ApiBasePath, jsonRequest,
+ getHeadersWithBearerToken(switchedM2MToken))) {
+ if (response.getStatusLine().getStatusCode() >= 400) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ throw new RuntimeException("Error occurred while creating the role. Response: " + responseBody);
+ }
+ String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR);
+ return locationElements[locationElements.length - 1];
+ }
+ }
+
/**
* To delete V2 roles.
*
@@ -185,6 +231,26 @@ public ApplicationResponseModel getApplication(String appId) throws IOException
}
}
+ /**
+ * Get Application details.
+ *
+ * @param appId Application id.
+ * @return ApplicationResponseModel object.
+ * @throws IOException If an error occurred while getting an application.
+ */
+ public ApplicationResponseModel getSubOrgApplication(String appId, String switchedToken) throws IOException {
+
+ String endPointUrl = subOrgApplicationManagementApiBasePath + PATH_SEPARATOR + appId;
+
+ try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(
+ switchedToken))) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+
+ ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory());
+ return jsonWriter.readValue(responseBody, ApplicationResponseModel.class);
+ }
+ }
+
/**
* Get Application details by client id.
*
@@ -320,6 +386,13 @@ public OpenIDConnectConfiguration getOIDCInboundDetails(String appId) throws Exc
return jsonWriter.readValue(responseBody, OpenIDConnectConfiguration.class);
}
+ public OpenIDConnectConfiguration getOIDCInboundDetailsForSubOrgApplications(String appId, String switchedToken) throws Exception {
+
+ String responseBody = getInboundProtocolConfigForSubOrgApplication(appId, OIDC, switchedToken);
+ ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory());
+ return jsonWriter.readValue(responseBody, OpenIDConnectConfiguration.class);
+ }
+
/**
* Get SAML inbound configuration details of an application.
*
@@ -345,6 +418,16 @@ private String getConfig(String appId, String inboundType) throws Exception {
}
}
+ private String getInboundProtocolConfigForSubOrgApplication(String appId, String inboundType, String switchedToken) throws Exception {
+
+ String endPointUrl = subOrgApplicationManagementApiBasePath + PATH_SEPARATOR + appId + INBOUND_PROTOCOLS_BASE_PATH +
+ PATH_SEPARATOR + inboundType;
+
+ try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(switchedToken))) {
+ return EntityUtils.toString(response.getEntity());
+ }
+ }
+
/**
* Update inbound configuration details of an application.
*
@@ -412,6 +495,15 @@ private String getAPIResourcesPath(String serverUrl, String tenantDomain) {
}
}
+ private String getSubOrgAPIResourcesPath(String serverUrl, String tenantDomain) {
+
+ if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
+ return serverUrl + ORGANIZATION_PATH + API_SERVER_BASE_PATH + API_RESOURCE_MANAGEMENT_PATH;
+ }
+ return serverUrl + TENANT_PATH + tenantDomain + PATH_SEPARATOR + ORGANIZATION_PATH + API_SERVER_BASE_PATH +
+ API_RESOURCE_MANAGEMENT_PATH;
+ }
+
private String getSCIM2RoleV2Path(String serverUrl, String tenantDomain) {
if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
@@ -421,6 +513,15 @@ private String getSCIM2RoleV2Path(String serverUrl, String tenantDomain) {
}
}
+ private String getSubOrgSCIM2RoleV2Path(String serverUrl, String tenantDomain) {
+
+ if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
+ return serverUrl + ORGANIZATION_PATH + SCIM_BASE_PATH + ROLE_V2_BASE_PATH;
+ }
+ return serverUrl + TENANT_PATH + tenantDomain + PATH_SEPARATOR + ORGANIZATION_PATH + SCIM_BASE_PATH +
+ ROLE_V2_BASE_PATH;
+ }
+
private Header[] getHeaders() {
Header[] headerList = new Header[3];
@@ -462,6 +563,26 @@ public int addAPIAuthorizationToApplication(String appId, AuthorizedAPICreationM
}
}
+ /**
+ * Add API authorization to an application registered in a sub organization.
+ *
+ * @param appId Sub organization application id.
+ * @param authorizedAPICreationModel AuthorizedAPICreationModel object with api authorization details.
+ * @return Status code of the response.
+ * @throws IOException Error when getting the response.
+ */
+ public int addAPIAuthorizationToSubOrgApplication(String appId, AuthorizedAPICreationModel
+ authorizedAPICreationModel, String switchedM2MToken) throws IOException {
+
+ String jsonRequestBody = toJSONString(authorizedAPICreationModel);
+ String endPointUrl = subOrgApplicationManagementApiBasePath + PATH_SEPARATOR + appId + AUTHORIZED_API_BASE_PATH;
+
+ try (CloseableHttpResponse response = getResponseOfHttpPost(endPointUrl, jsonRequestBody,
+ getHeadersWithBearerToken(switchedM2MToken))) {
+ return response.getStatusLine().getStatusCode();
+ }
+ }
+
/**
* Get API resources by filtering.
*
@@ -481,6 +602,28 @@ public List getAPIResourcesWithFiltering(String apiResource
}
}
+ /**
+ * Get API resources by filtering from sub organization.
+ *
+ * @param apiResourceFilter API resource filter.
+ * @return List of API resources.
+ * @throws IOException Error when getting the filtered API resource.
+ */
+ public List getAPIResourcesWithFilteringFromSubOrganization(String apiResourceFilter,
+ String switchedM2MToken)
+ throws IOException {
+
+ String endPointUrl = subOrgApiResourceManagementApiBasePath + "?filter=" + apiResourceFilter;
+ try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(
+ switchedM2MToken))) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory());
+ APIResourceListResponse apiResourceListResponse =
+ jsonWriter.readValue(responseBody, APIResourceListResponse.class);
+ return apiResourceListResponse.getApiResources();
+ }
+ }
+
/**
* Get API resource scopes.
*
@@ -499,6 +642,26 @@ public List getAPIResourceScopes(String apiIdentifier) throws IOE
}
}
+ /**
+ * Get API resource scopes in sub organization.
+ *
+ * @param apiIdentifier API identifier.
+ * @return List of API resource scopes.
+ * @throws IOException Error when getting the scopes.
+ */
+ public List getAPIResourceScopesInSubOrganization(String apiIdentifier, String switchedM2MToken)
+ throws IOException {
+
+ String endPointUrl = subOrgApiResourceManagementApiBasePath + PATH_SEPARATOR + apiIdentifier;
+ try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(
+ switchedM2MToken))) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory());
+ APIResourceResponse apiResourceResponse = jsonWriter.readValue(responseBody, APIResourceResponse.class);
+ return apiResourceResponse.getScopes();
+ }
+ }
+
/**
* Creates a domain API.
*
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java
index ac088698be7..5a5727c8fc1 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java
@@ -42,9 +42,12 @@
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.wso2.carbon.automation.engine.context.AutomationContext;
import org.wso2.carbon.automation.engine.context.beans.Tenant;
@@ -67,10 +70,12 @@
public class OrgMgtRestClient extends RestBaseClient {
private static final String API_SERVER_BASE_PATH = "api/server/v1";
+ private static final String SCIM2_BASE_PATH = "scim2";
private static final String APPLICATION_MANAGEMENT_PATH = "/applications";
private static final String ORGANIZATION_MANAGEMENT_PATH = "/organizations";
private static final String API_RESOURCE_MANAGEMENT_PATH = "/api-resources";
private static final String AUTHORIZED_APIS_PATH = "/authorized-apis";
+ private static final String SCIM2_USERS_PATH = "/Users";
private static final String B2B_APP_NAME = "b2b-app";
private final OAuth2RestClient oAuth2RestClient;
@@ -80,6 +85,7 @@ public class OrgMgtRestClient extends RestBaseClient {
private final String organizationManagementApiBasePath;
private final String subOrganizationManagementApiBasePath;
private final String apiResourceManagementApiBasePath;
+ private final String subOrgSCIM2UsersAPIBasePath;
private final String authenticatingUserName;
private final String authenticatingCredential;
@@ -104,6 +110,7 @@ public OrgMgtRestClient(AutomationContext context, Tenant tenantInfo, String bas
buildPath(baseUrl, tenantInfo.getDomain(), API_RESOURCE_MANAGEMENT_PATH);
this.subOrganizationManagementApiBasePath =
buildSubOrgPath(baseUrl, tenantInfo.getDomain(), ORGANIZATION_MANAGEMENT_PATH);
+ this.subOrgSCIM2UsersAPIBasePath = buildSubOrgSCIM2Path(baseUrl, tenantInfo.getDomain(), SCIM2_USERS_PATH);
createB2BApplication(authorizedAPIs);
}
@@ -378,6 +385,15 @@ private String buildSubOrgPath(String serverUrl, String tenantDomain, String end
endpointURL;
}
+ private String buildSubOrgSCIM2Path(String serverUrl, String tenantDomain, String endpoint) {
+
+// if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
+// return serverUrl + ORGANIZATION_PATH + SCIM2_BASE_PATH + endpoint;
+// }
+ return serverUrl + TENANT_PATH + tenantDomain + PATH_SEPARATOR + ORGANIZATION_PATH + SCIM2_BASE_PATH +
+ endpoint;
+ }
+
/**
* Close the HTTP client.
*
@@ -389,4 +405,62 @@ public void closeHttpClient() throws IOException {
oAuth2RestClient.closeHttpClient();
client.close();
}
+
+ /**
+ * Add a user inside a sub organization.
+ *
+ * @param username Name of the organization.
+ * @return password of the created organization.
+ * @throws Exception If an error occurs while creating the organization.
+ */
+ public String addOrganizationUser(String username, String password) throws Exception {
+
+ String m2mToken = getM2MAccessToken();
+ String body = buildOrgUserCreationRequestBody(username, password);
+ try (CloseableHttpResponse response = getResponseOfHttpPost(subOrgSCIM2UsersAPIBasePath, body,
+ getHeadersWithBearerToken(m2mToken))) {
+ if (response.getStatusLine().getStatusCode() >= 400) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ throw new RuntimeException("Error occurred while creating the role. Response: " + responseBody);
+ }
+ String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR);
+ return locationElements[locationElements.length - 1];
+ }
+ }
+
+ private String buildOrgUserCreationRequestBody(String username, String password) throws JSONException {
+
+ JSONObject userPayload = new JSONObject();
+ userPayload.put("schemas", new JSONArray());
+
+ JSONObject name = new JSONObject();
+ name.put("givenName", "Kim05");
+ name.put("familyName", "Berry05");
+ userPayload.put("name", name);
+
+ userPayload.put("userName", username);
+ userPayload.put("password", password);
+
+ JSONArray emails = new JSONArray();
+ JSONObject email1 = new JSONObject();
+ email1.put("value", "kim05@gmail.com");
+ emails.put(email1);
+
+ JSONObject email2 = new JSONObject();
+ email2.put("type", "work");
+ email2.put("value", "kim05@wso2.com");
+ emails.put(email2);
+
+ userPayload.put("emails", emails);
+
+ JSONObject enterpriseUser = new JSONObject();
+ enterpriseUser.put("employeeNumber", "1234A03");
+
+ JSONObject manager = new JSONObject();
+ manager.put("value", "Taylor");
+ enterpriseUser.put("manager", manager);
+
+ userPayload.put("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", enterpriseUser);
+ return userPayload.toString();
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/create-basic-oauth2-application.json b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/create-basic-oauth2-application.json
new file mode 100644
index 00000000000..416de5d15c8
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/create-basic-oauth2-application.json
@@ -0,0 +1,20 @@
+{
+ "name": "My SAMPLE APP",
+ "description": "my application 2",
+ "imageUrl": "https://localhost/image",
+ "accessUrl": "https://localhost/accessUrl",
+ "associatedRoles": {
+ "allowedAudience": "APPLICATION",
+ "roles": []
+ },
+ "inboundProtocolConfiguration": {
+ "oidc": {
+ "grantTypes": [
+ "client_credentials",
+ "password",
+ "refresh_token"
+ ],
+ "isFAPIApplication": false
+ }
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/org-based-authorized-apis.json b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/org-based-authorized-apis.json
new file mode 100644
index 00000000000..9b8637ff574
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/rest/api/server/application/management/v1/org-based-authorized-apis.json
@@ -0,0 +1,42 @@
+{
+ "/api/server/v1/organizations": [
+ "internal_organization_view",
+ "internal_organization_create",
+ "internal_organization_delete"
+ ],
+ "/o/api/server/v1/userstore": [
+ "internal_org_userstore_create",
+ "internal_org_userstore_delete",
+ "internal_org_userstore_view"
+ ],
+ "/o/scim2/Users": [
+ "internal_org_user_mgt_create",
+ "internal_org_user_mgt_view",
+ "internal_org_user_mgt_list",
+ "internal_org_user_mgt_delete"
+ ],
+ "/o/scim2/Groups": [
+ "internal_org_group_mgt_create",
+ "internal_org_group_mgt_view",
+ "internal_org_group_mgt_delete"
+ ],
+ "/o/api/server/v1/claim-dialects": [
+ "internal_org_claim_meta_view",
+ "internal_org_claim_meta_update"
+ ],
+ "/o/api/server/v1/applications": [
+ "internal_org_application_mgt_create",
+ "internal_org_application_mgt_view",
+ "internal_org_application_mgt_update",
+ "internal_org_application_mgt_delete"
+ ],
+ "/o/api/server/v1/api-resources": [
+ "internal_org_api_resource_view"
+ ],
+ "/o/scim2/Roles": [
+ "internal_org_role_mgt_view",
+ "internal_org_role_mgt_create",
+ "internal_org_role_mgt_update",
+ "internal_org_role_mgt_delete"
+ ]
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
index bac9306fc3a..54cfb656068 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
+++ b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
@@ -30,424 +30,426 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
- Two different Nashorn engines are used based on JDK runtime compatibility in integration tests:
- Nashorn: Supports JDK runtimes up to version 15.
- OpenJDKNashorn: Supports JDK runtimes above version 15.
- -->
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
- Two different Nashorn engines are used based on JDK runtime compatibility in integration tests:
- Nashorn: Supports JDK runtimes up to version 15.
- OpenJDKNashorn: Supports JDK runtimes above version 15.
- -->
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
+
- To minimize the number of restarts, at each test, additional instance is started before all the tests in the
- below tag and stopped at the end.
- ====================================================================================================================
- -->
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
- To minimize the number of restarts, at each test, do the configuration update and restart. Then do the test
- and finally restore the configuration without restarting. The next test will perform the restart with the
- configuration changes required for it.
+
+
+
- If multiple tests can be run with one configuration change, group them into a test group and do the above at
- @BeforeTest, and @AfterTest. See 'is-tests-jdbc-userstore' for example.
- ====================================================================================================================
- -->
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+