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 - fix encoding for user-entered paths #6294

Merged
merged 19 commits into from
Mar 1, 2019
Merged

Conversation

meirish
Copy link
Contributor

@meirish meirish commented Feb 26, 2019

By default ember will encode and decode dynamic route segments for you, but there are several places where we're using star dynamic segments which don't come with this behavior so we need to do that encoding and decoding ourselves.

This is also true in ember data - model ids are encoded when you pass them to ember data's buildUrl method. There are several places where we're constructing api URLs via string concatenation, and not properly encoding the user-entered items.

Additionally, when passing the path into the filter box on the secret list page, we were not escaping the path so that we could create a valid Regex object. This meant that any characters that were valid in Regex pattern matching being present in the paths could potentially cause an error.

This PR changes the app to make sure we're encoding when passing elements to star segment urls, decoding when we're pulling params from those same routes, and properly escaping strings before passing them to the Regex constructor in the list-controller mixin.

Fixes #6282 .

@meirish meirish marked this pull request as ready for review February 27, 2019 20:54
johncowen
johncowen previously approved these changes Feb 28, 2019
Copy link

@johncowen johncowen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Matthew!

There's a load of comments here just to triple check certain vars and whether they should be encoded or not, I'm sure they are fine but its just incase, I'd rather notice and say than not.

Also theres a query in there about the encodeURIComponent vs extra encoding in RouteRecognizer. I'm quibbling about changing consul to use extra encoding also (right now I'm pretty sure we just use encodeURIComponent, what's your thoughts on that?

Other than that mainly just nits

👍

}
if (action === 'export' && param) {
let [type, version] = param;
const exportBase = `${urlBase}/${type}-key/${id}`;
const exportBase = `${urlBase}/${type}-key/${encodePath(id)}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure you've checked these but just a triple sanity check that action, param version and type are hardcoded elsewhere/not user generated. There are a couple of others I think down below. I'll just put a little comment next to them so you know where, but same thing, just a triple sanity check.

Actually, just spotted something, 1 question around a slightly different thing here. You treat param as a string on line 66, but then it's an array on line 69? Is that ok? Maybe I read it wrong?

Sorry 1 more tiny teeny nit. I'm not sure what your let/const usage is like. You use const in one place here and let in others. Should this single const be let, or all the lets be consts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the type and action are hard-coded elsewhere in the app, the only thing the user does is name the transit key (which is the id).

Good spot on the array vs string, I'll follow up on that!

Re: const/let - yeah we need to decide as a team how we want to use this. I personally don't think const adds much most of the time (which is also why it's all over the place across the codebase), but we should decide on a standard and stick to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, found the param bit - looks like in export it is an array, and datakey it's a string - I created a ticket internally to track that as we have upcoming work in that area which would be a good time to refactor it.

}

return args;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering why the change from yargs? Also super nit, you have some vars here not sure if you want to switch those out, did this come from elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some changes I need to push - we went back to yargs-parser - but the change here had to do with handling " and ' in the web console - the tokenizer tries to be smart about where splitting should occur based on quotes and single / double quote break it. I'm thinking maybe we shouldn't support single or double quotes in paths in the web cli, but haven't landed anywhere yet.

The vars are from the source file - https://github.com/yargs/yargs-parser/blob/master/lib/tokenize-arg-string.js


const {
Normalizer: { normalizePath, encodePathSegment },
} = RouteRecognizer;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I did this in Consul Land I wondered whether to use encodeURIComponent or this slightly customized version. Just wondering if I should change to use this RouteRecognizer one also?

Just been reading this:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Description

It mentions something similar to adhere to RFC 3986. I don't follow what impact following this/not following this would mean. Do you know what the ins and outs are? Are ! etc just reserved for future or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/tildeio/route-recognizer/blob/master/lib/route-recognizer/normalizer.ts#L20 has some good comments - I was thinking it'd be nice to have the same semantics as the router. I think for adapter use it's not strictly necessary, but decoded slashes still look nicer.

']',
'^',
'_',
].map(char => `${char}some`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Water tight! 😍 I should check all these in consul land aswell really.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄 - we wanted to recreate the script from the reported issue, and doing it this way meant we got to test the web cli too (and found it buggy) so win, win!

ui/package.json Outdated
"sass-svg-uri": "^1.0.0",
"string.prototype.endswith": "^0.2.0",
"string.prototype.startswith": "^0.2.0",
"text-encoder-lite": "1.0.0",
"walk-sync": "^0.3.3",
"xstate": "^3.3.3",
"yargs-parser": "^10.0.0"
"yargs-parser": "^12.0.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh weird I thought you'd removed of yargs? Did I read it wrong or are you still using it somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tried upgrading first, then pulled in the file we were using - but this has changed in the latest back to 10.

setFilterFocus(bool) {
this.set('filterFocused', bool);
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of removals here, I guess this is all covered in ListController now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! It was previously, we just weren't using the mixin very much.


export default ApplicationAdapter.extend({
namespace: 'v1',
_url(backend, id, infix = 'data') {
let url = `${this.buildURL()}/${backend}/${infix}/`;
let url = `${this.buildURL()}/${encodePath(backend)}/${infix}/`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this was the other possibly user generated value here infix. I'm 99.9% sure it's probably hardcoded somewhere else I can see here. But just to triple sanity check with you in case its coming from a user generated value somewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it's hardcoded - it'll either be data or metadata - the apis for v2 have that prefix (infix here because there's /v1/backend_path at the start of all of them).

}
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 + '/';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again just a sanity check that this doesn't need encoding here, you encode it on 49 but not on 50

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we're only encoding when it goes to the server via ajax, and when it goes to the URL for routing - here it's going to be put in ember data for the model so we want the decoded version for display.

@@ -9,7 +10,7 @@ export default ApplicationAdapter.extend({
let [path, role] = JSON.parse(id);

let namespace = get(snapshot, 'adapterOptions.namespace');
let url = `/v1/auth/${path}/oidc/auth_url`;
let url = `/v1/auth/${encodePath(path)}/oidc/auth_url`;
let redirect_uri = `${window.location.origin}${this.router.urlFor('vault.cluster.oidc-callback', {
auth_path: path,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Little sanity check, line 13 you encode line 15 you don't. 99.9% sure thats ok, but just to check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yep, urlFor is going to want encoded since it's router-related - thanks!

@meirish
Copy link
Contributor Author

meirish commented Feb 28, 2019

@johncowen Thanks for checking this out! I think I addressed all of the points you raised. The tests here just cover secret stuff as that's where Vault server is most lenient in allowed paths. I dug into the error we saw when I tried to create a transit key named #foo and it turns out that many endpoints in vault are more strict wrt characters, so that's disallowed at the server level.

@johncowen
Copy link

Ah yeah course! Makes sense. Good stuff, anyway thanks for the walkthrough and chat also, good to catch up!

John

@meirish meirish added this to the 1.1 milestone Mar 1, 2019
@meirish meirish modified the milestones: 1.1, 1.0.4 Mar 1, 2019
@meirish meirish merged commit b585c20 into master Mar 1, 2019
@meirish meirish deleted the b-ui-encode-secrets branch March 1, 2019 16:08
@dupainaulevain
Copy link

@meirish thanks for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants