Skip to content

Commit

Permalink
Merge branch 'craft-4' of https://github.com/verbb/auth into craft-5
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
#	composer.json
  • Loading branch information
engram-design committed Oct 20, 2024
2 parents 7ec39ae + e57f537 commit 3c6cb6d
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
180 changes: 180 additions & 0 deletions src/clients/xero/provider/Xero.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php

namespace verbb\auth\clients\xero\provider;

use verbb\auth\clients\xero\provider\exception\XeroProviderException;
use League\OAuth2\Client\Provider\AbstractProvider;
use League\OAuth2\Client\Provider\ResourceOwnerInterface;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Token\AccessTokenInterface;
use Psr\Http\Message\ResponseInterface;

/**
* @package Calcinai\OAuth2\Client\Provider
*/
class Xero extends AbstractProvider
{
const METHOD_DELETE = 'DELETE';

/**
* Returns the base URL for authorizing a client.
*
* @return string
*/
public function getBaseAuthorizationUrl()
{
return 'https://login.xero.com/identity/connect/authorize';
}

/**
* Returns the base URL for requesting an access token.
*
* @param array $params
*
* @return string
*/
public function getBaseAccessTokenUrl(array $params)
{
return 'https://identity.xero.com/connect/token';
}

/**
* @param null|array $params
* @return string
*/
public function getTenantsUrl(?array $params = null)
{
if ($params) {
$params = '?' . http_build_query($params);
}

return 'https://api.xero.com/connections' . $params;
}

/**
* @param AccessTokenInterface $token
* @param null|array $params
* @return XeroTenant[]
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
* @throws \Exception
*/
public function getTenants(AccessTokenInterface $token, ?array $params = null)
{
$request = $this->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()
];
}
}
21 changes: 21 additions & 0 deletions src/clients/xero/provider/XeroPkce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace verbb\auth\clients\xero\provider;

use League\OAuth2\Client\Provider\AbstractProvider;

/**
* @package Calcinai\OAuth2\Client\Provider
*/
class XeroPkce extends Xero
{
/**
* Enable the PKCE flow
*
* @return string PKCE Method S256
*/
protected function getPkceMethod()
{
return AbstractProvider::PKCE_METHOD_S256;
}
}
56 changes: 56 additions & 0 deletions src/clients/xero/provider/XeroResourceOwner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace verbb\auth\clients\xero\provider;

use Firebase\JWT\JWT;

class XeroResourceOwner
{
/**
* Xero user's UUID
*
* @var string
*/
public $xero_userid;

/**
* @var string
*/
public $preferred_username;

/**
* @var string
*/
public $email;

/**
* @var string
*/
public $given_name;

/**
* @var string
*/
public $family_name;

/**
* @param $token
* @return static
*/
public static function fromJWT($token)
{
list($header, $body, $crypto) = explode('.', $token);
//This needs to be done manually as we don't get a signed JWT
$decoded = JWT::jsonDecode(JWT::urlsafeB64Decode($body));

$self = new static();

$self->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;
}
}
61 changes: 61 additions & 0 deletions src/clients/xero/provider/XeroTenant.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace verbb\auth\clients\xero\provider;

class XeroTenant
{
/**
* @var string
*/
public $id;

/**
* @var string
*/
public $authEventId;

/**
* @var string
*/
public $tenantId;

/**
* @var string
*/
public $tenantType;

/**
* @var string
*/
public $tenantName;

/**
* @var \DateTime
*/
public $createdDateUtc;

/**
* @var \DateTime
*/
public $updatedDateUtc;

/**
* @param $data
* @return XeroTenant
* @throws \Exception
*/
public static function fromArray($data)
{
$self = new static();

$self->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;
}
}
20 changes: 20 additions & 0 deletions src/clients/xero/provider/exception/XeroProviderException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace verbb\auth\clients\xero\provider\exception;

use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Psr\Http\Message\ResponseInterface;

class XeroProviderException extends IdentityProviderException
{
/**
* @param ResponseInterface $response
* @param string|null $message
*
* @throws XeroProviderException
*/
public static function fromResponse(ResponseInterface $response, $message = null)
{
throw new static($message, $response->getStatusCode(), (string)$response->getBody());
}
}
3 changes: 3 additions & 0 deletions src/helpers/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -461,6 +462,8 @@ public static function getIcon(string $handle): ?string

'x' => '<svg fill="currentColor" viewBox="0 0 24 24"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg>',

'xero' => '<svg fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm6.585 14.655c-1.485 0-2.69-1.206-2.69-2.689 0-1.485 1.207-2.691 2.69-2.691 1.485 0 2.69 1.207 2.69 2.691s-1.207 2.689-2.69 2.689zM7.53 14.644c-.099 0-.192-.041-.267-.116l-2.043-2.04-2.052 2.047c-.069.068-.16.108-.258.108-.202 0-.368-.166-.368-.368 0-.099.04-.191.111-.263l2.04-2.05-2.038-2.047c-.075-.069-.113-.162-.113-.261 0-.203.166-.366.368-.366.098 0 .188.037.258.105l2.055 2.048 2.048-2.045c.069-.071.162-.108.26-.108.211 0 .375.165.375.366 0 .098-.029.188-.104.258l-2.056 2.055 2.055 2.051c.068.069.104.16.104.258 0 .202-.165.368-.365.368h-.01zm8.017-4.591c-.796.101-.882.476-.882 1.404v2.787c0 .202-.165.366-.366.366-.203 0-.367-.165-.368-.366v-4.53c0-.204.16-.366.362-.366.166 0 .316.125.346.289.27-.209.6-.317.93-.317h.105c.195 0 .359.165.359.368 0 .201-.164.352-.375.359 0 0-.09 0-.164.008l.053-.002zm-3.091 2.205H8.625c0 .019.003.037.006.057.02.105.045.211.083.31.194.531.765 1.275 1.829 1.29.33-.003.631-.086.9-.229.21-.12.391-.271.525-.428.045-.058.09-.112.12-.168.18-.229.405-.186.54-.083.164.135.18.391.045.57l-.016.016c-.21.27-.435.495-.689.66-.255.164-.525.284-.811.345-.33.09-.645.104-.975.06-1.095-.135-2.01-.93-2.28-2.01-.06-.21-.09-.42-.09-.645 0-.855.421-1.695 1.125-2.205.885-.615 2.085-.66 3-.075.63.405 1.035 1.021 1.185 1.771.075.419-.21.794-.734.81l.068-.046zm6.129-2.223c-1.064 0-1.931.865-1.931 1.931 0 1.064.866 1.931 1.931 1.931s1.931-.867 1.931-1.931c0-1.065-.866-1.933-1.931-1.933v.002zm0 2.595c-.367 0-.666-.297-.666-.666 0-.367.3-.665.666-.665.367 0 .667.299.667.665 0 .369-.3.667-.667.666zm-8.04-2.603c-.91 0-1.672.623-1.886 1.466v.03h3.776c-.203-.855-.973-1.494-1.891-1.494v-.002z"/></svg>',

'xing' => '<svg fill="currentColor" viewBox="0 0 384 512"><path d="M162.7 210c-1.8 3.3-25.2 44.4-70.1 123.5-4.9 8.3-10.8 12.5-17.7 12.5H9.8c-7.7 0-12.1-7.5-8.5-14.4l69-121.3c.2 0 .2-.1 0-.3l-43.9-75.6c-4.3-7.8.3-14.1 8.5-14.1H100c7.3 0 13.3 4.1 18 12.2l44.7 77.5zM382.6 46.1l-144 253v.3L330.2 466c3.9 7.1.2 14.1-8.5 14.1h-65.2c-7.6 0-13.6-4-18-12.2l-92.4-168.5c3.3-5.8 51.5-90.8 144.8-255.2 4.6-8.1 10.4-12.2 17.5-12.2h65.7c8 0 12.3 6.7 8.5 14.1z"></path></svg>',

'yahoo' => '<svg fill="currentColor" viewBox="0 0 24 24"><path d="M18.86 1.56L14.27 11.87H19.4L24 1.56H18.86M0 6.71L5.15 18.27L3.3 22.44H7.83L14.69 6.71H10.19L7.39 13.44L4.62 6.71H0M15.62 12.87C13.95 12.87 12.71 14.12 12.71 15.58C12.71 17 13.91 18.19 15.5 18.19C17.18 18.19 18.43 16.96 18.43 15.5C18.43 14.03 17.23 12.87 15.62 12.87Z"/></svg>',
Expand Down
22 changes: 22 additions & 0 deletions src/providers/Xero.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
namespace verbb\auth\providers;

use verbb\auth\base\ProviderTrait;
use verbb\auth\clients\xero\provider\Xero as XeroProvider;

class Xero extends XeroProvider
{
// Traits
// =========================================================================

use ProviderTrait;


// Public Methods
// =========================================================================

public function getBaseApiUrl(): ?string
{
return 'https://api.xero.com/';
}
}

0 comments on commit 3c6cb6d

Please sign in to comment.