Repository navigation
feat: add TransportOptions for configuring TLS, proxy, and default headers #122
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
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
887d007
Add TransportOptions for configuring TLS, proxy, and default headers
mridang 0444f7f
Fix hostname verification for custom CA and address review feedback
mridang d3fcc5c
Merge custom CA with default trust store instead of replacing it
mridang 31bccb0
Fix SSL socket resource leak in transport options test
mridang e7def42
Apply transport options to OAuth token exchange requests
mridang 2f29aef
Fix custom CA cert test and apply transport options to token exchange
mridang c34990c
Standardize transport options tests across SDKs
mridang 2bb9aa1
Add null guard for transportOptions in ApiClient constructor
mridang 55beb47
Add null guards for transportOptions in all public constructors
mridang 1dd95e3
Validate header name and value in TransportOptions builder
mridang 16c7a55
Centralize SSL context building in TransportOptions
mridang 8ee3d24
Verify default headers on API calls via WireMock verification
mridang 728e978
Fix SpotBugs warning and proxy test reliability
mridang 39765d7
Cache SSLContext in TransportOptions to avoid per-request rebuilds
mridang ef23bed
Fix install command from composer to Maven dependency
mridang ee976f4
fix: remove unnecessary SpotBugs suppression from buildSSLContext
mridang 6677286
build: enable unused import removal in Spotless
mridang 604bbd3
build: reorder Spotless steps to remove unused imports before formatting
mridang 06365f3
fix: remove unused imports from ApiClient and OAuthAuthenticator
mridang 6345a39
Add real proxy container to transport options test
mridang 3d9cff2
chore: align docs and remove inline comments
mridang c9f4747
replace tinyproxy with ubuntu/squid:6.10-24.10_beta
mridang 17bc888
catch GeneralSecurityException explicitly instead of broad Exception
mridang 60db143
docs: fix proxy auth docs to use URL credentials instead of default h…
mridang bb84212
fix: replace broad catch(Exception) with specific checked exceptions
mridang fb43253
fix: remove stale SpotBugs filters for moved trust manager and except…
mridang 2f18350
fix: parse JSON instead of fragile string matching in default headers…
mridang e356d03
Add missing @param transportOptions javadoc tags
mridang 5212e15
Standardize @param transportOptions descriptions
mridang 0f8352f
Remove TransportOptions.Builder for consistency with other SDKs
mridang 168b357
Remove inline comments from OAuthAuthenticator
mridang 72a11fa
Standardize cross-references and remove inline comments\n\nAdd @see l…
mridang e59b495
Align defaults() docstring with other SDKs\n\nUse the same summary te…
mridang d192f6b
Move SpotBugs suppressions from XML to code annotations\n\nReplace sp…
mridang f87bb27
Add backwards-compatible 2-param OAuthAuthenticator constructor
mridang 65a8d4f
Standardize WireMock version to 3.12.1
mridang 4d2fb51
Clarify defaultHeaders are sent to the origin server
mridang d4158f9
Fix stale JWTAuthenticator references in Javadoc
mridang 50ceac4
Capitalize @param defaultHeaders description for consistency
mridang acce336
Replace programmatic WireMock stubs with static JSON mapping files
mridang 8ea6f25
Standardize TransportOptions docstrings for cross-SDK consistency
mridang 0f3dea2
Restructure tests: split TransportOptions unit tests from Zitadel int…
mridang 4b6aa66
Harden insecure precedence test with nonexistent CA cert path
mridang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| package com.zitadel; | ||
|
|
||
| import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; | ||
|
|
||
| import javax.annotation.Nullable; | ||
| import javax.net.ssl.SSLContext; | ||
| import javax.net.ssl.TrustManager; | ||
| import javax.net.ssl.TrustManagerFactory; | ||
| import javax.net.ssl.X509TrustManager; | ||
| import java.io.FileInputStream; | ||
| import java.io.IOException; | ||
| import java.security.GeneralSecurityException; | ||
| import java.security.KeyStore; | ||
| import java.security.cert.CertificateFactory; | ||
| import java.security.cert.X509Certificate; | ||
| import java.util.Collections; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Immutable transport options for configuring HTTP connections. | ||
| */ | ||
| public class TransportOptions { | ||
|
|
||
| private final Map<String, String> defaultHeaders; | ||
| @Nullable | ||
| private final String caCertPath; | ||
| private final boolean insecure; | ||
| @Nullable | ||
| private final String proxyUrl; | ||
| @Nullable | ||
| private volatile SSLContext cachedSSLContext; | ||
| private volatile boolean sslContextBuilt; | ||
|
|
||
| /** | ||
| * @param defaultHeaders Default HTTP headers sent to the origin server with every request. | ||
| * @param caCertPath Path to a custom CA certificate file for TLS verification, or {@code null}. | ||
| * @param insecure Whether to disable TLS certificate verification. | ||
| * @param proxyUrl Proxy URL for HTTP connections, or {@code null}. | ||
| */ | ||
| public TransportOptions(Map<String, String> defaultHeaders, @Nullable String caCertPath, boolean insecure, @Nullable String proxyUrl) { | ||
| this.defaultHeaders = Collections.unmodifiableMap(new LinkedHashMap<>(defaultHeaders)); | ||
| this.caCertPath = caCertPath; | ||
| this.insecure = insecure; | ||
| this.proxyUrl = proxyUrl; | ||
|
mridang marked this conversation as resolved.
|
||
| } | ||
|
mridang marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Returns a {@code TransportOptions} instance with all default values. | ||
| * | ||
| * @return the default transport options. | ||
| */ | ||
| public static TransportOptions defaults() { | ||
| return new TransportOptions(Collections.emptyMap(), null, false, null); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the default HTTP headers sent to the origin server with every request. | ||
| * | ||
| * @return an unmodifiable map of header names to values. | ||
| */ | ||
| public Map<String, String> getDefaultHeaders() { | ||
| return defaultHeaders; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the path to a custom CA certificate file used for TLS verification. | ||
| * | ||
| * @return the CA cert file path, or {@code null} if not set. | ||
| */ | ||
| @Nullable | ||
| public String getCaCertPath() { | ||
| return caCertPath; | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether insecure (trust-all) TLS mode is enabled. | ||
| * | ||
| * @return {@code true} if insecure mode is enabled; {@code false} otherwise. | ||
| */ | ||
| public boolean isInsecure() { | ||
| return insecure; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the proxy URL used for HTTP connections. | ||
| * | ||
| * @return the proxy URL, or {@code null} if not set. | ||
| */ | ||
| @Nullable | ||
| public String getProxyUrl() { | ||
| return proxyUrl; | ||
| } | ||
|
|
||
| /** | ||
| * Builds an {@link SSLContext} from these transport options. | ||
| * | ||
| * <p>If insecure mode is enabled, returns a trust-all SSLContext. | ||
| * If a custom CA cert path is set, returns an SSLContext that trusts | ||
| * both the custom CA and the system default CAs. | ||
| * Otherwise returns {@code null} (use JVM defaults). | ||
| * | ||
| * @return the configured SSLContext, or {@code null} if no custom SSL is needed. | ||
| * @throws GeneralSecurityException if SSL context creation fails. | ||
| * @throws IOException if the CA cert file cannot be read. | ||
| */ | ||
| @Nullable | ||
| public SSLContext buildSSLContext() throws GeneralSecurityException, IOException { | ||
| if (sslContextBuilt) { | ||
| return cachedSSLContext; | ||
| } | ||
| synchronized (this) { | ||
| if (sslContextBuilt) { | ||
| return cachedSSLContext; | ||
| } | ||
| cachedSSLContext = buildSSLContextInternal(); | ||
| sslContextBuilt = true; | ||
| return cachedSSLContext; | ||
| } | ||
| } | ||
|
|
||
| @Nullable | ||
| @SuppressFBWarnings("PATH_TRAVERSAL_IN") | ||
| private SSLContext buildSSLContextInternal() throws GeneralSecurityException, IOException { | ||
| if (insecure) { | ||
| SSLContext sslContext = SSLContext.getInstance("TLS"); | ||
| sslContext.init(null, new TrustManager[]{new InsecureTrustManager()}, null); | ||
| return sslContext; | ||
| } else if (caCertPath != null) { | ||
| CertificateFactory cf = CertificateFactory.getInstance("X.509"); | ||
| java.security.cert.Certificate caCert; | ||
| try (FileInputStream fis = new FileInputStream(caCertPath)) { | ||
| caCert = cf.generateCertificate(fis); | ||
| } | ||
| KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); | ||
| ks.load(null, null); | ||
| ks.setCertificateEntry("custom-ca", caCert); | ||
| TrustManagerFactory defaultTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
| defaultTmf.init((KeyStore) null); | ||
| int certIndex = 0; | ||
| for (TrustManager tm : defaultTmf.getTrustManagers()) { | ||
| if (tm instanceof X509TrustManager) { | ||
| for (X509Certificate cert : ((X509TrustManager) tm).getAcceptedIssuers()) { | ||
| ks.setCertificateEntry("default-" + certIndex++, cert); | ||
| } | ||
| } | ||
| } | ||
| TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
| tmf.init(ks); | ||
| SSLContext sslContext = SSLContext.getInstance("TLS"); | ||
| sslContext.init(null, tmf.getTrustManagers(), null); | ||
| return sslContext; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| @SuppressFBWarnings("WEAK_TRUST_MANAGER") | ||
| private static final class InsecureTrustManager implements X509TrustManager { | ||
| @Override | ||
| public void checkClientTrusted(X509Certificate[] chain, String authType) { | ||
| } | ||
|
|
||
| @Override | ||
| public void checkServerTrusted(X509Certificate[] chain, String authType) { | ||
| } | ||
|
|
||
| @Override | ||
| public X509Certificate[] getAcceptedIssuers() { | ||
| return new X509Certificate[0]; | ||
| } | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.