111 lines
3.1 KiB
PHP
111 lines
3.1 KiB
PHP
|
<?php
|
||
|
|
||
|
declare(strict_types=1);
|
||
|
|
||
|
namespace OCA\SCIMServiceProvider\Middleware;
|
||
|
|
||
|
use Exception;
|
||
|
use OCA\SCIMServiceProvider\AppInfo\Application;
|
||
|
use OCA\SCIMServiceProvider\Exception\AuthException;
|
||
|
use OCP\AppFramework\Middleware;
|
||
|
use OCP\IConfig;
|
||
|
use OCP\IGroupManager;
|
||
|
use OCP\IRequest;
|
||
|
use OCP\IUser;
|
||
|
use OCP\IUserManager;
|
||
|
use OCP\IUserSession;
|
||
|
use Opf\ScimServerPhp\Firebase\JWT\JWT;
|
||
|
use Opf\ScimServerPhp\Firebase\JWT\Key;
|
||
|
use Psr\Log\LoggerInterface;
|
||
|
|
||
|
class AuthMiddleware extends Middleware {
|
||
|
private IRequest $request;
|
||
|
private IUserSession $userSession;
|
||
|
private IUserManager $userManager;
|
||
|
private IGroupManager $groupManager;
|
||
|
private IConfig $config;
|
||
|
private LoggerInterface $logger;
|
||
|
|
||
|
public function __construct(IRequest $request, IUserSession $userSession, IUserManager $userManager, IGroupManager $groupManager, IConfig $config, LoggerInterface $logger) {
|
||
|
$this->request = $request;
|
||
|
$this->userSession = $userSession;
|
||
|
$this->userManager = $userManager;
|
||
|
$this->groupManager = $groupManager;
|
||
|
$this->config = $config;
|
||
|
$this->logger = $logger;
|
||
|
}
|
||
|
|
||
|
public function beforeController($controller, $methodName) {
|
||
|
$currentRoute = $this->request->getParams()["_route"];
|
||
|
$publicRoutes = [
|
||
|
"scimserviceprovider.service_provider_configuration.resource_types",
|
||
|
"scimserviceprovider.service_provider_configuration.schemas",
|
||
|
"scimserviceprovider.service_provider_configuration.service_provider_config"
|
||
|
];
|
||
|
|
||
|
// Don't require an auth header for public routes
|
||
|
if (in_array($currentRoute, $publicRoutes)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$authHeader = $this->request->getHeader('Authorization');
|
||
|
|
||
|
if (empty($authHeader)) {
|
||
|
throw new AuthException("No Authorization header supplied");
|
||
|
}
|
||
|
|
||
|
$authHeaderSplit = explode(' ', $authHeader);
|
||
|
if (count($authHeaderSplit) !== 2) {
|
||
|
throw new AuthException("Incorrect authorization header");
|
||
|
}
|
||
|
|
||
|
switch ($authHeaderSplit[0]) {
|
||
|
case 'Basic':
|
||
|
$user = $this->userSession->getUser();
|
||
|
if ($user == null) {
|
||
|
throw new AuthException("Not logged-in");
|
||
|
}
|
||
|
break;
|
||
|
case 'Bearer':
|
||
|
$user = $this->authenticateBearerToken($authHeaderSplit[1]);
|
||
|
break;
|
||
|
default:
|
||
|
throw new AuthException("Incorrect authorization type");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// For now only allow admin users
|
||
|
if (!$this->groupManager->isAdmin($user->getUID())) {
|
||
|
throw new AuthException("Not admin");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private function authenticateBearerToken(string $token): ?IUser {
|
||
|
$e = new AuthException("Bearer token is invalid");
|
||
|
$jwtPayload = [];
|
||
|
$jwtSecret = $this->config->getAppValue(Application::APP_ID, "jwt-secret");
|
||
|
if (empty($jwtSecret)) {
|
||
|
$this->logger->error("jwt-secret not configued");
|
||
|
throw $e;
|
||
|
}
|
||
|
try {
|
||
|
$jwtPayload = (array) JWT::decode($token, new Key($jwtSecret, 'HS256'));
|
||
|
} catch (Exception $e2) {
|
||
|
$this->logger->error($e2->getMessage());
|
||
|
throw $e;
|
||
|
}
|
||
|
|
||
|
$username = $jwtPayload['sub'];
|
||
|
|
||
|
// If we managed to find a user with that username, then auth succeeded
|
||
|
$user = $this->userManager->get($username);
|
||
|
if ($user === null) {
|
||
|
$this->logger->error("User with this username doesn't exist");
|
||
|
throw $e;
|
||
|
}
|
||
|
|
||
|
$this->userSession->setUser($user);
|
||
|
return $user;
|
||
|
}
|
||
|
}
|