MediaWiki  1.34.0
OATHUserRepository.php
Go to the documentation of this file.
1 <?php
20 
22 use Psr\Log\LoggerInterface;
25 use FormatJson;
26 use CentralIdLookup;
27 use MWException;
28 use BagOStuff;
29 use ConfigException;
30 use User;
31 use stdClass;
32 
35  protected $lb;
36 
38  protected $cache;
39 
43  protected $auth;
44 
46  private $logger;
47 
55  $this->lb = $lb;
56  $this->cache = $cache;
57  $this->auth = $auth;
58 
59  $this->setLogger( LoggerFactory::getInstance( 'authentication' ) );
60  }
61 
65  public function setLogger( LoggerInterface $logger ) {
66  $this->logger = $logger;
67  }
68 
75  public function findByUser( User $user ) {
76  $oathUser = $this->cache->get( $user->getName() );
77  if ( !$oathUser ) {
78  $oathUser = new OATHUser( $user, null );
79 
80  $uid = CentralIdLookup::factory()->centralIdFromLocalUser( $user );
81  $res = $this->getDB( DB_REPLICA )->selectRow(
82  'oathauth_users',
83  '*',
84  [ 'id' => $uid ],
85  __METHOD__
86  );
87  if ( $res ) {
88  $data = $res->data;
89  $moduleKey = $res->module;
90  if ( $this->isLegacy( $res ) ) {
91  $module = $this->auth->getModuleByKey( 'totp' );
92  $data = $this->checkAndResolveLegacy( $data, $res );
93  } else {
94  $module = $this->auth->getModuleByKey( $moduleKey );
95  }
96  if ( $module === null ) {
97  // For sanity
98  throw new MWException( 'oathauth-module-invalid' );
99  }
100 
101  $oathUser->setModule( $module );
102  $decodedData = FormatJson::decode( $res->data, 1 );
103  if ( !isset( $decodedData['keys'] ) && $module->getName() === 'totp' ) {
104  // Legacy single-key setup
105  $key = $module->newKey( $decodedData );
106  $oathUser->addKey( $key );
107  } elseif ( is_array( $decodedData['keys'] ) ) {
108  foreach ( $decodedData['keys'] as $keyData ) {
109  $key = $module->newKey( $keyData );
110  $oathUser->addKey( $key );
111  }
112  }
113  }
114 
115  $this->cache->set( $user->getName(), $oathUser );
116  }
117  return $oathUser;
118  }
119 
126  public function persist( OATHUser $user, $clientInfo ) {
127  $prevUser = $this->findByUser( $user->getUser() );
128  $data = $user->getModule()->getDataFromUser( $user );
129 
130  $this->getDB( DB_MASTER )->replace(
131  'oathauth_users',
132  [ 'id' ],
133  [
134  'id' => CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() ),
135  'module' => $user->getModule()->getName(),
136  'data' => FormatJson::encode( $data )
137  ],
138  __METHOD__
139  );
140 
141  $userName = $user->getUser()->getName();
142  $this->cache->set( $userName, $user );
143 
144  if ( $prevUser !== false ) {
145  $this->logger->info( 'OATHAuth updated for {user} from {clientip}', [
146  'user' => $userName,
147  'clientip' => $clientInfo,
148  ] );
149  } else {
150  // If findByUser() has returned false, there was no user row or cache entry
151  $this->logger->info( 'OATHAuth enabled for {user} from {clientip}', [
152  'user' => $userName,
153  'clientip' => $clientInfo,
154  ] );
155  }
156  }
157 
162  public function remove( OATHUser $user, $clientInfo ) {
163  $this->getDB( DB_MASTER )->delete(
164  'oathauth_users',
165  [ 'id' => CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() ) ],
166  __METHOD__
167  );
168 
169  $userName = $user->getUser()->getName();
170  $this->cache->delete( $userName );
171 
172  $this->logger->info( 'OATHAuth disabled for {user} from {clientip}', [
173  'user' => $userName,
174  'clientip' => $clientInfo,
175  ] );
176  }
177 
182  private function getDB( $index ) {
183  global $wgOATHAuthDatabase;
184 
185  return $this->lb->getConnectionRef( $index, [], $wgOATHAuthDatabase );
186  }
187 
192  private function isLegacy( $row ) {
193  if ( $row->module !== '' ) {
194  return false;
195  }
196  if ( property_exists( $row, 'secret' ) && $row->secret !== null ) {
197  return true;
198  }
199  return false;
200  }
201 
210  private function checkAndResolveLegacy( $data, $row ) {
211  if ( $data ) {
212  // New data exists - no action required
213  return $data;
214  }
215  if ( property_exists( $row, 'secret' ) && property_exists( $row, 'scratch_tokens' ) ) {
216  return FormatJson::encode( [
217  'secret' => $row->secret,
218  'scratch_tokens' => $row->scratch_tokens
219  ] );
220  }
221  return '';
222  }
223 }
MediaWiki\Extension\OATHAuth\OATHUserRepository\$cache
BagOStuff $cache
Definition: OATHUserRepository.php:38
MediaWiki\Extension\OATHAuth\OATHUser\getModule
getModule()
Gets the module instance associated with this user.
Definition: OATHUser.php:140
MediaWiki\Extension\OATHAuth\OATHUserRepository\persist
persist(OATHUser $user, $clientInfo)
Definition: OATHUserRepository.php:126
MediaWiki\Extension\OATHAuth\OATHUserRepository\findByUser
findByUser(User $user)
Definition: OATHUserRepository.php:75
MediaWiki\Extension\OATHAuth\OATHUserRepository\isLegacy
isLegacy( $row)
Definition: OATHUserRepository.php:192
MediaWiki\Extension\OATHAuth\OATHUser
Class representing a user from OATH's perspective.
Definition: OATHUser.php:28
MediaWiki\Extension\OATHAuth\OATHUserRepository\getDB
getDB( $index)
Definition: OATHUserRepository.php:182
MediaWiki\Logger\LoggerFactory\getInstance
static getInstance( $channel)
Get a named logger instance from the currently configured logger factory.
Definition: LoggerFactory.php:92
MediaWiki\Extension\OATHAuth\OATHUserRepository\$lb
ILoadBalancer $lb
Definition: OATHUserRepository.php:35
BagOStuff
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:63
$res
$res
Definition: testCompression.php:52
MediaWiki\Extension\OATHAuth\OATHUserRepository
Definition: OATHUserRepository.php:33
FormatJson\decode
static decode( $value, $assoc=false)
Decodes a JSON string.
Definition: FormatJson.php:174
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:115
FormatJson
JSON formatter wrapper class.
Definition: FormatJson.php:26
MWException
MediaWiki exception.
Definition: MWException.php:26
MediaWiki\Extension\OATHAuth\OATHAuth
Definition: OATHAuth.php:14
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
MediaWiki\Extension\OATHAuth\OATHUserRepository\setLogger
setLogger(LoggerInterface $logger)
Definition: OATHUserRepository.php:65
ConfigException
Exceptions for config failures.
Definition: ConfigException.php:28
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
DB_MASTER
const DB_MASTER
Definition: defines.php:26
MediaWiki\Extension\OATHAuth\OATHUserRepository\$logger
LoggerInterface $logger
Definition: OATHUserRepository.php:46
MediaWiki\Extension\OATHAuth\OATHUserRepository\$auth
OATHAuth $auth
Definition: OATHUserRepository.php:43
Wikimedia\Rdbms\DBConnRef
Helper class used for automatically marking an IDatabase connection as reusable (once it no longer ma...
Definition: DBConnRef.php:29
MediaWiki\Extension\OATHAuth
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
CentralIdLookup
The CentralIdLookup service allows for connecting local users with cluster-wide IDs.
Definition: CentralIdLookup.php:30
MediaWiki\Extension\OATHAuth\OATHUserRepository\checkAndResolveLegacy
checkAndResolveLegacy( $data, $row)
Checks if the DB data is in the new format, if not converts old data to new.
Definition: OATHUserRepository.php:210
MediaWiki\Extension\OATHAuth\OATHUser\getUser
getUser()
Definition: OATHUser.php:53
CentralIdLookup\factory
static factory( $providerId=null)
Fetch a CentralIdLookup.
Definition: CentralIdLookup.php:46
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:51
MediaWiki\Extension\OATHAuth\OATHUserRepository\__construct
__construct(ILoadBalancer $lb, BagOStuff $cache, OATHAuth $auth)
OATHUserRepository constructor.
Definition: OATHUserRepository.php:54
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2232
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81