userConfigManager = $userConfigManager; $this->storeManager = $storeManager; $this->scopeConfig = $scopeConfig; } /** * Converts array to object * @param array $hash * @return \stdClass */ private function hashToObject(array $hash) { // @codingStandardsIgnoreStart $object = new \stdClass(); // @codingStandardsIgnoreEnd foreach ($hash as $key => $value) { $object->$key = $value; } return $object; } /** * Return true on token validation * @param UserInterface $user * @param DataObject $request * @return true * @throws LocalizedException * @throws \u2flib_server\Error */ public function verify(UserInterface $user, DataObject $request) { $u2f = $this->getU2f(); $registration = $this->getRegistration($user); if ($registration === null) { throw new LocalizedException(__('Missing registration data')); } $requests = [$this->hashToObject($request->getData('request')[0])]; $registrations = [$this->hashToObject($registration)]; $response = $this->hashToObject($request->getData('response')); // it triggers an error in case of auth failure $u2f->doAuthenticate($requests, $registrations, $response); return true; } /** * Create the registration challenge * @return array * @throws LocalizedException * @throws \u2flib_server\Error */ public function getRegisterData() { $u2f = $this->getU2f(); return $u2f->getRegisterData(); } /** * Get authenticate data * @param UserInterface $user * @return array * @throws LocalizedException * @throws \u2flib_server\Error */ public function getAuthenticateData(UserInterface $user) { $u2f = $this->getU2f(); $registration = $this->getRegistration($user); if ($registration === null) { throw new LocalizedException(__('Missing registration data')); } return $u2f->getAuthenticateData([$this->hashToObject($registration)]); } /** * Get registration information * @param UserInterface $user * @return array * @throws \Magento\Framework\Exception\NoSuchEntityException */ private function getRegistration(UserInterface $user) { $providerConfig = $this->userConfigManager->getProviderConfig($user->getId(), static::CODE); if (!isset($providerConfig['registration'])) { return null; } return $providerConfig['registration']; } /** * Register a new key * @param UserInterface $user * @param array $request * @param array $response * @return \u2flib_server\Registration * @throws LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException * @throws \u2flib_server\Error */ public function registerDevice(UserInterface $user, array $request, array $response) { // Must convert to object $request = $this->hashToObject($request); $response = $this->hashToObject($response); $u2f = $this->getU2f(); $res = $u2f->doRegister($request, $response); $this->userConfigManager->addProviderConfig($user->getId(), static::CODE, [ 'registration' => [ 'certificate' => $res->certificate, 'keyHandle' => $res->keyHandle, 'publicKey' => $res->publicKey, 'counter' => $res->counter, ] ]); $this->userConfigManager->activateProviderConfiguration($user->getId(), static::CODE); return $res; } /** * Return true if this provider has been enabled by admin * @return boolean */ public function isEnabled() { return !!$this->scopeConfig->getValue(static::XML_PATH_ENABLED); } /** * Return true if this provider allows trusted devices * @return boolean */ public function isTrustedDevicesAllowed() { return !!$this->scopeConfig->getValue(static::XML_PATH_ALLOW_TRUSTED_DEVICES); } /** * @return U2F * @throws LocalizedException * @throws \u2flib_server\Error */ private function getU2f() { /** @var Store $store */ $store = $this->storeManager->getStore(Store::ADMIN_CODE); $baseUrl = $store->getBaseUrl(); if (preg_match('/^(https?:\/\/.+?)\//', $baseUrl, $matches)) { $domain = $matches[1]; } else { throw new LocalizedException(__('Unexpected error while parsing domain name')); } /** @var U2F $u2f */ // @codingStandardsIgnoreStart return new U2F($domain); // @codingStandardsIgnoreEnd } }