X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/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 index 00000000..69703134 --- /dev/null +++ b/tests/phpunit/includes/auth/AuthPluginPrimaryAuthenticationProviderTest.php @@ -0,0 +1,716 @@ +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 ] ); + } + +}