Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Module Name: Single Sign On |
||
| 5 | * Module Description: Secure user authentication with WordPress.com. |
||
| 6 | * Jumpstart Description: Lets you log in to all your Jetpack-enabled sites with one click using your WordPress.com account. |
||
| 7 | * Sort Order: 30 |
||
| 8 | * Recommendation Order: 5 |
||
| 9 | * First Introduced: 2.6 |
||
| 10 | * Requires Connection: Yes |
||
| 11 | * Auto Activate: No |
||
| 12 | * Module Tags: Developers |
||
| 13 | * Feature: Security, Jumpstart |
||
| 14 | * Additional Search Queries: sso, single sign on, login, log in |
||
| 15 | */ |
||
| 16 | |||
| 17 | class Jetpack_SSO { |
||
| 18 | static $instance = null; |
||
| 19 | |||
| 20 | private function __construct() { |
||
| 21 | |||
| 22 | self::$instance = $this; |
||
| 23 | |||
| 24 | add_action( 'admin_init', array( $this, 'maybe_authorize_user_after_sso' ), 1 ); |
||
| 25 | add_action( 'admin_init', array( $this, 'admin_init' ) ); |
||
| 26 | add_action( 'admin_init', array( $this, 'register_settings' ) ); |
||
| 27 | add_action( 'login_init', array( $this, 'login_init' ) ); |
||
| 28 | add_action( 'delete_user', array( $this, 'delete_connection_for_user' ) ); |
||
| 29 | add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) ); |
||
| 30 | add_action( 'init', array( $this, 'maybe_logout_user' ), 5 ); |
||
| 31 | add_action( 'jetpack_modules_loaded', array( $this, 'module_configure_button' ) ); |
||
| 32 | add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); |
||
| 33 | add_action( 'login_form_logout', array( $this, 'store_wpcom_profile_cookies_on_logout' ) ); |
||
| 34 | add_action( 'wp_login', array( 'Jetpack_SSO', 'clear_wpcom_profile_cookies' ) ); |
||
| 35 | |||
| 36 | |||
| 37 | // Adding this action so that on login_init, the action won't be sanitized out of the $action global. |
||
| 38 | add_action( 'login_form_jetpack-sso', '__return_true' ); |
||
| 39 | |||
| 40 | if ( |
||
| 41 | $this->should_hide_login_form() && |
||
| 42 | /** |
||
| 43 | * Filter the display of the disclaimer message appearing when default WordPress login form is disabled. |
||
| 44 | * |
||
| 45 | * @module sso |
||
| 46 | * |
||
| 47 | * @since 2.8.0 |
||
| 48 | * |
||
| 49 | * @param bool true Should the disclaimer be displayed. Default to true. |
||
| 50 | */ |
||
| 51 | apply_filters( 'jetpack_sso_display_disclaimer', true ) |
||
| 52 | ) { |
||
| 53 | add_action( 'login_message', array( $this, 'msg_login_by_jetpack' ) ); |
||
| 54 | } |
||
| 55 | } |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Returns the single instance of the Jetpack_SSO object |
||
| 59 | * |
||
| 60 | * @since 2.8 |
||
| 61 | * @return Jetpack_SSO |
||
| 62 | **/ |
||
| 63 | public static function get_instance() { |
||
| 64 | if ( ! is_null( self::$instance ) ) { |
||
| 65 | return self::$instance; |
||
| 66 | } |
||
| 67 | |||
| 68 | return self::$instance = new Jetpack_SSO; |
||
| 69 | } |
||
| 70 | |||
| 71 | /** |
||
| 72 | * Add configure button and functionality to the module card on the Jetpack screen |
||
| 73 | **/ |
||
| 74 | public static function module_configure_button() { |
||
| 75 | Jetpack::enable_module_configurable( __FILE__ ); |
||
| 76 | Jetpack::module_configuration_load( __FILE__, array( __CLASS__, 'module_configuration_load' ) ); |
||
| 77 | Jetpack::module_configuration_head( __FILE__, array( __CLASS__, 'module_configuration_head' ) ); |
||
| 78 | Jetpack::module_configuration_screen( __FILE__, array( __CLASS__, 'module_configuration_screen' ) ); |
||
| 79 | } |
||
| 80 | |||
| 81 | public static function module_configuration_load() { |
||
| 82 | // wp_safe_redirect( admin_url( 'options-general.php#configure-sso' ) ); |
||
| 83 | // exit; |
||
| 84 | } |
||
| 85 | |||
| 86 | public static function module_configuration_head() {} |
||
| 87 | |||
| 88 | public static function module_configuration_screen() { |
||
| 89 | ?> |
||
| 90 | <form method="post" action="options.php"> |
||
| 91 | <?php settings_fields( 'jetpack-sso' ); ?> |
||
| 92 | <?php do_settings_sections( 'jetpack-sso' ); ?> |
||
| 93 | <?php submit_button(); ?> |
||
| 94 | </form> |
||
| 95 | <?php |
||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * If jetpack_force_logout == 1 in current user meta the user will be forced |
||
| 100 | * to logout and reauthenticate with the site. |
||
| 101 | **/ |
||
| 102 | public function maybe_logout_user() { |
||
| 103 | global $current_user; |
||
| 104 | |||
| 105 | if ( 1 == $current_user->jetpack_force_logout ) { |
||
| 106 | delete_user_meta( $current_user->ID, 'jetpack_force_logout' ); |
||
| 107 | self::delete_connection_for_user( $current_user->ID ); |
||
| 108 | wp_logout(); |
||
| 109 | wp_safe_redirect( wp_login_url() ); |
||
| 110 | exit; |
||
|
0 ignored issues
–
show
|
|||
| 111 | } |
||
| 112 | } |
||
| 113 | |||
| 114 | |||
| 115 | /** |
||
| 116 | * Adds additional methods the WordPress xmlrpc API for handling SSO specific features |
||
| 117 | * |
||
| 118 | * @param array $methods |
||
| 119 | * @return array |
||
| 120 | **/ |
||
| 121 | public function xmlrpc_methods( $methods ) { |
||
| 122 | $methods['jetpack.userDisconnect'] = array( $this, 'xmlrpc_user_disconnect' ); |
||
| 123 | return $methods; |
||
| 124 | } |
||
| 125 | |||
| 126 | /** |
||
| 127 | * Marks a user's profile for disconnect from WordPress.com and forces a logout |
||
| 128 | * the next time the user visits the site. |
||
| 129 | **/ |
||
| 130 | public function xmlrpc_user_disconnect( $user_id ) { |
||
| 131 | $user_query = new WP_User_Query( |
||
| 132 | array( |
||
| 133 | 'meta_key' => 'wpcom_user_id', |
||
| 134 | 'meta_value' => $user_id, |
||
| 135 | ) |
||
| 136 | ); |
||
| 137 | $user = $user_query->get_results(); |
||
| 138 | $user = $user[0]; |
||
| 139 | |||
| 140 | if ( $user instanceof WP_User ) { |
||
| 141 | $user = wp_set_current_user( $user->ID ); |
||
| 142 | update_user_meta( $user->ID, 'jetpack_force_logout', '1' ); |
||
| 143 | self::delete_connection_for_user( $user->ID ); |
||
| 144 | return true; |
||
| 145 | } |
||
| 146 | return false; |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Enqueues scripts and styles necessary for SSO login. |
||
| 151 | */ |
||
| 152 | public function login_enqueue_scripts() { |
||
| 153 | global $action; |
||
| 154 | |||
| 155 | if ( ! in_array( $action, array( 'jetpack-sso', 'login' ) ) ) { |
||
| 156 | return; |
||
| 157 | } |
||
| 158 | |||
| 159 | wp_enqueue_style( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.css', JETPACK__PLUGIN_FILE ), array( 'login', 'genericons' ), JETPACK__VERSION ); |
||
| 160 | wp_enqueue_script( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.js', JETPACK__PLUGIN_FILE ), array( 'jquery' ), JETPACK__VERSION ); |
||
| 161 | } |
||
| 162 | |||
| 163 | /** |
||
| 164 | * Enqueue styles neceessary for Jetpack SSO on users' profiles |
||
| 165 | */ |
||
| 166 | public function admin_enqueue_scripts() { |
||
| 167 | $screen = get_current_screen(); |
||
| 168 | |||
| 169 | if ( empty( $screen ) || ! in_array( $screen->base, array( 'edit-user', 'profile' ) ) ) { |
||
| 170 | return; |
||
| 171 | } |
||
| 172 | |||
| 173 | wp_enqueue_style( 'jetpack-sso-profile', plugins_url( 'modules/sso/jetpack-sso-profile.css', JETPACK__PLUGIN_FILE ), array( 'genericons' ), JETPACK__VERSION ); |
||
| 174 | } |
||
| 175 | |||
| 176 | /** |
||
| 177 | * Adds Jetpack SSO classes to login body |
||
| 178 | * |
||
| 179 | * @param array $classes Array of classes to add to body tag |
||
| 180 | * @return array Array of classes to add to body tag |
||
| 181 | */ |
||
| 182 | public function login_body_class( $classes ) { |
||
| 183 | global $action; |
||
| 184 | |||
| 185 | if ( ! in_array( $action, array( 'jetpack-sso', 'login' ) ) ) { |
||
| 186 | return $classes; |
||
| 187 | } |
||
| 188 | |||
| 189 | // If jetpack-sso-default-form, show the default login form. |
||
| 190 | if ( isset( $_GET['jetpack-sso-default-form'] ) && 1 == $_GET['jetpack-sso-default-form'] ) { |
||
| 191 | return $classes; |
||
| 192 | } |
||
| 193 | |||
| 194 | $classes[] = 'jetpack-sso-body'; |
||
| 195 | return $classes; |
||
| 196 | } |
||
| 197 | |||
| 198 | /** |
||
| 199 | * Adds settings fields to Settings > General > Single Sign On that allows users to |
||
| 200 | * turn off the login form on wp-login.php |
||
| 201 | * |
||
| 202 | * @since 2.7 |
||
| 203 | **/ |
||
| 204 | public function register_settings() { |
||
| 205 | |||
| 206 | add_settings_section( |
||
| 207 | 'jetpack_sso_settings', |
||
| 208 | __( 'Single Sign On' , 'jetpack' ), |
||
| 209 | '__return_false', |
||
| 210 | 'jetpack-sso' |
||
| 211 | ); |
||
| 212 | |||
| 213 | /* |
||
| 214 | * Settings > General > Single Sign On |
||
| 215 | * Checkbox for Remove default login form |
||
| 216 | */ |
||
| 217 | /* Hide in 2.9 |
||
| 218 | register_setting( |
||
| 219 | 'general', |
||
| 220 | 'jetpack_sso_remove_login_form', |
||
| 221 | array( $this, 'validate_settings_remove_login_form_checkbox' ) |
||
| 222 | ); |
||
| 223 | |||
| 224 | add_settings_field( |
||
| 225 | 'jetpack_sso_remove_login_form', |
||
| 226 | __( 'Remove default login form?' , 'jetpack' ), |
||
| 227 | array( $this, 'render_remove_login_form_checkbox' ), |
||
| 228 | 'general', |
||
| 229 | 'jetpack_sso_settings' |
||
| 230 | ); |
||
| 231 | */ |
||
| 232 | |||
| 233 | /* |
||
| 234 | * Settings > General > Single Sign On |
||
| 235 | * Require two step authentication |
||
| 236 | */ |
||
| 237 | register_setting( |
||
| 238 | 'jetpack-sso', |
||
| 239 | 'jetpack_sso_require_two_step', |
||
| 240 | array( $this, 'validate_jetpack_sso_require_two_step' ) |
||
| 241 | ); |
||
| 242 | |||
| 243 | add_settings_field( |
||
| 244 | 'jetpack_sso_require_two_step', |
||
| 245 | '', // __( 'Require Two-Step Authentication' , 'jetpack' ), |
||
| 246 | array( $this, 'render_require_two_step' ), |
||
| 247 | 'jetpack-sso', |
||
| 248 | 'jetpack_sso_settings' |
||
| 249 | ); |
||
| 250 | |||
| 251 | /* |
||
| 252 | * Settings > General > Single Sign On |
||
| 253 | */ |
||
| 254 | register_setting( |
||
| 255 | 'jetpack-sso', |
||
| 256 | 'jetpack_sso_match_by_email', |
||
| 257 | array( $this, 'validate_jetpack_sso_match_by_email' ) |
||
| 258 | ); |
||
| 259 | |||
| 260 | add_settings_field( |
||
| 261 | 'jetpack_sso_match_by_email', |
||
| 262 | '', // __( 'Match by Email' , 'jetpack' ), |
||
| 263 | array( $this, 'render_match_by_email' ), |
||
| 264 | 'jetpack-sso', |
||
| 265 | 'jetpack_sso_settings' |
||
| 266 | ); |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Builds the display for the checkbox allowing user to require two step |
||
| 271 | * auth be enabled on WordPress.com accounts before login. Displays in Settings > General |
||
| 272 | * |
||
| 273 | * @since 2.7 |
||
| 274 | **/ |
||
| 275 | public function render_require_two_step() { |
||
| 276 | /** This filter is documented in modules/sso.php */ |
||
| 277 | $require_two_step = ( 1 == apply_filters( 'jetpack_sso_require_two_step', get_option( 'jetpack_sso_require_two_step' ) ) ); |
||
| 278 | $disabled = $require_two_step ? ' disabled="disabled"' : ''; |
||
| 279 | echo '<label>'; |
||
| 280 | echo '<input type="checkbox" name="jetpack_sso_require_two_step" ' . checked( $require_two_step, true, false ) . "$disabled>"; |
||
| 281 | esc_html_e( 'Require Two-Step Authentication' , 'jetpack' ); |
||
| 282 | echo '</label>'; |
||
| 283 | } |
||
| 284 | |||
| 285 | /** |
||
| 286 | * Validate the require two step checkbox in Settings > General |
||
| 287 | * |
||
| 288 | * @since 2.7 |
||
| 289 | * @return boolean |
||
| 290 | **/ |
||
| 291 | public function validate_jetpack_sso_require_two_step( $input ) { |
||
| 292 | return ( ! empty( $input ) ) ? 1 : 0; |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Builds the display for the checkbox allowing the user to allow matching logins by email |
||
| 297 | * Displays in Settings > General |
||
| 298 | * |
||
| 299 | * @since 2.9 |
||
| 300 | **/ |
||
| 301 | public function render_match_by_email() { |
||
| 302 | $match_by_email = 1 == $this->match_by_email(); |
||
| 303 | $disabled = $match_by_email ? ' disabled="disabled"' : ''; |
||
| 304 | echo '<label>'; |
||
| 305 | echo '<input type="checkbox" name="jetpack_sso_match_by_email"' . checked( $match_by_email, true, false ) . "$disabled>"; |
||
| 306 | esc_html_e( 'Match by Email', 'jetpack' ); |
||
| 307 | echo '</label>'; |
||
| 308 | } |
||
| 309 | |||
| 310 | /** |
||
| 311 | * Validate the match by email check in Settings > General |
||
| 312 | * |
||
| 313 | * @since 2.9 |
||
| 314 | * @return boolean |
||
| 315 | **/ |
||
| 316 | public function validate_jetpack_sso_match_by_email( $input ) { |
||
| 317 | return ( ! empty( $input ) ) ? 1 : 0; |
||
| 318 | } |
||
| 319 | |||
| 320 | /** |
||
| 321 | * Builds the display for the checkbox allowing users to remove the default |
||
| 322 | * WordPress login form from wp-login.php. Displays in Settings > General |
||
| 323 | * |
||
| 324 | * @since 2.7 |
||
| 325 | **/ |
||
| 326 | public function render_remove_login_form_checkbox() { |
||
| 327 | if ( $this->is_user_connected( get_current_user_id() ) ) { |
||
| 328 | echo '<a name="configure-sso"></a>'; |
||
| 329 | echo '<input type="checkbox" name="jetpack_sso_remove_login_form[remove_login_form]" ' . checked( 1 == get_option( 'jetpack_sso_remove_login_form' ), true, false ) . '>'; |
||
| 330 | echo '<p class="description">Removes default login form and disallows login via POST</p>'; |
||
| 331 | } else { |
||
| 332 | echo 'Your account must be connected to WordPress.com before disabling the login form.'; |
||
| 333 | echo '<br/>' . $this->button(); |
||
|
0 ignored issues
–
show
|
|||
| 334 | } |
||
| 335 | } |
||
| 336 | |||
| 337 | /** |
||
| 338 | * Validate settings input from Settings > General |
||
| 339 | * |
||
| 340 | * @since 2.7 |
||
| 341 | * @return boolean |
||
| 342 | **/ |
||
| 343 | public function validate_settings_remove_login_form_checkbox( $input ) { |
||
| 344 | return ( isset( $input['remove_login_form'] ) )? 1: 0; |
||
| 345 | } |
||
| 346 | |||
| 347 | /** |
||
| 348 | * Checks to determine if the user wants to login on wp-login |
||
| 349 | * |
||
| 350 | * This function mostly exists to cover the exceptions to login |
||
| 351 | * that may exist as other parameters to $_GET[action] as $_GET[action] |
||
| 352 | * does not have to exist. By default WordPress assumes login if an action |
||
| 353 | * is not set, however this may not be true, as in the case of logout |
||
| 354 | * where $_GET[loggedout] is instead set |
||
| 355 | * |
||
| 356 | * @return boolean |
||
| 357 | **/ |
||
| 358 | private function wants_to_login() { |
||
| 359 | $wants_to_login = false; |
||
| 360 | |||
| 361 | // Cover default WordPress behavior |
||
| 362 | $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login'; |
||
| 363 | |||
| 364 | // And now the exceptions |
||
| 365 | $action = isset( $_GET['loggedout'] ) ? 'loggedout' : $action; |
||
| 366 | |||
| 367 | if ( 'login' == $action ) { |
||
| 368 | $wants_to_login = true; |
||
| 369 | } |
||
| 370 | |||
| 371 | return $wants_to_login; |
||
| 372 | } |
||
| 373 | |||
| 374 | private function bypass_login_forward_wpcom() { |
||
| 375 | /** |
||
| 376 | * Redirect the site's log in form to WordPress.com's log in form. |
||
| 377 | * |
||
| 378 | * @module sso |
||
| 379 | * |
||
| 380 | * @since 3.1.0 |
||
| 381 | * |
||
| 382 | * @param bool false Should the site's log in form be automatically forwarded to WordPress.com's log in form. |
||
| 383 | */ |
||
| 384 | return apply_filters( 'jetpack_sso_bypass_login_forward_wpcom', false ); |
||
| 385 | } |
||
| 386 | |||
| 387 | function login_init() { |
||
| 388 | global $action; |
||
| 389 | |||
| 390 | /** |
||
| 391 | * If the user is attempting to logout AND the auto-forward to WordPress.com |
||
| 392 | * login is set then we need to ensure we do not auto-forward the user and get |
||
| 393 | * them stuck in an infinite logout loop. |
||
| 394 | */ |
||
| 395 | if ( isset( $_GET['loggedout'] ) && $this->bypass_login_forward_wpcom() ) { |
||
| 396 | add_filter( 'jetpack_remove_login_form', '__return_true' ); |
||
| 397 | } |
||
| 398 | |||
| 399 | /** |
||
| 400 | * Check to see if the site admin wants to automagically forward the user |
||
| 401 | * to the WordPress.com login page AND that the request to wp-login.php |
||
| 402 | * is not something other than login (Like logout!) |
||
| 403 | */ |
||
| 404 | if ( |
||
| 405 | $this->wants_to_login() |
||
| 406 | && $this->bypass_login_forward_wpcom() |
||
| 407 | ) { |
||
| 408 | add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) ); |
||
| 409 | $this->maybe_save_cookie_redirect(); |
||
| 410 | $reauth = ! empty( $_GET['reauth'] ); |
||
| 411 | wp_safe_redirect( $this->get_sso_url_or_die( $reauth ) ); |
||
| 412 | exit; |
||
|
0 ignored issues
–
show
The method
login_init() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an Loading history...
|
|||
| 413 | } |
||
| 414 | |||
| 415 | if ( 'login' === $action ) { |
||
| 416 | $this->display_sso_login_form(); |
||
| 417 | } elseif ( 'jetpack-sso' === $action ) { |
||
| 418 | if ( isset( $_GET['result'], $_GET['user_id'], $_GET['sso_nonce'] ) && 'success' == $_GET['result'] ) { |
||
| 419 | $this->handle_login(); |
||
| 420 | $this->display_sso_login_form(); |
||
| 421 | } else { |
||
| 422 | if ( Jetpack::check_identity_crisis() ) { |
||
| 423 | wp_die( __( "Error: This site's Jetpack connection is currently experiencing problems.", 'jetpack' ) ); |
||
| 424 | } else { |
||
| 425 | $this->maybe_save_cookie_redirect(); |
||
| 426 | // Is it wiser to just use wp_redirect than do this runaround to wp_safe_redirect? |
||
| 427 | add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) ); |
||
| 428 | $reauth = ! empty( $_GET['reauth'] ); |
||
| 429 | wp_safe_redirect( $this->get_sso_url_or_die( $reauth ) ); |
||
| 430 | exit; |
||
|
0 ignored issues
–
show
The method
login_init() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an Loading history...
|
|||
| 431 | } |
||
| 432 | } |
||
| 433 | } |
||
| 434 | } |
||
| 435 | |||
| 436 | /** |
||
| 437 | * Ensures that we can get a nonce from WordPress.com via XML-RPC before setting |
||
| 438 | * up the hooks required to display the SSO form. |
||
| 439 | */ |
||
| 440 | public function display_sso_login_form() { |
||
| 441 | $sso_nonce = self::request_initial_nonce(); |
||
| 442 | if ( is_wp_error( $sso_nonce ) ) { |
||
| 443 | return; |
||
| 444 | } |
||
| 445 | |||
| 446 | add_action( 'login_form', array( $this, 'login_form' ) ); |
||
| 447 | add_filter( 'login_body_class', array( $this, 'login_body_class' ) ); |
||
| 448 | add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts' ) ); |
||
| 449 | } |
||
| 450 | |||
| 451 | /** |
||
| 452 | * Conditionally save the redirect_to url as a cookie. |
||
| 453 | */ |
||
| 454 | public static function maybe_save_cookie_redirect() { |
||
| 455 | if ( headers_sent() ) { |
||
| 456 | return new WP_Error( 'headers_sent', __( 'Cannot deal with cookie redirects, as headers are already sent.', 'jetpack' ) ); |
||
| 457 | } |
||
| 458 | |||
| 459 | if ( ! empty( $_GET['redirect_to'] ) ) { |
||
| 460 | // If we have something to redirect to |
||
| 461 | $url = esc_url_raw( $_GET['redirect_to'] ); |
||
| 462 | setcookie( 'jetpack_sso_redirect_to', $url, time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true ); |
||
| 463 | |||
| 464 | } elseif ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) { |
||
| 465 | // Otherwise, if it's already set, purge it. |
||
| 466 | setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN ); |
||
| 467 | } |
||
| 468 | |||
| 469 | if ( ! empty( $_GET['rememberme'] ) ) { |
||
| 470 | setcookie( 'jetpack_sso_remember_me', '1', time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true ); |
||
| 471 | } elseif ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) { |
||
| 472 | setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN ); |
||
| 473 | } |
||
| 474 | } |
||
| 475 | |||
| 476 | /** |
||
| 477 | * Determine if the login form should be hidden or not |
||
| 478 | * |
||
| 479 | * Method is private only because it is only used in this class so far. |
||
| 480 | * Feel free to change it later |
||
| 481 | * |
||
| 482 | * @return bool |
||
| 483 | **/ |
||
| 484 | private function should_hide_login_form() { |
||
| 485 | /** |
||
| 486 | * Remove the default log in form, only leave the WordPress.com log in button. |
||
| 487 | * |
||
| 488 | * @module sso |
||
| 489 | * |
||
| 490 | * @since 3.1.0 |
||
| 491 | * |
||
| 492 | * @param bool get_option( 'jetpack_sso_remove_login_form', false ) Should the default log in form be removed. Default to false. |
||
| 493 | */ |
||
| 494 | return apply_filters( 'jetpack_remove_login_form', get_option( 'jetpack_sso_remove_login_form', false ) ); |
||
| 495 | } |
||
| 496 | |||
| 497 | /** |
||
| 498 | * Outputs the Jetpack SSO button and description as well as the toggle link |
||
| 499 | * for switching between Jetpack SSO and default login. |
||
| 500 | */ |
||
| 501 | function login_form() { |
||
| 502 | $site_name = get_bloginfo( 'name' ); |
||
| 503 | if ( ! $site_name ) { |
||
| 504 | $site_name = get_bloginfo( 'url' ); |
||
| 505 | } |
||
| 506 | |||
| 507 | $display_name = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] ) |
||
| 508 | ? $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] |
||
| 509 | : false; |
||
| 510 | $gravatar = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] ) |
||
| 511 | ? $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] |
||
| 512 | : false; |
||
| 513 | |||
| 514 | ?> |
||
| 515 | <div id="jetpack-sso-wrap"> |
||
| 516 | <?php if ( $display_name && $gravatar ) : ?> |
||
| 517 | <div id="jetpack-sso-wrap__user"> |
||
| 518 | <img width="72" height="72" src="<?php echo esc_html( $gravatar ); ?>" /> |
||
| 519 | |||
| 520 | <h2> |
||
| 521 | <?php |
||
| 522 | echo wp_kses( |
||
| 523 | sprintf( __( 'Log in as <span>%s</span>', 'jetpack' ), esc_html( $display_name ) ), |
||
| 524 | array( 'span' => true ) |
||
| 525 | ); |
||
| 526 | ?> |
||
| 527 | </h2> |
||
| 528 | </div> |
||
| 529 | |||
| 530 | <?php endif; ?> |
||
| 531 | |||
| 532 | |||
| 533 | <div id="jetpack-sso-wrap__action"> |
||
| 534 | <?php echo $this->build_sso_button( array(), 'is_primary' ); ?> |
||
|
0 ignored issues
–
show
'is_primary' is of type string, but the function expects a boolean.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 535 | |||
| 536 | <?php if ( $display_name && $gravatar ) : ?> |
||
| 537 | <a class="jetpack-sso-wrap__reauth" href="<?php echo $this->build_sso_button_url( array( 'reauth' => '1' ) ); ?>"> |
||
| 538 | <?php esc_html_e( 'Log in as a different WordPress.com user', 'jetpack' ); ?> |
||
| 539 | </a> |
||
| 540 | <?php else : ?> |
||
| 541 | <p> |
||
| 542 | <?php |
||
| 543 | echo esc_html( |
||
| 544 | sprintf( |
||
| 545 | __( 'You can now save time spent logging in by connecting your WordPress.com account to %s.', 'jetpack' ), |
||
| 546 | esc_html( $site_name ) |
||
| 547 | ) |
||
| 548 | ); |
||
| 549 | ?> |
||
| 550 | </p> |
||
| 551 | <?php endif; ?> |
||
| 552 | </div> |
||
| 553 | |||
| 554 | <?php if ( ! $this->should_hide_login_form() ) : ?> |
||
| 555 | <div class="jetpack-sso-or"> |
||
| 556 | <span><?php esc_html_e( 'Or', 'jetpack' ); ?></span> |
||
| 557 | </div> |
||
| 558 | |||
| 559 | <a href="<?php echo add_query_arg( 'jetpack-sso-default-form', '1' ); ?>" class="jetpack-sso-toggle wpcom"> |
||
| 560 | <?php |
||
| 561 | esc_html_e( 'Log in with username and password', 'jetpack' ) |
||
| 562 | ?> |
||
| 563 | </a> |
||
| 564 | |||
| 565 | <a href="<?php echo add_query_arg( 'jetpack-sso-default-form', '0' ); ?>" class="jetpack-sso-toggle default"> |
||
| 566 | <?php |
||
| 567 | esc_html_e( 'Log in with WordPress.com', 'jetpack' ) |
||
| 568 | ?> |
||
| 569 | </a> |
||
| 570 | <?php endif; ?> |
||
| 571 | </div> |
||
| 572 | <?php |
||
| 573 | } |
||
| 574 | |||
| 575 | /** |
||
| 576 | * Clear the cookies that store the profile information for the last |
||
| 577 | * WPCOM user to connect. |
||
| 578 | */ |
||
| 579 | static function clear_wpcom_profile_cookies() { |
||
| 580 | View Code Duplication | if ( isset( $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] ) ) { |
|
| 581 | setcookie( |
||
| 582 | 'jetpack_sso_wpcom_name_' . COOKIEHASH, |
||
| 583 | ' ', |
||
| 584 | time() - YEAR_IN_SECONDS, |
||
| 585 | COOKIEPATH, |
||
| 586 | COOKIE_DOMAIN |
||
| 587 | ); |
||
| 588 | } |
||
| 589 | |||
| 590 | View Code Duplication | if ( isset( $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] ) ) { |
|
| 591 | setcookie( |
||
| 592 | 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH, |
||
| 593 | ' ', |
||
| 594 | time() - YEAR_IN_SECONDS, |
||
| 595 | COOKIEPATH, |
||
| 596 | COOKIE_DOMAIN |
||
| 597 | ); |
||
| 598 | } |
||
| 599 | } |
||
| 600 | |||
| 601 | static function delete_connection_for_user( $user_id ) { |
||
| 602 | if ( ! $wpcom_user_id = get_user_meta( $user_id, 'wpcom_user_id', true ) ) { |
||
| 603 | return; |
||
| 604 | } |
||
| 605 | Jetpack::load_xml_rpc_client(); |
||
| 606 | $xml = new Jetpack_IXR_Client( array( |
||
| 607 | 'wpcom_user_id' => $user_id, |
||
| 608 | ) ); |
||
| 609 | $xml->query( 'jetpack.sso.removeUser', $wpcom_user_id ); |
||
| 610 | |||
| 611 | if ( $xml->isError() ) { |
||
| 612 | return false; |
||
| 613 | } |
||
| 614 | |||
| 615 | self::clear_wpcom_profile_cookies(); |
||
| 616 | |||
| 617 | return $xml->getResponse(); |
||
| 618 | } |
||
| 619 | |||
| 620 | View Code Duplication | static function request_initial_nonce() { |
|
| 621 | Jetpack::load_xml_rpc_client(); |
||
| 622 | $xml = new Jetpack_IXR_Client( array( |
||
| 623 | 'user_id' => get_current_user_id(), |
||
| 624 | ) ); |
||
| 625 | $xml->query( 'jetpack.sso.requestNonce' ); |
||
| 626 | |||
| 627 | if ( $xml->isError() ) { |
||
| 628 | return new WP_Error( $xml->getErrorCode(), $xml->getErrorMessage() ); |
||
| 629 | } |
||
| 630 | |||
| 631 | return $xml->getResponse(); |
||
| 632 | } |
||
| 633 | |||
| 634 | /** |
||
| 635 | * The function that actually handles the login! |
||
| 636 | */ |
||
| 637 | function handle_login() { |
||
| 638 | $wpcom_nonce = sanitize_key( $_GET['sso_nonce'] ); |
||
| 639 | $wpcom_user_id = (int) $_GET['user_id']; |
||
| 640 | $result = sanitize_key( $_GET['result'] ); |
||
| 641 | |||
| 642 | Jetpack::load_xml_rpc_client(); |
||
| 643 | $xml = new Jetpack_IXR_Client( array( |
||
| 644 | 'user_id' => get_current_user_id(), |
||
| 645 | ) ); |
||
| 646 | $xml->query( 'jetpack.sso.validateResult', $wpcom_nonce, $wpcom_user_id ); |
||
| 647 | |||
| 648 | if ( $xml->isError() ) { |
||
| 649 | wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) ); |
||
| 650 | } |
||
| 651 | |||
| 652 | $user_data = $xml->getResponse(); |
||
| 653 | |||
| 654 | if ( empty( $user_data ) ) { |
||
| 655 | wp_die( __( 'Error, invalid response data.', 'jetpack' ) ); |
||
| 656 | } |
||
| 657 | |||
| 658 | $user_data = (object) $user_data; |
||
| 659 | $user = null; |
||
| 660 | |||
| 661 | /** |
||
| 662 | * Fires before Jetpack's SSO modifies the log in form. |
||
| 663 | * |
||
| 664 | * @module sso |
||
| 665 | * |
||
| 666 | * @since 2.6.0 |
||
| 667 | * |
||
| 668 | * @param object $user_data User login information. |
||
| 669 | */ |
||
| 670 | do_action( 'jetpack_sso_pre_handle_login', $user_data ); |
||
| 671 | |||
| 672 | /** |
||
| 673 | * Is it required to have 2-step authentication enabled on WordPress.com to use SSO? |
||
| 674 | * |
||
| 675 | * @module sso |
||
| 676 | * |
||
| 677 | * @since 2.8.0 |
||
| 678 | * |
||
| 679 | * @param bool get_option( 'jetpack_sso_require_two_step' ) Does SSO require 2-step authentication? |
||
| 680 | */ |
||
| 681 | $require_two_step = apply_filters( 'jetpack_sso_require_two_step', get_option( 'jetpack_sso_require_two_step' ) ); |
||
| 682 | if ( $require_two_step && 0 == (int) $user_data->two_step_enabled ) { |
||
| 683 | $this->user_data = $user_data; |
||
| 684 | /** This filter is documented in core/src/wp-includes/pluggable.php */ |
||
| 685 | do_action( 'wp_login_failed', $user_data->login ); |
||
| 686 | add_action( 'login_message', array( $this, 'error_msg_enable_two_step' ) ); |
||
| 687 | return; |
||
| 688 | } |
||
| 689 | |||
| 690 | if ( isset( $_GET['state'] ) && ( 0 < strpos( $_GET['state'], '|' ) ) ) { |
||
| 691 | list( $state, $nonce ) = explode( '|', $_GET['state'] ); |
||
| 692 | |||
| 693 | if ( wp_verify_nonce( $nonce, $state ) ) { |
||
| 694 | if ( 'sso-link-user' == $state ) { |
||
| 695 | $user = wp_get_current_user(); |
||
| 696 | update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID ); |
||
| 697 | add_filter( 'login_redirect', array( __CLASS__, 'profile_page_url' ) ); |
||
| 698 | } |
||
| 699 | } else { |
||
| 700 | wp_nonce_ays(); |
||
| 701 | } |
||
| 702 | } |
||
| 703 | |||
| 704 | if ( empty( $user ) ) { |
||
| 705 | $user = $this->get_user_by_wpcom_id( $user_data->ID ); |
||
| 706 | } |
||
| 707 | |||
| 708 | // If we don't have one by wpcom_user_id, try by the email? |
||
| 709 | if ( empty( $user ) && self::match_by_email() ) { |
||
| 710 | $user = get_user_by( 'email', $user_data->email ); |
||
| 711 | if ( $user ) { |
||
| 712 | update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID ); |
||
| 713 | } |
||
| 714 | } |
||
| 715 | |||
| 716 | // If we've still got nothing, create the user. |
||
| 717 | if ( empty( $user ) && ( get_option( 'users_can_register' ) || self::new_user_override() ) ) { |
||
| 718 | // If not matching by email we still need to verify the email does not exist |
||
| 719 | // or this blows up |
||
| 720 | /** |
||
| 721 | * If match_by_email is true, we know the email doesn't exist, as it would have |
||
| 722 | * been found in the first pass. If get_user_by( 'email' ) doesn't find the |
||
| 723 | * user, then we know that email is unused, so it's safe to add. |
||
| 724 | */ |
||
| 725 | if ( self::match_by_email() || ! get_user_by( 'email', $user_data->email ) ) { |
||
| 726 | $username = $user_data->login; |
||
| 727 | |||
| 728 | if ( username_exists( $username ) ) { |
||
| 729 | $username = $user_data->login . '_' . $user_data->ID; |
||
| 730 | } |
||
| 731 | |||
| 732 | $tries = 0; |
||
| 733 | while ( username_exists( $username ) ) { |
||
| 734 | $username = $user_data->login . '_' . $user_data->ID . '_' . mt_rand(); |
||
| 735 | if ( $tries++ >= 5 ) { |
||
| 736 | wp_die( __( "Error: Couldn't create suitable username.", 'jetpack' ) ); |
||
| 737 | } |
||
| 738 | } |
||
| 739 | |||
| 740 | $password = wp_generate_password( 20 ); |
||
| 741 | $user_id = wp_create_user( $username, $password, $user_data->email ); |
||
| 742 | $user = get_userdata( $user_id ); |
||
| 743 | |||
| 744 | $user->display_name = $user_data->display_name; |
||
| 745 | $user->first_name = $user_data->first_name; |
||
| 746 | $user->last_name = $user_data->last_name; |
||
| 747 | $user->url = $user_data->url; |
||
| 748 | $user->description = $user_data->description; |
||
| 749 | wp_update_user( $user ); |
||
| 750 | |||
| 751 | update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID ); |
||
| 752 | } else { |
||
| 753 | $this->user_data = $user_data; |
||
| 754 | // do_action( 'wp_login_failed', $user_data->login ); |
||
| 755 | add_action( 'login_message', array( $this, 'error_msg_email_already_exists' ) ); |
||
| 756 | return; |
||
| 757 | } |
||
| 758 | } |
||
| 759 | |||
| 760 | /** |
||
| 761 | * Fires after we got login information from WordPress.com. |
||
| 762 | * |
||
| 763 | * @module sso |
||
| 764 | * |
||
| 765 | * @since 2.6.0 |
||
| 766 | * |
||
| 767 | * @param array $user WordPress.com User information. |
||
| 768 | * @param object $user_data User Login information. |
||
| 769 | */ |
||
| 770 | do_action( 'jetpack_sso_handle_login', $user, $user_data ); |
||
| 771 | |||
| 772 | if ( $user ) { |
||
| 773 | // Cache the user's details, so we can present it back to them on their user screen |
||
| 774 | update_user_meta( $user->ID, 'wpcom_user_data', $user_data ); |
||
| 775 | |||
| 776 | $remember = false; |
||
| 777 | View Code Duplication | if ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) { |
|
| 778 | $remember = true; |
||
| 779 | // And then purge it |
||
| 780 | setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN ); |
||
| 781 | } |
||
| 782 | /** |
||
| 783 | * Filter the remember me value. |
||
| 784 | * |
||
| 785 | * @module sso |
||
| 786 | * |
||
| 787 | * @since 2.8.0 |
||
| 788 | * |
||
| 789 | * @param bool $remember Is the remember me option checked? |
||
| 790 | */ |
||
| 791 | $remember = apply_filters( 'jetpack_remember_login', $remember ); |
||
| 792 | wp_set_auth_cookie( $user->ID, $remember ); |
||
| 793 | |||
| 794 | /** This filter is documented in core/src/wp-includes/user.php */ |
||
| 795 | do_action( 'wp_login', $user->user_login, $user ); |
||
| 796 | |||
| 797 | $_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( $_REQUEST['redirect_to'] ) : ''; |
||
| 798 | $redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : self::profile_page_url(); |
||
| 799 | |||
| 800 | // If we have a saved redirect to request in a cookie |
||
| 801 | View Code Duplication | if ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) { |
|
| 802 | // Set that as the requested redirect to |
||
| 803 | $redirect_to = $_request_redirect_to = esc_url_raw( $_COOKIE['jetpack_sso_redirect_to'] ); |
||
| 804 | // And then purge it |
||
| 805 | setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN ); |
||
| 806 | } |
||
| 807 | |||
| 808 | if ( ! Jetpack::is_user_connected( $user->ID ) ) { |
||
| 809 | $calypso_env = ! empty( $_GET['calypso_env'] ) |
||
| 810 | ? sanitize_key( $_GET['calypso_env'] ) |
||
| 811 | : ''; |
||
| 812 | |||
| 813 | wp_safe_redirect( |
||
| 814 | add_query_arg( |
||
| 815 | array( |
||
| 816 | 'redirect_to' => $redirect_to, |
||
| 817 | 'request_redirect_to' => $_request_redirect_to, |
||
| 818 | 'calypso_env' => $calypso_env, |
||
| 819 | 'jetpack-sso-auth-redirect' => '1', |
||
| 820 | ), |
||
| 821 | admin_url() |
||
| 822 | ) |
||
| 823 | ); |
||
| 824 | exit; |
||
|
0 ignored issues
–
show
The method
handle_login() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an Loading history...
|
|||
| 825 | } |
||
| 826 | |||
| 827 | wp_safe_redirect( |
||
| 828 | /** This filter is documented in core/src/wp-login.php */ |
||
| 829 | apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user ) |
||
| 830 | ); |
||
| 831 | exit; |
||
| 832 | } |
||
| 833 | |||
| 834 | $this->user_data = $user_data; |
||
| 835 | /** This filter is documented in core/src/wp-includes/pluggable.php */ |
||
| 836 | do_action( 'wp_login_failed', $user_data->login ); |
||
| 837 | add_action( 'login_message', array( $this, 'cant_find_user' ) ); |
||
| 838 | } |
||
| 839 | |||
| 840 | static function profile_page_url() { |
||
| 841 | return admin_url( 'profile.php' ); |
||
| 842 | } |
||
| 843 | |||
| 844 | static function match_by_email() { |
||
| 845 | $match_by_email = ( 1 == get_option( 'jetpack_sso_match_by_email', true ) ) ? true: false; |
||
| 846 | $match_by_email = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : $match_by_email; |
||
| 847 | |||
| 848 | /** |
||
| 849 | * Link the local account to an account on WordPress.com using the same email address. |
||
| 850 | * |
||
| 851 | * @module sso |
||
| 852 | * |
||
| 853 | * @since 2.6.0 |
||
| 854 | * |
||
| 855 | * @param bool $match_by_email Should we link the local account to an account on WordPress.com using the same email address. Default to false. |
||
| 856 | */ |
||
| 857 | return apply_filters( 'jetpack_sso_match_by_email', $match_by_email ); |
||
| 858 | } |
||
| 859 | |||
| 860 | static function new_user_override() { |
||
| 861 | $new_user_override = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false; |
||
| 862 | |||
| 863 | /** |
||
| 864 | * Allow users to register on your site with a WordPress.com account, even though you disallow normal registrations. |
||
| 865 | * |
||
| 866 | * @module sso |
||
| 867 | * |
||
| 868 | * @since 2.6.0 |
||
| 869 | * |
||
| 870 | * @param bool $new_user_override Allow users to register on your site with a WordPress.com account. Default to false. |
||
| 871 | */ |
||
| 872 | return apply_filters( 'jetpack_sso_new_user_override', $new_user_override ); |
||
| 873 | } |
||
| 874 | |||
| 875 | function allowed_redirect_hosts( $hosts ) { |
||
| 876 | if ( empty( $hosts ) ) { |
||
| 877 | $hosts = array(); |
||
| 878 | } |
||
| 879 | $hosts[] = 'wordpress.com'; |
||
| 880 | $hosts[] = 'jetpack.wordpress.com'; |
||
| 881 | |||
| 882 | return array_unique( $hosts ); |
||
| 883 | } |
||
| 884 | |||
| 885 | /** |
||
| 886 | * Builds the "Login to WordPress.com" button that is displayed on the login page as well as user profile page. |
||
| 887 | * |
||
| 888 | * @param array $args An array of arguments to add to the SSO URL. |
||
| 889 | * @param boolean $is_primary Should the button have the `button-primary` class? |
||
| 890 | * @return string Returns the HTML markup for the button. |
||
| 891 | */ |
||
| 892 | function build_sso_button( $args = array(), $is_primary = false ) { |
||
| 893 | $url = $this->build_sso_button_url( $args ); |
||
| 894 | $classes = $is_primary |
||
| 895 | ? 'jetpack-sso button button-primary' |
||
| 896 | : 'jetpack-sso button'; |
||
| 897 | |||
| 898 | return sprintf( |
||
| 899 | '<a href="%1$s" class="%2$s">%3$s</a>', |
||
| 900 | esc_url( $url ), |
||
| 901 | $classes, |
||
| 902 | esc_html__( 'Log in with WordPress.com', 'jetpack' ) |
||
| 903 | ); |
||
| 904 | } |
||
| 905 | |||
| 906 | /** |
||
| 907 | * Builds a URL with `jetpack-sso` action and option args which is used to setup SSO. |
||
| 908 | * |
||
| 909 | * @param array $args An array of arguments to add to the SSO URL. |
||
| 910 | * @return string The URL used for SSO. |
||
| 911 | */ |
||
| 912 | function build_sso_button_url( $args = array() ) { |
||
| 913 | $defaults = array( |
||
| 914 | 'action' => 'jetpack-sso', |
||
| 915 | ); |
||
| 916 | |||
| 917 | $args = wp_parse_args( $args, $defaults ); |
||
| 918 | |||
| 919 | if ( ! empty( $_GET['redirect_to'] ) ) { |
||
| 920 | $args['redirect_to'] = esc_url_raw( $_GET['redirect_to'] ); |
||
| 921 | } |
||
| 922 | |||
| 923 | return add_query_arg( $args, wp_login_url() ); |
||
| 924 | } |
||
| 925 | |||
| 926 | /** |
||
| 927 | * Retrieves a WordPress.com SSO URL with appropriate query parameters or dies. |
||
| 928 | * |
||
| 929 | * @param boolean $reauth Should the user be forced to reauthenticate on WordPress.com? |
||
| 930 | * @param array $args Optional query parameters. |
||
| 931 | * @return string The WordPress.com SSO URL. |
||
| 932 | */ |
||
| 933 | function get_sso_url_or_die( $reauth = false, $args = array() ) { |
||
| 934 | if ( empty( $reauth ) ) { |
||
| 935 | $sso_redirect = $this->build_sso_url( $args ); |
||
| 936 | } else { |
||
| 937 | self::clear_wpcom_profile_cookies(); |
||
| 938 | $sso_redirect = $this->build_reauth_and_sso_url( $args ); |
||
| 939 | } |
||
| 940 | |||
| 941 | // If there was an error retrieving the SSO URL, then error. |
||
| 942 | if ( is_wp_error( $sso_redirect ) ) { |
||
| 943 | wp_die( sprintf( '%s: %s', $sso_redirect->get_error_code(), $sso_redirect->get_error_message() ) ); |
||
|
0 ignored issues
–
show
|
|||
| 944 | } |
||
| 945 | |||
| 946 | return $sso_redirect; |
||
| 947 | } |
||
| 948 | |||
| 949 | /** |
||
| 950 | * Build WordPress.com SSO URL with appropriate query parameters. |
||
| 951 | * |
||
| 952 | * @param array $args Optional query parameters. |
||
| 953 | * @return string WordPress.com SSO URL |
||
| 954 | */ |
||
| 955 | function build_sso_url( $args = array() ) { |
||
| 956 | $sso_nonce = ! empty( $args['sso_nonce'] ) ? $args['sso_nonce'] : self::request_initial_nonce(); |
||
| 957 | $defaults = array( |
||
| 958 | 'action' => 'jetpack-sso', |
||
| 959 | 'site_id' => Jetpack_Options::get_option( 'id' ), |
||
| 960 | 'sso_nonce' => $sso_nonce, |
||
| 961 | ); |
||
| 962 | |||
| 963 | if ( isset( $_GET['state'] ) && check_admin_referer( $_GET['state'] ) ) { |
||
| 964 | $defaults['state'] = rawurlencode( $_GET['state'] . '|' . $_GET['_wpnonce'] ); |
||
| 965 | } |
||
| 966 | |||
| 967 | $args = wp_parse_args( $args, $defaults ); |
||
| 968 | |||
| 969 | if ( is_wp_error( $args['sso_nonce'] ) ) { |
||
| 970 | return $args['sso_nonce']; |
||
| 971 | } |
||
| 972 | |||
| 973 | return add_query_arg( $args, 'https://wordpress.com/wp-login.php' ); |
||
| 974 | } |
||
| 975 | |||
| 976 | /** |
||
| 977 | * Build WordPress.com SSO URL with appropriate query parameters, |
||
| 978 | * including the parameters necessary to force the user to reauthenticate |
||
| 979 | * on WordPress.com. |
||
| 980 | * |
||
| 981 | * @param array $args Optional query parameters. |
||
| 982 | * @return string WordPress.com SSO URL |
||
| 983 | */ |
||
| 984 | function build_reauth_and_sso_url( $args = array() ) { |
||
| 985 | $sso_nonce = ! empty( $args['sso_nonce'] ) ? $args['sso_nonce'] : self::request_initial_nonce(); |
||
| 986 | $redirect = $this->build_sso_url( array( 'force_auth' => '1', 'sso_nonce' => $sso_nonce ) ); |
||
| 987 | |||
| 988 | if ( is_wp_error( $redirect ) ) { |
||
| 989 | return $redirect; |
||
| 990 | } |
||
| 991 | |||
| 992 | $defaults = array( |
||
| 993 | 'action' => 'jetpack-sso', |
||
| 994 | 'site_id' => Jetpack_Options::get_option( 'id' ), |
||
| 995 | 'sso_nonce' => $sso_nonce, |
||
| 996 | 'reauth' => '1', |
||
| 997 | 'redirect_to' => urlencode( $redirect ), |
||
| 998 | ); |
||
| 999 | |||
| 1000 | $args = wp_parse_args( $args, $defaults ); |
||
| 1001 | |||
| 1002 | if ( is_wp_error( $args['sso_nonce'] ) ) { |
||
| 1003 | return $args['sso_nonce']; |
||
| 1004 | } |
||
| 1005 | |||
| 1006 | return add_query_arg( $args, 'https://wordpress.com/wp-login.php' ); |
||
| 1007 | } |
||
| 1008 | |||
| 1009 | /** |
||
| 1010 | * Determines local user associated with a given WordPress.com user ID. |
||
| 1011 | * |
||
| 1012 | * @since 2.6.0 |
||
| 1013 | * |
||
| 1014 | * @param int $wpcom_user_id User ID from WordPress.com |
||
| 1015 | * @return object Local user object if found, null if not. |
||
| 1016 | */ |
||
| 1017 | static function get_user_by_wpcom_id( $wpcom_user_id ) { |
||
| 1018 | $user_query = new WP_User_Query( array( |
||
| 1019 | 'meta_key' => 'wpcom_user_id', |
||
| 1020 | 'meta_value' => intval( $wpcom_user_id ), |
||
| 1021 | 'number' => 1, |
||
| 1022 | ) ); |
||
| 1023 | |||
| 1024 | $users = $user_query->get_results(); |
||
| 1025 | return $users ? array_shift( $users ) : null; |
||
| 1026 | } |
||
| 1027 | |||
| 1028 | /** |
||
| 1029 | * Error message displayed on the login form when two step is required and |
||
| 1030 | * the user's account on WordPress.com does not have two step enabled. |
||
| 1031 | * |
||
| 1032 | * @since 2.7 |
||
| 1033 | * @param string $message |
||
| 1034 | * @return string |
||
| 1035 | **/ |
||
| 1036 | public function error_msg_enable_two_step( $message ) { |
||
| 1037 | $err = __( sprintf( 'This site requires two step authentication be enabled for your user account on WordPress.com. Please visit the <a href="%1$s" target="_blank"> Security Settings</a> page to enable two step', 'https://wordpress.com/me/security/two-step' ) , 'jetpack' ); |
||
| 1038 | |||
| 1039 | $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err ); |
||
| 1040 | |||
| 1041 | return $message; |
||
| 1042 | } |
||
| 1043 | |||
| 1044 | /** |
||
| 1045 | * Error message displayed when the user tries to SSO, but match by email |
||
| 1046 | * is off and they already have an account with their email address on |
||
| 1047 | * this site. |
||
| 1048 | * |
||
| 1049 | * @param string $message |
||
| 1050 | * @return string |
||
| 1051 | */ |
||
| 1052 | public function error_msg_email_already_exists( $message ) { |
||
| 1053 | $err = __( sprintf( 'You already have an account on this site. Please visit your <a href="%1$s">profile page</a> page to link your account to WordPress.com!', admin_url( 'profile.php' ) ) , 'jetpack' ); |
||
| 1054 | |||
| 1055 | $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err ); |
||
| 1056 | |||
| 1057 | return $message; |
||
| 1058 | } |
||
| 1059 | |||
| 1060 | /** |
||
| 1061 | * Message displayed when the site admin has disabled the default WordPress |
||
| 1062 | * login form in Settings > General > Single Sign On |
||
| 1063 | * |
||
| 1064 | * @since 2.7 |
||
| 1065 | * @param string $message |
||
| 1066 | * @return string |
||
| 1067 | **/ |
||
| 1068 | public function msg_login_by_jetpack( $message ) { |
||
| 1069 | |||
| 1070 | $msg = __( sprintf( 'Jetpack authenticates through WordPress.com — to log in, enter your WordPress.com username and password, or <a href="%1$s" target="_blank">visit WordPress.com</a> to create a free account now.', 'http://wordpress.com/signup' ) , 'jetpack' ); |
||
| 1071 | |||
| 1072 | /** |
||
| 1073 | * Filter the message displayed when the default WordPress login form is disabled. |
||
| 1074 | * |
||
| 1075 | * @module sso |
||
| 1076 | * |
||
| 1077 | * @since 2.8.0 |
||
| 1078 | * |
||
| 1079 | * @param string $msg Disclaimer when default WordPress login form is disabled. |
||
| 1080 | */ |
||
| 1081 | $msg = apply_filters( 'jetpack_sso_disclaimer_message', $msg ); |
||
| 1082 | |||
| 1083 | $message .= sprintf( '<p class="message">%s</p>', $msg ); |
||
| 1084 | return $message; |
||
| 1085 | } |
||
| 1086 | |||
| 1087 | /** |
||
| 1088 | * Error message displayed on the login form when the user attempts |
||
| 1089 | * to post to the login form and it is disabled. |
||
| 1090 | * |
||
| 1091 | * @since 2.8 |
||
| 1092 | * @param string $message |
||
| 1093 | * @param string |
||
| 1094 | **/ |
||
| 1095 | public function error_msg_login_method_not_allowed( $message ) { |
||
| 1096 | $err = __( 'Login method not allowed' , 'jetpack' ); |
||
| 1097 | $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err ); |
||
| 1098 | |||
| 1099 | return $message; |
||
| 1100 | } |
||
| 1101 | function cant_find_user( $message ) { |
||
| 1102 | if ( self::match_by_email() ) { |
||
| 1103 | $err_format = __( 'We couldn\'t find an account with the email <strong><code>%1$s</code></strong> to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that <strong><code>%1$s</code></strong> is configured as the email address, or that you have connected to WordPress.com on your profile page.', 'jetpack' ); |
||
| 1104 | } else { |
||
| 1105 | $err_format = __( 'We couldn\'t find any account on <strong>%2$s</strong> that is linked to your WordPress.com account to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that you have connected to WordPress.com on your profile page.', 'jetpack' ); |
||
| 1106 | } |
||
| 1107 | $err = sprintf( $err_format, $this->user_data->email, get_bloginfo( 'name' ) ); |
||
| 1108 | $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err ); |
||
| 1109 | return $message; |
||
| 1110 | } |
||
| 1111 | |||
| 1112 | /** |
||
| 1113 | * When jetpack-sso-auth-redirect query parameter is set, will redirect user to |
||
| 1114 | * WordPress.com authorization flow. |
||
| 1115 | * |
||
| 1116 | * We redirect here instead of in handle_login() because Jetpack::init()->build_connect_url |
||
| 1117 | * calls menu_page_url() which doesn't work properly until admin menus are registered. |
||
| 1118 | */ |
||
| 1119 | function maybe_authorize_user_after_sso() { |
||
| 1120 | if ( empty( $_GET['jetpack-sso-auth-redirect'] ) ) { |
||
| 1121 | return; |
||
| 1122 | } |
||
| 1123 | |||
| 1124 | $redirect_to = ! empty( $_GET['redirect_to'] ) ? esc_url_raw( $_GET['redirect_to'] ) : admin_url(); |
||
| 1125 | $request_redirect_to = ! empty( $_GET['request_redirect_to'] ) ? esc_url_raw( $_GET['request_redirect_to'] ) : $redirect_to; |
||
| 1126 | |||
| 1127 | /** This filter is documented in core/src/wp-login.php */ |
||
| 1128 | $redirect_after_auth = apply_filters( 'login_redirect', $redirect_to, $request_redirect_to, wp_get_current_user() ); |
||
| 1129 | |||
| 1130 | /** |
||
| 1131 | * Since we are passing this redirect to WordPress.com and therefore can not use wp_safe_redirect(), |
||
| 1132 | * let's sanitize it here to make sure it's safe. If the redirect is not safe, then use admin_url(). |
||
| 1133 | */ |
||
| 1134 | $redirect_after_auth = wp_sanitize_redirect( $redirect_after_auth ); |
||
| 1135 | $redirect_after_auth = wp_validate_redirect( $redirect_after_auth, admin_url() ); |
||
| 1136 | |||
| 1137 | /** |
||
| 1138 | * Return the raw connect URL with our redirect and attribute connection to SSO. |
||
| 1139 | */ |
||
| 1140 | $connect_url = Jetpack::init()->build_connect_url( true, $redirect_after_auth, 'sso' ); |
||
| 1141 | |||
| 1142 | add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) ); |
||
| 1143 | wp_safe_redirect( $connect_url ); |
||
| 1144 | exit; |
||
|
0 ignored issues
–
show
The method
maybe_authorize_user_after_sso() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an Loading history...
|
|||
| 1145 | } |
||
| 1146 | |||
| 1147 | /** |
||
| 1148 | * Cache user's display name and Gravatar so it can be displayed on the login screen. These cookies are |
||
| 1149 | * stored when the user logs out, and then deleted when the user logs in. |
||
| 1150 | */ |
||
| 1151 | function store_wpcom_profile_cookies_on_logout() { |
||
| 1152 | if ( ! Jetpack::is_user_connected( get_current_user_id() ) ) { |
||
| 1153 | return; |
||
| 1154 | } |
||
| 1155 | |||
| 1156 | $user_data = $this->get_user_data( get_current_user_id() ); |
||
| 1157 | if ( ! $user_data ) { |
||
| 1158 | return; |
||
| 1159 | } |
||
| 1160 | |||
| 1161 | setcookie( |
||
| 1162 | 'jetpack_sso_wpcom_name_' . COOKIEHASH, |
||
| 1163 | $user_data->display_name, |
||
| 1164 | time() + WEEK_IN_SECONDS, |
||
| 1165 | COOKIEPATH, |
||
| 1166 | COOKIE_DOMAIN |
||
| 1167 | ); |
||
| 1168 | |||
| 1169 | setcookie( |
||
| 1170 | 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH, |
||
| 1171 | get_avatar_url( |
||
| 1172 | $user_data->email, |
||
| 1173 | array( 'size' => 72, 'default' => 'mystery' ) |
||
| 1174 | ), |
||
| 1175 | time() + WEEK_IN_SECONDS, |
||
| 1176 | COOKIEPATH, |
||
| 1177 | COOKIE_DOMAIN |
||
| 1178 | ); |
||
| 1179 | } |
||
| 1180 | |||
| 1181 | /** |
||
| 1182 | * Deal with user connections... |
||
| 1183 | */ |
||
| 1184 | function admin_init() { |
||
| 1185 | add_action( 'show_user_profile', array( $this, 'edit_profile_fields' ) ); // For their own profile |
||
| 1186 | add_action( 'edit_user_profile', array( $this, 'edit_profile_fields' ) ); // For folks editing others profiles |
||
| 1187 | |||
| 1188 | if ( isset( $_GET['jetpack_sso'] ) && 'purge' == $_GET['jetpack_sso'] && check_admin_referer( 'jetpack_sso_purge' ) ) { |
||
| 1189 | $user = wp_get_current_user(); |
||
| 1190 | // Remove the connection on the wpcom end. |
||
| 1191 | self::delete_connection_for_user( $user->ID ); |
||
| 1192 | // Clear it locally. |
||
| 1193 | delete_user_meta( $user->ID, 'wpcom_user_id' ); |
||
| 1194 | delete_user_meta( $user->ID, 'wpcom_user_data' ); |
||
| 1195 | // Forward back to the profile page. |
||
| 1196 | wp_safe_redirect( remove_query_arg( array( 'jetpack_sso', '_wpnonce' ) ) ); |
||
| 1197 | exit; |
||
|
0 ignored issues
–
show
The method
admin_init() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an Loading history...
|
|||
| 1198 | } |
||
| 1199 | } |
||
| 1200 | |||
| 1201 | /** |
||
| 1202 | * Determines if a local user is connected to WordPress.com |
||
| 1203 | * |
||
| 1204 | * @since 2.8 |
||
| 1205 | * @param integer $user_id - Local user id |
||
| 1206 | * @return boolean |
||
| 1207 | **/ |
||
| 1208 | public function is_user_connected( $user_id ) { |
||
| 1209 | return $this->get_user_data( $user_id ); |
||
| 1210 | } |
||
| 1211 | |||
| 1212 | /** |
||
| 1213 | * Retrieves a user's WordPress.com data |
||
| 1214 | * |
||
| 1215 | * @since 2.8 |
||
| 1216 | * @param integer $user_id - Local user id |
||
| 1217 | * @return mixed null or stdClass |
||
| 1218 | **/ |
||
| 1219 | public function get_user_data( $user_id ) { |
||
| 1220 | return get_user_meta( $user_id, 'wpcom_user_data', true ); |
||
| 1221 | } |
||
| 1222 | |||
| 1223 | function edit_profile_fields( $user ) { |
||
| 1224 | ?> |
||
| 1225 | |||
| 1226 | <h3 id="single-sign-on"><?php _e( 'Single Sign On', 'jetpack' ); ?></h3> |
||
| 1227 | <p><?php _e( 'Connecting with Single Sign On enables you to log in via your WordPress.com account.', 'jetpack' ); ?></p> |
||
| 1228 | |||
| 1229 | <?php if ( $this->is_user_connected( $user->ID ) ) : /* If the user is currently connected... */ ?> |
||
| 1230 | <?php $user_data = $this->get_user_data( $user->ID ); ?> |
||
| 1231 | <table class="form-table jetpack-sso-form-table"> |
||
| 1232 | <tbody> |
||
| 1233 | <tr> |
||
| 1234 | <td> |
||
| 1235 | <div class="profile-card"> |
||
| 1236 | <?php echo get_avatar( $user_data->email ); ?> |
||
| 1237 | <p class="connected"><strong><?php _e( 'Connected', 'jetpack' ); ?></strong></p> |
||
| 1238 | <p><?php echo esc_html( $user_data->login ); ?></p> |
||
| 1239 | <span class="two_step"> |
||
| 1240 | <?php |
||
| 1241 | if ( $user_data->two_step_enabled ) { |
||
| 1242 | ?> <p class="enabled"><a href="https://wordpress.com/me/security/two-step" target="_blank"><?php _e( 'Two-Step Authentication Enabled', 'jetpack' ); ?></a></p> <?php |
||
| 1243 | } else { |
||
| 1244 | ?> <p class="disabled"><a href="https://wordpress.com/me/security/two-step" target="_blank"><?php _e( 'Two-Step Authentication Disabled', 'jetpack' ); ?></a></p> <?php |
||
| 1245 | } |
||
| 1246 | ?> |
||
| 1247 | </span> |
||
| 1248 | |||
| 1249 | </div> |
||
| 1250 | <p><a class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'jetpack_sso', 'purge' ), 'jetpack_sso_purge' ) ); ?>"><?php _e( 'Unlink This Account', 'jetpack' ); ?></a></p> |
||
| 1251 | </td> |
||
| 1252 | </tr> |
||
| 1253 | </tbody> |
||
| 1254 | </table> |
||
| 1255 | <?php elseif ( get_current_user_id() == $user->ID && Jetpack::is_user_connected( $user->ID ) ) : ?> |
||
| 1256 | |||
| 1257 | <?php echo $this->build_sso_button( 'state=sso-link-user&_wpnonce=' . wp_create_nonce( 'sso-link-user' ) ); ?> |
||
|
0 ignored issues
–
show
'state=sso-link-user&_wp..._nonce('sso-link-user') is of type string, but the function expects a array.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 1258 | |||
| 1259 | <?php else : ?> |
||
| 1260 | |||
| 1261 | <p><?php esc_html_e( wptexturize( __( "If you don't have a WordPress.com account yet, you can sign up for free in just a few seconds.", 'jetpack' ) ) ); ?></p> |
||
| 1262 | <a href="<?php echo Jetpack::init()->build_connect_url( false, get_edit_profile_url( get_current_user_id() ) . '#single-sign-on' ); ?>" class="button button-connector" id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a> |
||
| 1263 | |||
| 1264 | <?php endif; |
||
| 1265 | } |
||
| 1266 | } |
||
| 1267 | |||
| 1268 | Jetpack_SSO::get_instance(); |
||
| 1269 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exitexpression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.