Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
23057e5
refactor: normalize permission model
jhoward-lm Jun 20, 2025
c32a1c4
Merge branch 'main' of https://github.com/DependencyTrack/hyades-apis…
jhoward-lm Jul 2, 2025
5498303
fix: accidental overwrite during resolve
jhoward-lm Jul 2, 2025
2c4e931
test: fix asserts
jhoward-lm Jul 2, 2025
b3d3882
test: enable portfolio access control where needed
jhoward-lm Jul 3, 2025
a68d944
fix: generated JDBI statement
jhoward-lm Jul 7, 2025
1b2ad79
test: fix asserts
jhoward-lm Jul 7, 2025
df7ddda
test: fix asserts
jhoward-lm Jul 7, 2025
082cac6
Merge branch 'main' of https://github.com/jhoward-lm/hyades-apiserver…
jhoward-lm Jul 9, 2025
aa48c35
chore: revert workaround
jhoward-lm Jul 9, 2025
f59b065
refactor: validate that only project-scoped permissions can be added …
jhoward-lm Jul 9, 2025
abcdfe4
chore: resolve PR conflict
jhoward-lm Jul 9, 2025
0ef25e7
refactor: add migration to update old permissions
jhoward-lm Jul 10, 2025
384b7e2
refactor: clean up migration DDL
jhoward-lm Jul 10, 2025
fb58cbb
refactor: use temp tables for migrations
jhoward-lm Jul 11, 2025
3eff73c
fix: population of existing permission map
jhoward-lm Jul 14, 2025
5891fd9
fix: update references to changed permission names
jhoward-lm Jul 14, 2025
d44ec9f
Merge branch 'main' into normalize-permission-model
jhoward-lm Jul 14, 2025
b442807
fix: checkstyle violation
jhoward-lm Jul 14, 2025
aa1306b
fix: update references to changed permission names
jhoward-lm Jul 14, 2025
b56ab2e
fix: permissions for update/patch projects
jhoward-lm Jul 21, 2025
527e98a
Merge branch 'main' of https://github.com/DependencyTrack/hyades-apis…
jhoward-lm Jul 21, 2025
64a49e4
fix: permissions in v2 resources
jhoward-lm Jul 21, 2025
ffaefaf
fix: permissions in v2 resources
jhoward-lm Jul 21, 2025
47534df
test: fix permission setup
jhoward-lm Jul 23, 2025
752229a
test: fix permission setup
jhoward-lm Jul 23, 2025
41f82d6
fix: notification rule resource permissions
jhoward-lm Jul 23, 2025
ec6b9fb
Merge branch 'main' of https://github.com/DependencyTrack/hyades-apis…
jhoward-lm Jul 24, 2025
d54ab29
fix: changeset permission names, address comments
jhoward-lm Jul 24, 2025
68665c4
fix: update v2 metrics resource
jhoward-lm Jul 24, 2025
b336128
Merge branch 'main' of github.com:DependencyTrack/hyades-apiserver in…
nscuro Jul 25, 2025
21b608b
Fix missing unique index on `PERMISSION.NAME`
nscuro Jul 25, 2025
f21cc84
Merge pull request #16 from DependencyTrack/normalize-permission-mode…
jhoward-lm Jul 25, 2025
b54a60e
refactor: use explicit AND/OR with PermissionRequired
jhoward-lm Jul 28, 2025
2bdf477
Merge branch 'main' of https://github.com/DependencyTrack/hyades-apis…
jhoward-lm Jul 31, 2025
22923ba
chore: create new changelog file
jhoward-lm Jul 31, 2025
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
136 changes: 59 additions & 77 deletions apiserver/src/main/java/org/dependencytrack/auth/Permissions.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,96 +26,78 @@
*/
public enum Permissions {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note so we don't forget:

  • Before this can be merged, we need a DB migration that reassigns any existing old permissions to their corresponding new counterparts.
  • Changes in frontend would also be required.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nscuro I added a change set for the migration. Not sure if it's what you were looking for, so any suggestions are welcome. Will work on the frontend tomorrow


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_ACCESS_CONTROL_BYPASS("Provides the ability to bypass portfolio access control, granting access to all projects"),
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 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 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"),
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_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"),
TAG_MANAGEMENT("Allows the modification and deletion of tags"),
TAG_MANAGEMENT_DELETE("Allows the deletion of a tag"),
VIEW_BADGES("Provides the ability to view badges");
// @formatter:off
ACCESS_MANAGEMENT("Allows the management of users, teams, and API keys", Scope.SYSTEM),
BADGES_READ("Provides the ability to view badges", Scope.PROJECT),
BOM_CREATE("Allows the ability to upload CycloneDX Software Bill of Materials (SBOM)", Scope.PROJECT),
BOM_READ("Allows the ability to view CycloneDX Software Bill of Materials (SBOM)", Scope.PROJECT),
FINDING_CREATE("Provides the ability to upload supported VEX documents to a project", Scope.PROJECT),
FINDING_READ("Provides the ability read the VEX document for a project", Scope.PROJECT),
FINDING_UPDATE("Provides the ability to make analysis decisions on vulnerabilities and upload supported VEX documents for a project", Scope.PROJECT),
NOTIFICATION_RULE("Allows configuration of notifications and email settings", Scope.SYSTEM),
POLICY_VIOLATION_CREATE("Provides the ability to create policy violations", Scope.PROJECT),
POLICY_VIOLATION_READ("Provides the ability to view policy violations", Scope.PROJECT),
POLICY_VIOLATION_UPDATE("Provides the ability to make analysis decisions on policy violations", Scope.PROJECT),
POLICY("Allows the creation, modification, and deletion of policy", Scope.SYSTEM),
PORTFOLIO_ACCESS_CONTROL_BYPASS("Provides the ability to bypass portfolio access control, granting access to all projects", Scope.SYSTEM),
PORTFOLIO("Allows the creation, modification, and deletion of data in the portfolio", Scope.SYSTEM),
PROJECT_DELETE("Provides the ability to delete resources within a project", Scope.PROJECT),
PROJECT_READ("Provides the ability to read resources within a project", Scope.PROJECT),
PROJECT_UPDATE("Provides the ability to update resources within a project", Scope.PROJECT),
SYSTEM_CONFIGURATION("Allows all access to configuration of the system including notifications, repositories, and email settings", Scope.SYSTEM),
TAG("Allows the management of global tag definitions", Scope.SYSTEM),
VULNERABILITY("Allows the management of custom vulnerabilities", Scope.SYSTEM);
// @formatter:on

enum Scope {
PROJECT, SYSTEM
}

private final String description;
private final Scope scope;

Permissions(final String description) {
Permissions(final String description, final Scope scope) {
this.description = description;
this.scope = scope;
}

public String getDescription() {
return description;
}

public Scope getScope() {
return scope;
}

public boolean isProject() {
return scope == Scope.PROJECT;
}

public boolean isSystem() {
return scope == Scope.SYSTEM;
}

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_ACCESS_CONTROL_BYPASS = Permissions.PORTFOLIO_ACCESS_CONTROL_BYPASS.name();
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 BADGES_READ = "BADGES_READ";
public static final String BOM_CREATE = "BOM_CREATE";
public static final String BOM_READ = "BOM_READ";
public static final String FINDING_CREATE = "FINDING_CREATE";
public static final String FINDING_READ = "FINDING_READ";
public static final String FINDING_UPDATE = "FINDING_UPDATE";
public static final String NOTIFICATION_RULE = "NOTIFICATION_RULE";
public static final String POLICY = "POLICY";
public static final String POLICY_VIOLATION_CREATE = "POLICY_VIOLATION_CREATE";
public static final String POLICY_VIOLATION_READ = "POLICY_VIOLATION_READ";
public static final String POLICY_VIOLATION_UPDATE = "POLICY_VIOLATION_UPDATE";
public static final String PORTFOLIO_ACCESS_CONTROL_BYPASS = "PORTFOLIO_ACCESS_CONTROL_BYPASS";
public static final String PORTFOLIO = "PORTFOLIO";
public static final String PROJECT_DELETE = "PROJECT_DELETE";
public static final String PROJECT_READ = "PROJECT_READ";
public static final String PROJECT_UPDATE = "PROJECT_UPDATE";
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";
public static final String TAG_MANAGEMENT = "TAG_MANAGEMENT";
public static final String TAG_MANAGEMENT_DELETE = "TAG_MANAGEMENT_DELETE";
public static final String VIEW_BADGES = "VIEW_BADGES";
public static final String TAG = "TAG";
public static final String VULNERABILITY = "VULNERABILITY";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,53 +67,45 @@ public class DefaultObjectGenerator implements ServletContextListener {
private static final Logger LOGGER = Logger.getLogger(DefaultObjectGenerator.class);

private static final Map<String, List<String>> DEFAULT_TEAM_PERMISSIONS = Map.of(
"Administrators", Stream.of(Permissions.values())
.map(Permissions::name)
.toList(),
"Portfolio Managers", List.of(
Permissions.Constants.VIEW_PORTFOLIO,
Permissions.Constants.PORTFOLIO_MANAGEMENT,
Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE,
Permissions.Constants.PORTFOLIO_MANAGEMENT_READ,
Permissions.Constants.PORTFOLIO_MANAGEMENT_UPDATE,
Permissions.Constants.PORTFOLIO_MANAGEMENT_DELETE),
"Automation", List.of(
Permissions.Constants.VIEW_PORTFOLIO,
Permissions.Constants.BOM_UPLOAD),
"Badge Viewers", List.of(
Permissions.Constants.VIEW_BADGES));
"Administrators", Stream.of(Permissions.values()).map(Permissions::name).toList(),
"Portfolio Managers", List.of(Permissions.Constants.PORTFOLIO),
"Automation", List.of(Permissions.Constants.PORTFOLIO, Permissions.Constants.BOM_CREATE),
"Badge Viewers", List.of(Permissions.Constants.BADGES_READ));

private static final Map<String, List<String>> DEFAULT_ROLE_PERMISSIONS = Map.of(
"Project Admin", List.of(
Permissions.Constants.PORTFOLIO_MANAGEMENT_CREATE,
Permissions.Constants.PORTFOLIO_MANAGEMENT_READ,
Permissions.Constants.PORTFOLIO_MANAGEMENT_UPDATE,
Permissions.Constants.PORTFOLIO_MANAGEMENT_DELETE,
Permissions.Constants.VULNERABILITY_ANALYSIS,
Permissions.Constants.VULNERABILITY_ANALYSIS_CREATE,
Permissions.Constants.VULNERABILITY_ANALYSIS_READ,
Permissions.Constants.VULNERABILITY_ANALYSIS_UPDATE,
Permissions.Constants.POLICY_MANAGEMENT,
Permissions.Constants.POLICY_MANAGEMENT_CREATE,
Permissions.Constants.POLICY_MANAGEMENT_READ,
Permissions.Constants.POLICY_MANAGEMENT_UPDATE,
Permissions.Constants.POLICY_MANAGEMENT_DELETE),
Permissions.Constants.BADGES_READ,
Permissions.Constants.BOM_READ,
Permissions.Constants.BOM_CREATE,
Permissions.Constants.FINDING_CREATE,
Permissions.Constants.FINDING_READ,
Permissions.Constants.FINDING_UPDATE,
Permissions.Constants.POLICY_VIOLATION_CREATE,
Permissions.Constants.POLICY_VIOLATION_READ,
Permissions.Constants.POLICY_VIOLATION_UPDATE,
Permissions.Constants.PROJECT_READ,
Permissions.Constants.PROJECT_UPDATE,
Permissions.Constants.PROJECT_DELETE),
"Project Auditor", List.of(
Permissions.Constants.VIEW_PORTFOLIO,
Permissions.Constants.VIEW_VULNERABILITY,
Permissions.Constants.VIEW_POLICY_VIOLATION,
Permissions.Constants.VULNERABILITY_ANALYSIS_READ),
Permissions.Constants.BADGES_READ,
Permissions.Constants.BOM_READ,
Permissions.Constants.FINDING_READ,
Permissions.Constants.POLICY_VIOLATION_READ,
Permissions.Constants.PROJECT_READ),
"Project Editor", List.of(
Permissions.Constants.BOM_UPLOAD,
Permissions.Constants.VIEW_PORTFOLIO,
Permissions.Constants.PORTFOLIO_MANAGEMENT_READ,
Permissions.Constants.VIEW_VULNERABILITY,
Permissions.Constants.VULNERABILITY_ANALYSIS_READ,
Permissions.Constants.PROJECT_CREATION_UPLOAD),
Permissions.Constants.BOM_CREATE,
Permissions.Constants.BOM_READ,
Permissions.Constants.FINDING_READ,
Permissions.Constants.FINDING_UPDATE,
Permissions.Constants.POLICY_VIOLATION_CREATE,
Permissions.Constants.POLICY_VIOLATION_READ,
Permissions.Constants.POLICY_VIOLATION_UPDATE,
Permissions.Constants.PROJECT_READ,
Permissions.Constants.PROJECT_UPDATE),
"Project Viewer", List.of(
Permissions.Constants.VIEW_PORTFOLIO,
Permissions.Constants.VIEW_VULNERABILITY,
Permissions.Constants.VIEW_BADGES));
Permissions.Constants.BADGES_READ,
Permissions.Constants.BOM_READ,
Permissions.Constants.PROJECT_READ));

private final Map<String, Permission> persistentPermissionByName = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ SELECT EXISTS(
ON ph."PARENT_PROJECT_ID" = upep."PROJECT_ID"
WHERE ph."CHILD_PROJECT_ID" = ?
AND upep."USER_ID" = ?
AND upep."PERMISSION_NAME" = 'VIEW_PORTFOLIO'
AND upep."PERMISSION_NAME" = 'PROJECT_READ'
)
""")
.setParameters(project.getId(), user.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1210,9 +1210,9 @@ public Set<String> getEffectivePermissions(Principal principal) {

List<UserProjectRole> userRoles = getUserRoles(user.getUsername());

// If a user has a role on any project, grant VIEW_PORTFOLIO permission
// If a user has a role on any project, grant PROJECT_READ permission
if (userRoles != null && !userRoles.isEmpty())
permissions.add(Permissions.Constants.VIEW_PORTFOLIO);
permissions.add(Permissions.Constants.PROJECT_READ);

return permissions;
}
Expand Down Expand Up @@ -1701,7 +1701,7 @@ public Map.Entry<String, Map<String, Object>> getProjectAclSqlCondition(final St
ON ph."PARENT_PROJECT_ID" = upep."PROJECT_ID"
WHERE ph."CHILD_PROJECT_ID" = "%s"."ID"
AND upep."USER_ID" = :projectAclUserId
AND upep."PERMISSION_NAME" = 'VIEW_PORTFOLIO'
AND upep."PERMISSION_NAME" = 'PROJECT_READ'
)
""";
}
Expand Down
Loading
Loading