auth.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. <?php
  2. /**
  3. * @group pluggable
  4. * @group auth
  5. */
  6. class Tests_Auth extends WP_UnitTestCase {
  7. protected $user;
  8. /**
  9. * @var WP_User
  10. */
  11. protected static $_user;
  12. protected static $user_id;
  13. protected static $wp_hasher;
  14. /**
  15. * Action hook.
  16. */
  17. protected $nonce_failure_hook = 'wp_verify_nonce_failed';
  18. public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
  19. self::$_user = $factory->user->create_and_get(
  20. array(
  21. 'user_login' => 'password-tests',
  22. )
  23. );
  24. self::$user_id = self::$_user->ID;
  25. require_once ABSPATH . WPINC . '/class-phpass.php';
  26. self::$wp_hasher = new PasswordHash( 8, true );
  27. }
  28. function setUp() {
  29. parent::setUp();
  30. $this->user = clone self::$_user;
  31. wp_set_current_user( self::$user_id );
  32. update_site_option( 'using_application_passwords', 1 );
  33. unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'], $GLOBALS['wp_rest_application_password_uuid'] );
  34. }
  35. public function tearDown() {
  36. // Cleanup all the global state.
  37. unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'], $GLOBALS['wp_rest_application_password_uuid'] );
  38. parent::tearDown();
  39. }
  40. function test_auth_cookie_valid() {
  41. $cookie = wp_generate_auth_cookie( self::$user_id, time() + 3600, 'auth' );
  42. $this->assertSame( self::$user_id, wp_validate_auth_cookie( $cookie, 'auth' ) );
  43. }
  44. function test_auth_cookie_invalid() {
  45. // 3600 or less and +3600 may occur in wp_validate_auth_cookie(),
  46. // as an ajax test may have defined DOING_AJAX, failing the test.
  47. $cookie = wp_generate_auth_cookie( self::$user_id, time() - 7200, 'auth' );
  48. $this->assertFalse( wp_validate_auth_cookie( $cookie, 'auth' ), 'expired cookie' );
  49. $cookie = wp_generate_auth_cookie( self::$user_id, time() + 3600, 'auth' );
  50. $this->assertFalse( wp_validate_auth_cookie( $cookie, 'logged_in' ), 'wrong auth scheme' );
  51. $cookie = wp_generate_auth_cookie( self::$user_id, time() + 3600, 'auth' );
  52. list($a, $b, $c) = explode( '|', $cookie );
  53. $cookie = $a . '|' . ( $b + 1 ) . '|' . $c;
  54. $this->assertFalse( wp_validate_auth_cookie( self::$user_id, 'auth' ), 'altered cookie' );
  55. }
  56. function test_auth_cookie_scheme() {
  57. // Arbitrary scheme name.
  58. $cookie = wp_generate_auth_cookie( self::$user_id, time() + 3600, 'foo' );
  59. $this->assertSame( self::$user_id, wp_validate_auth_cookie( $cookie, 'foo' ) );
  60. // Wrong scheme name - should fail.
  61. $cookie = wp_generate_auth_cookie( self::$user_id, time() + 3600, 'foo' );
  62. $this->assertFalse( wp_validate_auth_cookie( $cookie, 'bar' ) );
  63. }
  64. /**
  65. * @ticket 23494
  66. */
  67. function test_password_trimming() {
  68. $passwords_to_test = array(
  69. 'a password with no trailing or leading spaces',
  70. 'a password with trailing spaces ',
  71. ' a password with leading spaces',
  72. ' a password with trailing and leading spaces ',
  73. );
  74. foreach ( $passwords_to_test as $password_to_test ) {
  75. wp_set_password( $password_to_test, $this->user->ID );
  76. $authed_user = wp_authenticate( $this->user->user_login, $password_to_test );
  77. $this->assertInstanceOf( 'WP_User', $authed_user );
  78. $this->assertSame( $this->user->ID, $authed_user->ID );
  79. }
  80. }
  81. /**
  82. * Test wp_hash_password trims whitespace
  83. *
  84. * This is similar to test_password_trimming but tests the "lower level"
  85. * wp_hash_password function
  86. *
  87. * @ticket 24973
  88. */
  89. function test_wp_hash_password_trimming() {
  90. $password = ' pass with leading whitespace';
  91. $this->assertTrue( wp_check_password( 'pass with leading whitespace', wp_hash_password( $password ) ) );
  92. $password = 'pass with trailing whitespace ';
  93. $this->assertTrue( wp_check_password( 'pass with trailing whitespace', wp_hash_password( $password ) ) );
  94. $password = ' pass with whitespace ';
  95. $this->assertTrue( wp_check_password( 'pass with whitespace', wp_hash_password( $password ) ) );
  96. $password = "pass with new line \n";
  97. $this->assertTrue( wp_check_password( 'pass with new line', wp_hash_password( $password ) ) );
  98. $password = "pass with vertial tab o_O\x0B";
  99. $this->assertTrue( wp_check_password( 'pass with vertial tab o_O', wp_hash_password( $password ) ) );
  100. }
  101. /**
  102. * @ticket 29217
  103. */
  104. function test_wp_verify_nonce_with_empty_arg() {
  105. $this->assertFalse( wp_verify_nonce( '' ) );
  106. $this->assertFalse( wp_verify_nonce( null ) );
  107. }
  108. /**
  109. * @ticket 29542
  110. */
  111. function test_wp_verify_nonce_with_integer_arg() {
  112. $this->assertFalse( wp_verify_nonce( 1 ) );
  113. }
  114. /**
  115. * @ticket 24030
  116. */
  117. function test_wp_nonce_verify_failed() {
  118. $nonce = substr( md5( uniqid() ), 0, 10 );
  119. $count = did_action( $this->nonce_failure_hook );
  120. wp_verify_nonce( $nonce, 'nonce_test_action' );
  121. $this->assertSame( ( $count + 1 ), did_action( $this->nonce_failure_hook ) );
  122. }
  123. /**
  124. * @ticket 24030
  125. */
  126. function test_wp_nonce_verify_success() {
  127. $nonce = wp_create_nonce( 'nonce_test_action' );
  128. $count = did_action( $this->nonce_failure_hook );
  129. wp_verify_nonce( $nonce, 'nonce_test_action' );
  130. $this->assertSame( $count, did_action( $this->nonce_failure_hook ) );
  131. }
  132. /**
  133. * @ticket 36361
  134. */
  135. public function test_check_admin_referer_with_no_action_triggers_doing_it_wrong() {
  136. $this->setExpectedIncorrectUsage( 'check_admin_referer' );
  137. // A valid nonce needs to be set so the check doesn't die().
  138. $_REQUEST['_wpnonce'] = wp_create_nonce( -1 );
  139. $result = check_admin_referer();
  140. $this->assertSame( 1, $result );
  141. unset( $_REQUEST['_wpnonce'] );
  142. }
  143. public function test_check_admin_referer_with_default_action_as_string_not_doing_it_wrong() {
  144. // A valid nonce needs to be set so the check doesn't die().
  145. $_REQUEST['_wpnonce'] = wp_create_nonce( '-1' );
  146. $result = check_admin_referer( '-1' );
  147. $this->assertSame( 1, $result );
  148. unset( $_REQUEST['_wpnonce'] );
  149. }
  150. /**
  151. * @ticket 36361
  152. */
  153. public function test_check_ajax_referer_with_no_action_triggers_doing_it_wrong() {
  154. $this->setExpectedIncorrectUsage( 'check_ajax_referer' );
  155. // A valid nonce needs to be set so the check doesn't die().
  156. $_REQUEST['_wpnonce'] = wp_create_nonce( -1 );
  157. $result = check_ajax_referer();
  158. $this->assertSame( 1, $result );
  159. unset( $_REQUEST['_wpnonce'] );
  160. }
  161. function test_password_length_limit() {
  162. $limit = str_repeat( 'a', 4096 );
  163. wp_set_password( $limit, self::$user_id );
  164. // phpass hashed password.
  165. $this->assertStringStartsWith( '$P$', $this->user->data->user_pass );
  166. $user = wp_authenticate( $this->user->user_login, 'aaaaaaaa' );
  167. // Wrong password.
  168. $this->assertInstanceOf( 'WP_Error', $user );
  169. $user = wp_authenticate( $this->user->user_login, $limit );
  170. $this->assertInstanceOf( 'WP_User', $user );
  171. $this->assertSame( self::$user_id, $user->ID );
  172. // One char too many.
  173. $user = wp_authenticate( $this->user->user_login, $limit . 'a' );
  174. // Wrong password.
  175. $this->assertInstanceOf( 'WP_Error', $user );
  176. wp_set_password( $limit . 'a', self::$user_id );
  177. $user = get_user_by( 'id', self::$user_id );
  178. // Password broken by setting it to be too long.
  179. $this->assertSame( '*', $user->data->user_pass );
  180. $user = wp_authenticate( $this->user->user_login, '*' );
  181. $this->assertInstanceOf( 'WP_Error', $user );
  182. $user = wp_authenticate( $this->user->user_login, '*0' );
  183. $this->assertInstanceOf( 'WP_Error', $user );
  184. $user = wp_authenticate( $this->user->user_login, '*1' );
  185. $this->assertInstanceOf( 'WP_Error', $user );
  186. $user = wp_authenticate( $this->user->user_login, 'aaaaaaaa' );
  187. // Wrong password.
  188. $this->assertInstanceOf( 'WP_Error', $user );
  189. $user = wp_authenticate( $this->user->user_login, $limit );
  190. // Wrong password.
  191. $this->assertInstanceOf( 'WP_Error', $user );
  192. $user = wp_authenticate( $this->user->user_login, $limit . 'a' );
  193. // Password broken by setting it to be too long.
  194. $this->assertInstanceOf( 'WP_Error', $user );
  195. }
  196. /**
  197. * @ticket 45746
  198. */
  199. function test_user_activation_key_is_saved() {
  200. $user = get_userdata( $this->user->ID );
  201. $key = get_password_reset_key( $user );
  202. // A correctly saved key should be accepted.
  203. $check = check_password_reset_key( $key, $this->user->user_login );
  204. $this->assertNotWPError( $check );
  205. $this->assertInstanceOf( 'WP_User', $check );
  206. $this->assertSame( $this->user->ID, $check->ID );
  207. }
  208. /**
  209. * @ticket 32429
  210. */
  211. function test_user_activation_key_is_checked() {
  212. global $wpdb;
  213. $key = wp_generate_password( 20, false );
  214. $wpdb->update(
  215. $wpdb->users,
  216. array(
  217. 'user_activation_key' => strtotime( '-1 hour' ) . ':' . self::$wp_hasher->HashPassword( $key ),
  218. ),
  219. array(
  220. 'ID' => $this->user->ID,
  221. )
  222. );
  223. clean_user_cache( $this->user );
  224. // A valid key should be accepted.
  225. $check = check_password_reset_key( $key, $this->user->user_login );
  226. $this->assertNotWPError( $check );
  227. $this->assertInstanceOf( 'WP_User', $check );
  228. $this->assertSame( $this->user->ID, $check->ID );
  229. // An invalid key should be rejected.
  230. $check = check_password_reset_key( 'key', $this->user->user_login );
  231. $this->assertInstanceOf( 'WP_Error', $check );
  232. // An empty key should be rejected.
  233. $check = check_password_reset_key( '', $this->user->user_login );
  234. $this->assertInstanceOf( 'WP_Error', $check );
  235. // A truncated key should be rejected.
  236. $partial = substr( $key, 0, 10 );
  237. $check = check_password_reset_key( $partial, $this->user->user_login );
  238. $this->assertInstanceOf( 'WP_Error', $check );
  239. }
  240. /**
  241. * @ticket 32429
  242. */
  243. function test_expired_user_activation_key_is_rejected() {
  244. global $wpdb;
  245. $key = wp_generate_password( 20, false );
  246. $wpdb->update(
  247. $wpdb->users,
  248. array(
  249. 'user_activation_key' => strtotime( '-48 hours' ) . ':' . self::$wp_hasher->HashPassword( $key ),
  250. ),
  251. array(
  252. 'ID' => $this->user->ID,
  253. )
  254. );
  255. clean_user_cache( $this->user );
  256. // An expired but otherwise valid key should be rejected.
  257. $check = check_password_reset_key( $key, $this->user->user_login );
  258. $this->assertInstanceOf( 'WP_Error', $check );
  259. }
  260. /**
  261. * @ticket 32429
  262. */
  263. function test_empty_user_activation_key_fails_key_check() {
  264. // An empty user_activation_key should not allow any key to be accepted.
  265. $check = check_password_reset_key( 'key', $this->user->user_login );
  266. $this->assertInstanceOf( 'WP_Error', $check );
  267. // An empty user_activation_key should not allow an empty key to be accepted.
  268. $check = check_password_reset_key( '', $this->user->user_login );
  269. $this->assertInstanceOf( 'WP_Error', $check );
  270. }
  271. /**
  272. * @ticket 32429
  273. */
  274. function test_legacy_user_activation_key_is_rejected() {
  275. global $wpdb;
  276. // A legacy user_activation_key is one without the `time()` prefix introduced in WordPress 4.3.
  277. $key = wp_generate_password( 20, false );
  278. $wpdb->update(
  279. $wpdb->users,
  280. array(
  281. 'user_activation_key' => self::$wp_hasher->HashPassword( $key ),
  282. ),
  283. array(
  284. 'ID' => $this->user->ID,
  285. )
  286. );
  287. clean_user_cache( $this->user );
  288. // A legacy user_activation_key should not be accepted.
  289. $check = check_password_reset_key( $key, $this->user->user_login );
  290. $this->assertInstanceOf( 'WP_Error', $check );
  291. // An empty key with a legacy user_activation_key should be rejected.
  292. $check = check_password_reset_key( '', $this->user->user_login );
  293. $this->assertInstanceOf( 'WP_Error', $check );
  294. }
  295. /**
  296. * @ticket 32429
  297. * @ticket 24783
  298. */
  299. function test_plaintext_user_activation_key_is_rejected() {
  300. global $wpdb;
  301. // A plaintext user_activation_key is one stored before hashing was introduced in WordPress 3.7.
  302. $key = wp_generate_password( 20, false );
  303. $wpdb->update(
  304. $wpdb->users,
  305. array(
  306. 'user_activation_key' => $key,
  307. ),
  308. array(
  309. 'ID' => $this->user->ID,
  310. )
  311. );
  312. clean_user_cache( $this->user );
  313. // A plaintext user_activation_key should not allow an otherwise valid key to be accepted.
  314. $check = check_password_reset_key( $key, $this->user->user_login );
  315. $this->assertInstanceOf( 'WP_Error', $check );
  316. // A plaintext user_activation_key should not allow an empty key to be accepted.
  317. $check = check_password_reset_key( '', $this->user->user_login );
  318. $this->assertInstanceOf( 'WP_Error', $check );
  319. }
  320. /**
  321. * Ensure users can log in using both their username and their email address.
  322. *
  323. * @ticket 9568
  324. */
  325. public function test_log_in_using_email() {
  326. $user_args = array(
  327. 'user_login' => 'johndoe',
  328. 'user_email' => 'mail@example.com',
  329. 'user_pass' => 'password',
  330. );
  331. $this->factory->user->create( $user_args );
  332. $this->assertInstanceOf( 'WP_User', wp_authenticate( $user_args['user_email'], $user_args['user_pass'] ) );
  333. $this->assertInstanceOf( 'WP_User', wp_authenticate( $user_args['user_login'], $user_args['user_pass'] ) );
  334. }
  335. /**
  336. * @ticket 38744
  337. */
  338. public function test_wp_signon_using_email_with_an_apostrophe() {
  339. $user_args = array(
  340. 'user_email' => "mail\'@example.com",
  341. 'user_pass' => 'password',
  342. );
  343. $this->factory()->user->create( $user_args );
  344. $_POST['log'] = $user_args['user_email'];
  345. $_POST['pwd'] = $user_args['user_pass'];
  346. $this->assertInstanceOf( 'WP_User', wp_signon() );
  347. }
  348. /**
  349. * HTTP Auth headers are used to determine the current user.
  350. *
  351. * @ticket 42790
  352. *
  353. * @covers ::wp_validate_application_password
  354. */
  355. public function test_application_password_authentication() {
  356. $user_id = $this->factory()->user->create(
  357. array(
  358. 'user_login' => 'http_auth_login',
  359. 'user_pass' => 'http_auth_pass', // Shouldn't be allowed for API login.
  360. )
  361. );
  362. // Create a new app-only password.
  363. list( $user_app_password, $item ) = WP_Application_Passwords::create_new_application_password( $user_id, array( 'name' => 'phpunit' ) );
  364. // Fake a REST API request.
  365. add_filter( 'application_password_is_api_request', '__return_true' );
  366. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  367. // Fake an HTTP Auth request with the regular account password first.
  368. $_SERVER['PHP_AUTH_USER'] = 'http_auth_login';
  369. $_SERVER['PHP_AUTH_PW'] = 'http_auth_pass';
  370. $this->assertNull(
  371. wp_validate_application_password( null ),
  372. 'Regular user account password should not be allowed for API authentication'
  373. );
  374. $this->assertNull( rest_get_authenticated_app_password() );
  375. // Not try with an App password instead.
  376. $_SERVER['PHP_AUTH_PW'] = $user_app_password;
  377. $this->assertSame(
  378. $user_id,
  379. wp_validate_application_password( null ),
  380. 'Application passwords should be allowed for API authentication'
  381. );
  382. $this->assertSame( $item['uuid'], rest_get_authenticated_app_password() );
  383. }
  384. /**
  385. * @ticket 42790
  386. */
  387. public function test_authenticate_application_password_respects_existing_user() {
  388. $this->assertSame( self::$_user, wp_authenticate_application_password( self::$_user, self::$_user->user_login, 'password' ) );
  389. }
  390. /**
  391. * @ticket 42790
  392. */
  393. public function test_authenticate_application_password_is_rejected_if_not_api_request() {
  394. add_filter( 'application_password_is_api_request', '__return_false' );
  395. $this->assertNull( wp_authenticate_application_password( null, self::$_user->user_login, 'password' ) );
  396. }
  397. /**
  398. * @ticket 42790
  399. */
  400. public function test_authenticate_application_password_invalid_username() {
  401. add_filter( 'application_password_is_api_request', '__return_true' );
  402. $error = wp_authenticate_application_password( null, 'idonotexist', 'password' );
  403. $this->assertWPError( $error );
  404. $this->assertSame( 'invalid_username', $error->get_error_code() );
  405. }
  406. /**
  407. * @ticket 42790
  408. */
  409. public function test_authenticate_application_password_invalid_email() {
  410. add_filter( 'application_password_is_api_request', '__return_true' );
  411. $error = wp_authenticate_application_password( null, 'idonotexist@example.org', 'password' );
  412. $this->assertWPError( $error );
  413. $this->assertSame( 'invalid_email', $error->get_error_code() );
  414. }
  415. /**
  416. * @ticket 42790
  417. */
  418. public function test_authenticate_application_password_not_allowed() {
  419. add_filter( 'application_password_is_api_request', '__return_true' );
  420. add_filter( 'wp_is_application_passwords_available', '__return_false' );
  421. $error = wp_authenticate_application_password( null, self::$_user->user_login, 'password' );
  422. $this->assertWPError( $error );
  423. $this->assertSame( 'application_passwords_disabled', $error->get_error_code() );
  424. }
  425. /**
  426. * @ticket 42790
  427. */
  428. public function test_authenticate_application_password_not_allowed_for_user() {
  429. add_filter( 'application_password_is_api_request', '__return_true' );
  430. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  431. add_filter( 'wp_is_application_passwords_available_for_user', '__return_false' );
  432. $error = wp_authenticate_application_password( null, self::$_user->user_login, 'password' );
  433. $this->assertWPError( $error );
  434. $this->assertSame( 'application_passwords_disabled_for_user', $error->get_error_code() );
  435. }
  436. /**
  437. * @ticket 42790
  438. */
  439. public function test_authenticate_application_password_incorrect_password() {
  440. add_filter( 'application_password_is_api_request', '__return_true' );
  441. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  442. $error = wp_authenticate_application_password( null, self::$_user->user_login, 'password' );
  443. $this->assertWPError( $error );
  444. $this->assertSame( 'incorrect_password', $error->get_error_code() );
  445. }
  446. /**
  447. * @ticket 42790
  448. */
  449. public function test_authenticate_application_password_custom_errors() {
  450. add_filter( 'application_password_is_api_request', '__return_true' );
  451. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  452. add_action(
  453. 'wp_authenticate_application_password_errors',
  454. static function ( WP_Error $error ) {
  455. $error->add( 'my_code', 'My Error' );
  456. }
  457. );
  458. list( $password ) = WP_Application_Passwords::create_new_application_password( self::$user_id, array( 'name' => 'phpunit' ) );
  459. $error = wp_authenticate_application_password( null, self::$_user->user_login, $password );
  460. $this->assertWPError( $error );
  461. $this->assertSame( 'my_code', $error->get_error_code() );
  462. }
  463. /**
  464. * @ticket 42790
  465. */
  466. public function test_authenticate_application_password_by_username() {
  467. add_filter( 'application_password_is_api_request', '__return_true' );
  468. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  469. list( $password ) = WP_Application_Passwords::create_new_application_password( self::$user_id, array( 'name' => 'phpunit' ) );
  470. $user = wp_authenticate_application_password( null, self::$_user->user_login, $password );
  471. $this->assertInstanceOf( WP_User::class, $user );
  472. $this->assertSame( self::$user_id, $user->ID );
  473. }
  474. /**
  475. * @ticket 42790
  476. */
  477. public function test_authenticate_application_password_by_email() {
  478. add_filter( 'application_password_is_api_request', '__return_true' );
  479. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  480. list( $password ) = WP_Application_Passwords::create_new_application_password( self::$user_id, array( 'name' => 'phpunit' ) );
  481. $user = wp_authenticate_application_password( null, self::$_user->user_email, $password );
  482. $this->assertInstanceOf( WP_User::class, $user );
  483. $this->assertSame( self::$user_id, $user->ID );
  484. }
  485. /**
  486. * @ticket 42790
  487. */
  488. public function test_authenticate_application_password_chunked() {
  489. add_filter( 'application_password_is_api_request', '__return_true' );
  490. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  491. list( $password ) = WP_Application_Passwords::create_new_application_password( self::$user_id, array( 'name' => 'phpunit' ) );
  492. $user = wp_authenticate_application_password( null, self::$_user->user_email, WP_Application_Passwords::chunk_password( $password ) );
  493. $this->assertInstanceOf( WP_User::class, $user );
  494. $this->assertSame( self::$user_id, $user->ID );
  495. }
  496. /**
  497. * @ticket 51939
  498. */
  499. public function test_authenticate_application_password_returns_null_if_not_in_use() {
  500. delete_site_option( 'using_application_passwords' );
  501. $authenticated = wp_authenticate_application_password( null, 'idonotexist', 'password' );
  502. $this->assertNull( $authenticated );
  503. }
  504. /**
  505. * @ticket 52003
  506. *
  507. * @covers ::wp_validate_application_password
  508. */
  509. public function test_application_passwords_does_not_attempt_auth_if_missing_password() {
  510. WP_Application_Passwords::create_new_application_password( self::$user_id, array( 'name' => 'phpunit' ) );
  511. add_filter( 'application_password_is_api_request', '__return_true' );
  512. add_filter( 'wp_is_application_passwords_available', '__return_true' );
  513. $_SERVER['PHP_AUTH_USER'] = self::$_user->user_login;
  514. unset( $_SERVER['PHP_AUTH_PW'] );
  515. $this->assertNull( wp_validate_application_password( null ) );
  516. }
  517. }