summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'OAuth/src/Entity/ClientEntity.php')
-rw-r--r--OAuth/src/Entity/ClientEntity.php191
1 files changed, 191 insertions, 0 deletions
diff --git a/OAuth/src/Entity/ClientEntity.php b/OAuth/src/Entity/ClientEntity.php
new file mode 100644
index 00000000..0def1470
--- /dev/null
+++ b/OAuth/src/Entity/ClientEntity.php
@@ -0,0 +1,191 @@
+<?php
+
+namespace MediaWiki\Extensions\OAuth\Entity;
+
+use Exception;
+use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
+use League\OAuth2\Server\Entities\ClientEntityInterface;
+use League\OAuth2\Server\Entities\ScopeEntityInterface;
+use League\OAuth2\Server\Exception\OAuthServerException;
+use MediaWiki\Extensions\OAuth\Backend\Consumer;
+use MediaWiki\Extensions\OAuth\Backend\ConsumerAcceptance;
+use MediaWiki\Extensions\OAuth\Backend\MWOAuthException;
+use MediaWiki\Extensions\OAuth\Backend\Utils;
+use MediaWiki\Extensions\OAuth\Repository\AccessTokenRepository;
+use MWException;
+use User;
+
+class ClientEntity extends Consumer implements ClientEntityInterface {
+
+ /**
+ * Returns the registered redirect URI (as a string).
+ *
+ * Alternatively return an indexed array of redirect URIs.
+ *
+ * @return string|string[]
+ */
+ public function getRedirectUri() {
+ return $this->getCallbackUrl();
+ }
+
+ /**
+ * Returns true if the client is confidential.
+ *
+ * @return bool
+ */
+ public function isConfidential() {
+ return $this->oauth2IsConfidential;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIdentifier() {
+ return $this->getConsumerKey();
+ }
+
+ /**
+ * @param mixed $identifier
+ */
+ public function setIdentifier( $identifier ) {
+ $this->consumerKey = $identifier;
+ }
+
+ /**
+ * Get the grant types this client is allowed to use
+ *
+ * @return array
+ */
+ public function getAllowedGrants() {
+ return $this->oauth2GrantTypes;
+ }
+
+ /**
+ * Convenience function, same as getGrants()
+ * it just returns array of ScopeEntity-es instead of strings
+ *
+ * @return ScopeEntityInterface[]
+ */
+ public function getScopes() {
+ $scopeEntities = [];
+ foreach ( $this->getGrants() as $grant ) {
+ $scopeEntities[] = new ScopeEntity( $grant );
+ }
+
+ return $scopeEntities;
+ }
+
+ /**
+ * @return bool|User
+ * @throws MWException
+ */
+ public function getUser() {
+ return Utils::getLocalUserFromCentralId( $this->getUserId() );
+ }
+
+ /**
+ * @param null|string $secret
+ * @param null|string $grantType
+ * @return bool
+ */
+ public function validate( $secret, $grantType ) {
+ if ( !$this->isSecretValid( $secret ) ) {
+ return false;
+ }
+
+ if ( !$this->isGrantAllowed( $grantType ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return int
+ */
+ public function getOAuthVersion() {
+ return static::OAUTH_VERSION_2;
+ }
+
+ private function isSecretValid( $secret ) {
+ return hash_equals( $secret, Utils::hmacDBSecret( $this->secretKey ) );
+ }
+
+ /**
+ * @param string $grantType
+ * @return bool
+ */
+ public function isGrantAllowed( $grantType ) {
+ return in_array( $grantType, $this->getAllowedGrants() );
+ }
+
+ /**
+ * @param User $mwUser
+ * @param bool $update
+ * @param array $grants
+ * @param null $requestTokenKey
+ * @return bool
+ * @throws MWException
+ * @throws MWOAuthException
+ */
+ public function authorize( User $mwUser, $update, $grants, $requestTokenKey = null ) {
+ $this->conductAuthorizationChecks( $mwUser );
+
+ $grants = $this->getVerifiedScopes( $grants );
+ $this->saveAuthorization( $mwUser, $update, $grants );
+
+ return true;
+ }
+
+ /**
+ * Get the access token to be used with a single user
+ * Should never be called outside of client registration/manage code
+ *
+ * @param ConsumerAcceptance $approval
+ * @param bool $revokeExisting - Delete all existing tokens
+ *
+ * @return AccessTokenEntityInterface
+ * @throws MWOAuthException
+ * @throws OAuthServerException
+ * @throws Exception
+ */
+ public function getOwnerOnlyAccessToken(
+ ConsumerAcceptance $approval, $revokeExisting = false
+ ) {
+ if (
+ count( $this->getAllowedGrants() ) !== 1 ||
+ $this->getAllowedGrants()[0] !== 'client_credentials'
+ ) {
+ // sanity - make sure client is allowed *only* client_credentials grant,
+ // so that this AT cannot be used in other grant type requests
+ throw new MWOAuthException( 'mwoauth-oauth2-error-owner-only-invalid-grant' );
+ }
+ $accessToken = null;
+ $accessTokenRepo = new AccessTokenRepository();
+ if ( $revokeExisting ) {
+ $accessTokenRepo->deleteForApprovalId( $approval->getId() );
+ }
+ /** @var AccessTokenEntity $accessToken */
+ $accessToken = $accessTokenRepo->getNewToken( $this, $this->getScopes(), $approval->getUserId() );
+ '@phan-var AccessTokenEntity $accessToken';
+ $accessToken->setExpiryDateTime( ( new \DateTimeImmutable() )->add(
+ new \DateInterval( 'P292277000000Y' )
+ ) );
+ $accessToken->setPrivateKeyFromConfig();
+ $accessToken->setIdentifier( bin2hex( random_bytes( 40 ) ) );
+
+ $accessTokenRepo->persistNewAccessToken( $accessToken );
+
+ return $accessToken;
+ }
+
+ /**
+ * Filter out scopes that application cannot use
+ *
+ * @param array $requested
+ * @return array
+ */
+ private function getVerifiedScopes( $requested ) {
+ return array_intersect( $requested, $this->getGrants() );
+ }
+}