Skip to content

Conversation

XJDKC
Copy link
Member

@XJDKC XJDKC commented Oct 9, 2025

Add Connection Credential Vendors for Other Auth Types

This change is a prerequisite for enabling connection credential caching.
By making PolarisCredentialManager the central entry point for obtaining connection credentials, we can introduce caching cleanly and manage all credential flows in a consistent way.

PolarisCredentialManager::getConnectionCredentials will delegate the call to the appropriate credential vendor based on the authentication type:

  • SigV4 -> SigV4ConnectionCredentialVendor
    • ServiceIdentityProvider: Uses ServiceIdentityProvider to retrieve the IAM user’s AWS credential that represents Polaris’s service identity.
    • StsClient: Then use StsClient to assume the user-provided iam role and obtain temporary AWS credentials.
  • OAuth -> OAuthConnectionCredentialVendor
    • UserSecretsManager: Uses UserSecretsManager to retrieve the OAuth2 credential from the secret manager.
  • Bearer -> BearerConnectionCredentialVendor
    • UserSecretsManager: Uses UserSecretsManager to retrieve the bearer token from the secret manager.
  • Implicit -> ImplicitConnectionCredentialVendor
    • A no-op vendor used when no authentication credentials are required.

With this structure, we no longer need to use UserSecretsManager directly inside IcebergCatalogPropertiesProvider::asIcebergCatalogProperties.

This unifies credential retrieval across all authentication types and simplifies the overall credential management flow.

Copy link
Contributor

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

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

LGTM overall 👍 Some comments below.

// OAuth credentials don't expire - set expiration to Instant.MAX to indicate infinite validity
// If the credential expires, users need to update the catalog entity to rotate the credential.
return ConnectionCredentials.builder()
.putCredential(CatalogAccessProperty.OAUTH2_CREDENTIAL.getPropertyName(), credential)
Copy link
Contributor

Choose a reason for hiding this comment

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

There is nothing in this class that actually relates to the OAuth2 spec as far as I can tell. It only relates to the Iceberg OAuth2Properties.CREDENTIAL constant, which again has very little to do with OAuth2 RFCs as far as connection configuration is concerned... It's just a property name plus format spec 🤷

What the client does with this property (whether it's OAuth2 or something else) is beyond the scope of this credential vendor. At this level we do not know how the credential is used.

I'd propose to rename this to "Iceberg Credential Vendor".

Copy link
Member Author

@XJDKC XJDKC Oct 10, 2025

Choose a reason for hiding this comment

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

Yes, you're right, this class currently just retrieves the OAuth credential from UserSecretsManager and returns it. The PolarisCredentialManager will then cache it in AccessCredsCache (not yet implemented, I plan to add that in a follow-up PR) so that we don't need to fetch the credential from UserSecretsManager every time we make a call, especially if the secret manager doesn't have its own cache.

The main goal of this PR is to make PolarisCredentialManager the single entry point for credential retrieval so we can centralize the caching logic in one place.

Regarding your suggestion, I agree, it's still beneficial to include OAuth in the class name to make the purpose of this class clear at a glance.

Right now, the class only returns the stored OAuth credential, but in the future, we could extend it to perform the client credentials flow to obtain a temporary token directly here, rather than relying on the Iceberg SDK to fetch a new token for every request.

WDYT?

Copy link
Contributor

@dimas-b dimas-b Oct 10, 2025

Choose a reason for hiding this comment

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

I fully support implementing OAuth2 flows in the future.

However, in its current form this credential vendor provides a simple pair of values, but claims the type of AuthenticationType.OAUTH. I personally find it misleading 🤔

Even if Polaris supported OAuth2 flows to obtain a token for a catalog connection, this class populates Iceberg's credential property, which is not a token. This property cannot hold an OAuth2 token. Instead it instruct the (Iceberg) client to perform some activities internally in order to obtain the access token. From the Polaris POV OAuth is not apparent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct, how about renaming it to OAuthClientCredentialVendor then add a real OAuthConnectionCredentialVendor to perform the oauth2 flow and get a token?

Copy link
Contributor

@HonahX HonahX left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! It looks great!

Comment on lines 50 to +55
@Override
public @Nonnull Map<String, String> asIcebergCatalogProperties(
UserSecretsManager secretsManager, PolarisCredentialManager credentialManager) {
String bearerToken = secretsManager.readSecret(getBearerTokenReference());
return Map.of(OAuth2Properties.TOKEN, bearerToken);
PolarisCredentialManager credentialManager) {
// Return only metadata properties - credentials are handled by ConnectionCredentialVendor
// Bearer auth has no metadata properties
return Map.of();
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we make this a default implementation in abstract class AuthenticationParametersDpo or the interface?

"Catalog federation is enabled but no ConnectionCredentialVendor found for "
+ "authentication type '%s'. External catalog connections using this "
+ "authentication type will fail.",
type),
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious, would this check be too strong that we only consider it to be production ready if all auth types need the vendor, or this is more like a warning despite it is called "Error"?

Copy link
Contributor

@dimas-b dimas-b Oct 10, 2025

Choose a reason for hiding this comment

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

Yeah, naming needs improvement here. An error production readiness check will not block startup. Only severe cases break startup.

Copy link
Contributor

@dimas-b dimas-b Oct 10, 2025

Choose a reason for hiding this comment

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

I'm not sure the check is logically correct. A particular deployment only needs to provide ConnectionCredentialVendor implementations for auth types that are actually used by created catalogs.

I think the vendor availability is implicitly checked on catalog creation already.

On startup, I think we only need to check types for existing catalogs, not for all types listed in the enum. The latter would put an undue burden on custom deployments.

*/
@RequestScoped
@AuthType(AuthenticationType.BEARER)
@Priority(100)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we extract the priority to some constants class, like FilterPriorities. It will be easier for custom implementation to use and managed the prioty.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants