Implement Application Passwords for API-based authentication.#540
Implement Application Passwords for API-based authentication.#540georgestephanis wants to merge 53 commits intoWordPress:masterfrom
Conversation
Not 100% sure it works, still need to build and test, but this is a starting point for future commits to get it shipshape. There's also a number of core tweaks in here that need to get spread out to better places within the codebase.
If there is no current user authenticated via other means, clear the cached lack of user, so that an authenticate check can set it properly. This is done because for authentications such as Application Passwords, we don't want it to be accepted unless the current HTTP request is an API request, which can't always be identified early enough in evaluation.
|
Added some changes since the last comment phase -- spread the code out across the admin in more relevant places. |
Also moves the list table back outside of the .form-table to fix styling conflicts with the list table.
Use wp.apiRequest instead of raw jQuery.ajax. Use wp.i18n for JS translation instead of translating in PHP. Remove localization for application-passwords.js. Also removes some phpcs comments that core doesn't use.
|
Instead of suggesting a user to edit their |
|
We should also populate |
|
Let's also move |
This should rarely be an issue now since we include the rewrite in the default htaccess. Once the Site Health REST API endpoints land, the check can be moved there. See #48105.
|
I think we should require the WordPress site be on SSL. And also verify that both the success and reject URLs are Ideally, we'd also mandate a |
Possibly to manually upgrade or display a warning for http urls, but please no for mandating It was explicitly written to account for custom protocols such as |
I do kinda wanna make it obvious that the user can just walk away from this process if they choose to and not have it feel like a "squeeze page" that forces a choice. I also hesitate on taking over the entire admin ui unless it's well discussed a conscious decision. |
This introduces a new function wp_is_authorize_application_password_request_valid that contains an action to allow for removing this error if desired. This also allows for developers to add additional constraints to the application request such as mandating that the application has been approved by an administrator.
This fixes an issue where the details of a newly added password weren't viewable on mobile. Props dinhtungdu. From WordPress/application-passwords#120.
As a follow-up to WordPress#540 (comment) Co-Authored-By: Ayesh Karunaratne <[email protected]>
Add: confirmation before delete passwords
JS hooks are introduced to customize the data sent to the REST API and perform actions after an app is approved/rejected. Display hooks are added to the authorize-application.php page to add additional form fields or customize the output.
This fixes JS linting issues.
Previously it'd only fire when used in wp_validate_application_password(). This meant the hook wouldn't fire during XML-RPC requests.
Core doesn't apply this level of sanitization.
The Passwords list table can now be extended by plugins. This requires the creation of a "fake" screen id of `application-passwords-user`. Otherwise, the list table uses the user screen id which isn't unique to the app passwords instance. The JS templating is now also moved to the table so plugins can now add their own templates for their columns. I've also moved the data formatting into the underscore template so we can pass the raw response to the template.
This allows for plugins to support things like read-only support, scoped capabilities, expiration, etc...
This can be used for implementing read-only passwords for instance.
The determine_current_user hook doesn't support a WP_Error return type, instead the input should be passed through.
Rearranges the App Passwords class to follow CRUD. Use static:: to allow for subclassing.
…flow. This should make it more clear what site you are logging into and that you need to login to continue the process. https://make.wordpress.org/core/2020/09/23/proposal-rest-api-authentication-application-passwords/#comment-40010
Switches the user-edit an inline role="alert" notice. The modal behavior we were using was not accessible and can be a jarring experience. Implements speak calls after passwords are revoked. Switches auth-app to also use an inline notice.
| * | ||
| * @type string | ||
| */ | ||
| const USERMETA_KEY_APPLICATION_PASSWORDS = '_application_passwords'; |
There was a problem hiding this comment.
Shouldn't an application password be lock to a single site on a multisite? Shouldn't this be prefixed this site id?
There was a problem hiding this comment.
Nope. If someone wants to use the WordPress mobile apps, for example, it would suck for them to log into each individual site in their multisite install individually.
Just as interactive login sessions aren't locked to a single site when in a multisite environment, api authentication is also supported across the install.
|
Merged in 1856d0f. |
| $hashed_passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); | ||
|
|
||
| foreach ( $hashed_passwords as $key => $item ) { | ||
| if ( ! wp_check_password( $password, $item['password'], $user->ID ) ) { |
There was a problem hiding this comment.
There might be a more efficient way to do this, but it'd require you to adopt a split tokens methodology.
Con: Your generated passwords will necessarily be longer as a result.
Pro: You don't need to check multiple password hashes on API authentication.
The way the code is written, it could be a little slow to handle requests for users with a lot of application passwords.
How to make the change:
-
Make the generated passwords longer. (e.g. 24 -> 32 chars)
-
The first 8 characters are now used as a separate identifier for this database lookup, and are included in the password hash calculation but are stored alongside it as plaintext. (This is provably as secure as 24 character passwords, but you get to side-step this performance pain.)
| $errors->add( 'updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to see what’s new.' ), 'message' ); | ||
| } elseif ( WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action ) { | ||
| $errors->add( 'enter_recovery_mode', __( 'Recovery Mode Initialized. Please log in to continue.' ), 'message' ); | ||
| } elseif ( isset( $_GET['redirect_to'] ) && false !== strpos( $_GET['redirect_to'], 'wp-admin/authorize-application.php' ) ) { |
There was a problem hiding this comment.
Accessing superglobals makes me feel less than fuzzy, but none of the subsequent uses are dangerous, so I think this is fine.
| __( 'Sorry, you are not allowed to manage application passwords for this user.' ), | ||
| array( 'status' => rest_authorization_required_code() ) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Is this a satisfactory permission check? Does it make sense that edit_user implies manage application passwords, or should that be a separate permission bit?
This is an alternative to Basic Auth in #169
Based off existing work in https://github.com/WordPress/application-passwords
PR in progress, collaborating with @TimothyBJacobs for the moment. Trying to make sure this is workable to provide an alternative to Basic Auth.
Trac ticket: https://core.trac.wordpress.org/ticket/42790
Also, worth acknowledging all the folks who have contributed to the Application Passwords plugin thus far, especially @kasparsd who has put in a ton of effort.:
https://github.com/WordPress/application-passwords/graphs/contributors
make/core proposal link: https://make.wordpress.org/core/2020/09/23/proposal-rest-api-authentication-application-passwords/