Description
OAuth 2.0 support is a key requirement if we want to start make ownCloud attractive as a platform for third-party developers. (e.g. if we want that they integrate ownCloud into their application)
Basically, OAuth is a protocol that allows third-party applications to request access to protected informations without providing the password to another party.
Currently, third-party applications have to use Basic Authentication (that is sending the username and the password) to access the ownCloud instance which has the following disadvantages:
- Users have to provide their credentials to third-party applications. If one of the third-party providers has been compromised the ownCloud login will be lost.
- An authentication can only be "revoked" by changing the user password which is suboptimal.
- Third-Party developers do currently have access to the whole ownCloud instance, they even could change your password.
Instead of using passwords for authorization OAuth is using unique tokens for every client. In OAuth, the client requests access to the needed resources (scopes) by redirecting the user to a website where he has to approve these permissions.
For example, a user might grant a "mobile news" application only access to the "news" API. Instead of entering his own credentials into the application the user just has to approve authorize the application via the ownCloud web interface.
User stories
- As a user, I want to be able to grant third-party applications access to my data without providing them my password or granting access to the whole instance.
- As a user and administrator, I want to see which applications have access to which data and manage them.
- As a developer, I want to use standard libraries to integrate with ownCloud.
Acceptance criteria
- Server MUST verify the CSRF token in any case. A request without CSRF token MUST be logged. (this is something that we should add to the CSRF implementation directly)
- Server MUST ensure that no session fixation is possible
- Server MUST not leak the authorization code (e.g. due to an open redirector)
- OAuth implementation MUST be fully audited and self-implemented. I'm tired by vulnerabilities in third-party code. This is not acceptable in such critical components.
- Server MUST verify the client_id issued for tokens
- Server MUST give applications the possibility to create their own permissions
- Users MUST be able to see see all the applications that have been granted permission, their scope (including descriptive text), when they were last used
- Users MUST be able to revoke granted permissions
- Admins MUST be able to limit OAuth to domains or completely disable it
- Server MUST allow self-registration of applications
- Server SHOULD implement the defined scopes below
Scopes
core
- core:user:read
- Grants read access to the user's mail address and name
- core:user:write
- Grants write access to the user's mail address and name
files
- files:appfolder
- Gives application full permissions on it's own application specific folder. This appfolder will be created automatically in the users root directory
- files:list('/path/')
- Allows the application to list all files in the specified path.
- files:read('/path/')
- Allows the application to read all files in the specified path.
- files:write('/path/')
- Allows the application to edit or create files in the specified path.
- files:delete('/path/')
- Allows the application to delete files in the specified path.
files_sharing
- files_sharing:appfolder
- Gives application sharing permissions on it's own application specific folder.
- files_sharing:list('/path/')
- Gives application the possibility to list shares in this subfolder.
- files_sharing:share('/path/')
- Allows the application to share all files in the specified path.
- files_sharing:unshare('/path/')
- Allows the application to unshare all files in the specified path.
Considerations
As applications should be able to register their own scopes (e.g. "contacts:read" to allow an application to read all contacts) we need it to make it as easy as possible to define their own scopes and which permissions they do grant.
I'd propose that we add the definitions of the scopes to "appinfo.xml", since we might reuse them in future for something else than OAuth we should give them a generic name.
<scopes>
<read>
<description>Grants read access to files in $1</description>
</read>
<write>
<description>Grants write access to files in $1</description>
</write>
</scopes>
$1
refers in this case to the first parameter, $2
would refer to the second parameter etc. (see below for some examples)- Those values are used to explain the permissions to the end-user when granting authorization.
To define which controllers are accessible by a scope we should use the annotations of the appframework:
/**
* @NoAdminRequired
* @CORS
* @Scope('read')
*/
public function read() {}
/**
* @NoAdminRequired
* @CORS
* @Scope('write')
*/
public function write() {}
/**
* @NoAdminRequired
* @CORS
* @Scope('read', 'write') // 'read' or 'write' permission are required
*/
public function both() {}
The scopes are specific for a specific application, if the above controller would be in the "contacts" app it would use the "read" and "write" scope definition from it. If it wants to check other permissions the full scope name (prefixed with the application identifier and a :
) has to be provided:
/**
* @NoAdminRequired
* @CORS
* @Scope('read', 'files:read') // 'read' from the contacts app or 'read' from the files app are required
*/
public function read() {}
To read the parameters (e.g. files:foo('/blah/', 'foo')
) $this->scope->0->0
can be used. This will return the first argument of the first scope (/blah/) defined in @scope. $this->scope->0->1
would return the second parameter of the first agument (foo).
In our legacy applications which are not using the AppFramework we could use a function call as following:
\OC\User::requireScope(array('contacts:read', 'files:read'));
\OC\User::readScopeValue('contacts:read', 0); // Would read the first argument of `contacts:read`
It shall be noted that if no scope is defined no access will be granted. To allow any scope *
can be used as wildcard. (@Scope('*')
)
Summoning @karlitschek @MTRichards @DeepDiver1975 @Raydiation
Please:
- Discuss this proposal and the suggested implementation
- Schedule this feature. I'd really like to have this in ownCloud 8.