Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start creating new permissions for registration #2674

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Whether or not a Project administrator can register a user
# PROJECT_ADMIN_REGISTRATION_FORM_ENABLED=true

# The minimum permission level able to register a user.
# Leaving this value blank will disable registration forms, unless a value can be
# generated from USER_REGISTRATION_FORM_ENABLED and PROJECT_ADMIN_REGISTRATION_FORM_ENABLED

# Options: PUBLIC, PROJECT_ADMIN, ADMIN, DISABLED
# USER_REGISTRATION_ACCESS_LEVEL_REQUIRED=PUBLIC

# Require all new projects to use authenticated submissions.
# Instance administrators can override this, and this setting has no effect on
# existing projects.
Expand Down
11 changes: 11 additions & 0 deletions app/Enums/RegistrationPermissionsLevel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Enums;

enum RegistrationPermissionsLevel: int
{
case PUBLIC = 0;
case PROJECT_ADMIN = 1;
case ADMIN = 2;
case DISABLED = 3;
}
6 changes: 4 additions & 2 deletions app/Http/Controllers/ManageProjectRolesController.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Project as EloquentProject;
Expand Down Expand Up @@ -384,7 +386,7 @@ public function viewPage(): View|RedirectResponse
if ((bool) config('require_full_email_when_adding_user')) {
$xml .= add_XML_value('fullemail', '1');
}
if ((config('auth.project_admin_registration_form_enabled') === true) || $current_user->admin) {
if ($current_user->can('create', [User::class, EloquentProject::find($projectid)])) {
$xml .= add_XML_value('canRegister', '1');
}
$xml .= '</cdash>';
Expand Down Expand Up @@ -426,7 +428,7 @@ private static function find_site_maintainers(int $projectid): array

private function register_user($projectid, $email, $firstName, $lastName, $repositoryCredential)
{
if (config('auth.project_admin_registration_form_enabled') === false) {
if (Gate::authorize('create', [User::class, EloquentProject::findOrFail($projectid)])->denied()) {
josephsnyder marked this conversation as resolved.
Show resolved Hide resolved
return '<error>Users cannot be registered via this form at the current time.</error>';
}

Expand Down
35 changes: 35 additions & 0 deletions app/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Policies;

use App\Enums\RegistrationPermissionsLevel;
use App\Models\Project;
use App\Models\User;
use Illuminate\Support\Str;

class UserPolicy
{
protected function AttemptValueBuild(): int
{
return (bool) env('USER_REGISTRATION_FORM_ENABLED', true) ? RegistrationPermissionsLevel::PUBLIC->value : ((bool) env('PROJECT_ADMIN_REGISTRATION_FORM_ENABLED', true) ? RegistrationPermissionsLevel::PROJECT_ADMIN->value : RegistrationPermissionsLevel::ADMIN->value);
}

/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
$user_permission_level = Project::whereRelation('administrators', 'users.id', request()->user()?->id)->exists() ? 1 : 0;
$user_permission_level = $user->admin ? 2 : $user_permission_level;
$registration_permission_level_required = match (Str::upper(config('auth.user_registration_access_level_required'))) {
'PUBLIC' => RegistrationPermissionsLevel::PUBLIC->value,
'PROJECT_ADMIN' => RegistrationPermissionsLevel::PROJECT_ADMIN->value,
'ADMIN' => RegistrationPermissionsLevel::ADMIN->value,
'DISABLED' => RegistrationPermissionsLevel::DISABLED->value,
default => $this->AttemptValueBuild(),
};

// Fail if the caller is requesting a value that the setting disallows
return $user_permission_level >= $registration_permission_level_required;
}
}
5 changes: 5 additions & 0 deletions app/cdash/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ add_laravel_test(/Browser/Pages/ProjectSitesPageTest)
set_tests_properties(/Browser/Pages/ProjectSitesPageTest PROPERTIES RUN_SERIAL TRUE)
set_tests_properties(/Browser/Pages/ProjectSitesPageTest PROPERTIES DEPENDS /CDash/XmlHandler/UpdateHandler)

# Technically this test doesn't have to run serially. It just needs to have exclusive access to the .env
add_laravel_test(/Browser/Pages/RegistrationTest)
set_tests_properties(/Browser/Pages/RegistrationTest PROPERTIES RUN_SERIAL TRUE)
set_tests_properties(/Browser/Pages/RegistrationTest PROPERTIES DEPENDS /CDash/XmlHandler/UpdateHandler)

add_laravel_test(/Feature/PurgeUnusedProjectsCommand)
set_tests_properties(/Feature/PurgeUnusedProjectsCommand PROPERTIES RUN_SERIAL TRUE)
set_tests_properties(/Feature/PurgeUnusedProjectsCommand PROPERTIES DEPENDS /CDash/XmlHandler/UpdateHandler)
Expand Down
7 changes: 3 additions & 4 deletions config/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
return [
// Whether or not "normal" username+password authentication is enabled
'username_password_authentication_enabled' => env('USERNAME_PASSWORD_AUTHENTICATION_ENABLED', true),
// Whether or not "normal" username+password authentication is enabled
'user_registration_form_enabled' => env('USER_REGISTRATION_FORM_ENABLED', true),
// Whether or not a Project administrator can register a user
'project_admin_registration_form_enabled' => env('PROJECT_ADMIN_REGISTRATION_FORM_ENABLED', true),
// Which level of permissions can register a user
// supported: PUBLIC,PROJECT_ADMIN,ADMIN,""
'user_registration_access_level_required' => env('USER_REGISTRATION_ACCESS_LEVEL_REQUIRED', (bool) env('USER_REGISTRATION_FORM_ENABLED', true) ? 'PUBLIC' : ((bool) env('PROJECT_ADMIN_REGISTRATION_FORM_ENABLED', true) ? 'PROJECT_ADMIN' : 'ADMIN')),

/*
|--------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3739,6 +3739,16 @@ parameters:
count: 2
path: app/Policies/ProjectPolicy.php

-
message: "#^Dynamic call to static method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<App\\\\Models\\\\Project\\>\\:\\:exists\\(\\)\\.$#"
count: 1
path: app/Policies/UserPolicy.php

-
message: "#^Parameter \\#1 \\$value of static method Illuminate\\\\Support\\\\Str\\:\\:upper\\(\\) expects string, mixed given\\.$#"
count: 1
path: app/Policies/UserPolicy.php

-
message: "#^Dynamic call to static method Illuminate\\\\Foundation\\\\Application\\:\\:isProduction\\(\\)\\.$#"
count: 1
Expand Down
176 changes: 89 additions & 87 deletions resources/views/admin/manage-users.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,93 +40,95 @@
>
</td>
</tr>
<tr>
<td></td>
<td>
<div name="newuser" id="newuser"></div>
</td>
</tr>
<tr>
<td></td>
<td bgcolor="#DDDDDD">
<strong>Add new user</strong>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right"> First Name: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="fname" size="20"/>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right"> Last Name: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="lname" size="20"/>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right"> Email: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="email" size="20"/>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right">Password: </div>
</td>
<td width="80%" height="2" class="nob">
<input
class="textbox"
type="password"
id="passwd"
name="passwd"
size="20"
>
<input
type="button"
value="Generate Password"
onclick="javascript:generatePassword();"
name="generatepassword"
class="textbox"
>
<span id="clearpasswd"></span>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right">Confirm Password: </div>
</td>
<td width="80%" height="2" class="nob">
<input
class="textbox"
type="password"
id="passwd2"
name="passwd2"
size="20"
>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right"> Institution: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="institution" size="20">
</td>
</tr>
<tr>
<td width="20%" class="nob"></td>
<td width="80%" class="nob">
<input type="submit" value="Add user >>" name="adduser" class="textbox"/>
(password will be displayed in clear text upon addition)
</td>
</tr>
@can("create", App\Models\User::class)
<tr>
<td></td>
<td>
<div name="newuser" id="newuser"></div>
</td>
</tr>
<tr>
<td></td>
<td bgcolor="#DDDDDD">
<strong>Add new user</strong>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right"> First Name: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="fname" size="20"/>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right"> Last Name: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="lname" size="20"/>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right"> Email: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="email" size="20"/>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right">Password: </div>
</td>
<td width="80%" height="2" class="nob">
<input
class="textbox"
type="password"
id="passwd"
name="passwd"
size="20"
>
<input
type="button"
value="Generate Password"
onclick="javascript:generatePassword();"
name="generatepassword"
class="textbox"
>
<span id="clearpasswd"></span>
</td>
</tr>
<tr class="treven">
<td width="20%" height="2" class="nob">
<div align="right">Confirm Password: </div>
</td>
<td width="80%" height="2" class="nob">
<input
class="textbox"
type="password"
id="passwd2"
name="passwd2"
size="20"
>
</td>
</tr>
<tr class="trodd">
<td width="20%" height="2" class="nob">
<div align="right"> Institution: </div>
</td>
<td width="80%" height="2" class="nob">
<input class="textbox" name="institution" size="20">
</td>
</tr>
<tr>
<td width="20%" class="nob"></td>
<td width="80%" class="nob">
<input type="submit" value="Add user >>" name="adduser" class="textbox"/>
(password will be displayed in clear text upon addition)
</td>
</tr>
@endcan
</table>
</form>

Expand Down
7 changes: 4 additions & 3 deletions resources/views/components/header.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
if (isset($project)) {
$logoid = $project->ImageId;
}
$hideRegistration = config('auth.user_registration_form_enabled') === false;
@endphp
use Illuminate\Support\Str;
$canRegister = Str::upper(config('auth.user_registration_access_level_required')) === "PUBLIC";
@endphp
<div id="header">
<div id="headertop">
<div id="topmenu">
Expand All @@ -18,7 +19,7 @@
<a class="cdash-link" href="{{ url('/logout') }}">Logout</a>
@else
<a class="cdash-link" href="{{ url('/login') }}">Login</a>
@if(!$hideRegistration)
@if($canRegister)
<a class="cdash-link" href="{{ route('register') }}">{{ __('Register') }}</a>
@endif
@endif
Expand Down
Loading