Repository navigation
feat(auth): limit scoped app passwords to the routes they open - #65340
Conversation
| $dispatcher->registerMiddleware($c->get(PublicShareMiddleware::class)); | ||
| $dispatcher->registerMiddleware($c->get(AdditionalScriptsMiddleware::class)); | ||
| // After AdditionalScriptsMiddleware, so pages are refused before their listeners run | ||
| $dispatcher->registerMiddleware($c->get(TokenScopeMiddleware::class)); |
There was a problem hiding this comment.
Own middleware instead of one more check in SecurityMiddleware, which is hand-built and already does a lot. Also registered last on purpose, the test in DIContainerTest checks the order.
| * Page renders run every app's listeners and initial state, so none reach a token with scopes | ||
| */ | ||
| #[\Override] | ||
| public function afterController(Controller $controller, string $methodName, Response $response): Response { |
There was a problem hiding this comment.
We only know it's a page once the controller returns a TemplateResponse, so it has to check after controller runs. Page GETs don't change data, so letting the controller run is fine though. What we block is the render, which pulls in every app's listeners and initial state.
d4d67af to
a2b3655
Compare
0823522 to
cf1ad78
Compare
c1b26e4 to
bdac8ee
Compare
|
@artonge I think adding multiple scopes later will be quite easy. For example we can do something like:
Either way I've moved the attribute to NCU so it can stay flexible until 37 cc @CarlSchwan |
fab26ff to
f7e03f6
Compare
| * @psalm-import-type Files_SharingRemoteShare from ResponseDefinitions | ||
| * @api | ||
| */ | ||
| #[TokenScope(scope: TokenScopes::FILES_WRITE)] |
There was a problem hiding this comment.
shouldnt this be allowing to write shares?
There was a problem hiding this comment.
Accepting mounts the share into your own files, so I decided to go with files write. The sharing write scope is for creating shares only, and a client without it should still be able to accept incoming shares. Happy to change it if you disagree?
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
…opeRequired Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
…ble API Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
65fc6f8 to
d7c0abc
Compare
Summary
Second step for limited app passwords: a token with scopes can only call the index.php and OCS routes its scopes open. Everything else gets a 403. Tokens without scopes aren't affected. DAV is in #65552.
How it works
#[TokenScope]on a method or the class (unstable API inNCU\, so apps can use it). A method's attribute replaces the class one. No attribute means refused, so new endpoints start closed<appid>:scopesfiles:files:read/files:files:write, shares, sharee search and direct linksfiles_sharing:shares:write. Calendar and contacts OCS routes in dav need the matchingdav:scopeKnown limit: an admin's calendar or contacts token can import into other users' calendars and address books via the
userparameter, and a files token can transfer ownership of files to another account.Tests
Unit tests for the middleware and its place in the stack. They pin the scopes of the share, direct link, preview and download endpoints, and check that templates, direct editing, conversion and page methods stay unannotated. Integration tests cover allowed and refused calls with a scoped token.
Next step
DAV enforcement, then the access picker in Settings.
Checklist
3. to review, feature component)stable32)AI (if applicable)