-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Microsoft POP3 XOAUTH2
Signed-off-by: Filippo Tessarotto <[email protected]>
- Loading branch information
Showing
7 changed files
with
293 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Laminas\Mail\Protocol\Pop3; | ||
|
||
/** | ||
* POP3 response value object | ||
* | ||
* @internal | ||
*/ | ||
final class Response | ||
{ | ||
/** @var string $status */ | ||
private $status; | ||
|
||
/** @var string $message */ | ||
private $message; | ||
|
||
public function __construct(string $status, string $message) | ||
{ | ||
$this->status = $status; | ||
$this->message = $message; | ||
} | ||
|
||
public function status(): string | ||
{ | ||
return $this->status; | ||
} | ||
|
||
public function message(): string | ||
{ | ||
return $this->message; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
namespace Laminas\Mail\Protocol\Pop3\Xoauth2; | ||
|
||
use Laminas\Mail\Protocol\Exception\RuntimeException; | ||
use Laminas\Mail\Protocol\Pop3; | ||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2; | ||
|
||
/** | ||
* @final | ||
*/ | ||
class Microsoft extends Pop3 | ||
{ | ||
protected const AUTH_INITIALIZE_REQUEST = 'AUTH XOAUTH2'; | ||
protected const AUTH_RESPONSE_INITIALIZED_OK = '+'; | ||
|
||
/** | ||
* @param string $user the target mailbox to access | ||
* @param string $password OAUTH2 accessToken | ||
* @param bool $tryApop obsolete parameter not used here | ||
*/ | ||
public function login($user, $password, $tryApop = true): void | ||
{ | ||
$this->sendRequest(self::AUTH_INITIALIZE_REQUEST); | ||
|
||
$response = $this->readRemoteResponse(); | ||
|
||
if ($response->status() != self::AUTH_RESPONSE_INITIALIZED_OK) { | ||
throw new RuntimeException($response->message()); | ||
} | ||
|
||
$this->request(Xoauth2::encodeXoauth2Sasl($user, $password)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Laminas\Mail\Protocol\Xoauth2; | ||
|
||
use function base64_encode; | ||
use function chr; | ||
use function sprintf; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
final class Xoauth2 | ||
{ | ||
/** | ||
* encodes accessToken and target mailbox to Xoauth2 SASL base64 encoded string | ||
*/ | ||
public static function encodeXoauth2Sasl(string $targetMailbox, string $accessToken): string | ||
{ | ||
return base64_encode( | ||
sprintf( | ||
"user=%s%sauth=Bearer %s%s%s", | ||
$targetMailbox, | ||
chr(0x01), | ||
$accessToken, | ||
chr(0x01), | ||
chr(0x01) | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LaminasTest\Mail\Protocol\Pop3; | ||
|
||
use Laminas\Mail\Protocol\Pop3\Response; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @covers Laminas\Mail\Protocol\Pop3\Response | ||
*/ | ||
class ResponseTest extends TestCase | ||
{ | ||
/** @psalm-suppress InternalClass */ | ||
public function testIntegration(): void | ||
{ | ||
/** @psalm-suppress InternalMethod */ | ||
$response = new Response('+OK', 'Auth'); | ||
|
||
/** @psalm-suppress InternalMethod */ | ||
$this->assertEquals('+OK', $response->status()); | ||
|
||
/** @psalm-suppress InternalMethod */ | ||
$this->assertEquals('Auth', $response->message()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LaminasTest\Mail\Protocol\Pop3\Xoauth2; | ||
|
||
use Laminas\Mail\Exception\RuntimeException; | ||
use Laminas\Mail\Protocol\Pop3\Response; | ||
use Laminas\Mail\Protocol\Pop3\Xoauth2\Microsoft; | ||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
use function fopen; | ||
use function rewind; | ||
use function str_replace; | ||
use function stream_get_contents; | ||
|
||
/** | ||
* @covers Laminas\Mail\Protocol\Pop3\Xoauth2\Microsoft | ||
*/ | ||
class MicrosoftTest extends TestCase | ||
{ | ||
/** @psalm-suppress InternalClass */ | ||
public function testIntegration(): void | ||
{ | ||
/** | ||
* @psalm-suppress PropertyNotSetInConstructor | ||
* @psalm-suppress InvalidExtendClass | ||
*/ | ||
$protocol = new class () extends Microsoft { | ||
private string $step; | ||
|
||
/** @psalm-suppress InternalClass */ | ||
public function readRemoteResponse(): Response | ||
{ | ||
if ($this->step === self::AUTH_INITIALIZE_REQUEST) { | ||
/** @psalm-suppress InternalMethod */ | ||
return new Response(self::AUTH_RESPONSE_INITIALIZED_OK, 'Auth initialized'); | ||
} | ||
|
||
/** @psalm-suppress InternalMethod */ | ||
return new Response('+OK', 'Authenticated'); | ||
} | ||
|
||
/** | ||
* Send a request | ||
* | ||
* @param string $request your request without newline | ||
* @throws RuntimeException | ||
*/ | ||
public function sendRequest($request): void | ||
{ | ||
$this->step = $request; | ||
parent::sendRequest($request); | ||
} | ||
|
||
/** | ||
* Open connection to POP3 server | ||
* | ||
* @param string $host hostname or IP address of POP3 server | ||
* @param int|null $port of POP3 server, default is 110 (995 for ssl) | ||
* @param string|bool $ssl use 'SSL', 'TLS' or false | ||
* @throws RuntimeException | ||
* @return string welcome message | ||
*/ | ||
public function connect($host, $port = null, $ssl = false) | ||
{ | ||
$this->socket = fopen("php://memory", 'rw+'); | ||
return ''; | ||
} | ||
|
||
/** | ||
* @return null|resource | ||
*/ | ||
public function getSocket() | ||
{ | ||
return $this->socket; | ||
} | ||
}; | ||
|
||
$protocol->connect('localhost', 0, false); | ||
|
||
$protocol->login('[email protected]', '123'); | ||
|
||
$this->assertInstanceOf(Microsoft::class, $protocol); | ||
|
||
$streamContents = ''; | ||
if ($socket = $protocol->getSocket()) { | ||
rewind($socket); | ||
$streamContents = stream_get_contents($socket); | ||
$streamContents = str_replace("\r\n", "\n", $streamContents); | ||
} | ||
|
||
/** @psalm-suppress InternalMethod */ | ||
$xoauth2Sasl = Xoauth2::encodeXoauth2Sasl('[email protected]', '123'); | ||
|
||
$this->assertEquals( | ||
'AUTH XOAUTH2' . "\n" . $xoauth2Sasl . "\n", | ||
$streamContents | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LaminasTest\Mail\Protocol\Xoauth2; | ||
|
||
use Laminas\Mail\Protocol\Xoauth2\Xoauth2; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @covers Laminas\Mail\Protocol\Xoauth2\Xoauth2 | ||
*/ | ||
class Xoauth2Test extends TestCase | ||
{ | ||
/** @psalm-suppress InternalClass */ | ||
public function testEncodeXoauth2Sasl(): void | ||
{ | ||
$accessToken = 'dXNlcj10ZXN0QGNvbnRvc28ub25taWNyb3NvZnQuY29tAWF1dGg9QmVhcmVyIEV3QkFBbDNCQUFVRkZwVUFvN'; | ||
$accessToken .= '0ozVmUwYmpMQldaV0NjbFJDM0VvQUEBAQ=='; | ||
|
||
/** | ||
* @psalm-suppress InternalMethod | ||
*/ | ||
$this->assertEquals( | ||
$accessToken, | ||
Xoauth2::encodeXoauth2Sasl( | ||
'[email protected]', | ||
'EwBAAl3BAAUFFpUAo7J3Ve0bjLBWZWCclRC3EoAA' | ||
) | ||
); | ||
} | ||
} |