MediaWiki master
BotPasswordSessionProvider.php
Go to the documentation of this file.
1<?php
8
9use InvalidArgumentException;
16
24 private GrantsInfo $grantsInfo;
25
27 private $isApiRequest;
28
37 public function __construct( GrantsInfo $grantsInfo, array $params = [] ) {
38 if ( !isset( $params['sessionCookieName'] ) ) {
39 $params['sessionCookieName'] = '_BPsession';
40 }
41 parent::__construct( $params );
42
43 if ( !isset( $params['priority'] ) ) {
44 throw new InvalidArgumentException( __METHOD__ . ': priority must be specified' );
45 }
46 if ( $params['priority'] < SessionInfo::MIN_PRIORITY ||
47 $params['priority'] > SessionInfo::MAX_PRIORITY
48 ) {
49 throw new InvalidArgumentException( __METHOD__ . ': Invalid priority' );
50 }
51
52 $this->priority = $params['priority'];
53
54 $this->grantsInfo = $grantsInfo;
55
56 $this->isApiRequest = $params['isApiRequest']
57 ?? ( defined( 'MW_API' ) || defined( 'MW_REST_API' ) );
58 }
59
61 public function provideSessionInfo( WebRequest $request ) {
62 // Only relevant for the (Action or REST) API
63 if ( !$this->isApiRequest ) {
64 return null;
65 }
66
67 // Enabled?
68 if ( !$this->getConfig()->get( MainConfigNames::EnableBotPasswords ) ) {
69 return null;
70 }
71
72 // Have a session ID?
73 $id = $this->getSessionIdFromCookie( $request );
74 if ( $id === null ) {
75 return null;
76 }
77
78 return new SessionInfo( $this->priority, [
79 'provider' => $this,
80 'id' => $id,
81 'persisted' => true
82 ] );
83 }
84
86 public function newSessionInfo( $id = null ) {
87 // We don't activate by default
88 return null;
89 }
90
98 public function newSessionForRequest( User $user, BotPassword $bp, WebRequest $request ) {
99 $id = $this->getSessionIdFromCookie( $request );
101 'provider' => $this,
102 'id' => $id,
103 'userInfo' => UserInfo::newFromUser( $user, true ),
104 'persisted' => $id !== null,
105 'metadata' => [
106 'centralId' => $bp->getUserCentralId(),
107 'appId' => $bp->getAppId(),
108 'token' => $bp->getToken(),
109 'rights' => $this->grantsInfo->getGrantRights( $bp->getGrants() ),
110 'restrictions' => $bp->getRestrictions()->toJson(),
111 ],
112 ] );
113 $session = $this->getManager()->getSessionFromInfo( $info, $request );
114 $session->persist();
115 return $session;
116 }
117
122 public function refreshSessionInfo( SessionInfo $info, WebRequest $request, &$metadata ) {
123 $missingKeys = array_diff(
124 [ 'centralId', 'appId', 'token' ],
125 array_keys( $metadata )
126 );
127 if ( $missingKeys ) {
128 $this->logger->info( 'Session "{session}": Missing metadata: {missing}', [
129 'session' => $info->__toString(),
130 'missing' => implode( ', ', $missingKeys ),
131 ] );
132 return false;
133 }
134
135 $bp = BotPassword::newFromCentralId( $metadata['centralId'], $metadata['appId'] );
136 if ( !$bp ) {
137 $this->logger->info(
138 'Session "{session}": No BotPassword for {centralId} {appId}',
139 [
140 'session' => $info->__toString(),
141 'centralId' => $metadata['centralId'],
142 'appId' => $metadata['appId'],
143 ] );
144 return false;
145 }
146
147 if ( !hash_equals( $metadata['token'], $bp->getToken() ) ) {
148 $this->logger->info( 'Session "{session}": BotPassword token check failed', [
149 'session' => $info->__toString(),
150 'centralId' => $metadata['centralId'],
151 'appId' => $metadata['appId'],
152 ] );
153 return false;
154 }
155
156 $status = $bp->getRestrictions()->check( $request );
157 if ( !$status->isOK() ) {
158 $this->logger->info(
159 'Session "{session}": Restrictions check failed',
160 [
161 'session' => $info->__toString(),
162 'restrictions' => $status->getValue(),
163 'centralId' => $metadata['centralId'],
164 'appId' => $metadata['appId'],
165 ] );
166 return false;
167 }
168
169 // Update saved rights
170 $metadata['rights'] = $this->grantsInfo->getGrantRights( $bp->getGrants() );
171
172 return true;
173 }
174
179 public function preventSessionsForUser( $username ) {
180 BotPassword::removeAllPasswordsForUser( $username );
181 }
182
184 public function getAllowedUserRights( SessionBackend $backend ) {
185 if ( $backend->getProvider() !== $this ) {
186 throw new InvalidArgumentException( 'Backend\'s provider isn\'t $this' );
187 }
188 $data = $backend->getProviderMetadata();
189 if ( $data && isset( $data['rights'] ) && is_array( $data['rights'] ) ) {
190 return $data['rights'];
191 }
192
193 // Should never happen
194 $this->logger->debug( __METHOD__ . ': No provider metadata, returning no rights allowed' );
195 return [];
196 }
197
198 public function getRestrictions( ?array $data ): ?MWRestrictions {
199 if ( $data && isset( $data['restrictions'] ) && is_string( $data['restrictions'] ) ) {
200 try {
201 return MWRestrictions::newFromJson( $data['restrictions'] );
202 } catch ( InvalidArgumentException ) {
203 $this->logger->warning( __METHOD__ . ': Failed to parse restrictions: {restrictions}', [
204 'restrictions' => $data['restrictions']
205 ] );
206 return null;
207 }
208 }
209 return null;
210 }
211}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:68
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.If no session exists for the request, return null....
__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.This is mainly meant for allow...
newSessionInfo( $id=null)
Provide session info for a new, empty session.Return null if such a session cannot be created....
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:108
Utility class for bot passwords.
getUserCentralId()
Get the central user ID.
User class for the MediaWiki software.
Definition User.php:130