Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
105 / 105 |
|
100.00% |
19 / 19 |
CRAP | |
100.00% |
1 / 1 |
OAuthRequest | |
100.00% |
105 / 105 |
|
100.00% |
19 / 19 |
52 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
from_request | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
11 | |||
from_consumer_and_token | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
set_parameter | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
4 | |||
get_parameter | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
get_parameters | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
unset_parameter | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get_signable_parameters | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
get_signature_base_string | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
get_normalized_http_method | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get_normalized_http_url | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
10 | |||
to_url | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
to_postdata | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
to_header | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
6 | |||
__toString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
sign_request | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
build_signature | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
generate_timestamp | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
generate_nonce | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | // vim: foldmethod=marker |
3 | /** |
4 | * The MIT License |
5 | * |
6 | * Copyright (c) 2007 Andy Smith |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files ( the "Software" ), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | namespace MediaWiki\Extension\OAuth\Lib; |
28 | |
29 | use MediaWiki\Extension\OAuth\Lib\OAuthException; |
30 | use MediaWiki\Extension\OAuth\Lib\OAuthUtil; |
31 | use MediaWiki\Logger\LoggerFactory; |
32 | use Psr\Log\LoggerInterface; |
33 | |
34 | class OAuthRequest { |
35 | protected $parameters; |
36 | protected $http_method; |
37 | protected $http_url; |
38 | // for debug purposes |
39 | public $base_string; |
40 | public static $version = '1.0'; |
41 | public static $POST_INPUT = 'php://input'; |
42 | |
43 | /** @var LoggerInterface */ |
44 | protected $logger; |
45 | |
46 | function __construct( $http_method, $http_url, $parameters = null ) { |
47 | $parameters = ( $parameters ) ? $parameters : array(); |
48 | $parameters = array_merge( |
49 | OAuthUtil::parse_parameters( parse_url( $http_url, PHP_URL_QUERY ) ), |
50 | $parameters |
51 | ); |
52 | $this->parameters = $parameters; |
53 | $this->http_method = $http_method; |
54 | $this->http_url = $http_url; |
55 | $this->logger = LoggerFactory::getInstance( 'OAuth' ); |
56 | } |
57 | |
58 | /** |
59 | * attempt to build up a request from what was passed to the server |
60 | */ |
61 | public static function from_request( $http_method = null, $http_url = null, $parameters = null ) { |
62 | $scheme = ( !isset( $_SERVER['HTTPS'] ) || $_SERVER['HTTPS'] != "on" ) ? 'http' : 'https'; |
63 | $http_url = ( $http_url ) ? $http_url : $scheme . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; |
64 | $http_method = ( $http_method ) ? $http_method : $_SERVER['REQUEST_METHOD']; |
65 | |
66 | // We weren't handed any parameters, so let's find the ones relevant to |
67 | // this request. |
68 | // If you run XML-RPC or similar you should use this to provide your own |
69 | // parsed parameter-list |
70 | if ( !$parameters ) { |
71 | // Find request headers |
72 | $request_headers = OAuthUtil::get_headers(); |
73 | |
74 | // Parse the query-string to find GET parameters |
75 | $parameters = OAuthUtil::parse_parameters( $_SERVER['QUERY_STRING'] ); |
76 | |
77 | // It's a POST request of the proper content-type, so parse POST |
78 | // parameters and add those overriding any duplicates from GET |
79 | if ( $http_method == "POST" && isset( $request_headers['Content-Type'] ) && strstr( |
80 | $request_headers['Content-Type'], |
81 | 'application/x-www-form-urlencoded' |
82 | ) |
83 | ) { |
84 | $post_data = OAuthUtil::parse_parameters( file_get_contents( self::$POST_INPUT ) ); |
85 | $parameters = array_merge( $parameters, $post_data ); |
86 | } |
87 | |
88 | // We have a Authorization-header with OAuth data. Parse the header |
89 | // and add those overriding any duplicates from GET or POST |
90 | if ( isset( $request_headers['Authorization'] ) && substr( |
91 | $request_headers['Authorization'], |
92 | 0, |
93 | 6 |
94 | ) == 'OAuth ' |
95 | ) { |
96 | $header_parameters = OAuthUtil::split_header( $request_headers['Authorization'] ); |
97 | $parameters = array_merge( $parameters, $header_parameters ); |
98 | } |
99 | } |
100 | |
101 | return new OAuthRequest( $http_method, $http_url, $parameters ); |
102 | } |
103 | |
104 | /** |
105 | * pretty much a helper function to set up the request |
106 | */ |
107 | public static function from_consumer_and_token( $consumer, $token, $http_method, $http_url, $parameters = null ) { |
108 | $parameters = ( $parameters ) ? $parameters : array(); |
109 | $defaults = array( |
110 | "oauth_version" => OAuthRequest::$version, |
111 | "oauth_nonce" => OAuthRequest::generate_nonce(), |
112 | "oauth_timestamp" => OAuthRequest::generate_timestamp(), |
113 | "oauth_consumer_key" => $consumer->key |
114 | ); |
115 | if ( $token ) { |
116 | $defaults['oauth_token'] = $token->key; |
117 | } |
118 | |
119 | $parameters = array_merge( $defaults, $parameters ); |
120 | |
121 | return new OAuthRequest( $http_method, $http_url, $parameters ); |
122 | } |
123 | |
124 | public function set_parameter( $name, $value, $allow_duplicates = true ) { |
125 | if ( $allow_duplicates && isset( $this->parameters[$name] ) ) { |
126 | // We have already added parameter( s ) with this name, so add to the list |
127 | if ( is_scalar( $this->parameters[$name] ) ) { |
128 | // This is the first duplicate, so transform scalar ( string ) |
129 | // into an array so we can add the duplicates |
130 | $this->parameters[$name] = array( $this->parameters[$name] ); |
131 | } |
132 | |
133 | $this->parameters[$name][] = $value; |
134 | } else { |
135 | $this->parameters[$name] = $value; |
136 | } |
137 | } |
138 | |
139 | public function get_parameter( $name ) { |
140 | return isset( $this->parameters[$name] ) ? $this->parameters[$name] : null; |
141 | } |
142 | |
143 | public function get_parameters() { |
144 | return $this->parameters; |
145 | } |
146 | |
147 | public function unset_parameter( $name ) { |
148 | unset( $this->parameters[$name] ); |
149 | } |
150 | |
151 | /** |
152 | * The request parameters, sorted and concatenated into a normalized string. |
153 | * @return string |
154 | */ |
155 | public function get_signable_parameters() { |
156 | // Grab all parameters |
157 | $params = $this->parameters; |
158 | |
159 | // Remove oauth_signature if present |
160 | // Ref: Spec: 9.1.1 ( "The oauth_signature parameter MUST be excluded." ) |
161 | if ( isset( $params['oauth_signature'] ) ) { |
162 | unset( $params['oauth_signature'] ); |
163 | } |
164 | |
165 | return OAuthUtil::build_http_query( $params ); |
166 | } |
167 | |
168 | /** |
169 | * Returns the base string of this request |
170 | * |
171 | * The base string defined as the method, the url |
172 | * and the parameters ( normalized ), each urlencoded |
173 | * and the concated with &. |
174 | */ |
175 | public function get_signature_base_string() { |
176 | $parts = array( |
177 | $this->get_normalized_http_method(), |
178 | $this->get_normalized_http_url(), |
179 | $this->get_signable_parameters() |
180 | ); |
181 | |
182 | $parts = OAuthUtil::urlencode_rfc3986( $parts ); |
183 | |
184 | return implode( '&', $parts ); |
185 | } |
186 | |
187 | /** |
188 | * just uppercases the http method |
189 | */ |
190 | public function get_normalized_http_method() { |
191 | return strtoupper( $this->http_method ); |
192 | } |
193 | |
194 | /** |
195 | * parses the url and rebuilds it to be |
196 | * scheme://host/path |
197 | */ |
198 | public function get_normalized_http_url() { |
199 | $parts = parse_url( $this->http_url ); |
200 | |
201 | $scheme = ( isset( $parts['scheme'] ) ) ? $parts['scheme'] : 'http'; |
202 | $port = ( isset( $parts['port'] ) ) ? $parts['port'] : ( ( $scheme == 'https' ) ? '443' : '80' ); |
203 | $host = ( isset( $parts['host'] ) ) ? strtolower( $parts['host'] ) : ''; |
204 | $path = ( isset( $parts['path'] ) ) ? $parts['path'] : ''; |
205 | |
206 | if ( ( $scheme == 'https' && $port != '443' ) || ( $scheme == 'http' && $port != '80' ) ) { |
207 | $host = "$host:$port"; |
208 | } |
209 | |
210 | return "$scheme://$host$path"; |
211 | } |
212 | |
213 | /** |
214 | * builds a url usable for a GET request |
215 | */ |
216 | public function to_url() { |
217 | $post_data = $this->to_postdata(); |
218 | $out = $this->get_normalized_http_url(); |
219 | if ( $post_data ) { |
220 | $out .= '?' . $post_data; |
221 | } |
222 | |
223 | return $out; |
224 | } |
225 | |
226 | /** |
227 | * builds the data one would send in a POST request |
228 | */ |
229 | public function to_postdata() { |
230 | return OAuthUtil::build_http_query( $this->parameters ); |
231 | } |
232 | |
233 | /** |
234 | * builds the Authorization: header |
235 | */ |
236 | public function to_header( $realm = null ) { |
237 | $first = true; |
238 | if ( $realm ) { |
239 | $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986( $realm ) . '"'; |
240 | $first = false; |
241 | } else { |
242 | $out = 'Authorization: OAuth'; |
243 | } |
244 | $total = array(); |
245 | foreach ( $this->parameters as $k => $v ) { |
246 | if ( substr( $k, 0, 5 ) != "oauth" ) { |
247 | continue; |
248 | } |
249 | if ( is_array( $v ) ) { |
250 | throw new OAuthException( 'Arrays not supported in headers' ); |
251 | } |
252 | $out .= ( $first ) ? ' ' : ','; |
253 | $out .= OAuthUtil::urlencode_rfc3986( $k ) . '="' . OAuthUtil::urlencode_rfc3986( |
254 | $v |
255 | ) . '"'; |
256 | $first = false; |
257 | } |
258 | |
259 | return $out; |
260 | } |
261 | |
262 | public function __toString() { |
263 | return $this->to_url(); |
264 | } |
265 | |
266 | public function sign_request( $signature_method, $consumer, $token ) { |
267 | $this->set_parameter( |
268 | "oauth_signature_method", |
269 | $signature_method->get_name(), |
270 | false |
271 | ); |
272 | $signature = $this->build_signature( $signature_method, $consumer, $token ); |
273 | $this->set_parameter( "oauth_signature", $signature, false ); |
274 | } |
275 | |
276 | public function build_signature( $signature_method, $consumer, $token ) { |
277 | $signature = $signature_method->build_signature( $this, $consumer, $token ); |
278 | |
279 | return $signature; |
280 | } |
281 | |
282 | /** |
283 | * util function: current timestamp |
284 | */ |
285 | private static function generate_timestamp() { |
286 | return time(); |
287 | } |
288 | |
289 | /** |
290 | * util function: current nonce |
291 | */ |
292 | private static function generate_nonce() { |
293 | $mt = microtime(); |
294 | $rand = mt_rand(); |
295 | |
296 | return md5( $mt . $rand ); // md5s look nicer than numbers |
297 | } |
298 | } |