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
|
|||
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 |
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.