Skip to content

Commit

Permalink
Cleanup temporary workarounds; Apply granular permissions to new tag …
Browse files Browse the repository at this point in the history
…endpoints

Ports DependencyTrack/dependency-track#3947 from Dependency-Track v4.12.0.

Also applies the new granular CRUD permissions to new tag resources.

Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro committed Sep 26, 2024
1 parent a3d83f7 commit ba80ce8
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 158 deletions.
86 changes: 36 additions & 50 deletions src/main/java/org/dependencytrack/persistence/TagQueryManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,14 @@ public List<TagListRow> getTags() {
sqlQuery += " ORDER BY \"%s\" %s, \"ID\" ASC".formatted(orderBy,
orderDirection == OrderDirection.DESCENDING ? "DESC" : "ASC");
} else {
// TODO: Throw NotSortableException once Alpine opens up its constructor.
throw new IllegalArgumentException("Cannot sort by " + orderBy);
throw new NotSortableException("Tag", orderBy, "Field does not exist or is not sortable");
}

sqlQuery += " " + getOffsetLimitSqlClause();

final Query<?> query = pm.newQuery(Query.SQL, sqlQuery);
query.setNamedParameters(params);
try {
return new ArrayList<>(query.executeResultList(TagListRow.class));
} finally {
query.closeAll();
}
return executeAndCloseResultList(query, TagListRow.class);
}

/**
Expand Down Expand Up @@ -207,12 +202,8 @@ public void deleteTags(final Collection<String> tagNames) {
WHERE %s
""".formatted(projectAclCondition, String.join(" OR ", tagNameFilters)));
candidateQuery.setNamedParameters(params);
final List<TagDeletionCandidateRow> candidateRows;
try {
candidateRows = List.copyOf(candidateQuery.executeResultList(TagDeletionCandidateRow.class));
} finally {
candidateQuery.closeAll();
}
final List<TagDeletionCandidateRow> candidateRows =
executeAndCloseResultList(candidateQuery, TagDeletionCandidateRow.class);

final var errorByTagName = new HashMap<String, String>();

Expand All @@ -229,30 +220,37 @@ public void deleteTags(final Collection<String> tagNames) {
throw TagOperationFailedException.forDeletion(errorByTagName);
}

boolean hasPortfolioManagementPermission = false;
boolean hasPolicyManagementPermission = false;
boolean hasSystemConfigurationPermission = false;
boolean hasPortfolioManagementUpdatePermission = false;
boolean hasPolicyManagementUpdatePermission = false;
boolean hasSystemConfigurationUpdatePermission = false;
if (principal == null) {
hasPortfolioManagementPermission = true;
hasPolicyManagementPermission = true;
hasSystemConfigurationPermission = true;
hasPortfolioManagementUpdatePermission = true;
hasPolicyManagementUpdatePermission = true;
hasSystemConfigurationUpdatePermission = true;
} else {
if (principal instanceof final ApiKey apiKey) {
hasPortfolioManagementPermission = hasPermission(apiKey, Permissions.Constants.PORTFOLIO_MANAGEMENT);
hasPolicyManagementPermission = hasPermission(apiKey, Permissions.Constants.POLICY_MANAGEMENT);
hasSystemConfigurationPermission = hasPermission(apiKey, Permissions.Constants.SYSTEM_CONFIGURATION);
hasPortfolioManagementUpdatePermission = hasPermission(apiKey, Permissions.Constants.PORTFOLIO_MANAGEMENT)
|| hasPermission(apiKey, Permissions.Constants.PORTFOLIO_MANAGEMENT_UPDATE);
hasPolicyManagementUpdatePermission = hasPermission(apiKey, Permissions.Constants.POLICY_MANAGEMENT)
|| hasPermission(apiKey, Permissions.Constants.POLICY_MANAGEMENT_UPDATE);
hasSystemConfigurationUpdatePermission = hasPermission(apiKey, Permissions.Constants.SYSTEM_CONFIGURATION)
|| hasPermission(apiKey, Permissions.Constants.SYSTEM_CONFIGURATION_UPDATE);
} else if (principal instanceof final UserPrincipal user) {
hasPortfolioManagementPermission = hasPermission(user, Permissions.Constants.PORTFOLIO_MANAGEMENT, /* includeTeams */ true);
hasPolicyManagementPermission = hasPermission(user, Permissions.Constants.POLICY_MANAGEMENT, /* includeTeams */ true);
hasSystemConfigurationPermission = hasPermission(user, Permissions.Constants.SYSTEM_CONFIGURATION, /* includeTeams */ true);
hasPortfolioManagementUpdatePermission = hasPermission(user, Permissions.Constants.PORTFOLIO_MANAGEMENT, /* includeTeams */ true)
|| hasPermission(user, Permissions.Constants.PORTFOLIO_MANAGEMENT_UPDATE, /* includeTeams */ true);
hasPolicyManagementUpdatePermission = hasPermission(user, Permissions.Constants.POLICY_MANAGEMENT, /* includeTeams */ true)
|| hasPermission(user, Permissions.Constants.POLICY_MANAGEMENT_UPDATE, /* includeTeams */ true);
hasSystemConfigurationUpdatePermission = hasPermission(user, Permissions.Constants.SYSTEM_CONFIGURATION, /* includeTeams */ true)
|| hasPermission(user, Permissions.Constants.SYSTEM_CONFIGURATION_UPDATE, /* includeTeams */ true);
}
}

for (final TagDeletionCandidateRow row : candidateRows) {
if (row.projectCount() > 0 && !hasPortfolioManagementPermission) {
if (row.projectCount() > 0 && !hasPortfolioManagementUpdatePermission) {
errorByTagName.put(row.name(), """
The tag is assigned to %d project(s), but the authenticated principal \
is missing the %s permission.""".formatted(row.projectCount(), Permissions.PORTFOLIO_MANAGEMENT));
is missing the %s or %s permission.""".formatted(row.projectCount(),
Permissions.PORTFOLIO_MANAGEMENT, Permissions.PORTFOLIO_MANAGEMENT_UPDATE));
continue;
}

Expand All @@ -265,16 +263,18 @@ public void deleteTags(final Collection<String> tagNames) {
continue;
}

if (row.policyCount() > 0 && !hasPolicyManagementPermission) {
if (row.policyCount() > 0 && !hasPolicyManagementUpdatePermission) {
errorByTagName.put(row.name(), """
The tag is assigned to %d policies, but the authenticated principal \
is missing the %s permission.""".formatted(row.policyCount(), Permissions.POLICY_MANAGEMENT));
is missing the %s or %s permission.""".formatted(row.policyCount(),
Permissions.POLICY_MANAGEMENT, Permissions.POLICY_MANAGEMENT_UPDATE));
}

if (row.notificationRuleCount() > 0 && !hasSystemConfigurationPermission) {
if (row.notificationRuleCount() > 0 && !hasSystemConfigurationUpdatePermission) {
errorByTagName.put(row.name(), """
The tag is assigned to %d notification rules, but the authenticated principal \
is missing the %s permission.""".formatted(row.notificationRuleCount(), Permissions.SYSTEM_CONFIGURATION));
is missing the %s or %s permission.""".formatted(row.notificationRuleCount(),
Permissions.SYSTEM_CONFIGURATION, Permissions.SYSTEM_CONFIGURATION_UPDATE));
}
}

Expand Down Expand Up @@ -330,19 +330,14 @@ public List<TaggedProjectRow> getTaggedProjects(final String tagName) {
sqlQuery += " ORDER BY \"%s\" %s, \"ID\" ASC".formatted(orderBy,
orderDirection == OrderDirection.DESCENDING ? "DESC" : "ASC");
} else {
// TODO: Throw NotSortableException once Alpine opens up its constructor.
throw new IllegalArgumentException("Cannot sort by " + orderBy);
throw new NotSortableException("TaggedProject", orderBy, "Field does not exist or is not sortable");
}

sqlQuery += " " + getOffsetLimitSqlClause();

final Query<?> query = pm.newQuery(Query.SQL, sqlQuery);
query.setNamedParameters(params);
try {
return new ArrayList<>(query.executeResultList(TaggedProjectRow.class));
} finally {
query.closeAll();
}
return executeAndCloseResultList(query, TaggedProjectRow.class);
}

/**
Expand Down Expand Up @@ -440,19 +435,14 @@ public List<TaggedPolicyRow> getTaggedPolicies(final String tagName) {
sqlQuery += " ORDER BY \"%s\" %s".formatted(orderBy,
orderDirection == OrderDirection.DESCENDING ? "DESC" : "ASC");
} else {
// TODO: Throw NotSortableException once Alpine opens up its constructor.
throw new IllegalArgumentException("Cannot sort by " + orderBy);
throw new NotSortableException("TaggedPolicy", orderBy, "Field does not exist or is not sortable");
}

sqlQuery += " " + getOffsetLimitSqlClause();

final Query<?> query = pm.newQuery(Query.SQL, sqlQuery);
query.setNamedParameters(params);
try {
return new ArrayList<>(query.executeResultList(TaggedPolicyRow.class));
} finally {
query.closeAll();
}
return executeAndCloseResultList(query, TaggedPolicyRow.class);
}

/**
Expand Down Expand Up @@ -660,11 +650,7 @@ public List<TaggedNotificationRuleRow> getTaggedNotificationRules(final String t

final Query<?> query = pm.newQuery(Query.SQL, sqlQuery);
query.setNamedParameters(params);
try {
return new ArrayList<>(query.executeResultList(TaggedNotificationRuleRow.class));
} finally {
query.closeAll();
}
return executeAndCloseResultList(query, TaggedNotificationRuleRow.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,16 +538,11 @@ static void validate(final byte[] bomBytes, final Project project) {
problemDetails.setErrors(e.getValidationErrors());
}

final Response response = Response.status(Response.Status.BAD_REQUEST)
.header("Content-Type", ProblemDetails.MEDIA_TYPE_JSON)
.entity(problemDetails)
.build();

final var bomEncoded = Base64.getEncoder()
.encodeToString(bomBytes);
dispatchBomValidationFailedNotification(project, bomEncoded, problemDetails.getErrors());

throw new WebApplicationException(response);
throw new WebApplicationException(problemDetails.toResponse());
} catch (RuntimeException e) {
LOGGER.error("Failed to validate BOM", e);
final Response response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
Expand Down
Loading

0 comments on commit ba80ce8

Please sign in to comment.