-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
OCS API for server-to-server sharing #12452
Conversation
The API looks good in general. |
Mhm. Would be great to incorporate either OCS with the AppFramework somehow or switch to REST routes powered by AppFramework controllers. That way we would be able to use all advantages of the AppFramework also in OCS routes... - Let me file a technical debt issue about that. |
I agree, from a standardization point of view this would make sense. I gave it a try, I could register following routes in core:
all the code will still be in files_sharing. This works as long as the app is enabled. If the app is disabled the API will return
|
👍 |
622c767
to
431b756
Compare
2cfa269
to
1d9906a
Compare
Thx |
1d9906a
to
04eb1c7
Compare
This is now ready for review. To try it out you can try follwing:
this should create a corresponding entry in accept/decline can be tested with a normal link share. Just create a link share and use the 'id' and 'token' from
and
|
} | ||
|
||
private function isS2SEnabled() { | ||
return \OCP\App::isEnabled('files_sharing'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about \OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled
and \OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled
?
04eb1c7
to
7d2260f
Compare
@LukasReschke good catch, I addressed all your comments. |
9c47274
to
89a87cb
Compare
👎 Introduces a critical security bug. - Will elaborate in an inline comment. |
|
||
if ($share) { | ||
// userId must be set to the user who unshares | ||
\OC_User::setUserId($share['uid_owner']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💣 💣 💣
This introduces a security bug. - \OC_User::setUserId($foo)
will also set the user session to the user:
/**
* Sets user id for session and triggers emit
*/
public static function setUserId($uid) {
\OC::$server->getSession()->set('user_id', $uid);
}
Since neither $token
nor $id
are secrets (you have them if somebody sent you a public link) this means an unauthenticated adversary can login as one of those users without providing any credentials.
💣 💣 💣
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem here is that while unshare we call the unshare hook to which various apps will listen. E.g. encryption to remove the corresponding share key. This hooks expect that unshare was triggered by a logged-in user getUser() for example to construct the correct path.
Since nobody login here there will be no session from a specific user. So what is the concrete problem if I set the user in the session for this call?
Also keep in mind that we only reach this point if the user who send the request provided a valid share ID and token (which could be seen as some kind of username/password in this context). Because the token is only known by you and the recipient of the server2server share.
Any other idea how to solve the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem here is that while unshare we call the unshare hook to which various apps will listen. E.g. encryption to remove the corresponding share key. This hooks expect that unshare was triggered by a logged-in user getUser() for example to construct the correct path.
Since nobody login here there will be no session from a specific user. So what is the concrete problem if I set the user in the session for this call?
The problem is that you create a valid session for $share['uid_owner']
and neither the token nor the id are really secrets. If you have access to a public share you know the token and enumerating an ID is just a 20liner.
The problem here is:
- You share the folder "bar" publicy (via link)
- You send the link of "bar" to Bob
- Bob accesses the decline URL
- Bob receives a valid session (the one in set-cookie), with that session he is authenticated (just copy this in your browser and enjoy being logged-in)
Any other idea how to solve the problem?
No. But no magic with setUserId
please. Also unsetting it after that is not what we should do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or as a practical example:
- Login as user "admin"
- Create a folder "foo"
- Share "foo" publicy (
http://localhost/core/index.php/s/aGCjLi78JOzFua4
) - Delete all cookies
- Send a decline request
➜ ~ curl -X POST http://localhost/core/ocs/v1.php/cloud/shares/1/decline -d token=aGCjLi78JOzFua4 -v
* Hostname was NOT found in DNS cache
* Trying ::1...
* Connected to localhost (::1) port 80 (#0)
> POST /core/ocs/v1.php/cloud/shares/1/decline HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost
> Accept: */*
> Content-Length: 21
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 21 out of 21 bytes
< HTTP/1.1 200 OK
< Date: Mon, 01 Dec 2014 18:18:10 GMT
* Server Apache/2.4.9 (Unix) PHP/5.6.2 is not blacklisted
< Server: Apache/2.4.9 (Unix) PHP/5.6.2
< X-Powered-By: PHP/5.6.2
< Set-Cookie: ocgns13bl46f=9b6krapplmghdc8n7fqfmndg06; path=/core; HttpOnly
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: Sameorigin
< Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src *; font-src 'self' data:; media-src *; connect-src *
< X-Robots-Tag: none
< Transfer-Encoding: chunked
< Content-Type: text/xml; charset=UTF-8
<
<?xml version="1.0"?>
<ocs>
<meta>
<status>ok</status>
<statuscode>100</statuscode>
<message/>
</meta>
<data/>
</ocs>
* Connection #0 to host localhost left intact
6.Copy the cookie's value (9b6krapplmghdc8n7fqfmndg06
) into your browser and have fun being logged-in as user "admin".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that's bad... Of course you shouldn't get access to my ownCloud just because I shared a file with you. I will think about it... Does someone else has a idea how to address the problem?
@LukasReschke I appreciate the discussion and I think we should definitely have this discussion. But I don't think that this PR is the right place and the right time for it. I think we should discuss this on devel@owncloud.org independent from this PR. This PR is a small part of a large feature for OC8 and we all know the deadlines. We shouldn't delay it because of a needed discussion about OCS and how this fits with the app framework. |
Tests pass locally, I create a new PR for Jenkins: #12541 |
My problem with that is that merging this will require the API to be unchangeable for quite a time. Resulting in a lot of additional code smell that we can't clean up easily. Then again: Why do we need to use OCS? - It's a pseudo-standard at best. Why can't we just use regular controllers and use If we go the route with adding this we have to support the A sum-up can also be found at #12454 - I'll also send a heads-up to the ML about that. I'll not give this implementation my 👍 just because I don't want to be the one held responsible for letting code in that we could have implemented better. - I'll do a security review later though… |
@LukasReschke we use ocs already for some key apis and we will use it for more in the future. I don't understand the resistance here. |
We could have URLs relative to the app, thats what the share API in apps/files_sharing/api/local.php does for example. The reason why we decided to have more general URLs is here: #12452 (comment) |
My resistance is pointed out at #12452 (comment) - the OCS implementation is just really really really bad compared to the other possibilities we have. And this will lead to bugs. It did in the past and it will pretty much in the future. I just don't want to add more and more technical debt to the whole project.
Dito. |
That said the critical security bug discovered in this PR would not have been possible with the AppFramework as session writing is blocked and |
0bf6dae
to
83c1d00
Compare
* | ||
* @param string $user | ||
* @param int $fileSource | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing return statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
83c1d00
to
a1a2e0c
Compare
Looks okay from a security PoV now. However, I'll take a second look at this once we have some kind of GUI for this. - So no objections from my side beside the above stated statement. |
fcbd3d7
to
6a8ad18
Compare
Thanks @LukasReschke ! With every piece the picture will become more clear, would be great if you could also review the following steps. Hopefully the unit tests are now also fixed, just waiting for Jenkins. Would be great to have a second reviewer... Maybe @DeepDiver1975 or @MorrisJobke ? Thanks! |
6a8ad18
to
2e2116e
Compare
2e2116e
to
698ecbf
Compare
A new inspection was created. |
The inspection completed: 11 new issues, 44 updated code elements |
🚀 Test PASSed. 🚀 Edited by @MorrisJobke copied over from #12567 (comment) |
Test passed: #12567 (comment) |
Still need a second reviewer. Would be great to get this in to be able to continue with the other parts of server-to-server sharing |
@schiesbn Review exchange? #12406 needs reviewers too ;) I will now review this one. |
Curl calls succeed and works as posted in the first comment. Code isn't the best, but I think that it impossible to refactor this to a proper state until january -> 👍 |
OCS API for server-to-server sharing
OCS API for server2server sharing as part of #12285 .
This is work in progress, I just want to give people a chance to look at it early.
This is how the API will look like:
POST to create new server2server share
post data: shareWith, token, name, remote, remote_id, owner
POST to notify that the share was accepted
post data: token
POST to notify that the share was declined
post data: token
POST to unshare server-to-server share
post data: 'token'
Known Issue: