Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
87.21% |
75 / 86 |
|
50.00% |
3 / 6 |
CRAP | |
0.00% |
0 / 1 |
OAuthUtil | |
87.21% |
75 / 86 |
|
50.00% |
3 / 6 |
30.76 | |
0.00% |
0 / 1 |
urlencode_rfc3986 | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
3 | |||
urldecode_rfc3986 | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
split_header | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
6 | |||
get_headers | |
62.50% |
15 / 24 |
|
0.00% |
0 / 1 |
9.58 | |||
parse_parameters | |
92.86% |
13 / 14 |
|
0.00% |
0 / 1 |
7.02 | |||
build_http_query | |
94.12% |
16 / 17 |
|
0.00% |
0 / 1 |
5.01 |
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\Logger\LoggerFactory; |
30 | |
31 | class OAuthUtil { |
32 | public static function urlencode_rfc3986( $input ) { |
33 | if ( is_array( $input ) ) { |
34 | return array_map( |
35 | array( |
36 | self::class, |
37 | 'urlencode_rfc3986' |
38 | ), |
39 | $input |
40 | ); |
41 | } else { |
42 | if ( is_scalar( $input ) ) { |
43 | return str_replace( |
44 | '+', |
45 | ' ', |
46 | str_replace( '%7E', '~', rawurlencode( $input ) ) |
47 | ); |
48 | } else { |
49 | return ''; |
50 | } |
51 | } |
52 | } |
53 | |
54 | |
55 | // This decode function isn't taking into consideration the above |
56 | // modifications to the encoding process. However, this method doesn't |
57 | // seem to be used anywhere so leaving it as is. |
58 | public static function urldecode_rfc3986( $string ) { |
59 | return urldecode( $string ); |
60 | } |
61 | |
62 | // Utility function for turning the Authorization: header into |
63 | // parameters, has to do some unescaping |
64 | // Can filter out any non-oauth parameters if needed ( default behaviour ) |
65 | // May 28th, 2010 - method updated to tjerk.meesters for a speed improvement. |
66 | // see http://code.google.com/p/oauth/issues/detail?id = 163 |
67 | public static function split_header( $header, $only_allow_oauth_parameters = true ) { |
68 | $logger = LoggerFactory::getInstance( 'OAuth' ); |
69 | $logger->debug( __METHOD__ . ": pulling headers from '$header'" ); |
70 | $params = array(); |
71 | if ( preg_match_all( |
72 | '/(' . ( $only_allow_oauth_parameters ? 'oauth_' : '' ) . '[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', |
73 | $header, |
74 | $matches |
75 | ) |
76 | ) { |
77 | foreach ( $matches[1] as $i => $h ) { |
78 | $params[$h] = OAuthUtil::urldecode_rfc3986( |
79 | empty( $matches[3][$i] ) ? $matches[4][$i] : $matches[3][$i] |
80 | ); |
81 | } |
82 | if ( isset( $params['realm'] ) ) { |
83 | unset( $params['realm'] ); |
84 | } |
85 | } |
86 | |
87 | return $params; |
88 | } |
89 | |
90 | // helper to try to sort out headers for people who aren't running apache |
91 | public static function get_headers() { |
92 | if ( function_exists( 'apache_request_headers' ) ) { |
93 | // we need this to get the actual Authorization: header |
94 | // because apache tends to tell us it doesn't exist |
95 | $headers = apache_request_headers(); |
96 | |
97 | // sanitize the output of apache_request_headers because |
98 | // we always want the keys to be Cased-Like-This and arh() |
99 | // returns the headers in the same case as they are in the |
100 | // request |
101 | $out = array(); |
102 | foreach ( $headers as $key => $value ) { |
103 | $key = str_replace( |
104 | " ", |
105 | "-", |
106 | ucwords( strtolower( str_replace( "-", " ", $key ) ) ) |
107 | ); |
108 | $out[$key] = $value; |
109 | } |
110 | } else { |
111 | // otherwise we don't have apache and are just going to have to hope |
112 | // that $_SERVER actually contains what we need |
113 | $out = array(); |
114 | if ( isset( $_SERVER['CONTENT_TYPE'] ) ) { |
115 | $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; |
116 | } |
117 | if ( isset( $_ENV['CONTENT_TYPE'] ) ) { |
118 | $out['Content-Type'] = $_ENV['CONTENT_TYPE']; |
119 | } |
120 | |
121 | foreach ( $_SERVER as $key => $value ) { |
122 | if ( substr( $key, 0, 5 ) == "HTTP_" ) { |
123 | // this is chaos, basically it is just there to capitalize the first |
124 | // letter of every word that is not an initial HTTP and strip HTTP |
125 | // code from przemek |
126 | $key = str_replace( |
127 | " ", |
128 | "-", |
129 | ucwords( strtolower( str_replace( "_", " ", substr( $key, 5 ) ) ) ) |
130 | ); |
131 | $out[$key] = $value; |
132 | } |
133 | } |
134 | } |
135 | |
136 | return $out; |
137 | } |
138 | |
139 | // This function takes a input like a=b&a=c&d=e and returns the parsed |
140 | // parameters like this |
141 | // array( 'a' => array( 'b','c' ), 'd' => 'e' ) |
142 | public static function parse_parameters( $input ) { |
143 | if ( !isset( $input ) || !$input ) { |
144 | return array(); |
145 | } |
146 | |
147 | $pairs = explode( '&', $input ); |
148 | |
149 | $parsed_parameters = array(); |
150 | foreach ( $pairs as $pair ) { |
151 | $split = explode( '=', $pair, 2 ); |
152 | $parameter = OAuthUtil::urldecode_rfc3986( $split[0] ); |
153 | $value = isset( $split[1] ) ? OAuthUtil::urldecode_rfc3986( $split[1] ) : ''; |
154 | |
155 | if ( isset( $parsed_parameters[$parameter] ) ) { |
156 | // We have already recieved parameter( s ) with this name, so add to the list |
157 | // of parameters with this name |
158 | |
159 | if ( is_scalar( $parsed_parameters[$parameter] ) ) { |
160 | // This is the first duplicate, so transform scalar ( string ) into an array |
161 | // so we can add the duplicates |
162 | $parsed_parameters[$parameter] = array( $parsed_parameters[$parameter] ); |
163 | } |
164 | |
165 | $parsed_parameters[$parameter][] = $value; |
166 | } else { |
167 | $parsed_parameters[$parameter] = $value; |
168 | } |
169 | } |
170 | |
171 | return $parsed_parameters; |
172 | } |
173 | |
174 | public static function build_http_query( $params ) { |
175 | LoggerFactory::getInstance( 'OAuth' )->debug( |
176 | __METHOD__ . " called with params:\n" . print_r( $params, true ) |
177 | ); |
178 | if ( !$params ) { |
179 | return ''; |
180 | } |
181 | |
182 | // Urlencode both keys and values |
183 | $keys = OAuthUtil::urlencode_rfc3986( array_keys( $params ) ); |
184 | $values = OAuthUtil::urlencode_rfc3986( array_values( $params ) ); |
185 | $params = array_combine( $keys, $values ); |
186 | |
187 | // Parameters are sorted by name, using lexicographical byte value ordering. |
188 | // Ref: Spec: 9.1.1 ( 1 ) |
189 | uksort( $params, 'strcmp' ); |
190 | |
191 | $pairs = array(); |
192 | foreach ( $params as $parameter => $value ) { |
193 | if ( is_array( $value ) ) { |
194 | // If two or more parameters share the same name, they are sorted by their value |
195 | // Ref: Spec: 9.1.1 ( 1 ) |
196 | // June 12th, 2010 - changed to sort because of issue 164 by hidetaka |
197 | sort( $value, SORT_STRING ); |
198 | foreach ( $value as $duplicate_value ) { |
199 | $pairs[] = $parameter . '=' . $duplicate_value; |
200 | } |
201 | } else { |
202 | $pairs[] = $parameter . '=' . $value; |
203 | } |
204 | } |
205 | // For each parameter, the name is separated from the corresponding value by an ' = ' character ( ASCII code 61 ) |
206 | // Each name-value pair is separated by an '&' character ( ASCII code 38 ) |
207 | return implode( '&', $pairs ); |
208 | } |
209 | } |