Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.59% covered (success)
92.59%
75 / 81
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccessToken
92.59% covered (success)
92.59%
75 / 81
80.00% covered (warning)
80.00%
4 / 5
8.03
0.00% covered (danger)
0.00%
0 / 1
 getSupportedRequestTypes
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 execute
62.50% covered (warning)
62.50%
10 / 16
0.00% covered (danger)
0.00%
0 / 1
4.84
 getBodyParamSettings
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
1 / 1
1
 getGrantType
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getGrantClass
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Extension\OAuth\Rest\Handler;
4
5use GuzzleHttp\Psr7\ServerRequest;
6use League\OAuth2\Server\Exception\OAuthServerException;
7use MediaWiki\Exception\MWExceptionHandler;
8use MediaWiki\Extension\OAuth\AuthorizationProvider\Grant\AuthorizationCodeAccessTokenProvider;
9use MediaWiki\Extension\OAuth\AuthorizationProvider\Grant\ClientCredentialsAccessTokenProvider;
10use MediaWiki\Extension\OAuth\AuthorizationProvider\Grant\RefreshTokenAccessTokenProvider;
11use MediaWiki\Extension\OAuth\Entity\ClientEntity;
12use MediaWiki\Extension\OAuth\Response;
13use Throwable;
14use Wikimedia\Message\MessageValue;
15use Wikimedia\ParamValidator\ParamValidator;
16
17/**
18 * Handles the oauth2/access_token endpoint, which can be used after the user has returned from
19 * the authorization dialog to trade the off the received authorization code for an access token.
20 */
21class AccessToken extends AuthenticationHandler {
22
23    /**
24     * Support x-www-form-urlencoded (and nothing else), as required by RFC 6749.
25     * @return string[]
26     */
27    public function getSupportedRequestTypes(): array {
28        return [
29            'application/x-www-form-urlencoded',
30        ];
31    }
32
33    /**
34     * @inheritDoc
35     */
36    public function execute() {
37        $response = new Response();
38
39        try {
40            if ( $this->queuedError ) {
41                throw $this->queuedError;
42            }
43            $request = ServerRequest::fromGlobals()->withParsedBody(
44                $this->getValidatedBody()
45            );
46
47            $authProvider = $this->getAuthorizationProvider();
48            return $authProvider->getAccessTokens( $request, $response );
49        } catch ( OAuthServerException $exception ) {
50            return $this->errorResponse( $exception, $response );
51        } catch ( Throwable $exception ) {
52            MWExceptionHandler::logException( $exception );
53            return $this->errorResponse(
54                OAuthServerException::serverError( $exception->getMessage(), $exception ),
55                $response
56            );
57        }
58    }
59
60    /**
61     * @inheritDoc
62     */
63    public function getBodyParamSettings(): array {
64        return [
65            'grant_type' => [
66                self::PARAM_SOURCE => 'body',
67                ParamValidator::PARAM_TYPE => [
68                    ClientEntity::GRANT_TYPE_CLIENT_CREDENTIALS,
69                    ClientEntity::GRANT_TYPE_AUTHORIZATION_CODE,
70                    ClientEntity::GRANT_TYPE_REFRESH_TOKEN,
71                ],
72                ParamValidator::PARAM_REQUIRED => true,
73                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-grant_type' ),
74            ],
75            'client_id' => [
76                self::PARAM_SOURCE => 'body',
77                ParamValidator::PARAM_TYPE => 'string',
78                ParamValidator::PARAM_REQUIRED => false,
79                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-client_id' ),
80            ],
81            'client_secret' => [
82                self::PARAM_SOURCE => 'body',
83                ParamValidator::PARAM_TYPE => 'string',
84                ParamValidator::PARAM_REQUIRED => false,
85                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-client_secret' ),
86            ],
87            'redirect_uri' => [
88                self::PARAM_SOURCE => 'body',
89                ParamValidator::PARAM_TYPE => 'string',
90                ParamValidator::PARAM_REQUIRED => false,
91                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-redirect_uri' ),
92            ],
93            'scope' => [
94                self::PARAM_SOURCE => 'body',
95                ParamValidator::PARAM_TYPE => 'string',
96                ParamValidator::PARAM_REQUIRED => false,
97                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-scope' ),
98            ],
99            'code' => [
100                self::PARAM_SOURCE => 'body',
101                ParamValidator::PARAM_TYPE => 'string',
102                ParamValidator::PARAM_REQUIRED => false,
103                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-code' ),
104            ],
105            'refresh_token' => [
106                self::PARAM_SOURCE => 'body',
107                ParamValidator::PARAM_TYPE => 'string',
108                ParamValidator::PARAM_REQUIRED => false,
109                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-refresh_token' ),
110            ],
111            'code_verifier' => [
112                self::PARAM_SOURCE => 'body',
113                ParamValidator::PARAM_TYPE => 'string',
114                ParamValidator::PARAM_REQUIRED => false,
115                self::PARAM_DESCRIPTION => new MessageValue( 'mwoauth-rest-param-desc-code_verifier' ),
116            ]
117        ];
118    }
119
120    /**
121     * @return string
122     */
123    protected function getGrantType() {
124        $body = $this->getValidatedBody();
125        '@phan-var array $body';
126        return $body['grant_type'];
127    }
128
129    /**
130     * @param string $grantType
131     * @return string|false
132     */
133    protected function getGrantClass( $grantType ) {
134        return match ( $grantType ) {
135            ClientEntity::GRANT_TYPE_AUTHORIZATION_CODE => AuthorizationCodeAccessTokenProvider::class,
136            ClientEntity::GRANT_TYPE_CLIENT_CREDENTIALS => ClientCredentialsAccessTokenProvider::class,
137            ClientEntity::GRANT_TYPE_REFRESH_TOKEN => RefreshTokenAccessTokenProvider::class,
138            default => false,
139        };
140    }
141}