From fa6687b7f4eab680108710ec025c0094b96b6083 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Thu, 11 Mar 2021 09:29:11 +0000 Subject: [PATCH] ui: Implement ACLs access based on ACLs (#9835) Adds restrictions to everything within the ACLs (and nspaces) area based on your ACLs (including readonly views etc.) --- ui/packages/consul-ui/app/abilities/acl.js | 9 ++- .../consul-ui/app/abilities/auth-method.js | 21 +++++++ ui/packages/consul-ui/app/abilities/nspace.js | 4 ++ ui/packages/consul-ui/app/abilities/policy.js | 34 ++++++++++++ ui/packages/consul-ui/app/abilities/role.js | 21 +++++++ ui/packages/consul-ui/app/abilities/token.js | 33 +++++++++++ .../app/components/child-selector/index.hbs | 2 + .../app/components/consul/acl/list/index.hbs | 12 +++- .../components/consul/nspace/list/index.hbs | 6 +- .../components/consul/policy/list/index.hbs | 8 +-- .../app/components/consul/role/list/index.hbs | 6 ++ .../components/consul/token/list/index.hbs | 17 ++++-- .../app/components/policy-form/index.hbs | 5 +- .../app/components/policy-selector/index.hbs | 13 ++++- .../app/components/role-form/index.hbs | 13 ++++- .../app/components/role-selector/index.hbs | 13 ++++- ui/packages/consul-ui/app/router.js | 55 +++++++++++++++---- .../consul-ui/app/routes/dc/nspaces/create.js | 10 ++-- ui/packages/consul-ui/app/routing/route.js | 11 +++- .../app/services/repository/permission.js | 4 ++ ui/packages/consul-ui/app/styles/layout.scss | 3 + .../consul-ui/app/templates/dc/acls/-form.hbs | 14 +++-- .../consul-ui/app/templates/dc/acls/edit.hbs | 2 + .../consul-ui/app/templates/dc/acls/index.hbs | 2 + .../app/templates/dc/acls/policies/-form.hbs | 6 +- .../app/templates/dc/acls/policies/edit.hbs | 6 +- .../app/templates/dc/acls/roles/-form.hbs | 6 +- .../dc/acls/tokens/-fieldsets-legacy.hbs | 4 +- .../templates/dc/acls/tokens/-fieldsets.hbs | 18 +++++- .../app/templates/dc/acls/tokens/-form.hbs | 7 ++- .../app/templates/dc/acls/tokens/edit.hbs | 2 +- .../app/templates/dc/acls/tokens/index.hbs | 2 + .../app/templates/dc/nspaces/-form.hbs | 35 ++++++++++-- 33 files changed, 339 insertions(+), 65 deletions(-) create mode 100644 ui/packages/consul-ui/app/abilities/auth-method.js create mode 100644 ui/packages/consul-ui/app/abilities/policy.js create mode 100644 ui/packages/consul-ui/app/abilities/role.js create mode 100644 ui/packages/consul-ui/app/abilities/token.js diff --git a/ui/packages/consul-ui/app/abilities/acl.js b/ui/packages/consul-ui/app/abilities/acl.js index f62383f415..ae584a0665 100644 --- a/ui/packages/consul-ui/app/abilities/acl.js +++ b/ui/packages/consul-ui/app/abilities/acl.js @@ -1,9 +1,6 @@ import BaseAbility from './base'; import { inject as service } from '@ember/service'; -// ACL ability covers all of the ACL things, like tokens, policies, roles and -// auth methods and this therefore should not be deleted once we remove the on -// legacy ACLs related classes export default class ACLAbility extends BaseAbility { @service('env') env; @@ -13,4 +10,10 @@ export default class ACLAbility extends BaseAbility { get canRead() { return this.env.var('CONSUL_ACLS_ENABLED') && super.canRead; } + get canDuplicate() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canWrite; + } + get canDelete() { + return this.env.var('CONSUL_ACLS_ENABLED') && this.item.ID !== 'anonymous' && super.canWrite; + } } diff --git a/ui/packages/consul-ui/app/abilities/auth-method.js b/ui/packages/consul-ui/app/abilities/auth-method.js new file mode 100644 index 0000000000..b0af41980a --- /dev/null +++ b/ui/packages/consul-ui/app/abilities/auth-method.js @@ -0,0 +1,21 @@ +import BaseAbility from './base'; +import { inject as service } from '@ember/service'; + +export default class AuthMethodAbility extends BaseAbility { + @service('env') env; + + resource = 'acl'; + segmented = false; + + get canRead() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canRead; + } + + get canCreate() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canCreate; + } + + get canDelete() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canDelete; + } +} diff --git a/ui/packages/consul-ui/app/abilities/nspace.js b/ui/packages/consul-ui/app/abilities/nspace.js index f13f36e6d8..8d2e400d81 100644 --- a/ui/packages/consul-ui/app/abilities/nspace.js +++ b/ui/packages/consul-ui/app/abilities/nspace.js @@ -11,6 +11,10 @@ export default class NspaceAbility extends BaseAbility { return this.canCreate; } + get canDelete() { + return this.item.Name !== 'default' && super.canDelete; + } + get canChoose() { return this.env.var('CONSUL_NSPACES_ENABLED') && this.nspaces.length > 0; } diff --git a/ui/packages/consul-ui/app/abilities/policy.js b/ui/packages/consul-ui/app/abilities/policy.js new file mode 100644 index 0000000000..739408a187 --- /dev/null +++ b/ui/packages/consul-ui/app/abilities/policy.js @@ -0,0 +1,34 @@ +import BaseAbility from './base'; +import { inject as service } from '@ember/service'; +import { typeOf } from 'consul-ui/helpers/policy/typeof'; + +export default class PolicyAbility extends BaseAbility { + @service('env') env; + + resource = 'acl'; + segmented = false; + + get canRead() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canRead; + } + + get canWrite() { + return ( + this.env.var('CONSUL_ACLS_ENABLED') && + (typeof this.item === 'undefined' || typeOf([this.item]) !== 'policy-management') && + super.canRead + ); + } + + get canCreate() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canCreate; + } + + get canDelete() { + return ( + this.env.var('CONSUL_ACLS_ENABLED') && + (typeof this.item === 'undefined' || typeOf([this.item]) !== 'policy-management') && + super.canDelete + ); + } +} diff --git a/ui/packages/consul-ui/app/abilities/role.js b/ui/packages/consul-ui/app/abilities/role.js new file mode 100644 index 0000000000..5c14e58f6b --- /dev/null +++ b/ui/packages/consul-ui/app/abilities/role.js @@ -0,0 +1,21 @@ +import BaseAbility from './base'; +import { inject as service } from '@ember/service'; + +export default class RoleAbility extends BaseAbility { + @service('env') env; + + resource = 'acl'; + segmented = false; + + get canRead() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canRead; + } + + get canCreate() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canCreate; + } + + get canDelete() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canDelete; + } +} diff --git a/ui/packages/consul-ui/app/abilities/token.js b/ui/packages/consul-ui/app/abilities/token.js new file mode 100644 index 0000000000..a47c392888 --- /dev/null +++ b/ui/packages/consul-ui/app/abilities/token.js @@ -0,0 +1,33 @@ +import BaseAbility from './base'; +import { inject as service } from '@ember/service'; + +import { isLegacy } from 'consul-ui/helpers/token/is-legacy'; +import { isAnonymous } from 'consul-ui/helpers/token/is-anonymous'; + +export default class TokenAbility extends BaseAbility { + @service('env') env; + + resource = 'acl'; + segmented = false; + + get canRead() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canRead; + } + + get canCreate() { + return this.env.var('CONSUL_ACLS_ENABLED') && super.canCreate; + } + + get canDelete() { + return ( + this.env.var('CONSUL_ACLS_ENABLED') && + !isAnonymous([this.item]) && + this.item.AccessorID !== this.token.AccessorID && + super.canDelete + ); + } + + get canDuplicate() { + return this.env.var('CONSUL_ACLS_ENABLED') && !isLegacy([this.item]) && super.canWrite; + } +} diff --git a/ui/packages/consul-ui/app/components/child-selector/index.hbs b/ui/packages/consul-ui/app/components/child-selector/index.hbs index 280e17806a..f09d04ceb5 100644 --- a/ui/packages/consul-ui/app/components/child-selector/index.hbs +++ b/ui/packages/consul-ui/app/components/child-selector/index.hbs @@ -3,6 +3,7 @@ ...attributes > {{yield}} +{{#if (not disabled)}} {{yield}} +{{/if}} {{#if (gt items.length 0)}} {{yield}} {{else}} diff --git a/ui/packages/consul-ui/app/components/consul/acl/list/index.hbs b/ui/packages/consul-ui/app/components/consul/acl/list/index.hbs index 371e0155e2..763dd16f71 100644 --- a/ui/packages/consul-ui/app/components/consul/acl/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/acl/list/index.hbs @@ -29,7 +29,13 @@
  • - Edit + +{{#if (can "write acl" item=item)}} + Edit +{{else}} + View +{{/if}} +
  • {{#if (eq item.ID token.SecretID) }}
  • @@ -87,10 +93,12 @@
  • {{/if}} +{{#if (can "duplicate acl" item=item)}}
  • - {{# if (not-eq item.ID 'anonymous') }} +{{/if}} +{{#if (can "delete acl" item=item)}}
  • diff --git a/ui/packages/consul-ui/app/components/consul/nspace/list/index.hbs b/ui/packages/consul-ui/app/components/consul/nspace/list/index.hbs index 085f9d045e..48e36ae904 100644 --- a/ui/packages/consul-ui/app/components/consul/nspace/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/nspace/list/index.hbs @@ -29,10 +29,14 @@ as |item|> +{{#if (can "write nspace" item=item)}} Edit +{{else}} + View +{{/if}} - {{#if (not-eq item.Name 'default') }} + {{#if (can "delete nspace" item=item)}} Delete diff --git a/ui/packages/consul-ui/app/components/consul/policy/list/index.hbs b/ui/packages/consul-ui/app/components/consul/policy/list/index.hbs index c4f5dfa3c1..a518a84e3e 100644 --- a/ui/packages/consul-ui/app/components/consul/policy/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/policy/list/index.hbs @@ -35,14 +35,14 @@ as |item|> -{{#if (eq (policy/typeof item) 'policy-management')}} - View -{{else}} +{{#if (can "write policy" item=item)}} Edit +{{else}} + View {{/if}} -{{#if (not-eq (policy/typeof item) 'policy-management')}} +{{#if (can "delete policy" item=item)}} Delete diff --git a/ui/packages/consul-ui/app/components/consul/role/list/index.hbs b/ui/packages/consul-ui/app/components/consul/role/list/index.hbs index ba2da7e606..9c8254f682 100644 --- a/ui/packages/consul-ui/app/components/consul/role/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/role/list/index.hbs @@ -19,9 +19,14 @@ as |item|> +{{#if (can "write role" item=item)}} Edit +{{else}} + View +{{/if}} +{{#if (can "delete role" item=item)}} Delete @@ -42,6 +47,7 @@ as |item|> +{{/if}} \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/consul/token/list/index.hbs b/ui/packages/consul-ui/app/components/consul/token/list/index.hbs index 5440458752..e0e7e13ae8 100644 --- a/ui/packages/consul-ui/app/components/consul/token/list/index.hbs +++ b/ui/packages/consul-ui/app/components/consul/token/list/index.hbs @@ -30,19 +30,25 @@ as |item|> + +{{#if (can "write token" item=item)}} Edit +{{else}} + View +{{/if}} - {{#if (not (token/is-legacy item))}} +{{#if (can "duplicate token" item=item)}} Duplicate - {{/if}} +{{/if}} + {{#if (eq item.AccessorID token.AccessorID)}} @@ -86,7 +92,9 @@ as |item|> {{/if}} - {{#if (not (or (token/is-anonymous item) (eq item.AccessorID @token.AccessorID)))}} + + +{{#if (can "delete token" item=item token=@token)}} Delete @@ -107,7 +115,8 @@ as |item|> - {{/if}} +{{/if}} + \ No newline at end of file diff --git a/ui/packages/consul-ui/app/components/policy-form/index.hbs b/ui/packages/consul-ui/app/components/policy-form/index.hbs index 18fab4fcee..dee068eb01 100644 --- a/ui/packages/consul-ui/app/components/policy-form/index.hbs +++ b/ui/packages/consul-ui/app/components/policy-form/index.hbs @@ -1,5 +1,8 @@ {{yield}} -
    +
    {{#yield-slot name='template'}} {{else}}
    diff --git a/ui/packages/consul-ui/app/components/policy-selector/index.hbs b/ui/packages/consul-ui/app/components/policy-selector/index.hbs index 803f8a3518..2ed61a8506 100644 --- a/ui/packages/consul-ui/app/components/policy-selector/index.hbs +++ b/ui/packages/consul-ui/app/components/policy-selector/index.hbs @@ -1,4 +1,13 @@ - + {{yield}} Apply an existing policy @@ -112,6 +121,7 @@ /> {{/if}} +{{#if (not disabled)}}
    @@ -127,6 +137,7 @@
    +{{/if}}
    diff --git a/ui/packages/consul-ui/app/components/role-form/index.hbs b/ui/packages/consul-ui/app/components/role-form/index.hbs index 460c6d6904..88ea366c0b 100644 --- a/ui/packages/consul-ui/app/components/role-form/index.hbs +++ b/ui/packages/consul-ui/app/components/role-form/index.hbs @@ -1,5 +1,9 @@ {{yield}} -
    +
    diff --git a/ui/packages/consul-ui/app/components/role-selector/index.hbs b/ui/packages/consul-ui/app/components/role-selector/index.hbs index f9e0283c9d..3320cdd418 100644 --- a/ui/packages/consul-ui/app/components/role-selector/index.hbs +++ b/ui/packages/consul-ui/app/components/role-selector/index.hbs @@ -59,7 +59,7 @@ as |modal|> - + Apply an existing role @@ -70,7 +70,6 @@ as |modal|> > Create new role - {{option.Name}} @@ -100,8 +99,15 @@ as |modal|>
  • - Edit + +{{#if (can "edit role" item=item)}} + Edit +{{else}} + View +{{/if}} +
  • +{{#if (not disabled)}}
  • @@ -125,6 +131,7 @@ as |modal|>
  • +{{/if}}
    diff --git a/ui/packages/consul-ui/app/router.js b/ui/packages/consul-ui/app/router.js index ac4795db36..fd2564cece 100644 --- a/ui/packages/consul-ui/app/router.js +++ b/ui/packages/consul-ui/app/router.js @@ -128,42 +128,69 @@ export const routes = { }, // ACLs acls: { - _options: { path: '/acls' }, + _options: { + path: '/acls', + abilities: ['read acls'], + }, edit: { _options: { path: '/:id' }, }, create: { - _options: { path: '/create' }, + _options: { + path: '/create', + abilities: ['create acls'], + }, }, policies: { - _options: { path: '/policies' }, + _options: { + path: '/policies', + abilities: ['read policies'], + }, edit: { _options: { path: '/:id' }, }, create: { - _options: { path: '/create' }, + _options: { + path: '/create', + abilities: ['create policies'], + }, }, }, roles: { - _options: { path: '/roles' }, + _options: { + path: '/roles', + abilities: ['read roles'], + }, edit: { _options: { path: '/:id' }, }, create: { - _options: { path: '/create' }, + _options: { + path: '/create', + abilities: ['create roles'], + }, }, }, tokens: { - _options: { path: '/tokens' }, + _options: { + path: '/tokens', + abilities: ['read tokens'], + }, edit: { _options: { path: '/:id' }, }, create: { - _options: { path: '/create' }, + _options: { + path: '/create', + abilities: ['create tokens'], + }, }, }, 'auth-methods': { - _options: { path: '/auth-methods' }, + _options: { + path: '/auth-methods', + abilities: ['read auth-methods'], + }, show: { _options: { path: '/show' }, }, @@ -185,12 +212,18 @@ export const routes = { }; if (env('CONSUL_NSPACES_ENABLED')) { routes.dc.nspaces = { - _options: { path: '/namespaces' }, + _options: { + path: '/namespaces', + abilities: ['read nspaces'], + }, edit: { _options: { path: '/:name' }, }, create: { - _options: { path: '/create' }, + _options: { + path: '/create', + abilities: ['create nspaces'], + }, }, }; routes.nspace = { diff --git a/ui/packages/consul-ui/app/routes/dc/nspaces/create.js b/ui/packages/consul-ui/app/routes/dc/nspaces/create.js index f1599c6ebb..35abaec6d1 100644 --- a/ui/packages/consul-ui/app/routes/dc/nspaces/create.js +++ b/ui/packages/consul-ui/app/routes/dc/nspaces/create.js @@ -4,12 +4,10 @@ import CreatingRoute from 'consul-ui/mixins/creating-route'; export default class CreateRoute extends Route.extend(CreatingRoute) { templateName = 'dc/nspaces/edit'; - beforeModel() { + async beforeModel() { + // TODO: Update nspace CRUD to use Data components // we need to skip CreatingRoute.beforeModel here - // TODO(octane): ideally we'd like to call Route.beforeModel - // but its not clear how to do that with old ember - // maybe it will be more normal with modern ember - // up until now we haven't been calling super here anyway - // so this is probably ok until we can skip a parent super + // but still call Route.beforeModel + return Route.prototype.beforeModel.apply(this, arguments); } } diff --git a/ui/packages/consul-ui/app/routing/route.js b/ui/packages/consul-ui/app/routing/route.js index 6259af33ca..3b9ea3d901 100644 --- a/ui/packages/consul-ui/app/routing/route.js +++ b/ui/packages/consul-ui/app/routing/route.js @@ -16,14 +16,19 @@ export default class BaseRoute extends Route { * Inspects a custom `abilities` array on the router for this route. Every * abililty needs to 'pass' for the route not to throw a 403 error. Anything * more complex then this (say ORs) should use a single ability and perform - * the OR lgic in the test for the ability. Note, this ability check happens + * the OR logic in the test for the ability. Note, this ability check happens * before any calls to the backend for this model/route. */ async beforeModel() { - const abilities = get(routes, `${this.routeName}._options.abilities`) || []; + // remove any references to index as it is the same as the root routeName + const routeName = this.routeName + .split('.') + .filter(item => item !== 'index') + .join('.'); + const abilities = get(routes, `${routeName}._options.abilities`) || []; if (abilities.length > 0) { if (!abilities.every(ability => this.permissions.can(ability))) { - throw new HTTPError(403); + throw new HTTPError('403'); } } } diff --git a/ui/packages/consul-ui/app/services/repository/permission.js b/ui/packages/consul-ui/app/services/repository/permission.js index b78b56ba50..ff0ac57fa8 100644 --- a/ui/packages/consul-ui/app/services/repository/permission.js +++ b/ui/packages/consul-ui/app/services/repository/permission.js @@ -11,6 +11,10 @@ const REQUIRED_PERMISSIONS = [ Resource: 'operator', Access: 'write', }, + { + Resource: 'operator', + Access: 'read', + }, { Resource: 'service', Access: 'read', diff --git a/ui/packages/consul-ui/app/styles/layout.scss b/ui/packages/consul-ui/app/styles/layout.scss index 4cfd9ea373..e816900c60 100644 --- a/ui/packages/consul-ui/app/styles/layout.scss +++ b/ui/packages/consul-ui/app/styles/layout.scss @@ -70,6 +70,9 @@ html[data-route$='create'] main, html[data-route$='edit'] main { @extend %content-container-restricted; } +html:not([data-route$='index']):not([data-route$='instances']) main { + margin-bottom: 2em; +} @media #{$--lt-spacious-page-header} { .actions button.copy-btn { diff --git a/ui/packages/consul-ui/app/templates/dc/acls/-form.hbs b/ui/packages/consul-ui/app/templates/dc/acls/-form.hbs index df995189ea..1a2e01ca8a 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/-form.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/-form.hbs @@ -1,5 +1,7 @@
    -
    +
    -{{#if create }} +{{#if (and create (can "create acls")) }} {{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}} - {{else}} + +{{else}} + {{#if (can "write acl" item=item)}} + + {{/if}} {{/if}} -{{# if (and (not create) (not-eq item.ID 'anonymous')) }} +{{# if (and (not create) (can "delete acl" item=item) ) }} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/edit.hbs b/ui/packages/consul-ui/app/templates/dc/acls/edit.hbs index b10cd72859..da650481fc 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/edit.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/edit.hbs @@ -25,6 +25,7 @@ Copy token ID + {{#if (can "duplicate acl" item=item)}} @@ -38,6 +39,7 @@ + {{/if}} {{/if}} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/index.hbs b/ui/packages/consul-ui/app/templates/dc/acls/index.hbs index 7bf7b3da5e..1546309fa0 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/index.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/index.hbs @@ -32,7 +32,9 @@ as |sort filters items|}} +{{#if (can "create acls")}} Create +{{/if}} {{#if (gt items.length 0) }} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/policies/-form.hbs b/ui/packages/consul-ui/app/templates/dc/acls/policies/-form.hbs index e3ec9be954..21a2f790c2 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/policies/-form.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/policies/-form.hbs @@ -7,14 +7,16 @@ {{/if}}
    -{{#if create }} +{{#if (and create (can "create tokens")) }} {{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}} {{ else }} + {{#if (can "write policy" item=item)}} + {{/if}} {{/if}} -{{# if (not create) }} +{{# if (and (not create) (can "delete policy" item=item) ) }} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/policies/edit.hbs b/ui/packages/consul-ui/app/templates/dc/acls/policies/edit.hbs index d16ba51679..96418a7ec5 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/policies/edit.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/policies/edit.hbs @@ -30,10 +30,10 @@ {{#if create }} New Policy {{else}} - {{#if (eq (policy/typeof item) 'policy-management')}} - View Policy - {{else}} + {{#if (can "write policy" item=item)}} Edit Policy + {{else}} + View Policy {{/if}} {{/if}} {{else}} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/roles/-form.hbs b/ui/packages/consul-ui/app/templates/dc/acls/roles/-form.hbs index 092fcda217..886153552f 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/roles/-form.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/roles/-form.hbs @@ -8,14 +8,16 @@ {{/if}}
    -{{#if create }} +{{#if (and create (can "create roles")) }} {{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}} {{ else }} + {{#if (can "write role" item=item)}} + {{/if}} {{/if}} -{{# if (not create) }} +{{# if (and (not create) (can "delete role" item=item) ) }} diff --git a/ui/packages/consul-ui/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs b/ui/packages/consul-ui/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs index a96aac9cdb..3dfebadfae 100644 --- a/ui/packages/consul-ui/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs +++ b/ui/packages/consul-ui/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs @@ -1,4 +1,6 @@ -
    +