Skip to content

Commit

Permalink
Custom Authentication Mechanisms for WebDAV and APIs (#26742)
Browse files Browse the repository at this point in the history
* Add plugin mechanism for authentication

* Update PHPDoc in IAuthModule

* Update PHPDoc for auth function

* Add getUserPassword function in IAuthModule

* Add loading of additional AuthBackends for webdav interface

* Add type check for IAuthModule
  • Loading branch information
joneug authored and DeepDiver1975 committed Mar 9, 2017
1 parent 7ec5c15 commit d35a58d
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
4 changes: 4 additions & 0 deletions apps/dav/appinfo/v1/webdav.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,9 @@
return \OC\Files\Filesystem::getView();
});

// allow setup of additional auth backends
$event = new \OCP\SabrePluginEvent($server);
\OC::$server->getEventDispatcher()->dispatch('OCA\DAV\Connector\Sabre::authInit', $event);

// And off we go!
$server->exec();
82 changes: 82 additions & 0 deletions lib/private/User/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,22 @@

namespace OC\User;

use Exception;
use OC;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OC\Hooks\Emitter;
use OC_App;
use OC_User;
use OC_Util;
use OCA\DAV\Connector\Sabre\Auth;
use OCP\App\IAppManager;
use OCP\AppFramework\QueryException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\IAuthModule;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
Expand Down Expand Up @@ -675,6 +680,83 @@ public function tryTokenLogin(IRequest $request) {
return true;
}

/**
* Tries to login with an AuthModule provided by an app
*
* @param IRequest $request The request
* @return bool True if request can be authenticated, false otherwise
* @throws Exception If the auth module could not be loaded
*/
public function tryAuthModuleLogin(IRequest $request) {
/** @var IAppManager $appManager */
$appManager = OC::$server->query('AppManager');
$allApps = $appManager->getInstalledApps();

foreach ($allApps as $appId) {
$info = $appManager->getAppInfo($appId);

if (isset($info['auth-modules'])) {
$authModules = $info['auth-modules'];

foreach ($authModules as $class) {
try {
if (!OC_App::isAppLoaded($appId)) {
OC_App::loadApp($appId);
}

/** @var IAuthModule $authModule */
$authModule = OC::$server->query($class);

if ($authModule instanceof IAuthModule) {
return $this->loginUser($authModule->auth($request), $authModule->getUserPassword($request));
} else {
throw new Exception("Could not load the auth module $class");
}
} catch (QueryException $exc) {
throw new Exception("Could not load the auth module $class");
}
}
}
}

return false;
}

/**
* Log an user in
*
* @param IUser $user The user
* @param String $password The user's password
* @return boolean True if the user can be authenticated, false otherwise
* @throws LoginException if an app canceld the login process or the user is not enabled
*/
private function loginUser($user, $password) {
if (is_null($user)) {
return false;
}

$this->manager->emit('\OC\User', 'preLogin', [$user, $password]);

if (!$user->isEnabled()) {
$message = \OC::$server->getL10N('lib')->t('User disabled');
throw new LoginException($message);
}

$this->setUser($user);
$this->setLoginName($user->getDisplayName());

$this->manager->emit('\OC\User', 'postLogin', [$user, $password]);

if ($this->isLoggedIn()) {
$this->prepareUserLogin(false);
} else {
$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
throw new LoginException($message);
}

return true;
}

/**
* perform login using the magic cookie (remember login)
*
Expand Down
1 change: 1 addition & 0 deletions lib/private/legacy/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ private static function loginUser() {
if (OC_User::handleApacheAuth()) {
self::$logoutRequired = false;
} else if ($userSession->tryTokenLogin($request)
|| $userSession->tryAuthModuleLogin($request)
|| $userSession->tryBasicAuthLogin($request)) {
self::$logoutRequired = true;
} else {
Expand Down
36 changes: 36 additions & 0 deletions lib/public/Authentication/IAuthModule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace OCP\Authentication;

use OCP\IRequest;
use OCP\IUser;

/**
* Interface IAuthModule
*
* @package OCP\Authentication
* @since 10.0.0
*/
interface IAuthModule {

/**
* Authenticates a request.
*
* @param IRequest $request The request.
*
* @return null|IUser The user if the request is authenticated, null otherwise.
* @since 10.0.0
*/
public function auth(IRequest $request);

/**
* Returns the user's password.
*
* @param IRequest $request The request.
*
* @return String The user's password.
* @since 10.0.0
*/
public function getUserPassword(IRequest $request);

}

0 comments on commit d35a58d

Please sign in to comment.