Issues (20)

Provider/Provider.php (2 issues)

1
<?php
2
/**
3
 * Copyright © 2019 O2TI. All rights reserved.
4
 * See LICENSE.txt for license details.
5
 */
6
7
namespace O2TI\SocialLogin\Provider;
8
9
use Exception;
10
use Hybridauth\HybridauthFactory;
11
use Hybridauth\User\Profile as SocialProfile;
12
use Magento\Customer\Api\AccountManagementInterface;
13
use Magento\Customer\Api\CustomerRepositoryInterface;
14
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
15
use Magento\Customer\Model\Account\Redirect as AccountRedirect;
16
use Magento\Customer\Model\Customer;
17
use Magento\Customer\Model\CustomerFactory;
18
use Magento\Customer\Model\ResourceModel\Customer as CustomerResource;
19
use Magento\Customer\Model\Session as CustomerSession;
20
use Magento\Customer\Model\Url as CustomerUrl;
21
use Magento\Framework\App\Config\ScopeConfigInterface;
22
use Magento\Framework\App\ObjectManager;
23
use Magento\Framework\Exception\LocalizedException;
24
use Magento\Framework\Message\ManagerInterface;
25
use Magento\Framework\Session\SessionManagerInterface;
26
use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory;
27
use Magento\Framework\Stdlib\CookieManagerInterface;
28
use Magento\Framework\UrlInterface;
29
use Magento\Store\Model\ScopeInterface;
30
use Magento\Store\Model\StoreManagerInterface;
31
32
/**
33
 * Provider section.
34
 *
35
 * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
36
 */
37
class Provider
38
{
39
    public const CONFIG_PATH_SOCIAL_LOGIN_ENABLED = 'social_login/general/enabled';
40
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_ENABLED = 'social_login/general/%s/enabled';
41
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_KEY = 'social_login/general/%s/api_key';
42
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_SECRET = 'social_login/general/%s/api_secret';
43
    public const COOKIE_NAME = 'login_redirect';
44
45
    /**
46
     * The providers we currently support.
47
     */
48
    public const PROVIDERS = [
49
        'facebook',
50
        'google',
51
        'WindowsLive',
52
    ];
53
54
    /**
55
     * @var HybridauthFactory
56
     */
57
    private $hybridauthFactory;
58
59
    /**
60
     * @var UrlInterface
61
     */
62
    private $url;
63
64
    /**
65
     * @var AccountManagementInterface
66
     */
67
    protected $accountManagement;
68
69
    /**
70
     * @var CustomerUrl
71
     */
72
    protected $customerUrl;
73
74
    /**
75
     * @var CustomerInterfaceFactory
76
     */
77
    protected $customerDataFactory;
78
79
    /**
80
     * @var CustomerFactory
81
     */
82
    private $customerFactory;
83
84
    /**
85
     * @var CustomerResource
86
     */
87
    private $customerResource;
88
89
    /**
90
     * @var CustomerSession
91
     */
92
    private $customerSession;
93
94
    /**
95
     * @var StoreManagerInterface
96
     */
97
    private $storeManager;
98
99
    /**
100
     * @var ScopeConfigInterface
101
     */
102
    private $scopeConfig;
103
104
    /**
105
     * @var CookieManagerInterface
106
     */
107
    private $cookieManager;
108
109
    /**
110
     * @var CookieMetadataFactory
111
     */
112
    private $cookieMetadataFactory;
113
114
    /**
115
     * @var SessionManagerInterface
116
     */
117
    private $sessionManager;
118
119
    /**
120
     * @var CustomerRepositoryInterface
121
     */
122
    protected $customerRepository;
123
124
    /**
125
     * @var ManagerInterface
126
     */
127
    private $messageManager;
128
129
    /**
130
     * @var AccountRedirect
131
     */
132
    protected $accountRedirect;
133
134
    /**
135
     * @param HybridauthFactory           $hybridauthFactory
136
     * @param UrlInterface                $url
137
     * @param AccountManagementInterface  $accountManagement
138
     * @param CustomerUrl                 $customerUrl
139
     * @param CustomerInterfaceFactory    $customerDataFactory
140
     * @param CustomerFactory             $customerFactory
141
     * @param CustomerResource            $customerResource
142
     * @param CustomerSession|null        $customerSession
143
     * @param StoreManagerInterface       $storeManager
144
     * @param ScopeConfigInterface        $scopeConfig
145
     * @param CookieManagerInterface      $cookieManager
146
     * @param CookieMetadataFactory       $cookieMetadataFactory
147
     * @param SessionManagerInterface     $sessionManager
148
     * @param CustomerRepositoryInterface $customerRepository
149
     * @param ManagerInterface            $messageManager
150
     * @param AccountRedirect             $accountRedirect
151
     */
152
    public function __construct(
153
        HybridauthFactory $hybridauthFactory,
154
        UrlInterface $url,
155
        AccountManagementInterface $accountManagement,
156
        CustomerUrl $customerUrl,
157
        CustomerInterfaceFactory $customerDataFactory,
158
        CustomerFactory $customerFactory,
159
        CustomerResource $customerResource,
160
        ?CustomerSession $customerSession = null,
161
        StoreManagerInterface $storeManager,
162
        ScopeConfigInterface $scopeConfig,
163
        CookieManagerInterface $cookieManager = null,
164
        CookieMetadataFactory $cookieMetadataFactory = null,
165
        SessionManagerInterface $sessionManager,
166
        CustomerRepositoryInterface $customerRepository,
167
        ManagerInterface $messageManager,
168
        AccountRedirect $accountRedirect
169
    ) {
170
        $this->hybridauthFactory = $hybridauthFactory;
171
        $this->url = $url;
172
        $this->accountManagement = $accountManagement;
173
        $this->customerUrl = $customerUrl;
174
        $this->customerDataFactory = $customerDataFactory;
175
        $this->customerFactory = $customerFactory;
176
        $this->customerResource = $customerResource;
177
        $this->customerSession = $customerSession ?? ObjectManager::getInstance()->get(CustomerSession::class);
178
        $this->storeManager = $storeManager;
179
        $this->scopeConfig = $scopeConfig;
180
        $this->cookieManager = $cookieManager ?:
181
            ObjectManager::getInstance()->get(CookieManagerInterface::class);
182
        $this->cookieMetadataFactory = $cookieMetadataFactory ?:
183
            ObjectManager::getInstance()->get(CookieMetadataFactory::class);
184
        $this->sessionManager = $sessionManager;
185
        $this->customerRepository = $customerRepository;
186
        $this->messageManager = $messageManager;
187
        $this->accountRedirect = $accountRedirect ?: ObjectManager::getInstance()->get(AccountRedirect::class);
188
    }
189
190
    /**
191
     * Implements Config Module.
192
     *
193
     * @param string $provider
194
     *
195
     * @return array
196
     */
197
    private function getProvidersConfig(string $provider): array
198
    {
199
        $config = [];
200
        $config[$provider] = [
201
            'enabled' => (bool) $this->scopeConfig->getValue(
202
                sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_ENABLED, $provider),
203
                ScopeInterface::SCOPE_STORE
204
            ),
205
            'keys' => [
206
                'key' => $this->scopeConfig->getValue(
207
                    sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_KEY, $provider),
208
                    ScopeInterface::SCOPE_STORE
209
                ),
210
                'secret' => $this->scopeConfig->getValue(
211
                    sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_SECRET, $provider),
212
                    ScopeInterface::SCOPE_STORE
213
                ),
214
            ],
215
        ];
216
217
        return $config;
218
    }
219
220
    /**
221
     * Generate Url Endpoint.
222
     *
223
     * @param string $provider
224
     *
225
     * @return string
226
     */
227
    private function getEndpoint(string $provider): string
228
    {
229
        $params = [
230
            '_secure'  => true,
231
            'provider' => $provider,
232
        ];
233
234
        return $this->url->getUrl('sociallogin/endpoint/index', $params);
235
    }
236
237
    /**
238
     * Gets customer data for a hybrid auth profile.
239
     *
240
     * @param SocialProfile $profile
241
     *
242
     * @return CustomerFactory
243
     */
244
    private function getCustomerData(SocialProfile $profile)
245
    {
246
        $customerData = [];
247
        foreach (['firstName', 'lastName', 'email'] as $field) {
248
            $data = $profile->{$field};
249
            $customerData[strtolower($field)] = $data !== null ? $data : '-';
250
        }
251
252
        $customer = $this->customerDataFactory->create();
253
        $customer->setEmail($customerData['email']);
254
        $customer->setFirstname($customerData['firstname']);
255
        $customer->setLastname($customerData['lastname']);
256
        $storeId = $this->storeManager->getStore()->getId();
257
        $customer->setStoreId($storeId);
258
        $websiteId = $this->storeManager->getStore($customer->getStoreId())->getWebsiteId();
259
        $customer->setWebsiteId($websiteId);
260
261
        return $customer;
262
    }
263
264
    /**
265
     * Set Customer.
266
     *
267
     * @param SocialProfile $socialProfile
268
     *
269
     * @return CustomerFactory
270
     */
271
    private function setCustomerData(SocialProfile $socialProfile)
272
    {
273
        $websiteId = $this->storeManager->getWebsite()->getId();
274
        $customer = $this->customerFactory->create();
275
        $customer->setWebsiteId($websiteId);
276
        if ($socialProfile->email) {
277
            $customer->loadByEmail($socialProfile->email);
278
            if (!$customer->getId()) {
279
                $customer = $this->getCustomerData($socialProfile);
280
                $customer = $this->createNewAccount($customer);
281
            }
282
        }
283
284
        return $customer;
285
    }
286
287
    /**
288
     * Create New Account.
289
     *
290
     * @param CustomerFactory $customer
291
     *
292
     * @return CustomerFactory
293
     */
294
    public function createNewAccount($customer)
295
    {
296
        try {
297
            $customer = $this->accountManagement
298
                ->createAccount($customer);
299
300
            $confirmationStatus = $this->accountManagement->getConfirmationStatus($customer->getId());
301
            if ($confirmationStatus === AccountManagementInterface::ACCOUNT_CONFIRMATION_REQUIRED) {
302
                $this->messageManager->addComplexSuccessMessage(
303
                    'checkoutConfirmAccountSuccessMessage',
304
                    [
305
                        'url' => $this->customerUrl->getEmailConfirmationUrl($customer->getEmail()),
306
                    ]
307
                );
308
            } else {
309
                $this->customerSession->setCustomerDataAsLoggedIn($customer);
310
            }
311
            if ($this->cookieManager->getCookie('mage-cache-sessid')) {
312
                $metadata = $this->cookieMetadataFactory->createCookieMetadata();
313
                $metadata->setPath('/');
314
                $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
315
            }
316
        } catch (\Exception $exc) {
317
            $this->messageManager->addError(__('Unable to create account.'));
318
            $this->messageManager->addError(__($exc->getMessage()));
319
        }
320
321
        return $customer;
322
    }
323
324
    /**
325
     * Login account.
326
     *
327
     * @param string $provider
328
     *
329
     * @throws LocalizedException
330
     *
331
     * @return void
332
     */
333
    public function login(string $provider): void
334
    {
335
        $hybridAuth = $this->hybridauthFactory->create([
336
            'config' => [
337
                'callback'  => $this->getEndpoint($provider),
338
                'providers' => $this->getProvidersConfig($provider),
339
            ],
340
        ]);
341
        $authenticate = $hybridAuth->authenticate($provider);
342
        if ($authenticate->isConnected()) {
343
            $socialProfile = $authenticate->getUserProfile();
344
            $customer = $this->setCustomerData($socialProfile);
345
            $this->customerSession->setCustomerDataAsLoggedIn($customer);
346
347
            if ($this->cookieManager->getCookie('mage-cache-sessid')) {
348
                $metadata = $this->cookieMetadataFactory->createCookieMetadata();
349
                $metadata->setPath('/');
350
                $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
351
            }
352
        }
353
    }
354
355
    /**
356
     * Set Autenticate And Referer.
357
     *
358
     * @param string      $provider
359
     * @param int|null    $isSecure
360
     * @param string|null $referer
361
     *
362
     * @return array
363
     */
364
    public function setAutenticateAndReferer(string $provider, int $isSecure = 1, string $referer = null): array
365
    {
366
        if ($referer) {
367
            $this->accountRedirect->setRedirectCookie($referer);
368
        }
369
370
        $redirect = $this->accountRedirect->getRedirectCookie();
371
372
        $response['redirectUrl'] = $redirect;
373
374
        $hybridAuth = $this->hybridauthFactory->create([
375
            'config' => [
376
                'callback'  => $this->getEndpoint($provider),
377
                'providers' => $this->getProvidersConfig($provider),
378
            ],
379
        ]);
380
381
        try {
382
            $authenticate = $hybridAuth->authenticate($provider);
383
        } catch (Exception $e) {
384
            $this->messageManager->addError(__('Unable to login, try another way.'));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

384
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__('Unable to login, try another way.'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
385
386
            return $response;
387
        }
388
389
        if ($authenticate->isConnected()) {
390
            $socialProfile = $authenticate->getUserProfile();
391
            $customer = $this->setCustomerData($socialProfile);
392
            if ($customer->getId()) {
393
                $this->customerSession->getCustomerFormData(true);
394
                $customerId = $this->customerSession->getCustomerId();
395
                $customerDataObject = $this->customerRepository->getById($customer->getId());
396
397
                $this->customerSession->setCustomerDataAsLoggedIn($customerDataObject);
398
399
                if ($this->cookieManager->getCookie('mage-cache-sessid')) {
400
                    $metadata = $this->cookieMetadataFactory->createCookieMetadata();
401
                    $metadata->setPath('/');
402
                    $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
403
                }
404
405
                return $response;
406
            }
407
408
            $this->messageManager->addError(__('Unable to login, try another way.'));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

408
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__('Unable to login, try another way.'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
409
410
            return $response;
411
        }
412
    }
413
}
414