Skip to content

Commit

Permalink
UI - fix encoding for user-entered paths (#6294)
Browse files Browse the repository at this point in the history
* directly depend on route-recognizer

* add path encode helper using route-recognizer normalizer methods

* encode user-entered paths/ids for places we're not using the built-in ember data buildUrl method

* encode secret link params

* decode params from the url, and encode for linked-block and navigate-input components

* add escape-string-regexp

* use list-controller mixin and escape the string when contructing new Regex objects

* encode paths in the console service

* add acceptance tests for kv secrets

* make encoding in linked-block an attribute, and use it on secret lists

* egp endpoints are enterprise-only, so include 'enterprise' text in the test

* fix routing test and exclude single quote from encoding tests

* encode cli string before tokenizing

* encode auth_path for use with urlFor

* add test for single quote via UI input instead of web cli
  • Loading branch information
meirish authored Mar 1, 2019
1 parent 9617832 commit b585c20
Show file tree
Hide file tree
Showing 33 changed files with 248 additions and 133 deletions.
5 changes: 3 additions & 2 deletions ui/app/adapters/auth-method.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { assign } from '@ember/polyfills';
import { get, set } from '@ember/object';
import ApplicationAdapter from './application';
import DS from 'ember-data';
import { encodePath } from 'vault/utils/path-encoding-helpers';

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

// used in updateRecord on the model#tune action
Expand Down Expand Up @@ -58,6 +59,6 @@ export default ApplicationAdapter.extend({
},

exchangeOIDC(path, state, code) {
return this.ajax(`/v1/auth/${path}/oidc/callback`, 'GET', { data: { state, code } });
return this.ajax(`/v1/auth/${encodePath(path)}/oidc/callback`, 'GET', { data: { state, code } });
},
});
7 changes: 4 additions & 3 deletions ui/app/adapters/lease.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
revokePrefix(prefix) {
let url = this.buildURL() + '/leases/revoke-prefix/' + prefix;
let url = this.buildURL() + '/leases/revoke-prefix/' + encodePath(prefix);
url = url.replace(/\/$/, '');
return this.ajax(url, 'PUT');
},

forceRevokePrefix(prefix) {
let url = this.buildURL() + '/leases/revoke-prefix/' + prefix;
let url = this.buildURL() + '/leases/revoke-prefix/' + encodePath(prefix);
url = url.replace(/\/$/, '');
return this.ajax(url, 'PUT');
},
Expand Down Expand Up @@ -43,7 +44,7 @@ export default ApplicationAdapter.extend({

query(store, type, query) {
const prefix = query.prefix || '';
return this.ajax(this.buildURL() + '/leases/lookup/' + prefix, 'GET', {
return this.ajax(this.buildURL() + '/leases/lookup/' + encodePath(prefix), 'GET', {
data: {
list: true,
},
Expand Down
5 changes: 3 additions & 2 deletions ui/app/adapters/role-aws.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assign } from '@ember/polyfills';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
Expand Down Expand Up @@ -31,9 +32,9 @@ export default ApplicationAdapter.extend({
},

urlForRole(backend, id) {
let url = `${this.buildURL()}/${backend}/roles`;
let url = `${this.buildURL()}/${encodePath(backend)}/roles`;
if (id) {
url = url + '/' + id;
url = url + '/' + encodePath(id);
}
return url;
},
Expand Down
2 changes: 2 additions & 0 deletions ui/app/adapters/role-jwt.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import ApplicationAdapter from './application';
import { inject as service } from '@ember/service';
import { get } from '@ember/object';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
router: service(),

findRecord(store, type, id, snapshot) {
let [path, role] = JSON.parse(id);
path = encodePath(path);

let namespace = get(snapshot, 'adapterOptions.namespace');
let url = `/v1/auth/${path}/oidc/auth_url`;
Expand Down
5 changes: 3 additions & 2 deletions ui/app/adapters/role-pki.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assign } from '@ember/polyfills';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
Expand Down Expand Up @@ -31,9 +32,9 @@ export default ApplicationAdapter.extend({
},

urlForRole(backend, id) {
let url = `${this.buildURL()}/${backend}/roles`;
let url = `${this.buildURL()}/${encodePath(backend)}/roles`;
if (id) {
url = url + '/' + id;
url = url + '/' + encodePath(id);
}
return url;
},
Expand Down
7 changes: 4 additions & 3 deletions ui/app/adapters/role-ssh.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { assign } from '@ember/polyfills';
import { resolve, allSettled } from 'rsvp';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
Expand Down Expand Up @@ -34,9 +35,9 @@ export default ApplicationAdapter.extend({
},

urlForRole(backend, id) {
let url = `${this.buildURL()}/${backend}/roles`;
let url = `${this.buildURL()}/${encodePath(backend)}/roles`;
if (id) {
url = url + '/' + id;
url = url + '/' + encodePath(id);
}
return url;
},
Expand Down Expand Up @@ -84,7 +85,7 @@ export default ApplicationAdapter.extend({

findAllZeroAddress(store, query) {
const { backend } = query;
const url = `/v1/${backend}/config/zeroaddress`;
const url = `/v1/${encodePath(backend)}/config/zeroaddress`;
return this.ajax(url, 'GET');
},

Expand Down
17 changes: 9 additions & 8 deletions ui/app/adapters/secret-engine.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { assign } from '@ember/polyfills';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

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

internalURL(path) {
let url = `/${this.urlPrefix()}/internal/ui/mounts`;
if (path) {
url = `${url}/${path}`;
url = `${url}/${encodePath(path)}`;
}
return url;
},
Expand Down Expand Up @@ -38,14 +39,14 @@ export default ApplicationAdapter.extend({

findRecord(store, type, path, snapshot) {
if (snapshot.attr('type') === 'ssh') {
return this.ajax(`/v1/${path}/config/ca`, 'GET');
return this.ajax(`/v1/${encodePath(path)}/config/ca`, 'GET');
}
return;
},

queryRecord(store, type, query) {
if (query.type === 'aws') {
return this.ajax(`/v1/${query.backend}/config/lease`, 'GET').then(resp => {
return this.ajax(`/v1/${encodePath(query.backend)}/config/lease`, 'GET').then(resp => {
resp.path = query.backend + '/';
return resp;
});
Expand All @@ -61,25 +62,25 @@ export default ApplicationAdapter.extend({
if (apiPath) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const path = snapshot.id;
const path = encodePath(snapshot.id);
return this.ajax(`/v1/${path}/${apiPath}`, options.isDelete ? 'DELETE' : 'POST', { data });
}
},

saveAWSRoot(store, type, snapshot) {
let { data } = snapshot.adapterOptions;
const path = snapshot.id;
const path = encodePath(snapshot.id);
return this.ajax(`/v1/${path}/config/root`, 'POST', { data });
},

saveAWSLease(store, type, snapshot) {
let { data } = snapshot.adapterOptions;
const path = snapshot.id;
const path = encodePath(snapshot.id);
return this.ajax(`/v1/${path}/config/lease`, 'POST', { data });
},

saveZeroAddressConfig(store, type, snapshot) {
const path = snapshot.id;
const path = encodePath(snapshot.id);
const roles = store
.peekAll('role-ssh')
.filterBy('zeroAddress')
Expand Down
5 changes: 3 additions & 2 deletions ui/app/adapters/secret-v2-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { isEmpty } from '@ember/utils';
import { get } from '@ember/object';
import ApplicationAdapter from './application';
import DS from 'ember-data';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
_url(backend, id, infix = 'data') {
let url = `${this.buildURL()}/${backend}/${infix}/`;
let url = `${this.buildURL()}/${encodePath(backend)}/${infix}/`;
if (!isEmpty(id)) {
url = url + id;
url = url + encodePath(id);
}
return url;
},
Expand Down
5 changes: 3 additions & 2 deletions ui/app/adapters/secret-v2.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable */
import { isEmpty } from '@ember/utils';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
_url(backend, id) {
let url = `${this.buildURL()}/${backend}/metadata/`;
let url = `${this.buildURL()}/${encodePath(backend)}/metadata/`;
if (!isEmpty(id)) {
url = url + id;
url = url + encodePath(id);
}
return url;
},
Expand Down
5 changes: 3 additions & 2 deletions ui/app/adapters/secret.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isEmpty } from '@ember/utils';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
Expand All @@ -26,9 +27,9 @@ export default ApplicationAdapter.extend({
},

urlForSecret(backend, id) {
let url = `${this.buildURL()}/${backend}/`;
let url = `${this.buildURL()}/${encodePath(backend)}/`;
if (!isEmpty(id)) {
url = url + id;
url = url + encodePath(id);
}

return url;
Expand Down
13 changes: 7 additions & 6 deletions ui/app/adapters/transit-key.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ApplicationAdapter from './application';
import { pluralize } from 'ember-inflector';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',
Expand Down Expand Up @@ -47,29 +48,29 @@ export default ApplicationAdapter.extend({
},

urlForSecret(backend, id) {
let url = `${this.buildURL()}/${backend}/keys/`;
let url = `${this.buildURL()}/${encodePath(backend)}/keys/`;
if (id) {
url += id;
url += encodePath(id);
}
return url;
},

urlForAction(action, backend, id, param) {
let urlBase = `${this.buildURL()}/${backend}/${action}`;
let urlBase = `${this.buildURL()}/${encodePath(backend)}/${action}`;
// these aren't key-specific
if (action === 'hash' || action === 'random') {
return urlBase;
}
if (action === 'datakey' && param) {
// datakey action has `wrapped` or `plaintext` as part of the url
return `${urlBase}/${param}/${id}`;
return `${urlBase}/${param}/${encodePath(id)}`;
}
if (action === 'export' && param) {
let [type, version] = param;
const exportBase = `${urlBase}/${type}-key/${id}`;
const exportBase = `${urlBase}/${type}-key/${encodePath(id)}`;
return version ? `${exportBase}/${version}` : exportBase;
}
return `${urlBase}/${id}`;
return `${urlBase}/${encodePath(id)}`;
},

optionsForQuery(id) {
Expand Down
3 changes: 2 additions & 1 deletion ui/app/components/key-value-header.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { computed } from '@ember/object';
import Component from '@ember/component';
import utils from 'vault/lib/key-utils';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default Component.extend({
tagName: 'nav',
Expand Down Expand Up @@ -31,7 +32,7 @@ export default Component.extend({
let crumbs = [];
const root = this.get('root');
const baseKey = this.get('baseKey.display') || this.get('baseKey.id');
const baseKeyModel = this.get('baseKey.id');
const baseKeyModel = encodePath(this.get('baseKey.id'));

if (root) {
crumbs.push(root);
Expand Down
13 changes: 12 additions & 1 deletion ui/app/components/linked-block.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import hbs from 'htmlbars-inline-precompile';
import { encodePath } from 'vault/utils/path-encoding-helpers';

let LinkedBlockComponent = Component.extend({
router: service(),
Expand All @@ -11,6 +12,8 @@ let LinkedBlockComponent = Component.extend({

queryParams: null,

encode: false,

click(event) {
const $target = this.$(event.target);
const isAnchorOrButton =
Expand All @@ -19,7 +22,15 @@ let LinkedBlockComponent = Component.extend({
$target.closest('button', event.currentTarget).length > 0 ||
$target.closest('a', event.currentTarget).length > 0;
if (!isAnchorOrButton) {
const params = this.get('params');
let params = this.get('params');
if (this.encode) {
params = params.map((param, index) => {
if (index === 0 || typeof param !== 'string') {
return param;
}
return encodePath(param);
});
}
const queryParams = this.get('queryParams');
if (queryParams) {
params.push({ queryParams });
Expand Down
12 changes: 10 additions & 2 deletions ui/app/components/navigate-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Component from '@ember/component';
import utils from 'vault/lib/key-utils';
import keys from 'vault/lib/keycodes';
import FocusOnInsertMixin from 'vault/mixins/focus-on-insert';
import { encodePath } from 'vault/utils/path-encoding-helpers';

const routeFor = function(type, mode) {
const MODES = {
Expand Down Expand Up @@ -43,8 +44,15 @@ export default Component.extend(FocusOnInsertMixin, {
filterMatchesKey: null,
firstPartialMatch: null,

transitionToRoute: function() {
this.get('router').transitionTo(...arguments);
transitionToRoute(...args) {
let params = args.map((param, index) => {
if (index === 0 || typeof param !== 'string') {
return param;
}
return encodePath(param);
});

this.get('router').transitionTo(...params);
},

shouldFocus: false,
Expand Down
3 changes: 2 additions & 1 deletion ui/app/components/secret-link.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { computed } from '@ember/object';
import Component from '@ember/component';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export function linkParams({ mode, secret, queryParams }) {
let params;
Expand All @@ -8,7 +9,7 @@ export function linkParams({ mode, secret, queryParams }) {
if (!secret || secret === ' ') {
params = [route + '-root'];
} else {
params = [route, secret];
params = [route, encodePath(secret)];
}

if (queryParams) {
Expand Down
Loading

0 comments on commit b585c20

Please sign in to comment.