Skip to content

Commit

Permalink
throw better exception when imap authentication fails (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
frederikbosch authored Oct 13, 2020
1 parent 95d72b8 commit 107a88a
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 7 deletions.
28 changes: 21 additions & 7 deletions src/Protocol/Imap/Negotiation/AuthNegotiation.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace Genkgo\Mail\Protocol\Imap\Negotiation;

use Genkgo\Mail\Exception\AssertionFailedException;
use Genkgo\Mail\Exception\ImapAuthenticationException;
use Genkgo\Mail\Protocol\Imap\Client;
use Genkgo\Mail\Protocol\Imap\NegotiationInterface;
Expand Down Expand Up @@ -88,7 +89,7 @@ public function negotiate(Client $client): void
->first()
->assertContinuation();

$client
$taggedResponse = $client
->emit(
new AuthPlainCredentialsRequest(
$tag,
Expand All @@ -97,16 +98,29 @@ public function negotiate(Client $client): void
)
)
->last()
->assertCompletion(CompletionResult::ok())
->assertTagged();

try {
$taggedResponse->assertCompletion(CompletionResult::ok());
} catch (AssertionFailedException $e) {
throw new ImapAuthenticationException(
'Failed to authenticate: ' . $taggedResponse->getBody()
);
}
break;
case Client::AUTH_LOGIN:
$tag = $client->newTag();
$client
->emit(new LoginCommand($tag, $this->username, $this->password))
$taggedResponse = $client
->emit(new LoginCommand($client->newTag(), $this->username, $this->password))
->last()
->assertTagged()
->assertCompletion(CompletionResult::ok());
->assertTagged();

try {
$taggedResponse->assertCompletion(CompletionResult::ok());
} catch (AssertionFailedException $e) {
throw new ImapAuthenticationException(
'Failed to authenticate: ' . $taggedResponse->getBody()
);
}
break;
}
}
Expand Down
88 changes: 88 additions & 0 deletions test/Unit/Protocol/Imap/Negotiation/AuthNegotiationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,92 @@ public function it_uses_capability_when_method_is_auto_and_not_advertised_and_lo
$negotiation = new AuthNegotiation(Client::AUTH_AUTO, 'username', 'password');
$negotiation->negotiate($client);
}

/**
* @test
*/
public function it_throws_auth_exception_when_plain_auth_fails(): void
{
$this->expectException(ImapAuthenticationException::class);
$this->expectExceptionMessage('Failed to authenticate: NO [AUTHENTICATIONFAILED] Authentication failed.');

$connection = $this->createMock(ConnectionInterface::class);
$connection
->expects($this->at(0))
->method('addListener');

$connection
->expects($this->at(1))
->method('send')
->with("TAG1 AUTHENTICATE PLAIN\r\n");

$connection
->expects($this->at(2))
->method('receive')
->willReturn('+ Send password');

$connection
->expects($this->at(3))
->method('send')
->with("AHVzZXJuYW1lAHBhc3N3b3Jk\r\n");

$connection
->expects($this->at(4))
->method('receive')
->willReturn('TAG1 NO [AUTHENTICATIONFAILED] Authentication failed.');

$client = new Client($connection, new GeneratorTagFactory(), []);

$negotiation = new AuthNegotiation(Client::AUTH_PLAIN, 'username', 'password');
$negotiation->negotiate($client);
}

/**
* @test
*/
public function it_throws_auth_exception_when_login_fails(): void
{
$this->expectException(ImapAuthenticationException::class);
$this->expectExceptionMessage('Failed to authenticate: NO [AUTHENTICATIONFAILED] Authentication failed.');

$connection = $this->createMock(ConnectionInterface::class);
$connection
->expects($this->at(0))
->method('addListener');

$connection
->expects($this->at(1))
->method('send')
->with("TAG1 CAPABILITY\r\n");

$connection
->expects($this->at(2))
->method('receive')
->willReturn('* CAPABILITY IMAP4rev1 STARTTLS');

$connection
->expects($this->at(3))
->method('receive')
->willReturn('TAG1 OK');

$connection
->expects($this->at(4))
->method('send')
->with("TAG2 LOGIN username password\r\n");

$connection
->expects($this->at(5))
->method('receive')
->willReturn('TAG2 NO [AUTHENTICATIONFAILED] Authentication failed.');

$client = new Client($connection, new GeneratorTagFactory(), []);

$negotiation = new AuthNegotiation(Client::AUTH_AUTO, 'username', 'password');
$negotiation->negotiate($client);

$client = new Client($connection, new GeneratorTagFactory(), []);

$negotiation = new AuthNegotiation(Client::AUTH_PLAIN, 'username', 'password');
$negotiation->negotiate($client);
}
}

0 comments on commit 107a88a

Please sign in to comment.