Nextcloud deprecated
Unlike oauth based file storages the Nextcloud integration works with basic authentication. Currently the user can configure his credentials himself and they are stored encrypted. The admin just needs to configure the appropriate capability for this user:
com.openexchange.capability.filestorage_nextcloud=true
A client can trigger the account creation on behalf of the user by calling the new action in the fileaccount module (fileaccount?action=new). The configuration object within the request body must contain the WebDAV root URL and the user's Nextcloud credentials.
For example:
{
"filestorageService": "nextcloud",
"displayName": "My Nextcloud Account",
"configuration": {
"login": "username",
"password": "password",
"url": "http://example.com:8080/remote.php/dav/files/username"
}
}
OAuth
OAuth requires the open-xchange-oauth package in addition to open-xchange-file-storage-webdav, see 3rd Party Integrations. OAuth itself is disabled by default and needs to be set up for the instance the deployment integrates with. Whether it is enabled is evaluated through the config cascade whenever the nextcloud capability is checked, so enabling or disabling it takes effect with a configuration reload, without a restart. As long as it is not enabled, no user is offered OAuth for Nextcloud, and the storage stays available with basic authentication.
com.openexchange.oauth.nextcloud.enabled=true
com.openexchange.oauth.nextcloud.hostname=nextcloud.example.com
com.openexchange.oauth.nextcloud.apiKey=<client id>
com.openexchange.oauth.nextcloud.apiSecret=<client secret>
com.openexchange.oauth.nextcloud.redirectUrl=https://appsuite.example.com/ajax/defer
com.openexchange.oauth.nextcloud.productName=<name shown to the user>
The deployment authenticates as a confidential client, so both the client identifier and the client secret are required. A public client that authenticates with PKCE and states no secret is not supported.
An instance that is fronted by an identity provider of its own, e.g. Keycloak, states its endpoints, which default to the ones of the identity provider built into Nextcloud otherwise.
com.openexchange.oauth.nextcloud.authorizationUrl=https://keycloak.example.com/realms/nextcloud/protocol/openid-connect/auth
com.openexchange.oauth.nextcloud.tokenUrl=https://keycloak.example.com/realms/nextcloud/protocol/openid-connect/token
com.openexchange.oauth.nextcloud.userInfoUrl=https://keycloak.example.com/realms/nextcloud/protocol/openid-connect/userinfo
The identity provider built into Nextcloud binds an access token to the user that authorized the deployment, and states no claims about that user, so it needs no scopes at all. An instance that is fronted by an identity provider of its own associates a token with one of its users by the claims the token states instead, which the identity provider may only state if a further scope asks for them, so the scopes that are requested are stated by
com.openexchange.oauth.nextcloud.scope=openid profile email offline_access
An account that is linked to an OAuth account states nothing but that account, as the URL is derived from the configured hostname. A URL that is stated for such an account is rejected, so that the access token is only ever sent to the instance that issued it.
{
"filestorageService": "nextcloud",
"displayName": "My Nextcloud Account",
"configuration": {
"account": "17"
}
}
Users and groups
The users and groups of a Nextcloud instance are matched with the ones of the server, so that a share can state who it is granted to, and so that a client can share an item with them. By default a user is matched by its mail address, falling back to the name it logs in with, and a group by its name:
com.openexchange.file.storage.nextcloud.entityResolver.attribute=mail
A Nextcloud instance identifies a user by a single value, which a deployment sets to either its mail address or the name it logs in with, so that value is matched against both attributes of a user of the server.
The user an account accesses the instance as is asked from the instance itself, as the login of an account may be the mail address of the user, and the identity an OAuth account states may be the one of an identity provider in front of the instance, while the instance names the user by its own identifier within the paths it serves, e.g. the one of the trash bin. The answer is remembered as long as the credentials of the account stay the same.
A deployment whose users and groups do not agree on those attributes can map them statically instead, which takes precedence:
com.openexchange.file.storage.nextcloud.entityResolver.mappingFile=/opt/open-xchange/etc/nextcloud-entities.list
The file states one entry per line, ':'-separated:
contextId:nextCloudUserId:oxUserId - a user of the given context
group:contextId:nextCloudGroupId:oxGroupId - a group of the given context
Only an entity that matches a search of the instance exactly is shared with, so that an item is never shared with a user whose attribute merely contains the one that was searched for.
Reducing requests
The shares of an item and the users of the instance are looked up through the OCS API, in addition to the WebDAV requests the files are accessed through. The following lookups are optional, as each of them is a request per item:
com.openexchange.file.storage.nextcloud.entityResolver.folderPermissions=false
com.openexchange.file.storage.nextcloud.entityResolver.objectPermissions=false
folderPermissionsexpresses the shares of a folder as its permissions. A listing tells whether a folder is shared, so only the shared ones require a request of their own. Disabled by default, in which case a shared folder states that it is shared, but not with whom.objectPermissionsexpresses the shares of a file as its object permissions. A listing tells whether a file is shared as well, and the shares are only looked up if a client asks for the object permissions, but still with a request per shared file. Disabled by default.
Neither of them applies to the permissions a client states for an item, which are applied to its shares in any case, as that needs no such lookup.
The folders that list the items the user shares look them up by their identifiers through a single SEARCH request, rather than by a request per shared item, so that the number of requests does not grow with the number of shares.
Rejected credentials
An instance that rejects the credentials of an account, e.g. because an app password was revoked or an OAuth authorization was withdrawn, is not asked again for a while. The rejection is remembered for the account, whose folders below the root are stated along with that error meanwhile, so that a client can tell the user to put the credentials right, rather than the instance being asked with every listing.
com.openexchange.file.storage.nextcloud.retryAfterErrorInterval=300
Credentials that are put right take effect right away, as changing the configuration of an account lets the rejection be forgotten. An OAuth account that is authorized anew is tried again once the period has passed.
Notable differences
- The account's root holds the virtual folders Personal, Shares and Team folders, along with Trash. Shares holds Shared with me, Shared with others and Shared via link. Each of them states its kind within the
metaof the folder, so that a client can tell them apart. - The folders listing the shared items are stated as virtual folders, so that a traversal of the folder tree, such as the one archiving a folder as a ZIP file, passes them over rather than archiving those items beside the folders they are located in.
- A Nextcloud instance limits the storage of a user as a whole, while a team folder it mounts into the files of a user may be limited on its own, so the quota of a folder is the one of the storage it belongs to. The Personal folder and each team folder state that quota within their
metaas well, a storage that is not limited stating-1as its total. - Each file and folder that has a counterpart in the storage states the link that opens it within the web interface of the instance as
backwardLinkwithin thenextcloudentry of itsmeta, so that a client needs not ask for it by a request of its own. The virtual folders and the items of the trash bin state none. - A preview of an item is served under an endpoint of its own, which takes the path of the item as an argument, rather than under the path of the item as an ownCloud instance serves it. A request that states the parameters of a preview along with the path of an item is answered with that item itself, so the middleware addresses that endpoint, and states no preview for an item the instance answers with
404. - The trash bin is served under a path of its own rather than being a folder within the user's files. A deleted item is restored by the instance to the location it was deleted from, or to the account's root if that location no longer exists, and is renamed by the instance if an item of the same name already exists there. The middleware looks the restored item up by its identifier afterwards, and moves it to the folder the request states if the instance restored it to the account's root because its original location is gone.
- The contents of a deleted item are not served by the instance, so a deleted item can be listed, restored and purged, but not read.
- The permissions of a folder always apply to the items it holds, so a request that asks for them not to be cascaded is answered with a warning.
- A search is performed by the instance through a
SEARCHrequest. It evaluates the name and the media type of an item, and combines those criteria with "and", "or" and "not", while it states an item no matter what a criterion on its size or on its modification date demands. Those criteria are therefore evaluated by the middleware against the items the instance states, and a term that states a criterion the middleware cannot evaluate either, e.g. the content of an item, is rejected. - The instance searches a folder recursively no matter whether a search asks for the items below it, so a search that does not is answered by the middleware leaving them out.
- The matches of a search are sorted and paged by the middleware, as the instance orders them by its own collation. A search that is sorted by the modification date, whose term the instance evaluates completely and that asks for the items below the searched folder, is the exception: its page is requested from the instance, so that the number of matches it states does not grow with the number of files.
- A share that grants access through a link is managed through the sharing API, while the ones granted to a user or a group of the instance are managed as the permissions of an item. Applying permissions therefore never changes the links of an item, and never revokes a share granted to an entity that has no counterpart on the server, as a client cannot state those.
- A link that is meant to grant the rights to upload into a folder cannot be created for a file, and a link that grants the rights to delete a file is granted the ones to change it instead, as a Nextcloud instance grants a link to a file the rights to read and to change it only.