芝麻web文件管理V1.00
编辑当前文件:/home2/sdektunc/.trash/plugins.2/system/webauthn/src/Helper/CredentialsCreation.php
* @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Webauthn\Helper; // Protect from unauthorized access \defined('_JEXEC') or die(); use CBOR\Decoder; use CBOR\OtherObject\OtherObjectManager; use CBOR\Tag\TagObjectManager; use Cose\Algorithm\Manager; use Cose\Algorithm\Signature\ECDSA; use Cose\Algorithm\Signature\EdDSA; use Cose\Algorithm\Signature\RSA; use Cose\Algorithms; use Exception; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Crypt\Crypt; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Uri\Uri; use Joomla\CMS\User\User; use Joomla\CMS\User\UserFactoryInterface; use Joomla\Plugin\System\Webauthn\CredentialRepository; use Laminas\Diactoros\ServerRequestFactory; use RuntimeException; use Webauthn\AttestationStatement\AndroidKeyAttestationStatementSupport; use Webauthn\AttestationStatement\AttestationObjectLoader; use Webauthn\AttestationStatement\AttestationStatementSupportManager; use Webauthn\AttestationStatement\FidoU2FAttestationStatementSupport; use Webauthn\AttestationStatement\NoneAttestationStatementSupport; use Webauthn\AttestationStatement\PackedAttestationStatementSupport; use Webauthn\AttestationStatement\TPMAttestationStatementSupport; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler; use Webauthn\AuthenticatorAttestationResponse; use Webauthn\AuthenticatorAttestationResponseValidator; use Webauthn\AuthenticatorSelectionCriteria; use Webauthn\PublicKeyCredentialCreationOptions; use Webauthn\PublicKeyCredentialDescriptor; use Webauthn\PublicKeyCredentialLoader; use Webauthn\PublicKeyCredentialParameters; use Webauthn\PublicKeyCredentialRpEntity; use Webauthn\PublicKeyCredentialSource; use Webauthn\PublicKeyCredentialUserEntity; use Webauthn\TokenBinding\TokenBindingNotSupportedHandler; /** * Helper class to aid in credentials creation (link an authenticator to a user account) * * @since 4.0.0 */ abstract class CredentialsCreation { /** * Create a public key for credentials creation. The result is a JSON string which can be used in Javascript code * with navigator.credentials.create(). * * @param User $user The Joomla user to create the public key for * * @return string * * @since 4.0.0 */ public static function createPublicKey(User $user): string { /** @var CMSApplication $app */ try { $app = Factory::getApplication(); $siteName = $app->getConfig()->get('sitename', 'Joomla! Site'); } catch (Exception $e) { $siteName = 'Joomla! Site'; } // Credentials repository $repository = new CredentialRepository; // Relaying Party -- Our site $rpEntity = new PublicKeyCredentialRpEntity( $siteName, Uri::getInstance()->toString(['host']), self::getSiteIcon() ); // User Entity $userEntity = new PublicKeyCredentialUserEntity( $user->username, $repository->getHandleFromUserId($user->id), $user->name ); // Challenge try { $challenge = random_bytes(32); } catch (Exception $e) { $challenge = Crypt::genRandomBytes(32); } // Public Key Credential Parameters $publicKeyCredentialParametersList = [ new PublicKeyCredentialParameters('public-key', Algorithms::COSE_ALGORITHM_ES256), ]; // Timeout: 60 seconds (given in milliseconds) $timeout = 60000; // Devices to exclude (already set up authenticators) $excludedPublicKeyDescriptors = []; $records = $repository->findAllForUserEntity($userEntity); /** @var PublicKeyCredentialSource $record */ foreach ($records as $record) { $excludedPublicKeyDescriptors[] = new PublicKeyCredentialDescriptor($record->getType(), $record->getCredentialPublicKey()); } // Authenticator Selection Criteria (we used default values) $authenticatorSelectionCriteria = new AuthenticatorSelectionCriteria; // Extensions (not yet supported by the library) $extensions = new AuthenticationExtensionsClientInputs; // Attestation preference $attestationPreference = PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE; // Public key credential creation options $publicKeyCredentialCreationOptions = new PublicKeyCredentialCreationOptions( $rpEntity, $userEntity, $challenge, $publicKeyCredentialParametersList, $timeout, $excludedPublicKeyDescriptors, $authenticatorSelectionCriteria, $attestationPreference, $extensions ); // Save data in the session Joomla::setSessionVar('publicKeyCredentialCreationOptions', base64_encode(serialize($publicKeyCredentialCreationOptions)), 'plg_system_webauthn' ); Joomla::setSessionVar('registration_user_id', $user->id, 'plg_system_webauthn'); return json_encode($publicKeyCredentialCreationOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } /** * Validate the authentication data returned by the device and return the public key credential source on success. * * An exception will be returned on error. Also, under very rare conditions, you may receive NULL instead of * a PublicKeyCredentialSource object which means that something was off in the returned data from the browser. * * @param string $data The JSON-encoded data returned by the browser during the authentication flow * * @return PublicKeyCredentialSource|null * * @since 4.0.0 */ public static function validateAuthenticationData(string $data): ?PublicKeyCredentialSource { // Retrieve the PublicKeyCredentialCreationOptions object created earlier and perform sanity checks $encodedOptions = Joomla::getSessionVar('publicKeyCredentialCreationOptions', null, 'plg_system_webauthn'); if (empty($encodedOptions)) { throw new RuntimeException(Text::_('PLG_SYSTEM_WEBAUTHN_ERR_CREATE_NO_PK')); } try { $publicKeyCredentialCreationOptions = unserialize(base64_decode($encodedOptions)); } catch (Exception $e) { $publicKeyCredentialCreationOptions = null; } if (!\is_object($publicKeyCredentialCreationOptions) || !($publicKeyCredentialCreationOptions instanceof PublicKeyCredentialCreationOptions)) { throw new RuntimeException(Text::_('PLG_SYSTEM_WEBAUTHN_ERR_CREATE_NO_PK')); } // Retrieve the stored user ID and make sure it's the same one in the request. $storedUserId = Joomla::getSessionVar('registration_user_id', 0, 'plg_system_webauthn'); try { $myUser = Factory::getApplication()->getIdentity(); } catch (Exception $e) { $dummyUserId = 0; $myUser = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($dummyUserId); } $myUserId = $myUser->id; if (($myUser->guest) || ($myUserId != $storedUserId)) { throw new RuntimeException(Text::_('PLG_SYSTEM_WEBAUTHN_ERR_CREATE_INVALID_USER')); } // Cose Algorithm Manager $coseAlgorithmManager = new Manager; $coseAlgorithmManager->add(new ECDSA\ES256); $coseAlgorithmManager->add(new ECDSA\ES512); $coseAlgorithmManager->add(new EdDSA\EdDSA); $coseAlgorithmManager->add(new RSA\RS1); $coseAlgorithmManager->add(new RSA\RS256); $coseAlgorithmManager->add(new RSA\RS512); // Create a CBOR Decoder object $otherObjectManager = new OtherObjectManager; $tagObjectManager = new TagObjectManager; $decoder = new Decoder($tagObjectManager, $otherObjectManager); // The token binding handler $tokenBindingHandler = new TokenBindingNotSupportedHandler; // Attestation Statement Support Manager $attestationStatementSupportManager = new AttestationStatementSupportManager; $attestationStatementSupportManager->add(new NoneAttestationStatementSupport); $attestationStatementSupportManager->add(new FidoU2FAttestationStatementSupport($decoder)); /** $attestationStatementSupportManager->add( new AndroidSafetyNetAttestationStatementSupport(HttpFactory::getHttp(), 'GOOGLE_SAFETYNET_API_KEY', new RequestFactory ) ); */ $attestationStatementSupportManager->add(new AndroidKeyAttestationStatementSupport($decoder)); $attestationStatementSupportManager->add(new TPMAttestationStatementSupport); $attestationStatementSupportManager->add(new PackedAttestationStatementSupport($decoder, $coseAlgorithmManager)); // Attestation Object Loader $attestationObjectLoader = new AttestationObjectLoader($attestationStatementSupportManager, $decoder); // Public Key Credential Loader $publicKeyCredentialLoader = new PublicKeyCredentialLoader($attestationObjectLoader, $decoder); // Credential Repository $credentialRepository = new CredentialRepository; // Extension output checker handler $extensionOutputCheckerHandler = new ExtensionOutputCheckerHandler; // Authenticator Attestation Response Validator $authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator( $attestationStatementSupportManager, $credentialRepository, $tokenBindingHandler, $extensionOutputCheckerHandler ); // Any Throwable from this point will bubble up to the GUI // We init the PSR-7 request object using Diactoros $request = ServerRequestFactory::fromGlobals(); // Load the data $publicKeyCredential = $publicKeyCredentialLoader->load(base64_decode($data)); $response = $publicKeyCredential->getResponse(); // Check if the response is an Authenticator Attestation Response if (!$response instanceof AuthenticatorAttestationResponse) { throw new RuntimeException('Not an authenticator attestation response'); } // Check the response against the request $authenticatorAttestationResponseValidator->check($response, $publicKeyCredentialCreationOptions, $request); /** * Everything is OK here. You can get the Public Key Credential Source. This object should be persisted using * the Public Key Credential Source repository. */ return PublicKeyCredentialSource::createFromPublicKeyCredential( $publicKeyCredential, $publicKeyCredentialCreationOptions->getUser()->getId() ); } /** * Try to find the site's favicon in the site's root, images, media, templates or current template directory. * * @return string|null * * @since 4.0.0 */ protected static function getSiteIcon(): ?string { $filenames = [ 'apple-touch-icon.png', 'apple_touch_icon.png', 'favicon.ico', 'favicon.png', 'favicon.gif', 'favicon.bmp', 'favicon.jpg', 'favicon.svg', ]; try { $paths = [ '/', '/images/', '/media/', '/templates/', '/templates/' . Factory::getApplication()->getTemplate(), ]; } catch (Exception $e) { return null; } foreach ($paths as $path) { foreach ($filenames as $filename) { $relFile = $path . $filename; $filePath = JPATH_BASE . $relFile; if (is_file($filePath)) { break 2; } $relFile = null; } } if (!isset($relFile) || \is_null($relFile)) { return null; } return rtrim(Uri::base(), '/') . '/' . ltrim($relFile, '/'); } }