Skip to content
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

feat(auth): platform instance ownership in policies #8396

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6c49801
feat(auth): platform instance ownership added in policies
amanda-her Jul 5, 2023
cc25870
tests and front-end
amanda-her Jul 6, 2023
6e2d686
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 10, 2023
199ab5b
remove files
amanda-her Jul 10, 2023
2e7e6a1
remove schema file
amanda-her Jul 10, 2023
4db96bf
feat(ingest): add formatting
amanda-her Jul 10, 2023
b70f4ea
feat(ingest): revert some changes and fix policyUtils
amanda-her Jul 10, 2023
f68cee6
feat(ingest): adding PlatformInstanceFieldResolverProvider
amanda-her Jul 11, 2023
d691b40
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 11, 2023
173a397
feat(ingest): fix format in PolicyUpdateInputInfoMapper
amanda-her Jul 11, 2023
5fd57ce
feat(auth): fix formatting and tests
amanda-her Jul 12, 2023
a1af3f8
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 12, 2023
ba43738
feat(auth): fix tests
amanda-her Jul 12, 2023
a40720c
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 12, 2023
fb37de2
feat(auth): update doc
amanda-her Jul 12, 2023
5654a6b
feat(auth): remove doc
amanda-her Jul 13, 2023
bc810d7
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 13, 2023
7afcf37
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 13, 2023
8654913
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 17, 2023
b502619
Merge branch 'master' into feat/platform_instance_ownerhip_in_policies
amanda-her Jul 20, 2023
5eac18e
Merge branch 'datahub-project:master' into feat/platform_instance_own…
amanda-her Sep 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1719,9 +1719,12 @@ private void configurePolicyResolvers(final RuntimeWiring.Builder builder) {
})).dataFetcher("resolvedRoles", new LoadableTypeBatchResolver<>(dataHubRoleType, (env) -> {
final ActorFilter filter = env.getSource();
return filter.getRoles();
})).dataFetcher("resolvedOwnershipTypes", new LoadableTypeBatchResolver<>(ownershipType, (env) -> {
})).dataFetcher("resolvedResourceOwnershipTypes", new LoadableTypeBatchResolver<>(ownershipType, (env) -> {
final ActorFilter filter = env.getSource();
return filter.getResourceOwnersTypes();
})).dataFetcher("resolvedPlatformInstanceOwnershipTypes", new LoadableTypeBatchResolver<>(ownershipType, (env) -> {
final ActorFilter filter = env.getSource();
return filter.getPlatformInstanceOwnersTypes();
})));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ private ActorFilter mapActors(final DataHubActorFilter actorFilter) {
result.setAllGroups(actorFilter.isAllGroups());
result.setAllUsers(actorFilter.isAllUsers());
result.setResourceOwners(actorFilter.isResourceOwners());
result.setPlatformInstanceOwners(actorFilter.isPlatformInstanceOwners());
UrnArray resourceOwnersTypes = actorFilter.getResourceOwnersTypes();
if (resourceOwnersTypes != null) {
result.setResourceOwnersTypes(resourceOwnersTypes.stream().map(Urn::toString).collect(Collectors.toList()));
}
UrnArray platformInstanceOwnersTypes = actorFilter.getPlatformInstanceOwnersTypes();
if (platformInstanceOwnersTypes != null) {
result.setPlatformInstanceOwnersTypes(platformInstanceOwnersTypes.stream().map(Urn::toString).collect(Collectors.toList()));
}
if (actorFilter.hasGroups()) {
result.setGroups(actorFilter.getGroups().stream().map(Urn::toString).collect(Collectors.toList()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,16 @@ private DataHubActorFilter mapActors(final ActorFilterInput actorInput) {
result.setAllGroups(actorInput.getAllGroups());
result.setAllUsers(actorInput.getAllUsers());
result.setResourceOwners(actorInput.getResourceOwners());
result.setPlatformInstanceOwners(actorInput.getPlatformInstanceOwners());
if (actorInput.getResourceOwnersTypes() != null) {
result.setResourceOwnersTypes(new UrnArray(actorInput.getResourceOwnersTypes().stream().map(this::createUrn).collect(Collectors.toList())));
result.setResourceOwnersTypes(
new UrnArray(actorInput.getResourceOwnersTypes().stream().map(this::createUrn).collect(Collectors.toList()))
);
}
if (actorInput.getPlatformInstanceOwnersTypes() != null) {
result.setPlatformInstanceOwnersTypes(
new UrnArray(actorInput.getPlatformInstanceOwnersTypes().stream().map(this::createUrn).collect(Collectors.toList()))
);
}
if (actorInput.getGroups() != null) {
result.setGroups(new UrnArray(actorInput.getGroups().stream().map(this::createUrn).collect(Collectors.toList())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,16 @@ private ActorFilter mapActors(final DataHubActorFilter actorFilter) {
result.setAllGroups(actorFilter.isAllGroups());
result.setAllUsers(actorFilter.isAllUsers());
result.setResourceOwners(actorFilter.isResourceOwners());
result.setPlatformInstanceOwners(actorFilter.isPlatformInstanceOwners());
// Change here is not executed at the moment - leaving it for the future
UrnArray resourceOwnersTypes = actorFilter.getResourceOwnersTypes();
if (resourceOwnersTypes != null) {
result.setResourceOwnersTypes(resourceOwnersTypes.stream().map(Urn::toString).collect(Collectors.toList()));
}
UrnArray platformInstanceOwnersTypes = actorFilter.getPlatformInstanceOwnersTypes();
if (platformInstanceOwnersTypes != null) {
result.setPlatformInstanceOwnersTypes(platformInstanceOwnersTypes.stream().map(Urn::toString).collect(Collectors.toList()));
}
if (actorFilter.hasGroups()) {
result.setGroups(actorFilter.getGroups().stream().map(Urn::toString).collect(Collectors.toList()));
}
Expand Down
29 changes: 28 additions & 1 deletion datahub-graphql-core/src/main/resources/entity.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8122,7 +8122,23 @@ type ActorFilter {
"""
Set of OwnershipTypes to apply the policy to (if resourceOwners field is set to True), resolved.
"""
resolvedOwnershipTypes: [OwnershipTypeEntity!]
resolvedResourceOwnershipTypes: [OwnershipTypeEntity!]

"""
Whether the filter should return TRUE for platform instance owners of a particular resource
Only applies to policies of type METADATA, which have a resource associated with them
"""
platformInstanceOwners: Boolean!

"""
Set of OwnershipTypes to apply the policy to (if platformInstanceOwners field is set to True)
"""
platformInstanceOwnersTypes: [String!]

"""
Set of OwnershipTypes to apply the policy to (if platformInstanceOwners field is set to True), resolved.
"""
resolvedPlatformInstanceOwnershipTypes: [OwnershipTypeEntity!]

"""
Whether the filter should apply to all users
Expand Down Expand Up @@ -8257,6 +8273,17 @@ input ActorFilterInput {
"""
resourceOwnersTypes: [String!]

"""
Whether the filter should return TRUE for platform instance owners of a particular resource
Only applies to policies of type METADATA, which have a resource associated with them
"""
platformInstanceOwners: Boolean!

"""
Set of OwnershipTypes to apply the policy to (if platformInstanceOwners field is set to True)
"""
platformInstanceOwnersTypes: [String!]

"""
Whether the filter should apply to all users
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ const toPolicyInput = (policy: Omit<Policy, 'urn'>): PolicyUpdateInput => {
allGroups: policy.actors.allGroups,
resourceOwners: policy.actors.resourceOwners,
resourceOwnersTypes: policy.actors.resourceOwnersTypes,
platformInstanceOwners: policy.actors.platformInstanceOwners,
platformInstanceOwnersTypes: policy.actors.platformInstanceOwnersTypes,
},
};
if (policy.resources !== null && policy.resources !== undefined) {
Expand Down Expand Up @@ -360,7 +362,8 @@ export const ManagePolicies = () => {
/>
{record?.allUsers ? <ActorTag>All Users</ActorTag> : null}
{record?.allGroups ? <ActorTag>All Groups</ActorTag> : null}
{record?.resourceOwners ? <ActorTag>All Owners</ActorTag> : null}
{record?.resourceOwners ? <ActorTag>All Resource Owners</ActorTag> : null}
{record?.platformInstanceOwners ? <ActorTag>All Platform Instance Owners</ActorTag> : null}
</>
);
},
Expand Down Expand Up @@ -430,6 +433,7 @@ export const ManagePolicies = () => {
allGroups: policy?.actors?.allGroups,
allUsers: policy?.actors?.allUsers,
resourceOwners: policy?.actors?.resourceOwners,
platformInstanceOwners: policy?.actors?.platformInstanceOwners,
description: policy?.description,
editable: policy?.editable,
name: policy?.name,
Expand Down
103 changes: 90 additions & 13 deletions datahub-web-react/src/app/permissions/policy/PolicyActorForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,59 @@ export default function PolicyActorForm({ policyType, actors, setActors }: Props
ownershipData?.listOwnershipTypes?.ownershipTypes.filter((type) => type.urn !== 'urn:li:ownershipType:none') ||
[];
const ownershipTypesMap = Object.fromEntries(ownershipTypes.map((type) => [type.urn, type.info?.name]));
// Toggle the "Owners" switch
const onToggleAppliesToOwners = (value: boolean) => {
// Toggle the "Resource Owners" switch
const onToggleAppliesToResourceOwners = (value: boolean) => {
setActors({
...actors,
resourceOwners: value,
resourceOwnersTypes: value ? actors.resourceOwnersTypes : null,
});
};

const onSelectOwnershipTypeActor = (newType: string) => {
const onSelectResourceOwnershipTypeActor = (newType: string) => {
const newResourceOwnersTypes: Maybe<string[]> = [...(actors.resourceOwnersTypes || []), newType];
setActors({
...actors,
resourceOwnersTypes: newResourceOwnersTypes,
});
};

const onDeselectOwnershipTypeActor = (type: string) => {
const onDeselectResourceOwnershipTypeActor = (type: string) => {
const newResourceOwnersTypes: Maybe<string[]> = actors.resourceOwnersTypes?.filter((u: string) => u !== type);
setActors({
...actors,
resourceOwnersTypes: newResourceOwnersTypes?.length ? newResourceOwnersTypes : null,
});
};
// Toggle the "Platform Instance Owners" switch
const onToggleAppliesToPlatformInstanceOwners = (value: boolean) => {
setActors({
...actors,
platformInstanceOwners: value,
platformInstanceOwnersTypes: value ? actors.platformInstanceOwnersTypes : null,
});
};

const onSelectPlatformInstanceOwnershipTypeActor = (newType: string) => {
const newPlatformInstanceOwnersTypes: Maybe<string[]> = [
...(actors.platformInstanceOwnersTypes || []),
newType,
];
setActors({
...actors,
platformInstanceOwnersTypes: newPlatformInstanceOwnersTypes,
});
};

const onDeselectPlatformInstanceOwnershipTypeActor = (type: string) => {
const newPlatformInstanceOwnersTypes: Maybe<string[]> = actors.platformInstanceOwnersTypes?.filter(
(u: string) => u !== type,
);
setActors({
...actors,
platformInstanceOwnersTypes: newPlatformInstanceOwnersTypes?.length ? newPlatformInstanceOwnersTypes : null,
});
};

// When a user search result is selected, add the urn to the ActorFilter
const onSelectUserActor = (newUser: string) => {
Expand Down Expand Up @@ -206,7 +235,8 @@ export default function PolicyActorForm({ policyType, actors, setActors }: Props
// Select dropdown values.
const usersSelectValue = actors.allUsers ? ['All'] : actors.users || [];
const groupsSelectValue = actors.allGroups ? ['All'] : actors.groups || [];
const ownershipTypesSelectValue = actors.resourceOwnersTypes || [];
const resourceOwnershipTypesSelectValue = actors.resourceOwnersTypes || [];
const platformInstanceOwnershipTypesSelectValue = actors.platformInstanceOwnersTypes || [];

const tagRender = (props) => {
// eslint-disable-next-line react/prop-types
Expand Down Expand Up @@ -240,25 +270,72 @@ export default function PolicyActorForm({ policyType, actors, setActors }: Props
<Typography.Paragraph>Select the users & groups that this policy should apply to.</Typography.Paragraph>
</ActorFormHeader>
{showAppliesToOwners && (
<Form.Item label={<Typography.Text strong>Owners</Typography.Text>} labelAlign="right">
<Form.Item label={<Typography.Text strong>Resource Owners</Typography.Text>} labelAlign="right">
<Typography.Paragraph>
Whether this policy should be apply to owners of the Metadata asset. If true, those who are
marked as owners of a Metadata Asset, either directly or indirectly via a Group, will have the
selected privileges.
Whether this policy should apply to owners of the Metadata asset. If true, those who are marked
as owners of a Metadata Asset, either directly or indirectly via a Group, will have the selected
privileges.
</Typography.Paragraph>
<Switch size="small" checked={actors.resourceOwners} onChange={onToggleAppliesToOwners} />
<Switch size="small" checked={actors.resourceOwners} onChange={onToggleAppliesToResourceOwners} />
{actors.resourceOwners && (
<OwnershipWrapper>
<Typography.Paragraph>
List of types of ownership which will be used to match owners. If empty, the policies
will applied to any type of ownership.
</Typography.Paragraph>
<Select
value={ownershipTypesSelectValue}
value={resourceOwnershipTypesSelectValue}
mode="multiple"
placeholder="Ownership types"
onSelect={(asset: any) => onSelectResourceOwnershipTypeActor(asset)}
onDeselect={(asset: any) => onDeselectResourceOwnershipTypeActor(asset)}
tagRender={(tagProps) => {
return (
<Tag closable={tagProps.closable} onClose={tagProps.onClose}>
{ownershipTypesMap[tagProps.value.toString()]}
</Tag>
);
}}
>
{ownershipTypes.map((resOwnershipType) => {
return (
<Select.Option value={resOwnershipType.urn}>
{resOwnershipType?.info?.name}
</Select.Option>
);
})}
</Select>
</OwnershipWrapper>
)}
</Form.Item>
)}
{showAppliesToOwners && (
<Form.Item
label={<Typography.Text strong>Platform Instance Owners</Typography.Text>}
labelAlign="right"
>
<Typography.Paragraph>
Whether this policy should apply to platform instance owners of the Metadata asset. If true,
those who are marked as owners of the platform instance to which a Metadata Asset belongs to,
either directly or indirectly via a Group, will have the selected privileges.
</Typography.Paragraph>
<Switch
size="small"
checked={actors.platformInstanceOwners}
onChange={onToggleAppliesToPlatformInstanceOwners}
/>
{actors.platformInstanceOwners && (
<OwnershipWrapper>
<Typography.Paragraph>
List of types of ownership which will be used to match plafrom instance owners. If
empty, the policies will applied to any type of ownership.
</Typography.Paragraph>
<Select
value={platformInstanceOwnershipTypesSelectValue}
mode="multiple"
placeholder="Ownership types"
onSelect={(asset: any) => onSelectOwnershipTypeActor(asset)}
onDeselect={(asset: any) => onDeselectOwnershipTypeActor(asset)}
onSelect={(asset: any) => onSelectPlatformInstanceOwnershipTypeActor(asset)}
onDeselect={(asset: any) => onDeselectPlatformInstanceOwnershipTypeActor(asset)}
tagRender={(tagProps) => {
return (
<Tag closable={tagProps.closable} onClose={tagProps.onClose}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,26 @@ export default function PolicyDetailsModal({ policy, visible, onClose, privilege
if (!actors?.resourceOwners) {
return <PoliciesTag>No</PoliciesTag>;
}
if ((actors?.resolvedOwnershipTypes?.length ?? 0) > 0) {
if ((actors?.resolvedResourceOwnershipTypes?.length ?? 0) > 0) {
return (
<div>
{actors?.resolvedOwnershipTypes?.map((type) => (
{actors?.resolvedResourceOwnershipTypes?.map((type) => (
<PoliciesTag>{type.info.name}</PoliciesTag>
))}
</div>
);
}
return <PoliciesTag>Yes - All owners</PoliciesTag>;
};

const platformInstanceOwnersField = (actors) => {
if (!actors?.platformInstanceOwners) {
return <PoliciesTag>No</PoliciesTag>;
}
if ((actors?.resolvedPlatformInstanceOwnershipTypes?.length ?? 0) > 0) {
return (
<div>
{actors?.resolvedPlatformInstanceOwnershipTypes?.map((type) => (
<PoliciesTag>{type.info.name}</PoliciesTag>
))}
</div>
Expand Down Expand Up @@ -194,10 +210,15 @@ export default function PolicyDetailsModal({ policy, visible, onClose, privilege
))}
</Privileges>
<div>
<Typography.Title level={5}>Applies to Owners</Typography.Title>
<Typography.Title level={5}>Applies to Resource Owners</Typography.Title>
<ThinDivider />
{resourceOwnersField(policy?.actors)}
</div>
<div>
<Typography.Title level={5}>Applies to Platform InstanceOwners</Typography.Title>
<ThinDivider />
{platformInstanceOwnersField(policy?.actors)}
</div>
<div>
<Typography.Title level={5}>Applies to Users</Typography.Title>
<ThinDivider />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const EMPTY_POLICY = {
allUsers: false,
allGroups: false,
resourceOwners: false,
platformInstanceOwners: false,
},
editable: true,
};
Expand Down
10 changes: 9 additions & 1 deletion datahub-web-react/src/graphql/policy.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@ query listPolicies($input: ListPoliciesInput!) {
allGroups
resourceOwners
resourceOwnersTypes
resolvedOwnershipTypes {
resolvedResourceOwnershipTypes {
urn
info {
name
}
}
platformInstanceOwners
platformInstanceOwnersTypes
resolvedPlatformInstanceOwnershipTypes {
urn
info {
name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,18 @@ public String getDomain() {
}
return null;
}

/**
* Fetch the platform instance for a Resolved Resource Spec
* @return a Platform Instance or null if one does not exist.
*/
@Nullable
public String getPlatformInstance() {
if (!fieldResolvers.containsKey(ResourceFieldType.PLATFORM_INSTANCE)) {
return null;
}
Set<String> platformInstance = fieldResolvers.get(ResourceFieldType.PLATFORM_INSTANCE).getFieldValuesFuture().join().getValues();
assert platformInstance.size() == 1; // There should be a single platform instance.
return platformInstance.stream().findFirst().get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ public enum ResourceFieldType {
/**
* Domains of resource
*/
DOMAIN
DOMAIN,
/**
* Platform instance of resource
*/
PLATFORM_INSTANCE
}
Loading
Loading