diff --git a/CHANGELOG.md b/CHANGELOG.md index bce86a1..8d043aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,6 +112,12 @@ - Fix an error with URL generation for authenticated requests. - Fix error handling for IdentityServer4 provider. +## 1.0.35 - 2024-10-20 + +### Added +- Add Xero provider. +- Add CA domain to Zoho provider. + ## 1.0.34 - 2024-09-13 ### Fixed diff --git a/src/clients/xero/provider/Xero.php b/src/clients/xero/provider/Xero.php new file mode 100644 index 0000000..8397741 --- /dev/null +++ b/src/clients/xero/provider/Xero.php @@ -0,0 +1,180 @@ +getAuthenticatedRequest( + self::METHOD_GET, + $this->getTenantsUrl($params), + $token + ); + + $response = $this->getParsedResponse($request); + $tenants = []; + + foreach ($response as $tenantData) { + $tenants[] = XeroTenant::fromArray($tenantData); + } + + return $tenants; + } + + /** + * @param AccessTokenInterface $token + * @param $connectionId + * @return mixed + * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + public function disconnect(AccessTokenInterface $token, $connectionId) + { + $url = sprintf('%s/%s', $this->getTenantsUrl(), $connectionId); + + $request = $this->getAuthenticatedRequest(self::METHOD_DELETE, $url, $token); + + $response = $this->getParsedResponse($request); + return $response; + } + + + /** + * Returns the URL for requesting the resource owner's details. + * + * @param AccessToken $token + * + * @return string + */ + public function getResourceOwnerDetailsUrl(AccessToken $token) + { + //This does not exist as it comes down in the JWT + return ''; + } + + /** + * @param AccessToken $token + * @return XeroResourceOwner + */ + public function getResourceOwner(AccessToken $token) + { + return XeroResourceOwner::fromJWT($token->getValues()['id_token']); + } + + + /** + * Checks a provider response for errors. + * + * @param ResponseInterface $response + * @param array|string $data Parsed response data + * + * @throws \Calcinai\OAuth2\Client\Provider\Exception\XeroProviderException + */ + protected function checkResponse(ResponseInterface $response, $data) + { + if ($response->getStatusCode() >= 400) { + throw new XeroProviderException( + isset($data['error']) ? $data['error'] : $response->getReasonPhrase(), + $response->getStatusCode(), + $response + ); + } + } + + /** + * @return array + */ + protected function getDefaultScopes() + { + return ['openid email profile']; + } + + /** + * Returns the string that should be used to separate scopes when building + * the URL for requesting an access token. + * + * @return string Scope separator, defaults to ' ' + */ + protected function getScopeSeparator() + { + return ' '; + } + + /** + * Generates a resource owner object from a successful resource owner + * details request. + * + * @param array $response + * @param AccessToken $token + * @return void|ResourceOwnerInterface + */ + protected function createResourceOwner(array $response, AccessToken $token) + { + // This does nothing as we get the resource owner from the token itself, don't need to make a request to get it. + } + + /** + * @param mixed|null $token + * @return array + */ + protected function getAuthorizationHeaders($token = null) + { + return [ + 'Authorization' => 'Bearer ' . $token->getToken() + ]; + } +} diff --git a/src/clients/xero/provider/XeroPkce.php b/src/clients/xero/provider/XeroPkce.php new file mode 100644 index 0000000..646c267 --- /dev/null +++ b/src/clients/xero/provider/XeroPkce.php @@ -0,0 +1,21 @@ +xero_userid = $decoded->xero_userid; + $self->preferred_username = $decoded->preferred_username; + $self->email = $decoded->email; + $self->given_name = $decoded->given_name; + $self->family_name = $decoded->family_name; + + return $self; + } +} diff --git a/src/clients/xero/provider/XeroTenant.php b/src/clients/xero/provider/XeroTenant.php new file mode 100644 index 0000000..7d48aea --- /dev/null +++ b/src/clients/xero/provider/XeroTenant.php @@ -0,0 +1,61 @@ +id = $data['id']; + $self->authEventId = $data['authEventId']; + $self->tenantId = $data['tenantId']; + $self->tenantType = $data['tenantType']; + $self->tenantName = $data['tenantName']; + $self->createdDateUtc = new \DateTime($data['createdDateUtc']); + $self->updatedDateUtc = isset($data['updatedDateUtc']) ? new \DateTime($data['updatedDateUtc']) : null; + + return $self; + } +} diff --git a/src/clients/xero/provider/exception/XeroProviderException.php b/src/clients/xero/provider/exception/XeroProviderException.php new file mode 100644 index 0000000..7ef2136 --- /dev/null +++ b/src/clients/xero/provider/exception/XeroProviderException.php @@ -0,0 +1,20 @@ +getStatusCode(), (string)$response->getBody()); + } +} diff --git a/src/helpers/Provider.php b/src/helpers/Provider.php index 7c26bd0..96b0f1c 100644 --- a/src/helpers/Provider.php +++ b/src/helpers/Provider.php @@ -156,6 +156,7 @@ public static function getPrimaryColor(string $handle): ?string 'wikipedia' => '#000000', 'wordpress' => '#21759B', 'x' => '#0f141a', + 'xero' => '#02b7e3', 'xing' => '#046466', 'yahoo' => '#6001D2', 'yammer' => '#106EBE', @@ -461,6 +462,8 @@ public static function getIcon(string $handle): ?string 'x' => '', + 'xero' => '', + 'xing' => '', 'yahoo' => '', diff --git a/src/providers/Xero.php b/src/providers/Xero.php new file mode 100644 index 0000000..784ffb7 --- /dev/null +++ b/src/providers/Xero.php @@ -0,0 +1,22 @@ +