MediaWiki master
BotPasswordSessionProvider.php
Go to the documentation of this file.
1<?php
25
32
39 private $grantsInfo;
40
42 private $isApiRequest;
43
52 public function __construct( GrantsInfo $grantsInfo, array $params = [] ) {
53 if ( !isset( $params['sessionCookieName'] ) ) {
54 $params['sessionCookieName'] = '_BPsession';
55 }
56 parent::__construct( $params );
57
58 if ( !isset( $params['priority'] ) ) {
59 throw new \InvalidArgumentException( __METHOD__ . ': priority must be specified' );
60 }
61 if ( $params['priority'] < SessionInfo::MIN_PRIORITY ||
63 ) {
64 throw new \InvalidArgumentException( __METHOD__ . ': Invalid priority' );
65 }
66
67 $this->priority = $params['priority'];
68
69 $this->grantsInfo = $grantsInfo;
70
71 $this->isApiRequest = $params['isApiRequest']
72 ?? ( defined( 'MW_API' ) || defined( 'MW_REST_API' ) );
73 }
74
75 public function provideSessionInfo( WebRequest $request ) {
76 // Only relevant for the (Action or REST) API
77 if ( !$this->isApiRequest ) {
78 return null;
79 }
80
81 // Enabled?
82 if ( !$this->getConfig()->get( MainConfigNames::EnableBotPasswords ) ) {
83 return null;
84 }
85
86 // Have a session ID?
87 $id = $this->getSessionIdFromCookie( $request );
88 if ( $id === null ) {
89 return null;
90 }
91
92 return new SessionInfo( $this->priority, [
93 'provider' => $this,
94 'id' => $id,
95 'persisted' => true
96 ] );
97 }
98
99 public function newSessionInfo( $id = null ) {
100 // We don't activate by default
101 return null;
102 }
103
111 public function newSessionForRequest( User $user, BotPassword $bp, WebRequest $request ) {
112 $id = $this->getSessionIdFromCookie( $request );
114 'provider' => $this,
115 'id' => $id,
116 'userInfo' => UserInfo::newFromUser( $user, true ),
117 'persisted' => $id !== null,
118 'metadata' => [
119 'centralId' => $bp->getUserCentralId(),
120 'appId' => $bp->getAppId(),
121 'token' => $bp->getToken(),
122 'rights' => $this->grantsInfo->getGrantRights( $bp->getGrants() ),
123 'restrictions' => $bp->getRestrictions()->toJson(),
124 ],
125 ] );
126 $session = $this->getManager()->getSessionFromInfo( $info, $request );
127 $session->persist();
128 return $session;
129 }
130
135 public function refreshSessionInfo( SessionInfo $info, WebRequest $request, &$metadata ) {
136 $missingKeys = array_diff(
137 [ 'centralId', 'appId', 'token' ],
138 array_keys( $metadata )
139 );
140 if ( $missingKeys ) {
141 $this->logger->info( 'Session "{session}": Missing metadata: {missing}', [
142 'session' => $info->__toString(),
143 'missing' => implode( ', ', $missingKeys ),
144 ] );
145 return false;
146 }
147
148 $bp = BotPassword::newFromCentralId( $metadata['centralId'], $metadata['appId'] );
149 if ( !$bp ) {
150 $this->logger->info(
151 'Session "{session}": No BotPassword for {centralId} {appId}',
152 [
153 'session' => $info->__toString(),
154 'centralId' => $metadata['centralId'],
155 'appId' => $metadata['appId'],
156 ] );
157 return false;
158 }
159
160 if ( !hash_equals( $metadata['token'], $bp->getToken() ) ) {
161 $this->logger->info( 'Session "{session}": BotPassword token check failed', [
162 'session' => $info->__toString(),
163 'centralId' => $metadata['centralId'],
164 'appId' => $metadata['appId'],
165 ] );
166 return false;
167 }
168
169 $status = $bp->getRestrictions()->check( $request );
170 if ( !$status->isOK() ) {
171 $this->logger->info(
172 'Session "{session}": Restrictions check failed',
173 [
174 'session' => $info->__toString(),
175 'restrictions' => $status->getValue(),
176 'centralId' => $metadata['centralId'],
177 'appId' => $metadata['appId'],
178 ] );
179 return false;
180 }
181
182 // Update saved rights
183 $metadata['rights'] = $this->grantsInfo->getGrantRights( $bp->getGrants() );
184
185 return true;
186 }
187
192 public function preventSessionsForUser( $username ) {
193 BotPassword::removeAllPasswordsForUser( $username );
194 }
195
196 public function getAllowedUserRights( SessionBackend $backend ) {
197 if ( $backend->getProvider() !== $this ) {
198 throw new \InvalidArgumentException( 'Backend\'s provider isn\'t $this' );
199 }
200 $data = $backend->getProviderMetadata();
201 if ( $data && isset( $data['rights'] ) && is_array( $data['rights'] ) ) {
202 return $data['rights'];
203 }
204
205 // Should never happen
206 $this->logger->debug( __METHOD__ . ': No provider metadata, returning no rights allowed' );
207 return [];
208 }
209
210 public function getRestrictions( ?array $data ): ?MWRestrictions {
211 if ( $data && isset( $data['restrictions'] ) && is_string( $data['restrictions'] ) ) {
212 try {
213 return MWRestrictions::newFromJson( $data['restrictions'] );
214 } catch ( \InvalidArgumentException $e ) {
215 $this->logger->warning( __METHOD__ . ': Failed to parse restrictions: {restrictions}', [
216 'restrictions' => $data['restrictions']
217 ] );
218 return null;
219 }
220 }
221 return null;
222 }
223}
array $params
The job parameters.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
A class to check request restrictions expressed as a JSON object.
A class containing constants representing the names of configuration variables.
const EnableBotPasswords
Name constant for the EnableBotPasswords setting, for use with Config::get()
Users can authorize applications to use their account via OAuth.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
newSessionForRequest(User $user, BotPassword $bp, WebRequest $request)
Create a new session for a request.
provideSessionInfo(WebRequest $request)
Provide session info for a request.
__construct(GrantsInfo $grantsInfo, array $params=[])
preventSessionsForUser( $username)
Prevent future sessions for the user.If the provider is capable of returning a SessionInfo with a ver...
getRestrictions(?array $data)
Fetch any restrictions imposed on logins or actions when this session is active.
getAllowedUserRights(SessionBackend $backend)
Fetch the rights allowed the user when the specified session is active.
newSessionInfo( $id=null)
Provide session info for a new, empty session.
refreshSessionInfo(SessionInfo $info, WebRequest $request, &$metadata)
Validate a loaded SessionInfo and refresh provider metadata.This is similar in purpose to the 'Sessio...
An ImmutableSessionProviderWithCookie doesn't persist the user, but optionally can use a cookie to su...
getSessionIdFromCookie(WebRequest $request)
Get the session ID from the cookie, if any.
This is the actual workhorse for Session.
getProviderMetadata()
Fetch provider metadata.
getProvider()
Fetch the SessionProvider for this session.
Value object returned by SessionProvider.
const MIN_PRIORITY
Minimum allowed priority.
const MAX_PRIORITY
Maximum allowed priority.
getManager()
Get the session manager.
static newFromUser(User $user, $verified=false)
Create an instance from an existing User object.
Definition UserInfo.php:123
Utility class for bot passwords.
getUserCentralId()
Get the central user ID.
internal since 1.36
Definition User.php:93