From f8f40c3d16d5243b46b23f625b12e77237b93428 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Wed, 3 Apr 2024 10:14:16 -0500
Subject: [PATCH] UI: Don't show Resultant-ACL banner when wildcard policy
present (#26233)
* Add wildcard calc helpers to permissions service with tests
* Check for wildcard access when calculating permissionsBanner
* Move resultant-acl banner within TokenExpireWarning so it's mutually exclusive with token expired banner
* fix permissions banner if statement
* Add margin to resultant-acl
* cleanup comments
---
ui/app/services/permissions.js | 32 ++++-
ui/app/templates/vault/cluster.hbs | 8 +-
ui/tests/unit/services/permissions-test.js | 134 +++++++++++++++++++++
3 files changed, 170 insertions(+), 4 deletions(-)
diff --git a/ui/app/services/permissions.js b/ui/app/services/permissions.js
index c5e8064025..3233d09599 100644
--- a/ui/app/services/permissions.js
+++ b/ui/app/services/permissions.js
@@ -82,6 +82,12 @@ const API_PATHS_TO_ROUTE_PARAMS = {
root: boolean;
chroot_namespace?: string;
};
+ There are a couple nuances to be aware of about this response. When a
+ chroot_namespace is set, all of the paths in the response will be prefixed
+ with that namespace. Additionally, this endpoint is only added to the default
+ policy in the user's root namespace, so we make the call to the user's root
+ namespace (the namespace where the user's auth method is mounted) no matter
+ what the current namespace is.
*/
export default class PermissionsService extends Service {
@@ -91,7 +97,6 @@ export default class PermissionsService extends Service {
@tracked permissionsBanner = null;
@tracked chrootNamespace = null;
@service store;
- @service auth;
@service namespace;
get baseNs() {
@@ -117,6 +122,27 @@ export default class PermissionsService extends Service {
}
}
+ get wildcardPath() {
+ const ns = [sanitizePath(this.chrootNamespace), sanitizePath(this.namespace.userRootNamespace)].join('/');
+ // wildcard path comes back from root namespace as empty string,
+ // but within a namespace it's the namespace itself ending with a slash
+ return ns === '/' ? '' : `${sanitizePath(ns)}/`;
+ }
+
+ /**
+ * hasWildcardAccess checks if the user has a wildcard policy
+ * @param {object} globPaths key is path, value is object with capabilities
+ * @returns {boolean} whether the user's policy includes wildcard access to NS
+ */
+ hasWildcardAccess(globPaths = {}) {
+ // First check if the wildcard path is in the globPaths object
+ if (!Object.keys(globPaths).includes(this.wildcardPath)) return false;
+
+ // if so, make sure the current namespace is a child of the wildcard path
+ return this.namespace.path.startsWith(this.wildcardPath);
+ }
+
+ // This method is called to recalculate whether to show the permissionsBanner when the namespace changes
calcNsAccess() {
if (this.canViewAll) {
this.permissionsBanner = null;
@@ -124,7 +150,11 @@ export default class PermissionsService extends Service {
}
const namespace = this.baseNs;
const allowed =
+ // check if the user has wildcard access to the relative root namespace
+ this.hasWildcardAccess(this.globPaths) ||
+ // or if any of their glob paths start with the namespace
Object.keys(this.globPaths).any((k) => k.startsWith(namespace)) ||
+ // or if any of their exact paths start with the namespace
Object.keys(this.exactPaths).any((k) => k.startsWith(namespace));
this.permissionsBanner = allowed ? null : PERMISSIONS_BANNER_STATES.noAccess;
}
diff --git a/ui/app/templates/vault/cluster.hbs b/ui/app/templates/vault/cluster.hbs
index 49d7c35978..4fa86a248d 100644
--- a/ui/app/templates/vault/cluster.hbs
+++ b/ui/app/templates/vault/cluster.hbs
@@ -70,9 +70,6 @@
@autoloaded={{eq this.activeCluster.licenseState "autoloaded"}}
/>
{{/if}}
- {{#if this.permissionBanner}}
-