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

Implement singleton pattern for OpenID_Connect_Generic class #190

Merged
merged 4 commits into from
Feb 25, 2022

Conversation

RobjS
Copy link
Contributor

@RobjS RobjS commented Jun 3, 2020

This will allow developers who want to be able to call methods belonging to this class (or methods belonging to any of this class's properties) to do so, without having to create a new instance, and therefore repeat all the bootstrapping.

Instead, they will just be able to call OpenID_Connect_Generic::get() to retrieve the singleton.

@daggerhart
Copy link
Collaborator

Hi @RobjS,

I've thought about this PR a number of times and ultimately don't want to turn the main plugin class into a singleton. The point of the main plugin class is to hook the rest of the plugin into WP, and nothing more. If there are some methods on this class that a developer may want access to, then it makes more sense to move those methods to another class that is either a stateless service/utility thing, or if the method is closely related to the client or client wrapper, maybe move it there.

Do you have a use-case that needs access to someone methods on the main plugin class? That would help think through what other changes might be needed.

@RobjS
Copy link
Contributor Author

RobjS commented Jun 15, 2020

Hi @daggerhart,

Thanks for responding and merging the other two PRs. Hopefully it'll be useful if I provide some context around the issue we're having and what I was hoping to achieve with this PR.

We're seeing a small but sustained number of missing state errors. These have persisted even after applying the fix for the race condition (#171) and increasing the state time limit from a few minutes to several hours.

I think one possible cause of these is people clicking the OpenID Login button after the provided state token has expired (even given our increased state time limit). One potential fix for this could be to start the countdown on the state token validity when the login button is clicked, rather than when the page containing the login button is served.

Rather than open a PR making that (potentially quite substantial) change within the plugin, I was aiming to use the new openid-connect-generic-login-button-url filter from #191 to point users initially to an internal page when the button was clicked, and at that point call the client wrapper's get_authentication_url() method to generate the relevant login URL & state token, and redirect the user to that URL.

However, that method would only be available by new-ing up the client wrapper and its dependencies (and their dependencies in turn), which feels unnecessarily clunky. Instead, I was hoping this change would allow me to do something like:

$openIdConnectGeneric = \OpenID_Connect_Generic::get();
$url = $openIdConnectGeneric->client_wrapper->get_authentication_url();
wp_redirect($url);

My hope was that the change in this PR was self-contained enough that it would enable this level of customisation, without having any impact on other plugin users. But if you have a preferred approach, I'm happy to amend the PR accordingly 👍

@RobjS
Copy link
Contributor Author

RobjS commented Aug 18, 2020

Hi @daggerhart, do you have any more thoughts on the above?

@timnolte timnolte added the enhancement Issues & PRs related to new features. label Aug 20, 2020
@daggerhart
Copy link
Collaborator

daggerhart commented Aug 20, 2020

@RobjS Yes! Thanks for asking.

I don't mind making a singleton (or global variable) out of the plugin class for this version 3.x, but I wouldn't want people to use it directly. I'd rather that be paired with some simple functions for getting the specific thing people might want.

For example:

function oidcg_get_authentication_url() {
  return \OpenID_Connect_Generic::get()->client_wrapper->get_authentication_url();
}

This way, we aren't stuck with the singleton pattern forever just for the sake of backwards compatibility.

I imagine that the 4.x version of this module would be significantly different in architecture, and I wouldn't want people to start relying on the actual singleton within their site. Same applies to the client_wrapper, and other classes. Atm, the client wrapper is doing Waaaay too much work and needs to be split up into different services. If people start relying directly on that class for its methods, then we're a little bit stuck with that going forward.

What do you think?

@timnolte
Copy link
Collaborator

@daggerhart I would agree that it would be much better to provide global functions that we can have documented as the supported what of providing this functionality. This will allow us to adjust them, as needed, when/if the plugin structure changes.

@timnolte timnolte added the status: needs review PR that needs review. label Aug 27, 2020
@daggerhart
Copy link
Collaborator

@RobjS,

I thought about this more over the long weekend, and think we can move forward with this PR with a few changes.

  1. Let's change the ::get() method name to ::instance() -- this is very minor, just preference.
  2. Can you create a new includes/functions.php file, that makes use of the new singleton instance to provide the specific things you want to use? For example, the get_authentication_url() method from the client wrapper, or any other parts of the plugin you need in the short term. Doesn't have to be extensive, just what you need for now.

@RobjS RobjS force-pushed the feature/implement-singleton-pattern branch from 19b13c3 to 932ded9 Compare September 22, 2020 09:14
@RobjS RobjS force-pushed the feature/implement-singleton-pattern branch 4 times, most recently from 6c71ba4 to 864185c Compare September 22, 2020 09:57
@RobjS
Copy link
Contributor Author

RobjS commented Sep 22, 2020

Thanks @daggerhart, that all sounds good to me.

I've made those changes to the PR. It's just the one function in functions.php for now, but hopefully that works as a starting point.

@timnolte
Copy link
Collaborator

@RobjS please ensure you are using the local development environment provided by the plugin to ensure that your PR meets coding standards and code quality requirements. Right now your PR has failed some of the code quality checks. When setting up the local plugin development environment things are setup to ensure that your code is checked on your local machine before you are even able to commit code changes. Thanks!

This will allow developers who want to be able to call methods belonging to this class (or methods belonging to any of this class's properties) to do so, without having to create a new instance, and therefore repeat all the bootstrapping.

Instead, they will just be able to call OpenID_Connect_Generic::instance() to retrieve the singleton.
These will act as wrappers for methods you would otherwise call by getting the Open_ID_Connect_Generic singleton and then calling the appropriate method.
@RobjS RobjS force-pushed the feature/implement-singleton-pattern branch from 864185c to 91e1574 Compare September 22, 2020 10:29
@timnolte timnolte added status: needs changelog Mark all PRs that have not had their changelog entries added. status: needs docs Needs explanation in release notes, README, or documentation. labels Sep 22, 2020
This allows us to access client_wrapper methods via the singleton of Open_ID_Connect_Generic.
@RobjS
Copy link
Contributor Author

RobjS commented Sep 22, 2020

Thanks @timnolte. Sorry about that, it looks like a lot of tests & CI have been added since I originally started on the PR 👍

Everything should be passing now.

@timnolte
Copy link
Collaborator

@RobjS since we don't currently have unit testing in place, I'm assuming that you've tested these changes fully on your own development environment and have confirmed the plugin is still working as expected?

@timnolte timnolte added this to the 3.9 Release milestone Sep 24, 2020
@gassan
Copy link
Contributor

gassan commented Sep 24, 2020

Why not simply to rename boostrap() to instance(), make constructor private and modify instance() like followed:

public static function instance() {
    static $instance;

    if ($instance === null) {
        .....
        $instance = new self( $settings, $logger );
 
        ... // add actions and filters
    }

    return $instance;
}

It is better to avoid publishing $instance variable. class should be accessible only with static instance() method

@gassan
Copy link
Contributor

gassan commented Sep 24, 2020

it would be nice to add the next function:

public function get_setting_values() {
    return $this->settings->get_values();
}

we could read settings (for our plugins) but not change them.

For example I need Register User Endpoint and in my case that would be:

preg_replace('/auth$/', 'register', OpenID_Connect_Generic::instance()->get_setting_values()['endpoint_login]);

@timnolte
Copy link
Collaborator

@gassan the plugin uses standard WordPress core methods for settings, I don't see a need to expose our own method when you can just get this using core WordPress functionality.

@gassan
Copy link
Contributor

gassan commented Sep 26, 2020

@timnolte Of course we can read settings from db. Nevertheless, I would like to ask @daggerhart to check whether the $settings can be public.
Thanks.

@timnolte
Copy link
Collaborator

@gassan you do realize that I'm also a maintainer of the plugin?

My point is that what methods are made public need to be carefully considered and should only be done where there is not already a method for accomplishing this. That is also why the plugin already supports so many hooks and generally provides what is needed through those means, but in some cases there is a need that can't be accomplished without a code change.

My stance is that there is no sense adding additional code to maintain, and develop tests for, that already have a working solution. From my standpoint the primary focus of changes right now need to be those that fix real issues that are preventing people from using the plugin, or requests that, if implemented, will enhance the security and the usability with existing IDPs.

@RobjS
Copy link
Contributor Author

RobjS commented Oct 2, 2020

@RobjS since we don't currently have unit testing in place, I'm assuming that you've tested these changes fully on your own development environment and have confirmed the plugin is still working as expected?

@timnolte Yes, tested in my dev environment and the plugin is behaving as expected.

Copy link
Collaborator

@timnolte timnolte left a comment

Choose a reason for hiding this comment

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

@daggerhart I'm going to approve these changes.

@timnolte timnolte self-assigned this Jan 12, 2021
@timnolte
Copy link
Collaborator

@RobjS FYI, would you be able to get this branch updated with the latest changes in the dev branch? I'm pushing out a fix release and will be looking to bring in as many approved PRs into the next feature release soon. Thanks!

@timnolte timnolte added status: approved PRs that have been approved and ready to be merged. and removed status: needs review PR that needs review. labels Jan 13, 2021
@RobjS
Copy link
Contributor Author

RobjS commented Jan 14, 2021

Thanks @timnolte - done.

@timnolte timnolte added this to To do in 3.9.0 Release Jan 30, 2021
@timnolte timnolte moved this from To do to In progress in 3.9.0 Release Jan 30, 2021
@timnolte
Copy link
Collaborator

@RobjS my apologies, I'm actually getting PRs merged in ready for a new release, I know it's been a long time coming. For some reason GitHub isn't allowing my to rebase your branch to bring it up-to-date. Would you be able to get your branch up-to-date with the latest in our dev branch and then I'll get this merged in and ready for the release. Thanks!

@timnolte
Copy link
Collaborator

@RobjS never mind on my last comment. I made some updates to the repository configuration and that appears to have resolved the issues I was seeing.

@timnolte timnolte merged commit 480dded into oidc-wp:dev Feb 25, 2022
@timnolte timnolte moved this from In progress to Done in 3.9.0 Release Feb 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Issues & PRs related to new features. status: approved PRs that have been approved and ready to be merged. status: needs changelog Mark all PRs that have not had their changelog entries added. status: needs docs Needs explanation in release notes, README, or documentation.
Projects
No open projects
3.9.0 Release
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants