Support filtering the list of user authentication failures (#4062)
authorMatthias Schmidt <gravatronics@live.com>
Wed, 10 Mar 2021 10:41:17 +0000 (11:41 +0100)
committerGitHub <noreply@github.com>
Wed, 10 Mar 2021 10:41:17 +0000 (11:41 +0100)
Filtering by IP address is not supported due storing IPv4 addresses in IPv6 format but displaying them in as IPv4 so that (partial) IPv4 addresses cannot be (easily) searched for.

See #3395

wcfsetup/install/files/acp/templates/userAuthenticationFailureList.tpl
wcfsetup/install/files/lib/acp/page/UserAuthenticationFailureListPage.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index cddec7e82e2fe64dae9af2e71d0a0411b66177fb..3b689cf4656832532b37ce797ac32348d70108c2 100644 (file)
        {/hascontent}
 </header>
 
+<form method="post" action="{link controller='UserAuthenticationFailureList'}{/link}">
+       <section class="section">
+               <h2 class="sectionTitle">{lang}wcf.global.filter{/lang}</h2>
+
+               <div class="row rowColGap formGrid">
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <select name="filter[environment]" id="environment">
+                                               <option value="">{lang}wcf.acp.user.authentication.failure.environment{/lang}</option>
+                                               <option value="admin"{if $filter[environment] === 'admin'} selected{/if}>{lang}wcf.acp.user.authentication.failure.environment.admin{/lang}</option>
+                                               <option value="user"{if $filter[environment] === 'user'} selected{/if}>{lang}wcf.acp.user.authentication.failure.environment.user{/lang}</option>
+                                       </select>
+                               </dd>
+                       </dl>
+
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <input type="text" id="username" name="filter[username]" value="{$filter[username]}" placeholder="{lang}wcf.user.username{/lang}" class="long">
+                               </dd>
+                       </dl>
+
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <select name="filter[validationError]" id="validationError">
+                                               <option value="">{lang}wcf.acp.user.authentication.failure.validationError{/lang}</option>
+                                               <option value="invalidPassword"{if $filter[validationError] === 'invalidPassword'} selected{/if}>{lang}wcf.acp.user.authentication.failure.validationError.invalidPassword{/lang}</option>
+                                               <option value="invalidUsername"{if $filter[validationError] === 'invalidUsername'} selected{/if}>{lang}wcf.acp.user.authentication.failure.validationError.invalidUsername{/lang}</option>
+                                               {event name='validationErrorFilterOptions'}
+                                       </select>
+                               </dd>
+                       </dl>
+
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <input type="date" id="startDate" name="filter[startDate]" value="{$filter[startDate]}" data-placeholder="{lang}wcf.acp.user.authentication.failure.time.start{/lang}">
+                               </dd>
+                       </dl>
+
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <input type="date" id="endDate" name="filter[endDate]" value="{$filter[endDate]}" data-placeholder="{lang}wcf.acp.user.authentication.failure.time.end{/lang}">
+                               </dd>
+                       </dl>
+
+                       <dl class="col-xs-12 col-md-4">
+                               <dt></dt>
+                               <dd>
+                                       <input type="text" id="userAgent" name="filter[userAgent]" value="{$filter[userAgent]}" placeholder="{lang}wcf.user.userAgent{/lang}" class="long">
+                               </dd>
+                       </dl>
+
+                       {event name='filterFields'}
+               </div>
+
+               <div class="formSubmit">
+                       <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
+                       {csrfToken}
+               </div>
+       </section>
+</form>
+
 {hascontent}
        <div class="paginationTop">
-               {content}{pages print=true assign=pagesLinks controller='UserAuthenticationFailureList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}{/content}
+               {content}
+                       {pages print=true assign=pagesLinks controller='UserAuthenticationFailureList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$filterLinkParameters"}
+               {/content}
        </div>
 {/hascontent}
 
index 49471377614a9dcd4a24902305d14e7c79dde230..ed0667925118dbd803becaf5b56824433f8aa009 100644 (file)
@@ -4,6 +4,7 @@ namespace wcf\acp\page;
 
 use wcf\data\user\authentication\failure\UserAuthenticationFailureList;
 use wcf\page\SortablePage;
+use wcf\system\WCF;
 
 /**
  * Shows a list of user authentication failures.
@@ -51,4 +52,99 @@ class UserAuthenticationFailureListPage extends SortablePage
      * @inheritDoc
      */
     public $objectListClassName = UserAuthenticationFailureList::class;
+
+    /**
+     * @var string[]
+     * @since   5.4
+     */
+    public $filter = [
+        'environment' => '',
+        'endDate' => '',
+        'startDate' => '',
+        'username' => '',
+        'userAgent' => '',
+        'validationError' => '',
+    ];
+
+    /**
+     * @inheritDoc
+     */
+    public function readParameters()
+    {
+        parent::readParameters();
+
+        if (isset($_REQUEST['filter']) && \is_array($_REQUEST['filter'])) {
+            foreach ($_REQUEST['filter'] as $key => $value) {
+                if (\array_key_exists($key, $this->filter)) {
+                    $this->filter[$key] = $value;
+                }
+            }
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    protected function initObjectList()
+    {
+        parent::initObjectList();
+
+        if ($this->filter['environment'] !== '') {
+            $this->objectList->getConditionBuilder()->add(
+                'user_authentication_failure.environment = ?',
+                [$this->filter['environment']]
+            );
+        }
+        if ($this->filter['endDate'] !== '') {
+            $endDate = @\strtotime($this->filter['endDate']);
+            if ($endDate > 0) {
+                $this->objectList->getConditionBuilder()->add(
+                    'user_authentication_failure.time <= ?',
+                    [$endDate]
+                );
+            }
+        }
+        if ($this->filter['startDate'] !== '') {
+            $startDate = @\strtotime($this->filter['startDate']);
+            if ($startDate > 0) {
+                $this->objectList->getConditionBuilder()->add(
+                    'user_authentication_failure.time >= ?',
+                    [$startDate]
+                );
+            }
+        }
+        if ($this->filter['username'] !== '') {
+            $this->objectList->getConditionBuilder()->add(
+                'user_authentication_failure.username LIKE ?',
+                ['%' . \addcslashes($this->filter['username'], '_%') . '%']
+            );
+        }
+        if ($this->filter['userAgent'] !== '') {
+            $this->objectList->getConditionBuilder()->add(
+                'user_authentication_failure.userAgent LIKE ?',
+                ['%' . \addcslashes($this->filter['userAgent'], '_%') . '%']
+            );
+        }
+        if ($this->filter['validationError'] !== '') {
+            $this->objectList->getConditionBuilder()->add(
+                'user_authentication_failure.validationError = ?',
+                [$this->filter['validationError']]
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function assignVariables()
+    {
+        parent::assignVariables();
+
+        $filterLinkParameters = \http_build_query(['filter' => \array_filter($this->filter)], '', '&');
+
+        WCF::getTPL()->assign([
+            'filter' => $this->filter,
+            'filterLinkParameters' => $filterLinkParameters ? '&' . $filterLinkParameters : '',
+        ]);
+    }
 }
index 1451e1c815bcb2e649d2eee9c064d3075b27be16..b5f3de49cecd163f4675b1a8fb7ca7529ceb38e1 100644 (file)
@@ -3238,6 +3238,8 @@ aus Sicherheitsgründen erforderlich, dass {if LANGUAGE_USE_INFORMAL_VARIANT}du{
                <item name="wcf.acp.user.authentication.failure.environment.user"><![CDATA[Benutzer]]></item>
                <item name="wcf.acp.user.authentication.failure.environment.admin"><![CDATA[Administration]]></item>
                <item name="wcf.acp.user.authentication.failure.time"><![CDATA[Datum]]></item>
+               <item name="wcf.acp.user.authentication.failure.time.start"><![CDATA[Datum von]]></item>
+               <item name="wcf.acp.user.authentication.failure.time.end"><![CDATA[Datum bis]]></item>
                <item name="wcf.acp.user.authentication.failure.password"><![CDATA[Ungültiges Kennwort]]></item>
                <item name="wcf.acp.user.authentication.failure.username"><![CDATA[Unbekannter Benutzername]]></item>
                <item name="wcf.acp.user.authentication.failure.validationError"><![CDATA[Fehler]]></item>
index fbf131379d322710fa99f18208e7abd3c5447fec..f7d2f1e8ab39de16d43490c5079d40789638760e 100644 (file)
@@ -3162,6 +3162,8 @@ the lost password form <a href="{link controller='LostPassword' isHtmlEmail=true
                <item name="wcf.acp.user.authentication.failure.environment.user"><![CDATA[User]]></item>
                <item name="wcf.acp.user.authentication.failure.environment.admin"><![CDATA[Administration]]></item>
                <item name="wcf.acp.user.authentication.failure.time"><![CDATA[Date]]></item>
+               <item name="wcf.acp.user.authentication.failure.time.start"><![CDATA[Date from]]></item>
+               <item name="wcf.acp.user.authentication.failure.time.end"><![CDATA[Date to]]></item>
                <item name="wcf.acp.user.authentication.failure.password"><![CDATA[Invalid Password]]></item>
                <item name="wcf.acp.user.authentication.failure.username"><![CDATA[Unknown Username]]></item>
                <item name="wcf.acp.user.authentication.failure.validationError"><![CDATA[Error]]></item>