1<?php 2 /** 3 * Base include file for SimpleTest 4 * @package SimpleTest 5 * @subpackage WebTester 6 * @version $Id: authentication.php,v 1.1 2005/11/09 23:41:18 gsmet Exp $ 7 */ 8 /** 9 * include http class 10 */ 11 require_once(dirname(__FILE__) . '/http.php'); 12 13 /** 14 * Represents a single security realm's identity. 15 * @package SimpleTest 16 * @subpackage WebTester 17 */ 18 class SimpleRealm { 19 var $_type; 20 var $_root; 21 var $_username; 22 var $_password; 23 24 /** 25 * Starts with the initial entry directory. 26 * @param string $type Authentication type for this 27 * realm. Only Basic authentication 28 * is currently supported. 29 * @param SimpleUrl $url Somewhere in realm. 30 * @access public 31 */ 32 function SimpleRealm($type, $url) { 33 $this->_type = $type; 34 $this->_root = $url->getBasePath(); 35 $this->_username = false; 36 $this->_password = false; 37 } 38 39 /** 40 * Adds another location to the realm. 41 * @param SimpleUrl $url Somewhere in realm. 42 * @access public 43 */ 44 function stretch($url) { 45 $this->_root = $this->_getCommonPath($this->_root, $url->getPath()); 46 } 47 48 /** 49 * Finds the common starting path. 50 * @param string $first Path to compare. 51 * @param string $second Path to compare. 52 * @return string Common directories. 53 * @access private 54 */ 55 function _getCommonPath($first, $second) { 56 $first = explode('/', $first); 57 $second = explode('/', $second); 58 for ($i = 0; $i < min(count($first), count($second)); $i++) { 59 if ($first[$i] != $second[$i]) { 60 return implode('/', array_slice($first, 0, $i)) . '/'; 61 } 62 } 63 return implode('/', $first) . '/'; 64 } 65 66 /** 67 * Sets the identity to try within this realm. 68 * @param string $username Username in authentication dialog. 69 * @param string $username Password in authentication dialog. 70 * @access public 71 */ 72 function setIdentity($username, $password) { 73 $this->_username = $username; 74 $this->_password = $password; 75 } 76 77 /** 78 * Accessor for current identity. 79 * @return string Last succesful username. 80 * @access public 81 */ 82 function getUsername() { 83 return $this->_username; 84 } 85 86 /** 87 * Accessor for current identity. 88 * @return string Last succesful password. 89 * @access public 90 */ 91 function getPassword() { 92 return $this->_password; 93 } 94 95 /** 96 * Test to see if the URL is within the directory 97 * tree of the realm. 98 * @param SimpleUrl $url URL to test. 99 * @return boolean True if subpath. 100 * @access public 101 */ 102 function isWithin($url) { 103 return (strpos($url->getBasePath(), $this->_root) === 0); 104 } 105 } 106 107 /** 108 * Manages security realms. 109 * @package SimpleTest 110 * @subpackage WebTester 111 */ 112 class SimpleAuthenticator { 113 var $_realms; 114 115 /** 116 * Clears the realms. 117 * @access public 118 */ 119 function SimpleAuthenticator() { 120 $this->restartSession(); 121 } 122 123 /** 124 * Starts with no realms set up. 125 * @access public 126 */ 127 function restartSession() { 128 $this->_realms = array(); 129 } 130 131 /** 132 * Adds a new realm centered the current URL. 133 * Browsers vary wildly on their behaviour in this 134 * regard. Mozilla ignores the realm and presents 135 * only when challenged, wasting bandwidth. IE 136 * just carries on presenting until a new challenge 137 * occours. SimpleTest tries to follow the spirit of 138 * the original standards committee and treats the 139 * base URL as the root of a file tree shaped realm. 140 * @param SimpleUrl $url Base of realm. 141 * @param string $type Authentication type for this 142 * realm. Only Basic authentication 143 * is currently supported. 144 * @param string $realm Name of realm. 145 * @access public 146 */ 147 function addRealm($url, $type, $realm) { 148 $this->_realms[$url->getHost()][$realm] = new SimpleRealm($type, $url); 149 } 150 151 /** 152 * Sets the current identity to be presented 153 * against that realm. 154 * @param string $host Server hosting realm. 155 * @param string $realm Name of realm. 156 * @param string $username Username for realm. 157 * @param string $password Password for realm. 158 * @access public 159 */ 160 function setIdentityForRealm($host, $realm, $username, $password) { 161 if (isset($this->_realms[$host][$realm])) { 162 $this->_realms[$host][$realm]->setIdentity($username, $password); 163 } 164 } 165 166 /** 167 * Finds the name of the realm by comparing URLs. 168 * @param SimpleUrl $url URL to test. 169 * @return SimpleRealm Name of realm. 170 * @access private 171 */ 172 function _findRealmFromUrl($url) { 173 if (! isset($this->_realms[$url->getHost()])) { 174 return false; 175 } 176 foreach ($this->_realms[$url->getHost()] as $name => $realm) { 177 if ($realm->isWithin($url)) { 178 return $realm; 179 } 180 } 181 return false; 182 } 183 184 /** 185 * Presents the appropriate headers for this location. 186 * @param SimpleHttpRequest $request Request to modify. 187 * @param SimpleUrl $url Base of realm. 188 * @access public 189 */ 190 function addHeaders(&$request, $url) { 191 if ($url->getUsername() && $url->getPassword()) { 192 $username = $url->getUsername(); 193 $password = $url->getPassword(); 194 } elseif ($realm = $this->_findRealmFromUrl($url)) { 195 $username = $realm->getUsername(); 196 $password = $realm->getPassword(); 197 } else { 198 return; 199 } 200 $this->addBasicHeaders($request, $username, $password); 201 } 202 203 /** 204 * Presents the appropriate headers for this 205 * location for basic authentication. 206 * @param SimpleHttpRequest $request Request to modify. 207 * @param string $username Username for realm. 208 * @param string $password Password for realm. 209 * @access public 210 * @static 211 */ 212 function addBasicHeaders(&$request, $username, $password) { 213 if ($username && $password) { 214 $request->addHeaderLine( 215 'Authorization: Basic ' . base64_encode("$username:$password")); 216 } 217 } 218 } 219?>