Skip to content

Commit

Permalink
refactor SaslAuthenticator test
Browse files Browse the repository at this point in the history
  • Loading branch information
kadet1090 committed Aug 11, 2016
1 parent 641e7ab commit 5eff093
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Module/SaslAuthenticator.php
Expand Up @@ -51,7 +51,7 @@ class SaslAuthenticator extends ClientModule implements Authenticator
*/
public function __construct($password, Sasl $sasl = null)
{
$this->_password = $password;
$this->setPassword($password);
$this->_sasl = $sasl ?: new Sasl();
}

Expand Down
132 changes: 114 additions & 18 deletions Tests/SaslAuthenticatorTest.php
Expand Up @@ -17,6 +17,8 @@


use Fabiang\Sasl\Authentication\AuthenticationInterface;
use Fabiang\Sasl\Authentication\ChallengeAuthenticationInterface;
use Fabiang\Sasl\Exception\InvalidArgumentException;
use Fabiang\Sasl\Sasl;
use Kadet\Xmpp\Jid;
use Kadet\Xmpp\Module\SaslAuthenticator;
Expand All @@ -33,7 +35,45 @@
*/
class SaslAuthenticatorTest extends \PHPUnit_Framework_TestCase
{
public function testMechanismWithoutChallenge()
/** @var \PHPUnit_Framework_MockObject_MockObject|XmppClient */
private $_client;

/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->_client = $this->getMockClient();
}

public function testWithChallengeSuccess()
{
$this->mechanismWithChallenge();
$this->success();
}

public function testWithoutChallengeSuccess()
{
$this->mechanismWithoutChallenge();
$this->success();
}

/** @expectedException \Kadet\Xmpp\Exception\Protocol\AuthenticationException */
public function testWithChallengeFailure()
{
$this->mechanismWithChallenge();
$this->failure();
}

/** @expectedException \Kadet\Xmpp\Exception\Protocol\AuthenticationException */
public function testWithoutChallengeFailure()
{
$this->mechanismWithoutChallenge();
$this->failure();
}

private function mechanismWithoutChallenge()
{
$features = new Features([
new XmlElement('mechanisms', 'urn:ietf:params:xml:ns:xmpp-sasl', [
Expand All @@ -44,48 +84,104 @@ public function testMechanismWithoutChallenge()
$mechanism = $this->getMockForAbstractClass(AuthenticationInterface::class, [], 'StubAuthenticator');
$mechanism->expects($this->once())->method('createResponse')->willReturn('foobar');

$factory = $this->getSaslFactoryMock();
$factory->expects($this->atLeast(1))->method('factory')->with('STUB', $this->anything())->willReturn($mechanism);
$factory = $this->getSaslFactoryMock($mechanism);

$client = $this->getMockClient('local@domain.tld', 'password', $factory);
$client->expects($this->once())->method('write')->with($this->callback(function (XmlElement $element) {
$this->_client->register(new SaslAuthenticator('password', $factory));
$this->_client->expects($this->once())->method('write')->with($this->callback(function (XmlElement $element) {
$this->assertEquals('auth', $element->localName);
$this->assertEquals('STUB', $element->getAttribute('mechanism'));
$this->assertEquals('foobar', base64_decode($element->innerXml));

return true;
}));

$this->assertTrue($client->get(SaslAuthenticator::class)->auth($features));
$this->assertTrue($this->_client->get(SaslAuthenticator::class)->auth($features));
}

private function mechanismWithChallenge()
{
$features = new Features([
new XmlElement('mechanisms', 'urn:ietf:params:xml:ns:xmpp-sasl', [
new XmlElement('mechanism', null, 'STUB')
])
]);

$mechanism = $this->getMockForAbstractClass(ChallengeAuthenticationInterface::class, [], 'ChallengeStubAuthenticator');
$mechanism->expects($this->exactly(2))->method('createResponse')
->withConsecutive([], ['challenge'])
->willReturnOnConsecutiveCalls(
$this->throwException(new InvalidArgumentException()),
$this->returnValue('response')
);

$factory = $this->getSaslFactoryMock($mechanism);

$this->_client->register(new SaslAuthenticator('password', $factory));
$this->_client->expects($this->exactly(2))->method('write')->withConsecutive($this->callback(function (XmlElement $element) {
$this->assertEquals('auth', $element->localName);
$this->assertEquals('STUB', $element->getAttribute('mechanism'));
$this->assertEquals('=', $element->innerXml);

return true;
}), $this->callback(function (XmlElement $element) {
$this->assertEquals('response', $element->localName);
$this->assertEquals('response', base64_decode($element->innerXml));

return true;
}));

$this->assertTrue($this->_client->get(SaslAuthenticator::class)->auth($features));
$this->_client->emit('element', [
new XmlElement('challenge', 'urn:ietf:params:xml:ns:xmpp-sasl', base64_encode('challenge'))
]);
}

private function success()
{
$proceed = new XmlElement('success', 'urn:ietf:params:xml:ns:xmpp-sasl');

$this->_client->expects($this->once())->method('restart');
$this->_client->emit('element', [$proceed]);
}

private function failure()
{
$proceed = new XmlElement('failure', 'urn:ietf:params:xml:ns:xmpp-sasl');

$this->_client->emit('element', [$proceed]);
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject|Sasl
* @param $mechanism
* @return Sasl|\PHPUnit_Framework_MockObject_MockObject
*/
private function getSaslFactoryMock()
private function getSaslFactoryMock($mechanism)
{
return $this->getMockBuilder(Sasl::class)
$factory = $this->getMockBuilder(Sasl::class)
->disableAutoload()
->disableProxyingToOriginalMethods()
->setMethods(['factory'])
->getMock();

$factory->expects($this->atLeast(1))->method('factory')->with('STUB', $this->callback(function($options) {
return $options['secret'] == 'password'
&& $options['authcid'] == 'local'
&& $options['hostname'] == 'domain.tld';
}))->willReturn($mechanism);

return $factory;
}

/**
* @param $jid
* @param string $password
* @param Sasl $factory
* @return XmppClient|\PHPUnit_Framework_MockObject_MockObject
*/
private function getMockClient($jid, $password = 'password', Sasl $factory)
private function getMockClient()
{
return $this->getMockBuilder(XmppClient::class)
->setConstructorArgs([$jid instanceof Jid ? $jid : new Jid($jid), [
->setConstructorArgs([new Jid('local@domain.tld'), [
'connector' => new ConnectorStub(),
'modules' => [
new SaslAuthenticator($password, $factory)
]
]])->setMethods(['write', 'bind'])
'default-modules' => []
]])->setMethods(['write', 'bind', 'restart'])
->getMock();
}
}
7 changes: 4 additions & 3 deletions XmppClient.php
Expand Up @@ -83,10 +83,11 @@ class XmppClient extends XmlStream implements ContainerInterface
*/
public function __construct(Jid $jid, array $options = [])
{
$options = array_merge_recursive([
$options = array_replace([
'parser' => new XmlParser(new XmlElementFactory()),
'lang' => 'en',
'modules' => [
'modules' => [],
'default-modules' => [
new StartTls(),
new Binding()
]
Expand All @@ -105,7 +106,7 @@ public function __construct(Jid $jid, array $options = [])
$this->register(new SaslAuthenticator($options['password']));
}

foreach ($options['modules'] as $name => $module) {
foreach (array_merge($options['default-modules'], $options['modules']) as $name => $module) {
$this->register($module, is_string($name) ? $name : true);
}

Expand Down

0 comments on commit 5eff093

Please sign in to comment.