From 07842af43d95ec0046a915ecadcf6d6c4cf793e9 Mon Sep 17 00:00:00 2001 From: James Edmonston Date: Mon, 9 Nov 2020 13:06:52 +0000 Subject: [PATCH 1/3] Fixed issues with non-user tokens (i.e. tokens used for SSG) --- src/GraphqlAuthentication.php | 48 +++++++++++++++++++---------------- src/resolvers/Asset.php | 35 ++++++++++++++----------- src/resolvers/Entry.php | 35 ++++++++++++++----------- 3 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/GraphqlAuthentication.php b/src/GraphqlAuthentication.php index 4e663d7..5d9ef88 100644 --- a/src/GraphqlAuthentication.php +++ b/src/GraphqlAuthentication.php @@ -488,7 +488,7 @@ public function registerGqlMutations(Event $event) 'type' => Type::nonNull(Type::boolean()), 'args' => [], 'resolve' => function () use ($gql) { - $token = $this->_getHeaderToken(); + $token = $this->getHeaderToken(); if (!$token) { throw new Error(TOKEN_NOT_FOUND); @@ -659,25 +659,7 @@ public function ensureAssetMutationAllowed(ModelEvent $event) } } - public function getUserFromToken(): User - { - return Craft::$app->getUsers()->getUserById($this->_extractUserIdFromToken($this->_getHeaderToken())); - } - - public function isGraphiqlRequest(): bool - { - return StringHelper::contains(Craft::$app->getRequest()->getReferrer() ?? '', UrlHelper::cpUrl() . 'graphiql'); - } - - // Protected Methods - // ========================================================================= - - protected function _isSchemaSet(): bool - { - return (bool) isset($this->getSettings()->schemaId); - } - - protected function _getHeaderToken(): GqlToken + public function getHeaderToken(): GqlToken { if ($this->getSettings()->setCookie && isset($_COOKIE['gql_accessToken'])) { try { @@ -725,8 +707,30 @@ protected function _getHeaderToken(): GqlToken return $token; } + public function getUserFromToken(): User + { + return Craft::$app->getUsers()->getUserById($this->_extractUserIdFromToken($this->getHeaderToken())); + } + + public function isGraphiqlRequest(): bool + { + return StringHelper::contains(Craft::$app->getRequest()->getReferrer() ?? '', UrlHelper::cpUrl() . 'graphiql'); + } + + // Protected Methods + // ========================================================================= + + protected function _isSchemaSet(): bool + { + return (bool) isset($this->getSettings()->schemaId); + } + protected function _validateTokenExpiry(GqlToken $token) { + if (!$token->expiryDate) { + return; + } + if (strtotime(date('y-m-d H:i:s')) < strtotime($token->expiryDate->format('y-m-d H:i:s'))) { return; } @@ -810,7 +814,7 @@ protected function _ensureValidEntry(int $id) return; } - $scope = $this->_getHeaderToken()->getScope(); + $scope = $this->getHeaderToken()->getScope(); if (!in_array("sections.{$entry->section->uid}:read", $scope)) { throw new Error(FORBIDDEN_MUTATION); @@ -850,7 +854,7 @@ protected function _ensureValidAsset(int $id) return; } - $scope = $this->_getHeaderToken()->getScope(); + $scope = $this->getHeaderToken()->getScope(); if (!in_array("volumes.{$asset->volume->uid}:read", $scope)) { throw new Error(FORBIDDEN_MUTATION); diff --git a/src/resolvers/Asset.php b/src/resolvers/Asset.php index e6fe7aa..19b9b1e 100644 --- a/src/resolvers/Asset.php +++ b/src/resolvers/Asset.php @@ -11,6 +11,7 @@ use craft\gql\base\ElementResolver; use craft\helpers\Db; use craft\helpers\Gql as GqlHelper; +use craft\helpers\StringHelper; use jamesedmonston\graphqlauthentication\GraphqlAuthentication; /** @@ -40,26 +41,30 @@ public static function prepareQuery($source, array $arguments, $fieldName = null } if (!GraphqlAuthentication::$plugin->isGraphiqlRequest()) { - $arguments['uploader'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + $token = GraphqlAuthentication::$plugin->getHeaderToken(); - if (isset($arguments['volume']) || isset($arguments['volumeId'])) { - unset($arguments['uploader']); - $authorOnlyVolumes = GraphqlAuthentication::$plugin->getSettings()->assetQueries ?? []; + if (StringHelper::contains($token, 'user-')) { + $arguments['uploader'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; - foreach ($authorOnlyVolumes as $volume => $value) { - if (!(bool) $value) { - continue; - } + if (isset($arguments['volume']) || isset($arguments['volumeId'])) { + unset($arguments['uploader']); + $authorOnlyVolumes = GraphqlAuthentication::$plugin->getSettings()->assetQueries ?? []; - if (isset($arguments['volume']) && trim($arguments['volume'][0]) !== $volume) { - continue; - } + foreach ($authorOnlyVolumes as $volume => $value) { + if (!(bool) $value) { + continue; + } - if (isset($arguments['volumeId']) && trim((string) $arguments['volumeId'][0]) !== Craft::$app->getVolumes()->getVolumeByHandle($volume)->id) { - continue; - } + if (isset($arguments['volume']) && trim($arguments['volume'][0]) !== $volume) { + continue; + } - $arguments['uploader'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + if (isset($arguments['volumeId']) && trim((string) $arguments['volumeId'][0]) !== Craft::$app->getVolumes()->getVolumeByHandle($volume)->id) { + continue; + } + + $arguments['uploader'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + } } } } diff --git a/src/resolvers/Entry.php b/src/resolvers/Entry.php index 3e77403..f7a5359 100644 --- a/src/resolvers/Entry.php +++ b/src/resolvers/Entry.php @@ -11,6 +11,7 @@ use craft\gql\base\ElementResolver; use craft\helpers\Db; use craft\helpers\Gql as GqlHelper; +use craft\helpers\StringHelper; use jamesedmonston\graphqlauthentication\GraphqlAuthentication; /** @@ -40,26 +41,30 @@ public static function prepareQuery($source, array $arguments, $fieldName = null } if (!GraphqlAuthentication::$plugin->isGraphiqlRequest()) { - $arguments['authorId'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + $token = GraphqlAuthentication::$plugin->getHeaderToken(); - if (isset($arguments['section']) || isset($arguments['sectionId'])) { - unset($arguments['authorId']); - $authorOnlySections = GraphqlAuthentication::$plugin->getSettings()->entryQueries ?? []; + if (StringHelper::contains($token, 'user-')) { + $arguments['authorId'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; - foreach ($authorOnlySections as $section => $value) { - if (!(bool) $value) { - continue; - } + if (isset($arguments['section']) || isset($arguments['sectionId'])) { + unset($arguments['authorId']); + $authorOnlySections = GraphqlAuthentication::$plugin->getSettings()->entryQueries ?? []; - if (isset($arguments['section']) && trim($arguments['section'][0]) !== $section) { - continue; - } + foreach ($authorOnlySections as $section => $value) { + if (!(bool) $value) { + continue; + } - if (isset($arguments['sectionId']) && trim((string) $arguments['sectionId'][0]) !== Craft::$app->getSections()->getSectionByHandle($section)->id) { - continue; - } + if (isset($arguments['section']) && trim($arguments['section'][0]) !== $section) { + continue; + } - $arguments['authorId'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + if (isset($arguments['sectionId']) && trim((string) $arguments['sectionId'][0]) !== Craft::$app->getSections()->getSectionByHandle($section)->id) { + continue; + } + + $arguments['authorId'] = GraphqlAuthentication::$plugin->getUserFromToken()->id; + } } } } From 363e307615aed6027b51e28dd9581d93b166186e Mon Sep 17 00:00:00 2001 From: James Edmonston Date: Mon, 9 Nov 2020 13:07:09 +0000 Subject: [PATCH 2/3] Bump version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a716ed5..353cfc3 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "jamesedmonston/graphql-authentication", "description": "GraphQL authentication for your headless Craft CMS applications.", "type": "craft-plugin", - "version": "1.1.2", + "version": "1.1.3", "keywords": [ "craft", "cms", From 0b5c2e3236b653755209ba5d33802995167d35be Mon Sep 17 00:00:00 2001 From: James Edmonston Date: Mon, 9 Nov 2020 13:08:55 +0000 Subject: [PATCH 3/3] Updated changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e9cf9..129479d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## 1.1.1 - 2020-11-09 +## 1.1.3 - 2020-11-09 + +### Fixed + +- Fixed issues with non-user tokens throwing `Invalid Authorization Header`. Previously it was _always_ trying to validate queries against user permissions, but this was causing conflicts with tokens that will only be used server-side (i.e. in Next.js SSG requests) + +## 1.1.2 - 2020-11-09 ### Fixed