[#11154] fix(authz): Fix the NullPointerException when filesets request the credential#11155
Merged
Conversation
… request the credential
Change CredentialProvider.getCredential and downstream CatalogCredentialManager / CredentialCache methods to return Optional<Credential> instead of @nullable Credential, and update CredentialOperationDispatcher and CatalogWrapperForREST callers accordingly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…urn Optional Apply the Optional<Credential> return type change to JdbcCredentialProvider and its tests, which were added to upstream/main after the previous commit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Code Coverage Report
Files
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses a NullPointerException when filesets request credentials by making credential retrieval explicitly optional and ensuring missing credentials are skipped/handled safely across the credential vending flow.
Changes:
- Updated
CredentialProviderand related implementations to returnOptional<Credential>instead of nullableCredential. - Updated credential vending call sites (dispatcher and Iceberg REST wrapper) to handle missing credentials via
Optional(ifPresent,orElseThrow). - Updated/added unit tests to validate behavior when a provider returns no credential.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/extension/DummyCredentialProvider.java | Updates test provider to return Optional<Credential>. |
| iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/CatalogWrapperForREST.java | Switches to Optional flow and throws when no credential is available. |
| core/src/test/java/org/apache/gravitino/credential/TestJdbcCredentialProvider.java | Updates JDBC provider tests for Optional return values. |
| core/src/test/java/org/apache/gravitino/credential/TestCredentialProvider.java | Adapts dummy provider test to Optional API. |
| core/src/test/java/org/apache/gravitino/credential/TestCredentialOperationDispatcher.java | Adds coverage ensuring missing credentials are skipped. |
| core/src/test/java/org/apache/gravitino/credential/DummyCredentialProvider.java | Updates dummy provider to return Optional. |
| core/src/test/java/org/apache/gravitino/credential/Dummy2CredentialProvider.java | Updates dummy provider to return Optional. |
| core/src/main/java/org/apache/gravitino/credential/JdbcCredentialProvider.java | Returns Optional.empty() when JDBC properties are missing/blank. |
| core/src/main/java/org/apache/gravitino/credential/CredentialOperationDispatcher.java | Skips absent credentials via Optional#ifPresent. |
| core/src/main/java/org/apache/gravitino/credential/CredentialCache.java | Changes cache API to Optional, but currently maps empty to null (see review comments). |
| core/src/main/java/org/apache/gravitino/credential/CatalogCredentialManager.java | Propagates Optional through manager APIs. |
| common/src/main/java/org/apache/gravitino/credential/CredentialProviderDelegator.java | Wraps generator output with Optional.ofNullable. |
| common/src/main/java/org/apache/gravitino/credential/CredentialProvider.java | Changes interface contract to Optional<Credential>. |
| bundles/azure/src/main/java/org/apache/gravitino/abs/credential/AzureAccountKeyProvider.java | Updates provider to return Optional. |
| bundles/aws/src/main/java/org/apache/gravitino/s3/credential/S3SecretKeyProvider.java | Updates provider to return Optional. |
| bundles/aliyun/src/main/java/org/apache/gravitino/oss/credential/OSSSecretKeyProvider.java | Updates provider to return Optional. |
Comment on lines
+93
to
+95
| Credential credential = | ||
| credentialCache.get(cacheKey, key -> credentialSupplier.apply(cacheKey).orElse(null)); | ||
| return Optional.ofNullable(credential); |
Contributor
Author
There was a problem hiding this comment.
unacceptable. It will breaks the atomic.
Comment on lines
66
to
74
| * Gets a credential based on the provided context information. | ||
| * | ||
| * @param context A context object providing necessary information for retrieving credentials. | ||
| * @return A Credential object containing the authentication information needed to access a system | ||
| * or resource. Null will be returned if no credential is available. | ||
| * @return An {@link Optional} containing the {@link Credential} with the authentication | ||
| * information needed to access a system or resource, or {@link Optional#empty()} if no | ||
| * credential is available. | ||
| */ | ||
| @Nullable | ||
| Credential getCredential(CredentialContext context); | ||
| Optional<Credential> getCredential(CredentialContext context); | ||
| } |
Comment on lines
154
to
+160
| CredentialProvider credentialProvider = | ||
| CredentialProviderFactory.create(JdbcCredential.JDBC_CREDENTIAL_TYPE, catalogProperties); | ||
|
|
||
| CatalogCredentialContext context = new CatalogCredentialContext("test-user"); | ||
| Credential credential = credentialProvider.getCredential(context); | ||
| Optional<Credential> credential = credentialProvider.getCredential(context); | ||
|
|
||
| Assertions.assertNull(credential); | ||
| Assertions.assertFalse(credential.isPresent()); |
Rename testEmptyPasswordReturnsNull to testEmptyPasswordReturnsEmptyOptional to match the behavior after switching getCredential to return Optional. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment on lines
+91
to
+95
| public Optional<Credential> getCredential( | ||
| T cacheKey, Function<T, Optional<Credential>> credentialSupplier) { | ||
| Credential credential = | ||
| credentialCache.get(cacheKey, key -> credentialSupplier.apply(cacheKey).orElse(null)); | ||
| return Optional.ofNullable(credential); |
Comment on lines
65
to
74
| /** | ||
| * Gets a credential based on the provided context information. | ||
| * | ||
| * @param context A context object providing necessary information for retrieving credentials. | ||
| * @return A Credential object containing the authentication information needed to access a system | ||
| * or resource. Null will be returned if no credential is available. | ||
| * @return An {@link Optional} containing the {@link Credential} with the authentication | ||
| * information needed to access a system or resource, or {@link Optional#empty()} if no | ||
| * credential is available. | ||
| */ | ||
| @Nullable | ||
| Credential getCredential(CredentialContext context); | ||
| Optional<Credential> getCredential(CredentialContext context); | ||
| } |
…al credential Fix the Caffeine cache mapping function returning null and keep the CredentialProvider SPI backward compatible. - CredentialCache stores a non-null Optional<Credential> so Cache#get stays atomic; the Expiry calculator handles the empty case without calling expireTimeInMs(). - Restore the legacy @nullable Credential getCredential(CredentialContext) as a deprecated default and add a new Optional-returning getCredentialOptional(CredentialContext), preserving binary/source compatibility for ServiceLoader-discovered implementations. - Update first-party providers, callers, and tests to the new method. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
Author
|
@diqiu50 Could u take a look again? |
diqiu50
reviewed
May 20, 2026
| Method method = | ||
| CredentialOperationDispatcher.class.getDeclaredMethod( | ||
| "getCredentials", BaseCatalog.class, NameIdentifier.class, CredentialPrivilege.class); | ||
| method.setAccessible(true); |
Contributor
There was a problem hiding this comment.
Why don’t we call dispatcher.getCredentials() directly?
| // Do not cache the absence of a credential, expire it immediately. | ||
| if (!credential.isPresent()) { | ||
| return 0; | ||
| } |
Contributor
There was a problem hiding this comment.
Add a test to cover this case.
- Call CredentialOperationDispatcher.getCredentials directly in the test instead of via reflection (made the overload package-private). - Add TestCredentialCache covering that an absent credential is not cached while a present one is. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…edential Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…l abstract Make getCredential the abstract SPI method that providers implement, with getCredentialOptional kept as a default wrapper. Update all in-repo providers (delegator, JDBC, Azure, OSS, S3 secret-key) and test providers to implement getCredential. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What changes were proposed in this pull request?
Fix the NullPointerException when filesets request the credential
Why are the changes needed?
Fix: #11154
Does this PR introduce any user-facing change?
No.
How was this patch tested?
Add UTs.