Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user last seen information #4765

Open
wants to merge 46 commits into
base: develop
Choose a base branch
from
Open

Conversation

luismulinari
Copy link
Contributor

@luismulinari luismulinari commented Aug 9, 2023

Description

This PR introduces a Last Seen user meta to the users, which is going to be used to report and block inactive users, improving security by reducing the surface attack.

Inactive users blocked on login

Inactive users on the Users page (network and site)

Inactive users

curl -X GET --user "example@example.org:key" "http://vip-testing-luismulinari-multi.vipdev.lndo.site/wp-json/wp/v2/users?context=edit"
{"code":"rest_forbidden_context","message":"Sorry, you are not allowed to list users.","data":{"status":401}}%

Changelog Description

Pre-review checklist

Please make sure the items below have been covered before requesting a review:

  • This change works and has been tested locally (or has an appropriate fallback).
  • This change works and has been tested on a Go sandbox.
  • This change has relevant unit tests (if applicable).
  • This change uses a rollout method to ease with deployment (if applicable - especially for large scale actions that require writes).
  • This change has relevant documentation additions / updates (if applicable).
  • I've created a changelog description that aligns with the provided examples.

Pre-deploy checklist

  • VIP staff: Ensure any alerts added/updated conform to internal standards (see internal documentation).

Steps to Test

  1. Check out PR.
  2. Add the following constants:
define( 'VIP_SECURITY_INACTIVE_USERS_ACTION', 'BLOCK' );
define( 'VIP_SECURITY_CONSIDER_USERS_INACTIVE_AFTER_DAYS', 30 );
  1. Go to wp-admin > Users

@codecov
Copy link

codecov bot commented Aug 9, 2023

Codecov Report

Attention: Patch coverage is 43.04348% with 131 lines in your changes are missing coverage. Please review.

Project coverage is 29.11%. Comparing base (5dcdedd) to head (dff4503).

Files Patch % Lines
security/class-user-last-seen.php 43.55% 127 Missing ⚠️
security.php 0.00% 4 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #4765      +/-   ##
=============================================
+ Coverage      29.02%   29.11%   +0.08%     
- Complexity      4825     4908      +83     
=============================================
  Files            283      284       +1     
  Lines          20951    21169     +218     
=============================================
+ Hits            6082     6163      +81     
- Misses         14869    15006     +137     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@luismulinari
Copy link
Contributor Author

luismulinari commented Aug 15, 2023

Thanks for such a thoughtful review @WPprodigy ❤️

Copy link
Member

@mjangda mjangda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spotted a couple of things I wanted to flag.

security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
security/user-last-seen.php Outdated Show resolved Hide resolved
@luismulinari luismulinari force-pushed the add/users-last-seen branch 2 times, most recently from 48b1594 to 31cfcdc Compare August 21, 2023 22:28
@luismulinari luismulinari marked this pull request as ready for review August 22, 2023 14:47

add_action( 'admin_init', array( $this, 'register_release_date' ) );
add_action( 'set_user_role', array( $this, 'user_promoted' ) );
add_action( 'vip_support_user_added', function( $user_id ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we already have an existing job that clears out the vip_support users (

const CRON_ACTION = 'wpcom_vip_support_remove_user_via_cron';
) after a timeperiod of being added, do you think we can skip checking those types of users with that role for inactivity altogether?

return;
}

$this->release_date = get_option( self::LAST_SEEN_RELEASE_DATE_TIMESTAMP_OPTION_KEY );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we using this property anywhere or just directly checking the option?

Copy link
Contributor

@WPprodigy WPprodigy Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The options main purpose is for: https://github.com/Automattic/vip-go-mu-plugins/pull/4765/files#diff-d6cd56ee4fe98abf6b5d384fc94675502abd9ad6a5d412954a4ccccc35cb2bb4R311-R314

But I agree, let's just call get_option() when it's needed. There is runtime caching in place for it, and validation is handled internally already. So no need for the class property to maintain it's own state. As-is, the current version will run this DB query/memcache get on every request rather unnecessarily.

$error = __( 'User not found.', 'wpvip' );
}

if ( ! current_user_can( 'edit_user', $user_id ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but can we move this permissions check up earlier?

* @return bool
*/
public function application_password_authentication( $available, $user ) {
global $wp_last_seen_application_password_error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a class property rather than a global

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Done: 182dc0d

@nickdaugherty
Copy link
Member

nickdaugherty commented Oct 20, 2023

I have a higher level thought on this ... can we reduce the instances of VIP-specific naming inside the class (meta/option keys, filter names) and make it more generic? This functionality is something that has wider appeal outside of VIP and by removing VIP references, re create an easier path to open sourcing this as a standalone plugin one day. It's always a goal to contribute back when possible and this seems like it can be a great standalone plugin in the future.

*
* @param array $skip_users The list of user IDs to skip.
*/
$skip_users = apply_filters( 'vip_security_last_seen_skip_users', array() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about moving this filter to is_considered_inactive()? That gives more flexibility for filtering the results of the check and might be more predictable.


public function ignore_inactivity_check_for_user( $user_id, $until_timestamp = null ) {
if ( ! $until_timestamp ) {
$until_timestamp = strtotime( '+2 days' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default of +2 days feels a little too magic and is hard to predict. Maybe we should just require $until_timestamp be specified?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but I'd also consider naming the function ignore_inactivity_check_for_user_until( $user_id, $until_timestamp ). The _until makes it obvious that it's a limited time action, vs. permanent (which is what I thought it would do before I read the code)

Copy link

sonarcloud bot commented Jan 25, 2024

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

4 New issues
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

Copy link
Contributor

This pull request has been marked stale because it has been open for 60 days with no activity. If there is no activity within 7 days, it will be closed.

This is an automation to keep pull requests manageable and actionable and is not a comment on the quality of this pull request nor on the work done so far. Closed PRs are still valuable to the project and their branches are preserved.

Copy link

sonarcloud bot commented Mar 26, 2024

Quality Gate Passed Quality Gate passed

Issues
4 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants