Skip to content

Commit d09e72a

Browse files
authored
Implement maven auth and permission levels (#27)
* `is_admin` -> `permission_level` in user model * Dropdown in users management page for modifying permission levels * Support maven editor role for new registrations * Add tests to maven, fixes for these and general improvement * Add tests for new maven editor permission level
1 parent 2190d91 commit d09e72a

39 files changed

+541
-132
lines changed

app/Attachments/AttachmentWriter.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace App\Attachments;
44

5-
use Illuminate\Http\UploadedFile;
65
use Livewire\Wireable;
76

87
interface AttachmentWriter extends Wireable

app/Auth/Registration/Registrant.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class Registrant
77

88
public function __construct(
99
private string $email,
10-
private bool $isAdmin
10+
private int $permissionLevel
1111
) {
1212
}
1313

@@ -16,9 +16,9 @@ public function getEmail(): string
1616
return $this->email;
1717
}
1818

19-
public function isAdmin(): bool
19+
public function getPermissionLevel(): int
2020
{
21-
return $this->isAdmin;
21+
return $this->permissionLevel;
2222
}
2323

2424
}

app/Auth/Registration/RegistrationTokenRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private function createRecord(Registrant $registrant, #[\SensitiveParameter] str
5858
{
5959
return [
6060
'email' => $registrant->getEmail(),
61-
'is_admin' => $registrant->isAdmin(),
61+
'permission_level' => $registrant->getPermissionLevel(),
6262
'token' => Hash::make($token),
6363
'created_at' => new Carbon
6464
];
@@ -81,7 +81,7 @@ private function tokenExpired($createdAt)
8181

8282
private function readRecord($record): Registrant
8383
{
84-
return new Registrant($record['email'], $record['is_admin']);
84+
return new Registrant($record['email'], $record['permission_level']);
8585
}
8686

8787
public function deleteExisting(string $email): bool
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use const App\Models\ADMIN_LEVEL;
6+
7+
class AdminAuthorization extends PermissionLevelAuthorization
8+
{
9+
protected function getRequiredLevel(): int
10+
{
11+
return ADMIN_LEVEL;
12+
}
13+
14+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use App\Models\User;
6+
use Closure;
7+
use Illuminate\Http\Request;
8+
use Illuminate\Support\Facades\Hash;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
class BasicAuthorization
12+
{
13+
14+
/**
15+
* Handle an incoming request.
16+
*
17+
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
18+
*/
19+
public function handle(Request $request, Closure $next): Response
20+
{
21+
if (!self::hasHeader($request) || !self::getAuthenticatedUser($request)) {
22+
abort(Response::HTTP_UNAUTHORIZED);
23+
}
24+
return $next($request);
25+
}
26+
27+
public static function hasHeader(Request $request): bool
28+
{
29+
return $request->hasHeader('Authorization');
30+
}
31+
32+
public static function getAuthenticatedUser(Request $request): User|false
33+
{
34+
$credentials = base64_decode(substr($request->header('Authorization'), 6));
35+
list($username, $password) = explode(':', $credentials);
36+
$user = User::where('email', $username)->first();
37+
if (isset($user) and Hash::check($password, $user->password)) {
38+
return $user;
39+
}
40+
return false;
41+
}
42+
43+
}

app/Http/Middleware/IsAdminMiddleware.php

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use const App\Models\MAVEN_EDITOR_LEVEL;
6+
7+
class MavenEditorAuthorization extends PermissionLevelAuthorization
8+
{
9+
protected function getRequiredLevel(): int
10+
{
11+
return MAVEN_EDITOR_LEVEL;
12+
}
13+
14+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use Symfony\Component\HttpFoundation\Response;
8+
9+
abstract class PermissionLevelAuthorization
10+
{
11+
protected abstract function getRequiredLevel(): int;
12+
13+
/**
14+
* Handle an incoming request.
15+
*
16+
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
17+
*/
18+
public function handle(Request $request, Closure $next): Response
19+
{
20+
if (auth()->check()) {
21+
$user = auth()->user();
22+
} else {
23+
// Fallback to basic Authorization if no standard auth
24+
$user = BasicAuthorization::getAuthenticatedUser($request);
25+
}
26+
if (!isset($user) or !$user->hasPermission($this->getRequiredLevel())) {
27+
abort(Response::HTTP_FORBIDDEN);
28+
}
29+
return $next($request);
30+
}
31+
}

app/Livewire/Auth/Register.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Livewire\Attributes\Locked;
1313
use Livewire\Attributes\Title;
1414
use Livewire\Component;
15+
use const App\Models\USER_LEVEL;
1516

1617
#[Title('Register')]
1718
#[Layout('components.layouts.auth')]
@@ -60,8 +61,8 @@ public function register(): void
6061
// Since the user needs a token to register, we can consider this an email verification
6162
$user->markEmailAsVerified();
6263

63-
if ($registrant->isAdmin()) {
64-
$user->is_admin = true;
64+
if ($registrant->getPermissionLevel() > USER_LEVEL) {
65+
$user->permission_level = $registrant->getPermissionLevel();
6566
$user->save();
6667
}
6768
RegistrationTokenRepository::get()->deleteExisting($this->email);

app/Livewire/Maven/DirectoryIndex.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ public function mount(?string $path = '')
1717
{
1818
$this->isRoot = $path == '';
1919
$this->path = $path;
20-
if (!Storage::directoryExists("maven$path")) {
21-
return redirect(route('maven.download', $path));
20+
if (!Storage::disk('maven')->exists($path)) {
21+
abort(404);
2222
}
23-
$fullPath = Storage::path("maven/$path");
23+
if (!Storage::disk('maven')->directoryExists($path)) {
24+
return redirect(route('maven.download', substr($path, 1)));
25+
}
26+
$fullPath = Storage::disk('maven')->path($path);
2427
foreach (new DirectoryIterator($fullPath) as $file) {
2528
if ($file->isDot()) continue;
2629
$path = $file->getRealPath();

0 commit comments

Comments
 (0)