Skip to content
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 kv preflight endpoints #4439

Merged
merged 10 commits into from
Apr 24, 2018
31 changes: 8 additions & 23 deletions ui/app/adapters/secret-engine.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
import Ember from 'ember';
import ApplicationAdapter from './application';
import DS from 'ember-data';

export default ApplicationAdapter.extend({
url(path) {
const url = `${this.buildURL()}/mounts`;
return path ? url + '/' + path : url;
},

pathForType(type) {
let path;
switch (type) {
case 'cluster':
path = 'clusters';
break;
case 'secret-engine':
path = 'mounts';
break;
default:
path = Ember.String.pluralize(type);
break;
}
return path;
pathForType() {
return 'mounts';
},

query() {
return this.ajax(this.url(), 'GET').catch(e => {
if (e instanceof DS.AdapterError) {
Ember.set(e, 'policyPath', 'sys/mounts');
}

throw e;
});
query(store, type, query) {
let url = `/${this.urlPrefix()}/internal/ui/mounts`;
if (query.path) {
url = `${url}/${query.path}`;
}
return this.ajax(url, 'GET');
},

createRecord(store, type, snapshot) {
Expand Down
9 changes: 0 additions & 9 deletions ui/app/controllers/vault/cluster/response-wrapping.js

This file was deleted.

1 change: 0 additions & 1 deletion ui/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ Router.map(function() {
});
});

this.route('response-wrapping');
this.route('not-found', { path: '/*path' });
});
this.route('not-found', { path: '/*path' });
Expand Down
6 changes: 1 addition & 5 deletions ui/app/routes/vault/cluster/secrets.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import Ember from 'ember';
import ClusterRoute from 'vault/mixins/cluster-route';

export default Ember.Route.extend(ClusterRoute, {
model() {
return this.store.query('secret-engine', {});
},
});
export default Ember.Route.extend(ClusterRoute);
28 changes: 20 additions & 8 deletions ui/app/routes/vault/cluster/secrets/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@ import Ember from 'ember';
const { inject } = Ember;
export default Ember.Route.extend({
flashMessages: inject.service(),
beforeModel(transition) {
const target = transition.targetName;
const { backend } = this.paramsFor(this.routeName);
const backendModel = this.store.peekRecord('secret-engine', backend);
const type = backendModel && backendModel.get('type');
if (type === 'kv' && backendModel.get('options.version') === 2) {
model(params) {
let { backend } = params;
return this.store
.query('secret-engine', {
path: backend,
})
.then(model => {
if (model) {
return model.get('firstObject');
}
});
},

afterModel(model, transition) {
let target = transition.targetName;
let path = model && model.get('path');
let type = model && model.get('type');
if (type === 'kv' && model.get('options.version') === 2) {
this.get('flashMessages').stickyInfo(
`"${backend}" is a newer version of the KV backend. The Vault UI does not currently support the additional versioning features. All actions taken through the UI in this engine will operate on the most recent version of a secret.`
`"${path}" is a newer version of the KV backend. The Vault UI does not currently support the additional versioning features. All actions taken through the UI in this engine will operate on the most recent version of a secret.`
);
}

if (target === this.routeName) {
return this.replaceWith('vault.cluster.secrets.backend.list-root', backend);
return this.replaceWith('vault.cluster.secrets.backend.list-root', path);
}
},
});
3 changes: 1 addition & 2 deletions ui/app/routes/vault/cluster/secrets/backend/credentials.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ export default Ember.Route.extend(UnloadModel, {
templateName: 'vault/cluster/secrets/backend/credentials',

backendModel() {
const backend = this.paramsFor('vault.cluster.secrets.backend').backend;
return this.store.peekRecord('secret-engine', backend);
return this.modelFor('vault.cluster.secrets.backend');
},

pathQuery(role, backend) {
Expand Down
42 changes: 20 additions & 22 deletions ui/app/routes/vault/cluster/secrets/backend/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,29 @@ export default Ember.Route.extend({
model(params) {
const secret = params.secret ? params.secret : '';
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');
const backendModel = this.modelFor('vault.cluster.secrets.backend');
return Ember.RSVP.hash({
secret,
secrets: this.store
.lazyPaginatedQuery(this.getModelType(backend, params.tab), {
id: secret,
backend,
responsePath: 'data.keys',
page: params.page,
pageFilter: params.pageFilter,
size: 100,
})
.then(model => {
this.set('has404', false);
return model;
})
.catch(err => {
if (backends.includes(backend) && err.httpStatus === 404 && secret === '') {
return [];
} else {
throw err;
}
}),
.lazyPaginatedQuery(this.getModelType(backend, params.tab), {
id: secret,
backend,
responsePath: 'data.keys',
page: params.page,
pageFilter: params.pageFilter,
size: 100,
})
.then(model => {
this.set('has404', false);
return model;
})
.catch(err => {
if (backendModel && err.httpStatus === 404 && secret === '') {
return [];
} else {
throw err;
}
})
});
},

Expand Down Expand Up @@ -138,11 +138,9 @@ export default Ember.Route.extend({
error(error, transition) {
const { secret } = this.paramsFor(this.routeName);
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');

Ember.set(error, 'secret', secret);
Ember.set(error, 'isRoot', true);
Ember.set(error, 'hasBackend', backends.includes(backend));
Ember.set(error, 'backend', backend);
const hasModel = this.controllerFor(this.routeName).get('hasModel');
// only swallow the error if we have a previous model
Expand Down
12 changes: 5 additions & 7 deletions ui/app/routes/vault/cluster/secrets/backend/secret-edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UnloadModelRoute from 'vault/mixins/unload-model-route';
export default Ember.Route.extend(UnloadModelRoute, {
capabilities(secret) {
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
let backendModel = this.store.peekRecord('secret-engine', backend);
let backendModel = this.modelFor('vault.cluster.secrets.backend');
let backendType = backendModel.get('type');
let version = backendModel.get('options.version');
let path;
Expand All @@ -21,8 +21,8 @@ export default Ember.Route.extend(UnloadModelRoute, {
return this.store.findRecord('capabilities', path);
},

backendType(path) {
return this.store.peekRecord('secret-engine', path).get('type');
backendType() {
return this.modelFor('vault.cluster.secrets.backend').get('type');
},

templateName: 'vault/cluster/secrets/backend/secretEditLayout',
Expand Down Expand Up @@ -50,7 +50,7 @@ export default Ember.Route.extend(UnloadModelRoute, {
aws: 'role-aws',
pki: secret && secret.startsWith('cert/') ? 'pki-certificate' : 'role-pki',
};
let backendModel = this.store.peekRecord('secret-engine', backend);
let backendModel = this.modelFor('vault.cluster.secrets.backend', backend);
let defaultType = 'secret';
if (backendModel.get('type') === 'kv' && backendModel.get('options.version') === 2) {
defaultType = 'secret-v2';
Expand Down Expand Up @@ -81,7 +81,7 @@ export default Ember.Route.extend(UnloadModelRoute, {
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
const preferAdvancedEdit =
this.controllerFor('vault.cluster.secrets.backend').get('preferAdvancedEdit') || false;
const backendType = this.backendType(backend);
const backendType = this.backendType();
model.secret.setProperties({ backend });
controller.setProperties({
model: model.secret,
Expand All @@ -105,10 +105,8 @@ export default Ember.Route.extend(UnloadModelRoute, {
error(error) {
const { secret } = this.paramsFor(this.routeName);
const { backend } = this.paramsFor('vault.cluster.secrets.backend');
const backends = this.modelFor('vault.cluster.secrets').mapBy('id');
Ember.set(error, 'keyId', backend + '/' + secret);
Ember.set(error, 'backend', backend);
Ember.set(error, 'hasBackend', backends.includes(backend));
return true;
},

Expand Down
3 changes: 1 addition & 2 deletions ui/app/routes/vault/cluster/secrets/backend/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ export default Ember.Route.extend(UnloadModel, {
templateName: 'vault/cluster/secrets/backend/sign',

backendModel() {
const backend = this.paramsFor('vault.cluster.secrets.backend').backend;
return this.store.peekRecord('secret-engine', backend);
return this.modelFor('vault.cluster.secrets.backend');
},

pathQuery(role, backend) {
Expand Down
7 changes: 7 additions & 0 deletions ui/app/routes/vault/cluster/secrets/backends.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Ember from 'ember';

export default Ember.Route.extend({
model() {
return this.store.query('secret-engine', {});
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const CONFIGURABLE_BACKEND_TYPES = ['aws', 'ssh', 'pki'];
export default Ember.Route.extend({
model() {
const { backend } = this.paramsFor(this.routeName);
return this.store.query('secret-engine', {}).then(() => {
const model = this.store.peekRecord('secret-engine', backend);
return this.store.query('secret-engine', { path: backend }).then(modelList => {
let model = modelList && modelList.get('firstObject');
if (!model || !CONFIGURABLE_BACKEND_TYPES.includes(model.get('type'))) {
const error = new DS.AdapterError();
Ember.set(error, 'httpStatus', 404);
Expand Down
12 changes: 11 additions & 1 deletion ui/app/serializers/secret-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,17 @@ export default DS.RESTSerializer.extend({
} else if (isQueryRecord) {
backends = this.normalizeBackend(null, payload);
} else {
backends = Object.keys(payload.data).map(id => this.normalizeBackend(id, payload[id]));
// this is terrible, I'm sorry
// TODO extract AWS and SSH config saving from the secret-engine model to simplify this
if (payload.data.secret) {
backends = Object.keys(payload.data.secret).map(id =>
this.normalizeBackend(id, payload.data.secret[id])
);
} else if (!payload.data.path) {
backends = Object.keys(payload.data).map(id => this.normalizeBackend(id, payload[id]));
} else {
backends = [this.normalizeBackend(payload.data.path, payload.data)];
}
}

const transformedPayload = { [primaryModelClass.modelName]: backends };
Expand Down
6 changes: 3 additions & 3 deletions ui/app/templates/components/ttl-picker.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
value={{time}}
id="time-{{elementId}}"
type="text"
name="time-{{elementId}}"
name="time"
class="input"
oninput={{action 'changedValue' 'time'}}
/>
Expand All @@ -15,8 +15,8 @@
<div class="select is-fullwidth">
<select
data-test-ttl-unit
name="unit-{{elementId}}"
id="unit-{{elementId}}"
name="unit"
id="unit"
onchange={{action 'changedValue' 'unit'}}
>
{{#each unitOptions as |unitOption|}}
Expand Down
11 changes: 0 additions & 11 deletions ui/app/templates/vault/cluster/error.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@
<p>
Make sure the policy for the path <code>{{model.policyPath}}</code> includes <code>capabilities = ['update']</code>.
</p>
{{else if (and
(eq model.httpStatus 403)
(eq model.policyPath 'sys/mounts')
)
}}
<p data-test-sys-mounts-warning>
Your auth token does not have access to {{model.policyPath}}. This is necessary in order to browse secret backends.
</p>
<p>
Make sure the policy for the path <code>{{model.policyPath}}</code> has <code>capabilities = ['list', 'read']</code>.
</p>
{{else}}
{{#if model.message}}
<p>{{model.message}}</p>
Expand Down
8 changes: 4 additions & 4 deletions ui/app/templates/vault/cluster/secrets/backend/error.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<header class="page-header">
<nav class="breadcrumb">
<li>
<a href={{href-to params=(if model.hasBackend
<a href={{href-to params=(if model.backend
(array "vault.cluster.secrets.backend.list-root")
(array "vault.cluster.secrets")
)
Expand Down Expand Up @@ -30,9 +30,9 @@
{{#if (eq model.httpStatus 404)}}
<p data-test-secret-not-found>
Unable to find secret at <code>{{concat model.backend "/" model.secret}}</code>. Try going back to the
{{#link-to params=(if model.hasBackend
(reduce-to-array "vault.cluster.secrets.backend.list-root")
(reduce-to-array "vault.cluster.secrets")
{{#link-to params=(if model.backend
(array "vault.cluster.secrets.backend.list-root")
(array "vault.cluster.secrets")
)
}}root{{/link-to}}
and navigating from there.
Expand Down
7 changes: 4 additions & 3 deletions ui/app/templates/vault/cluster/secrets/backends.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
<div class="level is-mobile">
<div class="level-left">
<div>
<a data-test-secret-path href={{href-to 'vault.cluster.secrets.backend.list-root' backend.id}} class="has-text-black has-text-weight-semibold">
{{i-con glyph="folder" size=14 class="has-text-grey-light"}}{{backend.path}}
</a>
<a data-test-secret-path
href={{href-to 'vault.cluster.secrets.backend.list-root' backend.id}}
class="has-text-black has-text-weight-semibold"
>{{i-con glyph="folder" size=14 class="has-text-grey-light"}}{{backend.path}}</a>
<br />
<span class="tag">
<code>
Expand Down
3 changes: 3 additions & 0 deletions ui/config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ module.exports = function(environment) {
ENV.contentSecurityPolicyMeta = true;
ENV.contentSecurityPolicy = {
'connect-src': ["'self'"],
'img-src': ["'self'", 'data:'],
'form-action': ["'none'"],
'script-src': ["'self'"],
'style-src': ["'unsafe-inline'", "'self'"],
};
}
Expand Down
31 changes: 0 additions & 31 deletions ui/tests/acceptance/secrets/no-access-test.js

This file was deleted.

Loading