PluginProbe ʕ •ᴥ•ʔ
Firebase Authentication / 1.7.1
Firebase Authentication v1.7.1
1.7.1 1.7.0 trunk 1.0.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9
firebase-authentication / class-mo-firebase-config.php
firebase-authentication Last commit date
admin 3 weeks ago includes 3 weeks ago languages 3 weeks ago public 3 weeks ago views 3 weeks ago README.txt 3 weeks ago class-mo-firebase-config.php 3 weeks ago class-mo-firebase-contact-us.php 3 weeks ago firebase-authentication.php 3 weeks ago index.php 3 weeks ago uninstall.php 3 weeks ago
class-mo-firebase-config.php
377 lines
1 <?php
2 /**
3 * File containing Firebase API calls
4 *
5 * @package Firebase Config
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Class containing Firebase API call functions
14 */
15 class Mo_Firebase_Config {
16 /**
17 * Initializing the test config control
18 */
19 public function __construct() {
20 add_action( 'init', array( $this, 'testconfig' ) );
21 }
22 /**
23 * Test configuration check
24 */
25 public function testconfig() {
26 if ( isset( $_REQUEST['mo_action'] ) && 'firebaselogin' === sanitize_text_field( wp_unslash( $_REQUEST['mo_action'] ) ) && isset( $_REQUEST['test'] ) && 'true' === sanitize_text_field( wp_unslash( $_REQUEST['test'] ) ) && isset( $_REQUEST['mo_firebase_auth_test_config_field'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['mo_firebase_auth_test_config_field'] ) ), 'mo_firebase_auth_test_config_form' ) ) {
27
28 $project_id = get_option( 'mo_firebase_auth_project_id' );
29 $api_key = get_option( 'mo_firebase_auth_api_key' );
30
31 $test_username = isset( $_POST['test_username'] ) ? sanitize_text_field( wp_unslash( $_POST['test_username'] ) ) : '';
32 $test_password = isset( $_POST['test_password'] ) ? sanitize_text_field( wp_unslash( $_POST['test_password'] ) ) : '';
33
34 $response = $this->mo_firebase_authenticate_call( $test_username, $test_password );
35 $response = json_decode( $response, true );
36
37 if ( isset( $response['error'] ) ) {
38 $fb_error = $response['error']['message'];
39 if ( 'INVALID_PASSWORD' === $fb_error ) {
40 $fb_error = 'The password is invalid or the user does not have a password.';
41 } elseif ( 'EMAIL_NOT_FOUND' === $fb_error ) {
42 $fb_error = 'There is no user record corresponding to this identifier. The user may have been deleted.';
43 } elseif ( 'INVALID_EMAIL' === $fb_error ) {
44 $fb_error = 'The email address is badly formatted.';
45 }
46 echo '<div style="font-family:Calibri;padding: 0 30%;">';
47 echo '<h1 style="color:#d9534f;text-align:center;">test failed</h1>';
48 echo '<h4 style="text-align:center;"><b>ERROR :</b>' . esc_attr( $fb_error ) . '</h4>';
49 echo '</div>';
50 echo '<div style="padding: 10px;"></div><div style="position:absolute;padding:0 46%;"><input style="padding:1%;width:100px;height:30px;background: #0091CD none repeat scroll 0% 0%;cursor: pointer;font-size:15px;border-width: 1px;border-style: solid;border-radius: 3px;white-space: nowrap;box-sizing: border-box;border-color: #0073AA;box-shadow: 0px 1px 0px rgba(120, 200, 230, 0.6) inset;color: #FFF;"type="button" value="Close" onClick="self.close();"></div>';
51 exit();
52 } else {
53 $id_token = $response['idToken'];
54 $payload = $this->decode_jwt( $id_token );
55 echo '<div style="font-family:Calibri;margin: auto;padding:5%;">';
56 echo '<h1 style="color:#00C851;text-align:center;">Test Successful !</h1>';
57 echo '<style>table{border-collapse:collapse;}th {background-color: #eee; text-align: center; padding: 8px; border-width:1px; border-style:solid; border-color:#212121;}tr:nth-child(odd) {background-color: #f2f2f2;} td{padding:8px;border-width:1px; border-style:solid; border-color:#212121;}</style>';
58 echo '<h3 style="text-align:center;">Test Configuration</h3><table style="margin: auto;"><tr><th>Attribute Name</th><th>Attribute Value</th></tr>';
59 $this->testattrmappingconfig( '', $payload );
60 echo '</table></div>';
61 echo '<div style="margin: auto;position:absolute;padding:0 40%;"><input style="margin: auto;position:absolute; padding:8px;width:12%;background: #0091CD none repeat scroll 0% 0%;cursor: pointer;font-size:15px;border-width: 1px;border-style: solid;border-radius: 3px;white-space: nowrap;box-sizing: border-box;border-color: #0073AA;box-shadow: 0px 1px 0px rgba(120, 200, 230, 0.6) inset;color: #FFF;"type="button" value="Done" onClick="self.close();"></div>';
62 exit();
63 }
64 }
65 }
66 /**
67 * Processing test configuration
68 *
69 * @param string $nestedprefix .
70 * @param array $payload .
71 */
72 public function testattrmappingconfig( $nestedprefix, $payload ) {
73 foreach ( $payload as $key => $value ) {
74 if ( is_array( $value ) || is_object( $value ) ) {
75 if ( ! empty( $nestedprefix ) ) {
76 $nestedprefix .= '.';
77 }
78 $this->testattrmappingconfig( $nestedprefix . $key, $value );
79 } else {
80 echo '<tr><td>';
81 if ( ! empty( $nestedprefix ) ) {
82 echo esc_attr( $nestedprefix ) . '.';
83 }
84 echo esc_attr( $key ) . '</td><td>' . esc_attr( $value ) . '</td></tr>';
85 }
86 }
87 }
88 /**
89 * Decode JWT token.
90 *
91 * @param string $jwt_token firebase ID token.
92 */
93 public function decode_jwt( $jwt_token ) {
94 $flag = 0;
95 $pieces = explode( '.', $jwt_token );
96 $jwt_data = $pieces[0] . '.' . $pieces[1];
97 $jwt_signature = str_replace( array( '-', '_' ), array( '+', '/' ), $pieces[2] );
98 $jwt_signature = base64_decode( $jwt_signature ); //phpcs:ignore -- ignoring DiscouragedPHPFunctions warning as this line of code is used for decoding JWT signature part.
99 $jwt_header = json_decode( base64_decode( str_replace( array( '-', '_' ), array( '+', '/' ), $pieces[0] ) ), true ); //phpcs:ignore -- ignoring DiscouragedPHPFunctions warning as this line of code is used for decoding JWT header part.
100
101 $alg = $jwt_header['alg'];
102 $kid = $jwt_header['kid'];
103
104 if ( strpos( $alg, 'RS' ) !== false ) {
105 $algorithm = 'RSA';
106 $sha = explode( 'RS', $alg )[1];
107 }
108
109 $jwt_raw_certificate = $this->mo_firebase_auth_get_cert_from_kid( $kid );
110
111 $public_key = '';
112 $parts = explode( '-----', $jwt_raw_certificate );
113
114 if ( preg_match( '/\r\n|\r|\n/', $parts[2] ) ) {
115 $public_key = $jwt_raw_certificate;
116 } else {
117 $encoding = '-----' . $parts[1] . "-----\n";
118 $offset = 0;
119 $segment = substr( $parts[2], $offset, 64 );
120 while ( $segment ) {
121 $encoding .= $segment . "\n";
122 $offset += 64;
123 $segment = substr( $parts[2], $offset, 64 );
124 }
125 $encoding .= '-----' . $parts[3] . "-----\n";
126 $public_key = $encoding;
127 }
128
129 switch ( $sha ) {
130 case '256':
131 $verified = openssl_verify( $jwt_data, $jwt_signature, $public_key, OPENSSL_ALGO_SHA256 );
132 break;
133 case '384':
134 $verified = openssl_verify( $jwt_data, $jwt_signature, $public_key, OPENSSL_ALGO_SHA384 );
135 break;
136 case '512':
137 $verified = openssl_verify( $jwt_data, $jwt_signature, $public_key, OPENSSL_ALGO_SHA512 );
138 break;
139 default:
140 $verified = false;
141 break;
142 }
143
144 if ( ! $verified ) {
145 echo 'Invalid Token';
146 exit();
147 }
148
149 $jwt_payload = json_decode( base64_decode( $pieces[1] ), true ); //phpcs:ignore -- ignoring DiscouragedPHPFunctions warning as this line of code is used for decoding JWT payload part.
150
151 if ( empty( $jwt_payload['exp'] ) || time() >= (int) $jwt_payload['exp'] ) {
152 echo 'Token expired';
153 exit();
154 }
155
156 $expected_project_id = get_option( 'mo_firebase_auth_project_id' );
157 if ( $expected_project_id && ( empty( $jwt_payload['aud'] ) || $jwt_payload['aud'] !== $expected_project_id ) ) {
158 echo 'Invalid token audience';
159 exit();
160 }
161
162 return $jwt_payload;
163
164 }
165
166 /**
167 * Processing Firebase JWT
168 *
169 * @param mixed $kid kid.
170 *
171 * @return mixed jwt cert
172 */
173 public function mo_firebase_auth_get_cert_from_kid( $kid ) {
174 $flag = $this->mo_firebase_auth_get_kid( $kid );
175 if ( 0 === $flag ) {
176 $firebaselogin = new Miniorange_Firebase_Authentication();
177 $firebaselogin->mo_firebase_auth_store_certificates();
178 $flag = $this->mo_firebase_auth_get_kid( $kid );
179 }
180 if ( 0 !== $flag ) {
181 if ( 1 === $flag ) {
182 $jwt_raw_certificate = get_option( 'mo_firebase_auth_cert1' );
183 } elseif ( 2 === $flag ) {
184 $jwt_raw_certificate = get_option( 'mo_firebase_auth_cert2' );
185 } elseif ( 3 === $flag ) {
186 $jwt_raw_certificate = get_option( 'mo_firebase_auth_cert3' );
187 }
188 } else {
189 echo 'Please provide a valid certificate. Contact your administrator.';
190 exit;
191 }
192 return $jwt_raw_certificate;
193 }
194
195 /**
196 * Function included in JWT processing
197 *
198 * @param mixed $kid kid.
199 *
200 * @return int
201 */
202 public function mo_firebase_auth_get_kid( $kid ) {
203 $flag = 0;
204 $kid_stored = get_option( 'mo_firebase_auth_kid1' );
205 if ( $kid_stored !== $kid ) {
206 $flag = 2;
207 $kid_stored = get_option( 'mo_firebase_auth_kid2' );
208 if ( $kid_stored !== $kid ) {
209 $flag = 3;
210 $kid_stored = get_option( 'mo_firebase_auth_kid3' );
211 if ( $kid_stored !== $kid ) {
212 $flag = 0;
213 }
214 }
215 } else {
216 $flag = 1;
217 }
218 return $flag;
219 }
220
221 /**
222 * Check the user and set the session or return WP error
223 *
224 * @param mixed $fb_idtoken firebase Id token.
225 *
226 * @return object WP_User/WP_Error .
227 */
228 public function mo_fb_login_user( $fb_idtoken ) {
229
230 $payload = $this->decode_jwt( $fb_idtoken );
231
232 $user = $this->get_user( $payload );
233 if ( is_wp_error( $user ) ) {
234 return $user;
235 } else {
236 $user_id = $user->ID;
237 wp_set_auth_cookie( $user_id, true );
238 wp_safe_redirect( home_url() );
239 exit;
240 }
241
242 }
243
244 /**
245 * Get the user object from WordPress
246 *
247 * @param array $jwt_payload Firebase Id token payload.
248 */
249 public function get_user( $jwt_payload ) {
250 if ( isset( $jwt_payload['email'] ) ) {
251 $email = $jwt_payload['email'];
252 $email_verified = ! empty( $jwt_payload['email_verified'] );
253
254 // By default only Firebase-verified emails may log in. Admins can opt in
255 // to allow unverified emails via the "Allow login if email is not verified" setting.
256 if ( ! $email_verified && ! get_option( 'mo_firebase_allow_unverified_email_login' ) ) {
257 return new WP_Error(
258 'firebase_email_not_verified',
259 __( 'Your email is not verified. Please verify your email before logging in.', 'firebase-authentication' )
260 );
261 }
262
263 $firebase_uid = isset( $jwt_payload['sub'] ) ? $jwt_payload['sub'] : ( isset( $jwt_payload['user_id'] ) ? $jwt_payload['user_id'] : '' );
264 $user = null;
265
266 if ( $firebase_uid ) {
267 $bound_users = get_users(
268 array(
269 'meta_key' => 'mo_firebase_user_uid',
270 'meta_value' => $firebase_uid,
271 'number' => 1,
272 )
273 );
274 if ( ! empty( $bound_users ) ) {
275 $user = $bound_users[0];
276 }
277 }
278
279 if ( ! $user ) {
280 $user = get_user_by( 'email', $email );
281 if ( ! $user ) {
282 $user = get_user_by( 'login', $email );
283 }
284 }
285
286 if ( $user ) {
287 if ( $firebase_uid ) {
288 update_user_meta( $user->ID, 'mo_firebase_user_uid', $firebase_uid );
289 }
290 return $user;
291 }
292
293 $user_password = wp_generate_password( 10, false );
294
295 $userdata = array(
296 'user_login' => $email,
297 'user_pass' => $user_password,
298 'user_email' => $email,
299 );
300
301 $user_id = wp_insert_user( $userdata );
302
303 if ( ! is_wp_error( $user_id ) ) {
304 update_user_meta( $user_id, 'mo_firebase_user_dn', false );
305 if ( $firebase_uid ) {
306 update_user_meta( $user_id, 'mo_firebase_user_uid', $firebase_uid );
307 }
308 }
309
310 return get_user_by( 'email', $email );
311 }
312 }
313 /**
314 * Function to call Firebase email password API
315 *
316 * @param string $url .
317 * @param string $headers .
318 * @param string $body .
319 */
320 public function mo_fb_post_api( $url, $headers, $body ) {
321
322 $args = array(
323 'method' => 'POST',
324 'body' => $body,
325 'timeout' => '5',
326 'redirection' => '5',
327 'httpversion' => '1.0',
328 'blocking' => true,
329 'headers' => $headers,
330
331 );
332
333 $response = wp_remote_post( $url, $args );
334
335 if ( is_wp_error( $response ) ) {
336 $error_message = $response->get_error_message();
337 echo 'Something went wrong: ' . esc_attr( $error_message );
338 exit();
339 }
340
341 return wp_remote_retrieve_body( $response );
342 }
343
344 /**
345 * Function to call Firebase email password API
346 *
347 * @param string $email .
348 * @param string $password .
349 */
350 public function mo_firebase_authenticate_call( $email, $password ) {
351
352 $api_key = get_option( 'mo_firebase_auth_api_key' );
353
354 $url = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=' . $api_key;
355
356 $params = array(
357 'email' => $email,
358 'password' => $password,
359 'returnSecureToken' => true,
360 );
361
362 $body = wp_json_encode( $params );
363
364 $headers = array(
365 'Content-Type' => 'application/json',
366 'Content-Length' => strlen( $body ),
367 );
368
369 $response = $this->mo_fb_post_api( $url, $headers, $body );
370
371 return $response;
372 }
373
374 }
375
376 $mo_firebase_config_obj = new Mo_Firebase_Config();
377