feat(auth): add domain-based SSO discovery for unprovisioned users
Users who exist in Microsoft Entra ID or LDAP but have no local account were blocked at the email-first login step because the system required a local user record before showing SSO options. This adds a domain-based fallback: when the email is unknown locally, the system checks tenant SSO configurations for matching allowed_domains and presents SSO-only login options, enabling the existing JIT provisioning to trigger on callback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,18 +85,28 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
|
||||
}
|
||||
|
||||
$user = $userReadRepository->findByEmail($emailValue);
|
||||
if (!$user || (int) ($user['active'] ?? 0) !== 1) {
|
||||
return ['ok' => false];
|
||||
$isKnownActiveUser = $user && (int) ($user['active'] ?? 0) === 1 && (int) ($user['id'] ?? 0) > 0;
|
||||
|
||||
$tenants = [];
|
||||
$discovery = false;
|
||||
|
||||
if ($isKnownActiveUser) {
|
||||
$userId = (int) $user['id'];
|
||||
$tenants = $userTenantContextService->getAssignedActiveTenants($userId);
|
||||
}
|
||||
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return ['ok' => false];
|
||||
}
|
||||
|
||||
$tenants = $userTenantContextService->getAssignedActiveTenants($userId);
|
||||
// Fallback: domain-based SSO discovery for users not yet provisioned locally
|
||||
if (!$tenants) {
|
||||
return ['ok' => false];
|
||||
$discoveryResults = $tenantSsoService->discoverTenantsByEmailDomain($emailValue);
|
||||
if (!$discoveryResults) {
|
||||
return ['ok' => false];
|
||||
}
|
||||
$discovery = true;
|
||||
$tenants = array_map(static fn (array $r): array => $r['tenant'], $discoveryResults);
|
||||
$discoveryMethodsByTenantId = [];
|
||||
foreach ($discoveryResults as $r) {
|
||||
$discoveryMethodsByTenantId[(int) $r['id']] = $r['methods'];
|
||||
}
|
||||
}
|
||||
|
||||
$candidates = [];
|
||||
@@ -110,7 +120,9 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
|
||||
if ($tenantSlug === '') {
|
||||
continue;
|
||||
}
|
||||
$methods = $tenantSsoService->resolveTenantLoginMethods($tenantId);
|
||||
$methods = $discovery
|
||||
? ($discoveryMethodsByTenantId[$tenantId] ?? ['local' => false, 'microsoft' => false, 'microsoft_reason' => '', 'ldap' => false, 'ldap_reason' => ''])
|
||||
: $tenantSsoService->resolveTenantLoginMethods($tenantId);
|
||||
$tenantUuid = (string) ($tenant['uuid'] ?? '');
|
||||
$hasAvatar = $tenantUuid !== '' && $tenantAvatarService->hasAvatar($tenantUuid);
|
||||
$candidate = [
|
||||
@@ -135,9 +147,10 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
|
||||
return [
|
||||
'ok' => true,
|
||||
'email' => $emailValue,
|
||||
'user' => $user,
|
||||
'user' => $isKnownActiveUser ? $user : null,
|
||||
'candidates' => $candidates,
|
||||
'candidate_by_id' => $candidateById,
|
||||
'discovery' => $discovery,
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user