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

Do not use FormApply#applyResponse to execute arbitrary javascript #481

Merged
merged 4 commits into from
Oct 23, 2023

Conversation

yaroslavafenkin
Copy link
Contributor

@yaroslavafenkin yaroslavafenkin commented Sep 13, 2023

Motivated by jenkinsci/jenkins#8351.
That PR changes FormApply#applyResponse method to make it CSP compatible in a way that does not allow to execute arbitrary javascript as a callback.

Looking at the usages of FormApply#applyResponse in the ecosystem its most common (and perhaps intended) use is to show a notification after "Apply" button (or alike) was clicked. In credentials-plugin it's used in a "add credentials in-place" form, and the calls are rather uncommon.
Two calls are FormApply.applyResponse("window.alert(...)"), which could easily be replaced by the new CSP compatible version FormApply.showNotification from the core PR linked above.
Third call is worse - FormApply.applyResponse("window.credentials.refreshAll();").
My initial attempt was to keep using FormApply.applyResponse mechanism, but moving window.credentials.refreshAll() to .js and making that execute at the right time turned out to be far from trivial.

After analysing the code for a bit more there seems to be no reason to keep using FormApply.applyResponse, hence this PR gets rid of it. It changes the way that form is submitted, and gets rid of javascript code needed for the FormApply.applyResponse mechanism to work. Instead server now responds with data for the notification, and javascript code uses that data to call notificationBar.show(...). window.credentials.refreshAll() was also moved to .js file, and is executed after credentials were successfully added and response was received.

Testing done

Tested interactively by adding credentials via "add credentials in-place" form. Made sure credentials were added successfully and immediately available in the dropdown after the form popup was closed.
Tested error paths by attaching the debugger and changing values through that, since I found no way to make credentials domain non-modifiable via UI.

Submitter checklist

@daniel-beck daniel-beck self-requested a review September 25, 2023 13:27
@yaroslavafenkin yaroslavafenkin marked this pull request as ready for review September 25, 2023 14:05
@yaroslavafenkin yaroslavafenkin requested a review from a team as a code owner September 25, 2023 14:05
Copy link
Contributor

@Kevin-CB Kevin-CB left a comment

Choose a reason for hiding this comment

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

Except for the small comment I made, I have nothing to add.
I tested your PR locally and it works as expected.

}
store.checkPermission(CredentialsStoreAction.CREATE);
Credentials credentials = req.bindJSON(Credentials.class, data.getJSONObject("credentials"));
store.addCredentials(wrapper.getDomain(), credentials);
FormApply.applyResponse("window.credentials.refreshAll();").generateResponse(req, rsp, null);
return new JSONObject()
.accumulate("message", "Credentials created")
Copy link
Contributor

Choose a reason for hiding this comment

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

Well, that doesn't always result in the creation of credentials, e.g when ID already exists, it won't create anything.
You could use the boolean result of addCredentials(...) to adapt your message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You could use the boolean result of addCredentials(...) to adapt your message.

Oh, that sounds great to me, I've missed that there's return value from addCredentials.

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 think it would be weird to show a notification saying "Credentials not added" and not specifying reason why. So I'm unsure at the moment how to act on this, will give it another thought.

Copy link
Member

Choose a reason for hiding this comment

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

Existing implementations seem to return false when the specified domain already contains a credential with the specified ID. Unsure whether it's valid to just claim that's the cause though (even if it looks plausible).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And also if domain doesn't exist it seems. See

Unsure under what circumstances that path would be reachable.

@Wadeck Wadeck requested a review from a team September 26, 2023 13:07
* use `#element` over `#accumulate`
* show different notification when credentials weren't added
Copy link
Contributor

@car-roll car-roll left a comment

Choose a reason for hiding this comment

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

LGTM but to be fair, I focused more on the java part

@rsandell rsandell added the chore label Oct 23, 2023
@rsandell rsandell merged commit b83506d into jenkinsci:master Oct 23, 2023
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants