Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb65b3d9 authored by Akhil's avatar Akhil 🙂
Browse files

Add security middleware to block change of user agent and IP address

parent 5d14e86b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ use OCA\EcloudAccounts\Listeners\BeforeUserDeletedListener;
use OCA\EcloudAccounts\Listeners\PasswordUpdatedListener;
use OCA\EcloudAccounts\Listeners\TwoFactorStateChangedListener;
use OCA\EcloudAccounts\Listeners\UserChangedListener;
use OCA\EcloudAccounts\Middleware\AccountMiddleware;
use OCA\EcloudAccounts\Service\LDAPConnectionService;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCP\AppFramework\App;
@@ -56,6 +57,8 @@ class Application extends App implements IBootstrap {
		$context->registerEventListener(UserChangedEvent::class, UserChangedListener::class);
		$context->registerEventListener(StateChanged::class, TwoFactorStateChangedListener::class);
		$context->registerEventListener(PasswordUpdatedEvent::class, PasswordUpdatedListener::class);
	
		$context->registerMiddleware(AccountMiddleware::class);
	}

	public function boot(IBootContext $context): void {
+1 −1
Original line number Diff line number Diff line
@@ -225,7 +225,7 @@ class AccountController extends Controller {
	 *
	 * @return string|null If validation fails, a string describing the error; otherwise, null.
	 */
	public function validateInput(string $inputName, string $value, ?int $maxLength = null) : ?string {
	private function validateInput(string $inputName, string $value, ?int $maxLength = null) : ?string {
		if ($value === '') {
			return "$inputName is required.";
		}
+9 −0
Original line number Diff line number Diff line
<?php

namespace OCA\EcloudAccounts\Exception;

class SecurityException extends \Exception {
	public function __construct($message = null, $code = 0) {
		parent::__construct($message, $code);
	}
}
+72 −0
Original line number Diff line number Diff line
<?php

namespace OCA\EcloudAccounts\Middleware;

use OCA\EcloudAccounts\Controller\AccountController;
use OCA\EcloudAccounts\Exception\SecurityException;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Middleware;
use OCP\IRequest;
use OCP\ISession;

class AccountMiddleware extends Middleware {
	private IRequest $request;
	private ISession $session;

	private const SESSION_METHODS = ['create', 'checkUsernameAvailable', 'captcha', 'verifyCaptcha'];
	private const SESSION_USER_AGENT = 'USER_AGENT';
	private const SESSION_IP_ADDRESS = 'IP_ADDRESS';
	private const HEADER_USER_AGENT = 'USER_AGENT';

	public function __construct(IRequest $request, ISession $session) {
		$this->request = $request;
		$this->session = $session;
	}
	

	public function beforeController($controller, $methodName) {
		if (!$controller instanceof AccountController) {
			return;
		}
		
		// Add the required params to session for index
		if ($methodName === 'index') {
			$ipAddr = $this->request->getRemoteAddress();
			$userAgent = $this->request->getHeader(self::HEADER_USER_AGENT);
			$this->session->set(self::SESSION_IP_ADDRESS, $ipAddr);
			$this->session->set(self::SESSION_USER_AGENT, $userAgent);
			return;
		}

		if (!in_array($methodName, self::SESSION_METHODS)) {
			return;
		}

		$ipAddr = $this->request->getRemoteAddress();
		$userAgent = $this->request->getHeader(self::HEADER_USER_AGENT);
		if (!$this->isValidSessionParam(self::SESSION_IP_ADDRESS, $ipAddr)
		|| !$this->isValidSessionParam(self::SESSION_USER_AGENT, $userAgent)) {
			throw new SecurityException;
		}
	}

	public function afterException($controller, $methodName, \Exception $exception) {
		if (!$controller instanceof AccountController || !$exception instanceof SecurityException) {
			throw $exception;
		}
		
		$response = new DataResponse();
		$response->setStatus(401);
		return $response;
	}

	private function isValidSessionParam(string $sessionParam, string $value) : bool {
		if (!$this->session->exists($sessionParam)) {
			return false;
		}
		if ($this->session->get($sessionParam) !== $value) {
			return false;
		}
		return true;
	}
}
+6 −1
Original line number Diff line number Diff line
@@ -110,8 +110,13 @@ export default {
				this.showRecoveryEmailForm = false
				this.showSuccessSection = true
			} catch (error) {
				const genericErrorMessage = 'An error occurred while creating your account!'
				// Handle network errors and unexpected response structures here
				const errorMessage = error.response ? t(this.appName, error.response.data.message) : t(this.appName, error.message)
				let errorMessage = error.response ? t(this.appName, error.response.data.message) : t(this.appName, error.message)
				if (errorMessage === '') {
					// Fallback to generic error message
					errorMessage = t(this.appName, genericErrorMessage)
				}
				this.showMessage(errorMessage, 'error')
			}
		},