-
Notifications
You must be signed in to change notification settings - Fork 224
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
base: main
Are you sure you want to change the base?
Conversation
polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntity.java
Show resolved
Hide resolved
polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalRoleEntity.java
Show resolved
Hide resolved
@@ -65,6 +65,13 @@ public Builder(PrincipalRoleEntity original) { | |||
super(original); | |||
} | |||
|
|||
public Builder setFederated(Boolean isFederated) { | |||
if (isFederated != null && isFederated) { |
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
...us/service/src/test/java/org/apache/polaris/service/quarkus/admin/ManagementServiceTest.java
Show resolved
Hide resolved
@@ -871,6 +873,42 @@ public void testCreatePrincipalAndRotateCredentials() { | |||
// rotation that makes the old secret fall off retention. | |||
} | |||
|
|||
@Test | |||
public void testCreateFederatedPrincipalFails() { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)) { |
There was a problem hiding this comment.
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
🤔
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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.
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, butFEDERATED
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).