[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Plugin 5 * @subpackage System.Webauthn 6 * 7 * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Plugin\System\Webauthn\PluginTraits; 12 13 use Exception; 14 use Joomla\CMS\Factory; 15 use Joomla\CMS\Form\Form; 16 use Joomla\CMS\HTML\HTMLHelper; 17 use Joomla\CMS\Language\Text; 18 use Joomla\CMS\Log\Log; 19 use Joomla\CMS\Uri\Uri; 20 use Joomla\CMS\User\User; 21 use Joomla\CMS\User\UserFactoryInterface; 22 use Joomla\Event\Event; 23 use Joomla\Plugin\System\Webauthn\Extension\Webauthn; 24 use Joomla\Registry\Registry; 25 26 // phpcs:disable PSR1.Files.SideEffects 27 \defined('_JEXEC') or die; 28 // phpcs:enable PSR1.Files.SideEffects 29 30 /** 31 * Add extra fields in the User Profile page. 32 * 33 * This class only injects the custom form fields. The actual interface is rendered through 34 * JFormFieldWebauthn. 35 * 36 * @see JFormFieldWebauthn::getInput() 37 * 38 * @since 4.0.0 39 */ 40 trait UserProfileFields 41 { 42 /** 43 * User object derived from the displayed user profile data. 44 * 45 * This is required to display the number and names of authenticators already registered when 46 * the user displays the profile view page. 47 * 48 * @var User|null 49 * @since 4.0.0 50 */ 51 private static $userFromFormData = null; 52 53 /** 54 * HTMLHelper method to render the WebAuthn user profile field in the profile view page. 55 * 56 * Instead of showing a nonsensical "Website default" label next to the field, this method 57 * displays the number and names of authenticators already registered by the user. 58 * 59 * This static method is set up for use in the onContentPrepareData method of this plugin. 60 * 61 * @param mixed $value Ignored. The WebAuthn profile field is virtual, it doesn't have a 62 * stored value. We only use it as a proxy to render a sub-form. 63 * 64 * @return string 65 * @since 4.0.0 66 */ 67 public static function renderWebauthnProfileField($value): string 68 { 69 if (\is_null(self::$userFromFormData)) { 70 return ''; 71 } 72 73 /** @var Webauthn $plugin */ 74 $plugin = Factory::getApplication()->bootPlugin('webauthn', 'system'); 75 $credentialRepository = $plugin->getAuthenticationHelper()->getCredentialsRepository(); 76 $credentials = $credentialRepository->getAll(self::$userFromFormData->id); 77 $authenticators = array_map( 78 function (array $credential) { 79 return $credential['label']; 80 }, 81 $credentials 82 ); 83 84 return Text::plural('PLG_SYSTEM_WEBAUTHN_FIELD_N_AUTHENTICATORS_REGISTERED', \count($authenticators), implode(', ', $authenticators)); 85 } 86 87 /** 88 * Adds additional fields to the user editing form 89 * 90 * @param Event $event The event we are handling 91 * 92 * @return void 93 * 94 * @throws Exception 95 * @since 4.0.0 96 */ 97 public function onContentPrepareForm(Event $event) 98 { 99 /** 100 * @var Form $form The form to be altered. 101 * @var mixed $data The associated data for the form. 102 */ 103 [$form, $data] = $event->getArguments(); 104 105 // This feature only applies to HTTPS sites. 106 if (!Uri::getInstance()->isSsl()) { 107 return; 108 } 109 110 $name = $form->getName(); 111 112 $allowedForms = [ 113 'com_admin.profile', 'com_users.user', 'com_users.profile', 'com_users.registration', 114 ]; 115 116 if (!\in_array($name, $allowedForms)) { 117 return; 118 } 119 120 // Get the user object 121 $user = $this->getUserFromData($data); 122 123 // Make sure the loaded user is the correct one 124 if (\is_null($user)) { 125 return; 126 } 127 128 // Make sure I am either editing myself OR I am a Super User 129 if (!$this->canEditUser($user)) { 130 return; 131 } 132 133 // Add the fields to the form. 134 if ($name !== 'com_users.registration') { 135 Log::add('Injecting WebAuthn Passwordless Login fields in user profile edit page', Log::DEBUG, 'webauthn.system'); 136 137 Form::addFormPath(JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name . '/forms'); 138 $form->loadFile('webauthn', false); 139 } 140 } 141 142 /** 143 * @param Event $event The event we are handling 144 * 145 * @return void 146 * 147 * @throws Exception 148 * @since 4.0.0 149 */ 150 public function onContentPrepareData(Event $event): void 151 { 152 /** 153 * @var string|null $context The context for the data 154 * @var array|object|null $data An object or array containing the data for the form. 155 */ 156 [$context, $data] = $event->getArguments(); 157 158 if (!\in_array($context, ['com_users.profile', 'com_users.user'])) { 159 return; 160 } 161 162 self::$userFromFormData = $this->getUserFromData($data); 163 164 if (!HTMLHelper::isRegistered('users.webauthnWebauthn')) { 165 HTMLHelper::register('users.webauthn', [__CLASS__, 'renderWebauthnProfileField']); 166 } 167 } 168 169 /** 170 * Get the user object based on the ID found in the provided user form data 171 * 172 * @param array|object|null $data The user form data 173 * 174 * @return User|null A user object or null if no match is found 175 * 176 * @throws Exception 177 * @since 4.0.0 178 */ 179 private function getUserFromData($data): ?User 180 { 181 $id = null; 182 183 if (\is_array($data)) { 184 $id = $data['id'] ?? null; 185 } elseif (\is_object($data) && ($data instanceof Registry)) { 186 $id = $data->get('id'); 187 } elseif (\is_object($data)) { 188 $id = $data->id ?? null; 189 } 190 191 $user = empty($id) ? Factory::getApplication()->getIdentity() : Factory::getContainer() 192 ->get(UserFactoryInterface::class) 193 ->loadUserById($id); 194 195 // Make sure the loaded user is the correct one 196 if ($user->id != $id) { 197 return null; 198 } 199 200 return $user; 201 } 202 203 /** 204 * Is the current user allowed to edit the WebAuthn configuration of $user? 205 * 206 * To do so I must either be editing my own account OR I have to be a Super User. 207 * 208 * @param ?User $user The user you want to know if we're allowed to edit 209 * 210 * @return boolean 211 * 212 * @since 4.2.0 213 */ 214 private function canEditUser(?User $user = null): bool 215 { 216 // I can edit myself, but Guests can't have passwordless logins associated 217 if (empty($user) || $user->guest) { 218 return true; 219 } 220 221 // Get the currently logged in used 222 $myUser = $this->getApplication()->getIdentity() ?? new User(); 223 224 // I can edit myself. If I'm a Super user I can edit other users too. 225 return ($myUser->id == $user->id) || $myUser->authorise('core.admin'); 226 } 227 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |