PluginProbe ʕ •ᴥ•ʔ
Advanced Access Manager – Access Governance for WordPress / trunk
Advanced Access Manager – Access Governance for WordPress vtrunk
6.8.4 6.8.5 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17 6.9.18 6.9.19 6.9.2 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 6.9.25 6.9.26 6.9.27 6.9.28 6.9.29 6.9.3 6.9.30 6.9.31 6.9.32 6.9.33 6.9.34 6.9.35 6.9.36 6.9.37 6.9.38 6.9.39 6.9.4 6.9.41 6.9.42 6.9.43 6.9.44 6.9.45 6.9.46 6.9.47 6.9.48 6.9.49 6.9.5 6.9.51 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.0-alpha.6 7.0.0-alpha.7 7.0.0-beta.1 7.0.0-rc1 7.0.0-rc2 7.0.0-rc3 7.0.1 7.0.10 7.0.11 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7 7.0.8 7.0.9 7.1.0 7.1.1 trunk 3.0 4.0 4.0.1 4.1 4.2 4.3 4.4 4.4.1 4.5 4.6 4.6.1 4.6.2 4.7 4.7.1 4.7.2 4.7.5 4.7.6 4.8 4.8.1 4.9 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.5.1 4.9.5.2 5.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1 5.1.1 5.10 5.11 5.2 5.2.1 5.2.5 5.2.6 5.2.7 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.4 5.4.1 5.4.2 5.4.3 5.4.3.1 5.4.3.2 5.5 5.5.1 5.5.2 5.6 5.6.1 5.6.1.1 5.7 5.7.1 5.7.2 5.7.3 5.8 5.8.1 5.8.2 5.8.3 5.9 5.9.1 5.9.1.1 5.9.2 5.9.2.1 5.9.3 5.9.4 5.9.5 5.9.6 5.9.6.1 5.9.6.2 5.9.6.3 5.9.7 5.9.7.1 5.9.7.2 5.9.7.3 5.9.8 5.9.8.1 5.9.9 5.9.9.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.2.0 6.2.1 6.2.2 6.3.0 6.3.1 6.3.2 6.3.3 6.4.0 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.6.0 6.6.1 6.6.2 6.6.3 6.6.4 6.7.0 6.7.1 6.7.2 6.7.3 6.7.4 6.7.5 6.7.6 6.7.7 6.7.8 6.7.9 6.8.0 6.8.1 6.8.2 6.8.3
advanced-access-manager / application / Service / SecureLogin.php
advanced-access-manager / application / Service Last commit date
Shortcode 4 months ago AccessDeniedRedirect.php 1 year ago AdminToolbar.php 1 year ago ApiRoute.php 1 year ago BackendMenu.php 1 year ago BaseTrait.php 1 year ago Capability.php 1 year ago Content.php 4 months ago Core.php 8 months ago Hooks.php 1 year ago Identity.php 1 month ago Jwt.php 1 month ago LoginRedirect.php 1 year ago LogoutRedirect.php 1 month ago Metaboxes.php 1 year ago NotFoundRedirect.php 1 year ago Policies.php 1 year ago SecureLogin.php 1 year ago SecurityAudit.php 1 year ago Shortcodes.php 4 months ago Urls.php 1 year ago Welcome.php 1 year ago Widgets.php 1 year ago
SecureLogin.php
240 lines
1 <?php
2
3 /**
4 * ======================================================================
5 * LICENSE: This file is subject to the terms and conditions defined in *
6 * file 'license.txt', which is part of this source code package. *
7 * ======================================================================
8 */
9
10 use Vectorface\Whip\Whip;
11
12 /**
13 * Secure Login service
14 *
15 * @package AAM
16 * @version 7.0.0
17 */
18 class AAM_Service_SecureLogin
19 {
20 use AAM_Service_BaseTrait;
21
22 /**
23 * Default configurations
24 *
25 * @version 7.0.0
26 */
27 const DEFAULT_CONFIG = [
28 'service.secure_login.single_session' => false,
29 'service.secure_login.brute_force_lockout' => false,
30 'service.secure_login.time_window' => '+20 minutes',
31 'service.secure_login.login_attempts' => 5,
32 'service.secure_login.login_message' => 'Login to get access.'
33 ];
34
35 /**
36 * Constructor
37 *
38 * @return void
39 * @access protected
40 *
41 * @version 7.0.6
42 */
43 protected function __construct()
44 {
45 add_filter('aam_get_config_filter', function($result, $key) {
46 if (empty($result) && array_key_exists($key, self::DEFAULT_CONFIG)) {
47 $result = self::DEFAULT_CONFIG[$key];
48 }
49
50 return $result;
51 }, 10, 2);
52
53 // Register custom RESTful API endpoint for login
54 AAM_Restful_SecureLogin::bootstrap();
55
56 // Register custom frontend Login widget
57 add_action('widgets_init', function () {
58 register_widget('AAM_Backend_Widget_Login');
59 });
60
61 add_action('init', function() {
62 $this->initialize_hooks();
63 }, PHP_INT_MAX);
64 }
65
66 /**
67 * Initialize core hooks
68 *
69 * @return void
70 * @access protected
71 *
72 * @version 7.0.6
73 */
74 protected function initialize_hooks()
75 {
76 if (is_admin()) {
77 // Register additional tab for the Settings
78 add_action('aam_initialize_ui_action', function () {
79 AAM_Backend_Feature_Settings_Security::register();
80 });
81 }
82
83 // Redefine the wp-login.php header message
84 add_filter('login_message', function($message) {
85 return $this->_login_message($message);
86 });
87
88 // Security controls
89 add_filter('authenticate', function($response) {
90 return $this->_authenticate($response);
91 }, PHP_INT_MAX);
92
93 add_filter('auth_cookie', function($cookie, $user_id, $_, $__, $token) {
94 return $this->_auth_cookie($cookie, $user_id, $token);
95 }, 10, 5);
96
97 add_action('wp_login_failed', function() {
98 $this->_wp_login_failed();
99 });
100 }
101
102 /**
103 * Intercept auth token generation and enhance security
104 *
105 * If "One Session Per User" option is enabled, make sure that all other sessions
106 * are removed
107 *
108 * @param string $cookie Authentication cookie.
109 * @param int $user_id User ID.
110 * @param string $token User's session token used.
111 *
112 * @return string
113 * @access private
114 *
115 * @version 7.0.0
116 */
117 private function _auth_cookie($cookie, $user_id, $token)
118 {
119 $configs = AAM::api()->config;
120
121 // Remove all other sessions if single session feature is enabled
122 if ($configs->get('service.secure_login.single_session')) {
123 $sessions = WP_Session_Tokens::get_instance($user_id);
124
125 if (count($sessions->get_all()) > 1) {
126 $sessions->destroy_others($token);
127 }
128 }
129
130 return $cookie;
131 }
132
133 /**
134 * Track failed login attempts
135 *
136 * This method is used to enable brute force protection
137 *
138 * @return void
139 * @access private
140 *
141 * @version 7.0.0
142 */
143 private function _wp_login_failed()
144 {
145 $configs = AAM::api()->config;
146 $enabled = $configs->get('service.secure_login.brute_force_lockout');
147
148 // Track failed attempts only if Brute Force Lockout is enabled
149 if ($enabled) {
150 $name = $this->_get_login_attempt_key();
151 $attempts = AAM::api()->cache->get($name);
152
153 if (!empty($attempts)) {
154 $attempts = intval($attempts) + 1;
155
156 AAM::api()->cache->update($name, $attempts);
157 } else {
158 $timeout = strtotime($configs->get(
159 'service.secure_login.time_window'
160 ));
161
162 AAM::api()->cache->set($name, 1, $timeout - time());
163 }
164 }
165 }
166
167 /**
168 * Pre-authentication hook
169 *
170 * Enhance authentication security with Brute Force protection or login delay
171 *
172 * @param mixed $response
173 *
174 * @return mixed
175 * @access private
176 * @see wp_authenticate
177 *
178 * @version 7.0.0
179 */
180 private function _authenticate($response)
181 {
182 $configs = AAM::api()->config;
183
184 // Brute Force Lockout
185 if ($configs->get('service.secure_login.brute_force_lockout')) {
186 $threshold = $configs->get('service.secure_login.login_attempts');
187 $attempts = AAM::api()->cache->get($this->_get_login_attempt_key());
188
189 if ($attempts >= $threshold) {
190 $response = new WP_Error(
191 405,
192 __('Exceeded maximum number for login attempts.', 'advanced-access-manager')
193 );
194 }
195 }
196
197 return $response;
198 }
199
200 /**
201 * Customize login message
202 *
203 * @param string $message
204 *
205 * @return string
206 * @access private
207 *
208 * @version 7.0.0
209 */
210 private function _login_message($message)
211 {
212 $reason = AAM::api()->misc->get($_GET, 'reason');
213
214 if (empty($message) && ($reason === 'restricted')) {
215 $str = AAM::api()->config->get(
216 'service.secure_login.login_message'
217 );
218
219 $message = '<p class="message">' . esc_js($str) . '</p>';
220 }
221
222 return $message;
223 }
224
225 /**
226 * Get login attempts counter key name
227 *
228 * @return string
229 * @access private
230 *
231 * @version 7.0.0
232 */
233 private function _get_login_attempt_key()
234 {
235 $whip = new Whip();
236
237 return 'failed_login_attempts_' . $whip->getValidIpAddress();
238 }
239
240 }