scimserviceprovider/lib/Middleware/AuthMiddleware.php

110 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;
}
}