diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2022-12-20 08:58:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-20 08:58:33 +0100 |
commit | 0af4e9d4fe80ad3cffc6f3ff6a3d19d5f808cba9 (patch) | |
tree | b91084689580200f48e77f50d0d2b7efae0c893f | |
parent | fcf5789916e914613addd7d7fe32cf50bfd614ae (diff) | |
parent | 7dcd6eb561f4bba7ed36ce1178c725278dd9b80e (diff) | |
download | nextcloud-server-0af4e9d4fe80ad3cffc6f3ff6a3d19d5f808cba9.tar.gz nextcloud-server-0af4e9d4fe80ad3cffc6f3ff6a3d19d5f808cba9.zip |
Merge pull request #34172 from audriga/add-scim-json-support
Add support for application/scim+json
-rw-r--r-- | lib/private/AppFramework/Http/Request.php | 5 | ||||
-rw-r--r-- | lib/public/IRequest.php | 5 | ||||
-rw-r--r-- | tests/lib/AppFramework/Http/RequestTest.php | 183 |
3 files changed, 191 insertions, 2 deletions
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php index 32cce8a88e1..d8aac063f3e 100644 --- a/lib/private/AppFramework/Http/Request.php +++ b/lib/private/AppFramework/Http/Request.php @@ -26,6 +26,7 @@ declare(strict_types=1); * @author Thomas Tanghus <thomas@tanghus.net> * @author Vincent Petry <vincent@nextcloud.com> * @author Simon Leiner <simon@leiner.me> + * @author Stanimir Bozhilov <stanimir@audriga.com> * * @license AGPL-3.0 * @@ -419,8 +420,8 @@ class Request implements \ArrayAccess, \Countable, IRequest { } $params = []; - // 'application/json' must be decoded manually. - if (strpos($this->getHeader('Content-Type'), 'application/json') !== false) { + // 'application/json' and other JSON-related content types must be decoded manually. + if (preg_match(self::JSON_CONTENT_TYPE_REGEX, $this->getHeader('Content-Type')) === 1) { $params = json_decode(file_get_contents($this->inputStream), true); if (\is_array($params) && \count($params) > 0) { $this->items['params'] = $params; diff --git a/lib/public/IRequest.php b/lib/public/IRequest.php index 7696c3fa8c3..bb290233306 100644 --- a/lib/public/IRequest.php +++ b/lib/public/IRequest.php @@ -98,6 +98,11 @@ interface IRequest { public const USER_AGENT_THUNDERBIRD_ADDON = '/^Mozilla\/5\.0 \([A-Za-z ]+\) Nextcloud\-Thunderbird v.*$/'; /** + * @since 26.0.0 + */ + public const JSON_CONTENT_TYPE_REGEX = '/^application\/(?:[a-z0-9.-]+\+)?json\b/'; + + /** * @param string $name * * @psalm-taint-source input diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php index 78f4f80f8be..78e656f5fc3 100644 --- a/tests/lib/AppFramework/Http/RequestTest.php +++ b/tests/lib/AppFramework/Http/RequestTest.php @@ -2,6 +2,7 @@ /** * @copyright 2013 Thomas Tanghus (thomas@tanghus.net) * @copyright 2016 Lukas Reschke lukas@owncloud.com + * @copyright 2022 Stanimir Bozhilov (stanimir@audriga.com) * * This file is licensed under the Affero General Public License version 3 or * later. @@ -207,6 +208,54 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $request['nickname']); } + public function testScimJsonPost() { + global $data; + $data = '{"userName":"testusername", "displayName":"Example User"}'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('POST', $request->method); + $result = $request->post; + $this->assertSame('testusername', $result['userName']); + $this->assertSame('Example User', $result['displayName']); + $this->assertSame('Example User', $request->params['displayName']); + $this->assertSame('Example User', $request['displayName']); + } + + public function testCustomJsonPost() { + global $data; + $data = '{"propertyA":"sometestvalue", "propertyB":"someothertestvalue"}'; + + // Note: the content type used here is fictional and intended to check if the regex for JSON content types works fine + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('POST', $request->method); + $result = $request->post; + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame('someothertestvalue', $result['propertyB']); + } + public function notJsonDataProvider() { return [ ['this is not valid json'], @@ -239,6 +288,48 @@ class RequestTest extends \Test\TestCase { // ensure there's no error attempting to decode the content } + public function testNotScimJsonPost() { + global $data; + $data = 'this is not valid scim json'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertEquals('POST', $request->method); + $result = $request->post; + // ensure there's no error attempting to decode the content + } + + public function testNotCustomJsonPost() { + global $data; + $data = 'this is not valid json'; + $vars = [ + 'method' => 'POST', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'] + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertEquals('POST', $request->method); + $result = $request->post; + // ensure there's no error attempting to decode the content + } + public function testPatch() { global $data; $data = http_build_query(['name' => 'John Q. Public', 'nickname' => 'Joey'], '', '&'); @@ -309,6 +400,98 @@ class RequestTest extends \Test\TestCase { $this->assertSame(null, $result['nickname']); } + public function testScimJsonPatchAndPut() { + global $data; + + // PUT content + $data = '{"userName": "sometestusername", "displayName": "Example User"}'; + $vars = [ + 'method' => 'PUT', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'], + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('PUT', $request->method); + $result = $request->put; + + $this->assertSame('sometestusername', $result['userName']); + $this->assertSame('Example User', $result['displayName']); + + // PATCH content + $data = '{"userName": "sometestusername", "displayName": null}'; + $vars = [ + 'method' => 'PATCH', + 'server' => ['CONTENT_TYPE' => 'application/scim+json; utf-8'], + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('PATCH', $request->method); + $result = $request->patch; + + $this->assertSame('sometestusername', $result['userName']); + $this->assertSame(null, $result['displayName']); + } + + public function testCustomJsonPatchAndPut() { + global $data; + + // PUT content + $data = '{"propertyA": "sometestvalue", "propertyB": "someothertestvalue"}'; + $vars = [ + 'method' => 'PUT', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'], + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('PUT', $request->method); + $result = $request->put; + + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame('someothertestvalue', $result['propertyB']); + + // PATCH content + $data = '{"propertyA": "sometestvalue", "propertyB": null}'; + $vars = [ + 'method' => 'PATCH', + 'server' => ['CONTENT_TYPE' => 'application/custom-type+json; utf-8'], + ]; + + $request = new Request( + $vars, + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('PATCH', $request->method); + $result = $request->patch; + + $this->assertSame('sometestvalue', $result['propertyA']); + $this->assertSame(null, $result['propertyB']); + } + public function testPutStream() { global $data; $data = file_get_contents(__DIR__ . '/../../../data/testimage.png'); |