From 0ba688c1257afe9140d452338048e636b747b57c Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Fri, 27 Dec 2024 12:07:36 +0100 Subject: [PATCH] chore(federation): add trusted server auto accept integration tests Signed-off-by: skjnldsv --- apps/federation/appinfo/routes.php | 5 + .../lib/Controller/SettingsController.php | 102 ++- apps/federation/openapi-administration.json | 384 ++++++++ apps/federation/openapi-federation.json | 511 +++++++++++ apps/federation/openapi-full.json | 863 ++++++++++++++++++ .../Controller/SettingsControllerTest.php | 29 +- .../features/bootstrap/FederationContext.php | 45 + .../federation_features/federated.feature | 219 +++-- build/integration/run.sh | 3 + 9 files changed, 2073 insertions(+), 88 deletions(-) create mode 100644 apps/federation/openapi-administration.json create mode 100644 apps/federation/openapi-federation.json create mode 100644 apps/federation/openapi-full.json diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php index 663da827de31a..0fc6e5a16aef7 100644 --- a/apps/federation/appinfo/routes.php +++ b/apps/federation/appinfo/routes.php @@ -31,6 +31,11 @@ 'url' => '/shared-secret', 'verb' => 'POST', ], + [ + 'name' => 'Settings#getServers', + 'url' => '/trusted-servers', + 'verb' => 'GET' + ], [ 'name' => 'Settings#addServer', 'url' => '/trusted-servers', diff --git a/apps/federation/lib/Controller/SettingsController.php b/apps/federation/lib/Controller/SettingsController.php index 3da38e34fb893..5b2ee257e14a0 100644 --- a/apps/federation/lib/Controller/SettingsController.php +++ b/apps/federation/lib/Controller/SettingsController.php @@ -11,10 +11,8 @@ use OCA\Federation\TrustedServers; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; -use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\OCSController; -use OCP\HintException; use OCP\IL10N; use OCP\IRequest; @@ -30,26 +28,26 @@ public function __construct( /** - * Add server to the list of trusted Nextclouds. + * Add server to the list of trusted Nextcloud servers + * + * @param string $url The URL of the server to add + * @return JSONResponse|JSONResponse + * + * 200: Server added successfully + * 404: Server not found at the given URL + * 409: Server is already in the list of trusted servers */ #[AuthorizedAdminSetting(settings: Admin::class)] public function addServer(string $url): JSONResponse { - try { - $this->checkServer(trim($url)); - } catch (HintException $e) { - return new JSONResponse([ - 'message' => 'error', - 'data' => [ - 'message' => $e->getMessage(), - 'hint' => $e->getHint(), - ], - ], $e->getCode()); + $check = $this->checkServer(trim($url)); + if ($check instanceof JSONResponse) { + return $check; } // Add the server to the list of trusted servers, all is well $id = $this->trustedServers->addServer(trim($url)); return new JSONResponse([ - 'message' => 'ok', + 'status' => 'ok', 'data' => [ 'url' => $url, 'id' => $id, @@ -59,36 +57,94 @@ public function addServer(string $url): JSONResponse { } /** - * Add server to the list of trusted Nextclouds. + * Add server to the list of trusted Nextcloud servers + * + * @param int $id The ID of the trusted server to remove + * @return JSONResponse|JSONResponse + * + * 200: Server removed successfully + * 404: Server not found at the given ID */ #[AuthorizedAdminSetting(settings: Admin::class)] public function removeServer(int $id): JSONResponse { - $this->trustedServers->removeServer($id); + try { + $this->trustedServers->removeServer($id); + return new JSONResponse([ + 'status' => 'ok', + 'data' => ['id' => $id], + ]); + } catch (\Exception $e) { + return new JSONResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $e->getMessage(), + ], + ], Http::STATUS_NOT_FOUND); + } + } + + /** + * List all trusted servers + * + * @return JSONResponse, status: 'ok'}, array{}> + * + * 200: List of trusted servers + */ + #[AuthorizedAdminSetting(settings: Admin::class)] + public function getServers(): JSONResponse { + $servers = $this->trustedServers->getServers(); + + // obfuscate the shared secret + $servers = array_map(function ($server) { + return [ + 'url' => $server['url'], + 'id' => $server['id'], + 'status' => $server['status'], + ]; + }, $servers); + + // return the list of trusted servers return new JSONResponse([ - 'message' => 'ok', - 'data' => ['id' => $id], + 'status' => 'ok', + 'data' => $servers, ]); } + /** * Check if the server should be added to the list of trusted servers or not. * - * @throws HintException + * @return JSONResponse|null + * + * 404: Server not found at the given URL + * 409: Server is already in the list of trusted servers */ #[AuthorizedAdminSetting(settings: Admin::class)] - protected function checkServer(string $url): bool { + protected function checkServer(string $url): ?JSONResponse { if ($this->trustedServers->isTrustedServer($url) === true) { $message = 'Server is already in the list of trusted servers.'; $hint = $this->l->t('Server is already in the list of trusted servers.'); - throw new HintException($message, $hint, Http::STATUS_CONFLICT); + return new JSONResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $message, + 'hint' => $hint, + ], + ], Http::STATUS_CONFLICT); } if ($this->trustedServers->isNextcloudServer($url) === false) { $message = 'No server to federate with found'; $hint = $this->l->t('No server to federate with found'); - throw new HintException($message, $hint, Http::STATUS_NOT_FOUND); + return new JSONResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $message, + 'hint' => $hint, + ], + ], Http::STATUS_NOT_FOUND); } - return true; + return null; } } diff --git a/apps/federation/openapi-administration.json b/apps/federation/openapi-administration.json new file mode 100644 index 0000000000000..f1ecd62f3d8b3 --- /dev/null +++ b/apps/federation/openapi-administration.json @@ -0,0 +1,384 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "federation-administration", + "version": "0.0.1", + "description": "Federation allows you to connect with other trusted servers to exchange the account directory.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": {} + }, + "paths": { + "/ocs/v2.php/apps/federation/trusted-servers": { + "get": { + "operationId": "settings-get-servers", + "summary": "List all trusted servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "List of trusted servers", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "status", + "url" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "integer", + "format": "int64" + }, + "url": { + "type": "string" + } + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + } + } + }, + "post": { + "operationId": "settings-add-server", + "summary": "Add server to the list of trusted Nextcloud servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "The URL of the server to add" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "message", + "url" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + }, + "404": { + "description": "Server not found at the given URL", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "hint", + "message" + ], + "properties": { + "hint": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + }, + "409": { + "description": "Server is already in the list of trusted servers", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "hint", + "message" + ], + "properties": { + "hint": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/federation/trusted-servers/{id}": { + "delete": { + "operationId": "settings-remove-server", + "summary": "Add server to the list of trusted Nextcloud servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The ID of the trusted server to remove", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server removed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + }, + "404": { + "description": "Server not found at the given ID", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + } + } + } + } + }, + "tags": [ + { + "name": "ocs_authapi", + "description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds" + } + ] +} diff --git a/apps/federation/openapi-federation.json b/apps/federation/openapi-federation.json new file mode 100644 index 0000000000000..a9371f5492688 --- /dev/null +++ b/apps/federation/openapi-federation.json @@ -0,0 +1,511 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "federation-federation", + "version": "0.0.1", + "description": "Federation allows you to connect with other trusted servers to exchange the account directory.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/federation/api/v1/shared-secret": { + "get": { + "operationId": "ocs_authapi-get-shared-secret-legacy", + "summary": "Create shared secret and return it, for legacy end-points", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "url", + "in": "query", + "description": "URL of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "token", + "in": "query", + "description": "Token of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "sharedSecret" + ], + "properties": { + "sharedSecret": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Getting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/federation/api/v1/request-shared-secret": { + "post": { + "operationId": "ocs_authapi-request-shared-secret-legacy", + "summary": "Request received to ask remote server for a shared secret, for legacy end-points", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url", + "token" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the server" + }, + "token": { + "type": "string", + "description": "Token of the server" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret requested successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Requesting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/cloud/shared-secret": { + "get": { + "operationId": "ocs_authapi-get-shared-secret", + "summary": "Create shared secret and return it", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "url", + "in": "query", + "description": "URL of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "token", + "in": "query", + "description": "Token of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "sharedSecret" + ], + "properties": { + "sharedSecret": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Getting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "ocs_authapi-request-shared-secret", + "summary": "Request received to ask remote server for a shared secret", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url", + "token" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the server" + }, + "token": { + "type": "string", + "description": "Token of the server" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret requested successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Requesting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + } + }, + "tags": [ + { + "name": "ocs_authapi", + "description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds" + } + ] +} diff --git a/apps/federation/openapi-full.json b/apps/federation/openapi-full.json new file mode 100644 index 0000000000000..63f22be74e26a --- /dev/null +++ b/apps/federation/openapi-full.json @@ -0,0 +1,863 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "federation-full", + "version": "0.0.1", + "description": "Federation allows you to connect with other trusted servers to exchange the account directory.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/federation/api/v1/shared-secret": { + "get": { + "operationId": "ocs_authapi-get-shared-secret-legacy", + "summary": "Create shared secret and return it, for legacy end-points", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "url", + "in": "query", + "description": "URL of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "token", + "in": "query", + "description": "Token of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "sharedSecret" + ], + "properties": { + "sharedSecret": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Getting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/federation/api/v1/request-shared-secret": { + "post": { + "operationId": "ocs_authapi-request-shared-secret-legacy", + "summary": "Request received to ask remote server for a shared secret, for legacy end-points", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url", + "token" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the server" + }, + "token": { + "type": "string", + "description": "Token of the server" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret requested successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Requesting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/cloud/shared-secret": { + "get": { + "operationId": "ocs_authapi-get-shared-secret", + "summary": "Create shared secret and return it", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "url", + "in": "query", + "description": "URL of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "token", + "in": "query", + "description": "Token of the server", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "sharedSecret" + ], + "properties": { + "sharedSecret": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Getting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "ocs_authapi-request-shared-secret", + "summary": "Request received to ask remote server for a shared secret", + "tags": [ + "ocs_authapi" + ], + "security": [ + {}, + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url", + "token" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the server" + }, + "token": { + "type": "string", + "description": "Token of the server" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Shared secret requested successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Requesting shared secret is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/federation/trusted-servers": { + "get": { + "operationId": "settings-get-servers", + "summary": "List all trusted servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "List of trusted servers", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "status", + "url" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "integer", + "format": "int64" + }, + "url": { + "type": "string" + } + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + } + } + }, + "post": { + "operationId": "settings-add-server", + "summary": "Add server to the list of trusted Nextcloud servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "The URL of the server to add" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "message", + "url" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + }, + "404": { + "description": "Server not found at the given URL", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "hint", + "message" + ], + "properties": { + "hint": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + }, + "409": { + "description": "Server is already in the list of trusted servers", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "hint", + "message" + ], + "properties": { + "hint": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/federation/trusted-servers/{id}": { + "delete": { + "operationId": "settings-remove-server", + "summary": "Add server to the list of trusted Nextcloud servers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The ID of the trusted server to remove", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Server removed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + }, + "status": { + "type": "string", + "enum": [ + "ok" + ] + } + } + } + } + } + }, + "404": { + "description": "Server not found at the given ID", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "status" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + }, + "status": { + "type": "string", + "enum": [ + "error" + ] + } + } + } + } + } + } + } + } + } + }, + "tags": [ + { + "name": "ocs_authapi", + "description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds" + } + ] +} diff --git a/apps/federation/tests/Controller/SettingsControllerTest.php b/apps/federation/tests/Controller/SettingsControllerTest.php index a2969b510ad09..5652e2c055e52 100644 --- a/apps/federation/tests/Controller/SettingsControllerTest.php +++ b/apps/federation/tests/Controller/SettingsControllerTest.php @@ -9,8 +9,7 @@ use OCA\Federation\Controller\SettingsController; use OCA\Federation\TrustedServers; -use OCP\AppFramework\Http\DataResponse; -use OCP\HintException; +use OCP\AppFramework\Http\JSONResponse; use OCP\IL10N; use OCP\IRequest; use Test\TestCase; @@ -56,20 +55,18 @@ public function testAddServer(): void { ->willReturn(true); $result = $this->controller->addServer('url'); - $this->assertTrue($result instanceof DataResponse); + $this->assertTrue($result instanceof JSONResponse); $data = $result->getData(); $this->assertSame(200, $result->getStatus()); - $this->assertSame('url', $data['url']); - $this->assertArrayHasKey('id', $data); + $this->assertSame('url', $data['data']['url']); + $this->assertArrayHasKey('id', $data['data']); } /** * @dataProvider checkServerFails */ public function testAddServerFail(bool $isTrustedServer, bool $isNextcloud): void { - $this->expectException(HintException::class); - $this->trustedServers ->expects($this->any()) ->method('isTrustedServer') @@ -81,7 +78,15 @@ public function testAddServerFail(bool $isTrustedServer, bool $isNextcloud): voi ->with('url') ->willReturn($isNextcloud); - $this->controller->addServer('url'); + $result = $this->controller->addServer('url'); + $this->assertTrue($result instanceof JSONResponse); + if ($isTrustedServer) { + $this->assertSame(409, $result->getStatus()); + } + + if (!$isNextcloud) { + $this->assertSame(404, $result->getStatus()); + } } public function testRemoveServer(): void { @@ -89,7 +94,7 @@ public function testRemoveServer(): void { ->method('removeServer') ->with(1); $result = $this->controller->removeServer(1); - $this->assertTrue($result instanceof DataResponse); + $this->assertTrue($result instanceof JSONResponse); $this->assertSame(200, $result->getStatus()); } @@ -106,7 +111,7 @@ public function testCheckServer(): void { ->willReturn(true); $this->assertTrue( - $this->invokePrivate($this->controller, 'checkServer', ['url']) + $this->invokePrivate($this->controller, 'checkServer', ['url']) === null ); } @@ -114,8 +119,6 @@ public function testCheckServer(): void { * @dataProvider checkServerFails */ public function testCheckServerFail(bool $isTrustedServer, bool $isNextcloud): void { - $this->expectException(HintException::class); - $this->trustedServers ->expects($this->any()) ->method('isTrustedServer') @@ -128,7 +131,7 @@ public function testCheckServerFail(bool $isTrustedServer, bool $isNextcloud): v ->willReturn($isNextcloud); $this->assertTrue( - $this->invokePrivate($this->controller, 'checkServer', ['url']) + $this->invokePrivate($this->controller, 'checkServer', ['url']) instanceof JSONResponse ); } diff --git a/build/integration/features/bootstrap/FederationContext.php b/build/integration/features/bootstrap/FederationContext.php index bbd81396df56a..538dfb56cd3d0 100644 --- a/build/integration/features/bootstrap/FederationContext.php +++ b/build/integration/features/bootstrap/FederationContext.php @@ -7,6 +7,7 @@ use Behat\Behat\Context\Context; use Behat\Behat\Context\SnippetAcceptingContext; use Behat\Gherkin\Node\TableNode; +use PHPUnit\Framework\Assert; require __DIR__ . '/../../vendor/autoload.php'; @@ -168,8 +169,52 @@ public function remoteServerIsStopped() { self::$phpFederatedServerPid = ''; } + /** + * @BeforeScenario @TrustedFederation + */ + public function theServersAreTrustingEachOther() { + $this->asAn('admin'); + // Trust the remote server on the local server + $this->usingServer('LOCAL'); + $this->sendRequestForJSON('POST', '/apps/federation/trusted-servers', ['url' => 'http://localhost:' . getenv('PORT')]); + Assert::assertTrue(($this->response->getStatusCode() === 200 || $this->response->getStatusCode() === 409)); + + // Trust the local server on the remote server + $this->usingServer('REMOTE'); + $this->sendRequestForJSON('POST', '/apps/federation/trusted-servers', ['url' => 'http://localhost:' . getenv('PORT_FED')]); + // If the server is already trusted, we expect a 409 + Assert::assertTrue(($this->response->getStatusCode() === 200 || $this->response->getStatusCode() === 409)); + } + + /** + * @AfterScenario @TrustedFederation + */ + public function theServersAreNoLongerTrustingEachOther() { + $this->asAn('admin'); + // Untrust the remote servers on the local server + $this->usingServer('LOCAL'); + $this->sendRequestForJSON('GET', '/apps/federation/trusted-servers'); + $this->theHTTPStatusCodeShouldBe('200'); + $trustedServersIDs = array_map(fn ($server) => $server->id, json_decode($this->response->getBody())->data); + foreach ($trustedServersIDs as $id) { + $this->sendRequestForJSON('DELETE', '/apps/federation/trusted-servers/' . $id); + $this->theHTTPStatusCodeShouldBe('200'); + } + + // Untrust the local server on the remote server + $this->usingServer('REMOTE'); + $this->sendRequestForJSON('GET', '/apps/federation/trusted-servers'); + $this->theHTTPStatusCodeShouldBe('200'); + $trustedServersIDs = array_map(fn ($server) => $server->id, json_decode($this->response->getBody())->data); + foreach ($trustedServersIDs as $id) { + $this->sendRequestForJSON('DELETE', '/apps/federation/trusted-servers/' . $id); + $this->theHTTPStatusCodeShouldBe('200'); + } + } + protected function resetAppConfigs() { $this->deleteServerConfig('files_sharing', 'incoming_server2server_group_share_enabled'); $this->deleteServerConfig('files_sharing', 'outgoing_server2server_group_share_enabled'); + $this->deleteServerConfig('files_sharing', 'federated_trusted_share_auto_accept'); } } diff --git a/build/integration/federation_features/federated.feature b/build/integration/federation_features/federated.feature index 81a3d3abd02c0..d3a414cb8046c 100644 --- a/build/integration/federation_features/federated.feature +++ b/build/integration/federation_features/federated.feature @@ -8,7 +8,7 @@ Feature: federated Scenario: Federate share a file with another server Given Using server "REMOTE" And user "user1" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE" Then the OCS status code should be "100" @@ -30,6 +30,12 @@ Feature: federated | displayname_owner | user0 | | share_with | user1@REMOTE | | share_with_displayname | user1 | + Given Using server "REMOTE" + And As an "user1" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 0 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + Then the list of returned shares has 1 shares Scenario: Federated group share a file with another server Given Using server "REMOTE" @@ -40,7 +46,7 @@ Feature: federated And As an "admin" And Add user "gs-user1" to the group "group1" And Add user "gs-user2" to the group "group1" - And Using server "LOCAL" + Given Using server "LOCAL" And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes" And user "gs-user0" exists When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE" @@ -64,11 +70,10 @@ Feature: federated | share_with | group1@REMOTE | | share_with_displayname | group1@REMOTE | - Scenario: Federate share a file with local server Given Using server "LOCAL" And user "user0" exists - And Using server "REMOTE" + Given Using server "REMOTE" And user "user1" exists When User "user1" from server "REMOTE" shares "/textfile0.txt" with user "user0" from server "LOCAL" Then the OCS status code should be "100" @@ -94,10 +99,10 @@ Feature: federated Scenario: Remote sharee can see the pending share Given Using server "REMOTE" And user "user1" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE" - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" Then the OCS status code should be "100" @@ -122,11 +127,11 @@ Feature: federated And As an "admin" And Add user "gs-user1" to the group "group1" And Add user "gs-user2" to the group "group1" - And Using server "LOCAL" + Given Using server "LOCAL" And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes" And user "gs-user0" exists When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE" - And Using server "REMOTE" + Given Using server "REMOTE" And As an "gs-user1" When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" Then the OCS status code should be "100" @@ -159,7 +164,7 @@ Feature: federated Scenario: accept a pending remote share Given Using server "REMOTE" And user "user1" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE" When User "user1" from server "REMOTE" accepts last pending share @@ -175,7 +180,7 @@ Feature: federated And As an "admin" And Add user "gs-user1" to the group "group1" And Add user "gs-user2" to the group "group1" - And Using server "LOCAL" + Given Using server "LOCAL" And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes" And user "gs-user0" exists When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE" @@ -187,45 +192,45 @@ Feature: federated Given Using server "REMOTE" And user "user1" exists And user "user2" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE" And User "user1" from server "REMOTE" accepts last pending share - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" When creating a share with | path | /textfile0 (2).txt | | shareType | 0 | | shareWith | user2 | | permissions | 19 | - #Then the OCS status code should be "100" - #And the HTTP status code should be "200" - #And Share fields of last share match with - # | id | A_NUMBER | - # | item_type | file | - # | item_source | A_NUMBER | - # | share_type | 0 | - # | file_source | A_NUMBER | - # | path | /textfile0 (2).txt | - # | permissions | 19 | - # | stime | A_NUMBER | - # | storage | A_NUMBER | - # | mail_send | 1 | - # | uid_owner | user1 | - # | file_parent | A_NUMBER | - # | displayname_owner | user1 | - # | share_with | user2 | - # | share_with_displayname | user2 | + # Then the OCS status code should be "100" + # And the HTTP status code should be "200" + # And Share fields of last share match with + # | id | A_NUMBER | + # | item_type | file | + # | item_source | A_NUMBER | + # | share_type | 0 | + # | file_source | A_NUMBER | + # | path | /textfile0 (2).txt | + # | permissions | 19 | + # | stime | A_NUMBER | + # | storage | A_NUMBER | + # | mail_send | 1 | + # | uid_owner | user1 | + # | file_parent | A_NUMBER | + # | displayname_owner | user1 | + # | share_with | user2 | + # | share_with_displayname | user2 | Scenario: Overwrite a federated shared file as recipient Given Using server "REMOTE" And user "user1" exists And user "user2" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE" And User "user1" from server "REMOTE" accepts last pending share - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA" When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/textfile0 (2).txt" @@ -236,16 +241,16 @@ Feature: federated Given Using server "REMOTE" And user "user1" exists And user "user2" exists - And Using server "LOCAL" + Given Using server "LOCAL" And user "user0" exists And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE" And User "user1" from server "REMOTE" accepts last pending share - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA" - #When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt" - #And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8" - #Then Downloaded content should be "BLABLABLA" + When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt" + And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8" + Then Downloaded content should be "BLABLABLA" Scenario: List federated share from another server not accepted yet Given Using server "LOCAL" @@ -256,7 +261,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" When As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" Then the list of returned shares has 0 shares @@ -270,7 +275,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share When As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" @@ -296,7 +301,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And remote server is stopped When As an "user0" @@ -318,7 +323,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share # Checking that the file exists caches the file entry, which causes an # exception to be thrown when getting the file info if the remote server is @@ -335,8 +340,6 @@ Feature: federated | user | user0 | | mountpoint | /remote-share.txt | - - Scenario: Delete federated share with another server Given Using server "LOCAL" And user "user0" exists @@ -349,13 +352,13 @@ Feature: federated And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 1 shares - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And as "user0" the file "/remote-share.txt" exists And As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" And the list of returned shares has 1 shares - And Using server "REMOTE" + Given Using server "REMOTE" When As an "user1" And Deleting last share Then the OCS status code should be "100" @@ -363,7 +366,7 @@ Feature: federated And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 0 shares - And Using server "LOCAL" + Given Using server "LOCAL" And as "user0" the file "/remote-share.txt" does not exist And As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" @@ -381,7 +384,7 @@ Feature: federated And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 1 shares - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And as "user0" the file "/remote-share.txt" exists And As an "user0" @@ -394,7 +397,7 @@ Feature: federated And As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" And the list of returned shares has 0 shares - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 0 shares @@ -408,7 +411,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And as "user0" the file "/remote-share.txt" exists And As an "user0" @@ -435,7 +438,7 @@ Feature: federated And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 1 shares - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And as "user0" the file "/remote-share.txt" exists And As an "user0" @@ -447,7 +450,7 @@ Feature: federated And As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" And the list of returned shares has 0 shares - And Using server "REMOTE" + Given Using server "REMOTE" And As an "user1" And sending "GET" to "/apps/files_sharing/api/v1/shares" And the list of returned shares has 0 shares @@ -461,7 +464,7 @@ Feature: federated # server may have its own /textfile0.txt" file) And User "user1" copies file "/textfile0.txt" to "/remote-share.txt" And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL" - And Using server "LOCAL" + Given Using server "LOCAL" And User "user0" from server "LOCAL" accepts last pending share And as "user0" the file "/remote-share.txt" exists And As an "user0" @@ -474,3 +477,115 @@ Feature: federated And As an "user0" And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" And the list of returned shares has 0 shares + + Scenario: Share to a non-trusted server will NOT auto accept + Given Using server "LOCAL" + And user "user0" exists + Given Using server "REMOTE" + And user "userfed2" exists + And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes" + When As an "user0" + When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "userfed2" from server "REMOTE" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false" + And the list of returned shares has 1 shares + Given Using server "REMOTE" + And using new dav path + And As an "userfed2" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 0 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 1 shares + And as "userfed2" the file "/textfile0 (2).txt" does not exist + + Scenario: Share to a non-trusted server group will NOT auto accept + Given Using server "REMOTE" + And parameter "incoming_server2server_group_share_enabled" of app "files_sharing" is set to "yes" + And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes" + And user "gs-userfed3" exists + And user "gs-userfed4" exists + And group "groupfed2" exists + And As an "admin" + And Add user "gs-userfed3" to the group "groupfed2" + And Add user "gs-userfed4" to the group "groupfed2" + Given Using server "LOCAL" + And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes" + And user "gs-user0" exists + When As an "gs-user0" + When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "groupfed2" from server "REMOTE" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false" + And the list of returned shares has 1 shares + Given Using server "REMOTE" + And using new dav path + And As an "gs-userfed3" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 0 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 1 shares + And as "gs-userfed3" the file "/textfile0 (2).txt" does not exist + And As an "gs-userfed4" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 0 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 1 shares + And as "gs-userfed4" the file "/textfile0 (2).txt" does not exist + + @TrustedFederation + Scenario: Share to a trusted server auto accept + Given Using server "LOCAL" + And user "user0" exists + Given Using server "REMOTE" + And user "userfed1" exists + And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes" + When As an "user0" + When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "userfed1" from server "REMOTE" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false" + And the list of returned shares has 1 shares + Given Using server "REMOTE" + And using new dav path + And As an "userfed1" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 1 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 0 shares + And as "userfed1" the file "/textfile0 (2).txt" exists + + @TrustedFederation + Scenario: Share to a trusted server group auto accept + Given Using server "REMOTE" + And parameter "incoming_server2server_group_share_enabled" of app "files_sharing" is set to "yes" + And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes" + And user "gs-userfed1" exists + And user "gs-userfed2" exists + And group "groupfed1" exists + And As an "admin" + And Add user "gs-userfed1" to the group "groupfed1" + And Add user "gs-userfed2" to the group "groupfed1" + Given Using server "LOCAL" + And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes" + And user "gs-user0" exists + When As an "gs-user0" + When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "groupfed1" from server "REMOTE" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false" + And the list of returned shares has 1 shares + Given Using server "REMOTE" + And using new dav path + And As an "gs-userfed1" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 1 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 0 shares + And as "gs-userfed1" the file "/textfile0 (2).txt" exists + And As an "gs-userfed2" + And sending "GET" to "/apps/files_sharing/api/v1/remote_shares" + And the list of returned shares has 1 shares + When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending" + And the list of returned shares has 0 shares + And as "gs-userfed2" the file "/textfile0 (2).txt" exists diff --git a/build/integration/run.sh b/build/integration/run.sh index 309f8ed0c7566..8efb7593dfe94 100755 --- a/build/integration/run.sh +++ b/build/integration/run.sh @@ -22,6 +22,8 @@ if [ "$INSTALLED" == "true" ]; then $OCC config:system:set auth.bruteforce.protection.enabled --value false --type bool # Allow local remote urls otherwise we can not share $OCC config:system:set allow_local_remote_servers --value true --type bool + # Allow self signed certificates + $OCC config:system:set sharing.federation.allowSelfSignedCertificates --value true --type bool else if [ "$SCENARIO_TO_RUN" != "setup_features/setup.feature" ]; then echo "Nextcloud instance needs to be installed" >&2 @@ -38,6 +40,7 @@ if [ -z "$EXECUTOR_NUMBER" ]; then fi PORT=$((8080 + $EXECUTOR_NUMBER)) echo $PORT +export PORT echo "" > "${NC_DATADIR}/nextcloud.log" echo "" > phpserver.log