From 0def2e3210b18cc465af6456bf5a1b5ce4abe93e Mon Sep 17 00:00:00 2001 From: Zdeno Kuzmany Date: Sun, 22 Aug 2021 01:02:58 +0200 Subject: [PATCH 1/3] 2-legged OAuth2 using the client_credentials --- lib/Auth/TwoLeggedOAuth2.php | 160 +++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 lib/Auth/TwoLeggedOAuth2.php diff --git a/lib/Auth/TwoLeggedOAuth2.php b/lib/Auth/TwoLeggedOAuth2.php new file mode 100644 index 00000000..42f934b1 --- /dev/null +++ b/lib/Auth/TwoLeggedOAuth2.php @@ -0,0 +1,160 @@ +newAuth() will accept an array of Auth settings +| $settings = array( +| 'AuthMethod' => '2LeggedOAuth2' // Must be one of 'OAuth' or 'BasicAuth' + 'clientKey' => '', // Client/Consumer key from Mautic + 'clientSecret' => '', // Client/Consumer secret key from Mautic +| 'baseUrl' => '', // NOTE: Required for Unit tests; *must* contain a valid url +| ); +| +| // Initiate the auth object +| $initAuth = new ApiAuth(); +| $auth = $initAuth->newAuth($settings, $settings['AuthMethod']); +| +|-------------------------------------------------------------------------- +| Basic API Usage +|-------------------------------------------------------------------------- +| +| To use, just pass the auth object to the Api context you are creating. +| +| use Mautic\MauticApi; +| +| // Get a Contact context +| $api = new MauticApi(); +| $contactApi = $api->newApi('contacts', $auth, $settings['apiUrl']); +| +| // Get Contact list +| $results = $contactApi->getList(); +| +| Note: If the credentials are incorrect an error response will be returned: +| array('errors' => [[ +| 'code' => 403, +| 'message' => 'access_denied: OAuth2 authentication required' ) +| ]] +| +*/ + +namespace Mautic\Auth; + +use Mautic\Exception\RequiredParameterMissingException; + +class TwoLeggedOAuth2 extends AbstractAuth +{ + /** + * Password associated with Username. + * + * @var string + */ + private $clientSecret; + + /** + * Username or email, basically the Login Identifier. + * + * @var string + */ + private $clientKey; + + /** + * Access token returned by OAuth server. + * + * @var string + */ + protected $_access_token; + + /** + * @var string + */ + private $baseurl; + + /** + * @var string + */ + private $_access_token_url; + + /** + * {@inheritdoc} + */ + public function isAuthorized() + { + return !empty($this->clientKey) && !empty($this->clientSecret); + } + + /** + * @param string $baseUrl + * @param string $clientKey The username to use for Authentication *Required* + * @param string $clientSecret The Password to use *Required* + * + * @throws RequiredParameterMissingException + */ + public function setup($baseUrl, $clientKey, $clientSecret) + { + // we MUST have the username and password. No Blanks allowed! + // + // remove blanks else Empty doesn't work + $clientKey = trim($clientKey); + $clientSecret = trim($clientSecret); + + if (empty($clientKey) || empty($clientSecret)) { + //Throw exception if the required parameters were not found + $this->log('parameters did not include clientkey and/or clientSecret'); + throw new RequiredParameterMissingException( + 'One or more required parameters was not supplied. Both clientKey and clientSecret required!' + ); + } + + $this->baseurl = $baseUrl; + $this->clientKey = $clientKey; + $this->clientSecret = $clientSecret; + + if (!$this->_access_token_url) { + $this->_access_token_url = $baseUrl.'/oauth/v2/token'; + } + } + + /** + * @param $url + * @param $method + * + * @return array + */ + protected function prepareRequest($url, array $headers, array $parameters, $method, array $settings) + { + //Set Basic Auth parameters/headers + // $headers = array_merge($headers, ['Authorization: Bearer '.$this->_access_token]); + + return [$headers, $parameters]; + } + + /** + * @return string + */ + public function getAccessToken(): string + { + + $parameters = [ + 'client_id' => $this->clientKey, + 'client_secret' => $this->clientSecret, + 'grant_type' => 'client_credentials', + ]; + $params = $this->makeRequest($this->_access_token_url, $parameters, 'POST'); + print_r($params); + die(); + } +} From 6e03aecfa15a29699b491c62bf2e417ef03570e4 Mon Sep 17 00:00:00 2001 From: Zdeno Kuzmany Date: Sun, 22 Aug 2021 01:56:23 +0200 Subject: [PATCH 2/3] Finish Client Credentials grant type, add to readme and remove oauth1 from readme --- README.md | 41 +++++++++++++++++++--- lib/Auth/TwoLeggedOAuth2.php | 67 ++++++++---------------------------- 2 files changed, 50 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 9ee64d0f..198cbd9b 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,7 @@ then copy the Client ID and Client Secret to the application that will be using ## Authorization ### Obtaining an access token -The first step is to obtain authorization. Mautic supports OAuth 1.0a and OAuth 2 however it is up to the administrator -to decide which is enabled. Thus it is best to have a configuration option within your project for the administrator +The first step is to obtain authorization. Mautic supports OAuth 2. Thus it is best to have a configuration option within your project for the administrator to choose what method should be used by your code. ```php @@ -46,7 +45,6 @@ $callback = ''; // ApiAuth->newAuth() will accept an array of Auth settings $settings = [ 'baseUrl' => '', // Base URL of the Mautic instance - 'version' => 'OAuth2', // Version of the OAuth can be OAuth2 or OAuth1a. OAuth2 is the default value. 'clientKey' => '', // Client/Consumer key from Mautic 'clientSecret' => '', // Client/Consumer secret key from Mautic 'callback' => '', // Redirect URI/Callback URI for this script @@ -55,7 +53,6 @@ $settings = [ /* // If you already have the access token, et al, pass them in as well to prevent the need for reauthorization $settings['accessToken'] = $accessToken; -$settings['accessTokenSecret'] = $accessTokenSecret; //for OAuth1.0a $settings['accessTokenExpires'] = $accessTokenExpires; //UNIX timestamp $settings['refreshToken'] = $refreshToken; */ @@ -76,7 +73,6 @@ try { // refresh token // $accessTokenData will have the following keys: - // For OAuth1.0a: access_token, access_token_secret, expires // For OAuth2: access_token, expires, token_type, refresh_token if ($auth->accessTokenUpdated()) { @@ -90,6 +86,41 @@ try { } ``` + +### Using 2-legged OAuth2 using Client Credentials + +The Client Credentials grant is used when applications request an access token to access their own resources, not on behalf of a user. + +```php + 'TwoLeggedOAuth2', + 'clientKey' => '', + 'clientSecret' => '', + 'baseUrl' => '', +]; + +// $settings['accessToken'] = 'your stored access token'; + + +$initAuth = new ApiAuth(); +$auth = $initAuth->newAuth($settings, $settings['AuthMethod']); + +if (!isset($settings['accessToken'])) { + // store it for one hour and use it in $settings above + $accessToken = $auth->getAccessToken(); +} + +// Nothing else to do ... It's ready to use. +// Just pass the auth object to the API context you are creating. +``` + ### Using Basic Authentication Instead Instead of messing around with OAuth, you may simply elect to use BasicAuth instead. diff --git a/lib/Auth/TwoLeggedOAuth2.php b/lib/Auth/TwoLeggedOAuth2.php index 42f934b1..ea1cc374 100644 --- a/lib/Auth/TwoLeggedOAuth2.php +++ b/lib/Auth/TwoLeggedOAuth2.php @@ -9,48 +9,6 @@ * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html */ -/* -|-------------------------------------------------------------------------- -| 2-legged OAuth2 using the grant_type client_credentials -|-------------------------------------------------------------------------- -| -| use Mautic\Auth\ApiAuth; -| -| // ApiAuth->newAuth() will accept an array of Auth settings -| $settings = array( -| 'AuthMethod' => '2LeggedOAuth2' // Must be one of 'OAuth' or 'BasicAuth' - 'clientKey' => '', // Client/Consumer key from Mautic - 'clientSecret' => '', // Client/Consumer secret key from Mautic -| 'baseUrl' => '', // NOTE: Required for Unit tests; *must* contain a valid url -| ); -| -| // Initiate the auth object -| $initAuth = new ApiAuth(); -| $auth = $initAuth->newAuth($settings, $settings['AuthMethod']); -| -|-------------------------------------------------------------------------- -| Basic API Usage -|-------------------------------------------------------------------------- -| -| To use, just pass the auth object to the Api context you are creating. -| -| use Mautic\MauticApi; -| -| // Get a Contact context -| $api = new MauticApi(); -| $contactApi = $api->newApi('contacts', $auth, $settings['apiUrl']); -| -| // Get Contact list -| $results = $contactApi->getList(); -| -| Note: If the credentials are incorrect an error response will be returned: -| array('errors' => [[ -| 'code' => 403, -| 'message' => 'access_denied: OAuth2 authentication required' ) -| ]] -| -*/ - namespace Mautic\Auth; use Mautic\Exception\RequiredParameterMissingException; @@ -103,7 +61,7 @@ public function isAuthorized() * * @throws RequiredParameterMissingException */ - public function setup($baseUrl, $clientKey, $clientSecret) + public function setup($baseUrl, $clientKey, $clientSecret, $accessToken = null) { // we MUST have the username and password. No Blanks allowed! // @@ -119,9 +77,10 @@ public function setup($baseUrl, $clientKey, $clientSecret) ); } - $this->baseurl = $baseUrl; - $this->clientKey = $clientKey; - $this->clientSecret = $clientSecret; + $this->baseurl = $baseUrl; + $this->clientKey = $clientKey; + $this->clientSecret = $clientSecret; + $this->_access_token = $accessToken; if (!$this->_access_token_url) { $this->_access_token_url = $baseUrl.'/oauth/v2/token'; @@ -136,8 +95,9 @@ public function setup($baseUrl, $clientKey, $clientSecret) */ protected function prepareRequest($url, array $headers, array $parameters, $method, array $settings) { - //Set Basic Auth parameters/headers - // $headers = array_merge($headers, ['Authorization: Bearer '.$this->_access_token]); + if ($this->_access_token !== null) { + $headers = array_merge($headers, ['Authorization: Bearer '.$this->_access_token]); + } return [$headers, $parameters]; } @@ -147,14 +107,15 @@ protected function prepareRequest($url, array $headers, array $parameters, $meth */ public function getAccessToken(): string { - - $parameters = [ + $parameters = [ 'client_id' => $this->clientKey, 'client_secret' => $this->clientSecret, 'grant_type' => 'client_credentials', ]; - $params = $this->makeRequest($this->_access_token_url, $parameters, 'POST'); - print_r($params); - die(); + $accessTokenData = $this->makeRequest($this->_access_token_url, $parameters, 'POST'); + //store access token data however you want + $this->_access_token = $accessTokenData['access_token'] ?? null; + + return $this->_access_token; } } From 29ac7fac7434a68be74acbbe67d517cd4ce7edb5 Mon Sep 17 00:00:00 2001 From: Zdeno Kuzmany Date: Sun, 22 Aug 2021 05:33:36 +0200 Subject: [PATCH 3/3] CS fixer --- lib/Auth/TwoLeggedOAuth2.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/Auth/TwoLeggedOAuth2.php b/lib/Auth/TwoLeggedOAuth2.php index ea1cc374..ad7c0533 100644 --- a/lib/Auth/TwoLeggedOAuth2.php +++ b/lib/Auth/TwoLeggedOAuth2.php @@ -72,9 +72,7 @@ public function setup($baseUrl, $clientKey, $clientSecret, $accessToken = null) if (empty($clientKey) || empty($clientSecret)) { //Throw exception if the required parameters were not found $this->log('parameters did not include clientkey and/or clientSecret'); - throw new RequiredParameterMissingException( - 'One or more required parameters was not supplied. Both clientKey and clientSecret required!' - ); + throw new RequiredParameterMissingException('One or more required parameters was not supplied. Both clientKey and clientSecret required!'); } $this->baseurl = $baseUrl; @@ -95,16 +93,13 @@ public function setup($baseUrl, $clientKey, $clientSecret, $accessToken = null) */ protected function prepareRequest($url, array $headers, array $parameters, $method, array $settings) { - if ($this->_access_token !== null) { + if (null !== $this->_access_token) { $headers = array_merge($headers, ['Authorization: Bearer '.$this->_access_token]); } return [$headers, $parameters]; } - /** - * @return string - */ public function getAccessToken(): string { $parameters = [