From f0aa35b5807109e00ca8524251bf801241269f82 Mon Sep 17 00:00:00 2001
From: Joas Schilling
Date: Fri, 17 Jul 2020 11:14:02 +0200
Subject: [PATCH 03/10] Make RegistrationService strict
Signed-off-by: Joas Schilling
---
lib/Service/RegistrationService.php | 97 +++++++++++++++--------------
1 file changed, 50 insertions(+), 47 deletions(-)
diff --git a/lib/Service/RegistrationService.php b/lib/Service/RegistrationService.php
index 49528d8..2dfd3b3 100644
--- a/lib/Service/RegistrationService.php
+++ b/lib/Service/RegistrationService.php
@@ -1,4 +1,7 @@
* @copyright Copyright (c) 2017 Pellaeon Lin
@@ -34,8 +37,6 @@ use OC\Authentication\Token\IToken;
use OCA\Registration\Db\Registration;
use OCA\Registration\Db\RegistrationMapper;
use OCP\AppFramework\Db\DoesNotExistException;
-use \OCP\AppFramework\Http\TemplateResponse;
-use \OCP\AppFramework\Http\RedirectResponse;
use OCP\ILogger;
use OCP\IRequest;
use OCP\ISession;
@@ -71,7 +72,7 @@ class RegistrationService {
/** @var ISecureRandom */
private $random;
/** @var IUserSession */
- private $usersession;
+ private $userSession;
/** @var IRequest */
private $request;
/** @var ILogger */
@@ -83,9 +84,23 @@ class RegistrationService {
/** @var ICrypto */
private $crypto;
- public function __construct($appName, MailService $mailService, IL10N $l10n, IURLGenerator $urlGenerator,
- RegistrationMapper $registrationMapper, IUserManager $userManager, IConfig $config, IGroupManager $groupManager,
- ISecureRandom $random, IUserSession $us, IRequest $request, ILogger $logger, ISession $session, IProvider $tokenProvider, ICrypto $crypto) {
+ public function __construct(
+ string $appName,
+ MailService $mailService,
+ IL10N $l10n,
+ IURLGenerator $urlGenerator,
+ RegistrationMapper $registrationMapper,
+ IUserManager $userManager,
+ IConfig $config,
+ IGroupManager $groupManager,
+ ISecureRandom $random,
+ IUserSession $userSession,
+ IRequest $request,
+ ILogger $logger,
+ ISession $session,
+ IProvider $tokenProvider,
+ ICrypto $crypto
+ ) {
$this->appName = $appName;
$this->mailService = $mailService;
$this->l10n = $l10n;
@@ -95,7 +110,7 @@ class RegistrationService {
$this->config = $config;
$this->groupManager = $groupManager;
$this->random = $random;
- $this->usersession = $us;
+ $this->userSession = $userSession;
$this->request = $request;
$this->logger = $logger;
$this->session = $session;
@@ -103,21 +118,16 @@ class RegistrationService {
$this->crypto = $crypto;
}
- /**
- * @param Registration $registration
- */
- public function confirmEmail(Registration $registration) {
+ public function confirmEmail(Registration $registration): void {
$registration->setEmailConfirmed(true);
$this->registrationMapper->update($registration);
}
- /**
- * @param Registration $registration
- */
- public function generateNewToken(Registration $registration) {
+ public function generateNewToken(Registration $registration): void {
$this->registrationMapper->generateNewToken($registration);
$this->registrationMapper->update($registration);
}
+
/**
* Create registration request, used by both the API and form
* @param string $email
@@ -126,7 +136,7 @@ class RegistrationService {
* @param string $displayname
* @return Registration
*/
- public function createRegistration($email, $username="", $password="", $displayname="") {
+ public function createRegistration(string $email, string $username = '', string $password = '', string $displayname = ''): Registration {
$registration = new Registration();
$registration->setEmail($email);
$registration->setUsername($username);
@@ -178,8 +188,8 @@ class RegistrationService {
* @param string $displayname
* @throws RegistrationException
*/
- public function validateDisplayname($displayname) {
- if ($displayname === "") {
+ public function validateDisplayname(string $displayname): void {
+ if ($displayname === '') {
throw new RegistrationException($this->l10n->t('Please provide a valid display name.'));
}
}
@@ -188,7 +198,7 @@ class RegistrationService {
* @param string $username
* @throws RegistrationException
*/
- public function validateUsername($username) {
+ public function validateUsername(string $username): void {
if ($username === "") {
throw new RegistrationException($this->l10n->t('Please provide a valid user name.'));
}
@@ -204,7 +214,7 @@ class RegistrationService {
* @param string $email
* @return bool
*/
- public function checkAllowedDomains($email) {
+ public function checkAllowedDomains(string $email): bool {
$allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
if ($allowed_domains !== '') {
$allowed_domains = explode(';', $allowed_domains);
@@ -223,9 +233,9 @@ class RegistrationService {
}
/**
- * @return array
+ * @return string[]
*/
- public function getAllowedDomains() {
+ public function getAllowedDomains(): array {
$allowed_domains = $this->config->getAppValue($this->appName, 'allowed_domains', '');
$allowed_domains = explode(';', $allowed_domains);
return $allowed_domains;
@@ -250,10 +260,10 @@ class RegistrationService {
* @param $registration
* @param string|null $username
* @param string|null $password
- * @return \OCP\IUser
+ * @return IUser
* @throws RegistrationException|InvalidTokenException
*/
- public function createAccount(Registration $registration, ?string $username = null, ?string $password = null) {
+ public function createAccount(Registration $registration, ?string $username = null, ?string $password = null): IUser {
if ($password === null && $registration->getPassword() === null) {
$generatedPassword = $this->generateRandomDeviceToken();
$registration->setPassword($this->crypto->encrypt($generatedPassword));
@@ -281,6 +291,7 @@ class RegistrationService {
throw new RegistrationException($this->l10n->t('Unable to create user, there are problems with the user backend.'));
}
$userId = $user->getUID();
+
// Set user email
try {
$user->setEMailAddress($registration->getEmail());
@@ -289,25 +300,25 @@ class RegistrationService {
}
// Add user to group
- $registered_user_group = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
- if ($registered_user_group !== 'none') {
- $group = $this->groupManager->get($registered_user_group);
+ $registeredUserGroup = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
+ if ($registeredUserGroup !== 'none') {
+ $group = $this->groupManager->get($registeredUserGroup);
if ($group === null) {
// This might happen if $registered_user_group is deleted after setting the value
// Here I choose to log error instead of stopping the user to register
- $this->logger->error("You specified newly registered users be added to '$registered_user_group' group, but it does not exist.");
+ $this->logger->error("You specified newly registered users be added to '$registeredUserGroup' group, but it does not exist.");
$groupId = '';
} else {
$group->addUser($user);
$groupId = $group->getGID();
}
} else {
- $groupId = "";
+ $groupId = '';
}
// disable user if this is requested by config
- $admin_approval_required = $this->config->getAppValue($this->appName, 'admin_approval_required', "no");
- if ($admin_approval_required === "yes") {
+ $adminApprovalRequired = $this->config->getAppValue($this->appName, 'admin_approval_required', 'no');
+ if ($adminApprovalRequired === 'yes') {
$user->setEnabled(false);
}
@@ -353,19 +364,11 @@ class RegistrationService {
return $this->registrationMapper->findBySecret($secret);
}
- /**
- * @param Registration $registation
- * @return null|\OCP\IUser
- */
- public function getUserAccount(Registration $registation) {
- $user = $this->userManager->get($registation->getUsername());
- return $user;
+ public function getUserAccount(Registration $registration): ?IUser {
+ return $this->userManager->get($registration->getUsername());
}
- /**
- * @param Registration $registration
- */
- public function deleteRegistration(Registration $registration) {
+ public function deleteRegistration(Registration $registration): void {
$this->registrationMapper->delete($registration);
}
@@ -376,7 +379,7 @@ class RegistrationService {
*
* @return string
*/
- private function generateRandomDeviceToken() {
+ private function generateRandomDeviceToken(): string {
$groups = [];
for ($i = 0; $i < 5; $i++) {
$groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
@@ -389,7 +392,7 @@ class RegistrationService {
* @return string
* @throws RegistrationException
*/
- public function generateAppPassword($uid) {
+ public function generateAppPassword(string $uid): string {
$name = $this->l10n->t('Registration app auto setup');
try {
$sessionId = $this->session->getId();
@@ -425,15 +428,15 @@ class RegistrationService {
$password = $this->crypto->decrypt($password);
}
- $this->usersession->login($username, $password);
- $this->usersession->createSessionToken($this->request, $userId, $username, $password);
+ $this->userSession->login($username, $password);
+ $this->userSession->createSessionToken($this->request, $userId, $username, $password);
}
/**
* Replicates OC::cleanupLoginTokens() since it's protected
* @param string $userId
*/
- public function cleanupLoginTokens($userId) {
+ public function cleanupLoginTokens(string $userId): void {
$cutoff = time() - $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
$tokens = $this->config->getUserKeys($userId, 'login_token');
foreach ($tokens as $token) {
From 201f388dee2f6fcd338f35ae573b0b342b47f784 Mon Sep 17 00:00:00 2001
From: Joas Schilling
Date: Fri, 17 Jul 2020 11:14:29 +0200
Subject: [PATCH 04/10] Form also uses ClientSecret now, so manually remove the
registration at the end of the form too
Signed-off-by: Joas Schilling
---
lib/Controller/RegisterController.php | 3 +++
lib/Service/RegistrationService.php | 11 -----------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/lib/Controller/RegisterController.php b/lib/Controller/RegisterController.php
index 94abb43..30994b0 100644
--- a/lib/Controller/RegisterController.php
+++ b/lib/Controller/RegisterController.php
@@ -227,6 +227,9 @@ class RegisterController extends Controller {
return $this->showUserForm($secret, $token, $username, $exception->getMessage());
}
+ // Delete registration
+ $this->registrationService->deleteRegistration($registration);
+
if ($user->isEnabled()) {
$this->registrationService->loginUser($user->getUID(), $user->getUID(), $password);
diff --git a/lib/Service/RegistrationService.php b/lib/Service/RegistrationService.php
index 2dfd3b3..a5c4c80 100644
--- a/lib/Service/RegistrationService.php
+++ b/lib/Service/RegistrationService.php
@@ -322,17 +322,6 @@ class RegistrationService {
$user->setEnabled(false);
}
- // Delete pending registration if no client secret is stored
- // with client secret implies registered via API
- // without client secret implies registered via form
- // if registered via API, the registration request will be deleted in apicontroller::status
- if ($registration->getClientSecret() === null) {
- $res = $this->registrationMapper->delete($registration);
- if ($res === false) {
- throw new RegistrationException($this->l10n->t('Failed to delete pending registration request'));
- }
- }
-
$this->mailService->notifyAdmins($userId, $user->isEnabled(), $groupId);
return $user;
}
From 6f6057d0a949596dc41b776fe56f7e765760833f Mon Sep 17 00:00:00 2001
From: Joas Schilling
Date: Fri, 17 Jul 2020 14:41:50 +0200
Subject: [PATCH 05/10] Add unit tests
Signed-off-by: Joas Schilling
---
css/register-button.css | 6 +-
lib/Controller/RegisterController.php | 4 +-
.../Controller/RegisterControllerTest.php | 470 ++++++++++++++++++
3 files changed, 478 insertions(+), 2 deletions(-)
create mode 100644 tests/Unit/Controller/RegisterControllerTest.php
diff --git a/css/register-button.css b/css/register-button.css
index a732b81..9cf50b4 100644
--- a/css/register-button.css
+++ b/css/register-button.css
@@ -2,7 +2,11 @@
color: var(--color-primary-element);
}
-.register-button:only-child {
+#alternative-logins .register-button:only-child {
width: 220px;
margin-left: 70px !important;
}
+
+#alternative-logins .register-button.hidden {
+ display: none;
+}
diff --git a/lib/Controller/RegisterController.php b/lib/Controller/RegisterController.php
index 30994b0..4a4e167 100644
--- a/lib/Controller/RegisterController.php
+++ b/lib/Controller/RegisterController.php
@@ -102,10 +102,11 @@ class RegisterController extends Controller {
// No registration in progress
try {
$this->registrationService->validateEmail($email);
- $registration = $this->registrationService->createRegistration($email);
} catch (RegistrationException $e) {
return $this->showEmailForm($email, $e->getMessage());
}
+
+ $registration = $this->registrationService->createRegistration($email);
}
try {
@@ -203,6 +204,7 @@ class RegisterController extends Controller {
/**
* @PublicPage
* @UseSession
+ * @AnonRateThrottle(limit=5, period=1)
*
* @param string $secret
* @param string $token
diff --git a/tests/Unit/Controller/RegisterControllerTest.php b/tests/Unit/Controller/RegisterControllerTest.php
new file mode 100644
index 0000000..25ab347
--- /dev/null
+++ b/tests/Unit/Controller/RegisterControllerTest.php
@@ -0,0 +1,470 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\Registration\Tests\Unit\Controller;
+
+use OCA\Registration\Controller\RegisterController;
+use OCA\Registration\Db\Registration;
+use OCA\Registration\Service\LoginFlowService;
+use OCA\Registration\Service\MailService;
+use OCA\Registration\Service\RegistrationException;
+use OCA\Registration\Service\RegistrationService;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\IL10N;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class RegisterControllerTest extends TestCase {
+
+ /** @var IRequest */
+ private $request;
+ /** @var IL10N|MockObject */
+ private $l10n;
+ /** @var IURLGenerator|MockObject */
+ private $urlGenerator;
+ /** @var RegistrationService|MockObject */
+ private $registrationService;
+ /** @var LoginFlowService|MockObject */
+ private $loginFlowService;
+ /** @var MailService|MockObject */
+ private $mailService;
+
+ public function setUp(): void {
+ parent::setUp();
+ $this->request = $this->createMock(IRequest::class);
+ $this->l10n = $this->createMock(IL10N::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
+ $this->registrationService = $this->createMock(RegistrationService::class);
+ $this->loginFlowService = $this->createMock(LoginFlowService::class);
+ $this->mailService = $this->createMock(MailService::class);
+
+ $this->l10n->expects($this->any())
+ ->method('t')
+ ->willReturnCallback(function ($text, $parameters = []) {
+ return vsprintf($text, $parameters);
+ });
+ }
+
+ /**
+ * @param string[] $methods
+ * @return RegisterController|MockObject
+ */
+ protected function getController(array $methods = []) {
+ if (empty($methods)) {
+ return new RegisterController(
+ 'registration',
+ $this->request,
+ $this->l10n,
+ $this->urlGenerator,
+ $this->registrationService,
+ $this->loginFlowService,
+ $this->mailService
+ );
+ }
+
+ return $this->getMockBuilder(RegisterController::class)
+ ->onlyMethods($methods)
+ ->setConstructorArgs([
+ 'registration',
+ $this->request,
+ $this->l10n,
+ $this->urlGenerator,
+ $this->registrationService,
+ $this->loginFlowService,
+ $this->mailService,
+ ])
+ ->getMock();
+ }
+
+ public function dataShowEmailForm(): array {
+ return [
+ ['', ''],
+ ['test@example.tld', 'Registration is only allowed for the following domains: nextcloud.com'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataShowEmailForm
+ * @param string $email
+ * @param string $message
+ */
+ public function testShowEmailForm(string $email, string $message): void {
+ $controller = $this->getController();
+ $response = $controller->showEmailForm($email, $message);
+
+ self::assertSame(TemplateResponse::RENDER_AS_GUEST, $response->getRenderAs());
+ self::assertSame('form/email', $response->getTemplateName());
+
+ self::assertSame([
+ 'email' => $email,
+ 'message' => $message,
+ ], $response->getParams());
+ }
+
+ public function testSubmitEmailForm(): void {
+ $email = 'nextcloud@example.tld';
+
+ $this->registrationService
+ ->method('getRegistrationForEmail')
+ ->with($email)
+ ->willThrowException(new DoesNotExistException($email));
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => 'clientSecret',
+ ]);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateEmail')
+ ->with($email);
+ $this->registrationService
+ ->expects($this->once())
+ ->method('createRegistration')
+ ->with($email)
+ ->willReturn($registration);
+
+ $this->mailService
+ ->expects($this->once())
+ ->method('sendTokenByMail')
+ ->with($registration);
+
+ $this->urlGenerator
+ ->method('linkToRoute')
+ ->willReturnCallback(function () {
+ return json_encode(func_get_args());
+ });
+
+ $controller = $this->getController();
+ $response = $controller->submitEmailForm($email);
+
+ self::assertInstanceOf(RedirectResponse::class, $response);
+ /** @var RedirectResponse $response */
+ self::assertSame('["registration.register.showVerificationForm",{"secret":"clientSecret"}]', $response->getRedirectURL());
+ }
+
+ public function testSubmitEmailFormInvalidEmail(): void {
+ $email = 'nextcloud@example.tld';
+
+ $this->registrationService
+ ->method('getRegistrationForEmail')
+ ->with($email)
+ ->willThrowException(new DoesNotExistException($email));
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateEmail')
+ ->with($email)
+ ->willThrowException(new RegistrationException('Invalid email'));
+ $this->registrationService
+ ->expects($this->never())
+ ->method('createRegistration');
+
+ $controller = $this->getController([
+ 'showEmailForm',
+ ]);
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller->expects($this->once())
+ ->method('showEmailForm')
+ ->with($email, 'Invalid email')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->submitEmailForm($email));
+ }
+
+ public function testSubmitEmailFormErrorSendingEmail(): void {
+ $email = 'nextcloud@example.tld';
+
+ $this->registrationService
+ ->method('getRegistrationForEmail')
+ ->with($email)
+ ->willThrowException(new DoesNotExistException($email));
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => 'clientSecret',
+ ]);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('validateEmail')
+ ->with($email);
+ $this->registrationService
+ ->expects($this->once())
+ ->method('createRegistration')
+ ->with($email)
+ ->willReturn($registration);
+
+ $this->mailService
+ ->expects($this->once())
+ ->method('sendTokenByMail')
+ ->with($registration)
+ ->willThrowException(new RegistrationException('Error sending email'));
+
+ $controller = $this->getController([
+ 'showEmailForm',
+ ]);
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller->expects($this->once())
+ ->method('showEmailForm')
+ ->with($email, 'Error sending email')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->submitEmailForm($email));
+ }
+
+ public function testSubmitEmailFormResendPendingRequest(): void {
+ $email = 'nextcloud@example.tld';
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => 'clientSecret',
+ ]);
+
+ $this->registrationService
+ ->method('getRegistrationForEmail')
+ ->with($email)
+ ->willReturn($registration);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('generateNewToken')
+ ->with($registration);
+
+ $this->mailService
+ ->expects($this->once())
+ ->method('sendTokenByMail')
+ ->with($registration);
+
+ $this->urlGenerator
+ ->method('linkToRoute')
+ ->willReturnCallback(function () {
+ return json_encode(func_get_args());
+ });
+
+ $controller = $this->getController();
+ $response = $controller->submitEmailForm($email);
+ self::assertInstanceOf(RedirectResponse::class, $response);
+ /** @var RedirectResponse $response */
+ self::assertSame('["registration.register.showVerificationForm",{"secret":"clientSecret"}]', $response->getRedirectURL());
+ }
+
+ public function dataShowVerificationForm(): array {
+ return [
+ [''],
+ ['The entered verification code is wrong'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataShowVerificationForm
+ * @param string $message
+ */
+ public function testShowVerificationForm(string $message): void {
+ $secret = '123456789';
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getRegistrationForSecret')
+ ->with($secret);
+
+ $controller = $this->getController();
+ $response = $controller->showVerificationForm($secret, $message);
+
+ self::assertSame(TemplateResponse::RENDER_AS_GUEST, $response->getRenderAs());
+ self::assertSame('form/verification', $response->getTemplateName());
+
+ self::assertSame([
+ 'message' => $message,
+ ], $response->getParams());
+ }
+
+ public function testShowVerificationFormInvalidSecret(): void {
+ $secret = '123456789';
+ $message = '';
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getRegistrationForSecret')
+ ->with($secret)
+ ->willThrowException(new DoesNotExistException('Not found'));
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller = $this->getController([
+ 'validateSecretAndTokenErrorPage'
+ ]);
+
+ $controller->expects($this->once())
+ ->method('validateSecretAndTokenErrorPage')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->showVerificationForm($secret, $message));
+ }
+
+ public function testSubmitVerificationForm(): void {
+ $secret = '123456789';
+ $token = 'abcdefghi';
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => $secret,
+ 'token' => $token,
+ ]);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getRegistrationForSecret')
+ ->with($secret)
+ ->willReturn($registration);
+
+ $this->urlGenerator
+ ->method('linkToRoute')
+ ->willReturnCallback(function () {
+ return json_encode(func_get_args());
+ });
+
+ $controller = $this->getController();
+ $response = $controller->submitVerificationForm($secret, $token);
+ self::assertInstanceOf(RedirectResponse::class, $response);
+ /** @var RedirectResponse $response */
+ self::assertSame('["registration.register.showUserForm",{"secret":"123456789","token":"abcdefghi"}]', $response->getRedirectURL());
+ }
+
+ public function testSubmitVerificationFormInvalidToken(): void {
+ $secret = '123456789';
+ $token = 'abcdefghi';
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => $secret,
+ 'token' => 'zyxwvu',
+ ]);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getRegistrationForSecret')
+ ->with($secret)
+ ->willReturn($registration);
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller = $this->getController([
+ 'showVerificationForm',
+ ]);
+ $controller->expects($this->once())
+ ->method('showVerificationForm')
+ ->with($secret, 'The entered verification code is wrong')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->submitVerificationForm($secret, $token));
+ }
+
+ public function testSubmitVerificationFormInvalidSecret(): void {
+ $secret = '123456789';
+ $token = 'abcdefghi';
+
+ $registration = Registration::fromParams([
+ 'clientSecret' => $secret,
+ 'token' => $token,
+ ]);
+
+ $this->registrationService
+ ->expects($this->once())
+ ->method('getRegistrationForSecret')
+ ->with($secret)
+ ->willThrowException(new DoesNotExistException('Invalid secret'));
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller = $this->getController([
+ 'validateSecretAndTokenErrorPage',
+ ]);
+ $controller->expects($this->once())
+ ->method('validateSecretAndTokenErrorPage')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->submitVerificationForm($secret, $token));
+ }
+
+ public function dataShowUserForm(): array {
+ return [
+ ['', ''],
+ ['tester', ''],
+ ['', 'Unable to create user, there are problems with the user backend.'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataShowUserForm
+ * @param string $username
+ * @param string $message
+ */
+ public function testShowUserForm(string $username, string $message): void {
+ $secret = '123456789';
+ $token = 'abcdefghi';
+ $email = 'nextcloud@example.tld';
+
+ $registration = Registration::fromParams([
+ 'email' => 'nextcloud@example.tld',
+ ]);
+
+ $controller = $this->getController([
+ 'validateSecretAndToken'
+ ]);
+
+ $controller->expects($this->once())
+ ->method('validateSecretAndToken')
+ ->willReturn($registration);
+
+ $response = $controller->showUserForm($secret, $token, $username, $message);
+
+ self::assertSame(TemplateResponse::RENDER_AS_GUEST, $response->getRenderAs());
+ self::assertSame('form/user', $response->getTemplateName());
+
+ self::assertSame([
+ 'email' => $email,
+ 'username' => $username,
+ 'message' => $message,
+ ], $response->getParams());
+ }
+
+ public function testShowUserFormInvalidSecretAndToken(): void {
+ $secret = '123456789';
+ $token = 'abcdefghi';
+
+ $controller = $this->getController([
+ 'validateSecretAndToken',
+ 'validateSecretAndTokenErrorPage',
+ ]);
+
+ $controller->expects($this->once())
+ ->method('validateSecretAndToken')
+ ->willThrowException(new RegistrationException('Invalid secret or token'));
+
+ $response = $this->createMock(TemplateResponse::class);
+ $controller->expects($this->once())
+ ->method('validateSecretAndTokenErrorPage')
+ ->willReturn($response);
+
+ self::assertSame($response, $controller->showUserForm($secret, $token));
+ }
+}
From 5f9ca2a8aa16cbacbd1ee6aa60b022965ff10909 Mon Sep 17 00:00:00 2001
From: Joas Schilling
Date: Tue, 21 Jul 2020 21:16:18 +0200
Subject: [PATCH 06/10] Add a warning about admin approval breaking login flows
Signed-off-by: Joas Schilling
---
templates/admin.php | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/templates/admin.php b/templates/admin.php
index 16ff9e5..e9aeb12 100644
--- a/templates/admin.php
+++ b/templates/admin.php
@@ -26,9 +26,13 @@ foreach ($_['groups'] as $group) {
-
+ >
-
+
+
+
+ t('Enabling "admin approval" will prevent registrations from mobile and desktop clients to complete as the credentials can not be verified by the client until the user was enabled.'));?>