1<?php 2/** 3 * @copyright Copyright (c) 2015, ownCloud, Inc. 4 * 5 * @author blizzz <blizzz@arthur-schiwon.de> 6 * @author Christoph Wurst <christoph@winzerhof-wurst.at> 7 * @author Joas Schilling <coding@schilljs.com> 8 * @author Lukas Reschke <lukas@statuscode.ch> 9 * @author Morris Jobke <hey@morrisjobke.de> 10 * @author Robin Appelman <robin@icewind.nl> 11 * @author Roeland Jago Douma <roeland@famdouma.nl> 12 * 13 * @license AGPL-3.0 14 * 15 * This code is free software: you can redistribute it and/or modify 16 * it under the terms of the GNU Affero General Public License, version 3, 17 * as published by the Free Software Foundation. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU Affero General Public License for more details. 23 * 24 * You should have received a copy of the GNU Affero General Public License, version 3, 25 * along with this program. If not, see <http://www.gnu.org/licenses/> 26 * 27 */ 28namespace OCA\Files_External\Lib\Auth\Password; 29 30use OCA\Files_External\Lib\Auth\AuthMechanism; 31use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; 32use OCA\Files_External\Lib\StorageConfig; 33use OCA\Files_External\Listener\StorePasswordListener; 34use OCP\Authentication\Exceptions\CredentialsUnavailableException; 35use OCP\Authentication\LoginCredentials\IStore as CredentialsStore; 36use OCP\EventDispatcher\IEventDispatcher; 37use OCP\IL10N; 38use OCP\ISession; 39use OCP\IUser; 40use OCP\IUserBackend; 41use OCP\LDAP\ILDAPProviderFactory; 42use OCP\Security\ICredentialsManager; 43use OCP\User\Events\PasswordUpdatedEvent; 44use OCP\User\Events\UserLoggedInEvent; 45 46/** 47 * Username and password from login credentials, saved in DB 48 */ 49class LoginCredentials extends AuthMechanism { 50 public const CREDENTIALS_IDENTIFIER = 'password::logincredentials/credentials'; 51 52 /** @var ISession */ 53 protected $session; 54 55 /** @var ICredentialsManager */ 56 protected $credentialsManager; 57 58 /** @var CredentialsStore */ 59 private $credentialsStore; 60 61 /** @var ILDAPProviderFactory */ 62 private $ldapFactory; 63 64 public function __construct( 65 IL10N $l, 66 ISession $session, 67 ICredentialsManager $credentialsManager, 68 CredentialsStore $credentialsStore, 69 IEventDispatcher $eventDispatcher, 70 ILDAPProviderFactory $ldapFactory 71 ) { 72 $this->session = $session; 73 $this->credentialsManager = $credentialsManager; 74 $this->credentialsStore = $credentialsStore; 75 $this->ldapFactory = $ldapFactory; 76 77 $this 78 ->setIdentifier('password::logincredentials') 79 ->setScheme(self::SCHEME_PASSWORD) 80 ->setText($l->t('Log-in credentials, save in database')) 81 ->addParameters([ 82 ]); 83 84 $eventDispatcher->addServiceListener(UserLoggedInEvent::class, StorePasswordListener::class); 85 $eventDispatcher->addServiceListener(PasswordUpdatedEvent::class, StorePasswordListener::class); 86 } 87 88 private function getCredentials(IUser $user): array { 89 $credentials = $this->credentialsManager->retrieve($user->getUID(), self::CREDENTIALS_IDENTIFIER); 90 91 if (is_null($credentials)) { 92 // nothing saved in db, try to get it from the session and save it 93 try { 94 $sessionCredentials = $this->credentialsStore->getLoginCredentials(); 95 96 if ($sessionCredentials->getUID() !== $user->getUID()) { 97 // Can't take the credentials from the session as they are not the same user 98 throw new CredentialsUnavailableException(); 99 } 100 101 $credentials = [ 102 'user' => $sessionCredentials->getLoginName(), 103 'password' => $sessionCredentials->getPassword(), 104 ]; 105 106 $this->credentialsManager->store($user->getUID(), self::CREDENTIALS_IDENTIFIER, $credentials); 107 } catch (CredentialsUnavailableException $e) { 108 throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved'); 109 } 110 } 111 112 return $credentials; 113 } 114 115 public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) { 116 if (!isset($user)) { 117 throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved'); 118 } 119 $credentials = $this->getCredentials($user); 120 121 $loginKey = $storage->getBackendOption("login_ldap_attr"); 122 if ($loginKey) { 123 $backend = $user->getBackend(); 124 if ($backend instanceof IUserBackend && $backend->getBackendName() === 'LDAP') { 125 $value = $this->getLdapPropertyForUser($user, $loginKey); 126 if ($value === null) { 127 throw new InsufficientDataForMeaningfulAnswerException('Custom ldap attribute not set for user ' . $user->getUID()); 128 } 129 $storage->setBackendOption('user', $value); 130 } else { 131 throw new InsufficientDataForMeaningfulAnswerException('Custom ldap attribute configured but user ' . $user->getUID() . ' is not an ldap user'); 132 } 133 } else { 134 $storage->setBackendOption('user', $credentials['user']); 135 } 136 $storage->setBackendOption('password', $credentials['password']); 137 } 138 139 private function getLdapPropertyForUser(IUser $user, string $property): ?string { 140 return $this->ldapFactory->getLDAPProvider()->getUserAttribute($user->getUID(), $property); 141 } 142} 143