Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 005a990

Browse filesBrowse files
elias-playfindereliasfernandez
authored andcommitted
[FrameworkBundle][Mailer] Add the process to sign the message on a listener (Fix 53941)
1 parent 6f4f04b commit 005a990
Copy full SHA for 005a990

File tree

14 files changed

+567
-0
lines changed
Filter options

14 files changed

+567
-0
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+75
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,81 @@ private function addMailerSection(ArrayNodeDefinition $rootNode, callable $enabl
22362236
->end()
22372237
->end()
22382238
->end()
2239+
->arrayNode('dkim_signer')
2240+
->addDefaultsIfNotSet()
2241+
->fixXmlConfig('option')
2242+
->canBeEnabled()
2243+
->info('DKIM signer configuration')
2244+
->children()
2245+
->scalarNode('key')
2246+
->info('Key content, or path to key (in PEM format with the `file://` prefix)')
2247+
->defaultValue('')
2248+
->cannotBeEmpty()
2249+
->end()
2250+
->scalarNode('domain')->defaultValue('')->end()
2251+
->scalarNode('select')->defaultValue('')->end()
2252+
->scalarNode('passphrase')
2253+
->info('A passphrase of the private key if any')
2254+
->defaultValue('')
2255+
->end()
2256+
->arrayNode('options')
2257+
->performNoDeepMerging()
2258+
->normalizeKeys(false)
2259+
->useAttributeAsKey('name')
2260+
->prototype('variable')->end()
2261+
->end()
2262+
->end()
2263+
->end()
2264+
->arrayNode('smime_signer')
2265+
->addDefaultsIfNotSet()
2266+
->canBeEnabled()
2267+
->info('SMIME signer configuration')
2268+
->children()
2269+
->scalarNode('key')
2270+
->info('Path to key (in PEM format)')
2271+
->defaultValue('')
2272+
->cannotBeEmpty()
2273+
->end()
2274+
->scalarNode('certificate')
2275+
->info('Path to certificate (in PEM format without the `file://` prefix)')
2276+
->defaultValue('')
2277+
->cannotBeEmpty()
2278+
->end()
2279+
->scalarNode('passphrase')
2280+
->info('A passphrase of the private key if any')
2281+
->defaultNull()
2282+
->end()
2283+
->scalarNode('extra_certificates')->defaultNull()->end()
2284+
->integerNode('sign_options')->defaultNull()->end()
2285+
->end()
2286+
->end()
2287+
->arrayNode('smime_encrypter')
2288+
->addDefaultsIfNotSet()
2289+
->canBeEnabled()
2290+
->info('SMIME encrypter configuration')
2291+
->children()
2292+
->scalarNode('certificate')
2293+
->info('Path to certificate (in PEM format without the `file://` prefix)')
2294+
->defaultValue('')
2295+
->cannotBeEmpty()
2296+
->end()
2297+
->integerNode('cipher')
2298+
->info('A set of algorithms used to encrypt the message')
2299+
->defaultNull()
2300+
->beforeNormalization()
2301+
->always(function ($v): ?int {
2302+
return null !== $v && \defined('OPENSSL_CIPHER_' . $v) ? \constant('OPENSSL_CIPHER_' . $v) : null;
2303+
})
2304+
->end()
2305+
->validate()
2306+
->ifTrue(function ($v) {
2307+
return \extension_loaded('openssl') && null !== $v && !\defined('OPENSSL_CIPHER_' . $v);
2308+
})
2309+
->thenInvalid('You must provide a valid cipher.')
2310+
->end()
2311+
->end()
2312+
->end()
2313+
->end()
22392314
->end()
22402315
->end()
22412316
->end()

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+45
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@
112112
use Symfony\Component\Lock\Store\StoreFactory;
113113
use Symfony\Component\Mailer\Bridge as MailerBridge;
114114
use Symfony\Component\Mailer\Command\MailerTestCommand;
115+
use Symfony\Component\Mailer\EventListener\DkimSignedMessageListener;
115116
use Symfony\Component\Mailer\EventListener\MessengerTransportListener;
117+
use Symfony\Component\Mailer\EventListener\SmimeEncryptedMessageListener;
118+
use Symfony\Component\Mailer\EventListener\SmimeSignedMessageListener;
116119
use Symfony\Component\Mailer\Mailer;
117120
use Symfony\Component\Mercure\HubRegistry;
118121
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@@ -2837,6 +2840,48 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
28372840
$container->removeDefinition('mailer.messenger_transport_listener');
28382841
}
28392842

2843+
if ($config['dkim_signer']['enabled']) {
2844+
if (!class_exists(DkimSignedMessageListener::class)) {
2845+
throw new LogicException('DKIM signed messages support cannot be enabled as the component is not up to date. Update the symfony/mailer.');
2846+
}
2847+
$dkimSigner = $container->getDefinition('mailer.dkim_signer');
2848+
$dkimSigner->setArgument(0, $config['dkim_signer']['key']);
2849+
$dkimSigner->setArgument(1, $config['dkim_signer']['domain']);
2850+
$dkimSigner->setArgument(2, $config['dkim_signer']['select']);
2851+
$dkimSigner->setArgument(3, $config['dkim_signer']['options']);
2852+
$dkimSigner->setArgument(4, $config['dkim_signer']['passphrase']);
2853+
} else {
2854+
$container->removeDefinition('mailer.dkim_signer');
2855+
$container->removeDefinition('mailer.dkim_signer.listener');
2856+
}
2857+
2858+
if ($config['smime_signer']['enabled']) {
2859+
if (!class_exists(SmimeSignedMessageListener::class)) {
2860+
throw new LogicException('SMIME signed messages support cannot be enabled as the component is not up to date. Update the symfony/mailer.');
2861+
}
2862+
$smimeSigner = $container->getDefinition('mailer.smime_signer');
2863+
$smimeSigner->setArgument(0, $config['smime_signer']['key']);
2864+
$smimeSigner->setArgument(1, $config['smime_signer']['certificate']);
2865+
$smimeSigner->setArgument(2, $config['smime_signer']['passphrase']);
2866+
$smimeSigner->setArgument(3, $config['smime_signer']['extra_certificates']);
2867+
$smimeSigner->setArgument(4, $config['smime_signer']['sign_options']);
2868+
} else {
2869+
$container->removeDefinition('mailer.smime_signer');
2870+
$container->removeDefinition('mailer.smime_signer.listener');
2871+
}
2872+
2873+
if ($config['smime_encrypter']['enabled']) {
2874+
if (!class_exists(SmimeEncryptedMessageListener::class)) {
2875+
throw new LogicException('SMIME encrypted messages support cannot be enabled as the component is not up to date. Update the symfony/mailer.');
2876+
}
2877+
$smimeDecrypter = $container->getDefinition('mailer.smime_encrypter');
2878+
$smimeDecrypter->setArgument(0, $config['smime_encrypter']['certificate']);
2879+
$smimeDecrypter->setArgument(1, $config['smime_encrypter']['cipher']);
2880+
} else {
2881+
$container->removeDefinition('mailer.smime_encrypter');
2882+
$container->removeDefinition('mailer.smime_encrypter.listener');
2883+
}
2884+
28402885
if ($webhookEnabled) {
28412886
$loader->load('mailer_webhook.php');
28422887
}

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php
+48
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,22 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

1414
use Symfony\Component\Mailer\Command\MailerTestCommand;
15+
use Symfony\Component\Mailer\EventListener\DkimSignedMessageListener;
1516
use Symfony\Component\Mailer\EventListener\EnvelopeListener;
1617
use Symfony\Component\Mailer\EventListener\MessageListener;
1718
use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
1819
use Symfony\Component\Mailer\EventListener\MessengerTransportListener;
20+
use Symfony\Component\Mailer\EventListener\SmimeEncryptedMessageListener;
21+
use Symfony\Component\Mailer\EventListener\SmimeSignedMessageListener;
1922
use Symfony\Component\Mailer\Mailer;
2023
use Symfony\Component\Mailer\MailerInterface;
2124
use Symfony\Component\Mailer\Messenger\MessageHandler;
2225
use Symfony\Component\Mailer\Transport;
2326
use Symfony\Component\Mailer\Transport\TransportInterface;
2427
use Symfony\Component\Mailer\Transport\Transports;
28+
use Symfony\Component\Mime\Crypto\DkimSigner;
29+
use Symfony\Component\Mime\Crypto\SMimeEncrypter;
30+
use Symfony\Component\Mime\Crypto\SMimeSigner;
2531

2632
return static function (ContainerConfigurator $container) {
2733
$container->services()
@@ -78,6 +84,48 @@
7884
->set('mailer.messenger_transport_listener', MessengerTransportListener::class)
7985
->tag('kernel.event_subscriber')
8086

87+
->set('mailer.dkim_signer', DkimSigner::class)
88+
->args([
89+
abstract_arg('key'),
90+
abstract_arg('domain'),
91+
abstract_arg('select'),
92+
abstract_arg('options'),
93+
abstract_arg('passphrase'),
94+
])
95+
96+
->set('mailer.smime_signer', SMimeSigner::class)
97+
->args([
98+
abstract_arg('key'),
99+
abstract_arg('certificate'),
100+
abstract_arg('passphrase'),
101+
abstract_arg('extraCertificates'),
102+
abstract_arg('signOptions'),
103+
])
104+
105+
->set('mailer.smime_encrypter', SMimeEncrypter::class)
106+
->args([
107+
abstract_arg('certificate'),
108+
abstract_arg('cipher'),
109+
])
110+
111+
->set('mailer.dkim_signer.listener', DkimSignedMessageListener::class)
112+
->args([
113+
service(DkimSigner::class),
114+
])
115+
->tag('kernel.event_subscriber')
116+
117+
->set('mailer.smime_signer.listener', SmimeSignedMessageListener::class)
118+
->args([
119+
service('mailer.smime_signer'),
120+
])
121+
->tag('kernel.event_subscriber')
122+
123+
->set('mailer.smime_encrypter.listener', SmimeEncryptedMessageListener::class)
124+
->args([
125+
service('mailer.smime_encrypter'),
126+
])
127+
->tag('kernel.event_subscriber')
128+
81129
->set('console.command.mailer_test', MailerTestCommand::class)
82130
->args([
83131
service('mailer.transports'),

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+27
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,9 @@
789789
<xsd:element name="transport" type="mailer_transport" minOccurs="0" maxOccurs="unbounded" />
790790
<xsd:element name="envelope" type="mailer_envelope" minOccurs="0" maxOccurs="1" />
791791
<xsd:element name="header" type="header" minOccurs="0" maxOccurs="unbounded" />
792+
<xsd:element name="dkim-signer" type="mailer_dkim_signer" minOccurs="0" />
793+
<xsd:element name="smime-signer" type="mailer_smime_signer" minOccurs="0" />
794+
<xsd:element name="smime-encrypter" type="mailer_smime_encrypter" minOccurs="0" />
792795
</xsd:sequence>
793796
<xsd:attribute name="enabled" type="xsd:boolean" />
794797
<xsd:attribute name="dsn" type="xsd:string" />
@@ -811,6 +814,30 @@
811814
</xsd:sequence>
812815
</xsd:complexType>
813816

817+
818+
<xsd:complexType name="mailer_dkim_signer">
819+
<xsd:sequence>
820+
<xsd:element name="option" type="metadata" minOccurs="0" maxOccurs="unbounded" />
821+
</xsd:sequence>
822+
<xsd:attribute name="key" type="xsd:string"/>
823+
<xsd:attribute name="domain" type="xsd:string"/>
824+
<xsd:attribute name="select" type="xsd:string"/>
825+
<xsd:attribute name="passphrase" type="xsd:string" />
826+
</xsd:complexType>
827+
828+
<xsd:complexType name="mailer_smime_signer">
829+
<xsd:attribute name="key" type="xsd:string"/>
830+
<xsd:attribute name="certificate" type="xsd:string"/>
831+
<xsd:attribute name="passphrase" type="xsd:string" />
832+
<xsd:attribute name="extraCertificates" type="xsd:string" />
833+
<xsd:attribute name="signOptions" type="xsd:integer" />
834+
</xsd:complexType>
835+
836+
<xsd:complexType name="mailer_smime_encrypter">
837+
<xsd:attribute name="certificate" type="xsd:string"/>
838+
<xsd:attribute name="cipher" type="xsd:integer" />
839+
</xsd:complexType>
840+
814841
<xsd:complexType name="http_cache">
815842
<xsd:sequence>
816843
<xsd:element name="private-header" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+21
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,27 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
922922
'enabled' => !class_exists(FullStack::class) && class_exists(Mailer::class),
923923
'message_bus' => null,
924924
'headers' => [],
925+
'dkim_signer' => [
926+
'enabled' => false,
927+
'options' => [],
928+
'key' => '',
929+
'domain' => '',
930+
'select' => '',
931+
'passphrase' => '',
932+
],
933+
'smime_signer' => [
934+
'enabled' => false,
935+
'key' => '',
936+
'certificate' => '',
937+
'passphrase' => null,
938+
'extra_certificates' => null,
939+
'sign_options' => null,
940+
],
941+
'smime_encrypter' => [
942+
'enabled' => false,
943+
'certificate' => '',
944+
'cipher' => null,
945+
],
925946
],
926947
'notifier' => [
927948
'enabled' => !class_exists(FullStack::class) && class_exists(Notifier::class),

‎src/Symfony/Component/Mailer/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/CHANGELOG.md
+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Add DSN param `retry_period` to override default email transport retry period
88
* Add `Dsn::getBooleanOption()`
99
* Add DSN param `source_ip` to allow binding to a (specific) IPv4 or IPv6 address.
10+
* Enable the mailer to configure DKIM or SMIME signer
1011

1112
7.2
1213
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\EventListener;
13+
14+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\Mailer\Event\MessageEvent;
16+
use Symfony\Component\Mime\Crypto\DkimSigner;
17+
use Symfony\Component\Mime\Message;
18+
19+
/**
20+
* Signs the message.
21+
*
22+
* @author Elías Fernández
23+
*/
24+
class DkimSignedMessageListener implements EventSubscriberInterface
25+
{
26+
public function __construct(
27+
private DkimSigner $signer,
28+
) {
29+
}
30+
31+
public function onMessage(MessageEvent $event): void
32+
{
33+
$message = $event->getMessage();
34+
if (!$message instanceof Message) {
35+
return;
36+
}
37+
$event->setMessage($this->signer->sign($message));
38+
}
39+
40+
public static function getSubscribedEvents(): array
41+
{
42+
return [
43+
MessageEvent::class => ['onMessage', -128],
44+
];
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\EventListener;
13+
14+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15+
use Symfony\Component\Mailer\Event\MessageEvent;
16+
use Symfony\Component\Mime\Crypto\SMimeEncrypter;
17+
use Symfony\Component\Mime\Message;
18+
19+
/**
20+
* Encrypts the message.
21+
*
22+
* @author Elías Fernández
23+
*/
24+
class SmimeEncryptedMessageListener implements EventSubscriberInterface
25+
{
26+
public function __construct(
27+
private SMimeEncrypter $encrypter,
28+
) {
29+
}
30+
31+
public function onMessage(MessageEvent $event): void
32+
{
33+
$message = $event->getMessage();
34+
if (!$message instanceof Message) {
35+
return;
36+
}
37+
38+
$event->setMessage($this->encrypter->encrypt($message));
39+
}
40+
41+
public static function getSubscribedEvents(): array
42+
{
43+
return [
44+
MessageEvent::class => ['onMessage', -128],
45+
];
46+
}
47+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.