-
Notifications
You must be signed in to change notification settings - Fork 941
Add integration tests for performing authorizations for sub organization applications #26359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add integration tests for performing authorizations for sub organization applications #26359
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds organization-scoped REST methods and helpers (OAuth2, Org management, SCIM), a new OAuth2 grant constant, two permissions JSON resources, a TestNG entry, and a comprehensive integration test exercising sub-organization OAuth2 application and token flows. Changes
Sequence Diagram(s)mermaid rect rgb(235,245,255) Test->>AuthServer: request M2M token Test->>OrgClient: addOrganizationWithToken(orgName, orgHandle, m2mToken) Test->>OAuthClient: createOrganizationApplication(appModel, switchedAccessToken) Test->>SCIMClient: addOrganizationV2Roles(role, accessToken) Test->>AuthServer: exchange for organization-switched token (grant_type=organization_switch) Test->>API: call management API (Authorization: Bearer token) Note over Test: Cleanup (delete app, roles, org) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (10)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
31-31: Consider using this constant inOrgMgtRestClient.java.The new constant is correctly defined. However,
OrgMgtRestClient.javaat line 274 uses a hardcoded string"organization_switch"instead of referencing this constant:urlParameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE_NAME, "organization_switch"));Consider updating to use the constant for consistency:
-urlParameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE_NAME, "organization_switch")); +urlParameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE_NAME, OAuth2Constant.OAUTH2_GRANT_TYPE_ORGANIZATION_SWITCH));modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
272-332: Consider extracting common application configuration logic.This method largely duplicates the logic in
addApplication(ApplicationConfig)(lines 192-241). The only differences are the application name source and the REST client methods used.Consider extracting the common application model building logic into a private helper method to reduce duplication:
private ApplicationModel buildApplicationModel(String applicationName, ApplicationConfig applicationConfig) { // Common configuration building logic }Then both methods can use this helper, with only the REST client call differing.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (7)
56-59: Avoid wildcard imports for clarity and to prevent namespace conflicts.Using wildcard imports (
import java.util.*;andimport static org.testng.Assert.*;) can lead to ambiguity and makes it harder to track which classes are actually used.Consider explicit imports:
-import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map;
100-113: Static mutable fields may cause issues in parallel test execution.
CLIENT_ID,CLIENT_SECRET,ORG_APP_CLIENT_ID, andORG_APP_CLIENT_SECRETare static but mutated during test setup. If tests run in parallel, this could lead to race conditions.Consider making these instance fields instead:
- private static String CLIENT_ID; - private static String CLIENT_SECRET; - private static String ORG_APP_CLIENT_ID; - private static String ORG_APP_CLIENT_SECRET; + private String clientId; + private String clientSecret; + private String orgAppClientId; + private String orgAppClientSecret;
264-286: Created resources are not cleaned up after test.The test creates an organization application (
ORGANIZATION_TEST_APP_NAME) but doesn't delete it in cleanup. This could leave test artifacts and affect subsequent test runs.Consider storing the created
orgAppIdas a class field and deleting it inatEnd():// In atEnd(): if (testOrgAppId != null) { oAuth2RestClient.deleteApplication(testOrgAppId); }
288-317: Created test user is not cleaned up.Similar to the application, the user created with
TEST_ORG_END_USER_USERNAMEis not deleted after the test completes.Store the user ID and delete it in the cleanup phase to maintain test isolation.
384-455: Significant code duplication betweenupdateAuthorizedAPIsandupdateOrganizationAppAuthorizedAPIs.These two methods have nearly identical logic, differing only in the path construction and headers used. Consider extracting common logic.
private void updateAuthorizedAPIsInternal(String appId, JSONObject authorizedAPIs, String apiBasePath, String appBasePath, Header[] headers) throws JSONException, IOException { RestBaseClient restBaseClient = new RestBaseClient(); for (Iterator<String> apiNameIterator = authorizedAPIs.keys(); apiNameIterator.hasNext(); ) { String apiName = apiNameIterator.next(); Object requiredScopes = authorizedAPIs.get(apiName); // ... common logic } }
551-553: RedundantEntityUtils.consumeafterEntityUtils.toString.
EntityUtils.toString()already consumes the entity, making the subsequentEntityUtils.consume()call unnecessary.HttpResponse response = client.execute(httpPost); String responseString = EntityUtils.toString(response.getEntity(), "UTF-8"); - EntityUtils.consume(response.getEntity()); JSONParser parser = new JSONParser();
596-604:getAuthorizationCodeFromURLreturns null silently on failure.Returning
nullwhen the authorization code is not found could lead to cryptic NullPointerExceptions downstream. Consider throwing an exception with a descriptive message.private String getAuthorizationCodeFromURL(String location) { URI uri = URI.create(location); return URLEncodedUtils.parse(uri, StandardCharsets.UTF_8).stream() .filter(param -> "code".equals(param.getName())) .map(NameValuePair::getValue) .findFirst() - .orElse(null); + .orElseThrow(() -> new IllegalStateException( + "Authorization code not found in URL: " + location)); }modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (1)
531-541: Consider adding error handling for failed requests.Similar to
getConfig, this method doesn't validate the response status code before returning the entity. A failed request would return an error JSON that would fail deserialization upstream. While this is consistent with existing code, consider improving both.private String getConfigOrOrganizationApp(String appId, String inboundType, String accessToken) throws Exception { String endPointUrl = subOrgApplicationManagementApiBasePath + PATH_SEPARATOR + appId + INBOUND_PROTOCOLS_BASE_PATH + PATH_SEPARATOR + inboundType; try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(accessToken))) { + if (response.getStatusLine().getStatusCode() >= 400) { + throw new RuntimeException("Failed to get inbound config. Status: " + + response.getStatusLine().getStatusCode()); + } return EntityUtils.toString(response.getEntity()); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java(3 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java(8 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java(2 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
OAuth2Constant(24-150)
🔇 Additional comments (13)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
522-541: LGTM!The new
updateOrganizationUserRolemethod correctly follows the existing patterns in this class for organization-scoped operations. It properly uses thegetSubOrgRolesV2Path()endpoint builder and bearer token authentication consistent with similar methods likeupdateUsersOfRoleV2InSubOrg.modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json (1)
1-35: LGTM!The JSON configuration correctly maps management API endpoints to their required internal permissions. The structure is well-organized and follows a consistent permission naming pattern aligned with WSO2 Identity Server conventions.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java (2)
137-154: LGTM!The new
addOrganizationWithTokenmethod correctly follows the existing pattern of theaddOrganizationoverloads, allowing tests to provide an externally managed token for organization creation.
210-224: LGTM!The new
deleteOrganizationWithTokenmethod correctly mirrors the existingdeleteOrganizationmethod while accepting an externally provided access token. The HTTP 204 NO_CONTENT assertion is properly included.modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json (1)
10-15: Verify the role permissions scope difference is intentional.The
/o/scim2/Rolesendpoint here includes 4 permissions (view, create, update, delete), while the same endpoint inmanagement-app-authorized-apis.jsonincludes 7 permissions (additionally:internal_org_role_mgt_permissions_update,internal_org_role_mgt_users_update,internal_org_role_mgt_groups_update).Please confirm this difference is intentional based on the distinct use cases of these two configuration files (organization-app vs management-app contexts).
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (3)
285-287: Null config fallback returns a non-organization application.When
applicationConfigis null, this method returnsgetBasicOAuthApplication(CALLBACK_URL)which creates a regular application, not an organization-scoped one. This may be unexpected since the method name suggests organization-specific behavior.Consider either:
- Creating an organization-scoped basic application when config is null
- Throwing an exception if config is null for organization applications
- Documenting this behavior in the Javadoc
432-443: LGTM!The new
addOrganizationRolemethod follows the established pattern of the existingaddRolemethod, cleanly delegating to the organization-scoped REST client method.
486-499: LGTM!The new
getOIDCInboundDetailsOfOrganizationApplicationmethod cleanly mirrors the existinggetOIDCInboundDetailsOfApplicationmethod for organization-scoped operations.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (1)
115-163: LGTM - Well-structured test setup.The setup method properly initializes HTTP clients with cookie handling, creates necessary REST clients, and establishes the organization hierarchy required for testing. The disabled redirect strategy is appropriate for OAuth flow testing where manual redirect handling is needed.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (4)
170-192: LGTM - Consistent with existing pattern.The
createOrganizationApplicationmethod follows the same pattern ascreateApplication, appropriately using Bearer token authentication for organization-scoped operations.
279-299: LGTM - Follows existing pattern correctly.The
getOrganizationApplicationmethod correctly implements organization-scoped application retrieval using Bearer token authentication, consistent with the existinggetApplicationmethod pattern.
490-504: LGTM - Proper delegation to private helper.The
getOIDCInboundDetailsOfOrganizationAppmethod correctly delegates togetConfigOrOrganizationAppand deserializes the response, following the same pattern asgetOIDCInboundDetails.
891-898: LGTM - Consistent path construction.The
getOrganizationSCIM2RoleV2Pathmethod follows the established pattern for constructing organization-scoped paths, correctly handling both super tenant and regular tenant domains.
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
| assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK, | ||
| String.format("Authorized APIs update failed for application with ID: %s for API: %s.", | ||
| appAuthorizedAPIsResponse, apiName)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error message logs response object instead of response body.
The error message includes appAuthorizedAPIsResponse (the response object) instead of the actual response body, which won't provide useful debugging information.
- assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK,
- String.format("Authorized APIs update failed for application with ID: %s for API: %s.",
- appAuthorizedAPIsResponse, apiName));
+ assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK,
+ String.format("Authorized APIs update failed for application with ID: %s for API: %s.",
+ appId, apiName));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK, | |
| String.format("Authorized APIs update failed for application with ID: %s for API: %s.", | |
| appAuthorizedAPIsResponse, apiName)); | |
| assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK, | |
| String.format("Authorized APIs update failed for application with ID: %s for API: %s.", | |
| appId, apiName)); |
🤖 Prompt for AI Agents
In
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
around lines 413-415, the assertion error message logs the response object
(appAuthorizedAPIsResponse) instead of the response body; update the assertion
to extract the response body string (the HTTP entity/content) from
appAuthorizedAPIsResponse and include that body in the formatted error message
so failures show the actual server response content rather than the response
object reference.
...s-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive integration tests for OAuth2 authorization code grant flows in sub-organization contexts. The tests cover the complete workflow including organization management, application provisioning, user management, role assignment, and token exchange operations.
Key Changes
- Added new integration test case
OAuth2AuthorizationCodeGrantForSubOrgAppsTestCaseto verify OAuth2 authorization code grant for sub-organization applications - Introduced organization-scoped operations in REST clients (OAuth2RestClient, SCIM2RestClient, OrgMgtRestClient) to support token-based authentication for organization-level operations
- Added
OAUTH2_GRANT_TYPE_ORGANIZATION_SWITCHconstant to support organization switching grant type - Added JSON configuration files defining authorized APIs for management and organization applications
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java | New comprehensive integration test covering authorization code flow for sub-organization apps, including organization creation, app provisioning, user management, and API authorization |
| OAuth2Constant.java | Added constant for organization_switch grant type |
| SCIM2RestClient.java | Added updateOrganizationUserRole method to support role updates with token authentication |
| OrgMgtRestClient.java | Added token-based methods addOrganizationWithToken and deleteOrganizationWithToken for organization management |
| OAuth2RestClient.java | Added organization-specific methods for application, role, and OIDC configuration management with token authentication |
| OAuth2ServiceAbstractIntegrationTest.java | Added helper methods addOrganizationApplication, addOrganizationRole, and getOIDCInboundDetailsOfOrganizationApplication for organization-level operations |
| organization-app-authorized-apis.json | Configuration file defining authorized API scopes for organization applications |
| management-app-authorized-apis.json | Configuration file defining authorized API scopes for management applications |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
| } | ||
|
|
||
| private String getConfigOrOrganizationApp(String appId, String inboundType, |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method name getConfigOrOrganizationApp contains a typo. It should be getConfigOfOrganizationApp (using "Of" instead of "Or"). The current name suggests "or" as in a boolean operator rather than "of" which correctly expresses possession/relationship.
| * Get Application oidc inbound configuration details with a given application id of an organization. | ||
| * | ||
| * @param appId Application ID. | ||
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations or an application. |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JavaDoc contains a typo. "configurations or an application" should be "configurations of an application". The word "or" should be "of".
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations or an application. | |
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations of an application. |
| oidcConfig.refreshToken(refreshTokenConfiguration); | ||
| } | ||
|
|
||
| if (applicationConfig.getAudienceList() != null && !applicationConfig.getRequestedClaimList().isEmpty()) { |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition on line 313 checks !applicationConfig.getRequestedClaimList().isEmpty() but this is inconsistent with the logic. The audience list should be added to the ID token configuration when the audience list is not null, regardless of whether the requested claim list is empty. The condition should check !applicationConfig.getAudienceList().isEmpty() instead, or simply set the audience if the list is not null.
| if (applicationConfig.getAudienceList() != null && !applicationConfig.getRequestedClaimList().isEmpty()) { | |
| if (applicationConfig.getAudienceList() != null && !applicationConfig.getAudienceList().isEmpty()) { |
| * Create a v2 role in the organization. | ||
| * | ||
| * @param role an instance of RoleV2. | ||
| * @param accessToken Authorized token to create v2 roles in an organization. | ||
| * @return the roleID. |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] JavaDoc inconsistency: The documentation style is inconsistent. This method uses lowercase "v2" while other similar methods use "V2" (uppercase). For consistency with the existing createV2Roles method (line 195), this should say "Create a V2 role in the organization." The return value documentation should also say "the role ID" (with space) to match the pattern in line 198.
| * Create a v2 role in the organization. | |
| * | |
| * @param role an instance of RoleV2. | |
| * @param accessToken Authorized token to create v2 roles in an organization. | |
| * @return the roleID. | |
| * Create a V2 role in the organization. | |
| * | |
| * @param role an instance of RoleV2. | |
| * @param accessToken Authorized token to create V2 roles in an organization. | |
| * @return the role ID. |
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
| String switchedAccessToken) | ||
| throws Exception { | ||
|
|
||
| return restClient.getOIDCInboundDetailsOfOrganizationApp(appId, switchedAccessToken); |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double space detected: There are two spaces between appId, and switchedAccessToken in the method call. This should be a single space for consistency with coding standards.
| return restClient.getOIDCInboundDetailsOfOrganizationApp(appId, switchedAccessToken); | |
| return restClient.getOIDCInboundDetailsOfOrganizationApp(appId, switchedAccessToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No two spaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE | ||
| + switchedM2MToken); |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Extra space after the token in the Authorization header construction. The code currently has two spaces between "BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE" and "switchedM2MToken", but only one is needed.
| headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE | |
| + switchedM2MToken); | |
| headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE.trim() | |
| + " " + switchedM2MToken.trim()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here [1] is having only one space
[1]
Line 51 in a820658
| public static final String BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE = "Bearer "; |
| * Get Application oidc inbound configuration details with a given application id of an organization. | ||
| * | ||
| * @param appId Application ID. | ||
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations or an application. |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in the comment: 'or' should be 'of'. The comment reads "Authorized token to get the OIDC inbound configurations or an application" but should be "Authorized token to get the OIDC inbound configurations of an application".
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations or an application. | |
| * @param switchedAccessToken Authorized token to get the OIDC inbound configurations of an application. |
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
666cb80 to
c176ccd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (8)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (4)
288-317: Avoid shadowingscim2RestClientfield and ensure the org-scoped client is closedInside
testInvokeUserMgtAPIsFromOrganizationAppTokenyou declare:SCIM2RestClient scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo);This shadows the class field
scim2RestClientand is never closed, which:
- Makes the code harder to read (two different
scim2RestClients in the same class).- Leaks the underlying HTTP client for the org-scoped instance.
Consider renaming and closing it:
- // Creating the URLs with the tenant details provided. - SCIM2RestClient scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo); + // Creating the URLs with the tenant details provided. + SCIM2RestClient orgScim2RestClient = new SCIM2RestClient(serverURL, tenantInfo); @@ - String subOrgUserId = scim2RestClient.createSubOrgUser(endUser, orgAppAccessToken); + String subOrgUserId = orgScim2RestClient.createSubOrgUser(endUser, orgAppAccessToken); @@ - org.json.simple.JSONObject subOrgUserObject = scim2RestClient.getSubOrgUser(subOrgUserId, null, - orgAppAccessToken); + org.json.simple.JSONObject subOrgUserObject = orgScim2RestClient.getSubOrgUser(subOrgUserId, null, + orgAppAccessToken); @@ - assertTrue(subOrgUserObject.get("emails").toString().contains(TEST_ORG_END_USER_EMAIL), "Expected " + - "user emails are not present in the response."); + assertTrue(subOrgUserObject.get("emails").toString().contains(TEST_ORG_END_USER_EMAIL), "Expected " + + "user emails are not present in the response."); + orgScim2RestClient.closeHttpClient();(Or use a try/finally if you want to be defensive against assertion failures.)
1-1: Add standard license header to the new test classThis new test class is missing the usual WSO2 Apache 2.0 license header that appears in other test classes in this package. Please add the standard header for consistency and compliance.
165-172: Harden teardown: close all clients and guard against partial initialization
atEnd()currently:
- Deletes the organization but does not close
orgMgtRestClient.- Assumes all fields (
organizationId,accessToken, clients) are non-null and will succeed; an exception in one operation will skip the rest.Suggested refactor:
- Close
orgMgtRestClientas well.- Wrap each cleanup step in its own try-catch with null checks so one failure doesn’t prevent others.
@AfterClass(alwaysRun = true) public void atEnd() throws Exception { - orgMgtRestClient.deleteOrganizationWithToken(organizationId, accessToken); - restClient.closeHttpClient(); - scim2RestClient.closeHttpClient(); - client.close(); + try { + if (organizationId != null && accessToken != null && orgMgtRestClient != null) { + orgMgtRestClient.deleteOrganizationWithToken(organizationId, accessToken); + } + } catch (Exception e) { + // Log if you have a logger; keep going with other cleanups. + } + try { + if (orgMgtRestClient != null) { + orgMgtRestClient.closeHttpClient(); + } + } catch (Exception ignored) { } + try { + if (restClient != null) { + restClient.closeHttpClient(); + } + } catch (Exception ignored) { } + try { + if (scim2RestClient != null) { + scim2RestClient.closeHttpClient(); + } + } catch (Exception ignored) { } + try { + if (client != null) { + client.close(); + } + } catch (Exception ignored) { } }
384-418: Make authorized-API updates more robust and fix assertion messageIn
updateAuthorizedAPIs:
- Assumes at least one API resource exists
If the filter doesn’t match any API resource, this line will throw:
apiUUID = apiResourceResponseBody.getJSONArray(API_RESOURCES).getJSONObject(0).getString(ID);Consider asserting that the array is non-empty so failures are explicit:
- JSONObject apiResourceResponseBody = - new JSONObject(EntityUtils.toString(apiResourceResponse.getEntity())); - apiUUID = apiResourceResponseBody.getJSONArray(API_RESOURCES).getJSONObject(0).getString(ID); + JSONObject apiResourceResponseBody = + new JSONObject(EntityUtils.toString(apiResourceResponse.getEntity())); + if (apiResourceResponseBody.getJSONArray(API_RESOURCES).isEmpty()) { + throw new AssertionError("No API resource found for identifier: " + apiName); + } + apiUUID = apiResourceResponseBody.getJSONArray(API_RESOURCES).getJSONObject(0).getString(ID);(Adjust for the exact JSON API; some versions expose
length()instead ofisEmpty().)
- Assertion message logs the response object, not app id
The failure message currently interpolates
appAuthorizedAPIsResponseinstead of the application id:String.format("Authorized APIs update failed for application with ID: %s for API: %s.", appAuthorizedAPIsResponse, apiName)This produces an unhelpful string like
CloseableHttpResponse@.... UseappId(and, optionally, the response body) instead:- assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK, - String.format("Authorized APIs update failed for application with ID: %s for API: %s.", - appAuthorizedAPIsResponse, apiName)); + String responseBody = EntityUtils.toString(appAuthorizedAPIsResponse.getEntity()); + assertEquals(appAuthorizedAPIsResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK, + String.format("Authorized APIs update failed for application with ID: %s for API: %s. " + + "Response body: %s", appId, apiName, responseBody));The same two concerns apply to
updateOrganizationAppAuthorizedAPIs; it would be good to align both helpers.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (2)
272-332: FixapplicationConfignull handling and audience condition inaddOrganizationApplicationTwo issues here:
- Null
applicationConfigpath creates a root app, not an org appWhen
applicationConfigisnull, the method delegates togetBasicOAuthApplication(CALLBACK_URL), which internally creates a root application viaaddApplication(application), ignoring bothapplicationNameandswitchedAccessToken. That contradicts the method contract (“Add an application to an organization”) and will never produce an org-scoped app in that path.If you intend to support a “default config” branch, it should still go through
restClient.createOrganizationApplication(...), for example:- if (applicationConfig == null) { - return getBasicOAuthApplication(CALLBACK_URL); - } + if (applicationConfig == null) { + ApplicationModel defaultApp = new ApplicationModel(); + defaultApp.setName(applicationName); + + OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration(); + oidcConfig.setGrantTypes(Collections.singletonList("authorization_code")); + oidcConfig.setCallbackURLs(Collections.singletonList(CALLBACK_URL)); + + InboundProtocols inboundProtocolsConfig = new InboundProtocols(); + inboundProtocolsConfig.setOidc(oidcConfig); + defaultApp.setInboundProtocolConfiguration(inboundProtocolsConfig); + + String appId = restClient.createOrganizationApplication(defaultApp, switchedAccessToken); + return restClient.getOrganizationApplication(appId, switchedAccessToken); + }(Adjust defaults to whatever is appropriate for your org apps.)
- Audience configuration is gated on requested-claims emptiness
The condition
if (applicationConfig.getAudienceList() != null && !applicationConfig.getRequestedClaimList().isEmpty()) { oidcConfig.idToken(new IdTokenConfiguration().audience(applicationConfig.getAudienceList())); }ties audience configuration to requested claims rather than the actual audience list. If
requestedClaimListis empty butaudienceListis populated, audiences will not be applied.You likely want the same fix that was suggested earlier for the non-org
addApplicationpath—check the audience list itself:- if (applicationConfig.getAudienceList() != null && !applicationConfig.getRequestedClaimList().isEmpty()) { + if (applicationConfig.getAudienceList() != null && !applicationConfig.getAudienceList().isEmpty()) { oidcConfig.idToken(new IdTokenConfiguration().audience(applicationConfig.getAudienceList())); }Consider applying the same audience-condition fix to the existing
addApplication(ApplicationConfig)method for consistency.
486-499: Tidy OIDC org-inbound helper Javadoc and call formattingThe logic of
getOIDCInboundDetailsOfOrganizationApplicationis fine, but there are two small nits:
- Javadoc parameter text: “Authorized token to get the OIDC inbound configurations or an application” should be “of an application”.
- Method call has a double space between
appId,andswitchedAccessToken.Suggested cleanup:
- * @param switchedAccessToken Authorized token to get the OIDC inbound configurations or an application. + * @param switchedAccessToken Authorized token to get the OIDC inbound configurations of an application. @@ - return restClient.getOIDCInboundDetailsOfOrganizationApp(appId, switchedAccessToken); + return restClient.getOIDCInboundDetailsOfOrganizationApp(appId, switchedAccessToken);modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (2)
211-227: Add error handling and Location-header checks increateOrganizationV2Roles
createOrganizationV2Rolesstill assumes success and directly indexes theLocationheader:String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR); return locationElements[locationElements.length - 1];If the role creation fails (4xx/5xx) or the header is missing, this will throw an
ArrayIndexOutOfBoundsExceptionorNullPointerExceptionand obscure the real server error.Align this method with the robustness of
createOrganizationApplicationby validating the response and the header:public String createOrganizationV2Roles(RoleV2 role, String accessToken) throws IOException { String jsonRequest = toJSONString(role); try (CloseableHttpResponse response = getResponseOfHttpPost(organizationRoleV2ApiBasePath, jsonRequest, getHeadersWithBearerToken(accessToken))) { - String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR); - return locationElements[locationElements.length - 1]; + int status = response.getStatusLine().getStatusCode(); + if (status < 200 || status >= 300) { + String responseBody = EntityUtils.toString(response.getEntity()); + throw new IOException("Error occurred while creating the role. Status: " + status + + ", Response: " + responseBody); + } + Header[] locationHeaders = response.getHeaders(LOCATION_HEADER); + if (locationHeaders == null || locationHeaders.length == 0) { + throw new IOException("Location header missing in role creation response"); + } + String[] locationElements = locationHeaders[0].toString().split(PATH_SEPARATOR); + return locationElements[locationElements.length - 1]; } }
490-505: Clarify naming ofgetConfigOrOrganizationAppand reuse patternThe org-scoped OIDC helper:
public OpenIDConnectConfiguration getOIDCInboundDetailsOfOrganizationApp(String appId, String accessToken)delegates to
getConfigOrOrganizationApp, whose name is confusing (“Or” instead of “Of”) and doesn’t convey that it’s org-specific inbound-config retrieval:private String getConfigOrOrganizationApp(String appId, String inboundType, String accessToken)The implementation itself is fine, but for readability and consistency with
getConfig(...)you may want to:
- Rename the helper to something like
getOrgInboundConfigand fix the “Or/Of” typo.- Narrow its responsibility to “org inbound config” (which is how you currently use it) rather than a vague “config or organization app”.
Example:
- private String getConfigOrOrganizationApp(String appId, String inboundType, - String accessToken) throws Exception { + private String getOrgInboundConfig(String appId, String inboundType, String accessToken) throws Exception { @@ - String responseBody = getConfigOrOrganizationApp(appId, OIDC, accessToken); + String responseBody = getOrgInboundConfig(appId, OIDC, accessToken);This keeps the org/non-org variants parallel (
getConfigvsgetOrgInboundConfig) and makes future maintenance easier.
🧹 Nitpick comments (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (1)
264-286: Close the temporaryOAuth2RestClientto avoid leaking HTTP connections
testInvokeApplicationMgtAPIsFromOrganizationAppTokencreates a newOAuth2RestClientinstance but never closes its underlying HTTP client:OAuth2RestClient oAuth2RestClient = new OAuth2RestClient(serverURL, tenantInfo);Over many tests this can accumulate open connections. Since the test method already throws
Exception, you can safely close it in afinallyblock:- OAuth2RestClient oAuth2RestClient = new OAuth2RestClient(serverURL, tenantInfo); - - // Validate application creation - ApplicationModel applicationModel = getOrganizationAppModel(ORGANIZATION_TEST_APP_NAME); - String orgAppId = oAuth2RestClient.createOrganizationApplication(applicationModel, orgAppAccessToken); - ... + OAuth2RestClient oAuth2RestClient = new OAuth2RestClient(serverURL, tenantInfo); + try { + // Validate application creation + ApplicationModel applicationModel = getOrganizationAppModel(ORGANIZATION_TEST_APP_NAME); + String orgAppId = oAuth2RestClient.createOrganizationApplication(applicationModel, orgAppAccessToken); + ... + } finally { + oAuth2RestClient.closeHttpClient(); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java(3 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java(8 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java(2 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java
🧰 Additional context used
🧬 Code graph analysis (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
OAuth2Constant(24-150)
🔇 Additional comments (2)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
522-541: Org-scoped role update helper is consistent with existing patternsThe
updateOrganizationUserRoleimplementation correctly mirrors existing SCIM role update helpers (path, headers, and 200 assertion) and cleanly encapsulates the org-scoped PATCH call. No changes needed.modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml (1)
157-157: New OAuth2 sub-org test is correctly wired into TestNG suiteIncluding
OAuth2AuthorizationCodeGrantForSubOrgAppsTestCasein the default configuration test group is consistent with other OAuth2 tests and preserves existing suite settings.
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
c176ccd to
7f8f3ce
Compare
...s-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
Outdated
Show resolved
Hide resolved
...s-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
Outdated
Show resolved
Hide resolved
...wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
Show resolved
Hide resolved
7f8f3ce to
33f70e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
272-332: Clarify behavior ofaddOrganizationApplicationwhenapplicationConfigis nullThe null-config branch calls
getBasicOAuthApplication(CALLBACK_URL), which creates a root-level application rather than an organization-scoped one, inconsistent with the method’s name and Javadoc. Either forbidnullhere (and fail fast) or introduce an organization-scoped “basic” app path so the helper always returns an org application.Example: make config mandatory
- public ApplicationResponseModel addOrganizationApplication(String applicationName, - ApplicationConfig applicationConfig, - String switchedAccessToken) throws Exception { - - if (applicationConfig == null) { - return getBasicOAuthApplication(CALLBACK_URL); - } + public ApplicationResponseModel addOrganizationApplication(String applicationName, + ApplicationConfig applicationConfig, + String switchedAccessToken) throws Exception { + + if (applicationConfig == null) { + throw new IllegalArgumentException("applicationConfig must not be null for organization applications"); + }modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (1)
525-534: Consider avoiding reliance on the mutableswitchedM2MTokenfield in helpers
getHeadersWithTokenandupdateOrganizationAppAuthorizedAPIsimplicitly depend on the class-levelswitchedM2MToken, which couples these helpers to priorswitchM2MAccessTokencalls. Passing the token in as a parameter (and threading it through) would make these utilities more self-contained and less order-dependent.Illustrative refactor
- private Header[] getHeadersWithToken() { + private Header[] getHeadersWithToken(String token) { @@ - headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE - + switchedM2MToken); + headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BEARER_TOKEN_AUTHORIZATION_ATTRIBUTE + + token); @@ - getHeadersWithToken())) { + getHeadersWithToken(switchedM2MToken))) { @@ - authorizedAPIRequestBody.toString(), getHeadersWithToken())) { + authorizedAPIRequestBody.toString(), getHeadersWithToken(switchedM2MToken))) {Also applies to: 576-599
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java(3 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java(8 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java(2 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json(1 hunks)modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java
- modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json
🧰 Additional context used
🧬 Code graph analysis (2)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
OAuth2Constant(24-150)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (6)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/dataprovider/model/ApplicationConfig.java (1)
ApplicationConfig(23-152)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/common/RESTTestBase.java (1)
RESTTestBase(76-1060)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (1)
OAuth2RestClient(102-1403)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java (1)
OrgMgtRestClient(69-527)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
SCIM2RestClient(44-1106)modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
OAuth2Constant(24-150)
🔇 Additional comments (12)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
522-541: Organization role update helper is consistent with existing SCIM2 patternsThe new
updateOrganizationUserRolecorrectly targets the sub-organization Roles V2 path, uses the provided bearer token, and asserts200 OK, matching the existing role/user update helpers.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java (2)
137-155: Token-based organization creation helper looks correct
addOrganizationWithTokencleanly reusesbuildOrgCreationRequestBodyand the existing root org path while swapping to bearer-token auth, which aligns with the intended M2M/token-based flows.
210-225: Token-based organization deletion helper is aligned with existing delete flow
deleteOrganizationWithTokenmirrorsdeleteOrganizationbut externalizes the token, preserving path, expectations (204 NO_CONTENT), and assertion behavior.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (2)
432-443: Organization role wrapper is a thin, appropriate delegation
addOrganizationRoleis a simple façade overrestClient.createOrganizationV2Roles, keeping test code decoupled from the REST client details.
486-499: Organization OIDC inbound retrieval mirrors existing root-tenant helper
getOIDCInboundDetailsOfOrganizationApplicationuses the same pattern asgetOIDCInboundDetails, delegating to the new org-scoped REST client method and deserializing intoOpenIDConnectConfiguration; the Javadoc and parameterization are consistent.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java (4)
153-201: End-to-end sub-organization setup sequence is coherentThe
@BeforeClassflow (create and share management app, obtain M2M token, create org, switch token, create org app, user, and role) is internally consistent and uses the new org-scoped clients as intended. Teardown also now deletes the organization and closes all clients.
269-301: Access-token acquisition and scope assertions exercise the right behaviorThe auth-code token request for the organization app correctly uses the tenant-qualified token endpoint and basic auth, and the assertions on
internal_org_user_mgt_listandinternal_org_application_mgt_createensure that organization-scoped permissions are actually present in the issued token.
390-422: Organization application creation helper correctly wires org-scoped flows
createOrganizationApplicationbuilds anApplicationConfigwith the expected grant types (CC, RO, auth code), delegates toaddOrganizationApplicationwith the org token, then sets up authorized APIs and reads back OIDC client credentials from the organization context; this matches the intended org-scoped app lifecycle.
424-495: Org and root authorized-API updaters are consistent with existing patternsBoth
updateAuthorizedAPIs(root) andupdateOrganizationAppAuthorizedAPIs(org) correctly resolve API resources by identifier, construct RBAC-based authorized-API payloads, and assert200 OKon update using appropriate headers (basic vs. bearer) and paths (plain vs.o/).modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (3)
121-144: Organization-scoped application creation wiring looks correctThe new
organizationRoleV2ApiBasePathandcreateOrganizationApplicationcorrectly reuse the sub-org application base path with bearer authorization, validate non-2xx responses, and parse the application ID from theLocationheader in the same way as the root-scopedcreateApplication.Also applies to: 170-192
211-231: Org V2 role creation and SCIM2 org-role path helper are aligned
createOrganizationV2RolestargetsorganizationRoleV2ApiBasePath, uses bearer auth, adds basic error reporting for 4xx/5xx, and extracts the ID from theLocationheader. The newgetOrganizationSCIM2RoleV2Pathcomposes the expected/o/scim2/v2/Roles(or tenant-qualified) URL, matching the established org-path pattern.Also applies to: 895-902
283-303: Organization application and OIDC inbound getters mirror root-tenant behavior
getOrganizationApplicationandgetOIDCInboundDetailsOfOrganizationAppreuse the same deserialization approach as their root equivalents, but switch to sub-org application paths and bearer headers.getConfigOfOrganizationAppis a small, focused helper that keeps inbound-config URL construction and HTTP details encapsulated.Also applies to: 494-508, 535-545
| private ApplicationModel getOrganizationAppModel(String applicationName) { | ||
|
|
||
| ApplicationModel application = new ApplicationModel(); | ||
| application.setName(applicationName); | ||
|
|
||
| OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration(); | ||
| oidcConfig.setGrantTypes(Arrays.asList(OAuth2Constant.OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE, | ||
| OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER, | ||
| OAuth2Constant.OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS)); | ||
| oidcConfig.setCallbackURLs(Collections.singletonList(OAuth2Constant.CALLBACK_URL)); | ||
|
|
||
| AccessTokenConfiguration accessTokenConfiguration = new AccessTokenConfiguration(); | ||
| accessTokenConfiguration.type(ApplicationConfig.TokenType.OPAQUE.getTokenTypeProperty()); | ||
| accessTokenConfiguration.applicationAccessTokenExpiryInSeconds(86400L); | ||
| accessTokenConfiguration.userAccessTokenExpiryInSeconds(300L); | ||
|
|
||
| oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02"))); | ||
|
|
||
| InboundProtocols inboundProtocolsConfig = new InboundProtocols(); | ||
| inboundProtocolsConfig.setOidc(oidcConfig); | ||
| application.setInboundProtocolConfiguration(inboundProtocolsConfig); | ||
|
|
||
| application.advancedConfigurations(new AdvancedApplicationConfiguration() | ||
| .skipLoginConsent(true) | ||
| .skipLogoutConsent(true)); | ||
|
|
||
| return application; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Access token configuration in getOrganizationAppModel is built but never applied
getOrganizationAppModel constructs an AccessTokenConfiguration (type and expiry values) but never attaches it to oidcConfig, so those settings are effectively ignored and default server behavior is used instead.
Proposed fix: attach the access token configuration
AccessTokenConfiguration accessTokenConfiguration = new AccessTokenConfiguration();
accessTokenConfiguration.type(ApplicationConfig.TokenType.OPAQUE.getTokenTypeProperty());
accessTokenConfiguration.applicationAccessTokenExpiryInSeconds(86400L);
accessTokenConfiguration.userAccessTokenExpiryInSeconds(300L);
- oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02")));
+ oidcConfig.accessToken(accessTokenConfiguration);
+ oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02")));🤖 Prompt for AI Agents
In
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationCodeGrantForSubOrgAppsTestCase.java
around lines 646 to 673, the AccessTokenConfiguration instance is created but
never attached to the OpenIDConnectConfiguration, so its type and expiry
settings are ignored; fix this by calling the appropriate setter on oidcConfig
to attach the accessTokenConfiguration (for example,
oidcConfig.setAccessToken(accessTokenConfiguration) or
oidcConfig.accessToken(accessTokenConfiguration) depending on the API) before
assigning oidcConfig to inboundProtocolsConfig.
33f70e5 to
cf08079
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java (1)
837-864:AccessTokenConfigurationis built but never attached tooidcConfig.The
AccessTokenConfigurationis created with type and expiry settings but is never applied tooidcConfig, so these settings are ignored and server defaults are used instead.🔎 Proposed fix (from previous review)
AccessTokenConfiguration accessTokenConfiguration = new AccessTokenConfiguration(); accessTokenConfiguration.type(ApplicationConfig.TokenType.OPAQUE.getTokenTypeProperty()); accessTokenConfiguration.applicationAccessTokenExpiryInSeconds(86400L); accessTokenConfiguration.userAccessTokenExpiryInSeconds(300L); + oidcConfig.accessToken(accessTokenConfiguration); oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02")));
🧹 Nitpick comments (4)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java (2)
603-636: Resource leak:RestBaseClientinstance not closed.The
restBaseClientinstance created here is never explicitly closed. While it's used only within this method, the underlying HTTP client may hold connections.🔎 Proposed fix
Consider using try-with-resources or explicitly closing the client. Since
RestBaseClientdoesn't implementAutoCloseable, you could callcloseHttpClient()after use, or refactor to reuse an existing client instance:private void updateAuthorizedAPIs(String appId, JSONObject authorizedAPIs) throws JSONException, IOException { RestBaseClient restBaseClient = new RestBaseClient(); + try { String apiResourceManagementApiBasePath = buildPath(serverURL, tenantInfo.getDomain(), false, API_RESOURCE_MANAGEMENT_PATH); // ... rest of the method + } finally { + restBaseClient.closeHttpClient(); + } }
639-673: Same resource leak concern asupdateAuthorizedAPIs.The
restBaseClientinstance should be closed after use to prevent connection leaks.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (2)
259-279: Consider adding error handling for non-success responses.If the GET request fails (4xx/5xx), the response body may not be valid JSON, causing a confusing
JsonParseException. Adding status validation would provide clearer error messages.🔎 Suggested improvement
public ApplicationResponseModel getOrganizationApplication(String appId, String accessToken) throws IOException { String endPointUrl = subOrgApplicationManagementApiBasePath + PATH_SEPARATOR + appId; try (CloseableHttpResponse response = getResponseOfHttpGet(endPointUrl, getHeadersWithBearerToken(accessToken))) { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode >= 400) { + String responseBody = EntityUtils.toString(response.getEntity()); + throw new RuntimeException("Error getting organization application. Status: " + statusCode + + ", Response: " + responseBody); + } String responseBody = EntityUtils.toString(response.getEntity()); ObjectMapper jsonWriter = new ObjectMapper(new JsonFactory()); return jsonWriter.readValue(responseBody, ApplicationResponseModel.class); } }
511-521: Private helper lacks error handling.Similar to other GET methods, this helper returns the raw response body without validating the HTTP status code. If the request fails, calling code will receive an error response body and JSON parsing may fail with an unclear error.
Since this is a private helper method, the impact is contained, but for consistency with the pattern used in
createOrganizationApplication, consider validating the response status.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.javamodules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.jsonmodules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.jsonmodules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
🚧 Files skipped from review as they are similar to previous changes (6)
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java
- modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
- modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json
🔇 Additional comments (11)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (2)
522-541: LGTM!The method correctly updates an organization role using PATCH with bearer token authentication. It follows the same pattern as other role update methods in this class.
695-715: LGTM!Good implementation with proper error handling. The method correctly validates the 201 status code before accessing the
Locationheader, preventingArrayIndexOutOfBoundsExceptionon failure. The error response body is included in the exception message for debugging.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java (7)
1-17: LGTM - License header is present.The copyright header is correctly included.
177-191: LGTM - Test coverage for both tenant modes.The data provider correctly includes both
SUPER_TENANT_ADMINandTENANT_ADMINmodes, ensuring the test validates flows for both super tenant and tenant organizations.
211-268: Well-structured test initialization.The test initialization properly:
- Creates required REST clients
- Sets up M2M token and organization context
- Creates test resources (API resource, application, user, role)
The test dependency chain is clear.
343-362: Good coverage for JWT token type flow.The test correctly updates the application token type to JWT and validates the configuration change before proceeding with the JWT flow. Clearing sessions before the JWT flow ensures a clean test state.
438-492: Comprehensive JWT token structure validation.The tests validate:
- JWT has three parts (header.payload.signature)
- Standard claims are present (sub, iat, exp, client_id)
- client_id matches the expected application
This provides good coverage for JWT token format verification.
494-530: LGTM - Proper cleanup with null checks.The cleanup methods properly check for null before closing resources and deleting test data. The
AfterSuitecorrectly restores server configuration.
903-915: PUT is the correct HTTP method for this OIDC configuration update endpoint.The WSO2 application management API uses PUT for the
/inbound-protocols/oidcendpoint, as confirmed by the API implementation. The code is correct as written.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (2)
168-190: LGTM - Good error handling for organization application creation.The method correctly validates the 201 status code before accessing the
Locationheader, and includes the response body in the exception for debugging failures.
470-484: LGTM - Properly delegates to helper method.The method correctly delegates to
getConfigOfOrganizationAppand deserializes the response toOpenIDConnectConfiguration.
cf08079 to
1ecfbb9
Compare
1ecfbb9 to
3e57639
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java (2)
841-868: AccessTokenConfiguration in getOrganizationAppModel is built but never appliedYou construct
AccessTokenConfiguration(type + expiry) but never attach it tooidcConfig, so those settings are ignored and server defaults are used. This mirrors a previously flagged pattern in an earlier sub-org OAuth2 test.Consider wiring it like you do elsewhere:
Suggested fix
AccessTokenConfiguration accessTokenConfiguration = new AccessTokenConfiguration(); accessTokenConfiguration.type(ApplicationConfig.TokenType.OPAQUE.getTokenTypeProperty()); accessTokenConfiguration.applicationAccessTokenExpiryInSeconds(86400L); accessTokenConfiguration.userAccessTokenExpiryInSeconds(300L); - oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02"))); + oidcConfig.accessToken(accessTokenConfiguration); + oidcConfig.idToken(new IdTokenConfiguration().audience(Arrays.asList("audience01", "audience02")));
892-920: Use the accessToken parameter consistently instead of the switchedM2MToken field
updateOrganizationApplicationTokenTypeaccepts anaccessTokenparameter and uses it when fetching the current OIDC config, but the subsequent PUT reuses theswitchedM2MTokenfield viagetHeadersWithToken(). This couples the method to external state and makes the parameter slightly misleading.To keep it self-contained and future-proof, consider:
- Using the method parameter for both GET and PUT, or
- Passing the token explicitly into
getHeadersWithToken/a new helper that accepts a token.This mirrors an earlier concern you already fixed in another sub-org OAuth2 test.
🧹 Nitpick comments (6)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
31-31: Use the new org-switch grant constant at call sitesThe new
OAUTH2_GRANT_TYPE_ORGANIZATION_SWITCH = "organization_switch"constant looks correct. Consider replacing hard-coded"organization_switch"usages (e.g., inOrgMgtRestClient.switchM2MTokenandOAuth2AuthorizationForSubOrganizationAppsTestCase.switchM2MAccessToken) with this constant for consistency and easier maintenance.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
695-715: Org-scoped V2 role creation is fine; optionally guard for missing Location headerThe flow (POST to sub-org v2 roles, expect
201, parse role ID fromLocation) is correct and consistent with other clients. For extra robustness, you could defensively check thatresponse.getHeaders(LOCATION_HEADER)is non-empty before indexing[0], and throw a clearer error if the header is missing.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java (2)
137-154: Token-based organization creation mirrors existing flow but lacks status validation
addOrganizationWithTokenreusesbuildOrgCreationRequestBodyand the same URL asaddOrganization, which is good. However, like the original method, it assumes success and immediately indexesLOCATION_HEADER[0]. Consider checking the status code (e.g.,201) and throwing with the response body on failure so tests get a clear error instead of anArrayIndexOutOfBoundsExceptionif the call fails.
271-296: Prefer using the org-switch grant constant in switchM2MTokenIn
switchM2MToken, the grant type is still passed as the literal"organization_switch". Now thatOAuth2Constant.OAUTH2_GRANT_TYPE_ORGANIZATION_SWITCHexists, consider using it instead:Suggested change
- urlParameters.add(new BasicNameValuePair(OAuth2Constant.GRANT_TYPE_NAME, "organization_switch")); + urlParameters.add(new BasicNameValuePair( + OAuth2Constant.GRANT_TYPE_NAME, + OAuth2Constant.OAUTH2_GRANT_TYPE_ORGANIZATION_SWITCH));modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
272-332: Org-scoped application creation mirrors the non-org path correctly
addOrganizationApplication(...)essentially clones theaddApplication(ApplicationConfig)logic but:
- Uses the provided
applicationNameinstead of a fixed name.- Delegates to
restClient.createOrganizationApplicationandgetOrganizationApplicationwith the org token.This is the right abstraction for org apps. One minor point: the
applicationConfig == nullbranch callsgetBasicOAuthApplication(CALLBACK_URL), which creates a non-org app; if you ever rely on that branch, you may want an org-specific basic helper instead.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (1)
259-279: Org-scoped getApplication helper is fine; consider asserting success status
getOrganizationApplicationis the org variant ofgetApplication, using the sub-org base path and bearer headers, then mapping the JSON intoApplicationResponseModel. That’s correct.Optionally, you could assert an expected 2xx status before parsing to make failures more obvious during test debugging.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.javamodules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.javamodules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.jsonmodules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.jsonmodules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
🚧 Files skipped from review as they are similar to previous changes (2)
- modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml
- modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/organization-app-authorized-apis.json
🧰 Additional context used
🧬 Code graph analysis (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/OAuth2Constant.java (1)
OAuth2Constant(24-150)
🔇 Additional comments (9)
modules/integration/tests-integration/tests-backend/src/test/resources/org/wso2/identity/integration/test/oauth2/management-app-authorized-apis.json (1)
1-35: Authorized-APIs mapping looks consistent with org endpointsThe endpoint-to-permission mappings align with the org-scoped APIs used in the tests and with the internal_org_* permissions referenced elsewhere. No issues from a test/resources perspective.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.java (1)
522-541: Org-scoped role PATCH helper is consistent with existing patterns
updateOrganizationUserRolecorrectly:
- Uses the sub-org v2 roles path.
- Sends the bearer token via
getHeadersWithBearerToken.- Asserts
SC_OKon success.This mirrors the existing user/role update helpers and looks sound.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OrgMgtRestClient.java (1)
210-224: Explicit-token delete helper is consistent with existing deleteOrganization
deleteOrganizationWithTokencleanly mirrorsdeleteOrganization, differing only in how the token is obtained. The assertion onSC_NO_CONTENTis appropriate; no functional issues here.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java (3)
181-195: Data provider + factory setup correctly exercises both super-tenant and tenant modesUsing
@DataProvider+@Factoryto run the same flow forSUPER_TENANT_ADMINandTENANT_ADMINwith distinct org handles (sub001,sub002) is a good pattern and aligns with earlier review feedback to cover both modes.
536-565: Management app bootstrap flow is solid and reuses existing abstractions
addAndShareApp()cleanly composesApplicationConfig, creates the management app viaaddApplication, wires authorized APIs frommanagement-app-authorized-apis.json, fetches OIDC inbound details, and shares the app. This nicely encapsulates the management-app setup used later in the tests.
368-397: JWT/OPAQUE token-cycle coverage and introspection assertions are thoroughThe second half of the test suite (updating token type to JWT, re-running the auth code flow, validating JWT structure and introspection fields, and comparing token characteristics) provides strong coverage for both opaque and JWT tokens on sub-org apps, including the introspection behavior difference. This is valuable regression coverage for the new org-scoped flows.
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java (1)
473-486: Org-specific OIDC inbound retrieval helper is straightforward and consistent
getOIDCInboundDetailsOfOrganizationApplicationis a thin, clear delegate torestClient.getOIDCInboundDetailsOfOrganizationApp, and the Javadoc correctly documents the token parameter as the auth mechanism. No issues here.modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java (2)
168-190: Org-scoped application creation reuses existing patterns and handles errors well
createOrganizationApplication:
- Serializes the
ApplicationModelas JSON.- POSTs to the sub-org applications base path with a bearer token.
- Treats only
201as success and surfaces the error body otherwise.This is a good, explicit pattern for test clients.
470-485: Org-scoped OIDC config retrieval correctly mirrors the root-tenant helper
getOIDCInboundDetailsOfOrganizationApp+getConfigOfOrganizationAppare the org-scoped counterparts togetOIDCInboundDetails/getConfig. They use the same URL shape with the sub-org applications base path and bearer token. Implementation looks correct and consistent.
| private OAuth2RestClient createOAuth2RestClientForOrganization() throws IOException { | ||
|
|
||
| Tenant tenantInfo = new Tenant(); | ||
| tenantInfo.setDomain(ORGANIZATION_HANDLE); | ||
| User user = new User(); | ||
| user.setUserName("testadmin@" + ORGANIZATION_HANDLE); | ||
| tenantInfo.setContextUser(user); | ||
|
|
||
| return new OAuth2RestClient(serverURL, tenantInfo); | ||
| } | ||
|
|
||
| /** | ||
| * Creates SCIM2RestClient for organization. | ||
| */ | ||
| private SCIM2RestClient createSCIM2RestClientForOrganization() throws IOException { | ||
|
|
||
| Tenant tenantInfo = new Tenant(); | ||
| tenantInfo.setDomain(ORGANIZATION_HANDLE); | ||
| User user = new User(); | ||
| user.setUserName("testadmin@" + ORGANIZATION_HANDLE); | ||
| tenantInfo.setContextUser(user); | ||
|
|
||
| return new SCIM2RestClient(serverURL, tenantInfo); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "OAuth2RestClient.java" | head -5Repository: wso2/product-is
Length of output: 195
🏁 Script executed:
find . -type f -name "SCIM2RestClient.java" | head -5Repository: wso2/product-is
Length of output: 194
🏁 Script executed:
find . -type f -name "User.java" | head -10Repository: wso2/product-is
Length of output: 195
🏁 Script executed:
find . -type f -name "Tenant.java" | head -5Repository: wso2/product-is
Length of output: 197
🏁 Script executed:
cat -n ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.javaRepository: wso2/product-is
Length of output: 50371
🏁 Script executed:
cat -n ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.javaRepository: wso2/product-is
Length of output: 50371
🏁 Script executed:
cat -n ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/serviceextensions/model/User.javaRepository: wso2/product-is
Length of output: 4352
🏁 Script executed:
cat -n ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/serviceextensions/model/Tenant.javaRepository: wso2/product-is
Length of output: 2271
🏁 Script executed:
find . -type f -path "*/carbon/automation/engine/context/beans/User.java"Repository: wso2/product-is
Length of output: 41
🏁 Script executed:
find . -type f -path "*/carbon/automation/engine/context/beans/Tenant.java"Repository: wso2/product-is
Length of output: 41
🏁 Script executed:
cat -n ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java | sed -n '1050,1090p'Repository: wso2/product-is
Length of output: 1804
🏁 Script executed:
rg "createOAuth2RestClientForOrganization\|createSCIM2RestClientForOrganization" --max-count=20Repository: wso2/product-is
Length of output: 41
🏁 Script executed:
grep -r "new OAuth2RestClient\|new SCIM2RestClient" --include="*.java" | head -20Repository: wso2/product-is
Length of output: 4717
🏁 Script executed:
sed -n '833,841p' ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.javaRepository: wso2/product-is
Length of output: 486
🏁 Script executed:
sed -n '843,851p' ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.javaRepository: wso2/product-is
Length of output: 471
🏁 Script executed:
sed -n '1050,1100p' ./modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/SCIM2RestClient.javaRepository: wso2/product-is
Length of output: 1929
Set userDomain explicitly in REST client initialization for organization-specific tests
Both createOAuth2RestClientForOrganization and createSCIM2RestClientForOrganization set only the user name without populating userDomain. Since the REST client constructors derive tenant domain from getContextUser().getUserDomain() and immediately use it in .equals() comparisons within path builders, a null userDomain will cause NPE.
Add explicit user.setUserDomain(ORGANIZATION_HANDLE) calls:
Tenant tenantInfo = new Tenant();
tenantInfo.setDomain(ORGANIZATION_HANDLE);
User user = new User();
user.setUserName("testadmin@" + ORGANIZATION_HANDLE);
user.setUserDomain(ORGANIZATION_HANDLE);
tenantInfo.setContextUser(user);🤖 Prompt for AI Agents
In
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2AuthorizationForSubOrganizationAppsTestCase.java
around lines 1059 to 1082, both createOAuth2RestClientForOrganization and
createSCIM2RestClientForOrganization set only the userName on the User object
which leaves userDomain null and causes an NPE when the REST client reads
getContextUser().getUserDomain(); fix by setting the userDomain explicitly to
ORGANIZATION_HANDLE on the User object before calling
tenantInfo.setContextUser(user) (i.e., call
user.setUserDomain(ORGANIZATION_HANDLE) in both methods).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In these test cases the ORGANIZATION_HANDLE cannot be null in any cases. In the constructor, we are sending values for ORGANIZATION_HANDLE for each data set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how OAuth2RestClient and SCIM2RestClient use tenantInfo and getUserDomain()
echo "=== OAuth2RestClient constructor usage of getUserDomain() ==="
rg -A 20 "public OAuth2RestClient\(" --type java | head -50
echo ""
echo "=== SCIM2RestClient constructor usage of getUserDomain() ==="
rg -A 20 "public SCIM2RestClient\(" --type java | head -50
echo ""
echo "=== Check other test files for User object initialization patterns ==="
rg "new User\(\)" --type java -A 5 -B 2 | grep -E "(setUserName|setUserDomain|setContextUser)" | head -40
Length of output: 11435
🏁 Script executed:
#!/bin/bash
# Check what the path builder methods do with tenantDomain parameter
echo "=== OAuth2RestClient path builder methods ==="
rg "getApplicationsPath|getSubOrgApplicationsPath|getAPIResourcesPath" --type java -A 10 modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java | head -80
echo ""
echo "=== Check if any test sets userDomain explicitly ==="
rg "setUserDomain" --type java | head -20
Length of output: 2177
@ShanChathusanda93, you're absolutely right that ORGANIZATION_HANDLE cannot be null—it's passed through the constructor and used throughout the test. However, the issue flagged by CodeRabbit is about a different field.
The problem is that in both createOAuth2RestClientForOrganization() and createSCIM2RestClientForOrganization() (lines 1059-1082), you create a new User object and call:
User user = new User();
user.setUserName("testadmin@" + ORGANIZATION_HANDLE);But you never call user.setUserDomain(...), which means the userDomain field remains null.
When you pass this to the REST client constructors, here's what happens:
OAuth2RestClient constructor:
String tenantDomain = tenantInfo.getContextUser().getUserDomain(); // Returns null
applicationManagementApiBasePath = getApplicationsPath(backendUrl, tenantDomain);SCIM2RestClient constructor:
this.tenantDomain = tenantInfo.getContextUser().getUserDomain(); // Returns nullThe path builders then call:
if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) { // NPE here!This will throw a NullPointerException because you're calling .equals() on a null reference.
The fix is simple—set the userDomain field explicitly:
User user = new User();
user.setUserName("testadmin@" + ORGANIZATION_HANDLE);
user.setUserDomain(ORGANIZATION_HANDLE); // Add this line
tenantInfo.setContextUser(user);This ensures that getUserDomain() returns the organization handle instead of null, and the REST clients can properly construct their paths.
Changes in this PR
Summary by CodeRabbit
Tests
New Features
Documentation / Resources
✏️ Tip: You can customize this high-level summary in your review settings.