Skip to content

Conversation

@LinukaAr
Copy link
Member

@LinukaAr LinukaAr commented Jan 16, 2026

$subject

Screenshot 2026-01-16 at 14 36 25

Summary by CodeRabbit

  • Tests
    • Added comprehensive integration tests for TOTP enrollment configuration management across organizational hierarchies
    • Tests validate global enrollment governance, inheritance behavior in sub-organizations, and conditional authentication interactions in multi-tenant environments

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

Walkthrough

A comprehensive integration test class is added to validate TOTP enrollment configuration, governance toggles, and inheritance behavior across multi-tenant organizations. The test covers Service Provider setup, adaptive authentication scripts, org-level enrollment settings, and inheritance scenarios in sub-organizations.

Changes

Cohort / File(s) Summary
TOTP Organization Configuration Tests
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java
New integration test class with 775 lines covering: test SP creation with SAML and adaptive auth config; TOTP enrollment enable/disable via governance API; script override scenarios across org-level and conditional auth states; sub-organization inheritance validation; helper methods for SP updates, org management, app sharing, and login simulation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A test so grand, with TOTP's embrace,
Organizations dancing through multi-tenant space,
Enrollment flows and governance threads,
Sub-orgs inherit what the parent spreads,
Adaptive scripts conducting the show so bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Totp org config intergration tests' is directly related to the changeset, which adds a comprehensive integration test class for TOTP organization-level configuration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java`:
- Around line 735-743: The code calls Utils.sendPOSTMessage with sessionDataKey
returned from extractSessionDataKey without verifying it's non-null; add a guard
after calling extractSessionDataKey in TOTPOrgConfigurationTestCase to check if
sessionDataKey is null or empty and throw an informative exception (or fail the
test) before calling Utils.sendPOSTMessage; reference extractSessionDataKey, the
local variable sessionDataKey, and Utils.sendPOSTMessage so the null-check is
added in the block that currently prepares and posts credentials.
- Around line 650-689: The current code silently falls back to
getParentTOTPConfiguration() when the sub-org HTTP call fails or the property is
missing; instead, in the method that queries the sub-org TOTP config (the code
that builds the HttpGet, executes httpClient.execute(request) and inspects
response/responseString), change the control flow so that any non-200 response
or absence of the TOTP_ENROLL_CONFIG property causes the test to fail (throw an
AssertionError or use the test framework's fail/skip) rather than returning
getParentTOTPConfiguration(); specifically, after HttpResponse response =
httpClient.execute(request) check response.getStatusLine().getStatusCode() and
if it is not HttpStatus.SC_OK call fail with a clear message including the
status and responseString, and if connectors/properties are present but no prop
with name TOTP_ENROLL_CONFIG is found also fail with a clear message instead of
falling back to getParentTOTPConfiguration().
🧹 Nitpick comments (1)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java (1)

320-321: Use unique sub-org names to avoid collisions across runs.

If tests run in parallel or the environment is reused, fixed names can clash. Consider suffixing with a UUID.

♻️ Suggested change
+import java.util.UUID;
@@
-        String subOrgName = "sub-org-totp-test";
+        String subOrgName = "sub-org-totp-test-" + UUID.randomUUID();
@@
-        String subOrgName = "sub-org-totp-test-disabled";
+        String subOrgName = "sub-org-totp-test-disabled-" + UUID.randomUUID();

Also applies to: 362-363

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f626e9 and ab8708c.

📒 Files selected for processing (1)
  • modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java
🔇 Additional comments (5)
modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java (5)

64-107: Concise constants and script builder.

Clear constants plus centralized script generation make the scenarios easy to read and adjust.


147-313: Good coverage of org-level toggles and script overrides.

The scenarios cover the key permutations cleanly.


398-449: Sub-org update helper is well-contained.

Nice to have this encapsulated for future coverage expansion.


451-559: Setup/teardown helpers keep the test flow clean.

Creation/update/delete steps are explicit and easy to follow.


561-633: Org CRUD & sharing helpers look solid.

Encapsulation makes the sub-org tests easier to read.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +650 to +689
String url = backendURL.replace("services/", "") + "o/" + subOrgId +
"/api/server/v1/identity-governance/TOTP";

org.apache.http.client.methods.HttpGet request = new org.apache.http.client.methods.HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8)));
request.addHeader(HttpHeaders.ACCEPT, "application/json");

HttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity());

if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
JSONObject responseJson = new JSONObject(responseString);
JSONArray connectors = responseJson.optJSONArray("connectors");
if (connectors != null) {
for (int i = 0; i < connectors.length(); i++) {
JSONObject connector = connectors.getJSONObject(i);
JSONArray properties = connector.optJSONArray("properties");
if (properties != null) {
for (int j = 0; j < properties.length(); j++) {
JSONObject prop = properties.getJSONObject(j);
if (TOTP_ENROLL_CONFIG.equals(prop.optString("name"))) {
return prop.optString("value", "true");
}
}
}
}
}
}

// If we can't get the sub-org specific config, fall back to checking parent
// config
// This validates inheritance behavior - sub-org should use parent's
// configuration
log.info("Sub-org governance API returned status: " + response.getStatusLine().getStatusCode() +
". Validating inheritance by confirming parent configuration is effective.");

// Return the parent org configuration as sub-orgs inherit from parent
return getParentTOTPConfiguration();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t silently fall back to parent config when sub-org API fails.

Returning the parent value on non-200 responses can mask sub-org API failures and yield false positives. Fail the test (or explicitly skip) when the sub-org endpoint can’t be validated or the property isn’t present.

🐛 Suggested change
-        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
-            JSONObject responseJson = new JSONObject(responseString);
-            JSONArray connectors = responseJson.optJSONArray("connectors");
-            if (connectors != null) {
-                for (int i = 0; i < connectors.length(); i++) {
-                    JSONObject connector = connectors.getJSONObject(i);
-                    JSONArray properties = connector.optJSONArray("properties");
-                    if (properties != null) {
-                        for (int j = 0; j < properties.length(); j++) {
-                            JSONObject prop = properties.getJSONObject(j);
-                            if (TOTP_ENROLL_CONFIG.equals(prop.optString("name"))) {
-                                return prop.optString("value", "true");
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // If we can't get the sub-org specific config, fall back to checking parent
-        // config
-        // This validates inheritance behavior - sub-org should use parent's
-        // configuration
-        log.info("Sub-org governance API returned status: " + response.getStatusLine().getStatusCode() +
-                ". Validating inheritance by confirming parent configuration is effective.");
-
-        // Return the parent org configuration as sub-orgs inherit from parent
-        return getParentTOTPConfiguration();
+        int status = response.getStatusLine().getStatusCode();
+        if (status != HttpStatus.SC_OK) {
+            Assert.fail("Sub-org governance API call failed. HTTP " + status + " Body: " + responseString);
+        }
+
+        JSONObject responseJson = new JSONObject(responseString);
+        JSONArray connectors = responseJson.optJSONArray("connectors");
+        if (connectors != null) {
+            for (int i = 0; i < connectors.length(); i++) {
+                JSONObject connector = connectors.getJSONObject(i);
+                JSONArray properties = connector.optJSONArray("properties");
+                if (properties != null) {
+                    for (int j = 0; j < properties.length(); j++) {
+                        JSONObject prop = properties.getJSONObject(j);
+                        if (TOTP_ENROLL_CONFIG.equals(prop.optString("name"))) {
+                            return prop.optString("value", "true");
+                        }
+                    }
+                }
+            }
+        }
+
+        Assert.fail("TOTP enrollment config not found in sub-org response. Body: " + responseString);
+        return null;
📝 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.

Suggested change
String url = backendURL.replace("services/", "") + "o/" + subOrgId +
"/api/server/v1/identity-governance/TOTP";
org.apache.http.client.methods.HttpGet request = new org.apache.http.client.methods.HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8)));
request.addHeader(HttpHeaders.ACCEPT, "application/json");
HttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity());
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
JSONObject responseJson = new JSONObject(responseString);
JSONArray connectors = responseJson.optJSONArray("connectors");
if (connectors != null) {
for (int i = 0; i < connectors.length(); i++) {
JSONObject connector = connectors.getJSONObject(i);
JSONArray properties = connector.optJSONArray("properties");
if (properties != null) {
for (int j = 0; j < properties.length(); j++) {
JSONObject prop = properties.getJSONObject(j);
if (TOTP_ENROLL_CONFIG.equals(prop.optString("name"))) {
return prop.optString("value", "true");
}
}
}
}
}
}
// If we can't get the sub-org specific config, fall back to checking parent
// config
// This validates inheritance behavior - sub-org should use parent's
// configuration
log.info("Sub-org governance API returned status: " + response.getStatusLine().getStatusCode() +
". Validating inheritance by confirming parent configuration is effective.");
// Return the parent org configuration as sub-orgs inherit from parent
return getParentTOTPConfiguration();
}
String url = backendURL.replace("services/", "") + "o/" + subOrgId +
"/api/server/v1/identity-governance/TOTP";
org.apache.http.client.methods.HttpGet request = new org.apache.http.client.methods.HttpGet(url);
request.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8)));
request.addHeader(HttpHeaders.ACCEPT, "application/json");
HttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity());
int status = response.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
Assert.fail("Sub-org governance API call failed. HTTP " + status + " Body: " + responseString);
}
JSONObject responseJson = new JSONObject(responseString);
JSONArray connectors = responseJson.optJSONArray("connectors");
if (connectors != null) {
for (int i = 0; i < connectors.length(); i++) {
JSONObject connector = connectors.getJSONObject(i);
JSONArray properties = connector.optJSONArray("properties");
if (properties != null) {
for (int j = 0; j < properties.length(); j++) {
JSONObject prop = properties.getJSONObject(j);
if (TOTP_ENROLL_CONFIG.equals(prop.optString("name"))) {
return prop.optString("value", "true");
}
}
}
}
}
Assert.fail("TOTP enrollment config not found in sub-org response. Body: " + responseString);
return null;
🤖 Prompt for AI Agents
In
`@modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java`
around lines 650 - 689, The current code silently falls back to
getParentTOTPConfiguration() when the sub-org HTTP call fails or the property is
missing; instead, in the method that queries the sub-org TOTP config (the code
that builds the HttpGet, executes httpClient.execute(request) and inspects
response/responseString), change the control flow so that any non-200 response
or absence of the TOTP_ENROLL_CONFIG property causes the test to fail (throw an
AssertionError or use the test framework's fail/skip) rather than returning
getParentTOTPConfiguration(); specifically, after HttpResponse response =
httpClient.execute(request) check response.getStatusLine().getStatusCode() and
if it is not HttpStatus.SC_OK call fail with a clear message including the
status and responseString, and if connectors/properties are present but no prop
with name TOTP_ENROLL_CONFIG is found also fail with a clear message instead of
falling back to getParentTOTPConfiguration().

Comment on lines +735 to +743
String sessionDataKey = extractSessionDataKey(response);
// EntityUtils.consume(response.getEntity()); // Handled inside
// extractSessionDataKey

// 2. Post credentials to commonauth
response = Utils.sendPOSTMessage(sessionDataKey, commonAuthUrl, "User-Agent",
commonAuthUrl, SERVICE_PROVIDER_NAME,
USERNAME, PASSWORD, httpClient, samlSsoUrl);
return response;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fail fast if sessionDataKey isn’t extracted.

Without a guard, the POST can go out with null, making failures opaque.

🔧 Suggested change
-        String sessionDataKey = extractSessionDataKey(response);
+        String sessionDataKey = extractSessionDataKey(response);
+        Assert.assertNotNull(sessionDataKey, "sessionDataKey not found in login response");
📝 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.

Suggested change
String sessionDataKey = extractSessionDataKey(response);
// EntityUtils.consume(response.getEntity()); // Handled inside
// extractSessionDataKey
// 2. Post credentials to commonauth
response = Utils.sendPOSTMessage(sessionDataKey, commonAuthUrl, "User-Agent",
commonAuthUrl, SERVICE_PROVIDER_NAME,
USERNAME, PASSWORD, httpClient, samlSsoUrl);
return response;
String sessionDataKey = extractSessionDataKey(response);
Assert.assertNotNull(sessionDataKey, "sessionDataKey not found in login response");
// EntityUtils.consume(response.getEntity()); // Handled inside
// extractSessionDataKey
// 2. Post credentials to commonauth
response = Utils.sendPOSTMessage(sessionDataKey, commonAuthUrl, "User-Agent",
commonAuthUrl, SERVICE_PROVIDER_NAME,
USERNAME, PASSWORD, httpClient, samlSsoUrl);
return response;
🤖 Prompt for AI Agents
In
`@modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/totp/TOTPOrgConfigurationTestCase.java`
around lines 735 - 743, The code calls Utils.sendPOSTMessage with sessionDataKey
returned from extractSessionDataKey without verifying it's non-null; add a guard
after calling extractSessionDataKey in TOTPOrgConfigurationTestCase to check if
sessionDataKey is null or empty and throw an informative exception (or fail the
test) before calling Utils.sendPOSTMessage; reference extractSessionDataKey, the
local variable sessionDataKey, and Utils.sendPOSTMessage so the null-check is
added in the block that currently prepares and posts credentials.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant