/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $schoolId = $input->getOption('schoolId'); if (!$schoolId) { $schoolTitles = []; foreach ($this->schoolManager->findBy([], ['title' => 'ASC']) as $school) { $schoolTitles[$school->getTitle()] = $school->getId(); } $helper = $this->getHelper('question'); $question = new ChoiceQuestion("What is this user's primary school?", array_keys($schoolTitles)); $question->setErrorMessage('School %s is invalid.'); $schoolTitle = $helper->ask($input, $output, $question); $schoolId = $schoolTitles[$schoolTitle]; } $school = $this->schoolManager->findOneBy(['id' => $schoolId]); if (!$school) { throw new \Exception("School with id {$schoolId} could not be found."); } $userRecord = ['firstName' => $input->getOption('firstName'), 'lastName' => $input->getOption('lastName'), 'email' => $input->getOption('email'), 'telephoneNumber' => $input->getOption('telephoneNumber'), 'campusId' => $input->getOption('campusId'), 'username' => $input->getOption('username'), 'password' => $input->getOption('password')]; $userRecord = $this->fillUserRecord($userRecord, $input, $output); $user = $this->userManager->findOneBy(['campusId' => $userRecord['campusId']]); if ($user) { throw new \Exception('User #' . $user->getId() . " with campus id {$userRecord['campusId']} already exists."); } $user = $this->userManager->findOneBy(['email' => $userRecord['email']]); if ($user) { throw new \Exception('User #' . $user->getId() . " with email address {$userRecord['email']} already exists."); } $table = new Table($output); $table->setHeaders(array('Campus ID', 'First', 'Last', 'Email', 'Username', 'Phone Number'))->setRows(array([$userRecord['campusId'], $userRecord['firstName'], $userRecord['lastName'], $userRecord['email'], $userRecord['username'], $userRecord['telephoneNumber']])); $table->render(); $helper = $this->getHelper('question'); $output->writeln(''); $question = new ConfirmationQuestion("<question>Do you wish to add this user to Ilios in {$school->getTitle()}?</question>\n", true); if ($helper->ask($input, $output, $question)) { $user = $this->userManager->create(); $user->setFirstName($userRecord['firstName']); $user->setLastName($userRecord['lastName']); $user->setEmail($userRecord['email']); $user->setCampusId($userRecord['campusId']); $user->setAddedViaIlios(true); $user->setEnabled(true); $user->setSchool($school); $user->setUserSyncIgnore(false); $this->userManager->update($user); $authentication = $this->authenticationManager->create(); $authentication->setUsername($userRecord['username']); $user->setAuthentication($authentication); $encodedPassword = $this->encoder->encodePassword($user, $userRecord['password']); $authentication->setPasswordBcrypt($encodedPassword); $this->authenticationManager->update($authentication); $output->writeln('<info>Success! New user #' . $user->getId() . ' ' . $user->getFirstAndLastName() . ' created.</info>'); } else { $output->writeln('<comment>Canceled.</comment>'); } }
/** * Authenticate a user from shibboleth * * If the user is not yet logged in send a redirect Request * If the user is logged in, but no account exists send an error * If the user is authenticated send a JWT * @param Request $request * * @throws \Exception when the shibboleth attributes do not contain a value for the configured user id attribute * @return JsonResponse */ public function login(Request $request) { $applicationId = $request->server->get('Shib-Application-ID'); if (!$applicationId) { return new JsonResponse(array('status' => 'redirect', 'errors' => [], 'jwt' => null), JsonResponse::HTTP_OK); } $userId = $request->server->get($this->userIdAttribute); if (!$userId) { $msg = "No '{$this->userIdAttribute}' found for authenticated user."; $logVars = []; $shibProperties = ['Shib-Session-ID', 'Shib-Authentication-Instant', 'Shib-Authentication-Method', 'Shib-Session-Index']; foreach ($shibProperties as $key) { $logVars[$key] = $request->server->get($key); } $logVars['HTTP_REFERER'] = $request->server->get('HTTP_REFERER'); $logVars['REMOTE_ADDR'] = $request->server->get('REMOTE_ADDR'); $this->logger->error($msg, ['server variables' => var_export($logVars, true)]); throw new \Exception($msg); } /* @var \Ilios\CoreBundle\Entity\AuthenticationInterface $authEntity */ $authEntity = $this->authManager->findOneBy(array('username' => $userId)); if ($authEntity) { $user = $authEntity->getUser(); if ($user->isEnabled()) { $jwt = $this->jwtManager->createJwtFromUser($user); return $this->createSuccessResponseFromJWT($jwt); } } return new JsonResponse(array('status' => 'noAccountExists', 'userId' => $userId, 'errors' => [], 'jwt' => null), JsonResponse::HTTP_OK); }
/** * Login a user using a username and password * to bind against an LDAP server * @param Request $request * * @return JsonResponse */ public function login(Request $request) { $username = $request->request->get('username'); $password = $request->request->get('password'); $code = JsonResponse::HTTP_OK; $errors = []; if (!$username) { $errors[] = 'missingUsername'; $code = JsonResponse::HTTP_BAD_REQUEST; } if (!$password) { $errors[] = 'missingPassword'; $code = JsonResponse::HTTP_BAD_REQUEST; } if ($username && $password) { $authEntity = $this->authManager->findAuthenticationByUsername($username); if ($authEntity) { $user = $authEntity->getUser(); if ($user->isEnabled()) { $passwordValid = $this->checkLdapPassword($username, $password); if ($passwordValid) { $jwt = $this->jwtManager->createJwtFromUser($user); return $this->createSuccessResponseFromJWT($jwt); } } } $errors[] = 'badCredentials'; $code = JsonResponse::HTTP_UNAUTHORIZED; } return new JsonResponse(array('status' => 'error', 'errors' => $errors, 'jwt' => null), $code); }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $now = new DateTime(); $userId = $input->getArgument('userId'); $user = $this->userManager->findOneBy(['id' => $userId]); if (!$user) { throw new \Exception("No user with id #{$userId} was found."); } $authentication = $user->getAuthentication(); if (!$authentication) { $authentication = $this->authenticationManager->create(); $authentication->setUser($user); } $authentication->setInvalidateTokenIssuedBefore($now); $this->authenticationManager->update($authentication); $output->writeln('Success!'); $output->writeln('All the tokens for ' . $user->getFirstAndLastName() . ' issued before Today at ' . $now->format('g:i:s A e') . ' have been invalidated.'); }
/** * Update users to the new password encoding when they login * @param AuthenticationEntityInterface $authEntity * @param string $password */ protected function updateLegacyPassword(AuthenticationEntityInterface $authEntity, $password) { if ($authEntity->isLegacyAccount()) { //we have to have a valid token to update the user because the audit log requires it $authenticatedToken = new PreAuthenticatedToken($authEntity->getUser(), 'fakekey', 'fakeProvider'); $authenticatedToken->setAuthenticated(true); $this->tokenStorage->setToken($authenticatedToken); $authEntity->setPasswordSha256(null); $encodedPassword = $this->encoder->encodePassword($authEntity->getUser(), $password); $authEntity->setPasswordBcrypt($encodedPassword); $this->authManager->update($authEntity); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $userId = $input->getArgument('userId'); $user = $this->userManager->findOneBy(['id' => $userId]); if (!$user) { throw new \Exception("No user with id #{$userId} was found."); } $userRecord = $this->directory->findByCampusId($user->getCampusId()); if (!$userRecord) { $output->writeln('<error>Unable to find ' . $user->getCampusId() . ' in the directory.'); return; } $table = new Table($output); $table->setHeaders(array('Record', 'Campus ID', 'First', 'Last', 'Email', 'Phone Number'))->setRows(array(['Ilios User', $user->getCampusId(), $user->getFirstName(), $user->getLastName(), $user->getEmail(), $user->getPhone()], ['Directory User', $userRecord['campusId'], $userRecord['firstName'], $userRecord['lastName'], $userRecord['email'], $userRecord['telephoneNumber']])); $table->render(); $helper = $this->getHelper('question'); $output->writeln(''); $question = new ConfirmationQuestion('<question>Do you wish to update this Ilios User with the data ' . 'from the Directory User? </question>' . "\n", true); if ($helper->ask($input, $output, $question)) { $user->setFirstName($userRecord['firstName']); $user->setLastName($userRecord['lastName']); $user->setEmail($userRecord['email']); $user->setPhone($userRecord['telephoneNumber']); $authentication = $user->getAuthentication(); if (!$authentication) { $authentication = $this->authenticationManager->create(); $authentication->setUser($user); } $authentication->setUsername($userRecord['username']); $this->authenticationManager->update($authentication, false); $this->userManager->update($user); $output->writeln('<info>User updated successfully!</info>'); } else { $output->writeln('<comment>Update canceled.</comment>'); } }
/** * Authenticate a user from shibboleth * * If the user is not yet logged in send a redirect Request * If the user is logged in, but no account exists send an error * If the user is authenticated send a JWT * @param Request $request * * @throws \Exception when the shibboleth attributes do not contain a value for the configured user id attribute * @return JsonResponse */ public function login(Request $request) { $service = $request->query->get('service'); $ticket = $request->query->get('ticket'); if (!$ticket) { return new JsonResponse(array('status' => 'redirect', 'errors' => [], 'jwt' => null), JsonResponse::HTTP_OK); } $userId = $this->casManager->getUserId($service, $ticket); if (!$userId) { $msg = "No user found for authenticated user."; $this->logger->error($msg, ['server vars' => var_export($_SERVER, true)]); throw new \Exception($msg); } /* @var \Ilios\CoreBundle\Entity\AuthenticationInterface $authEntity */ $authEntity = $this->authManager->findOneBy(array('username' => $userId)); if ($authEntity) { $user = $authEntity->getUser(); if ($user->isEnabled()) { $jwt = $this->jwtManager->createJwtFromUser($user); return $this->createSuccessResponseFromJWT($jwt); } } return new JsonResponse(array('status' => 'noAccountExists', 'userId' => $userId, 'errors' => [], 'jwt' => null), JsonResponse::HTTP_OK); }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $campusId = $input->getArgument('campusId'); $user = $this->userManager->findOneBy(['campusId' => $campusId]); if ($user) { throw new \Exception('User #' . $user->getId() . " with campus id {$campusId} already exists."); } $schoolId = $input->getArgument('schoolId'); $school = $this->schoolManager->findOneBy(['id' => $schoolId]); if (!$school) { throw new \Exception("School with id {$schoolId} could not be found."); } $userRecord = $this->directory->findByCampusId($campusId); if (!$userRecord) { $output->writeln("<error>Unable to find campus ID {$campusId} in the directory.</error>"); return; } $table = new Table($output); $table->setHeaders(array('Campus ID', 'First', 'Last', 'Email', 'Username', 'Phone Number'))->setRows(array([$userRecord['campusId'], $userRecord['firstName'], $userRecord['lastName'], $userRecord['email'], $userRecord['username'], $userRecord['telephoneNumber']])); $table->render(); $helper = $this->getHelper('question'); $output->writeln(''); $question = new ConfirmationQuestion("<question>Do you wish to add this user to Ilios?</question>\n", true); if ($helper->ask($input, $output, $question)) { $user = $this->userManager->create(); $user->setFirstName($userRecord['firstName']); $user->setLastName($userRecord['lastName']); $user->setEmail($userRecord['email']); $user->setCampusId($userRecord['campusId']); $user->setAddedViaIlios(true); $user->setEnabled(true); $user->setSchool($school); $user->setUserSyncIgnore(false); $this->userManager->update($user); $authentication = $this->authenticationManager->create(); $authentication->setUser($user); $authentication->setUsername($userRecord['username']); $this->authenticationManager->update($authentication); $output->writeln('<info>Success! New user #' . $user->getId() . ' ' . $user->getFirstAndLastName() . ' created.</info>'); } else { $output->writeln('<comment>Canceled.</comment>'); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $filter = $input->getArgument('filter'); $schoolId = $input->getArgument('schoolId'); $school = $this->schoolManager->findOneBy(['id' => $schoolId]); if (!$school) { throw new \Exception("School with id {$schoolId} could not be found."); } $output->writeln("<info>Searching for new students to add to " . $school->getTitle() . ".</info>"); $students = $this->directory->findByLdapFilter($filter); if (!$students) { $output->writeln("<error>{$filter} returned no results.</error>"); return; } $output->writeln('<info>Found ' . count($students) . ' students in the directory.</info>'); $campusIds = $this->userManager->getAllCampusIds(); $newStudents = array_filter($students, function (array $arr) use($campusIds) { return !in_array($arr['campusId'], $campusIds); }); if (!count($newStudents) > 0) { $output->writeln("<info>There are no new students to add.</info>"); return; } $output->writeln('<info>There are ' . count($newStudents) . ' new students to be added to ' . $school->getTitle() . '.</info>'); $rows = array_map(function (array $arr) { return [$arr['campusId'], $arr['firstName'], $arr['lastName'], $arr['email']]; }, $newStudents); $table = new Table($output); $table->setHeaders(array('Campus ID', 'First', 'Last', 'Email'))->setRows($rows); $table->render(); $helper = $this->getHelper('question'); $output->writeln(''); $question = new ConfirmationQuestion('<question>Do you wish to add these students to ' . $school->getTitle() . '? </question>' . "\n", true); if ($helper->ask($input, $output, $question)) { $studentRole = $this->userRoleManager->findOneBy(array('title' => 'Student')); foreach ($newStudents as $userRecord) { if (empty($userRecord['email'])) { $output->writeln('<error>Unable to add student ' . var_export($userRecord, true) . ' they have no email address.</error>'); continue; } if (empty($userRecord['campusId'])) { $output->writeln('<error>Unable to add student ' . var_export($userRecord, true) . ' they have no campus ID.</error>'); continue; } if (empty($userRecord['username'])) { $output->writeln('<error>Unable to add student ' . var_export($userRecord, true) . ' they have no username.</error>'); continue; } $user = $this->userManager->create(); $user->setFirstName($userRecord['firstName']); $user->setLastName($userRecord['lastName']); $user->setEmail($userRecord['email']); $user->setCampusId($userRecord['campusId']); $user->setAddedViaIlios(true); $user->setEnabled(true); $user->setSchool($school); $user->setUserSyncIgnore(false); $user->addRole($studentRole); $this->userManager->update($user); $authentication = $this->authenticationManager->create(); $authentication->setUser($user); $authentication->setUsername($userRecord['username']); $this->authenticationManager->update($authentication, false); $studentRole->addUser($user); $this->userRoleManager->update($studentRole); $output->writeln('<info>Success! New student #' . $user->getId() . ' ' . $user->getFirstAndLastName() . ' created.</info>'); } } else { $output->writeln('<comment>Update canceled.</comment>'); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('<info>Starting User Sync Process.</info>'); $this->userManager->resetExaminedFlagForAllUsers(); $this->pendingUserUpdateManager->removeAllPendingUserUpdates(); $campusIds = $this->userManager->getAllCampusIds(false, false); $output->writeln('<info>Attempting to update the ' . count($campusIds) . ' enabled and non sync ignored users in the system.</info>'); $output->writeln('<info>Searching the directory for users.</info>'); $allUserRecords = $this->directory->findByCampusIds($campusIds); if (!$allUserRecords) { $output->writeln('<error>[E] Unable to find any users in the directory.</error>'); } $totalRecords = count($allUserRecords); $output->writeln("<info>Found {$totalRecords} records in the directory.</info>"); $updated = 0; $chunks = array_chunk($allUserRecords, 500); foreach ($chunks as $userRecords) { foreach ($userRecords as $recordArray) { $users = $this->userManager->findBy(['campusId' => $recordArray['campusId'], 'enabled' => true, 'userSyncIgnore' => false]); if (count($users) == 0) { //this shouldn't happen unless the user gets updated between //listing all the IDs and getting results back from //the directory $output->writeln('<error>[E] Unable to find an enabled sync active user with ' . 'campus ID ' . $recordArray['campusId'] . '.</error>'); continue; } if (count($users) > 1) { $output->writeln('<error>[E] Multiple accounts exist for the same ' . 'campus ID (' . $recordArray['campusId'] . '). ' . 'None of them will be updated.</error>'); /* @var UserInterface $user */ foreach ($users as $user) { $user->setExamined(true); $this->userManager->update($user, false); } continue; } $user = $users[0]; $update = false; $fixSmallThings = true; $output->writeln('<info>[I] Comparing User #' . $user->getId() . ' ' . $user->getFirstAndLastName() . ' (' . $user->getEmail() . ') ' . 'to directory user by campus ID ' . $user->getCampusId() . '.</info>'); if (!$this->validateDirectoryRecord($recordArray, $output)) { $user->setExamined(true); $this->userManager->update($user, false); //don't do anything else with invalid directory data continue; } if ($user->getEmail() != $recordArray['email']) { if (strtolower($user->getEmail()) == strtolower($recordArray['email'])) { $update = true; $output->writeln(' <comment>[I] Updating email from "' . $user->getEmail() . '" to "' . $recordArray['email'] . '" since the only difference was the case.</comment>'); $user->setEmail($recordArray['email']); } else { $fixSmallThings = false; $output->writeln(' <comment>[I] Email address "' . $user->getEmail() . '" differs from "' . $recordArray['email'] . '" logging for further action.</comment>'); $pendingUpdate = $this->pendingUserUpdateManager->create(); $pendingUpdate->setUser($user); $pendingUpdate->setProperty('email'); $pendingUpdate->setValue($recordArray['email']); $pendingUpdate->setType('emailMismatch'); $this->pendingUserUpdateManager->update($pendingUpdate, false); } } if ($fixSmallThings && $user->getFirstName() != $recordArray['firstName']) { $update = true; $output->writeln(' <comment>[I] Updating first name from "' . $user->getFirstName() . '" to "' . $recordArray['firstName'] . '".</comment>'); $user->setFirstName($recordArray['firstName']); } if ($fixSmallThings && $user->getLastName() != $recordArray['lastName']) { $update = true; $output->writeln(' <comment>[I] Updating last name from "' . $user->getLastName() . '" to "' . $recordArray['lastName'] . '".</comment>'); $user->setLastName($recordArray['lastName']); } if ($fixSmallThings && $user->getPhone() != $recordArray['telephoneNumber']) { $update = true; $output->writeln(' <comment>[I] Updating phone number from "' . $user->getPhone() . '" to "' . $recordArray['telephoneNumber'] . '".</comment>'); $user->setPhone($recordArray['telephoneNumber']); } $authentication = $user->getAuthentication(); if (!$authentication) { $output->writeln(' <comment>[I] User had no authentication data, creating it now.</comment>'); $authentication = $this->authenticationManager->create(); $authentication->setUser($user); } if ($fixSmallThings && $authentication->getUsername() != $recordArray['username']) { $update = true; $output->writeln(' <comment>[I] Updating username from "' . $authentication->getUsername() . '" to "' . $recordArray['username'] . '".</comment>'); $authentication->setUsername($recordArray['username']); $this->authenticationManager->update($authentication, false); } if ($update) { $updated++; } $user->setExamined(true); $this->userManager->update($user, false); } $this->em->flush(); $this->em->clear(); } $output->writeln('<info>Searching for users who were not examined during the sync process.</info>'); $unsyncedUsers = $this->userManager->findBy(['examined' => false, 'enabled' => true, 'userSyncIgnore' => false], ['lastName' => ' ASC', 'firstName' => 'ASC']); $output->writeln('<info>Found ' . count($unsyncedUsers) . ' unexamined users.</info>'); foreach ($unsyncedUsers as $user) { $output->writeln('<comment>[I] User #' . $user->getId() . ' ' . $user->getFirstAndLastName() . ' ' . $user->getEmail() . ' not found in the directory. Logged for further study.</comment>'); $update = $this->pendingUserUpdateManager->create(); $update->setUser($user); $update->setType('missingFromDirectory'); $this->pendingUserUpdateManager->update($update, false); } $this->em->flush(); $output->writeln("<info>Completed sync process {$totalRecords} users found in the directory; " . "{$updated} users updated.</info>"); }