Skip to content
Merged
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
3 changes: 2 additions & 1 deletion src/Console/Commands/FixUserCompanies.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public function handle()
$this->line('Found user ' . $user->name . ' (' . $user->email . ') which doesnt have correct company assignment.');
$company = Company::where('uuid', $user->company_uuid)->first();
if ($company) {
$user->assignCompany($company);
// Only the company owner is restored as an Administrator
$user->assignCompany($company, $company->owner_uuid === $user->uuid ? 'Administrator' : null);
$this->line('User ' . $user->email . ' was assigned to company: ' . $company->name);
}
}
Expand Down
47 changes: 38 additions & 9 deletions src/Http/Controllers/Internal/v1/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Fleetbase\Models\Company;
use Fleetbase\Models\CompanyUser;
use Fleetbase\Models\Invite;
use Fleetbase\Models\Role;
use Fleetbase\Models\User;
use Fleetbase\Models\VerificationCode;
use Fleetbase\Notifications\UserForgotPassword;
Expand Down Expand Up @@ -62,8 +63,8 @@ public function login(LoginRequest $request)
$tokenOwner instanceof User
&& ($tokenOwner->email === $identity || $tokenOwner->phone === $identity)
) {
if ($tokenOwner->type === 'customer') {
return response()->error('Customer accounts must sign in through the customer portal.', 403, ['code' => 'customer_login_not_allowed']);
if ($denied = Auth::denyConsoleLogin($tokenOwner)) {
return $denied;
}

return response()->json([
Expand All @@ -83,8 +84,8 @@ public function login(LoginRequest $request)
$query->where('email', $identity)->orWhere('phone', $identity);
})->first();

if ($user && $user->type === 'customer') {
return response()->error('Customer accounts must sign in through the customer portal.', 403, ['code' => 'customer_login_not_allowed']);
if ($denied = Auth::denyConsoleLogin($user)) {
return $denied;
}

// If the user exists but has no password set (e.g. SSO-invited or provisioned
Expand Down Expand Up @@ -138,7 +139,7 @@ public function session(Request $request)
$session = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($request) {
$user = $request->user();

if (!$user) {
if (!$user || !$user->canHoldConsoleSession()) {
return null;
}

Expand Down Expand Up @@ -196,6 +197,11 @@ public function bootstrap(Request $request)
{
$user = $request->user();
$token = $request->bearerToken();

if ($denied = Auth::denyConsoleSession($user)) {
return $denied;
}

$cacheKey = "auth_bootstrap_{$user->uuid}_{$token}";

// Cache for 5 minutes
Expand Down Expand Up @@ -491,7 +497,7 @@ public function verifyEmail(Request $request)
$user->activate();

// If authenticate is set, generate and return a token
if ($authenticate) {
if ($authenticate && $user->canHoldConsoleSession()) {
$user->updateLastLogin();
$token = $user->createToken($user->uuid);

Expand Down Expand Up @@ -872,8 +878,8 @@ public function joinOrganization(JoinOrganizationRequest $request)
$user = Auth::getUserFromSession($request);

// Make sure user has been invited to join organizations
$isAlreadyInvited = Invite::isAlreadySentToJoinCompany($user, $company);
if (!$isAlreadyInvited) {
$invite = Invite::findSentToJoinCompany($user, $company);
if (!$invite) {
return response()->error('User has not been invited to join this organization.');
}

Expand All @@ -882,7 +888,8 @@ public function joinOrganization(JoinOrganizationRequest $request)
return response()->error('User is already a member of this organization.');
}

$company->assignUser($user);
// Join with the role the invite carries; never a default one
$company->assignUser($user, $this->inviteRoleId($invite, $company));
Auth::setSession($user);

return response()->json(['status' => 'ok']);
Expand All @@ -894,6 +901,24 @@ public function joinOrganization(JoinOrganizationRequest $request)
// @codeCoverageIgnoreEnd
}

/**
* The id of the role an invite grants in the organization, when it names one
* that belongs to the organization or is global.
*/
private function inviteRoleId(Invite $invite, Company $company): ?string
{
$roleId = $invite->getMeta('role_uuid');
if (!$roleId) {
return null;
}

return Role::where(function ($query) use ($roleId) {
$query->where('id', $roleId)->orWhere('name', $roleId);
})->where(function ($query) use ($company) {
$query->where('company_uuid', $company->uuid)->orWhereNull('company_uuid');
})->value('id');
}

/**
* Allows user to create a new organization.
*
Expand Down Expand Up @@ -1019,6 +1044,10 @@ public function impersonate(AdminRequest $request)
return response()->error('The selected user to impersonate was not found.');
}

if ($denied = Auth::denyConsoleSession($targetUser)) {
return $denied;
}

try {
Auth::setSession($targetUser);
session()->put('impersonator', $currentUser->uuid);
Expand Down
11 changes: 11 additions & 0 deletions src/Http/Controllers/Internal/v1/TwoFaController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

use Fleetbase\Http\Controllers\Controller;
use Fleetbase\Http\Requests\TwoFaValidationRequest;
use Fleetbase\Support\Auth;
use Fleetbase\Support\TwoFactorAuth;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Sanctum\PersonalAccessToken;

/**
* Class TwoFaController.
Expand Down Expand Up @@ -103,6 +105,15 @@ public function verifyCode(Request $request)
try {
$authToken = TwoFactorAuth::verifyCode($code, $token, $clientToken);

// Driver and contact accounts cannot sign in to the console. Customers
// are left to the customer portal, which shares this route path.
$accessToken = PersonalAccessToken::findToken($authToken);
if ($denied = Auth::denyConsoleSession($accessToken?->tokenable)) {
$accessToken->delete();

return $denied;
}

return response()->json([
'authToken' => $authToken,
]);
Expand Down
Loading
Loading