]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / tests / phpunit / includes / auth / AuthPluginPrimaryAuthenticationProviderTest.php
diff --git a/tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php b/tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php
new file mode 100644 (file)
index 0000000..6970313
--- /dev/null
@@ -0,0 +1,716 @@
+<?php
+
+namespace MediaWiki\Auth;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider
+ */
+class AuthPluginPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
+       public function testConstruction() {
+               $plugin = new AuthManagerAuthPlugin();
+               try {
+                       $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \InvalidArgumentException $ex ) {
+                       $this->assertSame(
+                               'Trying to wrap AuthManagerAuthPlugin in AuthPluginPrimaryAuthenticationProvider ' .
+                                       'makes no sense.',
+                               $ex->getMessage()
+                       );
+               }
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       [ new PasswordAuthenticationRequest ],
+                       $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] )
+               );
+
+               $req = $this->createMock( PasswordAuthenticationRequest::class );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin, get_class( $req ) );
+               $this->assertEquals(
+                       [ $req ],
+                       $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] )
+               );
+
+               $reqType = get_class( $this->createMock( AuthenticationRequest::class ) );
+               try {
+                       $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin, $reqType );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \InvalidArgumentException $ex ) {
+                       $this->assertSame(
+                               "$reqType is not a MediaWiki\\Auth\\PasswordAuthenticationRequest",
+                               $ex->getMessage()
+                       );
+               }
+       }
+
+       public function testOnUserSaveSettings() {
+               $user = \User::newFromName( 'UTSysop' );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'updateExternalDB' )
+                       ->with( $this->identicalTo( $user ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               \Hooks::run( 'UserSaveSettings', [ $user ] );
+       }
+
+       public function testOnUserGroupsChanged() {
+               $user = \User::newFromName( 'UTSysop' );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'updateExternalDBGroups' )
+                       ->with(
+                               $this->identicalTo( $user ),
+                               $this->identicalTo( [ 'added' ] ),
+                               $this->identicalTo( [ 'removed' ] )
+                       );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               \Hooks::run( 'UserGroupsChanged', [ $user, [ 'added' ], [ 'removed' ] ] );
+       }
+
+       public function testOnUserLoggedIn() {
+               $user = \User::newFromName( 'UTSysop' );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->exactly( 2 ) )->method( 'updateUser' )
+                       ->with( $this->identicalTo( $user ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               \Hooks::run( 'UserLoggedIn', [ $user ] );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'updateUser' )
+                       ->will( $this->returnCallback( function ( &$user ) {
+                               $user = \User::newFromName( 'UTSysop' );
+                       } ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               try {
+                       \Hooks::run( 'UserLoggedIn', [ $user ] );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \UnexpectedValueException $ex ) {
+                       $this->assertSame(
+                               get_class( $plugin ) . '::updateUser() tried to replace $user!',
+                               $ex->getMessage()
+                       );
+               }
+       }
+
+       public function testOnLocalUserCreated() {
+               $user = \User::newFromName( 'UTSysop' );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->exactly( 2 ) )->method( 'initUser' )
+                       ->with( $this->identicalTo( $user ), $this->identicalTo( false ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'initUser' )
+                       ->will( $this->returnCallback( function ( &$user ) {
+                               $user = \User::newFromName( 'UTSysop' );
+                       } ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               try {
+                       \Hooks::run( 'LocalUserCreated', [ $user, false ] );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \UnexpectedValueException $ex ) {
+                       $this->assertSame(
+                               get_class( $plugin ) . '::initUser() tried to replace $user!',
+                               $ex->getMessage()
+                       );
+               }
+       }
+
+       public function testGetUniqueId() {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertSame(
+                       'MediaWiki\\Auth\\AuthPluginPrimaryAuthenticationProvider:' . get_class( $plugin ),
+                       $provider->getUniqueId()
+               );
+       }
+
+       /**
+        * @dataProvider provideGetAuthenticationRequests
+        * @param string $action
+        * @param array $response
+        * @param bool $allowPasswordChange
+        */
+       public function testGetAuthenticationRequests( $action, $response, $allowPasswordChange ) {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'allowPasswordChange' )
+                       ->will( $this->returnValue( $allowPasswordChange ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
+       }
+
+       public static function provideGetAuthenticationRequests() {
+               $arr = [ new PasswordAuthenticationRequest() ];
+               return [
+                       [ AuthManager::ACTION_LOGIN, $arr, true ],
+                       [ AuthManager::ACTION_LOGIN, $arr, false ],
+                       [ AuthManager::ACTION_CREATE, $arr, true ],
+                       [ AuthManager::ACTION_CREATE, $arr, false ],
+                       [ AuthManager::ACTION_LINK, [], true ],
+                       [ AuthManager::ACTION_LINK, [], false ],
+                       [ AuthManager::ACTION_CHANGE, $arr, true ],
+                       [ AuthManager::ACTION_CHANGE, [], false ],
+                       [ AuthManager::ACTION_REMOVE, $arr, true ],
+                       [ AuthManager::ACTION_REMOVE, [], false ],
+               ];
+       }
+
+       public function testAuthentication() {
+               $req = new PasswordAuthenticationRequest();
+               $req->action = AuthManager::ACTION_LOGIN;
+               $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->never() )->method( 'authenticate' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( [] )
+               );
+
+               $req->username = 'foo';
+               $req->password = null;
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $req->username = null;
+               $req->password = 'bar';
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $req->username = 'foo';
+               $req->password = 'bar';
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'authenticate' )
+                       ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       AuthenticationResponse::newPass( 'Foo', $req ),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( false ) );
+               $plugin->expects( $this->never() )->method( 'authenticate' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+                       ->setMethods( [ 'isLocked' ] )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $pluginUser->expects( $this->once() )->method( 'isLocked' )
+                       ->will( $this->returnValue( true ) );
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'getUserInstance', 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'getUserInstance' )
+                       ->will( $this->returnValue( $pluginUser ) );
+               $plugin->expects( $this->never() )->method( 'authenticate' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'authenticate' )
+                       ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( false ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAuthentication( $reqs )
+               );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'authenticate', 'strict' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'authenticate' )
+                       ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( false ) );
+               $plugin->expects( $this->any() )->method( 'strict' )->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $ret = $provider->beginPrimaryAuthentication( $reqs );
+               $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+               $this->assertSame( 'wrongpassword', $ret->message->getKey() );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'authenticate', 'strictUserAuth' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'authenticate' )
+                       ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( false ) );
+               $plugin->expects( $this->any() )->method( 'strictUserAuth' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $ret = $provider->beginPrimaryAuthentication( $reqs );
+               $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+               $this->assertSame( 'wrongpassword', $ret->message->getKey() );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'domainList', 'validDomain', 'setDomain', 'userExists', 'authenticate' ] )
+                       ->getMock();
+               $plugin->expects( $this->any() )->method( 'domainList' )
+                       ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+               $plugin->expects( $this->any() )->method( 'validDomain' )
+                       ->will( $this->returnCallback( function ( $domain ) {
+                               return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+                       } ) );
+               $plugin->expects( $this->once() )->method( 'setDomain' )
+                       ->with( $this->equalTo( 'Domain2' ) );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'authenticate' )
+                       ->with( $this->equalTo( 'Foo' ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_LOGIN, [] );
+               $req->username = 'foo';
+               $req->password = 'bar';
+               $req->domain = 'Domain2';
+               $provider->beginPrimaryAuthentication( [ $req ] );
+       }
+
+       public function testTestUserExists() {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertTrue( $provider->testUserExists( 'foo' ) );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( false ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertFalse( $provider->testUserExists( 'foo' ) );
+       }
+
+       public function testTestUserCanAuthenticate() {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( false ) );
+               $plugin->expects( $this->never() )->method( 'getUserInstance' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertFalse( $provider->testUserCanAuthenticate( 'foo' ) );
+
+               $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $pluginUser->expects( $this->once() )->method( 'isLocked' )
+                       ->will( $this->returnValue( true ) );
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'getUserInstance' )
+                       ->with( $this->callback( function ( $user ) {
+                               $this->assertInstanceOf( 'User', $user );
+                               $this->assertEquals( 'Foo', $user->getName() );
+                               return true;
+                       } ) )
+                       ->will( $this->returnValue( $pluginUser ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertFalse( $provider->testUserCanAuthenticate( 'foo' ) );
+
+               $pluginUser = $this->getMockBuilder( 'AuthPluginUser' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $pluginUser->expects( $this->once() )->method( 'isLocked' )
+                       ->will( $this->returnValue( false ) );
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'userExists' )
+                       ->with( $this->equalTo( 'Foo' ) )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'getUserInstance' )
+                       ->with( $this->callback( function ( $user ) {
+                               $this->assertInstanceOf( 'User', $user );
+                               $this->assertEquals( 'Foo', $user->getName() );
+                               return true;
+                       } ) )
+                       ->will( $this->returnValue( $pluginUser ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertTrue( $provider->testUserCanAuthenticate( 'foo' ) );
+       }
+
+       public function testProviderRevokeAccessForUser() {
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'userExists', 'setPassword' ] )
+                       ->getMock();
+               $plugin->expects( $this->once() )->method( 'userExists' )->willReturn( true );
+               $plugin->expects( $this->once() )->method( 'setPassword' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->identicalTo( null ) )
+                       ->willReturn( true );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $provider->providerRevokeAccessForUser( 'foo' );
+
+               $plugin = $this->getMockBuilder( 'AuthPlugin' )
+                       ->setMethods( [ 'domainList', 'userExists', 'setPassword' ] )
+                       ->getMock();
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [ 'D1', 'D2', 'D3' ] );
+               $plugin->expects( $this->exactly( 3 ) )->method( 'userExists' )
+                       ->willReturnCallback( function () use ( $plugin ) {
+                               return $plugin->getDomain() !== 'D2';
+                       } );
+               $plugin->expects( $this->exactly( 2 ) )->method( 'setPassword' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->identicalTo( null ) )
+                       ->willReturnCallback( function () use ( $plugin ) {
+                               $this->assertNotEquals( 'D2', $plugin->getDomain() );
+                               return $plugin->getDomain() !== 'D1';
+                       } );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               try {
+                       $provider->providerRevokeAccessForUser( 'foo' );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \UnexpectedValueException $ex ) {
+                       $this->assertSame(
+                               'AuthPlugin failed to reset password for Foo in the following domains: D1',
+                               $ex->getMessage()
+                       );
+               }
+       }
+
+       public function testProviderAllowsPropertyChange() {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'allowPropChange' )
+                       ->will( $this->returnCallback( function ( $prop ) {
+                               return $prop === 'allow';
+                       } ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertTrue( $provider->providerAllowsPropertyChange( 'allow' ) );
+               $this->assertFalse( $provider->providerAllowsPropertyChange( 'deny' ) );
+       }
+
+       /**
+        * @dataProvider provideProviderAllowsAuthenticationDataChange
+        * @param string $type
+        * @param bool|null $allow
+        * @param StatusValue $expect
+        */
+       public function testProviderAllowsAuthenticationDataChange( $type, $allow, $expect ) {
+               $domains = $type instanceof PasswordDomainAuthenticationRequest ? [ 'foo', 'bar' ] : [];
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( $domains );
+               $plugin->expects( $allow === null ? $this->never() : $this->once() )
+                       ->method( 'allowPasswordChange' )->will( $this->returnValue( $allow ) );
+               $plugin->expects( $this->any() )->method( 'validDomain' )
+                       ->willReturnCallback( function ( $d ) use ( $domains ) {
+                               return in_array( $d, $domains, true );
+                       } );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               if ( is_object( $type ) ) {
+                       $req = $type;
+               } else {
+                       $req = $this->createMock( $type );
+               }
+               $req->action = AuthManager::ACTION_CHANGE;
+               $req->username = 'UTSysop';
+               $req->password = 'Pa$$w0Rd!!!';
+               $req->retype = 'Pa$$w0Rd!!!';
+               $this->assertEquals( $expect, $provider->providerAllowsAuthenticationDataChange( $req ) );
+       }
+
+       public static function provideProviderAllowsAuthenticationDataChange() {
+               $domains = [ 'foo', 'bar' ];
+               $reqNoDomain = new PasswordDomainAuthenticationRequest( $domains );
+               $reqValidDomain = new PasswordDomainAuthenticationRequest( $domains );
+               $reqValidDomain->domain = 'foo';
+               $reqInvalidDomain = new PasswordDomainAuthenticationRequest( $domains );
+               $reqInvalidDomain->domain = 'invalid';
+
+               return [
+                       [ AuthenticationRequest::class, null, \StatusValue::newGood( 'ignored' ) ],
+                       [ new PasswordAuthenticationRequest, true, \StatusValue::newGood() ],
+                       [
+                               new PasswordAuthenticationRequest,
+                               false,
+                               \StatusValue::newFatal( 'authmanager-authplugin-setpass-denied' )
+                       ],
+                       [ $reqNoDomain, true, \StatusValue::newGood( 'ignored' ) ],
+                       [ $reqValidDomain, true, \StatusValue::newGood() ],
+                       [
+                               $reqInvalidDomain,
+                               true,
+                               \StatusValue::newFatal( 'authmanager-authplugin-setpass-bad-domain' )
+                       ],
+               ];
+       }
+
+       public function testProviderChangeAuthenticationData() {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->never() )->method( 'setPassword' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $provider->providerChangeAuthenticationData(
+                       $this->createMock( AuthenticationRequest::class )
+               );
+
+               $req = new PasswordAuthenticationRequest();
+               $req->action = AuthManager::ACTION_CHANGE;
+               $req->username = 'foo';
+               $req->password = 'bar';
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'setPassword' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $provider->providerChangeAuthenticationData( $req );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )->method( 'setPassword' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( false ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               try {
+                       $provider->providerChangeAuthenticationData( $req );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( \ErrorPageError $e ) {
+                       $this->assertSame( 'authmanager-authplugin-setpass-failed-title', $e->title );
+                       $this->assertSame( 'authmanager-authplugin-setpass-failed-message', $e->msg );
+               }
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )
+                       ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+               $plugin->expects( $this->any() )->method( 'validDomain' )
+                       ->will( $this->returnCallback( function ( $domain ) {
+                               return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+                       } ) );
+               $plugin->expects( $this->once() )->method( 'setDomain' )
+                       ->with( $this->equalTo( 'Domain2' ) );
+               $plugin->expects( $this->once() )->method( 'setPassword' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_CREATE, [] );
+               $req->username = 'foo';
+               $req->password = 'bar';
+               $req->domain = 'Domain2';
+               $provider->providerChangeAuthenticationData( $req );
+       }
+
+       /**
+        * @dataProvider provideAccountCreationType
+        * @param bool $can
+        * @param string $expect
+        */
+       public function testAccountCreationType( $can, $expect ) {
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->once() )
+                       ->method( 'canCreateAccounts' )->will( $this->returnValue( $can ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertSame( $expect, $provider->accountCreationType() );
+       }
+
+       public static function provideAccountCreationType() {
+               return [
+                       [ true, PrimaryAuthenticationProvider::TYPE_CREATE ],
+                       [ false, PrimaryAuthenticationProvider::TYPE_NONE ],
+               ];
+       }
+
+       public function testTestForAccountCreation() {
+               $user = \User::newFromName( 'foo' );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       \StatusValue::newGood(),
+                       $provider->testForAccountCreation( $user, $user, [] )
+               );
+       }
+
+       public function testAccountCreation() {
+               $user = \User::newFromName( 'foo' );
+               $user->setEmail( 'email' );
+               $user->setRealName( 'realname' );
+
+               $req = new PasswordAuthenticationRequest();
+               $req->action = AuthManager::ACTION_CREATE;
+               $reqs = [ PasswordAuthenticationRequest::class => $req ];
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+                       ->will( $this->returnValue( false ) );
+               $plugin->expects( $this->never() )->method( 'addUser' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               try {
+                       $provider->beginPrimaryAccountCreation( $user, $user, [] );
+                       $this->fail( 'Expected exception was not thrown' );
+               } catch ( \BadMethodCallException $ex ) {
+                       $this->assertSame(
+                               'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
+                       );
+               }
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->never() )->method( 'addUser' );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAccountCreation( $user, $user, [] )
+               );
+
+               $req->username = 'foo';
+               $req->password = null;
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+               );
+
+               $req->username = null;
+               $req->password = 'bar';
+               $this->assertEquals(
+                       AuthenticationResponse::newAbstain(),
+                       $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+               );
+
+               $req->username = 'foo';
+               $req->password = 'bar';
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'addUser' )
+                       ->with(
+                               $this->callback( function ( $u ) {
+                                       return $u instanceof \User && $u->getName() === 'Foo';
+                               } ),
+                               $this->equalTo( 'bar' ),
+                               $this->equalTo( 'email' ),
+                               $this->equalTo( 'realname' )
+                       )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $this->assertEquals(
+                       AuthenticationResponse::newPass(),
+                       $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
+               );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'domainList' )->willReturn( [] );
+               $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->once() )->method( 'addUser' )
+                       ->with(
+                               $this->callback( function ( $u ) {
+                                       return $u instanceof \User && $u->getName() === 'Foo';
+                               } ),
+                               $this->equalTo( 'bar' ),
+                               $this->equalTo( 'email' ),
+                               $this->equalTo( 'realname' )
+                       )
+                       ->will( $this->returnValue( false ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               $ret = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
+               $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
+               $this->assertSame( 'authmanager-authplugin-create-fail', $ret->message->getKey() );
+
+               $plugin = $this->createMock( 'AuthPlugin' );
+               $plugin->expects( $this->any() )->method( 'canCreateAccounts' )
+                       ->will( $this->returnValue( true ) );
+               $plugin->expects( $this->any() )->method( 'domainList' )
+                       ->will( $this->returnValue( [ 'Domain1', 'Domain2' ] ) );
+               $plugin->expects( $this->any() )->method( 'validDomain' )
+                       ->will( $this->returnCallback( function ( $domain ) {
+                               return in_array( $domain, [ 'Domain1', 'Domain2' ] );
+                       } ) );
+               $plugin->expects( $this->once() )->method( 'setDomain' )
+                       ->with( $this->equalTo( 'Domain2' ) );
+               $plugin->expects( $this->once() )->method( 'addUser' )
+                       ->with( $this->callback( function ( $u ) {
+                               return $u instanceof \User && $u->getName() === 'Foo';
+                       } ), $this->equalTo( 'bar' ) )
+                       ->will( $this->returnValue( true ) );
+               $provider = new AuthPluginPrimaryAuthenticationProvider( $plugin );
+               list( $req ) = $provider->getAuthenticationRequests( AuthManager::ACTION_CREATE, [] );
+               $req->username = 'foo';
+               $req->password = 'bar';
+               $req->domain = 'Domain2';
+               $provider->beginPrimaryAccountCreation( $user, $user, [ $req ] );
+       }
+
+}