PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.3.18
CloudSecure WP Security v1.3.18
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 10 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 10 months ago server-error-notification.php 1 year ago two-factor-authentication.php 10 months ago unify-messages.php 2 years ago update-notice.php 2 years ago waf-engine.php 10 months ago waf.php 1 year ago
two-factor-authentication.php
337 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 if ( ! isset( $user->roles[0] ) ) {
151 return;
152 }
153
154 // 有効な権限グループに含まれないとき
155 if ( ! $this->is_role_enabled( $user->roles[0] ) ) {
156 return;
157 }
158
159 $secret = get_user_option( 'cloudsecurewp_two_factor_authentication_secret', $user->ID );
160 // ユーザーがデバイス登録をしていないとき
161 if ( ! $secret ) {
162 return;
163 }
164
165 // 初回ログイン時に�
166 �の認証�
167 報を保存
168 if ( empty( $this->original_credentials ) ) {
169 $this->original_credentials['log'] = $user_login;
170 $this->original_credentials['pwd'] = $_POST['pwd'] ?? '';
171 }
172
173 // 2段階認証コードが送られたとき
174 if ( ! empty( $_POST['google_authenticator_code'] ) && check_admin_referer( $this->get_feature_key() . '_csrf' ) ) {
175 $google_authenticator_code = sanitize_text_field( $_POST['google_authenticator_code'] );
176 // 2段階認証コードが有効なとき
177 if ( CloudSecureWP_Time_Based_One_Time_Password::verify_code( $secret, $google_authenticator_code, 2 ) ) {
178 return;
179 }
180 // ログイン失敗回数をインクリメントしデータベースに格納
181 $this->disable_login->wp_login_failed( $user_login );
182 }
183
184 wp_logout();
185 login_header( '2段階認証画面' );
186 $this->login_error();
187 $this->login_form();
188 login_footer();
189 exit;
190 }
191
192 /**
193 * 2段階認証のエラーを出力
194 *
195 * @return void
196 */
197 private function login_error() {
198 if ( array_key_exists( 'google_authenticator_code', $_REQUEST ) ) {
199 if ( sanitize_text_field( $_REQUEST['google_authenticator_code'] ) ) {
200 $errors = '認証コードが間違っているか、有効期限が切れています。';
201 } else {
202 $errors = '認証コードが�
203 �力されていません。';
204 }
205 echo '<div id="login_error">' . esc_html( apply_filters( 'login_errors', $errors ) ) . "</div>\n";
206 }
207 }
208
209 /**
210 * 2段階認証のログインフォームを出力
211 *
212 * @return void
213 */
214 private function login_form() {
215 ?>
216 <form name="loginform" id="loginform"
217 action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
218 <input type="hidden" name="log" value="<?php echo base64_encode( $this->original_credentials['log'] ?? $_REQUEST['log'] ?? '' ); ?>"/>
219 <input type="hidden" name="pwd" value="<?php echo base64_encode( $this->original_credentials['pwd'] ?? $_REQUEST['pwd'] ?? '' ); ?>"/>
220 <?php if ( array_key_exists( 'cloudsecurewp_captcha', $_REQUEST ) ) : ?>
221 <input type="hidden" name="cloudsecurewp_captcha"
222 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha'] ) ); ?>"/>
223 <?php endif; ?>
224 <?php if ( array_key_exists( 'cloudsecurewp_captcha_prefix', $_REQUEST ) ) : ?>
225 <input type="hidden" name="cloudsecurewp_captcha_prefix"
226 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha_prefix'] ) ); ?>"/>
227 <?php endif; ?>
228 <?php if ( array_key_exists( 'cloudsecurewp_captcha_wpnonce', $_REQUEST ) ) : ?>
229 <input type="hidden" name="cloudsecurewp_captcha_wpnonce"
230 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['cloudsecurewp_captcha_wpnonce'] ) ); ?>"/>
231 <?php endif; ?>
232 <?php if ( array_key_exists( 'rememberme', $_REQUEST ) && 'forever' === sanitize_text_field( $_REQUEST['rememberme'] ) ) : ?>
233 <input name="rememberme" type="hidden" id="rememberme" value="forever"/>
234 <?php endif; ?>
235 <p>
236 <label for="google_authenticator_code">認証コード</label>
237 <input type="text" name="google_authenticator_code" id="google_authenticator_code" class="input"
238 value="" size="20"/>
239 </p>
240 <script type="text/javascript">document.getElementById("google_authenticator_code").focus();</script>
241 <p>デバイスのGoogle Authenticator アプリケーションに表示されている6桁の認証コードを�
242 �力してください。</p>
243 <p class="submit">
244 <?php wp_nonce_field( $this->get_feature_key() . '_csrf' ); ?>
245 <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large"
246 value="<?php esc_attr_e( 'Log In' ); ?>"/>
247 <input type="hidden" name="redirect_to"
248 value="<?php echo esc_attr( sanitize_text_field( $_REQUEST['redirect_to'] ?? admin_url() ) ); ?>"/>
249 <input type="hidden" name="testcookie" value="1"/>
250 </p>
251 </form>
252 <?php
253 }
254
255 /**
256 * デバイス登録がまだのユーザーは、デバイス登録画面にリダイレクト
257 *
258 * @param $user_login
259 * @param $user
260 *
261 * @return void
262 * @noinspection PhpUnusedParameterInspection
263 */
264 public function redirect_if_not_two_factor_authentication_registered( $user_login, $user ) {
265 $secret = get_user_option( 'cloudsecurewp_two_factor_authentication_secret', $user->ID );
266
267 if ( isset( $user->roles[0] ) ) {
268 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' ) {
269 wp_redirect( admin_url( 'admin.php?page=cloudsecurewp_two_factor_authentication_registration' ) );
270 exit;
271 }
272 }
273 }
274
275 /**
276 * WordPress標準機能のユーザー一覧に表示するcolumnを追加
277 */
278 public function add_2factor_state_2user_list( $columns ) {
279 $new_columns = [];
280
281 foreach ( $columns as $key => $value ) {
282 $new_columns[ $key ] = $value;
283
284 if ( $key === 'role' ) {
285 $new_columns['is_2factor'] = '2段階認証';
286 }
287 }
288
289 return $new_columns;
290 }
291
292 /**
293 * WordPress標準機能のユーザー一覧に表示する二段階認証の設定状�
294 �を指定
295 */
296 public function show_2factor_state_2user_list( $value, $column_name, $user_id ) {
297 if ( $column_name === 'is_2factor' ) {
298 $value = get_user_meta( $user_id, 'wp_cloudsecurewp_two_factor_authentication_secret', true );
299 return $value !== '' ? '設定済' : '未設定';
300 }
301 return $value;
302 }
303
304 /**
305 * 2段階認証フォームからのBase64エンコードされた認証�
306 報をデコード
307 *
308 * @param mixed $user
309 * @param string $username
310 * @param string $password
311 * @return mixed
312 */
313 public function decode_base64_credentials( $user, $username, $password ) {
314 // 2段階認証フォームからの送信かチェック
315 if ( ! empty( $_POST['google_authenticator_code'] ) && check_admin_referer( $this->get_feature_key() . '_csrf' ) ) {
316 // Base64エンコードされた認証�
317 報をデコード
318 if ( isset( $_POST['log'] ) ) {
319 $decoded_username = base64_decode( $_POST['log'] );
320 $this->original_credentials['log'] = $decoded_username;
321 $_POST['log'] = $decoded_username;
322 }
323
324 if ( isset( $_POST['pwd'] ) ) {
325 $decoded_password = base64_decode( $_POST['pwd'] );
326 $this->original_credentials['pwd'] = $decoded_password;
327 $_POST['pwd'] = $decoded_password;
328
329 // デコードされたパスワードで認証を実行
330 return wp_authenticate_username_password( null, $decoded_username, $decoded_password );
331 }
332 }
333
334 return $user;
335 }
336 }
337