PluginProbe
Easy Basic Authentication – Add basic auth to site or admin area / 4.2.0
Easy Basic Authentication – Add basic auth to site or admin area v4.2.0
4.2.0 4.1.0 trunk 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.7 1.7.1 1.8 All 52 releases
← All changes | class/easy-basic-authentication-class.php +103 -0 4.1.0 → 4.2.0 View file →
@@ -81,8 +81,16 @@
81 81 if ( self::is_cli() ) {
82 82 return;
83 83 }
84 84
85 + // wp-cron.php chiude la risposta con fastcgi_finish_request() prima ancora di
86 + // caricare WordPress: quando arriviamo qui gli header sono gia partiti. La sfida
87 + // 401 non raggiunge nessuno, lascia un warning "headers already sent" nel log a
88 + // ogni giro, e l'exit che la segue ferma tutte le azioni pianificate del sito.
89 + if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
90 + return;
91 + }
92 +
85 93 $user = get_option('basic_auth_plugin_username');
86 94 $pass = get_option('basic_auth_plugin_password');
87 95
88 96 if ($this->whiteListChecker()) {
@@ -92,8 +100,12 @@
92 100 if ($this->urlWhiteListChecker()) {
93 101 return;
94 102 }
95 103
104 + if ($this->tokenChecker()) {
105 + return;
106 + }
107 +
96 108 // Alcuni server (nginx + FastCGI su tutti) non popolano PHP_AUTH_USER da soli:
97 109 // le credenziali arrivano solo nell'header Authorization e vanno estratte a mano.
98 110 if (!isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
99 111 $authorization = sanitize_text_field( wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ) );
@@ -233,8 +245,99 @@
233 245 $ipLong = ip2long($ip);
234 246 $startLong = ip2long($start);
235 247 $endLong = ip2long($end);
236 248 return ($ipLong >= $startLong && $ipLong <= $endLong);
249 + }
250 +
251 + /**
252 + * Un crawler o un servizio esterno sta passando col token d'accesso?
253 + *
254 + * Serve a far entrare chi non puo usare l'autenticazione HTTP: un crawler, un
255 + * controllo di raggiungibilita, un front-end headless. Il token vale solo per
256 + * il sito: l'amministrazione e la pagina di accesso restano protette, perche
257 + * un crawler non ha motivo di entrarci e aprirgliele sarebbe rischio gratuito.
258 + *
259 + * @return bool
260 + */
261 + public function tokenChecker() {
262 + $token = (string) get_option('basic_auth_plugin_access_token', '');
263 +
264 + // Funzione spenta finche non si genera un token.
265 + if ('' === $token) {
266 + return false;
267 + }
268 +
269 + // Mai per l'amministrazione o la pagina di accesso.
270 + if (is_admin() || $this->isLoginRequest()) {
271 + return false;
272 + }
273 +
274 + $sent = $this->getRequestToken();
275 +
276 + if ('' === $sent) {
277 + return false;
278 + }
279 +
280 + // hash_equals: il confronto non deve rivelare quanti caratteri erano giusti.
281 + if (!hash_equals($token, $sent)) {
282 + // Un token sbagliato e un tentativo deliberato, non il primo giro a vuoto
283 + // del protocollo: va segnalato come una password sbagliata.
284 + $this->basic_auth_action_failed_access();
285 +
286 + return false;
287 + }
288 +
289 + /**
290 + * Scatta quando una richiesta entra col token invece che con le credenziali.
291 + */
292 + do_action('basic_auth_token_access_granted');
293 +
294 + return true;
295 + }
296 +
297 + /**
298 + * Il token inviato con la richiesta, da uno dei due header accettati.
299 + *
300 + * @return string
301 + */
302 + private function getRequestToken() {
303 + // Header dedicato: la strada piu pulita.
304 + if (!empty($_SERVER['HTTP_X_BASIC_AUTH_TOKEN'])) {
305 + return trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_BASIC_AUTH_TOKEN'])));
306 + }
307 +
308 + // Authorization: Bearer, per i servizi che sanno mandare solo questo.
309 + if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
310 + $header = sanitize_text_field(wp_unslash($_SERVER['HTTP_AUTHORIZATION']));
311 +
312 + if (preg_match('#^Bearer\s+(\S+)$#i', $header, $matches)) {
313 + return $matches[1];
314 + }
315 + }
316 +
317 + return '';
318 + }
319 +
320 + /**
321 + * Se la richiesta corrente e la pagina di accesso.
322 + *
323 + * @return bool
324 + */
325 + private function isLoginRequest() {
326 + $pagenow = isset($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
327 +
328 + if (in_array($pagenow, array('wp-login.php', 'wp-register.php'), true)) {
329 + return true;
330 + }
331 +
332 + if (empty($_SERVER['REQUEST_URI'])) {
333 + return false;
334 + }
335 +
336 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- solo confronto, mai stampato.
337 + $uri = wp_unslash($_SERVER['REQUEST_URI']);
338 +
339 + return false !== stripos($uri, 'wp-login.php') || false !== stripos($uri, 'wp-register.php');
237 340 }
238 341
239 342 /**
240 343 * Manda la sfida 401.