diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java index af657bf40b4..df50aec27c4 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java @@ -477,7 +477,8 @@ public class TableRepository extends EntityRepository { tableProfiles, startTs.toString(), endTs.toString(), tableProfiles.size()); } - public ResultList getColumnProfiles(String fqn, Long startTs, Long endTs) { + public ResultList getColumnProfiles( + String fqn, Long startTs, Long endTs, boolean authorizePII) { List columnProfiles; columnProfiles = JsonUtils.readObjects( @@ -490,8 +491,15 @@ public class TableRepository extends EntityRepository
{ endTs, EntityTimeSeriesDAO.OrderBy.DESC), ColumnProfile.class); - return new ResultList<>( - columnProfiles, startTs.toString(), endTs.toString(), columnProfiles.size()); + ResultList columnProfileResultList = + new ResultList<>( + columnProfiles, startTs.toString(), endTs.toString(), columnProfiles.size()); + if (!authorizePII) { + // Mask the PII data + columnProfileResultList.setData( + PIIMasker.getColumnProfile(fqn, columnProfileResultList.getData())); + } + return columnProfileResultList; } public ResultList getSystemProfiles(String fqn, Long startTs, Long endTs) { diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/resources/databases/TableResource.java b/openmetadata-service/src/main/java/org/openmetadata/service/resources/databases/TableResource.java index f5a0efafa36..13ecbe916b6 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/resources/databases/TableResource.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/resources/databases/TableResource.java @@ -75,6 +75,7 @@ import org.openmetadata.service.resources.EntityResource; import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.policyevaluator.OperationContext; import org.openmetadata.service.security.policyevaluator.ResourceContext; +import org.openmetadata.service.util.FullyQualifiedName; import org.openmetadata.service.util.JsonUtils; import org.openmetadata.service.util.ResultList; @@ -926,8 +927,13 @@ public class TableResource extends EntityResource { Long endTs) { OperationContext operationContext = new OperationContext(entityType, MetadataOperation.VIEW_DATA_PROFILE); - authorizer.authorize(securityContext, operationContext, getResourceContextByName(fqn)); - return repository.getColumnProfiles(fqn, startTs, endTs); + String tableFqn = + FullyQualifiedName.getTableFQN( + fqn); // get table fqn for the resource context (vs column fqn) + ResourceContext resourceContext = getResourceContextByName(tableFqn); + authorizer.authorize(securityContext, operationContext, resourceContext); + boolean authorizePII = authorizer.authorizePII(securityContext, resourceContext.getOwner()); + return repository.getColumnProfiles(fqn, startTs, endTs, authorizePII); } @GET diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/mask/PIIMasker.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/mask/PIIMasker.java index fdb68290f01..7c3fab0fa26 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/security/mask/PIIMasker.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/mask/PIIMasker.java @@ -3,6 +3,7 @@ package org.openmetadata.service.security.mask; import static org.openmetadata.common.utils.CommonUtil.listOrEmpty; import static org.openmetadata.service.jdbi3.TopicRepository.getAllFieldTags; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -20,6 +21,7 @@ import org.openmetadata.schema.entity.data.Topic; import org.openmetadata.schema.entity.teams.User; import org.openmetadata.schema.tests.TestCase; import org.openmetadata.schema.type.Column; +import org.openmetadata.schema.type.ColumnProfile; import org.openmetadata.schema.type.Field; import org.openmetadata.schema.type.Include; import org.openmetadata.schema.type.TableData; @@ -30,6 +32,7 @@ import org.openmetadata.service.Entity; import org.openmetadata.service.jdbi3.ColumnUtil; import org.openmetadata.service.resources.feeds.MessageParser; import org.openmetadata.service.security.Authorizer; +import org.openmetadata.service.util.FullyQualifiedName; import org.openmetadata.service.util.ResultList; public class PIIMasker { @@ -137,6 +140,22 @@ public class PIIMasker { return table; } + public static List getColumnProfile( + String fqn, List columnProfiles) { + Table table = + Entity.getEntityByName( + Entity.TABLE, FullyQualifiedName.getTableFQN(fqn), "columns,tags", Include.ALL); + Column column = + table.getColumns().stream() + .filter(c -> c.getFullyQualifiedName().equals(fqn)) + .findFirst() + .orElse(null); + if (column != null && hasPiiSensitiveTag(column)) { + return Collections.nCopies(columnProfiles.size(), new ColumnProfile()); + } + return columnProfiles; + } + private static TestCase getTestCase(Column column, TestCase testCase) { if (!hasPiiSensitiveTag(column)) return testCase; diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java index adc7ff32947..2d0cec789c3 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java @@ -2484,15 +2484,38 @@ public class TableResourceTest extends EntityResourceTest { createRequest(test, 1).withOwner(USER_TEAM21.getEntityReference()), ADMIN_AUTH_HEADERS); putTableProfile(table, table1, ADMIN_AUTH_HEADERS); + Column c3 = table.getColumns().stream().filter(c -> c.getName().equals(C3)).findFirst().get(); + // Owner can read the column profile of C3 Table tableWithProfileFromOwner = getLatestTableProfile(table.getFullyQualifiedName(), authHeaders(USER_TEAM21.getName())); assertNotNull(tableWithProfileFromOwner.getColumns().get(2).getProfile()); + ResultList columnProfiles = + getColumnProfiles( + c3.getFullyQualifiedName(), + TestUtils.dateToTimestamp("2021-09-01"), + TestUtils.dateToTimestamp("2021-09-30"), + authHeaders(USER_TEAM21.getName())); + for (ColumnProfile columnProfile : columnProfiles.getData()) { + assertNotNull(columnProfile.getMax()); + assertNotNull(columnProfile.getMin()); + } // Non owners cannot read the column profile of C3 Table tableWithProfileFromNotOwner = getLatestTableProfile(table.getFullyQualifiedName(), authHeaders(USER1_REF.getName())); assertNull(tableWithProfileFromNotOwner.getColumns().get(2).getProfile()); + ResultList maskedColumnProfiles = + getColumnProfiles( + c3.getFullyQualifiedName(), + TestUtils.dateToTimestamp("2021-09-01"), + TestUtils.dateToTimestamp("2021-09-30"), + authHeaders(USER1_REF.getName())); + for (ColumnProfile columnProfile : maskedColumnProfiles.getData()) { + assertNull(columnProfile.getMax()); + assertNull(columnProfile.getMin()); + } + assertEquals(maskedColumnProfiles.getData().size(), columnProfiles.getData().size()); } @Test