/[drupal]/contributions/modules/yahoo_bbauth/ybrowserauth.class.php5
ViewVC logotype

Contents of /contributions/modules/yahoo_bbauth/ybrowserauth.class.php5

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Fri Oct 20 22:49:11 2006 UTC (3 years, 1 month ago) by slimandslam
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.1: +2 -3 lines
File MIME type: text/x-php
Got rid of extraneous line feeds and commented out error_reporting statements
1 <?php
2 // ybrowserauth.class.php5 -- a PHP5 class for using Yahoo's browser
3 // authentication service
4 //
5 // Author: Jason Levitt
6 // October 6th, 2006 Version 1.01
7 // Credits: Based on code by Allen Tom with additions by Dan Theurer and Zack Steinkamp
8 // Requirements: PHP5. The Curl extension is required.
9 //
10 // Constructor usage:
11 // $yourappid = 'asdafasdfadfadfa';
12 // $yoursecret = 'asd1234125dfasdfasdfas';
13 // $authObj = new YBrowserAuth($yourappid, $yoursecret);
14 //
15 // Create an authentication link:
16 // <a href="< ? php echo $authObj->getAuthURL(null,true); ? >">Authorize Access To My Photos</a>
17 //
18 // After the user authenticates successfully, Yahoo returns the user to the page you
19 // dictated when you signed up. To verify whether authentication succeeded, you need to
20 // validate the signature:
21 // if ($authObj->validate_sig()) {
22 // echo 'Authentication Successful';
23 // } else {
24 // echo "Authentication Failed. Error is: $authObj->sig_validation_error";
25 // }
26 //
27 // The user hash will be in $authObj->userhash after validation succeeds if you
28 // passed hash=true in the getAuthURL call.
29 //
30 // Create an authenticated web service URL for calling a web service. Do this if you want to
31 // make the web service call yourself. Otherwise, use makeAuthWSgetCall below.
32 // $url = 'http://photos.yahooapis.com/V1.0/listAlbums?';
33 // $url = $this->createAuthWSurl($url);
34 // if ($url === false) {
35 // echo 'Failed to create authenticated url. Error is: $authObj->access_credentials_error';
36 // } else {
37 // echo 'Use this url, and send along the $this->cookie value in an HTTP cookie header,
38 // in order to make an authenticated WS call: '. $url;
39 // }
40 //
41 // Make an authenticated HTTP GET web service call
42 // $url = 'http://photos.yahooapis.com/V1.0/listAlbums?';
43 // $xml=$authObj->makeAuthWSgetCall($url);
44 // if ($xml == false) {
45 // echo 'WS call setup Failed. Error is: '. $authObj->access_credentials_error;
46 // } else {
47 // echo 'Look at response for other errors or success: '.$xml;
48 // }
49 //
50 // For short-term authentication, you can store the cookie value, the appid, the
51 // WSSID value, and the timeout value somewhere and keep doing authenticated web
52 // service calls until the cookie timeout value is reached (typically 1 hour) like this:
53 // $authObj->cookie = $storedcookie;
54 // $authObj->WSSID = $storedWSSID;
55 // $authObj->appid = $storedappid;
56 // $url = 'http://photos.yahooapis.com/V1.0/listAlbums?';
57 // $xml=$authObj->makeAuthWSgetCall($url);
58 // if ($xml == false) {
59 // echo 'WS call setup Failed. Error is: '.$authObj->access_credentials_error;
60 // } else {
61 // echo 'Look at response for other errors or success: '.$xml;
62 // }
63 //
64 // For long-term authentication, you can store the token and the timestamp ts
65 // value (from $_GET["ts"]) somewhere and make authenticated calls (until ts runs
66 // out -- typically 14 days) this way:
67 // $authObj->token = $storedtoken;
68 // $url = 'http://photos.yahooapis.com/V1.0/listAlbums?';
69 // $xml=$authObj->makeAuthWSgetCall($url);
70 // if ($xml == false) {
71 // echo 'WS call setup Failed. Error is: '.$authObj->access_credentials_error;
72 // } else {
73 // echo 'Look at response for other errors or success: '.$xml;
74 // }
75 //
76
77 // error_reporting(E_STRICT);
78
79 class YBrowserAuth {
80
81 private $appid;
82 private $secret;
83 public $appdata;
84 public $userhash;
85 public $timeout;
86 public $token;
87 public $WSSID;
88 public $cookie;
89 public $sig_validation_error;
90 public $access_credentials_error;
91 const wslogin_prefix = 'https://api.login.yahoo.com/WSLogin/V1/';
92
93 /**
94 * Constructor function. Instantiates the application id and shared secret
95 * used to authorize access.
96 * @param string $yourappid
97 * @param string $yoursecret
98 */
99 public function __construct($yourappid, $yoursecret) {
100 $this->appid = $yourappid;
101 $this->secret = $yoursecret;
102 }
103
104 /**
105 * Create the Login URL used to fetch authentication credentials. This is the
106 * first step in the browser authentication process.
107 *
108 * @param string $appd Optional data string, typically a session id,
109 * that Yahoo will transfer to the target application upon successful authentication
110 * @param boolean $hash Optional flag. If set, the send_userhash=1 request will be
111 * appended to the request URL so that the userhash will be returned by Yahoo! after
112 * successful authentication.
113 * @return string A full URL that initiates browser-based authentication.
114 */
115 public function getAuthURL($appd=null, $hash=false) {
116 // Add optional appdata parameter, if requested
117 $appdata = (empty($appd)) ? null : '&appdata=' . urlencode($appd);
118 $hashdata = ($hash) ? '&send_userhash=1' : null;
119 return $this->createAuthURL(self::wslogin_prefix . "wslogin?appid=" . $this->appid . $appdata . $hashdata);
120 }
121
122 /**
123 * Takes a REST-style web service URL and adds the necessary parameters
124 * to turn it into an authenticated REST-style web service URL for use
125 * with Yahoo browser-based authentication.
126 *
127 * @param string $url A valid URL for a web service call minus the authentication
128 * credentials.
129 * @return false | string Returns the full URL you can use to make an authenticated
130 * web service call. Returns false on error and the error should
131 * be in $this->access_credentials_error
132 */
133 public function createAuthWSurl($url) {
134 // If we already have the authentication cookie, don't bother getting the
135 // credentials again. If you want to force getting credentials again, you
136 // can unset($this->cookie) before calling this.
137 if (!isset($this->cookie)) {
138 if (!$this->getAccessCredentials()) {
139 return false;
140 }
141 }
142 // Security concern -- make sure there is a question mark in the URL
143 // If there's no question mark, add one.
144 $url=trim($url);
145 if (stristr($url,'?') == false) {
146 $url .= '?';
147 }
148
149 return $url."&WSSID=$this->WSSID&appid=$this->appid";
150 }
151
152 /**
153 * Validates the signature returned by Yahoo's browser authentication
154 * services
155 *
156 * @param string $ts Optional timestamp that typically will normally be retrieved
157 * from the global $_GET array after authentication succeeds.
158 * @param string $sig Optional sig that typically will normally be retrieved
159 * from the global $_GET array after authentication succeeds.
160 * @return true | false Returns true if the sig is validated. Returns false if
161 * any error occurs. If false is returned, $this->sig_validation_error should
162 * contain a string describing the error.
163 */
164 public function validate_sig($ts=null, $sig=null) {
165 // There might be a reason you'd want to pass in the timestamp and
166 // signature yourself, but typically not.
167 $ts = (empty($ts)) ? $_GET["ts"] : $ts;
168 $sig = (empty($sig)) ? $_GET["sig"] : $sig;
169 $this->userhash = isset($_GET["userhash"]) ? $_GET["userhash"] : null;
170 $this->appdata = isset($_GET["appdata"]) ? $_GET["appdata"] : null;
171
172 // Fetch the Request URI from the environment
173 $relative_url = getenv('REQUEST_URI');
174 if ($relative_url === false ) {
175 $this->sig_validation_error = "Failed getting REQUEST_URI from the environment";
176 return false;
177 }
178
179 // Parse the signature out of the REQUEST_URI
180 $match = array();
181 $preg_rv = preg_match("@^(.+)&sig=(\\w{32})$@", $relative_url, $match);
182
183 // Only one sig should be found. If it's found, it should match the sig
184 // sent by Yahoo!
185 if ($preg_rv == 1) {
186 if ($match[2] != $sig) {
187 $this->sig_validation_error = "Invalid sig may have been passed: " . $match[2] . ", $sig ";
188 return false;
189 }
190 } else {
191 $this->sig_validation_error = "Invalid url may have been passed - relative_url: $relative_url ";
192 return false;
193 }
194
195 // At this point, the url looks valid, and we pulled the sig from the url.
196 // The sig was guaranteed to be the last param on the url.
197 $relative_url_without_sig = $match[1];
198
199 // Make sure your server time is within 10 minutes (600 seconds) of Yahoo's servers
200 $current_time = time();
201 $clock_skew = abs($current_time - $ts);
202 if ($clock_skew >= 600) {
203 $this->sig_validation_error = "Invalid timestamp - clock_skew is $clock_skew seconds, current time is $current_time, ts is $ts";
204 return false;
205 }
206
207 // Use the PHP md5 function to caculate the sig using your shared secret, and
208 // then compare that sig to the one passed by Yahoo.
209 $sig_input = $relative_url_without_sig . $this->secret;
210 $calculated_sig = md5($sig_input);
211 if ($calculated_sig == $sig) {
212 return true;
213 } else {
214 $this->sig_validation_error = "calculated_sig was $calculated_sig, supplied sig was $sig, sig input was $sig_input";
215 return false;
216 }
217 }
218
219 /**
220 * Make an authenticated web services call using HTTP GET
221 *
222 * @param string $url The web services call minus the authentication credentials
223 * @return string | false If successful, a string is returned containing the web
224 * service response which might be XML, JSON, or some other type of text. If a curl
225 * error occurs, the error is stored in $this->access_credentials_error. Note that
226 * access to the HTTP status code (for further error checking) is not provided
227 * in this method.
228 */
229 public function makeAuthWSgetCall($url) {
230
231 // Add the authentication credentials to the web service call
232 $url = $this->createAuthWSurl($url);
233 if ($url === false) {
234 return false;
235 }
236
237 // Do an HTTP GET using Curl
238 $ch = curl_init();
239 curl_setopt($ch, CURLOPT_URL, $url);
240 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
241 curl_setopt($ch, CURLOPT_HTTPHEADER, array("Cookie: $this->cookie"));
242 $xml = curl_exec($ch);
243 if (curl_errno ($ch)) {
244 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
245 return false;
246 }
247 curl_close( $ch );
248
249 return $xml;
250 }
251
252 /**
253 * Make an authenticated web services call using HTTP POST
254 *
255 * @param string $url The web services call minus the authentication credentials
256 * @return string | false If successful, a string is returned containing the web
257 * service response which might be XML, JSON, or some other type of text. If a curl
258 * error occurs, the error is stored in $this->access_credentials_error. Note that
259 * access to the HTTP status code (for further error checking) is not provided
260 * in this method.
261 */
262 public function makeAuthWSpostCall($url) {
263
264 $url = $this->createAuthWSurl($url);
265 if ($url === false) {
266 return false;
267 }
268
269 $parts = parse_url($url);
270
271 $prefix = $parts["scheme"]."://".$parts["host"].$parts["path"];
272
273 $ch = curl_init($prefix);
274 curl_setopt ($ch, CURLOPT_POST, true);
275 curl_setopt ($ch, CURLOPT_POSTFIELDS, $parts["query"]);
276 curl_setopt( $ch, CURLOPT_HTTPHEADER, array("Cookie: $this->cookie"));
277 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
278 $xml = curl_exec( $ch );
279 if (curl_errno( $ch )) {
280 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
281 return false;
282 }
283 curl_close( $ch );
284
285 return $xml;
286 }
287
288 /**
289 * This method is used by getAccessCredentials to fetch all the
290 * values necessary to make an authenticated web service call.
291 *
292 * @param string $yourtoken Typically, you would not pass this in. It's sent by Yahoo
293 * as part of the response from successful user authentication
294 * @return string Returns a full URL that is used to retrieve all the authentication
295 * values
296 */
297 private function getAccessURL() {
298 // If the app is making a call by manually setting $this->token, we want to check for that
299 $this->token = (isset($this->token)) ? $this->token : $_GET["token"];
300 return $this->createAuthURL(self::wslogin_prefix . "wspwtoken_login?token=$this->token&appid=$this->appid");
301 }
302
303 /**
304 * A utility function used to build authenticated URLs
305 *
306 * @param string $url
307 * @return string The URL with authentication credentials added to it
308 */
309 private function createAuthURL($url) {
310 // Take apart the URL
311 $parts = parse_url($url);
312 // Get the current time
313 $ts = time();
314 // Re-build the path and query with the timestamp added
315 $relative_uri = "";
316 // Make sure we form the URL correctly
317 if (isset($parts["path"])) {
318 $relative_uri .= $parts["path"];
319 }
320 if (empty($parts["query"])) {
321 $relative_uri .= "?" . "ts=$ts";
322 } else {
323 $relative_uri .= "?" . $parts["query"] . "&ts=$ts";
324 }
325 // Generate the sig
326 $sig = md5($relative_uri . $this->secret);
327 // Build the signed URL
328 $signed_url = $parts["scheme"] . "://" . $parts["host"] . $relative_uri . "&sig=$sig";
329 return $signed_url;
330 }
331
332 /**
333 * Fetches all the authentication values for use in making authenticated
334 * web service calls
335 *
336 * @return true | false Returns true if all the authentication values are
337 * successfully fetched. Returns false if anything else happens and the error
338 * is in $this->access_credentials_error
339 */
340 private function getAccessCredentials() {
341 // Get the wspwtoken_login URL
342 $url = $this->getAccessURL();
343
344 // Do an HTTP GET to get the values
345 $ch = curl_init();
346 curl_setopt( $ch, CURLOPT_URL, $url );
347 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
348 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
349 $xml = curl_exec( $ch );
350
351 if (curl_errno($ch)) {
352 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
353 return false;
354 }
355 curl_close($ch);
356
357 // Check in the returned XML for an error
358 $match_array = array();
359 if (preg_match("@<ErrorCode>(.+)</ErrorCode>@", $xml, $match_array) == 1) {
360 $this->access_credentials_error = "Error code returned in XML response: $match_array[1]";
361 return false;
362 }
363
364 // Get the cookie
365 if (preg_match("@(Y=.*)@", $xml, $match_array) == 1) {
366 $this->cookie = $match_array[1];
367 } else {
368 $this->access_credentials_error = "No cookie found";
369 return false;
370 }
371
372 // Get the WSSID - Web Services Session ID. Used to avoid replay attacks
373 $match_array = array();
374 if (preg_match("@<WSSID>(.+)</WSSID>@", $xml, $match_array) == 1) {
375 $this->WSSID = $match_array[1];
376 } else {
377 $this->access_credentials_error = "No WSSID found";
378 return false;
379 }
380
381 // Get the timeout value. This is the length of time, in seconds, that
382 // The cookie value is valid. Usually 3600 seconds (1 hour).
383 $match_array = array();
384 if (preg_match( "@<Timeout>(.+)</Timeout>@", $xml, $match_array) == 1) {
385 $this->timeout = $match_array[1];
386 } else {
387 $this->access_credentials_error = "No timeout found";
388 return false;
389 }
390
391 return true;
392 }
393
394 }
395 ?>

  ViewVC Help
Powered by ViewVC 1.1.2