Skip to content

Conversation

@andyrzhao
Copy link
Contributor

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.

@andyrzhao andyrzhao requested review from a team as code owners April 7, 2025 21:03
@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Apr 7, 2025
Comment on lines 57 to 59
mtlsProvider = new SecureConnectProvider();
mtlsProvider.getKeyStore();
return mtlsProvider;
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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.

@lqiu96 lqiu96 requested a review from zhumin8 April 9, 2025 18:42
@andyrzhao andyrzhao requested review from lqiu96 and zhumin8 April 9, 2025 22:44
Copy link
Contributor

@zhumin8 zhumin8 left a 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.

mtlsProvider.getKeyStore();
return mtlsProvider;
} catch (CertificateSourceUnavailableException ex) {
throw new CertificateSourceUnavailableException(
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Comment on lines 143 to 145
while (remainTime > 0) {
Thread.sleep(Math.min(remainTime + 1, 100));
remainTime -= System.currentTimeMillis() - startTime;
Copy link
Contributor

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();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done~

Comment on lines 70 to 72
if (metadata == null) {
return null;
}
Copy link
Contributor

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?

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());

Copy link
Contributor Author

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");"

Comment on lines 57 to 59
mtlsProvider = new SecureConnectProvider();
mtlsProvider.getKeyStore();
return mtlsProvider;
Copy link
Contributor

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?

@andyrzhao andyrzhao requested a review from zhumin8 May 13, 2025 23:01
import java.util.List;
import org.junit.Test;

public class SecureConnectProviderTest {
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Member

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.

@andyrzhao andyrzhao requested a review from zhumin8 May 20, 2025 04:07
zhumin8
zhumin8 previously approved these changes May 27, 2025
Copy link
Contributor

@zhumin8 zhumin8 left a comment

Choose a reason for hiding this comment

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

LGTM

@andyrzhao andyrzhao requested review from lqiu96 and zhumin8 May 28, 2025 17:13
zhumin8
zhumin8 previously approved these changes May 29, 2025
lqiu96
lqiu96 previously approved these changes May 29, 2025
Copy link
Member

@lqiu96 lqiu96 left a 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.

@andyrzhao andyrzhao dismissed stale reviews from lqiu96 and zhumin8 via c895cb9 May 30, 2025 18:13
@andyrzhao
Copy link
Contributor Author

Changes generally LGTM. Added a few small comments if you could take a look at.

Thanks for the thorough review Lawrence and Min!

@andyrzhao andyrzhao requested a review from lqiu96 May 30, 2025 18:44
@andyrzhao andyrzhao requested a review from zhumin8 May 30, 2025 21:13
@andyrzhao andyrzhao merged commit c9fd1b1 into googleapis:main Jun 3, 2025
23 of 24 checks passed
svc-squareup-copybara pushed a commit to cashapp/misk that referenced this pull request Jun 5, 2025
| 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
([#&#8203;1730](googleapis/google-auth-library-java#1730))
([c9fd1b1](googleapis/google-auth-library-java@c9fd1b1))

##### Bug Fixes

- Correct capitalization of GitHub
([#&#8203;1761](googleapis/google-auth-library-java#1761))
([f79a2e4](googleapis/google-auth-library-java@f79a2e4))
- Correct extra spaces in README heading
([#&#8203;1760](googleapis/google-auth-library-java#1760))
([8d26666](googleapis/google-auth-library-java@8d26666))
- Correct misspelling of OAuth in comments
([#&#8203;1762](googleapis/google-auth-library-java#1762))
([42b9602](googleapis/google-auth-library-java@42b9602))
- Correct typo in ServiceAccountJwtAccessCredentials.java comment
([#&#8203;1765](googleapis/google-auth-library-java#1765))
([3058b06](googleapis/google-auth-library-java@3058b06))
- Update Javadoc reference in ExternalAccountCredentials
([#&#8203;1763](googleapis/google-auth-library-java#1763))
([5eb3659](googleapis/google-auth-library-java@5eb3659))

##### Documentation

- Duplicate "the" in Javadoc comments
([#&#8203;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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: l Pull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants