MediaWiki REL1_34
OATHUserRepository.php
Go to the documentation of this file.
1<?php
20
22use Psr\Log\LoggerInterface;
25use FormatJson;
27use MWException;
28use BagOStuff;
30use User;
31use stdClass;
33
36 protected $lb;
37
39 protected $cache;
40
44 protected $auth;
45
47 private $logger;
48
56 $this->lb = $lb;
57 $this->cache = $cache;
58 $this->auth = $auth;
59
60 $this->setLogger( LoggerFactory::getInstance( 'authentication' ) );
61 }
62
66 public function setLogger( LoggerInterface $logger ) {
67 $this->logger = $logger;
68 }
69
76 public function findByUser( User $user ) {
77 $oathUser = $this->cache->get( $user->getName() );
78 if ( !$oathUser ) {
79 $oathUser = new OATHUser( $user, null );
80
81 $uid = CentralIdLookup::factory()->centralIdFromLocalUser( $user );
82 $res = $this->getDB( DB_REPLICA )->selectRow(
83 'oathauth_users',
84 '*',
85 [ 'id' => $uid ],
86 __METHOD__
87 );
88 if ( $res ) {
89 $data = $res->data;
90 $moduleKey = $res->module;
91 if ( $this->isLegacy( $res ) ) {
92 $module = $this->auth->getModuleByKey( 'totp' );
93 $data = $this->checkAndResolveLegacy( $data, $res );
94 } else {
95 $module = $this->auth->getModuleByKey( $moduleKey );
96 }
97 if ( $module === null ) {
98 // For sanity
99 throw new MWException( 'oathauth-module-invalid' );
100 }
101
102 $oathUser->setModule( $module );
103 $decodedData = FormatJson::decode( $res->data, 1 );
104 if ( !isset( $decodedData['keys'] ) && $module->getName() === 'totp' ) {
105 // Legacy single-key setup
106 $key = $module->newKey( $decodedData );
107 $oathUser->addKey( $key );
108 } elseif ( is_array( $decodedData['keys'] ) ) {
109 foreach ( $decodedData['keys'] as $keyData ) {
110 $key = $module->newKey( $keyData );
111 $oathUser->addKey( $key );
112 }
113 }
114 }
115
116 $this->cache->set( $user->getName(), $oathUser );
117 }
118 return $oathUser;
119 }
120
127 public function persist( OATHUser $user, $clientInfo = null ) {
128 if ( !$clientInfo ) {
129 $clientInfo = RequestContext::getMain()->getRequest()->getIP();
130 }
131 $prevUser = $this->findByUser( $user->getUser() );
132 $data = $user->getModule()->getDataFromUser( $user );
133
134 $this->getDB( DB_MASTER )->replace(
135 'oathauth_users',
136 [ 'id' ],
137 [
138 'id' => CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() ),
139 'module' => $user->getModule()->getName(),
140 'data' => FormatJson::encode( $data )
141 ],
142 __METHOD__
143 );
144
145 $userName = $user->getUser()->getName();
146 $this->cache->set( $userName, $user );
147
148 if ( $prevUser !== false ) {
149 $this->logger->info( 'OATHAuth updated for {user} from {clientip}', [
150 'user' => $userName,
151 'clientip' => $clientInfo,
152 ] );
153 } else {
154 // If findByUser() has returned false, there was no user row or cache entry
155 $this->logger->info( 'OATHAuth enabled for {user} from {clientip}', [
156 'user' => $userName,
157 'clientip' => $clientInfo,
158 ] );
159 }
160 }
161
166 public function remove( OATHUser $user, $clientInfo ) {
167 $this->getDB( DB_MASTER )->delete(
168 'oathauth_users',
169 [ 'id' => CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() ) ],
170 __METHOD__
171 );
172
173 $userName = $user->getUser()->getName();
174 $this->cache->delete( $userName );
175
176 $this->logger->info( 'OATHAuth disabled for {user} from {clientip}', [
177 'user' => $userName,
178 'clientip' => $clientInfo,
179 ] );
180 }
181
186 private function getDB( $index ) {
187 global $wgOATHAuthDatabase;
188
189 return $this->lb->getConnectionRef( $index, [], $wgOATHAuthDatabase );
190 }
191
196 private function isLegacy( $row ) {
197 if ( $row->module !== '' ) {
198 return false;
199 }
200 if ( property_exists( $row, 'secret' ) && $row->secret !== null ) {
201 return true;
202 }
203 return false;
204 }
205
214 private function checkAndResolveLegacy( $data, $row ) {
215 if ( $data ) {
216 // New data exists - no action required
217 return $data;
218 }
219 if ( property_exists( $row, 'secret' ) && property_exists( $row, 'scratch_tokens' ) ) {
220 return FormatJson::encode( [
221 'secret' => $row->secret,
222 'scratch_tokens' => $row->scratch_tokens
223 ] );
224 }
225 return '';
226 }
227}
getDB()
Class representing a cache/ephemeral data store.
Definition BagOStuff.php:63
The CentralIdLookup service allows for connecting local users with cluster-wide IDs.
Exceptions for config failures.
JSON formatter wrapper class.
MediaWiki exception.
checkAndResolveLegacy( $data, $row)
Checks if the DB data is in the new format, if not converts old data to new.
__construct(ILoadBalancer $lb, BagOStuff $cache, OATHAuth $auth)
OATHUserRepository constructor.
Class representing a user from OATH's perspective.
Definition OATHUser.php:28
getModule()
Gets the module instance associated with this user.
Definition OATHUser.php:140
PSR-3 logger instance factory.
Group all the pieces relevant to the context of a request into one instance.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:51
getName()
Get the user name, or the IP of an anonymous user.
Definition User.php:2364
Helper class used for automatically marking an IDatabase connection as reusable (once it no longer ma...
Definition DBConnRef.php:29
Database cluster connection, tracking, load balancing, and transaction manager interface.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
const DB_REPLICA
Definition defines.php:25
const DB_MASTER
Definition defines.php:26