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

Feature #15664: Google OAuth plugin for emails #3054

Merged
merged 34 commits into from Oct 6, 2023

Conversation

gabrieljenik
Copy link
Collaborator

@gabrieljenik gabrieljenik commented Apr 17, 2023

Done

  • New email sending method: OAuthSMTP
  • Enhancements to core for allowing OAuthSmtpPlugins
    • Global Settings
    • Lime Mailer
    • New Plugin Events (see below)
    • New screen for launching the OAuth RefreshToken Retrieval Process
    • New endpoint for receiving the OAuth RefreshToken
    • Base for OAuth Plugins
  • OAuthSmtp Plugin for Google
  • OAuthSmtp Plugin for Azure
  • New features for Plugins:
    • Health Status

Plugin Events Added

listSMTPOauthPlugins

When selecting the email method, the user should get a list of available plugins to select the active one.
This event allows plugins to enlist in the dropdown.

afterSelectSMTPOAuthPlugin

The OAuth mechanism is based on a refresh token, that the client uses to authenticate to the provider.
This should be triggered by the admin user. Afer setting the smtp provider, the admin user is invited to trigger the process with a custom message, set from this plugin event.

beforePrepareRedirectToAuthPage

Before showing the button for launching the provider AuthPage, we need to know specifics, as for example, what is the size of the popup open, or specific messages to appear on that screen with instructions. This event provides so.

beforeRedirectToAuthPage

Before redirecting to the provider AuthPage, we need to know specifics, as for example, the provider URL. Also, set the state (similar to a CSRF) for later validation of the response. This event provides so.

afterReceiveOAuthResponse

When receiving a response from OAuth, the plugin (through this event) will process the response (ideally using the provider methods), extract the refreshtoken and save the refreshtoken on the session settings.

newSMTPOAuthInitialization

When sending emails, PHPMailer needs a provider (class which extends AbstractProvider) to authenticate with the provider.
The provider needs to be set from the plugin, using the event newSMTPOAuthInitialization

Pendings:

  • Add summary here
  • Some doc.
  • Unit tests

Wish / Nice to Have

  • Plugin Feature: Help Tab (should be easy to implement)

Some screenshots:

image
image
image
image
image
image
image
image

@Shnoulle
Copy link
Collaborator

Seems great, but

  1. Can be less related to OAuth ? For example : allow POP3 in plugin too
  2. Need a way to add vendor by plugin , and share vendor by plugin … an new system maybe ?

For 1 : i ask some question and put some idea

For 2 : i need to report as a new dev issue (we already have this vendor in Auth plugin for example)

@olleharstedt
Copy link
Contributor

234 files changed?

@gabrieljenik
Copy link
Collaborator Author

234 files changed?

Lot of vendor files

@olleharstedt
Copy link
Contributor

CI says you need to run composer install or update in web root folder.

- Extend support for non-OAuth email plugins
@gabrieljenik gabrieljenik added Code review done Version checked for code issue without testing and removed Needs code review labels Apr 26, 2023
Unit tests added for isCurrentEmailPlugin, saveSettings and getCredentials functions.
Unit tests added for the listEmailPlugins event.
@sonarcloud
Copy link

sonarcloud bot commented May 2, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 4 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot E 3 Security Hotspots
Code Smell A 53 Code Smells

0.0% 0.0% Coverage
7.0% 7.0% Duplication

@olleharstedt
Copy link
Contributor

Getting

AdminController cannot find the requested view "/admin/pluginmanager/partial/topbarBtns/rightSideButtons".

when clicking on plugin details.

$this->setOAuthState($plugin, $event->get('state'));

header('Location: ' . $authUrl);
exit;
Copy link
Contributor

Choose a reason for hiding this comment

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

Yii::app()->end; ?


private function getHelpContent()
{
$this->subscribe('getPluginTwigPath');
Copy link
Contributor

Choose a reason for hiding this comment

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

Subscribe? Is getPluginTwigPath an event?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes it is :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Where is it documented? I didn't find it on the plugin event manual page.

Copy link
Contributor

Choose a reason for hiding this comment

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

Found it. I don't understand why it's needed tho, can't you just use $this->renderPartial() and it will look in the views/ folder inside the plugin automatically?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Found it. I don't understand why it's needed tho, can't you just use $this->renderPartial() and it will look in the views/ folder inside the plugin automatically?

Currently no. View folder are not added automatically.

Copy link
Contributor

Choose a reason for hiding this comment

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

Found it. I don't understand why it's needed tho, can't you just use $this->renderPartial() and it will look in the views/ folder inside the plugin automatically?

Currently no. View folder are not added automatically.

    $content = $this->api->renderTwig(__DIR__ . '/views/index.twig', $data);

https://github.com/olleharstedt/MassAction/blob/master/MassAction.php#L228

That's not enough?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Found it. I don't understand why it's needed tho, can't you just use $this->renderPartial() and it will look in the views/ folder inside the plugin automatically?

Currently no. View folder are not added automatically.

    $content = $this->api->renderTwig(__DIR__ . '/views/index.twig', $data);

https://github.com/olleharstedt/MassAction/blob/master/MassAction.php#L228

That's not enough?

Oh !! You're right !

getPluginTwigPath isb only needed for Public page : to allow theme to replace the twig file !

Sorry !

Can be removed : you're right

SettingGlobal::setSetting('emailplugin', $emailPlugin);
// If the email plugin has changed, dispatch an event to allow the new plugin to do any necessary setup.
if ($emailMethod == LimeMailer::MethodPlugin && $oldEmailPlugin != $emailPlugin) {
$event = new PluginEvent('afterSelectEmailPlugin', $this);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this new event needed, or can we use afterControllerAction? Oh wait, there's only beforeControllerAction... Should we add afterControllerAction instead? It's way more general than afterSelectEmailPlugin.

@@ -604,6 +627,20 @@ public function Send()
$this->setError(gT('Email was not sent because demo-mode is activated.'));
return false;
}

// If the email method is set to "Plugin", we need to dispatch an event to that specific plugin
// so it can perform it's logic without depending on the more generic "beforeEmail" event.
Copy link
Contributor

Choose a reason for hiding this comment

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

without depending on the more generic "beforeEmail" event.

Why not depend on this one? Not possible/easy?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should read some back and forth to remember, but I recall one of the issue was the priority among beforeEmail events.

@olleharstedt
Copy link
Contributor

This is really good stuff, I just have some concern regarding too many new events.

olleharstedt added a commit that referenced this pull request Jul 4, 2023
@gabrieljenik
Copy link
Collaborator Author

This is really good stuff, I just have some concern regarding too many new events.

Well many of them are needed by the oAuth protocol.
Some of them are needed for integrating the setup process.

Let's review on a call

olleharstedt added a commit that referenced this pull request Jul 4, 2023
@tiborpacalat
Copy link
Collaborator

I am pretty sure we fixed this already, but in this branch I am getting 500 when I try to scan for plugins

Screenshot 2023-07-04 at 14 57 40

Then when I zip and upload a plugin and click on the name to set it up

Screenshot 2023-07-04 at 15 01 09

Base automatically changed from develop to master July 25, 2023 12:41
@gabrieljenik gabrieljenik changed the base branch from master to develop September 25, 2023 13:32
@tiborpacalat tiborpacalat merged commit a27c12a into develop Oct 6, 2023
20 checks passed
@tiborpacalat tiborpacalat deleted the feature/15664-Google-OAuth-plugin-3 branch October 6, 2023 06:55
Copy link
Contributor

Choose a reason for hiding this comment

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

@gabrieljenik Binary files should not be part of PR. I already removed it in a fixing commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Code review done Version checked for code issue without testing Needs testing
Projects
None yet
5 participants