1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\GoogleAuthWebclient;
9:
10: /**
11: * This module adds ability to login using Google account.
12: *
13: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
14: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
15: * @copyright Copyright (c) 2023, Afterlogic Corp.
16: *
17: * @property Settings $oModuleSettings
18: *
19: * @package Modules
20: */
21: class Module extends \Aurora\System\Module\AbstractWebclientModule
22: {
23: protected $sService = 'google';
24:
25: protected $aRequireModules = array(
26: 'OAuthIntegratorWebclient',
27: 'Google'
28: );
29:
30: /**
31: * @return Module
32: */
33: public static function getInstance()
34: {
35: return parent::getInstance();
36: }
37:
38: /**
39: * @return Module
40: */
41: public static function Decorator()
42: {
43: return parent::Decorator();
44: }
45:
46: /**
47: * @return Settings
48: */
49: public function getModuleSettings()
50: {
51: return $this->oModuleSettings;
52: }
53:
54: /***** private functions *****/
55: protected function issetScope($sScope)
56: {
57: return in_array($sScope, explode(' ', $this->oModuleSettings->Scopes));
58: }
59:
60: /**
61: * Initializes FacebookAuthWebclient Module.
62: *
63: * @ignore
64: */
65: public function init()
66: {
67: $this->subscribeEvent('OAuthIntegratorWebclient::GetServices::after', array($this, 'onAfterGetServices'));
68: $this->subscribeEvent('OAuthIntegratorAction', array($this, 'onOAuthIntegratorAction'));
69: $this->subscribeEvent('Google::GetSettings', array($this, 'onGetSettings'));
70: $this->subscribeEvent('Google::UpdateSettings::after', array($this, 'onAfterUpdateSettings'));
71: $this->subscribeEvent('RevokeAccessToken', array($this, 'onRevokeAccessToken'));
72: $this->subscribeEvent('ResetAccessToken', array($this, 'onResetAccessToken'));
73: $this->subscribeEvent('GetAccessToken', array($this, 'onGetAccessToken'));
74: }
75:
76: /**
77: * Adds service name to array passed by reference.
78: *
79: * @ignore
80: * @param array $aArgs
81: * @param array $aServices Array with services names passed by reference.
82: */
83: public function onAfterGetServices($aArgs, &$aServices)
84: {
85: $oModule = \Aurora\Modules\Google\Module::getInstance();
86: $sId = $oModule->oModuleSettings->Id;
87: $sSecret = $oModule->oModuleSettings->Secret;
88:
89: if ($oModule->oModuleSettings->EnableModule && $this->issetScope('auth') && !empty($sId) && !empty($sSecret)) {
90: $aServices[] = $this->sService;
91: }
92: }
93:
94: /**
95: * Passes data to connect to service.
96: *
97: * @ignore
98: * @param string $aArgs Service type to verify if data should be passed.
99: * @param boolean|array $mResult variable passed by reference to take the result.
100: */
101: public function onOAuthIntegratorAction($aArgs, &$mResult)
102: {
103: if (isset($aArgs['Service']) && $aArgs['Service'] === $this->sService) {
104: $sOAuthScopes = isset($_COOKIE['oauth-scopes']) ? $_COOKIE['oauth-scopes'] : '';
105: $aGoogleScopes = [
106: 'https://www.googleapis.com/auth/userinfo.email',
107: 'https://www.googleapis.com/auth/userinfo.profile'
108: ];
109: $this->broadcastEvent('PopulateScopes', $sOAuthScopes, $aGoogleScopes);
110:
111: $mResult = false;
112: $oConnector = new Classes\Connector($this);
113: if ($oConnector) {
114: $oGoogleModule = \Aurora\Modules\Google\Module::getInstance();
115: if ($oGoogleModule) {
116: $sId = $oGoogleModule->oModuleSettings->Id;
117: $sSecret = $oGoogleModule->oModuleSettings->Secret;
118:
119: $mResult = $oConnector->Init(
120: $sId,
121: $sSecret,
122: [$sOAuthScopes, \implode(' ', $aGoogleScopes)]
123: );
124: }
125: }
126: return true;
127: }
128: }
129:
130: /**
131: * Passes data to connect to service.
132: *
133: * @ignore
134: * @param string $aArgs Service type to verify if data should be passed.
135: * @param boolean|array $mResult variable passed by reference to take the result.
136: */
137: public function onGetSettings($aArgs, &$mResult)
138: {
139: $oUser = \Aurora\System\Api::getAuthenticatedUser();
140:
141: if ($oUser) {
142: $aScope = array(
143: 'Name' => 'auth',
144: 'Description' => $this->i18N('SCOPE_AUTH'),
145: 'Value' => false
146: );
147: if ($oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
148: $aScope['Value'] = $this->issetScope('auth');
149: $mResult['Scopes'][] = $aScope;
150: }
151: if ($oUser->isNormalOrTenant()) {
152: if ($aArgs['OAuthAccount'] instanceof \Aurora\Modules\OAuthIntegratorWebclient\Models\OauthAccount) {
153: $aScope['Value'] = $aArgs['OAuthAccount']->issetScope('auth');
154: }
155: if ($this->issetScope('auth')) {
156: $mResult['Scopes'][] = $aScope;
157: }
158: }
159: }
160: }
161:
162: public function onAfterUpdateSettings($aArgs, &$mResult)
163: {
164: $sScope = '';
165: if (isset($aArgs['Scopes']) && is_array($aArgs['Scopes'])) {
166: foreach ($aArgs['Scopes'] as $aScope) {
167: if ($aScope['Name'] === 'auth') {
168: if ($aScope['Value']) {
169: $sScope = 'auth';
170: break;
171: }
172: }
173: }
174: }
175: $this->setConfig('Scopes', $sScope);
176: $this->saveModuleConfig();
177: }
178:
179: public function onRevokeAccessToken($aArgs)
180: {
181: if (isset($aArgs['Service']) && $aArgs['Service'] === $this->sService) {
182: $oConnector = new Classes\Connector($this);
183: if ($oConnector) {
184: $oGoogleModule = \Aurora\Modules\Google\Module::getInstance();
185: if ($oGoogleModule) {
186: $sAccessToken = isset($aArgs['AccessToken']) ? $aArgs['AccessToken'] : '';
187: $oConnector->RevokeAccessToken(
188: $oGoogleModule->oModuleSettings->Id,
189: $oGoogleModule->oModuleSettings->Secret,
190: $sAccessToken
191: );
192: }
193: }
194: }
195: }
196:
197: public function onResetAccessToken($aArgs)
198: {
199: if (isset($aArgs['Service']) && $aArgs['Service'] === $this->sService) {
200: $oConnector = new Classes\Connector($this);
201: if ($oConnector) {
202: $oGoogleModule = \Aurora\Modules\Google\Module::getInstance();
203: if ($oGoogleModule) {
204: $oConnector->ResetAccessToken(
205: $oGoogleModule->oModuleSettings->Id,
206: $oGoogleModule->oModuleSettings->Secret
207: );
208: }
209: }
210: }
211: }
212:
213: public function onGetAccessToken($aArgs, &$mResult)
214: {
215: if (isset($aArgs['Service']) && $aArgs['Service'] === $this->sService && isset($aArgs['Account'])) {
216: $mResult = false;
217: /** @var \Aurora\Modules\OAuthIntegratorWebclient\Models\OauthAccount $oAccount */
218: $oAccount = $aArgs['Account'];
219: $oTokenData = \json_decode($oAccount->AccessToken);
220: if ($oTokenData) {
221: $iCreated = (int) $oTokenData->created;
222: $iExpiresIn = (int) $oTokenData->expires_in;
223: if (time() > ($iCreated + $iExpiresIn) && isset($oAccount->RefreshToken)) {
224: $oGoogleModule = \Aurora\Modules\Google\Module::getInstance();
225: if ($oGoogleModule) {
226: $oConnector = new Classes\Connector($this);
227: $aResult = $oConnector->RefreshAccessToken(
228: $oGoogleModule->oModuleSettings->Id,
229: $oGoogleModule->oModuleSettings->Secret,
230: $oAccount->RefreshToken
231: );
232: if (isset($aResult['access_token'])) {
233: $oTokenData->access_token = $aResult['access_token'];
234: $oTokenData->created = time();
235: $oTokenData->expires_in = $aResult['expires_in'];
236:
237: $mResult = $oTokenData->access_token;
238:
239: $oAccount->AccessToken = \json_encode($oTokenData);
240: $oAccount->save();
241: }
242: }
243: } else {
244: $mResult = $oTokenData->access_token;
245: }
246: }
247:
248: return true;
249: }
250: }
251: }
252: