8000 Fix 53941 Add the process to sign the message on a listener · symfony/symfony@f514909 · GitHub
[go: up one dir, main page]

Skip to content

Commit f514909

Browse files
Fix 53941 Add the process to sign the message on a listener
1 parent 5cabe45 commit f514909

File tree

9 files changed

+277
-0
lines changed

9 files changed

+277
-0
lines changed

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,37 @@ private function addMailerSection(ArrayNodeDefinition $rootNode, callable $enabl
22002200
->end()
22012201
->end()
22022202
->end()
2203+
->children()
2204+
->arrayNode('dkim_signer')
2205+
->fixXmlConfig('option')
2206+
->canBeEnabled()
2207+
->info('DKIM signer configuration')
2208+
->children()
2209+
->scalarNode('key')->end()
2210+
->scalarNode('domain')->end()
2211+
->scalarNode('select')->end()
2212+
->scalarNode('passphrase')->end()
2213+
->arrayNode('options')
2214+
->performNoDeepMerging()
2215+
->normalizeKeys(false)
2216+
->useAttributeAsKey('name')
2217+
->defaultValue([])
2218+
->prototype('variable')->end()
2219+
->end()
2220+
->end()
2221+
->end()
2222+
->arrayNode('smime_signer')
2223+
->canBeEnabled()
2224+
->info('SMIME signer configuration')
2225+
->children()
2226+
->scalarNode('key')->end()
2227+
->scalarNode('certificate')->end()
2228+
->scalarNode('passphrase')->end()
2229+
->scalarNode('extra_certificates')->end()
2230+
->scalarNode('sign_options')->end()
2231+
->end()
2232+
->end()
2233+
->end()
22032234
->end()
22042235
->end()
22052236
;

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,6 +2742,36 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
27422742
$container->removeDefinition('mailer.messenger_transport_listener');
27432743
}
27442744

2745+
if ($config['dkim_signer']['enabled']) {
2746+
$dkimSigner = $container->getDefinition('mailer.dkim_signer');
2747+
$dkimSigner->setArgument(0, $config['dkim_signer']['key'] ?? null);
2748+
$dkimSigner->setArgument(1, $config['dkim_signer']['domain'] ?? null);
2749+
$dkimSigner->setArgument(2, $config['dkim_signer']['select'] ?? null);
2750+
$dkimSigner->setArgument(3, $config['dkim_signer']['options'] ?? []);
2751+
$dkimSigner->setArgument(4, $config['dkim_signer']['passphrase'] ?? null);
2752+
2753+
$dkimSignerListener = $container->getDefinition('mailer.dkim_signer.listener');
2754+
$dkimSignerListener->setArgument(0, $dkimSigner ?? null);
2755+
} else {
2756+
$container->removeDefinition('mailer.dkim_signer.listener');
2757+
$container->removeDefinition('mailer.dkim_signer');
2758+
}
2759+
2760+
if ($config['smime_signer']['enabled']) {
2761+
$smimeSigner = $container->getDefinition('mailer.smime_signer');
2762+
$smimeSigner->setArgument(0, $config['smime_signer']['key'] ?? null);
2763+
$smimeSigner->setArgument(1, $config['smime_signer']['certificate'] ?? null);
2764+
$smimeSigner->setArgument(2, $config['smime_signer']['passphrase'] ?? null);
2765+
$smimeSigner->setArgument(3, $config['smime_signer']['extra_certificates'] ?? null);
2766+
$smimeSigner->setArgument(4, $config['smime_signer']['sign_options'] ?? null);
2767+
2768+
$smimeSignerListener = $container->getDefinition('mailer.smime_signer.listener');
2769+
$smimeSignerListener->setArgument(0, $smimeSigner ?? null);
2770+
} else {
2771+
$container->removeDefinition('mailer.smime_signer.listener');
2772+
$container->removeDefinition('mailer.smime_signer');
2773+
}
2774+
27452775
if ($webhookEnabled) {
27462776
$loader->load('mailer_webhook.php');
27472777
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
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\SmimeSignedMessageListener;
1921
use Symfony\Component\Mailer\Mailer;
2022
use Symfony\Component\Mailer\MailerInterface;
2123
use Symfony\Component\Mailer\Messenger\MessageHandler;
2224
use Symfony\Component\Mailer\Transport;
2325
use Symfony\Component\Mailer\Transport\TransportInterface;
2426
use Symfony\Component\Mailer\Transport\Transports;
27+
use Symfony\Component\Mime\Crypto\DkimSigner;
28+
use Symfony\Component\Mime\Crypto\SMimeSigner;
2529

2630
return static function (ContainerConfigurator $container) {
2731
$container->services()
@@ -78,6 +82,36 @@
7882
->set('mailer.messenger_transport_listener', MessengerTransportListener::class)
7983
->tag('kernel.event_subscriber')
8084

85+
->set('mailer.dkim_signer', DkimSigner::class)
86+
->args([
87+
abstract_arg('key'),
88+
abstract_arg('domain'),
89+
abstract_arg('select'),
90+
abstract_arg('options'),
91+
abstract_arg('passphrase'),
92+
])
93+
94+
->set('mailer.smime_signer', SMimeSigner::class)
95+
->args([
96+
abstract_arg('key'),
97+
abstract_arg('certificate'),
98+
abstract_arg('passphrase'),
99+
abstract_arg('extraCertificates'),
100+
abstract_arg('signOptions'),
101+
])
102+
103+
->set('mailer.dkim_signer.listener', DkimSignedMessageListener::class)
104+
->args([
105+
service('mailer.dkim_signer'),
106+
])
107+
->tag('kernel.event_subscriber')
108+
109+
->set('mailer.smime_signer.listener', SmimeSignedMessageListener::class)
110+
->args([
111+
service('mailer.smime_signer'),
112+
])
113+
->tag('kernel.event_subscriber')
114+
81115
->set('console.command.mailer_test', MailerTestCommand::class)
82116
->args([
83117
service('mailer.transports'),

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@
770770
<xsd:element name="transport" type="mailer_transport" minOccurs="0" maxOccurs="unbounded" />
771771
<xsd:element name="envelope" type="mailer_envelope" minOccurs="0" maxOccurs="1" />
772772
<xsd:element name="header" type="header" minOccurs="0" maxOccurs="unbounded" />
773+
<xsd:element name="dkim_signer" type="mailer_dkim_signer" minOccurs="0" />
774+
<xsd:element name="smime_signer" type="mailer_smime_signer" minOccurs="0" />
773775
</xsd:sequence>
774776
<xsd:attribute name="enabled" type="xsd:boolean" />
775777
<xsd:attribute name="dsn" type="xsd:string" />
@@ -792,6 +794,25 @@
792794
</xsd:sequence>
793795
</xsd:complexType>
794796

797+
798+
<xsd:complexType name="mailer_dkim_signer" mixed="true">
799+
<xsd:sequence>
800+
<xsd:element name="options" type="metadata" minOccurs="0" maxOccurs="unbounded" />
801+
</xsd:sequence>
802+
<xsd:attribute name="key" type="xsd:string" use="required" />
803+
<xsd:attribute name="domain" type="xsd:string" use="required" />
804+
<xsd:attribute name="select" type="xsd:string" use="required" />
805+
<xsd:attribute name="passphrase" type="xsd:string" />
806+
</xsd:complexType>
807+
808+
<xsd:complexType name="mailer_smime_signer" mixed="true">
809+
<xsd:attribute name="key" type="xsd:string" use="required" />
810+
<xsd:attribute name="certificate" type="xsd:string" use="required" />
811+
<xsd:attribute name="passphrase" type ="xsd:string" />
812+
<xsd:attribute name="extraCertificates" type ="xsd:string" />
813+
<xsd:attribute name="signOptions" type="xsd:integer" />
814+
</xsd:complexType>
815+
795816
<xsd:complexType name="http_cache">
796817
<xsd:sequence>
797818
<xsd:element name="private-header" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,13 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
910910
'enabled' => !class_exists(FullStack::class) && class_exists(Mailer::class),
911911
'message_bus' => null,
912912
'headers' => [],
913+
'dkim_signer' => [
914+
'enabled' => false,
915+
'options' => [],
916+
],
917+
'smime_signer' => [
918+
'enabled' => false,
919+
],
913920
],
914921
'notifier' => [
915922
'enabled' => !class_exists(FullStack::class) && class_exists(Notifier::class),

src/Symfony/Component/Mailer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CHANGELOG
1111

1212
* Make `TransportFactoryTestCase` compatible with PHPUnit 10+
1313
* Support unicode email addresses such as "dømi@dømi.fo"
14+
* Enable the mailer to configure DKIM or SMIME signer
15+
1416

1517
7.1
1618
---
Lines changed: 46 additions & 0 deletions
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 Fabien Potencier <fabien@symfony.com>
23+
* @author Elías Fernández
24+
*/
25+
class DkimSignedMessageListener implements EventSubscriberInterface
26+
{
27+
public function __construct(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+
}
Lines changed: 47 additions & 0 deletions
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\SMimeSigner;
17+
use Symfony\Component\Mime\Message;
18+
19+
/**
20+
* Signs the message.
21+
*
22+
* @author Fabien Potencier <fabien@symfony.com>
23+
* @author Elías Fernández
24+
*/
25+
class SmimeSignedMessageListener implements EventSubscriberInterface
26+
{
27+
public function __construct(private SMimeSigner $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+
38+
$event->setMessage($this->signer->sign($message));
39+
}
40+
41+
public static function getSubscribedEvents(): array
42+
{
43+
return [
44+
MessageEvent::class => ['onMessage', -128],
45+
];
46+
}
47+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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\Tests\EventListener;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mailer\Envelope;
16+
use Symfony\Component\Mailer\Event\MessageEvent;
17+
use Symfony\Component\Mailer\EventListener\DkimSignedMessageListener;
18+
use Symfony\Component\Mime\Address;
19+
use Symfony\Component\Mime\Crypto\DkimSigner;
20+
use Symfony\Component\Mime\Header\Headers;
21+
use Symfony\Component\Mime\Header\MailboxListHeader;
22+
use Symfony\Component\Mime\Message;
23+
use Symfony\Component\Mime\Part\TextPart;
24+
25+
class DkimSignedMessageListenerTest extends TestCase
26+
{
27+
public function testDkimMessageSigningProcess()
28+
{
29+
$signer = new DkimSigner(<<<KEY
30+
-----BEGIN RSA PRIVATE KEY-----
31+
MIICXAIBAAKBgQDbESTusnjpHAlqnU/zIcNcI1dskQBEG8N4mQo408n33M5FGLxo
32+
WoCQyqnnyujc2gkpG8aiPJFFnToWkbE8H+ursRRLBgdrCQOJh+akPEt4aNqiD/JK
33+
HxLr+1ar9zVUvvPuT4nbrJK44ixEyFbpV+xgiSWWIb8xtsRtoXEoH9yYrQIDAQAB
34+
AoGAGHi00HldamT4ZFGIcdeOtEc6Z+VWy0TytBEchDacdDTVUgCuY1Xg0Mvi6QLQ
35+
uoMczNvOd6ceb1FeANFrpBTIxaM68K/lIUn2fYrtcBpGtbXbSf5hTZhApFiEnQ1u
36+
H2TV+ItW6OYFLtZNY+Vym5/7HrXx/ADHSlMqA3KS8UEN/v0CQQD5RGhrwy92M0wh
37+
2UdSuL5IepjMvpeHcpbJlxtY8jhygnSDmvJtSdgFbP/VSzkYqnlFwXztRRt5F4XT
38+
aUQepFk/AkEA4PvpowzEZk6YnYMQV7qFYARJIB5nLpwCxPbvIooi8adiCuUBwxxe
39+
hRwRM9vHp641safMUaE/T/OovLVEezbHEwJBAOVn0t5SjWywO0HvsRdtlRopUlUk
40+
l1p92E6Bdha/HbotW8P/J1vzmQ8tSKpph4uu4NuU/j9z2ZvxTSXLfHji8osCQCUD
41+
jNaUXSNvvs/7Jg8o0pSPX/B20AbtB8+byI/oJgOXxBuCvZ1551sC2RmtCNXfZVoK
42+
/yRW4PGoZpRVRiT3SB0CQCkSOXB6YoLDagS3X10RInlGkB5pfBd1cG1pQS7YEFjX
43+
Y4x0EYVpNU9oHyeMlLgyevy07udFZXvHItT6WgbspQQ=
44+
-----END RSA PRIVATE KEY-----
45+
KEY, 'symfony.com', 's1');
46+
$listener = new DkimSignedMessageListener($signer);
47+
$message = new Message(
48+
new Headers(
49+
new MailboxListHeader('From', [new Address('sender@example.com')])
50+
),
51+
new TextPart('hello')
52+
);
53+
$envelope = new Envelope(new Address('sender@example.com'), [new Address('r1@example.com')]);
54+
$event = new MessageEvent($message, $envelope, 'default');
55+
56+
$listener->onMessage($event);
57+
$this->assertNotEquals($message, $event->getMessage());
58+
}
59+
}

0 commit comments

Comments
 (0)
0