where('id', $clientId)->first(); if (! $samlClient) { throw new \RuntimeException('Invalid SAML client with ID: ' . $clientId); } $settings = $this->loadMergedSettings(); $settings['idp'] = [ 'entityId' => $samlClient['saml_entity_id'], 'singleSignOnService' => [ 'url' => $samlClient['saml_sso_url'], ], 'singleLogoutService' => [ 'url' => $samlClient['saml_slo_url'] ?? '', ], 'x509cert' => $samlClient['saml_x509_cert'], ]; return new SamlAuth($settings); } public function login() { try { $email = $this->request->getGet('email'); if (! $email) { return $this->response->setStatusCode(400)->setJSON([ 'status' => 'failed', 'code' => 400, 'data' => '', 'message' => 'Email required', ]); } $email = trim((string) $email); $at = strrchr($email, '@'); if ($at === false) { return $this->response->setStatusCode(400)->setJSON([ 'status' => 'failed', 'code' => 400, 'data' => '', 'message' => 'Invalid email', ]); } $domain = strtolower(substr($at, 1)); // dd($domain); $model = new SamlClientModel(); $samlClient = $model->getByDomain($domain); // dd($samlClient); if (! $samlClient) { return $this->response->setStatusCode(404)->setJSON([ 'status' => 'failed', 'code' => 404, 'data' => '', 'message' => 'This email is not configured with Microsoft. Please try other login options.', ]); } $auth = $this->getSamlAuth($samlClient['id']); } catch (\Throwable $e) { return $this->response->setStatusCode(500)->setJSON([ 'status' => 'failed', 'code' => 500, 'data' => '', 'message' => $e->getMessage(), ]); } $url = $auth->login(null, [], false, false, true); return redirect()->to($url); } public function acs() { try { $postedEmail = $this->extractEmailFromPostedSamlResponse(); if (! $postedEmail) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 400, 'data' => '', 'post_enrollment' => ['status' => 'failed', 'code' => 404, 'data' => ''], 'message' => 'Unable to resolve email from SAML response', ]); } $at = strrchr($postedEmail, '@'); if ($at === false) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 400, 'data' => '', 'post_enrollment' => ['status' => 'failed', 'code' => 404, 'data' => ''], 'message' => 'Invalid email in SAML response', ]); } $domain = strtolower(substr($at, 1)); $model = new SamlClientModel(); $client = $model->getByDomain($domain); if (! $client) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 404, 'data' => '', 'post_enrollment' => ['status' => 'failed', 'code' => 404, 'data' => ''], 'message' => 'This email is not configured with Microsoft. Please try other login options.', ]); } $clientId = $client['id']; $auth = $this->getSamlAuth($clientId); $auth->processResponse(); } catch (\Throwable $e) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 500, 'data' => '', 'post_enrollment' => ['status' => 'failed', 'code' => 404, 'data' => ''], 'message' => $e->getMessage(), ]); } if (! $auth->isAuthenticated()) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 401, 'data' => '', 'post_enrollment' => ['status' => 'failed', 'code' => 404, 'data' => ''], 'message' => implode(', ', $auth->getErrors()), ]); } $attributes = $auth->getAttributes(); $nameId = $auth->getNameId(); $email = $this->resolveEmailFromSaml($nameId, $attributes); $email = trim((string) $email); // Same email lookup path used in RestAuthenticationController::getVerifiedUserData() $empdata = RestAuthHelper::getPreAndPostDataByEmailOrMobile(['email_id' => $email]); if (! empty($empdata['pre']['email_corporate'])) { $email = (string) $empdata['pre']['email_corporate']; } elseif (! empty($empdata['post']['email_id'])) { $email = (string) $empdata['post']['email_id']; } $postEnrollment = ['status' => 'failed', 'code' => 404, 'data' => '']; if (! empty($empdata['post'])) { $postId = $empdata['post']['id'] ?? $empdata['post']['employee_id'] ?? null; if ($postId !== null && $postId !== '') { $restAuth = new RestAuthenticationController(); $rawBody = $restAuth->callThirdPartyGETAPI(['id' => $postId],'getTokenforSamulssOAuthLogin'); $api = is_string($rawBody) ? json_decode($rawBody, true) : null; if (is_array($api) && (($api['status'] ?? '') === 'success' || (int) ($api['code'] ?? 0) === 200) && isset($api['data']) && $api['data'] !== '' ) { $postEnrollment = [ 'status' => 'success', 'code' => 200, 'data' => is_string($api['data']) ? $api['data'] : (string) $api['data'], ]; } else { $postEnrollment = [ 'status' => 'failed', 'code' => (int) ($api['code'] ?? 404), 'data' => '', ]; } } } if (empty($empdata)) { return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 404, 'data' => '', 'post_enrollment' => $postEnrollment, 'message' => 'User not found', ]); } if (! empty($empdata['pre'])) { $employeeData = $empdata['pre']; unset($employeeData['employee_id']); $employeeData['token_type'] = 'pre'; $result = JWTToken::encode($employeeData); return $this->redirectToFrontendSso([ 'status' => 'success', 'code' => 200, 'data' => $result, 'post_enrollment' => $postEnrollment, ]); } return $this->redirectToFrontendSso([ 'status' => 'failed', 'code' => 404, 'data' => '', 'post_enrollment' => $postEnrollment, 'message' => 'Employee not found in pre-enrollment', ]); } private function redirectToFrontendSso(array $payload) { $feUrl = rtrim((string) env('fe_url'), '/'); if ($feUrl === '') { $feUrl = rtrim((string) env('FE_URL'), '/'); } $responsePayload = [ 'status' => $payload['status'] ?? 'failed', 'code' => $payload['code'] ?? 500, 'data' => $payload['data'] ?? '', 'post_enrollment' => $payload['post_enrollment'] ?? ['status' => 'failed', 'code' => 404, 'data' => ''], ]; // dd($responsePayload); if (! empty($payload['message'])) { $responsePayload['message'] = $payload['message']; } $encodedPayload = base64_encode((string) json_encode($responsePayload)); $params = http_build_query([ 'payload' => $encodedPayload, ]); // dd($feUrl . '/sso-login?' . $params); return redirect()->to($feUrl . '/sso-login?' . $params); } protected function getUserDeviceInfo(int $userId, string $type_of_user): void { $userAgent = $this->request->getUserAgent(); $datd = [ 'user_id' => $userId, 'user_type' => $type_of_user, 'ip' => $this->request->getIPAddress(), 'platform' => $userAgent->getPlatform(), 'broswer' => $userAgent->getBrowser(), ]; $AuthHistoryModel = new \App\Models\AuthHistoryModel(); $AuthHistoryModel->insert($datd); } /** * @param array $attributes */ private function resolveEmailFromSaml(?string $nameId, array $attributes): string { if ($nameId && filter_var($nameId, FILTER_VALIDATE_EMAIL)) { return $nameId; } $keys = [ 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', 'http://schemas.microsoft.com/identity/claims/emailaddress', 'email', 'Email', 'mail', ]; foreach ($keys as $k) { if (! empty($attributes[$k][0])) { return (string) $attributes[$k][0]; } } foreach ($attributes as $vals) { if (is_array($vals) && ! empty($vals[0]) && filter_var($vals[0], FILTER_VALIDATE_EMAIL)) { return (string) $vals[0]; } } return (string) $nameId; } private function extractEmailFromPostedSamlResponse(): ?string { $raw = $this->request->getPost('SAMLResponse'); if (! is_string($raw) || $raw === '') { return null; } $decoded = base64_decode($raw, true); if ($decoded === false || trim($decoded) === '') { return null; } libxml_use_internal_errors(true); $xml = simplexml_load_string($decoded); if ($xml === false) { return null; } $emailNodes = $xml->xpath("//*[local-name()='Attribute' and (@Name='email' or @Name='Email' or @Name='mail' or @Name='http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress' or @Name='http://schemas.microsoft.com/identity/claims/emailaddress')]/*[local-name()='AttributeValue']"); if (is_array($emailNodes)) { foreach ($emailNodes as $node) { $val = trim((string) $node); if ($val !== '' && filter_var($val, FILTER_VALIDATE_EMAIL)) { return $val; } } } $nameIdNodes = $xml->xpath("//*[local-name()='NameID']"); if (is_array($nameIdNodes)) { foreach ($nameIdNodes as $node) { $val = trim((string) $node); if ($val !== '' && filter_var($val, FILTER_VALIDATE_EMAIL)) { return $val; } } } return null; } public function logout() { try { $clientId = $this->request->getGet('client_id'); if (! $clientId) { return $this->response->setStatusCode(400)->setBody('Client ID required'); } $auth = $this->getSamlAuth($clientId); $url = $auth->logout(null, [], null, null, true); } catch (SamlError $e) { session()->destroy(); return redirect()->to(site_url('login')); } catch (\Throwable $e) { session()->destroy(); return redirect()->to(site_url('login')); } session()->destroy(); return redirect()->to($url); } public function slo() { try { $clientId = $this->request->getGet('client_id'); if (! $clientId) { return $this->response->setStatusCode(400)->setBody('Client ID required'); } $auth = $this->getSamlAuth($clientId); } catch (\Throwable $e) { return redirect()->to(site_url('login')); } try { $redirectUrl = $auth->processSLO(false, null, false, null, true); } catch (SamlError $e) { return redirect()->to(site_url('login')); } if (! empty($auth->getErrors())) { return $this->response->setJSON($auth->getErrors()); } if ($redirectUrl) { return redirect()->to($redirectUrl); } return redirect()->to(site_url('login')); } public function metadata() { $settings = $this->loadMergedSettings(); try { $samlSettings = new SamlSettings($settings, true); $metadata = $samlSettings->getSPMetadata(); } catch (\Throwable $e) { return $this->response->setStatusCode(500)->setBody($e->getMessage()); } return $this->response ->setHeader('Content-Type', 'application/xml; charset=utf-8') ->setBody($metadata); } // public function verifyMSAuthUser() // { // $code = $this->request->getVar('code'); // // echo $code; // try { // $token = $this->provider->getAccessToken('authorization_code', [ // 'code' => $code // ]); // $ownerDetails = $this->provider->getResourceOwner($token); // $data = $ownerDetails->toArray(); // $name = $data['name'] ?? null; // $email = $data['upn'] ?? $data['unique_name'] ?? null; // $res = checkUserExist($name, $email); // if($res['status'] == true) // { // $user = $res['data']; // //get service for the organization // $orgService = $this->organizationModel->find($user['org_id']); // $user['service'] = json_decode($orgService['services_ids'],true); // foreach ($user['service'] as $key => $value) // { // $serviceData = $this->serviceModel->find($value['service_id']); // $user['service'][$key]['name'] = $serviceData['name']; // $user['service'][$key]['icon'] = $serviceData['icon']; // } // //get role // $user['role'] = $this->userModel->getRole($user['role_id']); // //find user has the all access // $user['plan_action'] = getUserPlanCreationRestrictionStatus($user); // $token = generateJWT($user); // return $this->respond([ 'status' => 200,'message' => 'Login successful','token' => $token ]); // }else{ // return $this->respond([ 'status' => 401,'message' => 'Login Failed','data' => [] ]); // } // } catch (IdentityProviderException $e) { // exit($e->getMessage()); // } // } //end of microsoft oAuth }