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

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

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.php4 -- a PHP4 class for using Yahoo's browser
3 // authentication service
4 //
5 // Author: Jason Levitt
6 // Date: October 6th, 2006 Version 1.01
7 // Credits: Based on code by Allen Tom with additions by Dan Theurer and Zack Steinkamp
8 // Requirements: PHP4. 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_ALL);
78
79 DEFINE ('WSLOGIN_PREFIX', 'https://api.login.yahoo.com/WSLogin/V1/');
80
81 class YBrowserAuth {
82
83 var $appid;
84 var $secret;
85 var $appdata;
86 var $timeout;
87 var $token;
88 var $WSSID;
89 var $cookie;
90 var $userhash;
91 var $sig_validation_error;
92 var $access_credentials_error;
93
94 /**
95 * Constructor function. Instantiates the application id and shared secret
96 * used to authorize access.
97 * @param string $yourappid
98 * @param string $yoursecret
99 */
100 function YBrowserAuth($yourappid, $yoursecret) {
101 $this->appid = $yourappid;
102 $this->secret = $yoursecret;
103 }
104
105 /**
106 * Create the Login URL used to fetch authentication credentials. This is the
107 * first step in the browser authentication process.
108 *
109 * @param string $appd Optional data string, typically a session id,
110 * that Yahoo will transfer to the target application upon successful authentication
111 * @param boolean $hash Optional flag. If set, the send_userhash=1 request will be
112 * appended to the request URL so that the userhash will be returned by Yahoo! after
113 * successful authentication.
114 * @return string A full URL that initiates browser-based authentication.
115 */
116 function getAuthURL($appd=null, $hash=false) {
117 // Add optional appdata parameter, if requested
118 $appdata = (empty($appd)) ? null : '&appdata=' . urlencode($appd);
119 $hashdata = ($hash) ? '&send_userhash=1' : null;
120 return $this->createAuthURL(WSLOGIN_PREFIX . "wslogin?appid=" . $this->appid . $appdata . $hashdata);
121 }
122
123 /**
124 * Takes a REST-style web service URL and adds the necessary parameters
125 * to turn it into an authenticated REST-style web service URL for use
126 * with Yahoo browser-based authentication.
127 *
128 * @param string $url A valid URL for a web service call minus the authentication
129 * credentials.
130 * @return false | string Returns the full URL you can use to make an authenticated
131 * web service call. Returns false on error and the error should
132 * be in $this->access_credentials_error
133 */
134 function createAuthWSurl($url) {
135 // If we already have the authentication cookie, don't bother getting the
136 // credentials again. If you want to force getting credentials again, you
137 // can unset($this->cookie) before calling this.
138 if (!isset($this->cookie)) {
139 if (!$this->getAccessCredentials()) {
140 return false;
141 }
142 }
143 // Security concern -- make sure there is a question mark in the URL
144 // If there's no question mark, add one.
145 $url=trim($url);
146 if (stristr($url,'?') == false) {
147 $url .= '?';
148 }
149
150 return $url."&WSSID=$this->WSSID&appid=$this->appid";
151 }
152
153 /**
154 * Validates the signature returned by Yahoo's browser authentication
155 * services
156 *
157 * @param string $ts Optional timestamp that typically will normally be retrieved
158 * from the global $_GET array after authentication succeeds.
159 * @param string $sig Optional sig that typically will normally be retrieved
160 * from the global $_GET array after authentication succeeds.
161 * @return true | false Returns true if the sig is validated. Returns false if
162 * any error occurs. If false is returned, $this->sig_validation_error should
163 * contain a string describing the error.
164 */
165 function validate_sig($ts=null, $sig=null) {
166 // There might be a reason you'd want to pass in the timestamp and
167 // signature yourself, but typically not.
168 $ts = (empty($ts)) ? $_GET["ts"] : $ts;
169 $sig = (empty($sig)) ? $_GET["sig"] : $sig;
170 $this->userhash = isset($_GET["userhash"]) ? $_GET["userhash"] : null;
171 $this->appdata = isset($_GET["appdata"]) ? $_GET["appdata"] : null;
172
173 // Fetch the Request URI from the environment
174 $relative_url = getenv('REQUEST_URI');
175 if ($relative_url === false ) {
176 $this->sig_validation_error = "Failed getting REQUEST_URI from the environment";
177 return false;
178 }
179
180 // Parse the signature out of the REQUEST_URI
181 $match = array();
182 $preg_rv = preg_match("@^(.+)&sig=(\\w{32})$@", $relative_url, $match);
183
184 // Only one sig should be found. If it's found, it should match the sig
185 // sent by Yahoo!
186 if ($preg_rv == 1) {
187 if ($match[2] != $sig) {
188 $this->sig_validation_error = "Invalid sig may have been passed: " . $match[2] . ", $sig ";
189 return false;
190 }
191 } else {
192 $this->sig_validation_error = "Invalid url may have been passed - relative_url: $relative_url ";
193 return false;
194 }
195
196 // At this point, the url looks valid, and we pulled the sig from the url.
197 // The sig was guaranteed to be the last param on the url.
198 $relative_url_without_sig = $match[1];
199
200 // Make sure your server time is within 10 minutes (600 seconds) of Yahoo's servers
201 $current_time = time();
202 $clock_skew = abs($current_time - $ts);
203 if ($clock_skew >= 600) {
204 $this->sig_validation_error = "Invalid timestamp - clock_skew is $clock_skew seconds, current time is $current_time, ts is $ts";
205 return false;
206 }
207
208 // Use the PHP md5 function to caculate the sig using your shared secret, and
209 // then compare that sig to the one passed by Yahoo.
210 $sig_input = $relative_url_without_sig . $this->secret;
211 $calculated_sig = md5($sig_input);
212 if ($calculated_sig == $sig) {
213 return true;
214 } else {
215 $this->sig_validation_error = "calculated_sig was $calculated_sig, supplied sig was $sig, sig input was $sig_input";
216 return false;
217 }
218 }
219
220 /**
221 * Make an authenticated web services call using HTTP GET
222 *
223 * @param string $url The web services call minus the authentication credentials
224 * @return string | false If successful, a string is returned containing the web
225 * service response which might be XML, JSON, or some other type of text. If a curl
226 * error occurs, the error is stored in $this->access_credentials_error. Note that
227 * access to the HTTP status code (for further error checking) is not provided
228 * in this method.
229 */
230 function makeAuthWSgetCall($url) {
231
232 // Add the authentication credentials to the web service call
233 $url = $this->createAuthWSurl($url);
234 if ($url === false) {
235 return false;
236 }
237
238 // Do an HTTP GET using Curl
239 $ch = curl_init();
240 curl_setopt($ch, CURLOPT_URL, $url);
241 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
242 curl_setopt($ch, CURLOPT_HTTPHEADER, array("Cookie: $this->cookie"));
243 $xml = curl_exec($ch);
244 if (curl_errno ($ch)) {
245 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
246 return false;
247 }
248 curl_close( $ch );
249
250 return $xml;
251 }
252
253 /**
254 * Make an authenticated web services call using HTTP POST
255 *
256 * @param string $url The web services call minus the authentication credentials
257 * @return string | false If successful, a string is returned containing the web
258 * service response which might be XML, JSON, or some other type of text. If a curl
259 * error occurs, the error is stored in $this->access_credentials_error. Note that
260 * access to the HTTP status code (for further error checking) is not provided
261 * in this method.
262 */
263 function makeAuthWSpostCall($url) {
264
265 $url = $this->createAuthWSurl($url);
266 if ($url === false) {
267 return false;
268 }
269
270 $parts = parse_url($url);
271
272 $prefix = $parts["scheme"]."://".$parts["host"].$parts["path"];
273
274 $ch = curl_init($prefix);
275 curl_setopt ($ch, CURLOPT_POST, true);
276 curl_setopt ($ch, CURLOPT_POSTFIELDS, $parts["query"]);
277 curl_setopt( $ch, CURLOPT_HTTPHEADER, array("Cookie: $this->cookie"));
278 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
279 $xml = curl_exec( $ch );
280 if (curl_errno( $ch )) {
281 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
282 return false;
283 }
284 curl_close( $ch );
285
286 return $xml;
287 }
288
289 /**
290 * This method is used by getAccessCredentials to fetch all the
291 * values necessary to make an authenticated web service call
292 *
293 * @param string $yourtoken Typically, you would not pass this in. It's sent by Yahoo
294 * as part of the response from successful user authentication
295 * @return string Returns a full URL that is used to retrieve all the authentication
296 * values
297 */
298 function getAccessURL() {
299 // If the app is making a call by manually setting $this->token, we want to check for that
300 $this->token = (isset($this->token)) ? $this->token : $_GET["token"];
301 return $this->createAuthURL(WSLOGIN_PREFIX . "wspwtoken_login?token=$this->token&appid=$this->appid");
302 }
303
304 /**
305 * A utility function used to build authenticated URLs
306 *
307 * @param string $url
308 * @return string The URL with authentication credentials added to it
309 */
310 function createAuthURL($url) {
311 // Take apart the URL
312 $parts = parse_url($url);
313 // Get the current time
314 $ts = time();
315 // Re-build the path and query with the timestamp added
316 $relative_uri = "";
317 // Make sure we form the URL correctly
318 if (isset($parts["path"])) {
319 $relative_uri .= $parts["path"];
320 }
321 if (empty($parts["query"])) {
322 $relative_uri .= "?" . "ts=$ts";
323 } else {
324 $relative_uri .= "?" . $parts["query"] . "&ts=$ts";
325 }
326 // Generate the sig
327 $sig = md5($relative_uri . $this->secret);
328 // Build the signed URL
329 $signed_url = $parts["scheme"] . "://" . $parts["host"] . $relative_uri . "&sig=$sig";
330 return $signed_url;
331 }
332
333 /**
334 * Fetches all the authentication values for use in making authenticated
335 * web service calls
336 *
337 * @return true | false Returns true if all the authentication values are
338 * successfully fetched. Returns false if anything else happens and the error
339 * is in $this->access_credentials_error
340 */
341 function getAccessCredentials() {
342 // Get the wspwtoken_login URL
343 $url = $this->getAccessURL();
344
345 // Do an HTTP GET to get the values
346 $ch = curl_init();
347 curl_setopt( $ch, CURLOPT_URL, $url );
348 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
349 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
350 $xml = curl_exec( $ch );
351
352 if (curl_errno($ch)) {
353 $this->access_credentials_error = "Curl error number:".curl_errno($ch);
354 return false;
355 }
356 curl_close($ch);
357
358 // Check in the returned XML for an error
359 $match_array = array();
360 if (preg_match("@<ErrorCode>(.+)</ErrorCode>@", $xml, $match_array) == 1) {
361 $this->access_credentials_error = "Error code returned in XML response: $match_array[1]";
362 return false;
363 }
364
365 // Get the cookie
366 if (preg_match("@(Y=.*)@", $xml, $match_array) == 1) {
367 $this->cookie = $match_array[1];
368 } else {
369 $this->access_credentials_error = "No cookie found";
370 return false;
371 }
372
373 // Get the WSSID - Web Services Session ID. Used to avoid replay attacks
374 $match_array = array();
375 if (preg_match("@<WSSID>(.+)</WSSID>@", $xml, $match_array) == 1) {
376 $this->WSSID = $match_array[1];
377 } else {
378 $this->access_credentials_error = "No WSSID found";
379 return false;
380 }
381
382 // Get the timeout value. This is the length of time, in seconds, that
383 // The cookie value is valid. Usually 3600 seconds (1 hour).
384 $match_array = array();
385 if (preg_match( "@<Timeout>(.+)</Timeout>@", $xml, $match_array) == 1) {
386 $this->timeout = $match_array[1];
387 } else {
388 $this->access_credentials_error = "No timeout found";
389 return false;
390 }
391
392 return true;
393 }
394
395 }
396 ?>

  ViewVC Help
Powered by ViewVC 1.1.2