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. - ==================================================================================================================== - --> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + +