Add REST endpoints for bulk tagging & un-tagging of projects

Signed-off-by: nscuro <nscuro@protonmail.com>
This commit is contained in:
nscuro 2024-06-29 19:42:44 +02:00
parent a0407b46af
commit c41717f515
No known key found for this signature in database
8 changed files with 498 additions and 50 deletions

View file

@ -31,6 +31,7 @@ import alpine.resources.AlpineRequest;
import com.github.packageurl.PackageURL;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.datanucleus.api.jdo.JDOQuery;
import org.dependencytrack.auth.Permissions;
import org.dependencytrack.event.IndexEvent;
import org.dependencytrack.model.Analysis;
@ -55,6 +56,8 @@ import org.dependencytrack.util.NotificationUtil;
import javax.jdo.FetchPlan;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.metadata.MemberMetadata;
import javax.jdo.metadata.TypeMetadata;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
@ -894,7 +897,36 @@ final class ProjectQueryManager extends QueryManager implements IQueryManager {
/**
* A similar method exists in ComponentQueryManager
*/
private void preprocessACLs(final Query<Project> query, final String inputFilter, final Map<String, Object> params, final boolean bypass) {
@Override
void preprocessACLs(final Query<?> query, final String inputFilter, final Map<String, Object> params, final boolean bypass) {
String projectMemberFieldName = null;
final org.datanucleus.store.query.Query<?> internalQuery = ((JDOQuery<?>)query).getInternalQuery();
if (!Project.class.equals(internalQuery.getCandidateClass())) {
// NB: The query does not directly target Project, but if it has a relationship
// with Project we can still make the ACL check work. If the query candidate
// has EXACTLY one persistent field of type Project, we'll use that.
// If there are more than one, or none at all, we fail to avoid unintentional behavior.
final TypeMetadata candidateTypeMetadata = pm.getPersistenceManagerFactory().getMetadata(internalQuery.getCandidateClassName());
for (final MemberMetadata memberMetadata : candidateTypeMetadata.getMembers()) {
if (!Project.class.getName().equals(memberMetadata.getFieldType())) {
continue;
}
if (projectMemberFieldName != null) {
throw new IllegalArgumentException("Query candidate class %s has multiple members of type %s"
.formatted(internalQuery.getCandidateClassName(), Project.class.getName()));
}
projectMemberFieldName = memberMetadata.getName();
}
if (projectMemberFieldName == null) {
throw new IllegalArgumentException("Query candidate class %s has no member of type %s"
.formatted(internalQuery.getCandidateClassName(), Project.class.getName()));
}
}
if (super.principal != null && isEnabled(ConfigPropertyConstants.ACCESS_MANAGEMENT_ACL_ENABLED) && !bypass) {
final List<Team> teams;
if (super.principal instanceof final UserPrincipal userPrincipal) {
@ -911,10 +943,14 @@ final class ProjectQueryManager extends QueryManager implements IQueryManager {
return;
}
}
if (teams != null && teams.size() > 0) {
if (teams != null && !teams.isEmpty()) {
final StringBuilder sb = new StringBuilder();
for (int i = 0, teamsSize = teams.size(); i < teamsSize; i++) {
final Team team = super.getObjectById(Team.class, teams.get(i).getId());
sb.append(" ");
if (projectMemberFieldName != null) {
sb.append(projectMemberFieldName).append(".");
}
sb.append(" accessTeams.contains(:team").append(i).append(") ");
params.put("team" + i, team);
if (i < teamsSize-1) {
@ -922,7 +958,7 @@ final class ProjectQueryManager extends QueryManager implements IQueryManager {
}
}
if (inputFilter != null && !inputFilter.isBlank()) {
query.setFilter(inputFilter + " && (" + sb.toString() + ")");
query.setFilter(inputFilter + " && (" + sb + ")");
} else {
query.setFilter(sb.toString());
}