Fix wildcard certificate deletion silently breaking unrelated APIs#13868
Fix wildcard certificate deletion silently breaking unrelated APIs#13868Tharsanan1 wants to merge 4 commits into
Conversation
When API-1 uploads a wildcard endpoint cert (e.g. *.am.wso2.com) and API-2 uses a different subdomain of the same wildcard (e.g. idp.am.wso2.com) without explicitly uploading a cert, deleting the cert for API-1 silently breaks API-2 with no warning. The fix adds searchPaginatedAPIsByCertificate which parses X.509 SANs from the certificate (with wildcard-aware matching) and returns all APIs whose endpoint configs match the wildcard domain. The usage endpoint now uses this instead of a plain FQDN match, so the Publisher correctly warns about all dependent APIs before allowing deletion. Fixes: wso2-enterprise/wso2-apim-internal#17072 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds utilities to extract endpoint hostnames from X.509 certificates (SANs/CN), a new APIProvider.searchPaginatedAPIsByCertificate(...) implementation that builds wildcard Solr queries from those terms and returns paginated APISearchResult, updates REST usage to call the new search, and adds unit tests for parsing and query generation. ChangesCertificate-based API search
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
AI Agent Log Improvement Checklist
- The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
- Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.
✅ Before merging this pull request:
- Review all AI-generated comments for accuracy and relevance.
- Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
There was a problem hiding this comment.
Pull request overview
This PR fixes a gap in endpoint-certificate “usage” detection where deleting a wildcard certificate could silently impact APIs using different subdomains under the same wildcard. It does so by deriving search terms from the certificate’s SANs/CN (wildcard-aware) and using those terms to find dependent APIs before deletion.
Changes:
- Added
APIProvider#searchPaginatedAPIsByCertificate(...)and implemented it inAPIProviderImplto search APIs using certificate-derived endpoint terms. - Added
CertificateMgtUtils.getEndpointSearchTermsFromCertificate(...)to extract DNS/IP SANs (with CN fallback). - Updated the Publisher endpoint-certificate usage API to use the new certificate-aware API search, and added/updated unit tests.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/EndpointCertificatesApiServiceImpl.java | Switches certificate usage lookup to certificate-aware search (SAN/CN-driven). |
| components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.java | Adds SAN/CN parsing to derive endpoint search terms for wildcard-aware dependency discovery. |
| components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java | Implements the new search-by-certificate method and constructs a multi-term endpointConfig query. |
| components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.java | Adds the new searchPaginatedAPIsByCertificate interface method. |
| components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtilTest.java | Adds unit coverage for SAN/CN/IP extraction behavior. |
| components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java | Adds unit coverage for query construction and null Solr result handling. |
Comments suppressed due to low confidence (2)
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.java:82
- Import statements are not in lexicographical order within the java/javax import group, which will fail the repository's Checkstyle ImportOrder rule (ordered=true). In particular, javax.security.auth.x500.X500Principal is placed between java.util imports, and java.util.List/Optional appear after it.
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import java.util.List;
import java.util.Optional;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java:185
- Import order is now out-of-order (CertificateMgtUtils is inserted between other org.wso2.carbon.apimgt.impl.utils imports). This will fail Checkstyle ImportOrder with ordered=true; keep imports lexicographically sorted within the group.
import org.wso2.carbon.apimgt.impl.utils.APIAuthenticationAdminClient;
import org.wso2.carbon.apimgt.impl.utils.CertificateMgtUtils;
import org.wso2.carbon.apimgt.impl.utils.APIMWSDLReader;
import org.wso2.carbon.apimgt.impl.utils.APINameComparator;
import org.wso2.carbon.apimgt.impl.utils.APIProductNameComparator;
import org.wso2.carbon.apimgt.impl.utils.APIStoreNameComparator;
import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.apimgt.impl.utils.APIVersionStringComparator;
import org.wso2.carbon.apimgt.impl.utils.LifeCycleUtils;
import org.wso2.carbon.apimgt.impl.utils.MCPUtils;
import org.wso2.carbon.apimgt.impl.utils.SimpleContentSearchResultNameComparator;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java (1)
1903-1909: 💤 Low valueConsider verifying the query format and prefix.
The test correctly verifies that the captured query contains the expected search terms (
.example.com,api1.hello.com,api2.hello.com). However, according to the review stack context, the query should be built withENDPOINT_CONFIG_SEARCH_TYPE_PREFIX. Consider adding an assertion to verify the query format/prefix to catch malformed queries that happen to contain the expected terms.Example assertion to add
String capturedQuery = queryCaptor.getValue(); +Assert.assertTrue("Query must start with endpointConfig: prefix", + capturedQuery.startsWith("endpointConfig:")); Assert.assertTrue("Query must contain .example.com term from wildcard SAN", capturedQuery.contains(".example.com"));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java` around lines 1903 - 1909, The test in APIProviderImplTest captures the query via queryCaptor but only asserts the presence of terms; update the test to also assert the query starts with or contains the expected prefix constant ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX to ensure correct format. Locate where capturedQuery is obtained (queryCaptor.getValue()) and add an assertion using that variable to check the prefix (e.g., startsWith or contains ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX) so malformed queries that still include terms will fail.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java`:
- Around line 6755-6760: APIProviderImpl currently appends certificate-derived
searchTerms directly into the Solr query (in the loop that builds queryBuilder
using ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX), which lets unescaped SAN values
(e.g., IPv6 with colons) break Solr parsing; update the code to escape each term
before concatenating: call or add a Solr-escaping utility (reuse or add a method
such as CertificateMgtUtils.escapeForSolr or use SolrQueryParser.escape) on each
term returned by CertificateMgtUtils.getEndpointSearchTermsFromCertificate()
(including type==7 IP SANs) and then append the escaped value with the wildcard
markers to queryBuilder so special characters are neutralized while preserving
the wildcard behavior.
---
Nitpick comments:
In
`@components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java`:
- Around line 1903-1909: The test in APIProviderImplTest captures the query via
queryCaptor but only asserts the presence of terms; update the test to also
assert the query starts with or contains the expected prefix constant
ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX to ensure correct format. Locate where
capturedQuery is obtained (queryCaptor.getValue()) and add an assertion using
that variable to check the prefix (e.g., startsWith or contains
ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX) so malformed queries that still include
terms will fail.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7fcde643-6e1a-42ee-a931-dec1a72c6a2c
📒 Files selected for processing (6)
components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtilTest.javacomponents/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/EndpointCertificatesApiServiceImpl.java
- Use LdapName (RFC2253) for CN extraction instead of naive split
- Skip IPv6 SAN/host literals since ':' breaks Solr query parsing
- Guard against blank certificate content
- Fix import ordering
- Rename test local variables to camelCase (checkstyle)
- Add @PowerMockIgnore({"javax.security.*","javax.naming.*"}) to avoid
JavassistMockClassLoader LinkageError on X500Principal/LdapName
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Tharsanan seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java (1)
6755-6760:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEscape certificate-derived terms before building the Solr query.
termis appended raw into the query string, so reserved characters from certificate-derived values can break parsing or broaden matching unexpectedly. This remains unresolved from earlier feedback on this same block.💡 Suggested fix
StringBuilder queryBuilder = new StringBuilder(); for (String term : searchTerms) { + if (StringUtils.isBlank(term)) { + continue; + } + String escapedTerm = ClientUtils.escapeQueryChars(term.trim()); if (queryBuilder.length() > 0) { queryBuilder.append(' '); } - queryBuilder.append(ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX).append("*").append(term).append("*"); + queryBuilder.append(ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX) + .append("*") + .append(escapedTerm) + .append("*"); }#!/bin/bash # Verify whether certificate-search query terms are escaped in searchPaginatedAPIsByCertificate. fd -i 'APIProviderImpl.java' | xargs -r rg -n -C4 \ 'searchPaginatedAPIsByCertificate|escapeQueryChars|append\("\*"\)\.append\(term\)'Expected after fix:
escapeQueryChars(...)appears in this method and rawappend(term)is absent from query construction.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java` around lines 6755 - 6760, In searchPaginatedAPIsByCertificate, the loop appends raw certificate-derived term values into the Solr query; call the existing escapeQueryChars(...) on each term before using it and append the escaped value instead of the raw term so reserved Solr characters don’t break parsing. Specifically, replace usage of queryBuilder.append(ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX).append("*").append(term).append("*") with the same sequence but passing escapeQueryChars(term) (or a trimmed/validated result) into append; ensure escapeQueryChars is imported/accessible and add a small null/empty guard for term if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In
`@components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java`:
- Around line 6755-6760: In searchPaginatedAPIsByCertificate, the loop appends
raw certificate-derived term values into the Solr query; call the existing
escapeQueryChars(...) on each term before using it and append the escaped value
instead of the raw term so reserved Solr characters don’t break parsing.
Specifically, replace usage of
queryBuilder.append(ENDPOINT_CONFIG_SEARCH_TYPE_PREFIX).append("*").append(term).append("*")
with the same sequence but passing escapeQueryChars(term) (or a
trimmed/validated result) into append; ensure escapeQueryChars is
imported/accessible and add a small null/empty guard for term if needed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fe074ad9-9ba7-45dc-9482-5b43d0eef729
📒 Files selected for processing (3)
components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.javacomponents/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
- components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/APIProviderImplTest.java
- components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/CertificateMgtUtils.java
Summary
*.am.wso2.com) and API-2 uses a different subdomain of the same wildcard (e.g.idp.am.wso2.com) without explicitly uploading a cert, deleting the cert for API-1 silently breaks API-2 with no warning.searchPaginatedAPIsByCertificatewhich parses X.509 SANs from the certificate (with wildcard-aware matching) and returns all APIs whose endpoint configs match the wildcard domain.GET /endpoint-certificates/{alias}/usage) now uses this instead of a plain FQDN match, so the Publisher correctly warns about all dependent APIs before allowing deletion.Root cause
getCertificateUsageByAliaswas callingsearchPaginatedAPIsByFQDN(endpoint, ...)which only matched APIs with the exact endpoint URL stored against the certificate. APIs on other subdomains of the same wildcard cert were not found.Changes
APIProvider.java— new interface methodsearchPaginatedAPIsByCertificateAPIProviderImpl.java— implementation that extracts SANs from the certificate, converts wildcard SANs (e.g.*.am.wso2.com→.am.wso2.com) to substring search terms, and queries Solr withendpointConfig:prefixCertificateMgtUtils.java— new utility methodgetEndpointSearchTermsFromCertificatethat parses X.509 SANs (DNS + IP) with CN fallbackEndpointCertificatesApiServiceImpl.java— switch usage endpoint to use the new methodAPIProviderImplTest.java/CertificateMgtUtilTest.java— unit testsTest plan
*.am.wso2.com) for API-1 endpoint (api.am.wso2.com)GET /endpoint-certificates/{alias}/usagereturns both API-1 and API-2 (endpoint:idp.am.wso2.com)Fixes: wso2/api-manager#5053
🤖 Generated with Claude Code