summaryrefslogtreecommitdiff
blob: f7c6eb9201fd2527f87d35669e6cfd0c5343d593 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
<?php

if ( ! class_exists( 'Jetpack_SSO_Helpers' ) ) :

/**
 * A collection of helper functions used in the SSO module.
 *
 * @since 4.1.0
 */
class Jetpack_SSO_Helpers {
	/**
	 * Determine if the login form should be hidden or not
	 *
	 * @return bool
	 **/
	static function should_hide_login_form() {
		/**
		 * Remove the default log in form, only leave the WordPress.com log in button.
		 *
		 * @module sso
		 *
		 * @since 3.1.0
		 *
		 * @param bool get_option( 'jetpack_sso_remove_login_form', false ) Should the default log in form be removed. Default to false.
		 */
		return (bool) apply_filters( 'jetpack_remove_login_form', get_option( 'jetpack_sso_remove_login_form', false ) );
	}

	/**
	 * Returns a boolean value for whether logging in by matching the WordPress.com user email to a
	 * Jetpack site user's email is allowed.
	 *
	 * @return bool
	 */
	static function match_by_email() {
		$match_by_email = ( 1 == get_option( 'jetpack_sso_match_by_email', true ) ) ? true: false;
		$match_by_email = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : $match_by_email;

		/**
		 * Link the local account to an account on WordPress.com using the same email address.
		 *
		 * @module sso
		 *
		 * @since 2.6.0
		 *
		 * @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.
		 */
		return (bool) apply_filters( 'jetpack_sso_match_by_email', $match_by_email );
	}

	/**
	 * Returns a boolean for whether users are allowed to register on the Jetpack site with SSO,
	 * even though the site disallows normal registrations.
	 *
	 * @return bool
	 */
	static function new_user_override( $user_data = null ) {
		$new_user_override = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false;

		/**
		 * Allow users to register on your site with a WordPress.com account, even though you disallow normal registrations. 
		 * If you return a string that corresponds to a user role, the user will be given that role.
		 *
		 * @module sso
		 *
		 * @since 2.6.0
		 * @since 4.6   $user_data object is now passed to the jetpack_sso_new_user_override filter
		 *
		 * @param bool        $new_user_override Allow users to register on your site with a WordPress.com account. Default to false.
		 * @param object|null $user_data         An object containing the user data returned from WordPress.com.
		 */
		$role = apply_filters( 'jetpack_sso_new_user_override', $new_user_override, $user_data );

		if ( $role ) {
			if ( is_string( $role ) && get_role( $role ) ) {
				return $role;
			} else {
				return get_option( 'default_role' );
			}
		}

		return false;
	}

	/**
	 * Returns a boolean value for whether two-step authentication is required for SSO.
	 *
	 * @since 4.1.0
	 *
	 * @return bool
	 */
	static function is_two_step_required() {
		/**
		 * Is it required to have 2-step authentication enabled on WordPress.com to use SSO?
		 *
		 * @module sso
		 *
		 * @since 2.8.0
		 *
		 * @param bool get_option( 'jetpack_sso_require_two_step' ) Does SSO require 2-step authentication?
		 */
		return (bool) apply_filters( 'jetpack_sso_require_two_step', get_option( 'jetpack_sso_require_two_step', false ) );
	}

	/**
	 * Returns a boolean for whether a user that is attempting to log in will be automatically
	 * redirected to WordPress.com to begin the SSO flow.
	 *
	 * @return bool
	 */
	static function bypass_login_forward_wpcom() {
		/**
		 * Redirect the site's log in form to WordPress.com's log in form.
		 *
		 * @module sso
		 *
		 * @since 3.1.0
		 *
		 * @param bool false Should the site's log in form be automatically forwarded to WordPress.com's log in form.
		 */
		return (bool) apply_filters( 'jetpack_sso_bypass_login_forward_wpcom', false );
	}

	/**
	 * Returns a boolean for whether the SSO login form should be displayed as the default
	 * when both the default and SSO login form allowed.
	 *
	 * @since 4.1.0
	 *
	 * @return bool
	 */
	static function show_sso_login() {
		if ( self::should_hide_login_form() ) {
			return true;
		}

		/**
		 * Display the SSO login form as the default when both the default and SSO login forms are enabled.
		 *
		 * @module sso
		 *
		 * @since 4.1.0
		 *
		 * @param bool true Should the SSO login form be displayed by default when the default login form is also enabled?
		 */
		return (bool) apply_filters( 'jetpack_sso_default_to_sso_login', true );
	}

	/**
	 * Returns a boolean for whether the two step required checkbox, displayed on the Jetpack admin page, should be disabled.
	 *
	 * @since 4.1.0
	 *
	 * @return bool
	 */
	static function is_require_two_step_checkbox_disabled() {
		return (bool) has_filter( 'jetpack_sso_require_two_step' );
	}

	/**
	 * Returns a boolean for whether the match by email checkbox, displayed on the Jetpack admin page, should be disabled.
	 *
	 * @since 4.1.0
	 *
	 * @return bool
	 */
	static function is_match_by_email_checkbox_disabled() {
		return defined( 'WPCC_MATCH_BY_EMAIL' ) || has_filter( 'jetpack_sso_match_by_email' );
	}

	/**
	 * Returns an array of hosts that SSO will redirect to.
	 *
	 * Instead of accessing JETPACK__API_BASE within the method directly, we set it as the
	 * default for $api_base due to restrictions with testing constants in our tests.
	 *
	 * @since 4.3.0
	 * @since 4.6.0 Added public-api.wordpress.com as an allowed redirect
	 *
	 * @param array $hosts
	 * @param string $api_base
	 *
	 * @return array
	 */
	static function allowed_redirect_hosts( $hosts, $api_base = JETPACK__API_BASE ) {
		if ( empty( $hosts ) ) {
			$hosts = array();
		}

		$hosts[] = 'wordpress.com';
		$hosts[] = 'jetpack.wordpress.com';
		$hosts[] = 'public-api.wordpress.com';

		if (
			( Jetpack::is_development_mode() || Jetpack::is_development_version() ) &&
			( false === strpos( $api_base, 'jetpack.wordpress.com/jetpack' ) )
		) {
			$base_url_parts = parse_url( esc_url_raw( $api_base ) );
			if ( $base_url_parts && ! empty( $base_url_parts[ 'host' ] ) ) {
				$hosts[] = $base_url_parts[ 'host' ];
			}
		}

		return array_unique( $hosts );
	}

	static function generate_user( $user_data ) {
		$username = $user_data->login;

		/**
		 * Determines how many times the SSO module can attempt to randomly generate a user.
		 *
		 * @module sso
		 *
		 * @since 4.3.2
		 *
		 * @param int 5 By default, SSO will attempt to random generate a user up to 5 times.
		 */
		$num_tries = intval( apply_filters( 'jetpack_sso_allowed_username_generate_retries', 5 ) );

		$tries = 0;
		while ( ( $exists = username_exists( $username ) ) && $tries++ < $num_tries ) {
			$username = $user_data->login . '_' . $user_data->ID . '_' . mt_rand();
		}

		if ( $exists ) {
			return false;
		}

		$password = wp_generate_password( 20 );
		$user_id  = wp_create_user( $username, $password, $user_data->email );
		$user     = get_userdata( $user_id );

		$user->display_name = $user_data->display_name;
		$user->first_name   = $user_data->first_name;
		$user->last_name    = $user_data->last_name;
		$user->url          = $user_data->url;
		$user->description  = $user_data->description;

		if ( isset( $user_data->role ) && $user_data->role ) {
			$user->role     = $user_data->role;
		}

		wp_update_user( $user );

		update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
		
		return $user;
	}

	static function extend_auth_cookie_expiration_for_sso() {
		/**
		 * Determines how long the auth cookie is valid for when a user logs in with SSO.
		 *
		 * @module sso
		 *
		 * @since 4.4.0
		 *
		 * @param int YEAR_IN_SECONDS
		 */
		return intval( apply_filters( 'jetpack_sso_auth_cookie_expirtation', YEAR_IN_SECONDS ) );
	}

	/**
	 * Determines if the SSO form should be displayed for the current action.
	 *
	 * @since 4.6.0
	 *
	 * @param string $action
	 *
	 * @return bool  Is SSO allowed for the current action?
	 */
	static function display_sso_form_for_action( $action ) {
		/**
		 * Allows plugins the ability to overwrite actions where the SSO form is allowed to be used.
		 *
		 * @module sso
		 *
		 * @since 4.6.0
		 *
		 * @param array $allowed_actions_for_sso
		 */
		$allowed_actions_for_sso = (array) apply_filters( 'jetpack_sso_allowed_actions', array(
			'login',
			'jetpack-sso',
			'jetpack_json_api_authorization',
		) );
		return in_array( $action, $allowed_actions_for_sso );
	}

	/**
	 * This method returns an environment array that is meant to simulate `$_REQUEST` when the initial
	 * JSON API auth request was made.
	 *
	 * @since 4.6.0
	 *
	 * @return array|bool
	 */
	static function get_json_api_auth_environment() {
		if ( empty( $_COOKIE['jetpack_sso_original_request'] ) ) {
			return false;
		}

		$original_request = esc_url_raw( $_COOKIE['jetpack_sso_original_request'] );

		$parsed_url = wp_parse_url( $original_request );
		if ( empty( $parsed_url ) || empty( $parsed_url['query'] ) ) {
			return false;
		}

		$args = array();
		wp_parse_str( $parsed_url['query'], $args );

		if ( empty( $args ) || empty( $args['action'] ) ) {
			return false;
		}

		if ( 'jetpack_json_api_authorization' != $args['action'] ) {
			return false;
		}

		return array_merge(
			$args,
			array( 'jetpack_json_api_original_query' => $original_request )
		);
	}
}

endif;