1<?php 2 3namespace MediaWiki\Auth; 4 5use MediaWiki\MediaWikiServices; 6use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait; 7use MediaWiki\User\UserNameUtils; 8use Psr\Container\ContainerInterface; 9use Psr\Log\LoggerInterface; 10use Wikimedia\TestingAccessWrapper; 11 12/** 13 * @covers \MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider 14 * @group Database 15 */ 16class EmailNotificationSecondaryAuthenticationProviderTest extends \MediaWikiIntegrationTestCase { 17 use AuthenticationProviderTestTrait; 18 19 /** 20 * @param array $options 21 * @return EmailNotificationSecondaryAuthenticationProvider 22 */ 23 private function getProvider( array $options = [] ): EmailNotificationSecondaryAuthenticationProvider { 24 $services = $this->getServiceContainer(); 25 $provider = new EmailNotificationSecondaryAuthenticationProvider( 26 $options['loadBalancer'] ?? $services->getDBLoadBalancer(), 27 $options // make things easier for tests by using the same options 28 ); 29 $this->initProvider( 30 $provider, 31 $options['config'] ?? null, 32 $options['logger'] ?? null, 33 $options['authManager'] ?? null, 34 $options['hookContainer'] ?? null, 35 $options['userNameUtils'] ?? null 36 ); 37 return $provider; 38 } 39 40 public function testConstructor() { 41 $config = new \HashConfig( [ 42 'EnableEmail' => true, 43 'EmailAuthentication' => true, 44 ] ); 45 46 $provider = $this->getProvider( [ 47 'config' => $config, 48 ] ); 49 $providerPriv = TestingAccessWrapper::newFromObject( $provider ); 50 $this->assertTrue( $providerPriv->sendConfirmationEmail ); 51 52 $provider = $this->getProvider( [ 53 'config' => $config, 54 'sendConfirmationEmail' => false, 55 ] ); 56 $providerPriv = TestingAccessWrapper::newFromObject( $provider ); 57 $this->assertFalse( $providerPriv->sendConfirmationEmail ); 58 } 59 60 /** 61 * @dataProvider provideGetAuthenticationRequests 62 * @param string $action 63 * @param AuthenticationRequest[] $expected 64 */ 65 public function testGetAuthenticationRequests( $action, $expected ) { 66 $provider = $this->getProvider( [ 67 'sendConfirmationEmail' => true, 68 ] ); 69 $this->assertSame( $expected, $provider->getAuthenticationRequests( $action, [] ) ); 70 } 71 72 public function provideGetAuthenticationRequests() { 73 return [ 74 [ AuthManager::ACTION_LOGIN, [] ], 75 [ AuthManager::ACTION_CREATE, [] ], 76 [ AuthManager::ACTION_LINK, [] ], 77 [ AuthManager::ACTION_CHANGE, [] ], 78 [ AuthManager::ACTION_REMOVE, [] ], 79 ]; 80 } 81 82 public function testBeginSecondaryAuthentication() { 83 $provider = $this->getProvider( [ 84 'sendConfirmationEmail' => true, 85 ] ); 86 $this->assertEquals( AuthenticationResponse::newAbstain(), 87 $provider->beginSecondaryAuthentication( \User::newFromName( 'Foo' ), [] ) ); 88 } 89 90 public function testBeginSecondaryAccountCreation() { 91 $mwServices = MediaWikiServices::getInstance(); 92 $services = $this->createNoOpAbstractMock( ContainerInterface::class ); 93 $objectFactory = new \Wikimedia\ObjectFactory( $services ); 94 $hookContainer = $this->createHookContainer(); 95 $userNameUtils = $this->createNoOpMock( UserNameUtils::class ); 96 $authManager = new AuthManager( 97 new \FauxRequest(), 98 new \HashConfig(), 99 $objectFactory, 100 $hookContainer, 101 $mwServices->getReadOnlyMode(), 102 $userNameUtils, 103 $mwServices->getBlockManager(), 104 $mwServices->getWatchlistManager(), 105 $mwServices->getDBLoadBalancer(), 106 $mwServices->getContentLanguage(), 107 $mwServices->getLanguageConverterFactory(), 108 $mwServices->getBotPasswordStore(), 109 $mwServices->getUserFactory(), 110 $mwServices->getUserIdentityLookup(), 111 $mwServices->getUserOptionsManager() 112 ); 113 114 $creator = $this->getMockBuilder( \User::class )->getMock(); 115 $userWithoutEmail = $this->getMockBuilder( \User::class )->getMock(); 116 $userWithoutEmail->method( 'getEmail' )->willReturn( '' ); 117 $userWithoutEmail->method( 'getInstanceForUpdate' )->willReturnSelf(); 118 $userWithoutEmail->expects( $this->never() )->method( 'sendConfirmationMail' ); 119 $userWithEmailError = $this->getMockBuilder( \User::class )->getMock(); 120 $userWithEmailError->method( 'getEmail' )->willReturn( 'foo@bar.baz' ); 121 $userWithEmailError->method( 'getInstanceForUpdate' )->willReturnSelf(); 122 $userWithEmailError->method( 'sendConfirmationMail' ) 123 ->willReturn( \Status::newFatal( 'fail' ) ); 124 $userExpectsConfirmation = $this->getMockBuilder( \User::class )->getMock(); 125 $userExpectsConfirmation->method( 'getEmail' ) 126 ->willReturn( 'foo@bar.baz' ); 127 $userExpectsConfirmation->method( 'getInstanceForUpdate' ) 128 ->willReturnSelf(); 129 $userExpectsConfirmation->expects( $this->once() )->method( 'sendConfirmationMail' ) 130 ->willReturn( \Status::newGood() ); 131 $userNotExpectsConfirmation = $this->getMockBuilder( \User::class )->getMock(); 132 $userNotExpectsConfirmation->method( 'getEmail' ) 133 ->willReturn( 'foo@bar.baz' ); 134 $userNotExpectsConfirmation->method( 'getInstanceForUpdate' ) 135 ->willReturnSelf(); 136 $userNotExpectsConfirmation->expects( $this->never() )->method( 'sendConfirmationMail' ); 137 138 $provider = $this->getProvider( [ 139 'sendConfirmationEmail' => false, 140 'authManager' => $authManager, 141 'hookContainer' => $hookContainer, 142 'userNameUtils' => $userNameUtils 143 ] ); 144 $provider->beginSecondaryAccountCreation( $userNotExpectsConfirmation, $creator, [] ); 145 146 $provider = $this->getProvider( [ 147 'sendConfirmationEmail' => true, 148 'authManager' => $authManager, 149 'userNameUtils' => $userNameUtils 150 ] ); 151 $provider->beginSecondaryAccountCreation( $userWithoutEmail, $creator, [] ); 152 $provider->beginSecondaryAccountCreation( $userExpectsConfirmation, $creator, [] ); 153 154 // test logging of email errors 155 $logger = $this->getMockForAbstractClass( LoggerInterface::class ); 156 $logger->expects( $this->once() )->method( 'warning' ); 157 $this->initProvider( $provider, null, $logger, $authManager ); 158 $provider->beginSecondaryAccountCreation( $userWithEmailError, $creator, [] ); 159 160 // test disable flag used by other providers 161 $authManager->setAuthenticationSessionData( 'no-email', true ); 162 $this->initProvider( $provider, null, null, $authManager ); 163 $provider->beginSecondaryAccountCreation( $userNotExpectsConfirmation, $creator, [] ); 164 } 165} 166