-
Notifications
You must be signed in to change notification settings - Fork 4.4k
UI: Add TOTP secrets engine #29751
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
UI: Add TOTP secrets engine #29751
Conversation
* TOTP secrets in the web UI * Use credentials route to show TOTP code * Refactor create and edit of TOTP keys * TOTP model validation * Add TOTP provider mode * Use withExpandedAttributes in TOTP model * Simplify attributes * Make TOTP period optional * Better TOTP editor labels * Fix disabled attribute for select and checkbox
CI Results: |
ui/app/adapters/totp.js
Outdated
import ApplicationAdapter from './application'; | ||
import { encodePath } from 'vault/utils/path-encoding-helpers'; | ||
|
||
export default ApplicationAdapter.extend({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modernize this adapter to match current Ember patterns, confirm each method is actually necessary (and not just copy pasta)
|
||
.code-validity { | ||
padding-left: $spacing-12; | ||
cursor: unset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really sure unset
is necessary here? We can double check, but ideally it'd be nice to remove this component file and use generic css spacing helpers for the padding
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
|
||
export default class SecretListItemComponent extends Component { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
component names should match the file
export default class SecretListItemComponent extends Component { | |
export default class TotpListItem extends Component { |
ui/app/components/totp-edit.js
Outdated
persist(method, successCallback) { | ||
const model = this.model; | ||
return model[method]().then(() => { | ||
if (!model.isError) { | ||
if (model.backend === 'totp' && model.generate) { | ||
this.hasGenerated = true; | ||
this.successCallback = successCallback; | ||
} else { | ||
successCallback(model); | ||
} | ||
} | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing a delete method specific for this item should remove the need for some conditionals here. But I'd still like to confirm what the intended functionality is here. Is this called when clicking "Delete" from the popup menu?
Also - why is hasGenerated
something that needs to be tracked here?
ui/app/models/totp.js
Outdated
}) | ||
backend; | ||
|
||
@alias('account_name') name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the original intention here was to use account_name
as name, but reviewing the docs they're separate parameters and some users may not want to use the same value for both.
ui/app/models/totp.js
Outdated
|
||
@withModelValidations(validations) | ||
@withExpandedAttributes() | ||
export default class TotpModel extends Model { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to audit the params here and make sure they match the docs: https://developer.hashicorp.com/vault/api-docs/secret/totp
ui/app/models/totp.js
Outdated
fieldValue: 'name', | ||
editDisabled: true, | ||
}) | ||
account_name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're inconsistent but typically use camel case syntax for model params accountName
ui/app/models/totp.js
Outdated
@computed('generate', function () { | ||
const defaultFields = ['generate']; | ||
const options = ['algorithm', 'digits', 'period']; | ||
const providerOptions = []; | ||
|
||
if (this.generate) { | ||
providerOptions.push('key_size', 'skew', 'exported', 'qr_size'); | ||
} else { | ||
defaultFields.push('url', 'key'); | ||
} | ||
|
||
defaultFields.push('account_name', 'issuer'); | ||
|
||
const groups = [ | ||
{ default: defaultFields }, | ||
{ | ||
Options: [...options], | ||
}, | ||
]; | ||
|
||
if (this.generate) { | ||
groups.push({ | ||
'Provider options': [...providerOptions], | ||
}); | ||
} | ||
|
||
return this._expandGroups(groups); | ||
}) | ||
fieldGroups; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The newer pattern is to keep models "thin" and any form logic should be handled by the form component, not the model. Instead, we can use the @withFormFields
decorator which will "expand" all of the model attributes into the form structure we want (with the options object that houses editType and all of that info).
The decorator can be called with args, like this: https://github.com/hashicorp/vault/blob/main/ui/app/models/pki/issuer.js#L27
@@ -335,7 +336,7 @@ | |||
{{else if (or (eq @attr.type "boolean") (eq @attr.options.editType "boolean"))}} | |||
<div class="b-checkbox"> | |||
<input | |||
disabled={{this.disabled}} | |||
disabled={{and @attr.options.editDisabled (not @model.isNew)}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking at the disabled
getter in the component file shows that a @disabled
arg can be passed in. we still need to account for that case and this logic should be added to the getter
We could then call this.disabled
here and above. It might be worth updating the other areas of and @attr.options.editDisabled (not @model.isNew)
so we're consistent (though as it is, not all inputs are even setup to accept a disabled arg...so the consistency is somewhat moot) This component file is always a challenge to balance keeping scope down without breaking backwards compatibility for an arg.
import Component from '@glimmer/component'; | ||
import { action } from '@ember/object'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { later, cancel } from '@ember/runloop'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file should be co-located and moved beside the generate-credentials-totp.js
file. (the separate file trees was necessary pre ember-octane)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file should be co-located and live beside totp-list-item.js
(we'll want to double check that doesn't message with the rendering expectations for the generic <Component>
helper the file path will be the same (secret-list/totp-list-item
), so it should be fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be co-located as well (we'll want to double check that doesn't mess with the generator pattern and how these are rendered)
{{did-insert this.startTimer}} | ||
{{will-destroy this.cancelTimer}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with ember concurrency we shouldn't need these. the task can be initiated in the constructor()
for the component and are automatically canceled when the component is torn down.
ui/app/models/totp.js
Outdated
algorithm; | ||
@attr('number', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: line break between each @attr
algorithm; | |
@attr('number', { | |
algorithm; | |
@attr('number', { |
ui/app/models/totp.js
Outdated
@attr('string', { | ||
editDisabled: true, | ||
}) | ||
issuer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small attr options blocks can be on a single line
@attr('string', { | |
editDisabled: true, | |
}) | |
issuer; | |
@attr('string', { editDisabled: true }) | |
issuer; |
ui/app/models/totp.js
Outdated
@attr('number', { | ||
possibleValues: SKEW, | ||
//defaultValue: 1, | ||
editDisabled: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems like edit is disabled for all of these? we just hide disable edit higher up
* a few changes to use newer extends pattern * refactor totp adapter * refactor generate-credentials-totp * update component name * refactor totp-edit * update naming from totp to totp-key for clarity and convention * update to use totp-key instead of totp * break totp actions into separate components * remove support for editing totp key * move new totp code logic into generate credentials totp (fixes delay in new code) * move hbs files to be alongside their js counterparts * refactor totp model and update form fields decorator to handle combined groups * Update ui/app/components/generate-credentials-totp.hbs Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * remove unnecessary update method and improve method separation of concerns * Update ui/app/components/generate-credentials-totp.js Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * pass only relevant model data into component * update totp credentials * url improvement * remove unnecessary cleanup method and move totp code generation * add todo * remove old totp code refresh * update directory location and name * combine conditionals * remove unused code * add todos * update model id assignment * move field display logic out of model * combine display conditional blocks * remove TOTP from unsupported engines list --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
* update getter to return non generated or generated form fields * update field text and labels to match design * only show exported for generate and fix toggle * add model validations and invalid form alert * update validations to match doc specifications * fix key validation * fix validations * add totp list item test * add tests for creating vault provided key, navigating to details, and deleting key * add jsdoc for totp-edit * remove todo * update jsdoc and convert create method to task * fix stying * make delete method async and remove persist * make method names more clear * remove extra div * remove unneeded test selector * update validators and messages * use existing toggle button type * add withExpandedAttributes back in * move common logic into before each hook * add test for non vault generated key * use general selectors * test improvements * test improvements * add success messages * update assertion message * update mountBackend to navigate to relevant page if not already there * update doc * fix model inconsistencies and update serializer * remove extra css and reverse progress bar for totp code * update naming * pass group fields to serializer as well * update tests * remove mode and update naming for clarity * remove comment * remove unneeded css file * remove unneeded mode getter, update docs, update delete fn and message * update reset to be more resilient and rename arg * update field naming for clarity and add back in namespace reminder * remove unneeded div, update test selector, clean up * clean up strings, remove unneeded labels, * remove aliases for capabilities * update and fix tests * remove unneeded test file
* match read key and generate code flow to design * add qr code view to acceptance tests * add component tests * remove unneeded variables * add backend and id * updated tests * flash error message in delete key * move test selector * add generate code link from details view * update back button to be dynamic * Update ui/tests/acceptance/secrets/backend/totp/key-test.js Co-authored-by: Shannon Roberts (Beagin) <beagins@users.noreply.github.com> * save id for success message and update routing for back button --------- Co-authored-by: Shannon Roberts (Beagin) <beagins@users.noreply.github.com>
Build Results: |
const { totpCodePeriod } = this.args; | ||
|
||
if (!totpCodePeriod) { | ||
return 0; // TODO improve this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this TODO need to be addressed before we merge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe so. I think that code block shouldn't be possible to reach anymore as we should always have a totpCodePeriod
, but I left it in to be safe for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not been too involved in this sidebranch process. There are a couple of small changes I was considering recommending, but I understand the background context to this sidebranch and know at this point it's about getting this functionality out to users. Nice work on this!
Description
This is a culmination of PRs into this sidebranch which have been individually reviewed. These changes include enabling the TOTP secrets engine according to current design specs + tests.
TOTP.secrets.engine.mov
enterprise tests ✅
TODO only if you're a HashiCorp employee
backport/
label that matches the desired release branch. Note that in the CE repo, the latest release branch will look likebackport/x.x.x
, but older release branches will bebackport/ent/x.x.x+ent
.of a public function, even if that change is in a CE file, double check that
applying the patch for this PR to the ENT repo and running tests doesn't
break any tests. Sometimes ENT only tests rely on public functions in CE
files.
in the PR description, commit message, or branch name.
description. Also, make sure the changelog is in this PR, not in your ENT PR.