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

Remove duplicate two_factor_providers filter calls to allow disabling core providers #651

Merged
merged 9 commits into from
Dec 18, 2024

Conversation

kasparsd
Copy link
Collaborator

@kasparsd kasparsd commented Dec 2, 2024

See #637 (comment)

What?

In #637 we introduced a dedicated helper to retrieve all possible two-factor providers (even if disabled) so that we could purge all their added user meta and options during uninstall.

Accidentally it added another instance of the two_factor_providers filter which was already defined in get_providers().

Why?

How?

  • Introduce a method for getting the default built-in providers. This is used as the starting point for enabled providers and when collecting all providers to clean during plugin uninstall.
  • Pass that default list of providers to the two_factor_providers filter when getting "enabled" providers from get_providers().
  • Refactor get_providers_classes() to accept a list of provider names and their class files instead of attempting to retrieve some provider state. During uninstall, we need all providers while during runtime only the enabled ones.

Testing Instructions

  • Use the plugin without any two_factor_providers filters. All default providers are available to all users.
  • Attach a filter to two_factor_providers that limits just one provider. Attempt to uninstall the plugin and confirm that it removes also the meta for the disabled providers (see the phpunit test case cover this).

Screenshots or screencast

Changelog Entry

Changed - removed duplicate two-factor provider filter.

class-two-factor-core.php Outdated Show resolved Hide resolved
@kasparsd kasparsd force-pushed the fix-available-providers-filter branch from 4a9feff to 93f561f Compare December 2, 2024 12:01
class-two-factor-core.php Show resolved Hide resolved
foreach ( $providers as $provider_key => $path ) {
require_once $path;
if ( ! empty( $path ) && is_readable( $path ) ) {
Copy link
Collaborator Author

@kasparsd kasparsd Dec 2, 2024

Choose a reason for hiding this comment

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

Previously this wasn't checking if the file path even exists. If the path isn't valid, we still attempt to check if the class exists and include it.

This was always a private method so we don't need to account for anyone referencing this.

*/
if ( method_exists( $class, 'get_instance' ) ) {
if ( class_exists( $class ) ) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The get_instance() presence is checked later when we actually attempt to load these classes. This method is strictly for mapping the classes and it shouldn't know anything about their structure.


foreach ( $providers as $provider_key => $provider_class ) {
if ( method_exists( $provider_class, 'get_instance' ) ) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Previously it wouldn't actually remove the provider from the list if it didn't have the get_instance method.

$providers = array_merge( $providers, $additional_providers );
}

foreach ( self::get_providers_classes( $providers ) as $provider_class ) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here we still pass the provider classes through the filters so any provider adjustments are accounted for.

unset( $providers[ $provider_key ] );
}
try {
$providers[ $provider_key ] = call_user_func( array( $provider_class, 'get_instance' ) );
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This will fail both when (1) get_instance is not defined for the class and (2) if that methods triggers some other error.

@kasparsd
Copy link
Collaborator Author

kasparsd commented Dec 2, 2024

@ocean90 This is ready for another round of code review. I've described the approach in the description of the pull request and added a test to cover this new use-case during uninstall.

During normal operation the two_factor_providers filter is called only once and the get_providers() method can be refactored to accept the user ID, if necessary. However, after working through this changeset, I would suggest we introduce a new helper method for getting the user-specific providers instead extending get_providers() to ensure we have reliable data for a settings page eventually (#249).

@jeffpaul jeffpaul added this to the 0.11.0 milestone Dec 2, 2024
}
);

$this->assertNotContains( 'Two_Factor_Email', array_keys( Two_Factor_Core::get_providers() ), 'Default provider can be disabled via a filter' );
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@ocean90 @r-a-y Here is a unit test to confirm that a core provider can be disabled via the filter.

@kasparsd
Copy link
Collaborator Author

This has been revised and is ready for code review. I've also added unit tests to confirm that it fixes the issue and allows removing core providers.

Would appreciate a code review.

@r-a-y
Copy link
Contributor

r-a-y commented Dec 18, 2024

@kasparsd - Thanks for your work on this. I can confirm that it is once again possible to disable a core provider with the 'two_factor_providers' filter with this PR.

@kasparsd kasparsd changed the title Remove the duplicate filter for providers Remove duplicate two_factor_providers filter calls to allow disabling core providers Dec 18, 2024
@kasparsd kasparsd merged commit a29b140 into master Dec 18, 2024
48 checks passed
@kasparsd kasparsd deleted the fix-available-providers-filter branch December 18, 2024 17:19
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.

4 participants