Skip to content

Add support for federated principal and role with block for manual role assignment #1353

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

collado-mike
Copy link
Contributor

First PR to begin implementing the design outlined in https://docs.google.com/document/d/15_3ZiRB6Lhzw0nxij341QUdxEIyFGTrI9_18bFIyJVo/edit?tab=t.0#heading=h.cu1a1acu4lc5 .

Implements #441

Adds a FEDERATED_ENTITY property, which can be defined in Principals and PrincipalRoles. FEDERATED Principals cannot be created via the API, but FEDERATED roles can be. This allows for creating roles which can be assigned privileges, while actual principal creation is delegated to the JIT creation mechanism (not in this PR).

@@ -65,6 +65,13 @@ public Builder(PrincipalRoleEntity original) {
super(original);
}

public Builder setFederated(Boolean isFederated) {
if (isFederated != null && isFederated) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic doesn't look right to me. This entity would come out federated:

new PolarisEntity.Builder()
. . .
.setFederated(true)
.setFederated(false)
.build()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, the idea is to avoid adding any entry for non-federated identities. I don't think the logic snippet you posted is reasonable or should be supported. I'd be in favor of an IllegalStateException if someone typed that code. Happy to add that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why should it not be supported? It sounds like you're saying that .setFederated(false) is never a valid call, in which case setFederated shouldn't take a boolean arg. Perhaps you are even looking for something like buildFederated?

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'm saying the code example you suggested is a programming error. Ideally, that would be handled by the compiler, but an exception would also work.

Copy link
Contributor

@dimas-b dimas-b Apr 16, 2025

Choose a reason for hiding this comment

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

I support @eric-maynard 's point here. Current code is very risky in terms of latent bugs, IMHO. A caller of .setFederated(false) can reasonably expect the property to become false regardless of any previous set* calls (which might have been made in a different context).

@@ -871,6 +873,42 @@ public void testCreatePrincipalAndRotateCredentials() {
// rotation that makes the old secret fall off retention.
}

@Test
public void testCreateFederatedPrincipalFails() {
Copy link
Contributor

@eric-maynard eric-maynard Apr 11, 2025

Choose a reason for hiding this comment

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

Given how different the semantics for federated principal (role)s appear to be, I wonder if we should consider a subtype? It looks like most APIs are valid for nonfederated principal (role)s are not valid for federated ones. This is reminiscent of EXTERNAL catalogs, but maybe more extreme

Copy link
Contributor Author

Choose a reason for hiding this comment

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

External catalog has a separate type because it has an extra field. Federated identity types don't have any additional fields at this point, so I'd prefer not to add an extra type. If extra fields end up getting added, then it would make sense, but for now deserializing wouldn't even be able to distinguish what type it should deserialized to.

@@ -1089,6 +1089,10 @@ components:
clientId:
type: string
description: The output-only OAuth clientId associated with this principal if applicable
federated:
Copy link
Contributor

Choose a reason for hiding this comment

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

This part LGTM, but it should go to a ML vote

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to ML discussion.

What's the use case for exposing federated principal in the Polaris Management API? Acting as a proxy in front of an IdP sounds questionable to me.

Copy link
Contributor Author

@collado-mike collado-mike Apr 15, 2025

Choose a reason for hiding this comment

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

The main case is to support adding federated roles so that privileges can be defined. Per the original design doc, federated identities are created on the fly when a user logs in, but if we don't allow creation of federated roles, we can't define any privileges for those users until they've logged in. That makes things hard for the admins, IMO.

For Principals, I don't think federated principals should be created via the API, for the same reasoning you suggest, but we should be able to return federated principals and report that they are federated. To make that clearer, maybe I can update the spec to return one of two types, but to only allow creation of one 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.

I updated the spec to be more clear about when federated principals are expected as return types/arguments. This unfortunately cluttered the generated code more than I had hoped. I'll post a link on the mailing list re: this change.

Copy link
Contributor

@dimas-b dimas-b Apr 16, 2025

Choose a reason for hiding this comment

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

Thanks for the clarification! The description of the property LGTM. However, I'm not not sure about exposing federated Principals in the Polaris API.

Granted, we have to expose federated Principal Roles in order to allow assignment to Catalog Roles, but do Principals have to be exposed?

The design doc does talk about Polaris entities for federated roles, but I did not see it mention having to define entities for federated principals. Per section Automatic User Provisioning there is no strict requirement for federated principal entities... hence my question.

Copy link
Contributor

@dimas-b dimas-b Apr 16, 2025

Choose a reason for hiding this comment

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

As @eric-maynard suggested, it might be more efficient to revive the ML / doc discussion. GH comment threads are less convenient for long discussions.

@@ -771,6 +771,9 @@ public PrincipalWithCredentials createPrincipal(PolarisEntity entity) {
PolarisAuthorizableOperation op = PolarisAuthorizableOperation.CREATE_PRINCIPAL;
authorizeBasicRootOperationOrThrow(op);

if (PolarisEntity.isFederated(entity)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we expose "federated" as a property settable via java API only to add validation that it cannot be set?

Also, REST API (which is the only caller of this method) does not allow setting the "federated" property, as far as I can tell, because it does not set internal properties on the PrincipalEntity 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

to clarify: My thinking was that the fact that make those entities "not creatable" via the Admin API is not the presence of a specific property (i.e. "federated") but the fact that they are managed in a different way (via IdP integrations, I believe).

Can this be made more explicit in code? I do not have a solid suggestion, but I wonder if some sort of a "manager" class might be suitable here. That "manager" would then make the decision about allowing or not allowing changes via Admin API. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The presence of a specific property is the only way that the admin API can tell if an entity is managed by an IdP. Principal Roles, federated or not, must be present in the service in order to be granted privileges. That means they have to be persisted, so the persistence API is going to return them as entities. We have to be able to introspect those entities to know when it is or isn't ok to grant access to those roles. This was outlined in the design doc at https://docs.google.com/document/d/15_3ZiRB6Lhzw0nxij341QUdxEIyFGTrI9_18bFIyJVo/edit?tab=t.0#heading=h.w9dvdtp5mw5p

Copy link
Contributor

@dimas-b dimas-b Apr 16, 2025

Choose a reason for hiding this comment

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

The design doc does talk about this, but I do not recall firm decisions on mentioned alternatives :)

Even if we create entities for federated principals, consider a use case when someone creates a principal called A (non-federated) and later someone else adds federation and federated principal with name A comes in (or the other way around). Where is this conflict resolved? This is what I mean be "manager".

Another use case: a federated principal B is created thought some IdP integration logic and brings in some properties from the IdP. A user updates principal B via Admin API. The doc mentions that being able to update principal properties is desirable, but where do we resolve conflicts between updates from the API and from the integration side?

@@ -1089,6 +1089,10 @@ components:
clientId:
type: string
description: The output-only OAuth clientId associated with this principal if applicable
federated:
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to ML discussion.

What's the use case for exposing federated principal in the Polaris Management API? Acting as a proxy in front of an IdP sounds questionable to me.

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