Skip to content
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

test ocs endpoints with CORS headers #34665

Merged
merged 3 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions tests/TestHelpers/OcsApiHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,19 @@ class OcsApiHelper {
* @param string $path
* @param array $body array of key, value pairs e.g ['value' => 'yes']
* @param int $ocsApiVersion (1|2) default 2
* @param array $headers
*
* @return ResponseInterface
*/
public static function sendRequest(
$baseUrl, $user, $password, $method, $path, $body = [], $ocsApiVersion = 2
$baseUrl, $user, $password, $method, $path, $body = [], $ocsApiVersion = 2, $headers = []
) {
$fullUrl = $baseUrl;
if (\substr($fullUrl, -1) !== '/') {
$fullUrl .= '/';
}
$fullUrl .= "ocs/v{$ocsApiVersion}.php" . $path;

return HttpRequestHelper::sendRequest($fullUrl, $method, $user, $password, [], $body);
return HttpRequestHelper::sendRequest($fullUrl, $method, $user, $password, $headers, $body);
}
}
1 change: 1 addition & 0 deletions tests/acceptance/config/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ default:
- '%paths.base%/../features/apiAuth'
contexts:
- FeatureContext: *common_feature_context_params
- CorsContext:

apiCapabilities:
paths:
Expand Down
123 changes: 123 additions & 0 deletions tests/acceptance/features/apiAuth/cors.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
@api @TestAlsoOnExternalUserBackend
Feature: CORS headers
Background:
Given user "user0" has been created with default attributes
And a new client token for "user0" has been generated

Scenario Outline: CORS headers should be returned when setting CORS domain sending Origin header
Given using OCS API version "<ocs_api_version>"
And user "user0" has added "https://aphno.badal" to the list of personal CORS domains
When user "user0" sends HTTP method "GET" to OCS API endpoint "<endpoint>" with headers
| header | value |
| Origin | https://aphno.badal |
Then the OCS status code should be "<ocs-code>"
And the HTTP status code should be "<http-code>"
Then the following headers should be set
| Access-Control-Allow-Headers | OC-Checksum,OC-Total-Length,OCS-APIREQUEST,X-OC-Mtime,Accept,Authorization,Brief,Content-Length,Content-Range,Content-Type,Date,Depth,Destination,Host,If,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Lock-Token,Overwrite,Prefer,Range,Schedule-Reply,Timeout,User-Agent,X-Expected-Entity-Length,Accept-Language,Access-Control-Request-Method,Access-Control-Allow-Origin,ETag,OC-Autorename,OC-CalDav-Import,OC-Chunked,OC-Etag,OC-FileId,OC-LazyOps,OC-Total-File-Length,Origin,X-Request-ID,X-Requested-With |
| Access-Control-Expose-Headers | Content-Location,DAV,ETag,Link,Lock-Token,OC-ETag,OC-Checksum,OC-FileId,OC-JobStatus-Location,Vary,Webdav-Location,X-Sabre-Status |
| Access-Control-Allow-Origin | https://aphno.badal |
| Access-Control-Allow-Methods | GET,OPTIONS,POST,PUT,DELETE,MKCOL,PROPFIND,PATCH,PROPPATCH,REPORT |
Examples:
| ocs_api_version |endpoint | ocs-code | http-code |
| 1 |/apps/files_external/api/v1/mounts | 100 | 200 |
| 2 |/apps/files_external/api/v1/mounts | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/remote_shares | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/remote_shares | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/remote_shares/pending | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/remote_shares/pending | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/shares | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/shares | 200 | 200 |
| 1 |/privatedata/getattribute | 100 | 200 |
| 2 |/privatedata/getattribute | 200 | 200 |

#merge into previous scenario when fixed
@issue-34664
Scenario Outline: CORS headers should be returned when setting CORS domain sending Origin header
Given using OCS API version "<ocs_api_version>"
And user "user0" has added "https://aphno.badal" to the list of personal CORS domains
When user "user0" sends HTTP method "GET" to OCS API endpoint "<endpoint>" with headers
| header | value |
| Origin | https://aphno.badal |
Then the OCS status code should be "<ocs-code>"
And the HTTP status code should be "<http-code>"
Then the following headers should not be set
| Access-Control-Allow-Headers |
| Access-Control-Expose-Headers |
| Access-Control-Allow-Origin |
| Access-Control-Allow-Methods |
Examples:
| ocs_api_version |endpoint | ocs-code | http-code |
| 1 |/config | 100 | 200 |
| 2 |/config | 200 | 200 |

Scenario Outline: CORS headers should be returned when setting CORS domain sending Origin header (admin only endpoints)
Given using OCS API version "<ocs_api_version>"
And the administrator has added "https://aphno.badal" to the list of personal CORS domains
When the administrator sends HTTP method "GET" to OCS API endpoint "<endpoint>" with headers
| header | value |
| Origin | https://aphno.badal |
Then the OCS status code should be "<ocs-code>"
And the HTTP status code should be "<http-code>"
Then the following headers should be set
| Access-Control-Allow-Headers | OC-Checksum,OC-Total-Length,OCS-APIREQUEST,X-OC-Mtime,Accept,Authorization,Brief,Content-Length,Content-Range,Content-Type,Date,Depth,Destination,Host,If,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Lock-Token,Overwrite,Prefer,Range,Schedule-Reply,Timeout,User-Agent,X-Expected-Entity-Length,Accept-Language,Access-Control-Request-Method,Access-Control-Allow-Origin,ETag,OC-Autorename,OC-CalDav-Import,OC-Chunked,OC-Etag,OC-FileId,OC-LazyOps,OC-Total-File-Length,Origin,X-Request-ID,X-Requested-With |
| Access-Control-Expose-Headers | Content-Location,DAV,ETag,Link,Lock-Token,OC-ETag,OC-Checksum,OC-FileId,OC-JobStatus-Location,Vary,Webdav-Location,X-Sabre-Status |
| Access-Control-Allow-Origin | https://aphno.badal |
| Access-Control-Allow-Methods | GET,OPTIONS,POST,PUT,DELETE,MKCOL,PROPFIND,PATCH,PROPPATCH,REPORT |
Examples:
| ocs_api_version |endpoint | ocs-code | http-code |
| 1 |/cloud/apps | 100 | 200 |
| 2 |/cloud/apps | 200 | 200 |
| 1 |/cloud/groups | 100 | 200 |
| 2 |/cloud/groups | 200 | 200 |
| 1 |/cloud/users | 100 | 200 |
| 2 |/cloud/users | 200 | 200 |

Scenario Outline: no CORS headers should be returned when CORS domain does not match Origin header
Given using OCS API version "<ocs_api_version>"
And user "user0" has added "https://mero.badal" to the list of personal CORS domains
When user "user0" sends HTTP method "GET" to OCS API endpoint "<endpoint>" with headers
| header | value |
| Origin | https://aphno.badal |
Then the OCS status code should be "<ocs-code>"
And the HTTP status code should be "<http-code>"
Then the following headers should not be set
| Access-Control-Allow-Headers |
| Access-Control-Expose-Headers |
| Access-Control-Allow-Origin |
| Access-Control-Allow-Methods |
Examples:
| ocs_api_version |endpoint | ocs-code | http-code |
| 1 |/apps/files_external/api/v1/mounts | 100 | 200 |
| 2 |/apps/files_external/api/v1/mounts | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/remote_shares | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/remote_shares | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/remote_shares/pending | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/remote_shares/pending | 200 | 200 |
| 1 |/apps/files_sharing/api/v1/shares | 100 | 200 |
| 2 |/apps/files_sharing/api/v1/shares | 200 | 200 |
| 1 |/config | 100 | 200 |
| 2 |/config | 200 | 200 |
| 1 |/privatedata/getattribute | 100 | 200 |
| 2 |/privatedata/getattribute | 200 | 200 |

Scenario Outline: no CORS headers should be returned when CORS domain does not match Origin header (admin only endpoints)
Given using OCS API version "<ocs_api_version>"
And the administrator has added "https://mero.badal" to the list of personal CORS domains
When the administrator sends HTTP method "GET" to OCS API endpoint "<endpoint>" with headers
| header | value |
| Origin | https://aphno.badal |
Then the OCS status code should be "<ocs-code>"
And the HTTP status code should be "<http-code>"
Then the following headers should not be set
| Access-Control-Allow-Headers |
| Access-Control-Expose-Headers |
| Access-Control-Allow-Origin |
| Access-Control-Allow-Methods |
Examples:
| ocs_api_version |endpoint | ocs-code | http-code |
| 1 |/cloud/apps | 100 | 200 |
| 2 |/cloud/apps | 200 | 200 |
| 1 |/cloud/groups | 100 | 200 |
| 2 |/cloud/groups | 200 | 200 |
| 1 |/cloud/users | 100 | 200 |
| 2 |/cloud/users | 200 | 200 |
44 changes: 44 additions & 0 deletions tests/acceptance/features/bootstrap/BasicStructure.php
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,50 @@ public function userSendsToOcsApiEndpoint($user, $verb, $url, $password = null)
);
}

/**
* @When /^user "([^"]*)" sends HTTP method "([^"]*)" to OCS API endpoint "([^"]*)" with headers$/
*
* @param string $user
* @param string $verb
* @param string $url
* @param TableNode $headersTable
*
* @return void
*/
public function userSendsToOcsApiEndpointWithHeaders(
$user, $verb, $url, TableNode $headersTable
) {
$user = $this->getActualUsername($user);
$password = $this->getPasswordForUser($user);

$headers = [];
foreach ($headersTable as $row) {
$headers[$row['header']] = $row ['value'];
}

$this->response = OcsApiHelper::sendRequest(
$this->getBaseUrl(), $user, $password, $verb,
$url, [], $this->ocsApiVersion, $headers
);
}

/**
* @When /^the administrator sends HTTP method "([^"]*)" to OCS API endpoint "([^"]*)" with headers$/
*
* @param string $verb
* @param string $url
* @param TableNode $headersTable
*
* @return void
*/
public function administratorSendsToOcsApiEndpointWithHeaders(
$verb, $url, TableNode $headersTable
) {
$this->userSendsToOcsApiEndpointWithHeaders(
$this->getAdminUsername(), $verb, $url, $headersTable
);
}

/**
* @When the administrator sends HTTP method :verb to OCS API endpoint :url
* @When the administrator sends HTTP method :verb to OCS API endpoint :url using password :password
Expand Down
165 changes: 165 additions & 0 deletions tests/acceptance/features/bootstrap/CorsContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php
/**
* ownCloud
*
* @author Artur Neumann <artur@jankaritech.com>
* @copyright Copyright (c) 2019, ownCloud GmbH
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License,
* as published by the Free Software Foundation;
* either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Behat\Hook\Scope\AfterScenarioScope;

require_once 'bootstrap.php';
/**
* Steps that relate to CORS tests
*/
class CorsContext implements Context {
/**
*
* @var FeatureContext
*/
private $featureContext;

private $originalAdminCorsDomains = null;

/**
* @Given user :user has added :domain to the list of personal CORS domains
*
* @param string $user
* @param string $domain
*
* @return void
*/
public function addDomainToPrivateCORSLists($user, $domain) {
$this->featureContext->runOcc(
[
'user:setting',
$user,
'core',
'domains'
]
);
if ($this->featureContext->getExitStatusCodeOfOccCommand() === 0) {
$domainsJson = $this->featureContext->getStdOutOfOccCommand();
$domains = \json_decode($domainsJson);
} else {
$domainsJson = "";
$domains = [];
}
if ($user === $this->featureContext->getAdminUsername()
&& $this->originalAdminCorsDomains === null
) {
$this->originalAdminCorsDomains = $domainsJson;
}
phil-davis marked this conversation as resolved.
Show resolved Hide resolved

$domains[] = $domain;
$valueString = \json_encode($domains);

$this->featureContext->runOcc(
[
'user:setting',
$user,
'core',
'domains',
'--value=\'' . $valueString . '\''
]
);
if ($this->featureContext->getExitStatusCodeOfOccCommand() !== 0) {
throw new \Exception(
"could not set CORS domain. " .
$this->featureContext->getStdErrOfOccCommand()
);
}
//double check if it was set
$this->featureContext->runOcc(
[
'user:setting',
$user,
'core',
'domains'
]
);
$domains = \json_decode($this->featureContext->getStdOutOfOccCommand());
PHPUnit_Framework_Assert::assertContains(
$domain, $domains, "CORS domain was not added correctly"
);
}

/**
* @Given the administrator has added :domain to the list of personal CORS domains
*
* @param string $domain
*
* @return void
*/
public function adminAddDomainToPrivateCORSLists($domain) {
$this->addDomainToPrivateCORSLists(
$this->featureContext->getAdminUsername(), $domain
);
}

/**
* This will run before EVERY scenario.
* It will set the properties for this object.
*
* @BeforeScenario
*
* @param BeforeScenarioScope $scope
*
* @return void
*/
public function before(BeforeScenarioScope $scope) {
// Get the environment
$environment = $scope->getEnvironment();
// Get all the contexts you need in this context
$this->featureContext = $environment->getContext('FeatureContext');
}

/**
* @AfterScenario
*
* @param AfterScenarioScope $scope
*
* @return void
*/
public function resetAdminCors(AfterScenarioScope $scope) {
if ($this->originalAdminCorsDomains !== null) {
if ($this->originalAdminCorsDomains !== "") {
$this->featureContext->runOcc(
[
'user:setting',
$this->featureContext->getAdminUsername(),
'core',
'domains',
'--value=\'' . $this->originalAdminCorsDomains . '\''
]
);
} else {
$this->featureContext->runOcc(
[
'user:setting',
$this->featureContext->getAdminUsername(),
'core',
'domains',
'--delete'
]
);
}
}
}
}