summaryrefslogtreecommitdiff
blob: 6b518461deb3ef247ae664f100b05877a52c5ce2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php

namespace MediaWiki\Extensions\OAuth;

use Config;
use MediaWiki\Extensions\OAuth\Backend\Consumer;
use MediaWiki\Extensions\OAuth\Backend\Utils;
use MediaWiki\MediaWikiServices;
use MWException;
use MWGrants;
use User;

class UserStatementProvider {
	/** @var Config */
	protected $config;
	/** @var User */
	protected $user;
	/** @var Consumer */
	protected $consumer;
	/** @var array */
	protected $grants;

	/**
	 * @param User $user
	 * @param Consumer $consumer
	 * @param array $grants
	 * @return static
	 */
	public static function factory( User $user, Consumer $consumer, $grants = [] ) {
		$mainConfig = MediaWikiServices::getInstance()->getMainConfig();
		return new static( $mainConfig, $user, $consumer, $grants );
	}

	/**
	 * UserStatementProvider constructor.
	 * @param Config $config
	 * @param User $user
	 * @param Consumer $consumer
	 * @param array $grants
	 */
	protected function __construct( $config, $user, $consumer, $grants ) {
		$this->config = $config;
		$this->user = $user;
		$this->consumer = $consumer;
		$this->grants = $grants;
	}

	/**
	 * Retrieve user statement suitable for JWT encoding
	 *
	 * @return array
	 * @throws MWException
	 */
	public function getUserStatement() {
		$statement = [];

		// Include some of the OpenID Connect attributes
		// http://openid.net/specs/openid-connect-core-1_0.html (draft 14)
		// Issuer Identifier for the Issuer of the response.
		$statement['iss'] = $this->config->get( 'CanonicalServer' );
		// Subject identifier. A locally unique and never reassigned identifier.
		// T264560: sub added via $this->getUserProfile()
		// Audience(s) that this ID Token is intended for.
		$statement['aud'] = $this->consumer->getConsumerKey();
		// Expiration time on or after which the ID Token MUST NOT be accepted for processing.
		$statement['exp'] = wfTimestamp() + 100;
		// Time at which the JWT was issued.
		$statement['iat'] = (int)wfTimestamp();
		// TODO: Add auth_time, if we start tracking last login timestamp

		$statement += $this->getUserProfile();

		return $statement;
	}

	/**
	 * Retrieve user profile information
	 *
	 * @return array
	 */
	public function getUserProfile() {
		$profile = [
			'sub' => Utils::getCentralIdFromLocalUser( $this->user ),
		];
		// Include some MediaWiki info about the user
		if ( !$this->user->isHidden() ) {
			$profile['username'] = $this->user->getName();
			$profile['editcount'] = intval( $this->user->getEditCount() );
			$profile['confirmed_email'] = $this->user->isEmailConfirmed();
			$profile['blocked'] = $this->user->getBlock() !== null;
			$profile['registered'] = $this->user->getRegistration();
			$profile['groups'] = $this->user->getEffectiveGroups();
			$profile['rights'] = array_values( array_unique(
				MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissions( $this->user )
			) );
			$profile['grants'] = $this->grants;

			if ( in_array( 'mwoauth-authonlyprivate', $this->grants ) ||
				in_array( 'viewmyprivateinfo', MWGrants::getGrantRights( $profile['grants'] ) )
			) {
				// Paranoia - avoid showing the real name if the wiki is not configured to use
				// it but it somehow exists (from past configuration, or some identity management
				// extension). This is important as the viewmyprivateinfo grant is presented
				// to the user differently when useRealNames() is false.
				// Don't omit the field completely to avoid a breaking change.
				$profile['realname'] = !in_array(
					'realname', $this->config->get( 'HiddenPrefs' ), true
				) ? $this->user->getRealName() : '';
				$profile['email'] = $this->user->getEmail();
			}
		} else {
			$profile['blocked'] = true;
		}

		return $profile;
	}
}