-
Notifications
You must be signed in to change notification settings - Fork 263
feat(mtls): Introduce DefaultMtlsProviderFactory and SecureConnectProvider #1730
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
Conversation
| mtlsProvider = new SecureConnectProvider(); | ||
| mtlsProvider.getKeyStore(); | ||
| return mtlsProvider; |
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.
Can SecureConnectProvider be added in a future PR? Or is this required for this PR? From my last discussion with Alex, the requirements was the inclusion of X.509 and having the Auth library STS functionality use the X.509 MtlsProvider.
I'm a bit concerned that SecureConnectProvider will exist in both Gax and Auth at the same time. I know that in the future that will commit to this existing in this repo.
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.
Thanks for taking a look Lawrence! So this PR is complementary to Alex's work to support X.509-based ADC auth. The goal of this PR is to bring Java SDK to feature parity with Golang SDK and Python SDK, both of which supports X.509-based ADC auth as well as X.509-backed mTLS transports (alongside SecureConnect backed mTLS transports). This is basically the final checkbox that allows the CBA team to declare client-side GA w.r.t X.509 work.
I think the fact that the SecureConnectProvider will exist in both Gax and Auth at the same time (in the near term) is a small inconvenience that we can solve with documentation updates. Btw, you will note that the SecureConnectProvider implementation in this CL does not have any of the "CBA environment variable look up logic" present in the gax version - this is intentional: I've already started a separate refactoring effort on the GAX side to create a new helper class "CertificateBasedAccess" that will handle all env var checks and endpoint calculations. This is necessary to ensure that both X.509 mTLS and SecureConnect mTLS are gated behind the same env var variables, regardless of which mTLS provider is used.
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.
Ok, I think the SecureConnectProvider duplication is OK for now, given that the implementation isn't intended to be used by customers and we don't expose this on the public surface for customers to set anyways. There shouldn't be any confusion from their POV.
I'll need to double check this behavior in our downstream libraries, but i'm 90% confident that it can be fine for now.
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.
Looks like although we do not expose the public surface for customers to set, downstream handwritten libraries have handles to set MtlsProvider from EndpointContext or InstantiatingGrpcChannelProvider? (I don't know if that's something touched in your related GAX changes?) It is unlikely a handwritten library used it, but can you double check this?
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.
mTLSProvder references in EndpointContext and InstantiatingGrpcChannelProviders are internal logic that was authored around the same time the original mTLS support was added, and I'm 99% sure there are no one else is using the set MtlsProvider functionality (it's mainly used by unit tests from the same suite as far as I can tell.) We can check it again when working on the Gax refactoring. This PR alone should not introduce any breaking changes.
oauth2_http/java/com/google/auth/mtls/DefaultMtlsProviderFactory.java
Outdated
Show resolved
Hide resolved
zhumin8
left a 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.
Taking a first round.
oauth2_http/java/com/google/auth/mtls/DefaultMtlsProviderFactory.java
Outdated
Show resolved
Hide resolved
| mtlsProvider.getKeyStore(); | ||
| return mtlsProvider; | ||
| } catch (CertificateSourceUnavailableException ex) { | ||
| throw new CertificateSourceUnavailableException( |
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.
Is it useful here to wrap the the original exception? It's usually good practice for debugging to wrap the original exception (the one from X509Provider or SecureConnectProvider) as the cause.
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.
So with the update to use "isCertificateSourceAvailable()", we no longer have the raw exceptions here. I don't have a strong preference here either-way - this is a non-blocking error message for the general use-case.
| while (remainTime > 0) { | ||
| Thread.sleep(Math.min(remainTime + 1, 100)); | ||
| remainTime -= System.currentTimeMillis() - startTime; |
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.
Instead of manual timeout logic implementation, for Java 8+, Process.waitFor(long timeout, TimeUnit unit) is the standard and much cleaner way to wait for a process with a timeout.
If check "every 100 milliseconds" itself is not a requirement, this would simplify logic here, to something along the lines of
static int runCertificateProviderCommand(Process commandProcess, long timeoutMilliseconds)
throws IOException, InterruptedException {
boolean terminated = commandProcess.waitFor(timeoutMilliseconds, TimeUnit.MILLISECONDS);
if (!terminated) {
commandProcess.destroy();
throw new IOException("Cert provider command timed out");
}
return commandProcess.exitValue();
}
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.
Done~
| if (metadata == null) { | ||
| return null; | ||
| } |
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.
if metadata == null a valid scenario? If so, when later calling methods on process can lead to NullPointerException?
google-auth-library-java/oauth2_http/java/com/google/auth/mtls/SecureConnectProvider.java
Lines 114 to 123 in 7a2b2ce
| Process process = processProvider.createProcess(metadata); | |
| // Run the command and timeout after 1000 milliseconds. | |
| int exitCode = runCertificateProviderCommand(process, 1000); | |
| if (exitCode != 0) { | |
| throw new IOException("Cert provider command failed with exit code: " + exitCode); | |
| } | |
| // Create mTLS key store with the input certificates from shell command. | |
| return SecurityUtils.createMtlsKeyStore(process.getInputStream()); |
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.
Good point! "metadata == null" in createProcess is not a case we expect to reach within the current code logic, since "new FileInputStream" would result in "FileNotFoundException" first. To safeguard against null pointer possibility, I updated "return null" to "throw new IOException("Error creating Process: metadata is null");"
| mtlsProvider = new SecureConnectProvider(); | ||
| mtlsProvider.getKeyStore(); | ||
| return mtlsProvider; |
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.
Looks like although we do not expose the public surface for customers to set, downstream handwritten libraries have handles to set MtlsProvider from EndpointContext or InstantiatingGrpcChannelProvider? (I don't know if that's something touched in your related GAX changes?) It is unlikely a handwritten library used it, but can you double check this?
| import java.util.List; | ||
| import org.junit.Test; | ||
|
|
||
| public class SecureConnectProviderTest { |
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.
Does it makes sense to create similar tests for the new X509Provider?
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.
So X509ProviderTest already exists (and was written by AION team), which should suffice for now?
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.
If possible, can we also have tests for DefaultMtlsProviderFactory?
I think some small tests to cover the fallback logic and a test to cover if both options fail? Hopefully it's not too much work to add these cases.
zhumin8
left a 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.
LGTM
oauth2_http/java/com/google/auth/mtls/ContextAwareMetadataJson.java
Outdated
Show resolved
Hide resolved
lqiu96
left a 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.
Changes generally LGTM. Added a few small comments if you could take a look at.
Thanks for the thorough review Lawrence and Min! |
| Package | Type | Package file | Manager | Update | Change | |---|---|---|---|---|---| | [io.netty:netty-handler](https://netty.io/) ([source](https://github.com/netty/netty)) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `4.2.1.Final` -> `4.2.2.Final` | | [io.netty:netty-bom](https://netty.io/) ([source](https://github.com/netty/netty)) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `4.2.1.Final` -> `4.2.2.Final` | | [com.google.auth:google-auth-library-oauth2-http](https://github.com/googleapis/google-auth-library-java) | dependencies | misk/gradle/libs.versions.toml | gradle | minor | `1.36.0` -> `1.37.0` | | [com.google.auth:google-auth-library-credentials](https://github.com/googleapis/google-auth-library-java) | dependencies | misk/gradle/libs.versions.toml | gradle | minor | `1.36.0` -> `1.37.0` | | [software.amazon.awssdk:sdk-core](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:sqs](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:dynamodb-enhanced](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:dynamodb](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:aws-core](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:bom](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | | [software.amazon.awssdk:auth](https://aws.amazon.com/sdkforjava) | dependencies | misk/gradle/libs.versions.toml | gradle | patch | `2.31.56` -> `2.31.57` | --- ### Release Notes <details> <summary>googleapis/google-auth-library-java (com.google.auth:google-auth-library-oauth2-http)</summary> ### [`v1.37.0`](https://github.com/googleapis/google-auth-library-java/blob/HEAD/CHANGELOG.md#1370-2025-06-04) ##### Features - **mtls:** Introduce DefaultMtlsProviderFactory and SecureConnectProvider ([#​1730](googleapis/google-auth-library-java#1730)) ([c9fd1b1](googleapis/google-auth-library-java@c9fd1b1)) ##### Bug Fixes - Correct capitalization of GitHub ([#​1761](googleapis/google-auth-library-java#1761)) ([f79a2e4](googleapis/google-auth-library-java@f79a2e4)) - Correct extra spaces in README heading ([#​1760](googleapis/google-auth-library-java#1760)) ([8d26666](googleapis/google-auth-library-java@8d26666)) - Correct misspelling of OAuth in comments ([#​1762](googleapis/google-auth-library-java#1762)) ([42b9602](googleapis/google-auth-library-java@42b9602)) - Correct typo in ServiceAccountJwtAccessCredentials.java comment ([#​1765](googleapis/google-auth-library-java#1765)) ([3058b06](googleapis/google-auth-library-java@3058b06)) - Update Javadoc reference in ExternalAccountCredentials ([#​1763](googleapis/google-auth-library-java#1763)) ([5eb3659](googleapis/google-auth-library-java@5eb3659)) ##### Documentation - Duplicate "the" in Javadoc comments ([#​1764](googleapis/google-auth-library-java#1764)) ([5f7a084](googleapis/google-auth-library-java@5f7a084)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - "after 6pm every weekday,before 2am every weekday" in timezone Australia/Melbourne, Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). GitOrigin-RevId: 57d30e592601468e7e82f86d4dcf27523cdba475
This PR allows the Java auth lib to provide either an X509 mTLS provider or SecureConnect mTLS provider based on availability and under a common "MtlsProvider" interface. The Java GAX lib will be refactored to use this factory and interface in a subsequent PR.