17 if (!defined(
"PSF_ENTRY_POINT"))
18 die(
"Not a valid psf entry point");
20 define(
"OAUTH_OK", 0);
21 define(
"OAUTH_NOT_AUTH", 2);
25 public $ConsumerKey = null;
26 public $UserAgent =
"psf";
27 public $AuthURL = null;
28 public $TokenSecret = null;
30 public $TokenKey = null;
31 public $ConsumerSecret = null;
33 public function __construct($url)
37 if (isset( $_SESSION[
'tokenKey']))
39 $o->TokenKey = $_SESSION[
'tokenKey'];
40 $o->TokenSecret = $_SESSION[
'tokenSecret'];
42 session_write_close();
45 private function SignRequest($method, $url, $params = array())
47 $parts = parse_url( $url );
50 $scheme = isset( $parts[
'scheme'] ) ? $parts[
'scheme'] :
'http';
51 $host = isset( $parts[
'host'] ) ? $parts[
'host'] :
'';
52 $port = isset( $parts[
'port'] ) ? $parts[
'port'] : ( $scheme ==
'https' ?
'443' :
'80' );
53 $path = isset( $parts[
'path'] ) ? $parts[
'path'] :
'';
54 if (( $scheme ==
'https' && $port !=
'443' ) ||
55 ( $scheme ==
'http' && $port !=
'80' ))
58 $host =
"$host:$port";
63 parse_str( isset( $parts[
'query'] ) ? $parts[
'query'] :
'', $query );
65 unset( $query[
'oauth_signature'] );
68 $query = array_combine(
70 array_map(
'rawurlencode', array_keys( $query ) ),
71 array_map(
'rawurlencode', array_values( $query ) )
73 ksort( $query, SORT_STRING );
74 foreach ( $query as $k => $v ) {
79 $toSign = rawurlencode( strtoupper( $method ) ) .
'&' .
80 rawurlencode(
"$scheme://$host$path" ) .
'&' .
81 rawurlencode( join(
'&', $pairs ) );
82 $key = rawurlencode( $this->ConsumerSecret ) .
'&' . rawurlencode( $this->TokenSecret );
83 return base64_encode( hash_hmac(
'sha1', $toSign, $key,
true ) );
86 public function ProcessToken()
88 $url = $this->URL .
'/token';
89 $url .= strpos( $url,
'?' ) ?
'&' :
'?';
90 $url .= http_build_query(array(
92 'oauth_verifier' => $_GET[
'oauth_verifier'],
95 'oauth_consumer_key' => $this->ConsumerKey,
96 'oauth_token' => $this->TokenKey,
97 'oauth_version' =>
'1.0',
98 'oauth_nonce' => md5( microtime() . mt_rand() ),
99 'oauth_timestamp' => time(),
102 'oauth_signature_method' =>
'HMAC-SHA1',
104 $signature = $this->SignRequest(
'GET', $url );
105 $url .=
"&oauth_signature=" . urlencode( $signature );
107 curl_setopt( $ch, CURLOPT_URL, $url );
109 curl_setopt( $ch, CURLOPT_USERAGENT, $this->UserAgent );
110 curl_setopt( $ch, CURLOPT_HEADER, 0 );
111 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
112 $data = curl_exec( $ch );
114 header(
"HTTP/1.1 500 Internal Server Error" );
115 echo
'Curl error: ' . htmlspecialchars( curl_error( $ch ) );
119 $token = json_decode( $data );
120 if ( is_object( $token ) && isset( $token->error ) ) {
121 header(
"HTTP/1.1 500 Internal Server Error" );
122 echo
'Error retrieving token: ' . htmlspecialchars( $token->error );
125 if ( !is_object( $token ) || !isset( $token->key ) || !isset( $token->secret ) ) {
126 header(
"HTTP/1.1 $errorCode Internal Server Error" );
127 echo
'Invalid response from token request';
133 $_SESSION[
'tokenKey'] = $this->TokenKey = $token->key;
134 $_SESSION[
'tokenSecret'] = $this->TokenSecret = $token->secret;
135 session_write_close();
138 public function AuthorizationRedirect()
140 $this->TokenSecret =
'';
141 $url = $this->URL .
'/initiate';
142 $url .= strpos( $url,
'?' ) ?
'&' :
'?';
143 $url .= http_build_query( array(
146 'oauth_callback' =>
'oob',
147 'oauth_consumer_key' => $this->ConsumerKey,
148 'oauth_version' =>
'1.0',
149 'oauth_nonce' => md5( microtime() . mt_rand() ),
150 'oauth_timestamp' => time(),
152 'oauth_signature_method' =>
'HMAC-SHA1',
154 $signature = $this->SignRequest(
'GET', $url );
155 $url .=
"&oauth_signature=" . urlencode( $signature );
157 curl_setopt( $ch, CURLOPT_URL, $url );
158 SystemLog::Write($url);
159 curl_setopt( $ch, CURLOPT_USERAGENT, $this->UserAgent );
160 curl_setopt( $ch, CURLOPT_HEADER, 0 );
161 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
162 $data = curl_exec( $ch );
164 header(
"HTTP/1.1 $errorCode Internal Server Error" );
165 echo
'Curl error: ' . htmlspecialchars( curl_error( $ch ) );
170 $token = json_decode( $data );
171 if ( is_object( $token ) && isset( $token->error ) ) {
172 header(
"HTTP/1.1 $errorCode Internal Server Error" );
173 echo
'Error retrieving token: ' . htmlspecialchars( $token->error );
176 if ( !is_object( $token ) || !isset( $token->key ) || !isset( $token->secret ) ) {
177 header(
"HTTP/1.1 $errorCode Internal Server Error" );
178 echo
'Invalid response from token request';
184 $_SESSION[
'tokenKey'] = $token->key;
185 $_SESSION[
'tokenSecret'] = $token->secret;
186 session_write_close();
189 $url = $this->AuthURL;
190 $url .= strpos( $url,
'?' ) ?
'&' :
'?';
191 $url .= http_build_query( array(
192 'oauth_token' => $token->key,
193 'oauth_consumer_key' => $this->ConsumerKey,
195 header(
"Location: $url" );
196 echo
'Please see <a href="' . htmlspecialchars( $url ) .
'">' . htmlspecialchars( $url ) .
'</a>';
200 public function fetchAccessToken() {
201 $url = $this->OAuth_URL .
'/token';
202 $url .= strpos( $url,
'?' ) ?
'&' :
'?';
203 $url .= http_build_query( array(
205 'oauth_verifier' => $_GET[
'oauth_verifier'],
208 'oauth_consumer_key' => $gConsumerKey,
209 'oauth_token' => $gTokenKey,
210 'oauth_version' =>
'1.0',
211 'oauth_nonce' => md5( microtime() . mt_rand() ),
212 'oauth_timestamp' => time(),
215 'oauth_signature_method' =>
'HMAC-SHA1',
217 $signature = $this->SignRequest(
'GET', $url );
218 $url .=
"&oauth_signature=" . urlencode( $signature );
220 curl_setopt( $ch, CURLOPT_URL, $url );
222 curl_setopt( $ch, CURLOPT_USERAGENT, $gUserAgent );
223 curl_setopt( $ch, CURLOPT_HEADER, 0 );
224 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
225 $data = curl_exec( $ch );
228 header(
"HTTP/1.1 500 Internal Server Error" );
229 echo
'Curl error: ' . htmlspecialchars( curl_error( $ch ) );
232 $token = json_decode( $data );
233 if (is_object( $token ) && isset( $token->error ))
235 header(
"HTTP/1.1 500 Internal Server Error" );
236 throw new Exception(
'Error retrieving token: ' . htmlspecialchars( $token->error ));
238 if ( !is_object( $token ) || !isset( $token->key ) || !isset( $token->secret)) {
239 header(
"HTTP/1.1 500 Internal Server Error" );
240 throw new Exception(
'Invalid response from token request');
245 $_SESSION[
'tokenKey'] = $gTokenKey = $token->key;
246 $_SESSION[
'tokenSecret'] = $gTokenSecret = $token->secret;
247 session_write_close();
250 public function Identify()
252 $url = $this->URL .
'/identify';
255 'oauth_consumer_key' => $this->ConsumerKey,
256 'oauth_token' => $this->TokenKey,
257 'oauth_version' =>
'1.0',
258 'oauth_nonce' => md5( microtime() . mt_rand() ),
259 'oauth_timestamp' => time(),
262 'oauth_signature_method' =>
'HMAC-SHA1',
264 $signature = $this->SignRequest(
'GET', $url, $headerArr );
265 $headerArr[
'oauth_signature'] = $signature;
268 foreach ( $headerArr as $k => $v )
270 $header[] = rawurlencode( $k ) .
'="' . rawurlencode( $v ) .
'"';
272 $header =
'Authorization: OAuth ' . join(
', ', $header );
275 curl_setopt( $ch, CURLOPT_URL, $url );
276 curl_setopt( $ch, CURLOPT_HTTPHEADER, array( $header ) );
277 curl_setopt( $ch, CURLOPT_USERAGENT, $gUserAgent );
278 curl_setopt( $ch, CURLOPT_HEADER, 0 );
279 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
280 $data = curl_exec( $ch );
282 header(
"HTTP/1.1 $errorCode Internal Server Error" );
283 throw new Exception(
'Curl error: ' . htmlspecialchars( curl_error( $ch )));
285 $err = json_decode( $data );
286 if ( is_object( $err ) && isset( $err->error ) && $err->error ===
'mwoauthdatastore-access-token-not-found' ) {
288 return OAUTH_NOT_AUTH;
292 $fields = explode(
'.', $data );
293 if ( count( $fields ) !== 3 )
295 header(
"HTTP/1.1 $errorCode Internal Server Error" );
296 throw new Exception(
'Invalid identify response: ' . htmlspecialchars( $data ));
300 $header = base64_decode( strtr( $fields[0],
'-_',
'+/' ),
true );
301 if ( $header !==
false )
303 $header = json_decode( $header );
305 if ( !is_object( $header ) || $header->typ !==
'JWT' || $header->alg !==
'HS256' )
307 header(
"HTTP/1.1 $errorCode Internal Server Error" );
308 throw new Exception(
'Invalid header in identify response: ' . htmlspecialchars( $data ));
312 $sig = base64_decode( strtr( $fields[2],
'-_',
'+/' ),
true );
313 $check = hash_hmac(
'sha256', $fields[0] .
'.' . $fields[1], $gConsumerSecret,
true );
314 if ( $sig !== $check )
316 header(
"HTTP/1.1 $errorCode Internal Server Error" );
317 throw new Exception(
'JWT signature validation failed: ' . htmlspecialchars( $data ) . var_dump( base64_encode($sig), base64_encode($check) ));
321 $payload = base64_decode( strtr( $fields[1],
'-_',
'+/' ),
true );
322 if ( $payload !==
false )
324 $payload = json_decode( $payload );
326 if ( !is_object( $payload ) )
328 header(
"HTTP/1.1 $errorCode Internal Server Error" );
329 throw new Exception(
'Invalid payload in identify response: ' . htmlspecialchars( $data ));
331 SystemLog::Write(
'JWT payload: <pre>' . htmlspecialchars( var_export( $payload, 1 ) ) .
'</pre>');
336 function OAuthFromIniFile($file)
338 $r = parse_ini_file($file);
340 throw new Exception(
"Unable to read: " . $file);
342 $o =
new OAuth($r[
"url"]);
343 $o->ConsumerSecret = $r[
"consumerSecret"];
344 $o->ConsumerKey = $r[
"consumerKey"];