jetpack_force_logout ) {
delete_user_meta( $current_user->ID, 'jetpack_force_logout' );
self::delete_connection_for_user( $current_user->ID );
wp_logout();
wp_safe_redirect( wp_login_url() );
exit;
}
}
/**
* Adds additional methods the WordPress xmlrpc API for handling SSO specific features
*
* @param array $methods
* @return array
**/
public function xmlrpc_methods( $methods ) {
$methods['jetpack.userDisconnect'] = array( $this, 'xmlrpc_user_disconnect' );
return $methods;
}
/**
* Marks a user's profile for disconnect from WordPress.com and forces a logout
* the next time the user visits the site.
**/
public function xmlrpc_user_disconnect( $user_id ) {
$user_query = new WP_User_Query(
array(
'meta_key' => 'wpcom_user_id',
'meta_value' => $user_id,
)
);
$user = $user_query->get_results();
$user = $user[0];
if ( $user instanceof WP_User ) {
$user = wp_set_current_user( $user->ID );
update_user_meta( $user->ID, 'jetpack_force_logout', '1' );
self::delete_connection_for_user( $user->ID );
return true;
}
return false;
}
/**
* Enqueues scripts and styles necessary for SSO login.
*/
public function login_enqueue_scripts() {
global $action;
if ( ! Jetpack_SSO_Helpers::display_sso_form_for_action( $action ) ) {
return;
}
if ( is_rtl() ) {
wp_enqueue_style( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login-rtl.css', JETPACK__PLUGIN_FILE ), array( 'login', 'genericons' ), JETPACK__VERSION );
} else {
wp_enqueue_style( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.css', JETPACK__PLUGIN_FILE ), array( 'login', 'genericons' ), JETPACK__VERSION );
}
wp_enqueue_script( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.js', JETPACK__PLUGIN_FILE ), array( 'jquery' ), JETPACK__VERSION );
}
/**
* Adds Jetpack SSO classes to login body
*
* @param array $classes Array of classes to add to body tag
* @return array Array of classes to add to body tag
*/
public function login_body_class( $classes ) {
global $action;
if ( ! Jetpack_SSO_Helpers::display_sso_form_for_action( $action ) ) {
return $classes;
}
// Always add the jetpack-sso class so that we can add SSO specific styling even when the SSO form isn't being displayed.
$classes[] = 'jetpack-sso';
if ( ! Jetpack::is_staging_site() ) {
/**
* Should we show the SSO login form?
*
* $_GET['jetpack-sso-default-form'] is used to provide a fallback in case JavaScript is not enabled.
*
* The default_to_sso_login() method allows us to dynamically decide whether we show the SSO login form or not.
* The SSO module uses the method to display the default login form if we can not find a user to log in via SSO.
* But, the method could be filtered by a site admin to always show the default login form if that is preferred.
*/
if ( empty( $_GET['jetpack-sso-show-default-form'] ) && Jetpack_SSO_Helpers::show_sso_login() ) {
$classes[] = 'jetpack-sso-form-display';
}
}
return $classes;
}
public function print_inline_admin_css() {
?>
General > Single Sign On that allows users to
* turn off the login form on wp-login.php
*
* @since 2.7
**/
public function register_settings() {
add_settings_section(
'jetpack_sso_settings',
__( 'Single Sign On' , 'jetpack' ),
'__return_false',
'jetpack-sso'
);
/*
* Settings > General > Single Sign On
* Require two step authentication
*/
register_setting(
'jetpack-sso',
'jetpack_sso_require_two_step',
array( $this, 'validate_jetpack_sso_require_two_step' )
);
add_settings_field(
'jetpack_sso_require_two_step',
'', // __( 'Require Two-Step Authentication' , 'jetpack' ),
array( $this, 'render_require_two_step' ),
'jetpack-sso',
'jetpack_sso_settings'
);
/*
* Settings > General > Single Sign On
*/
register_setting(
'jetpack-sso',
'jetpack_sso_match_by_email',
array( $this, 'validate_jetpack_sso_match_by_email' )
);
add_settings_field(
'jetpack_sso_match_by_email',
'', // __( 'Match by Email' , 'jetpack' ),
array( $this, 'render_match_by_email' ),
'jetpack-sso',
'jetpack_sso_settings'
);
}
/**
* Builds the display for the checkbox allowing user to require two step
* auth be enabled on WordPress.com accounts before login. Displays in Settings > General
*
* @since 2.7
**/
public function render_require_two_step() {
?>
General
*
* @since 2.7
* @return boolean
**/
public function validate_jetpack_sso_require_two_step( $input ) {
return ( ! empty( $input ) ) ? 1 : 0;
}
/**
* Builds the display for the checkbox allowing the user to allow matching logins by email
* Displays in Settings > General
*
* @since 2.9
**/
public function render_match_by_email() {
?>
General
*
* @since 2.9
* @return boolean
**/
public function validate_jetpack_sso_match_by_email( $input ) {
return ( ! empty( $input ) ) ? 1 : 0;
}
/**
* Checks to determine if the user wants to login on wp-login
*
* This function mostly exists to cover the exceptions to login
* that may exist as other parameters to $_GET[action] as $_GET[action]
* does not have to exist. By default WordPress assumes login if an action
* is not set, however this may not be true, as in the case of logout
* where $_GET[loggedout] is instead set
*
* @return boolean
**/
private function wants_to_login() {
$wants_to_login = false;
// Cover default WordPress behavior
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
// And now the exceptions
$action = isset( $_GET['loggedout'] ) ? 'loggedout' : $action;
if ( Jetpack_SSO_Helpers::display_sso_form_for_action( $action ) ) {
$wants_to_login = true;
}
return $wants_to_login;
}
function login_init() {
global $action;
if ( Jetpack_SSO_Helpers::should_hide_login_form() ) {
/**
* Since the default authenticate filters fire at priority 20 for checking username and password,
* let's fire at priority 30. wp_authenticate_spam_check is fired at priority 99, but since we return a
* WP_Error in disable_default_login_form, then we won't trigger spam processing logic.
*/
add_filter( 'authenticate', array( 'Jetpack_SSO_Notices', 'disable_default_login_form' ), 30 );
/**
* Filter the display of the disclaimer message appearing when default WordPress login form is disabled.
*
* @module sso
*
* @since 2.8.0
*
* @param bool true Should the disclaimer be displayed. Default to true.
*/
$display_sso_disclaimer = apply_filters( 'jetpack_sso_display_disclaimer', true );
if ( $display_sso_disclaimer ) {
add_filter( 'login_message', array( 'Jetpack_SSO_Notices', 'msg_login_by_jetpack' ) );
}
}
if ( 'jetpack-sso' === $action ) {
if ( isset( $_GET['result'], $_GET['user_id'], $_GET['sso_nonce'] ) && 'success' == $_GET['result'] ) {
$this->handle_login();
$this->display_sso_login_form();
} else {
if ( Jetpack::is_staging_site() ) {
add_filter( 'login_message', array( 'Jetpack_SSO_Notices', 'sso_not_allowed_in_staging' ) );
} else {
// Is it wiser to just use wp_redirect than do this runaround to wp_safe_redirect?
add_filter( 'allowed_redirect_hosts', array( 'Jetpack_SSO_Helpers', 'allowed_redirect_hosts' ) );
$reauth = ! empty( $_GET['force_reauth'] );
$sso_url = $this->get_sso_url_or_die( $reauth );
JetpackTracking::record_user_event( 'sso_login_redirect_success' );
wp_safe_redirect( $sso_url );
exit;
}
}
} else if ( Jetpack_SSO_Helpers::display_sso_form_for_action( $action ) ) {
// Save cookies so we can handle redirects after SSO
$this->save_cookies();
/**
* Check to see if the site admin wants to automagically forward the user
* to the WordPress.com login page AND that the request to wp-login.php
* is not something other than login (Like logout!)
*/
if ( Jetpack_SSO_Helpers::bypass_login_forward_wpcom() && $this->wants_to_login() ) {
add_filter( 'allowed_redirect_hosts', array( 'Jetpack_SSO_Helpers', 'allowed_redirect_hosts' ) );
$reauth = ! empty( $_GET['force_reauth'] );
$sso_url = $this->get_sso_url_or_die( $reauth );
JetpackTracking::record_user_event( 'sso_login_redirect_bypass_success' );
wp_safe_redirect( $sso_url );
exit;
}
$this->display_sso_login_form();
}
}
/**
* Ensures that we can get a nonce from WordPress.com via XML-RPC before setting
* up the hooks required to display the SSO form.
*/
public function display_sso_login_form() {
add_filter( 'login_body_class', array( $this, 'login_body_class' ) );
add_action( 'login_head', array( $this, 'print_inline_admin_css' ) );
if ( Jetpack::is_staging_site() ) {
add_filter( 'login_message', array( 'Jetpack_SSO_Notices', 'sso_not_allowed_in_staging' ) );
return;
}
$sso_nonce = self::request_initial_nonce();
if ( is_wp_error( $sso_nonce ) ) {
return;
}
add_action( 'login_form', array( $this, 'login_form' ) );
add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts' ) );
}
/**
* Conditionally save the redirect_to url as a cookie.
*
* @since 4.6.0 Renamed to save_cookies from maybe_save_redirect_cookies
*/
public static function save_cookies() {
if ( headers_sent() ) {
return new WP_Error( 'headers_sent', __( 'Cannot deal with cookie redirects, as headers are already sent.', 'jetpack' ) );
}
setcookie(
'jetpack_sso_original_request',
esc_url_raw( set_url_scheme( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ),
time() + HOUR_IN_SECONDS,
COOKIEPATH,
COOKIE_DOMAIN,
is_ssl(),
true
);
if ( ! empty( $_GET['redirect_to'] ) ) {
// If we have something to redirect to
$url = esc_url_raw( $_GET['redirect_to'] );
setcookie( 'jetpack_sso_redirect_to', $url, time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true );
} elseif ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
// Otherwise, if it's already set, purge it.
setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
}
}
/**
* Outputs the Jetpack SSO button and description as well as the toggle link
* for switching between Jetpack SSO and default login.
*/
function login_form() {
$site_name = get_bloginfo( 'name' );
if ( ! $site_name ) {
$site_name = get_bloginfo( 'url' );
}
$display_name = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] )
? $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ]
: false;
$gravatar = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] )
? $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ]
: false;
?>