implement crm login
This commit is contained in:
parent
462762a13f
commit
0efd443a53
@ -40,10 +40,14 @@ public function launchSSO($id)
|
|||||||
return redirect()->route('dashboard')->with('error', 'Access denied. You do not have permission to access this service.');
|
return redirect()->route('dashboard')->with('error', 'Access denied. You do not have permission to access this service.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$url = $app->url;
|
||||||
|
if (str_contains(strtolower($url), 'convexcrm.convexsol.co')) {
|
||||||
|
$url = rtrim($url, '/') . '/admin/authentication/microsoft_login';
|
||||||
|
}
|
||||||
|
|
||||||
if ($user->microsoft_id) {
|
if ($user->microsoft_id) {
|
||||||
// Save target app URL in session so callback knows where to redirect
|
// Save target app URL in session so callback knows where to redirect
|
||||||
session(['sso_target_url' => $app->url]);
|
session(['sso_target_url' => $url]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Determine domain hint based on user's email domain to skip account type prompt
|
// Determine domain hint based on user's email domain to skip account type prompt
|
||||||
@ -242,4 +246,45 @@ public function destroyPersonalApp($id)
|
|||||||
|
|
||||||
return redirect()->route('dashboard')->with('success', 'Custom app deleted successfully.');
|
return redirect()->route('dashboard')->with('success', 'Custom app deleted successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch a personal app using SSO.
|
||||||
|
*/
|
||||||
|
public function launchPersonalSSO($id)
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$pApp = $user->personalApps()->findOrFail($id);
|
||||||
|
|
||||||
|
$url = $pApp->url;
|
||||||
|
if (str_contains(strtolower($url), 'convexcrm.convexsol.co')) {
|
||||||
|
$url = rtrim($url, '/') . '/admin/authentication/microsoft_login';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->microsoft_id) {
|
||||||
|
// Save target app URL in session so callback knows where to redirect
|
||||||
|
session(['sso_target_url' => $url]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Determine domain hint based on user's email domain to skip account type prompt
|
||||||
|
$domainHint = (str_ends_with($user->email, '.onmicrosoft.com') || (str_contains($user->email, '@') && !str_ends_with($user->email, 'outlook.com') && !str_ends_with($user->email, 'hotmail.com') && !str_ends_with($user->email, 'live.com')))
|
||||||
|
? 'organizations'
|
||||||
|
: 'consumers';
|
||||||
|
|
||||||
|
// Redirect to Microsoft OAuth authorize page with login_hint, domain_hint, prompt=none and custom callback
|
||||||
|
return Socialite::driver('microsoft')
|
||||||
|
->redirectUrl(route('sso.callback'))
|
||||||
|
->with([
|
||||||
|
'login_hint' => $user->email,
|
||||||
|
'domain_hint' => $domainHint,
|
||||||
|
'prompt' => 'none'
|
||||||
|
])
|
||||||
|
->redirect();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return redirect($url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-Microsoft or non-Microsoft-linked users, redirect directly
|
||||||
|
return redirect($url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -862,7 +862,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Logo Wrapper -->
|
<!-- Logo Wrapper -->
|
||||||
<div class="service-logo-wrapper" onclick="window.open('{{ $pApp->url }}', '_blank')">
|
<div class="service-logo-wrapper" onclick="launchSSO('{{ $pApp->name }}', '{{ route('sso.personal-launch', $pApp->id) }}')">
|
||||||
@if($pApp->logo)
|
@if($pApp->logo)
|
||||||
<img src="{{ asset($pApp->logo) }}" alt="{{ $pApp->name }}" class="service-logo-img">
|
<img src="{{ asset($pApp->logo) }}" alt="{{ $pApp->name }}" class="service-logo-img">
|
||||||
@else
|
@else
|
||||||
@ -874,7 +874,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<h3 class="service-title" onclick="window.open('{{ $pApp->url }}', '_blank')">{{ strtoupper($pApp->name) }}</h3>
|
<h3 class="service-title" onclick="launchSSO('{{ $pApp->name }}', '{{ route('sso.personal-launch', $pApp->id) }}')">{{ strtoupper($pApp->name) }}</h3>
|
||||||
@if($pApp->tag)
|
@if($pApp->tag)
|
||||||
<div style="font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; margin-top: 4px; letter-spacing: 0.5px;">{{ $pApp->tag }}</div>
|
<div style="font-size: 0.65rem; color: var(--text-muted); text-transform: uppercase; margin-top: 4px; letter-spacing: 0.5px;">{{ $pApp->tag }}</div>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
Route::middleware(['auth', 'role:user'])->group(function () {
|
Route::middleware(['auth', 'role:user'])->group(function () {
|
||||||
Route::get('/sso/launch/{id}', [DashboardController::class, 'launchSSO'])->name('sso.launch');
|
Route::get('/sso/launch/{id}', [DashboardController::class, 'launchSSO'])->name('sso.launch');
|
||||||
|
Route::get('/sso/personal-launch/{id}', [DashboardController::class, 'launchPersonalSSO'])->name('sso.personal-launch');
|
||||||
Route::get('/sso/callback', [DashboardController::class, 'handleSSOCallback'])->name('sso.callback');
|
Route::get('/sso/callback', [DashboardController::class, 'handleSSOCallback'])->name('sso.callback');
|
||||||
Route::get('/sso/launch-app', [DashboardController::class, 'launchApp'])->name('sso.launch-app');
|
Route::get('/sso/launch-app', [DashboardController::class, 'launchApp'])->name('sso.launch-app');
|
||||||
|
|
||||||
|
|||||||
@ -517,4 +517,54 @@ public function test_user_personal_custom_apps(): void
|
|||||||
'id' => $personalApp->id
|
'id' => $personalApp->id
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test silent Microsoft SSO redirection for Convex CRM.
|
||||||
|
*/
|
||||||
|
public function test_convexcrm_silent_sso_redirection(): void
|
||||||
|
{
|
||||||
|
$user = User::create([
|
||||||
|
'name' => 'Convex CRM User',
|
||||||
|
'email' => 'convexcrm@sentientgeeks.com',
|
||||||
|
'role' => 'user',
|
||||||
|
'microsoft_id' => 'mock-ms-id-777',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$app = \App\Models\App::create([
|
||||||
|
'name' => 'Convex CRM',
|
||||||
|
'url' => 'https://demo-convexcrm.convexsol.co/',
|
||||||
|
'color' => '#123456',
|
||||||
|
'tag' => 'CRM'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Enable access to this app
|
||||||
|
$devRole = Role::firstOrCreate(['name' => 'Developer'], ['description' => 'Developer role']);
|
||||||
|
$devRole->apps()->syncWithoutDetaching([$app->id]);
|
||||||
|
$user->roles()->syncWithoutDetaching([$devRole->id]);
|
||||||
|
|
||||||
|
// Trigger SSO launch for corporate app
|
||||||
|
$response = $this->actingAs($user)
|
||||||
|
->get(route('sso.launch', $app->id));
|
||||||
|
|
||||||
|
// It should initiate Microsoft OAuth redirect to refresh the session
|
||||||
|
// And save rewritten target URL (Convex CRM Microsoft login redirect endpoint) in session
|
||||||
|
$this->assertEquals(
|
||||||
|
'https://demo-convexcrm.convexsol.co/admin/authentication/microsoft_login',
|
||||||
|
session('sso_target_url')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test personal custom app version
|
||||||
|
$pApp = $user->personalApps()->create([
|
||||||
|
'name' => 'My Custom Convex',
|
||||||
|
'url' => 'https://demo-convexcrm.convexsol.co',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$responsePersonal = $this->actingAs($user)
|
||||||
|
->get(route('sso.personal-launch', $pApp->id));
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'https://demo-convexcrm.convexsol.co/admin/authentication/microsoft_login',
|
||||||
|
session('sso_target_url')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user