Passed
Push — master ( 33e63f...3377ec )
by Tharanga
06:29
created

GitHubConnection::getGrantUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Tharanga Kothalawala <[email protected]>
4
 * @date 29-01-2019
5
 */
6
7
namespace TSK\SSO\ThirdParty\GitHub;
8
9
use TSK\SSO\Http\CurlRequest;
10
use TSK\SSO\ThirdParty;
11
use TSK\SSO\ThirdParty\CommonAccessToken;
12
use TSK\SSO\ThirdParty\Exception\NoThirdPartyEmailFoundException;
13
use TSK\SSO\ThirdParty\Exception\ThirdPartyConnectionFailedException;
14
use TSK\SSO\ThirdParty\ThirdPartyUser;
15
use TSK\SSO\ThirdParty\VendorConnection;
16
17
/**
18
 * @codeCoverageIgnore
19
 * @package TSK\SSO\ThirdParty\GitHub
20
 * @see https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps
21
 */
22
class GitHubConnection implements VendorConnection
23
{
24
    const API_BASE = 'https://github.com/login/oauth';
25
26
    /**
27
     * @var GitHubApiConfiguration
28
     */
29
    private $apiConfiguration;
30
31
    /**
32
     * @var CurlRequest
33
     */
34
    private $curlClient;
35
36
    /**
37
     * GitHubConnection constructor.
38
     * @param GitHubApiConfiguration $apiConfiguration
39
     * @param CurlRequest $curlClient
40
     */
41
    public function __construct(GitHubApiConfiguration $apiConfiguration, CurlRequest $curlClient)
42
    {
43
        $this->apiConfiguration = $apiConfiguration;
44
        $this->curlClient = $curlClient;
45
    }
46
47
    /**
48
     * Use this to get a link to redirect a user to the third party login
49
     *
50
     * @return string|null
51
     */
52
    public function getGrantUrl()
53
    {
54
        return sprintf(
55
            '%s/authorize?client_id=%s&redirect_uri=%s&response_type=code&language=en-us&state=%s',
56
            self::API_BASE,
57
            $this->apiConfiguration->clientId(),
58
            urlencode($this->apiConfiguration->redirectUrl()),
59
            $this->apiConfiguration->ourSecretState()
60
        );
61
    }
62
63
    /**
64
     * Grants a new access token
65
     *
66
     * @return CommonAccessToken
67
     * @throws ThirdPartyConnectionFailedException
68
     */
69
    public function grantNewAccessToken()
70
    {
71
        if (empty($_GET['code'])
72
            || empty($_GET['state'])
73
            || $_GET['state'] !== $this->apiConfiguration->ourSecretState()
74
        ) {
75
            throw new ThirdPartyConnectionFailedException('Invalid request!');
76
        }
77
78
        $accessTokenUrlQueryString = $this->curlClient->post(
79
            sprintf("%s/access_token", self::API_BASE),
80
            array(
81
                'client_id' => $this->apiConfiguration->clientId(),
82
                'client_secret' => $this->apiConfiguration->clientSecret(),
83
                'code' => $_GET['code'],
84
                'redirect_uri' => $this->apiConfiguration->redirectUrl()
85
            )
86
        );
87
88
        parse_str($accessTokenUrlQueryString, $queryStringArray);
89
        if (empty($queryStringArray['access_token'])) {
90
            throw new ThirdPartyConnectionFailedException('Failed to establish a new third party vendor connection.');
91
        }
92
93
        return new CommonAccessToken(
94
            $queryStringArray['access_token'],
95
            ThirdParty::GITHUB
96
        );
97
    }
98
99
    /**
100
     * Use this to retrieve the current user's third party user data using there existing granted access token
101
     *
102
     * @param CommonAccessToken $accessToken
103
     * @return ThirdPartyUser
104
     * @throws NoThirdPartyEmailFoundException
105
     * @throws ThirdPartyConnectionFailedException
106
     */
107
    public function getSelf(CommonAccessToken $accessToken)
108
    {
109
        $userJsonInfo = $this->curlClient->get(
110
            'https://api.github.com/user',
111
            array(
112
                sprintf('Authorization: token %s', $accessToken->token()),
113
                sprintf('User-Agent: %s', $this->apiConfiguration->oauthAppName()),
114
                'Accept: application/json',
115
            )
116
        );
117
118
        $userInfo = json_decode($userJsonInfo, true);
119
        if (empty($userInfo['email'])) {
120
            throw new NoThirdPartyEmailFoundException('An email address cannot be found from vendor');
121
        }
122
123
        return new ThirdPartyUser(
124
            $userInfo['login'],
125
            $userInfo['name'],
126
            $userInfo['email'],
127
            !empty($userInfo['avatar_url']) ? $userInfo['avatar_url'] : '',
128
            !empty($userInfo['profile']['gender']) ? $userInfo['profile']['gender'] : ''
129
        );
130
    }
131
132
    /**
133
     * Use this to revoke the access to the third party data.
134
     * This will completely remove the access from the vendor side.
135
     * @see https://developer.github.com/v3/oauth_authorizations/#revoke-a-grant-for-an-application
136
     *
137
     * @param CommonAccessToken $accessToken
138
     * @return bool
139
     */
140
    public function revokeAccess(CommonAccessToken $accessToken)
141
    {
142
        $response = $this->curlClient->deleteWithBasicAuth(
143
            sprintf(
144
                'https://api.github.com/applications/%s/grants/%s',
145
                $this->apiConfiguration->clientId(),
146
                $accessToken->token()
147
            ),
148
            sprintf('%s:%s', $this->apiConfiguration->clientId(), $this->apiConfiguration->clientSecret()),
149
            array(sprintf('User-Agent: %s', $this->apiConfiguration->oauthAppName()))
150
        );
151
152
        // on success returns an empty string
153
        return empty($response);
154
    }
155
}
156