Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractOAuth2Provider
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
5 / 5
13
100.00% covered (success)
100.00%
1 / 1
 getAuthorizeUrl
n/a
0 / 0
n/a
0 / 0
0
 getAccessTokenUrl
n/a
0 / 0
n/a
0 / 0
0
 getScope
n/a
0 / 0
n/a
0 / 0
0
 getUserProfile
n/a
0 / 0
n/a
0 / 0
0
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 authenticate
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 getAccessToken
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getFullAuthorizeUrl
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 generateState
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace Miniframe\SocialLogin\Provider;
4
5use Miniframe\Core\Config;
6use Miniframe\Core\Request;
7use Miniframe\Response\RedirectResponse;
8use Miniframe\SocialLogin\Middleware\SocialLogin;
9use Miniframe\SocialLogin\Model\User;
10
11abstract class AbstractOAuth2Provider extends AbstractOAuthProvider
12{
13    /**
14     * Returns the Authorize URL
15     *
16     * @return string
17     */
18    abstract protected function getAuthorizeUrl(): string;
19
20    /**
21     * Returns the Access Token URL
22     *
23     * @return string
24     */
25    abstract protected function getAccessTokenUrl(): string;
26
27    /**
28     * Returns the requested scope
29     *
30     * @return string|null
31     */
32    abstract protected function getScope(): ?string;
33
34    /**
35     * Returns the user profile
36     *
37     * @param array $accessToken The access token.
38     *
39     * @return User
40     */
41    abstract protected function getUserProfile(array $accessToken): User;
42
43    /**
44     * OAuth 2.0 Client ID
45     *
46     * @var string
47     */
48    protected $clientId;
49
50    /**
51     * OAuth 2.0 Client Secret
52     *
53     * @var string
54     */
55    protected $clientSecret;
56
57    /**
58     * Creates a new OAuth 2.0 provider
59     *
60     * @param Request $request Reference to the Request object.
61     * @param Config  $config  Reference to the Config object.
62     */
63    public function __construct(Request $request, Config $config)
64    {
65        parent::__construct($request, $config);
66
67        // Get config
68        $this->clientId = $config->get('sociallogin-' . $this->shortName, 'client_id');
69        $this->clientSecret = $config->get('sociallogin-' . $this->shortName, 'client_secret');
70    }
71
72    /**
73     * Starts the authentication process
74     *
75     * @return User
76     */
77    public function authenticate(): User
78    {
79        if ($this->request->getRequest('state') && $this->request->getRequest('code')) {
80            $state = SocialLogin::parseState($this->request->getRequest('state'));
81            if (!isset($state['redirectUrl'])) {
82                throw new \RuntimeException('State incomplete');
83            }
84
85            $accessToken = $this->getAccessToken($this->request->getRequest('code'));
86            if (!isset($accessToken['access_token'])) {
87                throw new \RuntimeException('Did\'t get an access token');
88            }
89            return $this->getUserProfile($accessToken);
90        }
91
92        throw new RedirectResponse($this->getFullAuthorizeUrl());
93    }
94
95    /**
96     * Requests the access token based on a code from the OAuth provider
97     *
98     * @param string $code The provided code.
99     *
100     * @return array
101     */
102    protected function getAccessToken(string $code): array
103    {
104        $data = array(
105            'client_id' => $this->clientId,
106            'client_secret' => $this->clientSecret,
107            'code' => $code,
108            'redirect_uri' => $this->getCurrentUri(),
109            'grant_type' => 'authorization_code',
110        );
111
112        return $this->curlRequest($this->getAccessTokenUrl(), 'POST', $data);
113    }
114
115    /**
116     * Gets a full authorize URL, including the client ID and all other required parameters.
117     *
118     * @param array $data Optionally extra fields to append to the authorize URL.
119     *
120     * @return string
121     */
122    protected function getFullAuthorizeUrl(array $data = array()): string
123    {
124        $data['client_id'] = $this->clientId;
125        $data['redirect_uri'] = $this->getCurrentUri();
126        $data['state'] = $this->generateState();
127        $data['response_type'] = 'code';
128        if ($this->getScope()) {
129            $data['scope'] = $this->getScope();
130        }
131
132        return $this->getAuthorizeUrl()
133            . (strpos($this->getAuthorizeUrl(), '?') !== false ? '&' : '?')
134            . http_build_query($data);
135    }
136
137    /**
138     * Generates the state string
139     *
140     * @return string
141     */
142    protected function generateState(): string
143    {
144        $state = array();
145        if ($this->request->getRequest('state')) {
146            $state = SocialLogin::parseState($this->request->getRequest('state'));
147        }
148        if (!isset($state['redirectUrl'])) {
149            $state['redirectUrl'] = $this->baseHref;
150        }
151        return SocialLogin::generateState($state);
152    }
153}