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

Permission deconstruction #800

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 50 additions & 4 deletions src/main/java/org/dependencytrack/auth/Permissions.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,38 @@ public enum Permissions {
BOM_UPLOAD("Allows the ability to upload CycloneDX Software Bill of Materials (SBOM)"),
VIEW_PORTFOLIO("Provides the ability to view the portfolio of projects, components, and licenses"),
PORTFOLIO_MANAGEMENT("Allows the creation, modification, and deletion of data in the portfolio"),
PORTFOLIO_MANAGEMENT_CREATE("Allows the creation of data in the portfolio"),
PORTFOLIO_MANAGEMENT_READ("Allows the reading of data in the portfolio"),
PORTFOLIO_MANAGEMENT_UPDATE("Allows the updating of data in the portfolio"),
PORTFOLIO_MANAGEMENT_DELETE("Allows the deletion of data in the portfolio"),
VIEW_VULNERABILITY("Provides the ability to view the vulnerabilities projects are affected by"),
VULNERABILITY_ANALYSIS("Provides the ability to make analysis decisions on vulnerabilities"),
VULNERABILITY_ANALYSIS("Provides all abilities to make analysis decisions on vulnerabilities"),
VULNERABILITY_ANALYSIS_CREATE("Provides the ability to upload supported VEX documents to a project"),
VULNERABILITY_ANALYSIS_READ("Provides the ability read the VEX document for a project"),
VULNERABILITY_ANALYSIS_UPDATE("Provides the ability to make analysis decisions on vulnerabilities and upload supported VEX documents for a project"),
VIEW_POLICY_VIOLATION("Provides the ability to view policy violations"),
VULNERABILITY_MANAGEMENT("Allows management of internally-defined vulnerabilities"),
VULNERABILITY_MANAGEMENT("Allows all management permissions of internally-defined vulnerabilities"),
VULNERABILITY_MANAGEMENT_CREATE("Allows creation of internally-defined vulnerabilities"),
VULNERABILITY_MANAGEMENT_READ("Allows reading internally-defined vulnerabilities"),
VULNERABILITY_MANAGEMENT_UPDATE("Allows updating internally-defined vulnerabilities and vulnerability tags"),
VULNERABILITY_MANAGEMENT_DELETE("Allows management of internally-defined vulnerabilities"),
POLICY_VIOLATION_ANALYSIS("Provides the ability to make analysis decisions on policy violations"),
ACCESS_MANAGEMENT("Allows the management of users, teams, and API keys"),
SYSTEM_CONFIGURATION("Allows the configuration of the system including notifications, repositories, and email settings"),
ACCESS_MANAGEMENT_CREATE("Allows create permissions of users, teams, and API keys"),
ACCESS_MANAGEMENT_READ("Allows read permissions of users, teams, and API keys"),
ACCESS_MANAGEMENT_UPDATE("Allows update permissions of users, teams, and API keys"),
ACCESS_MANAGEMENT_DELETE("Allows delete permissions of users, teams, and API keys"),
SYSTEM_CONFIGURATION("Allows all access to configuration of the system including notifications, repositories, and email settings"),
SYSTEM_CONFIGURATION_CREATE("Allows creating configuration of the system including notifications, repositories, and email settings"),
SYSTEM_CONFIGURATION_READ("Allows reading the configuration of the system including notifications, repositories, and email settings"),
SYSTEM_CONFIGURATION_UPDATE("Allows updating the configuration of the system including notifications, repositories, and email settings"),
SYSTEM_CONFIGURATION_DELETE("Allows deleting the configuration of the system including notifications, repositories, and email settings"),
PROJECT_CREATION_UPLOAD("Provides the ability to optionally create project (if non-existent) on BOM or scan upload"),
POLICY_MANAGEMENT("Allows the creation, modification, and deletion of policy");
POLICY_MANAGEMENT("Allows the creation, modification, and deletion of policy"),
POLICY_MANAGEMENT_CREATE("Allows the creation of a policy"),
POLICY_MANAGEMENT_READ("Allows reading of policies"),
POLICY_MANAGEMENT_UPDATE("Allows the modification of a policy"),
POLICY_MANAGEMENT_DELETE("Allows the deletion of a policy");

private final String description;

Expand All @@ -53,15 +76,38 @@ public static class Constants {
public static final String BOM_UPLOAD = "BOM_UPLOAD";
public static final String VIEW_PORTFOLIO = "VIEW_PORTFOLIO";
public static final String PORTFOLIO_MANAGEMENT = "PORTFOLIO_MANAGEMENT";
public static final String PORTFOLIO_MANAGEMENT_CREATE = "PORTFOLIO_MANAGEMENT_CREATE";
public static final String PORTFOLIO_MANAGEMENT_READ = "PORTFOLIO_MANAGEMENT_READ";
public static final String PORTFOLIO_MANAGEMENT_UPDATE = "PORTFOLIO_MANAGEMENT_UPDATE";
public static final String PORTFOLIO_MANAGEMENT_DELETE = "PORTFOLIO_MANAGEMENT_DELETE";
public static final String VIEW_VULNERABILITY = "VIEW_VULNERABILITY";
public static final String VULNERABILITY_ANALYSIS = "VULNERABILITY_ANALYSIS";
public static final String VULNERABILITY_ANALYSIS_CREATE = "VULNERABILITY_ANALYSIS_CREATE";
public static final String VULNERABILITY_ANALYSIS_READ = "VULNERABILITY_ANALYSIS_READ";
public static final String VULNERABILITY_ANALYSIS_UPDATE = "VULNERABILITY_ANALYSIS_UPDATE";
public static final String VIEW_POLICY_VIOLATION = "VIEW_POLICY_VIOLATION";
public static final String VULNERABILITY_MANAGEMENT = "VULNERABILITY_MANAGEMENT";
public static final String VULNERABILITY_MANAGEMENT_CREATE = "VULNERABILITY_MANAGEMENT_CREATE";
public static final String VULNERABILITY_MANAGEMENT_READ = "VULNERABILITY_MANAGEMENT_READ";
public static final String VULNERABILITY_MANAGEMENT_UPDATE = "VULNERABILITY_MANAGEMENT_UPDATE";
public static final String VULNERABILITY_MANAGEMENT_DELETE = "VULNERABILITY_MANAGEMENT_DELETE";
public static final String POLICY_VIOLATION_ANALYSIS = "POLICY_VIOLATION_ANALYSIS";
public static final String ACCESS_MANAGEMENT = "ACCESS_MANAGEMENT";
public static final String ACCESS_MANAGEMENT_CREATE = "ACCESS_MANAGEMENT_CREATE";
public static final String ACCESS_MANAGEMENT_READ = "ACCESS_MANAGEMENT_READ";
public static final String ACCESS_MANAGEMENT_UPDATE = "ACCESS_MANAGEMENT_UPDATE";
public static final String ACCESS_MANAGEMENT_DELETE = "ACCESS_MANAGEMENT_DELETE";
public static final String SYSTEM_CONFIGURATION = "SYSTEM_CONFIGURATION";
public static final String SYSTEM_CONFIGURATION_CREATE = "SYSTEM_CONFIGURATION_CREATE";
public static final String SYSTEM_CONFIGURATION_READ = "SYSTEM_CONFIGURATION_READ";
public static final String SYSTEM_CONFIGURATION_UPDATE = "SYSTEM_CONFIGURATION_UPDATE";
public static final String SYSTEM_CONFIGURATION_DELETE = "SYSTEM_CONFIGURATION_DELETE";
public static final String PROJECT_CREATION_UPLOAD = "PROJECT_CREATION_UPLOAD";
public static final String POLICY_MANAGEMENT = "POLICY_MANAGEMENT";
public static final String POLICY_MANAGEMENT_CREATE = "POLICY_MANAGEMENT_CREATE";
public static final String POLICY_MANAGEMENT_READ = "POLICY_MANAGEMENT_READ";
public static final String POLICY_MANAGEMENT_UPDATE = "POLICY_MANAGEMENT_UPDATE";
public static final String POLICY_MANAGEMENT_DELETE = "POLICY_MANAGEMENT_DELETE";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ private List<Permission> getPortfolioManagersPermissions(final List<Permission>
final List<Permission> permissions = new ArrayList<>();
for (final Permission permission: fullList) {
if (permission.getName().equals(Permissions.Constants.VIEW_PORTFOLIO) ||
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT)) {
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT) ||
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE) ||
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT_READ) ||
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT_UPDATE) ||
permission.getName().equals(Permissions.Constants.PORTFOLIO_MANAGEMENT_DELETE)) {
permissions.add(permission);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class AccessControlResource extends AlpineResource {
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Returns the projects assigned to the specified team",
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong></p>"
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong> or <strong>ACCESS_MANAGEMENT_READ</strong></p>"
)
@PaginatedApi
@ApiResponses(value = {
Expand All @@ -87,7 +87,7 @@ public class AccessControlResource extends AlpineResource {
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The UUID of the team could not be found"),
})
@PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT)
@PermissionRequired({ Permissions.Constants.ACCESS_MANAGEMENT, Permissions.Constants.ACCESS_MANAGEMENT_READ })
public Response retrieveProjects(@Parameter(description = "The UUID of the team to retrieve mappings for", schema = @Schema(type = "string", format = "uuid"), required = true)
@PathParam("uuid") @ValidUuid String uuid,
@Parameter(description = "Optionally excludes inactive projects from being returned", required = false)
Expand Down Expand Up @@ -118,7 +118,7 @@ public Response retrieveProjects(@Parameter(description = "The UUID of the team
@ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"),
@ApiResponse(responseCode = "409", description = "A mapping with the same team and project already exists")
})
@PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT)
@PermissionRequired({Permissions.Constants.ACCESS_MANAGEMENT, Permissions.Constants.ACCESS_MANAGEMENT_CREATE})
public Response addMapping(AclMappingRequest request) {
final Validator validator = super.getValidator();
failOnValidationError(
Expand Down Expand Up @@ -148,13 +148,13 @@ public Response addMapping(AclMappingRequest request) {
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Removes an ACL mapping",
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong></p>"
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong> or <strong>ACCESS_MANAGEMENT_DELETE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"),
})
@PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT)
@PermissionRequired({Permissions.Constants.ACCESS_MANAGEMENT, Permissions.Constants.ACCESS_MANAGEMENT_DELETE})
public Response deleteMapping(
@Parameter(description = "The UUID of the team to delete the mapping for", schema = @Schema(type = "string", format = "uuid"), required = true)
@PathParam("teamUuid") @ValidUuid String teamUuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ public Response retrieveAnalysis(@Parameter(description = "The UUID of the proje
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Records an analysis decision",
description = "<p>Requires permission <strong>VULNERABILITY_ANALYSIS</strong></p>"
description = "<p>Requires permission <strong>VULNERABILITY_ANALYSIS</strong></strong> or <strong>VULNERABILITY_ANALYSIS_UPDATE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project, component, or vulnerability could not be found")
})
@PermissionRequired(Permissions.Constants.VULNERABILITY_ANALYSIS)
@PermissionRequired({Permissions.Constants.VULNERABILITY_ANALYSIS, Permissions.Constants.VULNERABILITY_ANALYSIS_UPDATE})
public Response updateAnalysis(AnalysisRequest request) {
final Validator validator = getValidator();
failOnValidationError(
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/dependencytrack/resources/v1/BomResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ public Response exportComponentAsCycloneDx(
then the <code>projectName</code> and <code>projectVersion</code> must be specified.
Optionally, if <code>autoCreate</code> is specified and <code>true</code> and the project does not exist,
the project will be created. In this scenario, the principal making the request will
additionally need the <strong>PORTFOLIO_MANAGEMENT</strong> or
<strong>PROJECT_CREATION_UPLOAD</strong> permission.
additionally need the <strong>PORTFOLIO_MANAGEMENT</strong>, <strong>PORTFOLIO_MANAGEMENT_CREATE</strong>,
or <strong>PROJECT_CREATION_UPLOAD</strong> permission.
</p>
<p>
The BOM will be validated against the CycloneDX schema. If schema validation fails,
Expand Down Expand Up @@ -274,7 +274,7 @@ public Response uploadBom(@Parameter(required = true) BomSubmitRequest request)
try (QueryManager qm = new QueryManager()) {
Project project = qm.getProject(request.getProjectName(), request.getProjectVersion());
if (project == null && request.isAutoCreate()) {
if (hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT) || hasPermission(Permissions.Constants.PROJECT_CREATION_UPLOAD)) {
if (hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT) || hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE) || hasPermission(Permissions.Constants.PROJECT_CREATION_UPLOAD)) {
Project parent = null;
if (request.getParentUUID() != null || request.getParentName() != null) {
if (request.getParentUUID() != null) {
Expand Down Expand Up @@ -320,8 +320,8 @@ public Response uploadBom(@Parameter(required = true) BomSubmitRequest request)
then the <code>projectName</code> and <code>projectVersion</code> must be specified.
Optionally, if <code>autoCreate</code> is specified and <code>true</code> and the project does not exist,
the project will be created. In this scenario, the principal making the request will
additionally need the <strong>PORTFOLIO_MANAGEMENT</strong> or
<strong>PROJECT_CREATION_UPLOAD</strong> permission.
additionally need the <strong>PORTFOLIO_MANAGEMENT</strong>, <strong>PORTFOLIO_MANAGEMENT_CREATE</strong>,
or <strong>PROJECT_CREATION_UPLOAD</strong> permission.
</p>
<p>
The BOM will be validated against the CycloneDX schema. If schema validation fails,
Expand Down Expand Up @@ -366,7 +366,7 @@ public Response uploadBom(
final String trimmedProjectVersion = StringUtils.trimToNull(projectVersion);
Project project = qm.getProject(trimmedProjectName, trimmedProjectVersion);
if (project == null && autoCreate) {
if (hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT) || hasPermission(Permissions.Constants.PROJECT_CREATION_UPLOAD)) {
if (hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT) || hasPermission(Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE) || hasPermission(Permissions.Constants.PROJECT_CREATION_UPLOAD)) {
Project parent = null;
if (parentUUID != null || parentName != null) {
if (parentUUID != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public Response getProperties(
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Creates a new component property",
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong></p>"
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong> or <strong>PORTFOLIO_MANAGEMENT_CREATE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ComponentProperty.class))),
Expand All @@ -115,7 +115,7 @@ public Response getProperties(
@ApiResponse(responseCode = "404", description = "The component could not be found"),
@ApiResponse(responseCode = "409", description = "A property with the specified component/group/name combination already exists")
})
@PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT)
@PermissionRequired({Permissions.Constants.PORTFOLIO_MANAGEMENT, Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE})
public Response createProperty(
@Parameter(description = "The UUID of the component to create a property for", schema = @Schema(type = "string", format = "uuid"), required = true)
@PathParam("uuid") @ValidUuid String uuid,
Expand Down Expand Up @@ -164,15 +164,15 @@ public Response createProperty(
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Deletes a config property",
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong></p>"
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong> or <strong>PORTFOLIO_MANAGEMENT_DELETE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "204"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"),
@ApiResponse(responseCode = "404", description = "The component or component property could not be found"),
})
@PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT)
@PermissionRequired({Permissions.Constants.PORTFOLIO_MANAGEMENT, Permissions.Constants.PORTFOLIO_MANAGEMENT_DELETE})
public Response deleteProperty(
@Parameter(description = "The UUID of the component to delete a property from", schema = @Schema(type = "string", format = "uuid"), required = true)
@PathParam("uuid") @ValidUuid final String componentUuid,
Expand Down
Loading