<?php
namespace Platform\SecurityBundle\Service\OAuth;
use Cms\CoreBundle\Service\ContextManager;
use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Client\CurlClient;
use OAuth\Common\Service\ServiceInterface;
use OAuth\Common\Storage\SymfonySession;
use OAuth\ServiceFactory;
use Platform\SecurityBundle\Model\OAuth\OAuthOptions;
use Platform\SecurityBundle\Service\OAuth\Providers\AbstractOAuthProvider;
use Platform\SecurityBundle\Service\OAuth\Providers as OAuthProviders;
use Platform\SecurityBundle\Util\OAuth\ServiceFactory as ServiceFactories;
use Symfony\Component\HttpFoundation\RequestStack;
use OAuth\Common\Exception\Exception as OAuthException;
/**
* Manages the OAuth core services that pertain to logins.
*
* Class OAuthServiceFactory
* @package Platform\SecurityBundle\Service\OAuth
*/
final class OAuthServiceFactory extends ServiceFactory
{
/**
* Defines the set of services that this system will support.
* Keys are the IDs of the OAuth providers in the system.
* Values are the classnames of the service factory tied to that provider.
*/
private const SERVICES = [
OAuthProviders\ClassLinkOAuthProvider::ID => ServiceFactories\ClassLinkOAuth2ServiceFactory::class,
OAuthProviders\CleverOAuthProvider::ID => ServiceFactories\CleverOAuth2ServiceFactory::class,
OAuthProviders\GlobalGridOAuthProvider::ID => ServiceFactories\GlobalGridOAuth2ServiceFactory::class,
OAuthProviders\GoogleOAuthProvider::ID => ServiceFactories\GoogleOAuth2ServiceFactory::class,
OAuthProviders\MicrosoftOAuthProvider::ID => ServiceFactories\MicrosoftOAuth2ServiceFactory::class,
];
/**
* @var RequestStack
*/
private RequestStack $requestStack;
/**
* @var ContextManager
*/
private ContextManager $cm;
/**
* @param RequestStack $requestStack
* @param ContextManager $cm
* @throws OAuthException
*/
public function __construct(RequestStack $requestStack, ContextManager $cm)
{
$this->requestStack = $requestStack;
$this->cm = $cm;
// we need to set up the client that handles the http api calls
$this->setHttpClient(new CurlClient());
// go ahead and register each service
foreach (self::SERVICES as $name => $class) {
$this->registerService($name, $class);
}
}
/**
* Gets the core OAuth service.
* Services are loosely tied to the providers, so a provider is required to be passed in order to obtain one.
* An optional callback can be set for when configuring the "credentials" for the service.
* This is useful for when handling things like Clever "Instant Login" requests as the OAuth callback differs.
*
* @param AbstractOAuthProvider $provider
* @param OAuthOptions $options
* @return ServiceInterface
*/
public function getService(AbstractOAuthProvider $provider, OAuthOptions $options): ServiceInterface
{
return $this->createService(
$provider->getId(),
new Credentials(
$provider->getClient(),
$provider->getSecret(),
$options->getCallback() ?? $this->getDefaultCallbackUrl()
),
new SymfonySession($this->requestStack->getSession()),
array_merge($options->getScopes(), $provider->getScopes())
);
}
/**
* Gets a default value to use for the OAuth callbacks.
*
* TODO: this should use the router to properly generate the url
*
* @return string
*/
private function getDefaultCallbackUrl(): string
{
return sprintf(
'https://%s/_oauth',
$this->cm->getGlobalContext()->getDashboard(true)
);
}
}