Skip to content

Conversation

@sungwy
Copy link
Contributor

@sungwy sungwy commented Dec 10, 2025

Draft PR to introduce an External mode in the PolarisPrincipal. The goal of this PR is to introduce an authentication flow that skips principal resolution in the metastore for enhanced compatibility with authentication -> authorization flows that rely on external IDPs and PDPs.

This PR is motivated by @adutra 's mailing list proposal

Checklist

  • 🛡️ Don't disclose security issues! (contact [email protected])
  • 🔗 Clearly explained why the changes are needed, or linked related issues: Fixes #
  • 🧪 Added/updated tests with good coverage, or manually tested (and explained how)
  • 💡 Added comments for complex logic
  • 🧾 Updated CHANGELOG.md (if needed)
  • 📚 Updated documentation in site/content/in-dev/unreleased (if needed)

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.

Thanks for pushing this feature forward, @sungwy !

Some preliminary comments, while the proposal is still being discussed.

// if the principal was not found, we can end right there
if (this.resolvedCallerPrincipal == null
|| this.resolvedCallerPrincipal.getEntity().isDropped()) {
if (isExternalPrincipal()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can this be true without returning on line 759?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It cannot - this was before I moved the condition upto line 748 to avoid principal resolution altogether if it is external. I'll remove this check here to remove redundancy

List<ResolvedPolarisEntity> toValidate) {

if (isExternalPrincipal()) {
PrincipalEntity externalPrincipal = createExternalPrincipalEntity();
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an entity without a (real) ID... Some it's a kind of ephemeral entity... Would it be possible to avoid creating it at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good question - I'm a bit confused about the role of PrincipalEntity. We do have a public method for getResolvedCallerPrincipal() that returns resolvedCallerPrincipal. It's not being used anywhere in the codebase today, but I thought it'd be safe to populate it as it requires it to be @Nonnull: https://github.com/apache/polaris/blob/23ba2a05adc9c75f3e72aaf2ca370b4886964328/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/Resolver.java#L272C19-L280

Copy link
Contributor

@dimas-b dimas-b Dec 11, 2025

Choose a reason for hiding this comment

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

Conceptually, IMHO, the principal entity should only be required for AuthZ checks (which do not actually require it if it's external). So, any intermediate code that requires it may need to be refactored... but TBH, I do not remember that code very well 😅

}

private boolean isExternalPrincipal() {
return Boolean.parseBoolean(polarisPrincipal.getProperties().getOrDefault("external", "false"));
Copy link
Contributor

Choose a reason for hiding this comment

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

WDYT about making isExternal() a method of PolarisPrincipal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that's worth considering. I put it into PolarisPrincipal as a part of the property for now because it was already available, but I think adding it as an attribute or adding a class method that infers the property value is up for discussion

String grantType,
String scope,
TokenType requestedTokenType) {
return TokenResponse.of(OAuthError.invalid_request);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about invalid_request... it may actually be well-formed... How about unsupported_grant_type?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a great suggestion - thank you!

private ResolverStatus resolveCallerPrincipalAndPrincipalRoles(
List<ResolvedPolarisEntity> toValidate) {

if (isExternalPrincipal()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Cf. #3228


@Override
public PolarisPrincipal authenticate(PolarisCredential credentials) {
PolarisCredential externalCredentials = ensureExternal(credentials);
Copy link
Contributor Author

@sungwy sungwy Dec 11, 2025

Choose a reason for hiding this comment

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

instead of overriding the Principal to be external here, maybe we could validate that it is external and raise an exception if it isn't instead. Then we have a clearer separation of responsibility between:

  1. detecting whether a PolarisCredential's origin was internal or external
  2. and determining if a PolarisPrincipal should be internal, federated or external.

Copy link
Contributor

Choose a reason for hiding this comment

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

@adutra : WDYT?

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.

2 participants