creads/partners-sdk-php

View on GitHub
src/Console/Command/LoginCommand.php

Summary

Maintainability
C
7 hrs
Test Coverage
<?php

namespace Creads\Partners\Console\Command;

use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;

class LoginCommand extends Command
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName('login')
            ->setDescription('Log onto the API')
            ->addOption(
               'reset',
               'r',
               InputOption::VALUE_NONE,
               'Reset credentials'
            )
            ->addOption(
                'save-password',
                null,
                InputOption::VALUE_NONE,
                'Save your password locally'
            )
            ->addOption(
                'grant-type',
                null,
                InputOption::VALUE_REQUIRED,
                'Use a given OAuth2 grant type (default: password)'
            );
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        //for the output to stdderr to no break the output
        $output = $output->getErrorOutput();

        $style = new OutputFormatterStyle('black', 'white');
        $output->getFormatter()->setStyle('fire', $style);

        $questionHelper = $this->getHelperSet()->get('question');
        $formatter = $this->getHelperSet()->get('formatter');

        $reset = $input->getOption('reset', false);
        $type = $input->getOption('grant-type', null);
        $savePassword = $input->getOption('save-password', false);

        $configuration = $this->getHelperSet()->get('configuration');
        if (!$configuration->exists()) {
            $configuration['grant_type'] = $type ? $type : 'password';
        } elseif ($type && $configuration['grant_type'] !== $type) {
            //if grant type was forced to change
            $configuration['grant_type'] = $type;

            //clear password for security concerns
            unset($configuration['password']);
        }

        if (!in_array($configuration['grant_type'], ['client_credentials', 'password'])) {
            throw new \InvalidArgumentException(sprintf('Unsupported grant type "%s"', $configuration['grant_type']));
        }

        if ('password' === $configuration['grant_type']
            && !isset($configuration['password'])
            && !$savePassword
        ) {
            //if we are using password grant type
            //and password was not saved
            //and user did not ask to save it
            $output->writeln($formatter->formatBlock([
                'Avoid to type your password each time token expires, using "client_credentials" grant type:',
                '',
                sprintf('    %s login --grant-type=client_credentials', $_SERVER['argv'][0]),
                '',
                'Or save your password locally (not recommended):',
                '',
                sprintf('    %s login --save-password', $_SERVER['argv'][0]),
            ], 'fire', true));
        }

        if (!$configuration->exists() || $reset) {
            $output->writeln("Please provide your credentials (won't be asked next time).");

            unset($configuration['password']);

            $configuration['client_id'] = $this->getConfigValue($input, $output, 'Client ID', isset($configuration['client_id']) ? $configuration['client_id'] : null, $reset);

            $configuration['client_secret'] = $this->getConfigValue($input, $output, 'Client Secret', isset($configuration['client_secret']) ? $configuration['client_secret'] : null, $reset);

            if ('password' === $configuration['grant_type']) {
                $configuration['username'] = $this->getConfigValue($input, $output, 'Username', isset($configuration['username']) ? $configuration['username'] : null, $reset);
            }
        }

        //build form params
        $params = [
            'grant_type' => $configuration['grant_type'],
            'scope'      => 'base',
        ];
        if ('password' === $configuration['grant_type']) {
            if (!isset($configuration['password'])) {
                $question = new Question('<question>Password</question>: ');
                $question->setHidden(true);
                $question->setHiddenFallback(false);
                if (!$password = $questionHelper->ask(
                    $input,
                    $output,
                    $question
                )) {
                    return 1;
                }

                if ($savePassword) {
                    $configuration['password'] = $password;
                }
            } else {
                $password = $configuration['password'];
            }

            $params = array_merge($params, [
                'username' => $configuration['username'],
                'password' => $password,
            ]);
        }

        //@todo build a service to do that
        $client = new \GuzzleHttp\Client(['base_uri' => $configuration['connect_base_uri']]);
        try {
            $response = $client->post('/oauth2/token', [
                'auth'        => [$configuration['client_id'], $configuration['client_secret']],
                'form_params' => $params,
            ]);
        } catch (\GuzzleHttp\Exception\ClientException $e) {
            $data = json_decode($e->getResponse()->getBody(), true);
            $message = isset($data['error_description']) ? $data['error_description'] : ($e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase());
            throw new \Exception($message);
        }

        if (!($data = json_decode($response->getBody(), true))) {
            throw new \Exception('Failed to decode API response');
        }

        $configuration['access_token'] = $data['access_token'];
        $configuration['expires_at'] = isset($data['expires_in']) ? (time() + $data['expires_in']) : null;
        $configuration['refresh_token'] = isset($data['refresh_token']) ? $data['refresh_token'] : null;

        $configuration->store();

        $output->writeln('Login: <comment>OK</comment>');
    }

    /**
     * @param OutputInterface $output
     * @param string          $label
     * @param string|null     $previous
     * @param bool            $reset
     */
    protected function getConfigValue($input, $output, $label, $previous, $reset)
    {
        $questionHelper = $this->getHelperSet()->get('question');
        $question = new Question(sprintf('<question>%s</question>%s: ', $label, $previous ? (' [<comment>'.$previous.'</comment>]') : ''));
        if (!$value = $questionHelper->ask(
            $input,
            $output,
            $question
        )) {
            if ($reset) {
                $value = $previous;
            } else {
                throw new \InvalidArgumentException(sprintf('%s is required', $label));
            }
        }

        return $value;
    }
}