Skip to content

Enumerator should be able to access only open Form#968

Merged
sadiqkhoja merged 3 commits intogetodk:masterfrom
sadiqkhoja:security/form-form-verb
Sep 14, 2023
Merged

Enumerator should be able to access only open Form#968
sadiqkhoja merged 3 commits intogetodk:masterfrom
sadiqkhoja:security/form-form-verb

Conversation

@sadiqkhoja
Copy link
Contributor

@sadiqkhoja sadiqkhoja commented Sep 9, 2023

Closes sec#2

Impact:

Following endpoints were accessible for "App User", "Data Collector" and "Public link" when Form was closed, after this change they return 403:

  • /v1/projects/1/forms/:name
  • /v1/projects/1/forms/:name.xls
  • /v1/projects/1/forms/:name.xml
  • /v1/projects/1/forms/:name/versions
  • /v1/projects/1/forms/:name/fields
  • /v1/projects/1/forms/:name/manifest
  • /v1/projects/1/forms/:name/attachments
  • /v1/projects/1/forms/:name/attachments/:name.csv

What has been done to verify that this works as intended?

Integration tests + Manual testing

Why is this the best possible solution? Were any other approaches considered?

Discussed the solution over Slack

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

None

Does this change require updates to the API documentation? If so, please update docs/api.md as part of this PR.

No

Before submitting this PR, please make sure you have:

  • run make test-full and confirmed all checks still pass OR confirm CircleCI build passes
  • verified that any code from external sources are properly credited in comments or that everything is internally sourced

@sadiqkhoja sadiqkhoja force-pushed the security/form-form-verb branch from d002b19 to 7d6f380 Compare September 11, 2023 20:46
@sadiqkhoja sadiqkhoja marked this pull request as ready for review September 11, 2023 20:55
@sadiqkhoja sadiqkhoja requested a review from ktuite September 11, 2023 20:55
Comment on lines +54 to +57
// `open_form` is subset of `form` so if someone has grant access on `form`
// they should be able do it on `open_form` as well
if (has.has('form.list')) has.add('open_form.list');
if (has.has('form.read')) has.add('open_form.read');
Copy link
Member

Choose a reason for hiding this comment

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

Rather than inferring open_form.list and open_form.read from form.list and form.read, could we add open_form.list and open_form.read to the list of verbs for admins and project managers? I think that would simplify some of the SQL below as well.

Copy link
Member

@ktuite ktuite left a comment

Choose a reason for hiding this comment

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

Talked to Sadiq interactively just now and I'm convinced that this is a sensible tradeoff of code complexity vs. cleanly reasoning about the verbs.

With this approach, the meaning of form.list and form.read doesn't change for viewers/managers/admins, it continues to mean "access to all forms regardless of their state".

The lower access roles have their form verbs removed and replaced with open_form verbs, which also makes sense -- we're limiting the access for these roles.

If we were instead to add open_form.list/read to the higher access roles and try to use it, we would need to forever maintain this double verb (form + open_form) and form on its own might take on a kind of unintentional closed_form meaning. Anyone who happened to create custom roles (through the DB) would also need to know about this double verb and need to remember to add the lower level open_form verb to make things work.

(One example where we already have to check a double verb is in the _getSql query of Projects where users must have project.read and form.list. This check makes sense to me, though, and isn't nearly as complicated as the Forms queries.)

Caveats I remember from code review:

  • canAssignRole() has to change because higher access roles like admins/managers are expected to have all the verbs they assign to lower access roles, but admins don't have open_form verb so the function fakes it if that role has the superset form verb.

@matthew-white
Copy link
Member

Very helpful explanation, that sounds reasonable to me. I can see how there are tradeoffs here. It's a tricky problem!

@matthew-white
Copy link
Member

matthew-white commented Sep 13, 2023

Just to make sure I'm understanding, Data Collectors will still be able to access closing forms over the API, right? So they'll see a closing form in the forms table, but then Frontend will restrict them from actually navigating to the form page? If that's the case, I'm thinking of filing a separate Frontend issue about that. Frontend could hide closing forms from Data Collectors in the forms table.

@sadiqkhoja
Copy link
Contributor Author

I'm thinking of filing a separate Frontend issue about that. Frontend could hide closing forms from Data Collectors in the forms table.

I am not sure what's the ideal here. We allow "App Users" and "Public links" to submit against "Closing Forms", by that logic "Data Collector" should also be able to submit. But if they can't see the form in the form list then how are they gonna submit, by saving Enketo URL somewhere offline?

@matthew-white
Copy link
Member

Hmm I see what you mean. I don't remember whether we've discussed how Data Collectors should interact with closing forms. Maybe it's not likely that a project with Data Collectors would use the closing state.

For what it's worth, here's what's currently shown in Frontend to a Data Collector:

So I think a Data Collector won't be able to use Frontend to submit to a closing form. If a Data Collector should be able to, we could change the behavior in Frontend, though maybe this situation just doesn't come up that much.

So they'll see a closing form in the forms table, but then Frontend will restrict them from actually navigating to the form page?

For some reason, I was thinking that Frontend would link to the form page, but that's not the case. So I don't think I'd file an issue after all.

@sadiqkhoja sadiqkhoja force-pushed the security/form-form-verb branch from 519fa19 to 02d3bcb Compare September 14, 2023 21:07
@sadiqkhoja sadiqkhoja merged commit 5579559 into getodk:master Sep 14, 2023
alxndrsn pushed a commit to alxndrsn/odk-central-backend that referenced this pull request Jun 3, 2025
yanokwa pushed a commit to yanokwa/odk-central-backend that referenced this pull request Feb 9, 2026
* Fixes sec#2: add  verbs

so that enumerators can access only open Forms

* let Data collector access closing forms

* polish some of the tests
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