├── .gitignore ├── application ├── config │ ├── ddauth_site.example.php │ └── ddauth.php └── libraries │ └── Ddauth.php ├── INSTALL ├── dd-p2.xml ├── README ├── LICENSE └── phpdoc.ini /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | docs 3 | -------------------------------------------------------------------------------- /application/config/ddauth_site.example.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | ddauth - Dragonfly Development CodeIgniter Auth Add-on 2 | http://code.google.com/p/dd-ci-ddauth 3 | 4 | Copy the ddauth distribution files: 5 | 6 | cp dd-ci-ddauth/application/libraries/Ddauth.php \ 7 | system/application/libraries/ 8 | 9 | cp dd-ci-ddauth/application/config/ddauth.php \ 10 | system/application/config/ 11 | 12 | It is recommended to update the 'ddauth_ticket_secret' configuration value in 13 | the ddauth.php file located in path/to/your/system/application/config/. 14 | Setting this value ensures that the authentication tickets generated by ddauth 15 | are more secure. 16 | 17 | Optionally add ddauth to application's autoload. To do so, modify 18 | system/application/config/autoload.php to include the ddauth library: 19 | 20 | $autoload['libraries'] = array('Ddauth'); 21 | 22 | -------------------------------------------------------------------------------- /dd-p2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0.1.2 4 | ddauth - Dragonfly Development CodeIgniter Auth Add-on 5 | http://code.google.com/p/dd-ci-ddauth/ 6 | Copyright (c) 2010 Dragonfly Development 7 | Licensed under the New BSD License. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ddauth - Dragonfly Development CodeIgniter Auth Add-on 2 | http://code.google.com/p/dd-ci-ddauth 3 | 4 | 5 | The ddauth add-on for CodeIgniter is intended to be a flexible authentication 6 | library focussing almost entirely on the problem of creating a secure 7 | authentication ticket and attempts to place as few restrictions as possible 8 | on the application using it. 9 | 10 | The primary purpose for writing this library was the fact that many of the 11 | existing CodeIgniter authentication systems were either too complicated to 12 | implement easily, required too much integration into the application itself 13 | or focused solely on cookies and did not support fallback authentication 14 | methods for when cookies are not available. 15 | 16 | The latter is particularly important when using any sort of application with 17 | a web application that requires authentication as Flash cannot be assumed to 18 | send the browser's cookies reliably. In this case, it is beneficial to be able 19 | to pass the authentication ticket to the Flash movie and instruct it to pass 20 | the ticket along as a GET or POST param. 21 | 22 | 23 | The core security principles were inspired by the "Dos and Don'ts of Client 24 | Authentication on the Web" document found here: 25 | 26 | http://cookies.lcs.mit.edu/pubs/webauth:tr.pdf 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Dragonfly Development Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Dragonfly Development Inc nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /phpdoc.ini: -------------------------------------------------------------------------------- 1 | [Parse Data] 2 | title = ddauth Manual 3 | 4 | ;; parse files that start with a . like .bash_profile 5 | ;; legal values: true, false 6 | hidden = false 7 | 8 | ;; show elements marked @access private in documentation by setting this to on 9 | ;; legal values: on, off 10 | parseprivate = off 11 | 12 | ;; parse with javadoc-like description (first sentence is always the short description) 13 | ;; legal values: on, off 14 | javadocdesc = off 15 | 16 | ;; add any custom @tags separated by commas here 17 | ;; legal values: any legal tagname separated by commas. 18 | ;customtags = mytag1,mytag2 19 | 20 | ;; This is only used by the XML:DocBook/peardoc2 converter 21 | defaultcategoryname = Documentation 22 | 23 | ;; what is the main package? 24 | ;; legal values: alphanumeric string plus - and _ 25 | defaultpackagename = ddauth 26 | 27 | ;; output any parsing information? set to on for cron jobs 28 | ;; legal values: on 29 | ;quiet = on 30 | 31 | ;; parse a PEAR-style repository. Do not turn this on if your project does 32 | ;; not have a parent directory named "pear" 33 | ;; legal values: on/off 34 | pear = on 35 | 36 | ;; where should the documentation be written? 37 | ;; legal values: a legal path 38 | ;target = /home/cellog/output 39 | target = docs 40 | 41 | ;; Which files should be parsed out as special documentation files, such as README, 42 | ;; INSTALL and CHANGELOG? This overrides the default files found in 43 | ;; phpDocumentor.ini (this file is not a user .ini file, but the global file) 44 | readmeinstallchangelog = README, INSTALL, FAQ, LICENSE, Release-1.4.0, LICENSE.txt 45 | 46 | ;; limit output to the specified packages, even if others are parsed 47 | ;; legal values: package names separated by commas 48 | ;packageoutput = package1,package2 49 | packageoutput = ddauth 50 | 51 | ;; comma-separated list of files to parse 52 | ;; legal values: paths separated by commas 53 | ;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory 54 | 55 | ;; comma-separated list of directories to parse 56 | ;; legal values: directory paths separated by commas 57 | ;directory = /path1,/path2,.,..,subdirectory 58 | ;directory = /home/jeichorn/cvs/pear 59 | ;directory = /home/cellog/workspace/phpdoc 60 | directory = application/libraries 61 | 62 | ;; template base directory (the equivalent directory of /phpDocumentor) 63 | ;templatebase = /path/to/my/templates 64 | 65 | ;; directory to find any example files in through @example and {@example} tags 66 | ;examplesdir = /path/to/my/templates 67 | 68 | ;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore 69 | ;; legal values: any wildcard strings separated by commas 70 | ;; remember, this pathing is RELATIVE to the top-most directory in your "directory" value 71 | ;ignore = path/to/ignore*,*list.php,myfile.php,subdirectory/ 72 | 73 | ;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format 74 | ;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib, 75 | ;; HTML:frames:earthli, 76 | ;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de, 77 | ;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli 78 | ;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS 79 | ;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default 80 | output=HTML:frames:earthli 81 | 82 | ;; turn this option on if you want highlighted source code for every file 83 | ;; legal values: on/off 84 | sourcecode = on 85 | -------------------------------------------------------------------------------- /application/config/ddauth.php: -------------------------------------------------------------------------------- 1 | 220 | -------------------------------------------------------------------------------- /application/libraries/Ddauth.php: -------------------------------------------------------------------------------- 1 | load->helper('url'); 183 | 184 | $config = $CI->config; 185 | 186 | if ( ! $config->load('ddauth', false, true) ) { 187 | // Support legacy configuration file... for now. 188 | if ( ! $config->load('dd_ci_ddauth', false, true) ) { 189 | show_error('The ddauth configuration file does not exist.'); 190 | } 191 | } 192 | 193 | $this->configurationMethodName = $config->item( 194 | 'ddauth_configurationMethodName' 195 | ); 196 | 197 | $this->validateCredentialsMethodName = $config->item( 198 | 'ddauth_validateCredentialsMethodName' 199 | ); 200 | 201 | $this->authSuccessMethodName = $config->item( 202 | 'ddauth_authSuccessMethodName' 203 | ); 204 | 205 | $this->executeCompleteMethodName = $config->item( 206 | 'ddauth_executeCompleteMethodName' 207 | ); 208 | 209 | $this->errorMethodName = $config->item( 210 | 'ddauth_errorMethodName' 211 | ); 212 | 213 | // Redirects 214 | $this->signinRedirectPath = $config->item( 215 | 'ddauth_redirects_signin_redirectPath' 216 | ); 217 | 218 | // Ticket 219 | $this->ticketSecret = $config->item('ddauth_ticket_secret'); 220 | $this->ticketParamName = $config->item('ddauth_ticket_paramName'); 221 | $this->ticketExpiration = $config->item('ddauth_ticket_expiration'); 222 | $this->ticketKeepalive = $this->_sanitizeBool( 223 | $config->item('ddauth_ticket_keepalive') 224 | ); 225 | $this->ticketKeepaliveThreshold = $config->item( 226 | 'ddauth_ticket_keepaliveThreshold' 227 | ); 228 | 229 | $this->ticketCookieDomain = $config->item( 230 | 'ddauth_ticket_cookie_domain' 231 | ); 232 | $this->ticketCookiePath = $config->item( 233 | 'ddauth_ticket_cookie_path' 234 | ); 235 | $this->ticketCookiePrefix = $config->item( 236 | 'ddauth_ticket_cookie_prefix' 237 | ); 238 | 239 | // Session 240 | $this->sessionHandler = $config->item('ddauth_session_handler'); 241 | $this->allowFlash = $config->item('ddauth_session_allowFlash'); 242 | 243 | } 244 | 245 | /** 246 | * Redirect to sign in page 247 | * 248 | * Adds the current URL to the session as the requested URL if 249 | * a requested URL is not already specified and then redirects 250 | * to the sign in page. 251 | */ 252 | function redirectToSignin() { 253 | 254 | $CI =& get_instance(); 255 | $CI->load->helper('url'); 256 | 257 | if ( ! $this->_getSessionData('ddauth.requestedUrl') ) { 258 | $this->_setSessionData('ddauth.requestedUrl', current_url()); 259 | } 260 | 261 | redirect($this->signinRedirectPath); 262 | 263 | } 264 | 265 | /** 266 | * Perform login 267 | * 268 | * Performs login for specified username and password. If the 269 | * credentials validate, the ticket is set and the user identification 270 | * is returned. 271 | * 272 | * @param string $username Username 273 | * @param string $password Password 274 | * @return mixed Null or user identification 275 | */ 276 | function performLogin($username = null, $password = null) { 277 | if ( $id = $this->_validateCredentials($username, $password) ) { 278 | return $this->setAuthenticatedId($id, true); 279 | } 280 | return null; 281 | } 282 | 283 | /** 284 | * Force set the authenticated user ID. 285 | * @param string $id User ID 286 | * @param bool $isLogin Is this from a login? 287 | * @param bool $sendAuthTicketCookie Should an auth ticket cookie be sent? 288 | * @param int $expires Length of time in seconds that the ticket is valid 289 | */ 290 | function setAuthenticatedId($id = null, $isLogin = null, $sendAuthTicketCookie = true, $expires = null) { 291 | $this->id = $id; 292 | $this->isLoggedIn = true; 293 | if ( $sendAuthTicketCookie ) { 294 | $this->_sendAuthTicketCookie( 295 | $this->generateAuthTicket($id, $expires) 296 | ); 297 | } 298 | $this->reportAuthSuccess($isLogin); 299 | return $this->id; 300 | } 301 | 302 | /** 303 | * Invalidate an auth ticket cookie 304 | */ 305 | function invalidateAuthTicketCookie() { 306 | $this->_sendAuthTicketCookie(null); 307 | } 308 | 309 | /** 310 | * Generate an auth ticket for a user ID 311 | * 312 | * This method allows for the generation of a valid authentication ticket 313 | * for the specified ID. 314 | * 315 | * @param mixed $id User ID 316 | * @param int $expires Length of time in seconds that the ticket is valid 317 | * @return string 318 | */ 319 | function generateAuthTicket($id = null, $expires = null) { 320 | if ( $expires === null ) $expires = $this->ticketExpiration; 321 | $data = array('u' => $id, 'tt' => 'auth'); 322 | $time = time() + $expires; 323 | $serializedData = serialize($data); 324 | $digest = $this->_generateDigest($serializedData, $time); 325 | return base64_encode('e=' . urlencode($time) . '&d=' . urlencode($serializedData) . '&h=' . urlencode($digest)); 326 | } 327 | 328 | /** 329 | * Validate an auth ticket 330 | * 331 | * Decodes the specified authentication ticket and returns an array 332 | * containing information about the ticket. 333 | * 334 | * @param mixed $rawInput Suspected authentication ticket 335 | * @return string Authenticated user ID 336 | */ 337 | function decodeAuthTicket($rawInput = null) { 338 | 339 | if ( $rawInput === null ) return null; 340 | 341 | $parts = array(); 342 | 343 | foreach ( explode('&', base64_decode($rawInput)) as $pair ) { 344 | $keyValuePair = explode('=', $pair); 345 | if ( count($keyValuePair) == 2 ) { 346 | list($key, $value) = $keyValuePair; 347 | $parts[$key] = urldecode($value); 348 | } 349 | } 350 | 351 | foreach ( array('e', 'h', 'd') as $k ) { 352 | if ( ! array_key_exists($k, $parts) ) return NULL; 353 | } 354 | 355 | $expired = $parts['e'] < time() ? true : false; 356 | 357 | if ( $parts['h'] == $this->_generateDigest($parts['d'], $parts['e']) ) { 358 | return array( 359 | 'token' => $parts, 360 | 'data' => unserialize($parts['d']), 361 | 'expired' => $expired 362 | ); 363 | } else { 364 | return NULL; 365 | } 366 | 367 | } 368 | 369 | /** 370 | * Handle authentication success 371 | * @param bool $isLogin Is this a login success? 372 | */ 373 | function reportAuthSuccess($isLogin = null) { 374 | return $this->_controllerMethodCallback( 375 | $this->authSuccessMethodName, 376 | $this->authSuccessCb, 377 | array($isLogin) 378 | ); 379 | } 380 | 381 | /** 382 | * Handle execute complete 383 | */ 384 | function reportExecuteComplete() { 385 | return $this->_controllerMethodCallback( 386 | $this->executeCompleteMethodName, 387 | $this->executeCompleteCb, 388 | array() 389 | ); 390 | } 391 | 392 | /** 393 | * Report errors. 394 | * 395 | * Will attempt to execute error callback or call the error method on 396 | * the controller. 397 | * @param string $key Short key identifying the error 398 | * @param string $description Detailed texual description of the error 399 | */ 400 | function reportError($key, $description) { 401 | return $this->_controllerMethodCallback( 402 | $this->errorMethodName, 403 | $this->errorCb, 404 | array($key, $description) 405 | ); 406 | } 407 | 408 | /** 409 | * Execute authentication 410 | * 411 | * Attempts to handle all of the specified automated auth related tasks 412 | * in one go. Once this method has completed, ddauth should know whether 413 | * or not the end user has been successfully authenticated or not. 414 | * 415 | * Accepts an optional configuration array that will be passed to 416 | * _configure(). 417 | * 418 | * @param array $config Additional configuration 419 | * @return bool Was authentication successful? 420 | */ 421 | function execute($config = array()) { 422 | 423 | $this->_configure($config); 424 | 425 | $loggedIn = false; 426 | 427 | $loggedOut = $this->_attemptLogout(); 428 | 429 | if ( $this->_attemptLogin() ) { 430 | $loggedIn = true; 431 | $loggedOut = false; 432 | } 433 | 434 | if ( $loggedOut ) { 435 | 436 | // If user is logged out, invalidate our ticket. 437 | $this->invalidateAuthTicketCookie(); 438 | 439 | } elseif ( ! $loggedIn ) { 440 | 441 | // If we are not already listed as having logged in, we should 442 | // check to see if we are still logged in from before. 443 | if ( ! $this->_attemptContinuation() ) { 444 | // If we failed the continuation attempt we should 445 | // invalidate the ticket. 446 | $this->invalidateAuthTicketCookie(); 447 | } 448 | 449 | } 450 | 451 | $this->reportExecuteComplete(); 452 | return $this->isLoggedIn; 453 | 454 | } 455 | 456 | /** 457 | * Attempt logging out 458 | * 459 | * If `ddauth_params_logout_paramName` exists in the input specified by 460 | * `ddauth_params_logout_source` the visitor is logged out. 461 | * @return bool Was log this a log out attempt? 462 | */ 463 | function _attemptLogout() { 464 | 465 | $CI =& get_instance(); 466 | $config = $CI->config; 467 | 468 | $logoutValue = $this->_getLogoutParam(); 469 | 470 | if ( $logoutValue ) { 471 | // We have asked to log out! We use this state 472 | // later when we are trying to read auth data. 473 | return true; 474 | } 475 | 476 | return false; 477 | 478 | } 479 | 480 | /** 481 | * Attempt logging in 482 | * 483 | * If `ddauth_params_login_paramName` exists in the input specified by 484 | * `ddauth_params_login_source` the visitor's credentials as specified by 485 | * `ddauth_params_login_usernameParamName` and 486 | * `ddauth_params_login_passwordParamName` are tested. 487 | * @return bool Was log in attempt a success? 488 | */ 489 | function _attemptLogin() { 490 | 491 | $loginValue = $this->_getLoginParam(); 492 | 493 | if ( $loginValue ) { 494 | 495 | $username = $this->_getLoginUsernameParam(); 496 | $password = $this->_getLoginPasswordParam(); 497 | 498 | if ( $id = $this->performLogin($username, $password) ) { 499 | if ( $requestedUrl = $this->_getSessionData('ddauth.requestedUrl') ) { 500 | $this->_unsetSessionData('ddauth.requestedUrl'); 501 | redirect($requestedUrl); 502 | } 503 | return true; 504 | } else { 505 | $this->reportError( 506 | 'attemptLogin.invalid', 507 | 'Login attempt failure, unknown user or incorrect password' 508 | ); 509 | $this->invalidateAuthTicketCookie(); 510 | $this->redirectToSignin(); 511 | } 512 | 513 | } 514 | 515 | return false; 516 | 517 | } 518 | 519 | /** 520 | * Attempt continuation of an existing ticket 521 | * 522 | * Checks to see if a ticket already exists and validates the ticket and 523 | * ensures that the ticket has not already expired. 524 | * @return bool Was continuation attempt a success? 525 | */ 526 | function _attemptContinuation() { 527 | 528 | $authData = $this->_findAndDecodeAuthTicket(); 529 | 530 | // If there was no auth data, this is still a success case since 531 | // we are going to assume that this is a "continuation" of a 532 | // non-logged in session. 533 | if ( $authData === null ) { return true; } 534 | 535 | // If the ticket has expired, this is a failure. 536 | if ( $authData['expired'] ) { return false; } 537 | 538 | // TODO Do we need to make the ticket type configurable? 539 | if ( isset($authData['data']['tt']) and $authData['data']['tt'] == 'auth' ) { 540 | 541 | $this->id = $authData['data']['u']; 542 | $this->isLoggedIn = true; 543 | $this->reportAuthSuccess(false); 544 | 545 | if ( $this->ticketKeepalive ) { 546 | $e = $authData['token']['e']; 547 | $timeRunning = $this->ticketExpiration - ( $e - time() ); 548 | if ( $timeRunning > $this->ticketKeepaliveThreshold ) { 549 | $this->_sendAuthTicketCookie( 550 | $this->generateAuthTicket($this->id) 551 | ); 552 | } 553 | 554 | } 555 | 556 | return true; 557 | 558 | } 559 | 560 | return false; 561 | 562 | } 563 | 564 | /** 565 | * Send the auth ticket cookie 566 | * @input mixed $value Value 567 | * @param int $expires Length of time in seconds that the ticket is valid 568 | */ 569 | function _sendAuthTicketCookie($value = null, $expires = null) { 570 | if ( $expires === null ) $expires = $this->ticketExpiration; 571 | $this->reportError('setCookie', $value); 572 | if ( $this->shouldSendAuthTicketCookie ) { 573 | $CI =& get_instance(); 574 | $CI->load->helper('cookie'); 575 | set_cookie(array( 576 | 'name' => $this->ticketParamName, 577 | 'value' => $value, 578 | 'expire' => time() + $expires, 579 | 'domain' => $this->ticketCookieDomain, 580 | 'path' => $this->ticketCookiePath, 581 | 'prefix' => $this->ticketCookiePrefix 582 | )); 583 | } 584 | } 585 | 586 | /** 587 | * Get the value for the logout paramater. 588 | * @return string 589 | */ 590 | function _getLogoutParam() { 591 | return $this->_getConfigParam( 592 | 'ddauth_params_logout_source', 593 | 'ddauth_params_logout_paramName' 594 | ); 595 | } 596 | 597 | /** 598 | * Get the value for the login paramater. 599 | * @return string 600 | */ 601 | function _getLoginParam() { 602 | return $this->_getConfigParam( 603 | 'ddauth_params_login_source', 604 | 'ddauth_params_login_paramName' 605 | ); 606 | } 607 | 608 | /** 609 | * Get the value for the login username paramater. 610 | * @return string 611 | */ 612 | function _getLoginUsernameParam() { 613 | return $this->_getConfigParam( 614 | 'ddauth_params_login_source', 615 | 'ddauth_params_login_usernameParamName' 616 | ); 617 | } 618 | 619 | /** 620 | * Get the value for the login password paramater. 621 | * @return string 622 | */ 623 | function _getLoginPasswordParam() { 624 | return $this->_getConfigParam( 625 | 'ddauth_params_login_source', 626 | 'ddauth_params_login_passwordParamName' 627 | ); 628 | } 629 | 630 | /** 631 | * Get a config param from the request 632 | * 633 | * ddauth receives information from the request enviornment and 634 | * depending on the security requirements, the params may be 635 | * retrieved by either GET, POST or EITHER. 636 | * 637 | * This method ensures that the requested param specified by $configName 638 | * is only retrieved from the sources described by $sourceName. 639 | * 640 | * @param string $sourceName Config name of allowed source 641 | * @param string $configName Config name of the param 642 | */ 643 | function _getConfigParam($sourceName, $paramName) { 644 | 645 | if ( isset($this->_configParamCache[$sourceName][$paramName]) ) { 646 | return $this->_configParamCache[$sourceName][$paramName]; 647 | } 648 | 649 | if ( ! isset($this->_configParamCache[$sourceName]) ) { 650 | $this->_configParamCache[$sourceName] = array(); 651 | } 652 | 653 | $CI =& get_instance(); 654 | $config = $CI->config; 655 | $input = $CI->input; 656 | 657 | $source = $this->_sanitizeSource($config->item($sourceName)); 658 | $param = $config->item($paramName); 659 | 660 | $rv = null; 661 | 662 | if ( $source == 'either') { 663 | $rv = $input->get_post($param); 664 | } 665 | elseif ( $source == 'post' ) { 666 | $rv = $input->post($param); 667 | } 668 | elseif ( $source == 'get' ) { 669 | $rv = $input->get($param); 670 | } 671 | 672 | $this->_configParamCache[$sourceName][$paramName] = $rv; 673 | 674 | return $rv; 675 | 676 | } 677 | 678 | /** 679 | * Sanitize a bool value 680 | * @param mixed $value Input 681 | * @return bool 682 | */ 683 | function _sanitizeBool($value = null) { 684 | if ( $value === true ) return true; 685 | if ( strtolower($value) == 'true' ) return true; 686 | if ( $value == 1 ) return true; 687 | return false; 688 | } 689 | 690 | /** 691 | * Sanitize a source value 692 | * @param mixed $value Input 693 | * @return string 694 | */ 695 | function _sanitizeSource($sourceValue) { 696 | if ( preg_match('/^\s*(either|get|post)\s*$/i', $sourceValue, $matches) ) { 697 | return strtolower($matches[1]); 698 | } 699 | return null; 700 | } 701 | 702 | /** 703 | * Call a method on a controller or execute a callback 704 | * 705 | * Order of operations is as follows: $cb then controller method 706 | * @param string $methodName Name of method that should exist on controller 707 | * @param callback $cb Callback to execute 708 | * @param array $args Arguments to send to method 709 | */ 710 | function _controllerMethodCallback($methodName, $cb = null, $args = null) { 711 | if ( $args === null ) $args = array(); 712 | if ( $cb === null ) { 713 | $CI =& get_instance(); 714 | if ( method_exists($CI, $methodName) ) { 715 | $cb = array($CI, $methodName); 716 | } 717 | } 718 | if ( $cb !== null ) { return call_user_func_array($cb, $args); } 719 | } 720 | 721 | /** 722 | * Configure. 723 | * 724 | * Will attempt to execute configuration callback or call the configuration 725 | * method on the controller. 726 | * 727 | * Optional configuration array can be used to set a select number 728 | * of options at configuration time. Currently supports: 729 | * 730 | * 'shouldSendAuthTicketCookie' 731 | * 'configurationMethodName' 732 | * 'validateCredentialsMethodName' 733 | * 'authSuccessMethodName' 734 | * 'executeCompleteMethodName' 735 | * 'errorMethodName' 736 | * 'configurationCb' 737 | * 'validateCredentialsCb' 738 | * 'authSuccessCb' 739 | * 'executeCompleteCb' 740 | * 'errorCb' 741 | * 742 | * @param array $config Configuration array 743 | */ 744 | function _configure($config = array()) { 745 | foreach ( $config as $key => $value ) { 746 | switch($key) { 747 | case 'shouldSendAuthTicketCookie': 748 | case 'configurationMethodName': 749 | case 'validateCredentialsMethodName': 750 | case 'authSuccessMethodName': 751 | case 'executeCompleteMethodName': 752 | case 'errorMethodName': 753 | case 'configurationCb': 754 | case 'validateCredentialsCb': 755 | case 'authSuccessCb': 756 | case 'executeCompleteCb': 757 | case 'errorCb': 758 | $this->$key = $value; 759 | break; 760 | } 761 | } 762 | return $this->_controllerMethodCallback( 763 | $this->configurationMethodName, 764 | $this->configurationCb, 765 | array($config) 766 | ); 767 | } 768 | 769 | /** 770 | * Validate credentials. 771 | * 772 | * Will attempt to validate credentials using the credential validation 773 | * callback or call the credential validation method on the controller. 774 | * @param string $username Username to validate 775 | * @param string $password Password to validate 776 | */ 777 | function _validateCredentials($username = null, $password = null) { 778 | return $this->_controllerMethodCallback( 779 | $this->validateCredentialsMethodName, 780 | $this->validateCredentialsCb, 781 | array($username, $password) 782 | ); 783 | } 784 | 785 | /** 786 | * Initialize session handling. 787 | * 788 | * Session handling can be very specific to an application so we need 789 | * to be flexible in how we handle sessions. Setting and getting have 790 | * been abstracted out such that this library only directly refers to 791 | * _setSessionFlashData(), _setSessionData(), _unsetSessionData() and 792 | * _getSessionData(). 793 | * 794 | * These methods will call the appropriate implementation based on 795 | * how the session handling has been setup and initialized here. 796 | */ 797 | function _initSession() { 798 | if ( ! $this->isSessionInitialized ) { 799 | switch($this->sessionHandler) { 800 | case 'ci': 801 | // Native CodeIgnither sessions are what 802 | // we prefer so the interface resembles 803 | // it a great deal. However, the system 804 | // should hopefully be flexible enough 805 | // to accommodate many types of session 806 | // handling. 807 | $CI =& get_instance(); 808 | $CI->load->library('session'); 809 | $this->_setSessionFlashDataCb = array( 810 | $this, '_setSessionFlashDataCi' 811 | ); 812 | $this->_setSessionDataCb = array( 813 | $this, '_setSessionDataCi' 814 | ); 815 | $this->_unsetSessionDataCb = array( 816 | $this, '_unsetSessionDataCi' 817 | ); 818 | $this->_getSessionDataCb = array( 819 | $this, '_getSessionDataCi' 820 | ); 821 | break; 822 | case 'php': 823 | // Native PHP sessions are going to be 824 | // supported eventually. 825 | $this->_setSessionFlashDataCb = array( 826 | $this, '_setSessionFlashDataPhp' 827 | ); 828 | $this->_setSessionDataCb = array( 829 | $this, '_setSessionDataPhp' 830 | ); 831 | $this->_unsetSessionDataCb = array( 832 | $this, '_unsetSessionDataPhp' 833 | ); 834 | $this->_getSessionDataCb = array( 835 | $this, '_getSessionDataPhp' 836 | ); 837 | break; 838 | case 'callbacks': 839 | // Callbacks for each of these three functions 840 | // will be supported eventually. 841 | $this->_setSessionFlashDataCb = array( 842 | $this, '_setSessionFlashDataCallbacks' 843 | ); 844 | $this->_setSessionDataCb = array( 845 | $this, '_setSessionDataCallbacks' 846 | ); 847 | $this->_unsetSessionDataCb = array( 848 | $this, '_unsetSessionDataCallbacks' 849 | ); 850 | $this->_getSessionDataCb = array( 851 | $this, '_getSessionDataCallbacks' 852 | ); 853 | break; 854 | case 'methods': 855 | // Method names to be called on the controller for 856 | // each of these three functions will be 857 | // supported eventually. 858 | $this->_setSessionFlashDataCb = array( 859 | $this, '_setSessionFlashDataMethods' 860 | ); 861 | $this->_setSessionDataCb = array( 862 | $this, '_setSessionDataMethods' 863 | ); 864 | $this->_unsetSessionDataCb = array( 865 | $this, '_unsetSessionDataMethods' 866 | ); 867 | $this->_getSessionDataCb = array( 868 | $this, '_getSessionDataMethods' 869 | ); 870 | break; 871 | default: 872 | $this->reportError( 873 | 'session.unsupported', 874 | 'Unsupported session handler specified: "' . 875 | $this->sessionHandler . 876 | '"' 877 | ); 878 | break; 879 | } 880 | $this->isSessionInitialized = true; 881 | } 882 | } 883 | 884 | /** 885 | * Set session flash data 886 | * 887 | * Routes to the appropriate underlying session handler implementation. 888 | */ 889 | function _setSessionFlashData($key, $value = null) { 890 | if ( ! $this->allowFlash ) { 891 | return $this->_setSessionData($key, $value); 892 | } 893 | $this->_initSession(); 894 | return call_user_func($this->_setSessionFlashDataCb, $key, $value); 895 | } 896 | /** 897 | * Set session data 898 | * 899 | * Routes to the appropriate underlying session handler implementation. 900 | */ 901 | function _setSessionData($key, $value = null) { 902 | $this->_initSession(); 903 | return call_user_func($this->_setSessionDataCb, $key, $value); 904 | } 905 | 906 | /** 907 | * Unset session data 908 | * 909 | * Routes to the appropriate underlying session handler implementation. 910 | */ 911 | function _unsetSessionData($key) { 912 | $this->_initSession(); 913 | return call_user_func($this->_unsetSessionDataCb, $key); 914 | } 915 | 916 | /** 917 | * Get session data 918 | * 919 | * Routes to the appropriate underlying session handler implementation. 920 | */ 921 | function _getSessionData($key) { 922 | $this->_initSession(); 923 | return call_user_func($this->_getSessionDataCb, $key); 924 | } 925 | 926 | /** 927 | * CodeIgniter implementation of _setSessionFlashData 928 | */ 929 | function _setSessionFlashDataCi($key, $value = null) { 930 | $CI =& get_instance(); 931 | return $CI->session->set_flashdata($key, $value); 932 | } 933 | 934 | /** 935 | * CodeIgniter implementation of _setSessionData 936 | */ 937 | function _setSessionDataCi($key, $value = null) { 938 | $CI =& get_instance(); 939 | return $CI->session->set_userdata($key, $value); 940 | } 941 | 942 | /** 943 | * CodeIgniter implementation of _unsetSessionData 944 | */ 945 | function _unsetSessionDataCi($key) { 946 | $CI =& get_instance(); 947 | return $CI->session->unset_userdata($key); 948 | } 949 | 950 | /** 951 | * CodeIgniter implementation of _getSessionData 952 | */ 953 | function _getSessionDataCi($key) { 954 | $CI =& get_instance(); 955 | return $CI->session->userdata($key); 956 | } 957 | 958 | /** 959 | * PHP Session implementation of _setSessionFlashData 960 | */ 961 | function _setSessionFlashDataPhp($key, $value = null) { 962 | throw new Exception('Set Session Flash Data for PHP not implemented.'); 963 | } 964 | 965 | /** 966 | * PHP Session implementation of _setSessionData 967 | */ 968 | function _setSessionDataPhp($key, $value = null) { 969 | throw new Exception('Set Session Data for PHP not implemented.'); 970 | } 971 | 972 | /** 973 | * PHP Session implementation of _unsetSessionData 974 | */ 975 | function _unsetSessionDataPhp($key) { 976 | throw new Exception('Unset Session Data for PHP not implemented.'); 977 | } 978 | 979 | /** 980 | * PHP Session implementation of _getSessionData 981 | */ 982 | function _getSessionDataPhp($key) { 983 | throw new Exception('Get Session Data for PHP not implemented.'); 984 | } 985 | 986 | /** 987 | * Callbacks Session implementation of _setSessionFlashData 988 | */ 989 | function _setSessionFlashDataCallbacks($key, $value = null) { 990 | throw new Exception( 991 | 'Set Session Flash Data for Callbacks not implemented.' 992 | ); 993 | } 994 | 995 | /** 996 | * Callbacks Session implementation of _setSessionData 997 | */ 998 | function _setSessionDataCallbacks($key, $value = null) { 999 | throw new Exception('Set Session Data for Callbacks not implemented.'); 1000 | } 1001 | 1002 | /** 1003 | * Callbacks Session implementation of _unsetSessionData 1004 | */ 1005 | function _unsetSessionDataCallbacks($key) { 1006 | throw new Exception( 1007 | 'Unset Session Data for Callbacks not implemented.' 1008 | ); 1009 | } 1010 | 1011 | /** 1012 | * Callbacks Session implementation of _getSessionData 1013 | */ 1014 | function _getSessionDataCallbacks($key) { 1015 | throw new Exception('Get Session Data for Callbacks not implemented.'); 1016 | } 1017 | 1018 | /** 1019 | * Methods Session implementation of _setSessionFlashData 1020 | */ 1021 | function _setSessionFlashDataMethods($key, $value = null) { 1022 | throw new Exception( 1023 | 'Set Session Flash Data for Methods not implemented.' 1024 | ); 1025 | } 1026 | 1027 | /** 1028 | * Methods Session implementation of _setSessionData 1029 | */ 1030 | function _setSessionDataMethods($key, $value = null) { 1031 | throw new Exception('Set Session Data for Methods not implemented.'); 1032 | } 1033 | 1034 | /** 1035 | * Methods Session implementation of _unsetSessionData 1036 | */ 1037 | function _unsetSessionDataMethods($key) { 1038 | throw new Exception('Unset Session Data for Methods not implemented.'); 1039 | } 1040 | 1041 | /** 1042 | * Methods Session implementation of _getSessionData 1043 | */ 1044 | function _getSessionDataMethods($key) { 1045 | throw new Exception('Get Session Data for Methods not implemented.'); 1046 | } 1047 | 1048 | /** 1049 | * Find and decode auth ticket from request 1050 | */ 1051 | function _findAndDecodeAuthTicket() { 1052 | 1053 | $CI =& get_instance(); 1054 | 1055 | $input = $CI->input; 1056 | 1057 | $key = $this->ticketParamName; 1058 | 1059 | // This little IF block is designed to find the first 1060 | // place that the specified key exists and then break. 1061 | // If we get through all three input sources and still 1062 | // do not have any auth string, we return NULL so that 1063 | // the calller knows that we were not able to validate 1064 | // auth. 1065 | if ( ! ( 1066 | ( ( $authString = $input->get($key) ) != "" ) or 1067 | ( ( $authString = $input->post($key) ) != "" ) or 1068 | ( ( $authString = $input->cookie($key) ) != "" ) 1069 | ) ) { 1070 | return NULL; 1071 | } 1072 | 1073 | $authTicket = $this->decodeAuthTicket($authString); 1074 | if ( $authTicket === null ) { 1075 | // We found an auth string but it is invalid! We should 1076 | // make sure that nobody tries this funny business 1077 | // again! 1078 | $this->invalidateAuthTicketCookie(); 1079 | } 1080 | return $authTicket; 1081 | 1082 | } 1083 | 1084 | /** 1085 | * Generate a digest for the specified data and expiration time 1086 | * @param string $data Data 1087 | * @param int $time Expiration time 1088 | * @return string 1089 | */ 1090 | function _generateDigest($data, $time) { 1091 | return sha1( $time . $data . $this->ticketSecret ); 1092 | } 1093 | 1094 | } 1095 | 1096 | ?> 1097 | --------------------------------------------------------------------------------