PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.3.17
CloudSecure WP Security v1.3.17
1.4.10 1.4.9 trunk 0.9.0 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.22 1.3.23 1.3.24 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8
cloudsecure-wp-security / modules / two-factor-authentication.php
cloudsecure-wp-security / modules Last commit date
admin 1 year ago lib 11 months ago captcha.php 2 years ago cloudsecure-wp.php 11 months ago common.php 1 year ago config.php 2 years ago disable-access-system-file.php 1 year ago disable-author-query.php 2 years ago disable-login.php 1 year ago disable-restapi.php 1 year ago disable-xmlrpc.php 1 year ago htaccess.php 1 year ago login-log.php 1 year ago login-notification.php 1 year ago rename-login-page.php 1 year ago restrict-admin-page.php 1 year ago server-error-notification.php 1 year ago two-factor-authentication.php 11 months ago unify-messages.php 2 years ago update-notice.php 2 years ago waf-engine.php 1 year ago waf.php 1 year ago
two-factor-authentication.php
330 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class CloudSecureWP_Two_Factor_Authentication extends CloudSecureWP_Common {
8 private const KEY_FEATURE = 'two_factor_authentication';
9
10 private $config;
11
12 /**
13 * @var CloudSecureWP_Disable_Login
14 */
15 private $disable_login;
16
17 /**
18 * �
19 �の認証�
20 報を保存(Base64デコード済み)
21 */
22 private $original_credentials = array();
23
24 function __construct( array $info, CloudSecureWP_Config $config, CloudSecureWP_Disable_Login $disable_login ) {
25 parent::__construct( $info );
26 $this->config = $config;
27 $this->disable_login = $disable_login;
28 }
29
30 /**
31 * 機能毎のKEY取得
32 *
33 * @return string
34 */
35 public function get_feature_key(): string {
36 return self::KEY_FEATURE;
37 }
38
39 /**
40 * 有効無効判定
41 *
42 * @return bool
43 */
44 public function is_enabled(): bool {
45 return $this->config->get( $this->get_feature_key() ) === 't';
46 }
47
48 /**
49 * 初期設定値取得
50 *
51 * @return array
52 */
53 public function get_default(): array {
54 return array( self::KEY_FEATURE => 'f' );
55 }
56
57 /**
58 * 設定値key取得
59 */
60 public function get_keys(): array {
61 return array( self::KEY_FEATURE );
62 }
63
64 /**
65 * 設定値取得
66 */
67 public function get_settings(): array {
68 $settings = array();
69 $keys = $this->get_keys();
70
71 foreach ( $keys as $key ) {
72 $settings[ $key ] = $this->config->get( $key );
73 }
74
75 return $settings;
76 }
77
78 /**
79 * 設定値保存
80 *
81 * @param array $settings
82 *
83 * @return void
84 */
85 public function save_settings( array $settings ): void {
86 $keys = $this->get_keys();
87
88 foreach ( $keys as $key ) {
89 $this->config->set( $key, $settings[ $key ] ?? '' );
90 }
91 $this->config->save();
92 }
93
94 /**
95 * 有効化
96 *
97 * @return void
98 */
99 public function activate(): void {
100 $settings = $this->get_default();
101 $this->save_settings( $settings );
102 }
103
104 /**
105 * 無効化
106 *
107 * @return void
108 */
109 public function deactivate(): void {
110 $settings = $this->get_settings();
111 $settings[ self::KEY_FEATURE ] = 'f';
112 $this->save_settings( $settings );
113 }
114
115 /**
116 * 管理画面上での有効無効判定
117 * 2段階認証の管理画面で「変更を保存」ボタンを押下時、
118 * is_enabled()のみを使うとデバイス登録のメニューが正しく表示されない。
119 *
120 * @return bool
121 */
122 public function is_enabled_on_screen(): bool {
123 if ( isset( $_POST['two_factor_authentication'] ) && ! empty( $_POST['two_factor_authentication'] ) ) {
124 return $this->check_environment() && sanitize_text_field( $_POST['two_factor_authentication'] ) === 't';
125 }
126
127 return $this->is_enabled();
128 }
129
130 /**
131 * 有効な権限グループに含まれるかどうか
132 *
133 * @param $role
134 *
135 * @return bool
136 */
137 private function is_role_enabled( $role ): bool {
138 return in_array( $role, get_option( 'cloudsecurewp_two_factor_authentication_roles', array() ) );
139 }
140
141 /**
142 * ログインフォーム2段階認証チェック
143 */
144 public function wp_login( $user_login, $user ) {
145 // 2段階認証が無効なとき
146 if ( ! $this->is_enabled() ) {
147 return;
148 }
149
150 // 有効な権限グループに含まれないとき
151 if ( ! $this->is_role_enabled( $user->roles[0] ) ) {
152 return;
153 }
154
155 $secret = get_user_option( 'cloudsecurewp_two_factor_authentication_secret', $user->ID );
156 // ユーザーがデバイス登録をしていないとき
157 if ( ! $secret ) {
158 return;
159 }
160
161 // 初回ログイン時に�
162 �の認証�
163 報を保存
164 if ( empty( $this->original_credentials ) ) {
165 $this->original_credentials['log'] = $user_login;
166 $this->original_credentials['pwd'] = $_POST['pwd'] ?? '';
167 }
168
169 // 2段階認証コードが送られたとき
170 if ( ! empty( $_POST['google_authenticator_code'] ) && check_admin_referer( $this->get_feature_key() . '_csrf' ) ) {
171 $google_authenticator_code = sanitize_text_field( $_POST['google_authenticator_code'] );
172 // 2段階認証コードが有効なとき
173 if ( CloudSecureWP_Time_Based_One_Time_Password::verify_code( $secret, $google_authenticator_code, 2 ) ) {
174 return;
175 }
176 // ログイン失敗回数をインクリメントしデータベースに格納
177 $this->disable_login->wp_login_failed( $user_login );
178 }
179
180 wp_logout();
181 login_header( '2段階認証画面' );
182 $this->login_error();
183 $this->login_form();
184 login_footer();
185 exit;
186 }
187
188 /**
189 * 2段階認証のエラーを出力
190 *
191 * @return void
192 */
193 private function login_error() {
194 if ( array_key_exists( 'google_authenticator_code', $_REQUEST ) ) {
195 if ( sanitize_text_field( $_REQUEST['google_authenticator_code'] ) ) {
196 $errors = '認証コードが間違っているか、有効期限が切れています。';
197 } else {
198 $errors = '認証コードが�
199 �力されていません。';
200 }
201 echo '<div id="login_error">' . esc_html( apply_filters( 'login_errors', $errors ) ) . "</div>\n";
202 }
203 }
204
205 /**
206 * 2段階認証のログインフォームを出力
207 *
208 * @return void
209 */
210 private function login_form() {
211 ?>
212 <form name="loginform" id="loginform"
213 action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
214 <input type="hidden" name="log" value="<?php echo base64_encode( $this->original_credentials['log'] ?? $_REQUEST['log'] ?? '' ); ?>"/>
215 <input type="hidden" name="pwd" value="<?php echo base64_encode( $this->original_credentials['pwd'] ?? $_REQUEST['pwd'] ?? '' ); ?>"/>
216 <?php if ( array_key_exists( 'cloudsecurewp_captcha', $_REQUEST ) ) : ?>
217 <input type="hidden" name="cloudsecurewp_captcha"
218 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha'] ) ); ?>"/>
219 <?php endif; ?>
220 <?php if ( array_key_exists( 'cloudsecurewp_captcha_prefix', $_REQUEST ) ) : ?>
221 <input type="hidden" name="cloudsecurewp_captcha_prefix"
222 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha_prefix'] ) ); ?>"/>
223 <?php endif; ?>
224 <?php if ( array_key_exists( 'cloudsecurewp_captcha_wpnonce', $_REQUEST ) ) : ?>
225 <input type="hidden" name="cloudsecurewp_captcha_wpnonce"
226 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha_wpnonce'] ) ); ?>"/>
227 <?php endif; ?>
228 <?php if ( array_key_exists( 'rememberme', $_REQUEST ) && 'forever' === sanitize_text_field( $_REQUEST['rememberme'] ) ) : ?>
229 <input name="rememberme" type="hidden" id="rememberme" value="forever"/>
230 <?php endif; ?>
231 <p>
232 <label for="google_authenticator_code">認証コード</label>
233 <input type="text" name="google_authenticator_code" id="google_authenticator_code" class="input"
234 value="" size="20"/>
235 </p>
236 <script type="text/javascript">document.getElementById("google_authenticator_code").focus();</script>
237 <p>デバイスのGoogle Authenticator アプリケーションに表示されている6桁の認証コードを�
238 �力してください。</p>
239 <p class="submit">
240 <?php wp_nonce_field( $this->get_feature_key() . '_csrf' ); ?>
241 <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large"
242 value="<?php esc_attr_e( 'Log In' ); ?>"/>
243 <input type="hidden" name="redirect_to"
244 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['redirect_to'] ?? admin_url() ) ); ?>"/>
245 <input type="hidden" name="testcookie" value="1"/>
246 </p>
247 </form>
248 <?php
249 }
250
251 /**
252 * デバイス登録がまだのユーザーは、デバイス登録画面にリダイレクト
253 *
254 * @param $user_login
255 * @param $user
256 *
257 * @return void
258 * @noinspection PhpUnusedParameterInspection
259 */
260 public function redirect_if_not_two_factor_authentication_registered( $user_login, $user ) {
261 $secret = get_user_option( 'cloudsecurewp_two_factor_authentication_secret', $user->ID );
262 if ( $this->is_enabled() && $this->is_role_enabled( $user->roles[0] ) && ! $secret && $_SERVER['REQUEST_URI'] !== '/wp-admin/admin.php?page=cloudsecurewp_two_factor_authentication_registration' ) {
263 wp_redirect( admin_url( 'admin.php?page=cloudsecurewp_two_factor_authentication_registration' ) );
264 exit;
265 }
266 }
267
268 /**
269 * WordPress標準機能のユーザー一覧に表示するcolumnを追加
270 */
271 public function add_2factor_state_2user_list( $columns ) {
272 $new_columns = [];
273
274 foreach ( $columns as $key => $value ) {
275 $new_columns[ $key ] = $value;
276
277 if ( $key === 'role' ) {
278 $new_columns['is_2factor'] = '2段階認証';
279 }
280 }
281
282 return $new_columns;
283 }
284
285 /**
286 * WordPress標準機能のユーザー一覧に表示する二段階認証の設定状�
287 �を指定
288 */
289 public function show_2factor_state_2user_list( $value, $column_name, $user_id ) {
290 if ( $column_name === 'is_2factor' ) {
291 $value = get_user_meta( $user_id, 'wp_cloudsecurewp_two_factor_authentication_secret', true );
292 return $value !== '' ? '設定済' : '未設定';
293 }
294 return $value;
295 }
296
297 /**
298 * 2段階認証フォームからのBase64エンコードされた認証�
299 報をデコード
300 *
301 * @param mixed $user
302 * @param string $username
303 * @param string $password
304 * @return mixed
305 */
306 public function decode_base64_credentials( $user, $username, $password ) {
307 // 2段階認証フォームからの送信かチェック
308 if ( ! empty( $_POST['google_authenticator_code'] ) && check_admin_referer( $this->get_feature_key() . '_csrf' ) ) {
309 // Base64エンコードされた認証�
310 報をデコード
311 if ( isset( $_POST['log'] ) ) {
312 $decoded_username = base64_decode( $_POST['log'] );
313 $this->original_credentials['log'] = $decoded_username;
314 $_POST['log'] = $decoded_username;
315 }
316
317 if ( isset( $_POST['pwd'] ) ) {
318 $decoded_password = base64_decode( $_POST['pwd'] );
319 $this->original_credentials['pwd'] = $decoded_password;
320 $_POST['pwd'] = $decoded_password;
321
322 // デコードされたパスワードで認証を実行
323 return wp_authenticate_username_password( null, $decoded_username, $decoded_password );
324 }
325 }
326
327 return $user;
328 }
329 }
330