Issues (17)

src/ThirdParty/Google/GoogleConnection.php (1 issue)

1
<?php
2
/**
3
 * @author Tharanga Kothalawala <[email protected]>
4
 * @date 30-12-2018
5
 */
6
7
namespace TSK\SSO\ThirdParty\Google;
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
use Google_Client;
17
use Google_Service_Plus;
18
use RuntimeException;
19
20
/**
21
 * @codeCoverageIgnore
22
 * @package TSK\SSO\ThirdParty\Google
23
 * @see https://console.developers.google.com
24
 */
25
class GoogleConnection implements VendorConnection
26
{
27
    const API_BASE = 'https://www.googleapis.com';
28
29
    /**
30
     * @var GoogleApiConfiguration
31
     */
32
    private $apiConfiguration;
33
34
    /**
35
     * @var CurlRequest
36
     */
37
    private $curlClient;
38
39
    /**
40
     * @var Google_Client
41
     */
42
    private $googleClient;
43
44
    /**
45
     * @param GoogleApiConfiguration $apiConfiguration
46
     * @param CurlRequest $curlClient
47
     */
48
    public function __construct(
49
        GoogleApiConfiguration $apiConfiguration,
50
        CurlRequest $curlClient
51
    ) {
52
        $this->apiConfiguration = $apiConfiguration;
53
        $this->curlClient = $curlClient;
54
55
        $this->googleClient = new Google_Client(array(
56
            'client_id' => $this->apiConfiguration->appId(),
57
            'client_secret' => $this->apiConfiguration->appSecret(),
58
            'redirect_uri' => $this->apiConfiguration->redirectUrl(),
59
        ));
60
        $this->googleClient->setScopes($this->apiConfiguration->appPermissions());
61
    }
62
63
    /**
64
     * Use this to get a link to redirect a user to the google login page.
65
     *
66
     * @return string
67
     */
68
    public function getGrantUrl()
69
    {
70
        return filter_var($this->googleClient->createAuthUrl(), FILTER_SANITIZE_URL);
71
    }
72
73
    /**
74
     * Grants a new access token
75
     *
76
     * @return CommonAccessToken
77
     * @throws ThirdPartyConnectionFailedException
78
     */
79
    public function grantNewAccessToken()
80
    {
81
        if (empty($_GET['code'])) {
82
            throw new RuntimeException('Error : A code cannot be found!');
83
        }
84
85
        try {
86
            $authResponse = $this->googleClient->fetchAccessTokenWithAuthCode($_GET['code']);
87
            $accessTokenInfo = $this->googleClient->getAccessToken();
88
            $userInfo = array();
89
            if ($accessTokenInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $accessTokenInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
90
                $userInfo = $this->googleClient->verifyIdToken();
91
            }
92
        } catch (\Exception $ex) {
93
            throw new ThirdPartyConnectionFailedException(
94
                sprintf('Failed to establish a new third party vendor connection. Error : %s', $ex->getMessage())
95
            );
96
        }
97
98
        if (empty($authResponse['access_token'])) {
99
            throw new ThirdPartyConnectionFailedException('Failed to establish a new third party vendor connection.');
100
        }
101
102
        return new CommonAccessToken(
103
            $authResponse['access_token'],
104
            ThirdParty::GOOGLE,
105
            $userInfo['email']
106
        );
107
    }
108
109
    /**
110
     * Get the current authenticated user data using there existing granted token
111
     *
112
     * @param CommonAccessToken $accessToken
113
     * @return ThirdPartyUser
114
     * @throws NoThirdPartyEmailFoundException
115
     * @throws ThirdPartyConnectionFailedException
116
     */
117
    public function getSelf(CommonAccessToken $accessToken)
118
    {
119
        $userJsonInfo = $this->curlClient->get(
120
            sprintf('%s/oauth2/v1/userinfo?access_token=%s', self::API_BASE, $accessToken->token())
121
        );
122
123
        $userInfo = json_decode($userJsonInfo, true);
124
        if (!empty($userInfo['error'])) {
125
            throw new ThirdPartyConnectionFailedException(
126
                sprintf('Failed to retrieve third party user data. Error : %s', $userInfo['error'])
127
            );
128
        }
129
130
        if (empty($userInfo['email'])) {
131
            throw new NoThirdPartyEmailFoundException('An email address cannot be found from vendor');
132
        }
133
134
        return new ThirdPartyUser(
135
            $userInfo['id'],
136
            $userInfo['name'],
137
            $userInfo['email'],
138
            !empty($userInfo['picture']) ? $userInfo['picture'] : '',
139
            !empty($userInfo['gender']) ? $userInfo['gender'] : ''
140
        );
141
    }
142
143
    /**
144
     * Use this to revoke the access to the third party data.
145
     * This will completely remove the access from the vendor side.
146
     *
147
     * @param CommonAccessToken $accessToken
148
     * @return bool
149
     */
150
    public function revokeAccess(CommonAccessToken $accessToken)
151
    {
152
        $revoked = $this->googleClient->revokeToken($accessToken->token());
153
        if (!$revoked) {
154
            return false;
155
        }
156
157
        return true;
158
    }
159
}
160