From 9cde63e81a9926a1c54786b0d28dc55fffd8a1b6 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 29 Oct 2020 17:58:01 -0700 Subject: [PATCH] dev/core#2141 - Add support for token-tagging to all grant flows Suppose you have a downstream app/module -- such as the Civi-IMAP app/module. It needs to store a notation which says "this thing in our data" (e.g. `civicrm_mail_settings`) "corresponds to that token in the OAuth data". It can put a tag on the token (`tag=civicrm_mail_settings:123`) and use that for lookup ``` $tag = `OAuthSysToken.refresh +w tag=civicrm_mail_settings:123` ``` The advantage of this is that it's simple, flexible, and doesn't require new schema. Of course, it's not end-all/be-all. It's OK for 1:1 relationship. But if you want 1:M or M:M, then you'll have to model that as something else. But for basic usage, tags are simple and moderately flexible. --- ext/oauth-client/CRM/OAuth/BAO/OAuthSysToken.php | 2 +- ext/oauth-client/CRM/OAuth/Page/Return.php | 1 + .../Api4/Action/OAuthClient/AbstractGrantAction.php | 10 ++++++++++ .../Civi/Api4/Action/OAuthClient/AuthorizationCode.php | 1 + .../Civi/Api4/Action/OAuthClient/ClientCredential.php | 1 + .../Civi/Api4/Action/OAuthClient/UserPassword.php | 1 + ext/oauth-client/Civi/OAuth/OAuthTokenFacade.php | 4 +++- 7 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ext/oauth-client/CRM/OAuth/BAO/OAuthSysToken.php b/ext/oauth-client/CRM/OAuth/BAO/OAuthSysToken.php index 14402d18dc..21201f31f6 100644 --- a/ext/oauth-client/CRM/OAuth/BAO/OAuthSysToken.php +++ b/ext/oauth-client/CRM/OAuth/BAO/OAuthSysToken.php @@ -16,7 +16,7 @@ */ class CRM_OAuth_BAO_OAuthSysToken extends CRM_OAuth_DAO_OAuthSysToken { - private static $returnFields = ['id', 'client_id', 'expires']; + private static $returnFields = ['id', 'client_id', 'expires', 'tag']; /** * Create a new OAuthSysToken based on array-data diff --git a/ext/oauth-client/CRM/OAuth/Page/Return.php b/ext/oauth-client/CRM/OAuth/Page/Return.php index bf31de1482..a468bbdfaf 100644 --- a/ext/oauth-client/CRM/OAuth/Page/Return.php +++ b/ext/oauth-client/CRM/OAuth/Page/Return.php @@ -16,6 +16,7 @@ class CRM_OAuth_Page_Return extends CRM_Core_Page { $tokenRecord = Civi::service('oauth2.token')->init([ 'client' => $client, 'scope' => $state['scopes'], + 'tag' => $state['tag'], 'storage' => $state['storage'], 'grant_type' => 'authorization_code', 'cred' => ['code' => $authCode], diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php index 0de3c9e728..31352dc191 100644 --- a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php +++ b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php @@ -10,6 +10,8 @@ use Civi\OAuth\OAuthException; * * @method $this setStorage(string $storage) * @method string getStorage() + * @method $this setTag(string $tag) + * @method string getTag() */ abstract class AbstractGrantAction extends \Civi\Api4\Generic\AbstractBatchAction { @@ -29,6 +31,14 @@ abstract class AbstractGrantAction extends \Civi\Api4\Generic\AbstractBatchActio */ protected $storage = 'OAuthSysToken'; + /** + * Optionally tag the new token with a symbolic/freeform label. This tag can be + * used by automated mechanism to lookup/select a token. + * + * @var string|null + */ + protected $tag = NULL; + /** * The active client definition. * diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AuthorizationCode.php b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AuthorizationCode.php index 1f8c5171c0..3868973be0 100644 --- a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AuthorizationCode.php +++ b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AuthorizationCode.php @@ -61,6 +61,7 @@ class AuthorizationCode extends AbstractGrantAction { 'landingUrl' => $this->getLandingUrl(), 'storage' => $this->getStorage(), 'scopes' => $scopes, + 'tag' => $this->getTag(), ]); $result[] = [ 'url' => $provider->getAuthorizationUrl([ diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthClient/ClientCredential.php b/ext/oauth-client/Civi/Api4/Action/OAuthClient/ClientCredential.php index 3959103f9d..1369e686a5 100644 --- a/ext/oauth-client/Civi/Api4/Action/OAuthClient/ClientCredential.php +++ b/ext/oauth-client/Civi/Api4/Action/OAuthClient/ClientCredential.php @@ -31,6 +31,7 @@ class ClientCredential extends AbstractGrantAction { 'client' => $this->getClientDef(), 'scope' => $this->getScopes(), 'storage' => $this->getStorage(), + 'tag' => $this->getTag(), 'grant_type' => 'client_credentials', ]); diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthClient/UserPassword.php b/ext/oauth-client/Civi/Api4/Action/OAuthClient/UserPassword.php index 4f0bfdd253..d961a2e2ff 100644 --- a/ext/oauth-client/Civi/Api4/Action/OAuthClient/UserPassword.php +++ b/ext/oauth-client/Civi/Api4/Action/OAuthClient/UserPassword.php @@ -48,6 +48,7 @@ class UserPassword extends AbstractGrantAction { 'client' => $this->getClientDef(), 'scope' => $this->getScopes(), 'storage' => $this->getStorage(), + 'tag' => $this->getTag(), 'grant_type' => 'password', 'cred' => [ 'username' => $this->getUsername(), diff --git a/ext/oauth-client/Civi/OAuth/OAuthTokenFacade.php b/ext/oauth-client/Civi/OAuth/OAuthTokenFacade.php index 7956a87661..dcad4770bf 100644 --- a/ext/oauth-client/Civi/OAuth/OAuthTokenFacade.php +++ b/ext/oauth-client/Civi/OAuth/OAuthTokenFacade.php @@ -16,6 +16,7 @@ class OAuthTokenFacade { * - client: array, the OAuthClient record * - scope: array|string|null, list of scopes to request. if omitted, inherit default from client/provider * - storage: string, default: "OAuthSysToken" + * - tag: string|null, a symbolic/freeform identifier for looking-up tokens * - grant_type: string, ex "authorization_code", "client_credentials", "password" * - cred: array, extra credentialing options to pass to the "token" URL (via getAccessToken($tokenOptions)), * eg "username", "password", "code" @@ -52,6 +53,7 @@ class OAuthTokenFacade { $tokenRecord = [ 'client_id' => $options['client']['id'], 'grant_type' => $options['grant_type'], + 'tag' => $options['tag'] ?? NULL, 'scopes' => $this->splitScopes($scopeSeparator, $values['scope'] ?? $options['scope'] ?? NULL), 'token_type' => $values['token_type'] ?? NULL, 'access_token' => $accessToken->getToken(), @@ -124,7 +126,7 @@ class OAuthTokenFacade { protected function findName(ResourceOwnerInterface $owner) { $values = $owner->toArray(); - $fields = ['upn', 'userPrincipalName', 'mail', 'id']; + $fields = ['upn', 'userPrincipalName', 'mail', 'email', 'id']; foreach ($fields as $field) { if (isset($values[$field])) { return $values[$field]; -- 2.25.1