open-vault/ui/app/adapters/keymgmt/key.js

153 lines
4.3 KiB
JavaScript
Raw Normal View History

Key Management Secrets Engine Phase 1 (#15036) * KMSE: Key Model / Adapter / Serializer setup (#13638) * First pass model * KMS key adapter (create/update), serializer, model * Add last rotated and provider to key * KeyEdit secret-edit component, and more key model stuff * add formatDate param support to infotablerow * Add keymgmt key to routes and options-for-backend * Rename keymgmt-key to keymgmt/key * Add test, cleanup * Add mirage handler for kms * Address PR comments * KMS Providers (#13797) * adds pagination-controls component * adds kms provider model, adapter and serializer * adds kms provider-edit component * updates secrets routes to handle itemType query param for kms * updates kms key adapter to query by provider * adds tests for provider-edit component * refactors kms provider adapter to account for dynamic path * adds model-validations-helper util * removes keymgmt from supported-secret-backends * fixes issue generating url for fetching keys for a provider * updates modelType method on secret-edit route to accept options object as arg rather than transition * adds additional checks to ensure queryParams are defined in options object for modelType method * UI/keymgmt distribute key (#13840) * Add distribution details on key page, and empty states if no permissions * Allow search-select component to return object so parent can tell when new item was created * Add stringarray transform * Distribute component first pass * Refactor distribute component for use with internal object rather than ember-data model * Specific permission denied errors on key edit * Allow inline errors on search-select component * Style updates for form errors * Styling and error messages on distribute component * Allow block template on inline alert so we can add doc links * Add distribute action, flash messages, cleanup * Cleanup & Add tests * More cleanup * Address PR comments * Move disable operations logic to commponent class * KMSE Enable/Config (#14835) * adds keymgmt secrets engine as supported backend * adds comment to check on keymgmt as member of adp module * updates kms provider to use model-validations decorator * fixes lint errors and tests Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
2022-04-20 18:40:27 +00:00
import ApplicationAdapter from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';
function pickKeys(obj, picklist) {
const data = {};
Object.keys(obj).forEach((key) => {
if (picklist.indexOf(key) >= 0) {
data[key] = obj[key];
}
});
return data;
}
export default class KeymgmtKeyAdapter extends ApplicationAdapter {
namespace = 'v1';
url(backend, id, type) {
const url = `${this.buildURL()}/${backend}/key`;
if (id) {
if (type === 'ROTATE') {
return url + '/' + encodePath(id) + '/rotate';
} else if (type === 'PROVIDERS') {
return url + '/' + encodePath(id) + '/kms';
}
return url + '/' + encodePath(id);
}
return url;
}
urlForDeleteRecord(store, type, snapshot) {
const name = snapshot.attr('name');
const backend = snapshot.attr('backend');
return this.url(backend, name);
}
_updateKey(backend, name, serialized) {
// Only these two attributes are allowed to be updated
let data = pickKeys(serialized, ['deletion_allowed', 'min_enabled_version']);
return this.ajax(this.url(backend, name), 'PUT', { data });
}
_createKey(backend, name, serialized) {
// Only type is allowed on create
let data = pickKeys(serialized, ['type']);
return this.ajax(this.url(backend, name), 'POST', { data });
}
async createRecord(store, type, snapshot) {
const data = store.serializerFor(type.modelName).serialize(snapshot);
const name = snapshot.attr('name');
const backend = snapshot.attr('backend');
// Keys must be created and then updated
await this._createKey(backend, name, data);
if (snapshot.attr('deletionAllowed')) {
try {
await this._updateKey(backend, name, data);
} catch (e) {
// TODO: Test how this works with UI
throw new Error(`Key ${name} was created, but not all settings were saved`);
}
}
return {
data: {
...data,
id: name,
backend,
},
};
}
updateRecord(store, type, snapshot) {
const data = store.serializerFor(type.modelName).serialize(snapshot);
const name = snapshot.attr('name');
const backend = snapshot.attr('backend');
return this._updateKey(backend, name, data);
}
distribute(backend, kms, key, data) {
return this.ajax(`${this.buildURL()}/${backend}/kms/${encodePath(kms)}/key/${encodePath(key)}`, 'PUT', {
data: { ...data },
});
}
async getProvider(backend, name) {
try {
const resp = await this.ajax(this.url(backend, name, 'PROVIDERS'), 'GET', {
data: {
list: true,
},
});
return resp.data.keys ? resp.data.keys[0] : null;
} catch (e) {
if (e.httpStatus === 404) {
// No results, not distributed yet
return null;
} else if (e.httpStatus === 403) {
return { permissionsError: true };
}
// TODO: handle control group
throw e;
}
}
getDistribution(backend, kms, key) {
const url = `${this.buildURL()}/${backend}/kms/${kms}/key/${key}`;
return this.ajax(url, 'GET')
.then((res) => {
return {
...res.data,
purposeArray: res.data.purpose.split(','),
};
})
.catch(() => {
// TODO: handle control group
return null;
});
}
async queryRecord(store, type, query) {
const { id, backend, recordOnly = false } = query;
const keyData = await this.ajax(this.url(backend, id), 'GET');
keyData.data.id = id;
keyData.data.backend = backend;
let provider, distribution;
if (!recordOnly) {
provider = await this.getProvider(backend, id);
if (provider) {
distribution = await this.getDistribution(backend, provider, id);
}
}
return { ...keyData, provider, distribution };
}
async query(store, type, query) {
const { backend, provider } = query;
const providerAdapter = store.adapterFor('keymgmt/provider');
const url = provider ? providerAdapter.buildKeysURL(query) : this.url(backend);
return this.ajax(url, 'GET', {
data: {
list: true,
},
}).then((res) => {
res.backend = backend;
return res;
});
}
rotateKey(backend, id) {
// TODO: re-fetch record data after
return this.ajax(this.url(backend, id, 'ROTATE'), 'PUT');
}
}