Changeset 1439

Show
Ignore:
Timestamp:
01/27/10 18:12:30 (3 years ago)
Author:
gbastien
Message:

* Added more complete auth functionnality to the web service (documentation will follow but the header comment of /ws/WifidogWS/V1.php contains a bit)
* Added the function generateConnectionTokenNoSession in the User class so that we can now generate tokens through the web service, without session variables.

Location:
trunk/wifidog-auth/wifidog
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/wifidog-auth/wifidog/classes/User.php

    r1438 r1439  
    702702        return $retval; 
    703703    } 
     704     
     705    /** Generate a token in the connection table so the user can actually use the internet 
     706    @return true on success, false on failure 
     707    */ 
     708    function generateConnectionTokenNoSession($node, $node_ip = null, $mac = null ) { 
     709        if ($this->isUserValid()) { 
     710            $db = AbstractDb::getObject(); 
     711             
     712            $token = self :: generateToken(); 
     713            if ($node_ip && $node) { 
     714                //echo "$session && $node_ip && {$session->get(SESS_NODE_ID_VAR)}"; 
     715                $node_id = $node->getId(); 
     716                $abuseControlFault = User::isAbuseControlViolated($this, $mac, $node); 
     717                if($abuseControlFault) { 
     718                    throw new Exception ($abuseControlFault); 
     719                } 
     720                $mac = (is_null($mac)?'': $db->escapeString($mac)); 
     721                /* 
     722                 * Delete all unused tokens for this user, so we don't fill the database 
     723                 * with them 
     724                 */ 
     725                $sql = "DELETE FROM connections USING tokens "."WHERE tokens.token_id=connections.token_id AND token_status='".TOKEN_UNUSED."' AND user_id = '".$this->getId()."';\n"; 
     726                // TODO:  Try to find a reusable token before creating a brand new one! 
     727 
     728                $sql .= "INSERT INTO tokens (token_owner, token_issuer, token_id, token_status) VALUES ('" . $this->getId() . "', '" . $this->getId() . "', '$token', '" . TOKEN_UNUSED . "');\n"; 
     729                $sql .= "INSERT INTO connections (user_id, token_id, timestamp_in, node_id, node_ip, last_updated, user_mac) VALUES ('" . $this->getId() . "', '$token', CURRENT_TIMESTAMP, '$node_id', '$node_ip', CURRENT_TIMESTAMP, '$mac')"; 
     730                $db->execSqlUpdate($sql, false); 
     731                $retval = $token; 
     732            } 
     733            else { 
     734                $retval = false; 
     735            } 
     736        } 
     737        else { 
     738            $retval = false; 
     739        } 
     740        return $retval; 
     741    } 
    704742 
    705743    function setPassword($password) { 
  • trunk/wifidog-auth/wifidog/ws/classes/Exceptions/WSException.php

    r1427 r1439  
    5050class WSException extends Exception 
    5151{ 
     52    CONST INVALID_PARAMETER = 8801; 
     53    CONST GENERIC_EXCEPTION = 8800; 
     54    CONST PROCESS_ERROR = 8802; 
     55     
    5256    // Redefine the exception so message isn't optional 
    53     public function __construct($message, $code = 0) { 
     57    public function __construct($message, $code = 8800) { 
    5458        // some code 
    5559    
  • trunk/wifidog-auth/wifidog/ws/classes/WifidogWS/V1.php

    r1427 r1439  
    4343 * Web service V1 class 
    4444 * 
    45  * Actions are: 
     45 * mandatory parameters: 
     46 * action: get|list|auth 
     47 * 
     48 * Each action has its own set of parameters: 
     49 *  
    4650 * get: get some information concerning a given object, identified by its id 
     51 *              parameters: object_class  The class of the object to get 
     52 *               object_id  The id of the object 
     53 *               fields  The list of fields to fetch (absent: all the allowed fields) 
     54 *               id_type (o)  Not used yet 
     55 *                
    4756 * list: get some informations concerning a list of objects 
    48  * auth: verify the users credential.  
     57 *    parameters:  object_class The class of objects to list 
     58 *               fields   The fields to list for each object 
     59 *               parent_class (o)  The class of the parent object (for the nodes of a network, the class would be network) 
     60 *               parent_id (o)  The id of the parent object 
     61 *                
     62 * auth: verify the users credential. And in part authenticate the user 
     63 *    parameters: username  The username to authenticate 
     64 *               password   The password 
     65 *               gw_id (o)  The gateway id if the request comes from a gateway 
     66 *               gw_address (o)  The gateway address as sent in the original request from gateway 
     67 *               gw_port (o)  The gateway port as sent from the original request from gateway 
     68 *               from_ip (o)  The ip of the user, as can be got from the $_SERVER['REMOTE_ADDR'] variable 
     69 *               mac (o)  The user mac as sent in the original request from gateway 
    4970 *     NOTE: This action DOES NOT authenticate the user on the gateway and hence, DOES NOT grant access to the internet. 
    5071 *           There is an authentication protocol that needs to be respected (http://dev.wifidog.org/wiki/doc/developer/WiFiDogProtocol_V1) 
    51  *           An authentication token must be generated and the response redirects to the gateway's auth server that redirects to the portal page 
     72 *           However, this action will return the url that should be used as a next step of this protocol, so the calling system may do what it must 
    5273 * 
    5374 * @package    WiFiDogAuthServer 
     
    125146    } 
    126147     
     148    protected function mapFields($objectClass, $infields = array()) { 
     149        $fields = array()   ;     
     150        foreach($infields as $field) { 
     151            if (isset(self::$_allowedFields[$objectClass][$field])) 
     152                $fields[] = self::$_allowedFields[$objectClass][$field]; 
     153            else 
     154                $fields[] = "$field.forbidden"; 
     155        } 
     156        return $fields; 
     157    } 
     158     
    127159    /** 
    128160     * This function executes the action requested by the web service 
     
    132164    protected function executeAction() { 
    133165        if (!isset($this->_action)) { 
    134             throw new WSException("No action was specified.  Please use GET parameter 'action=list|get|auth' to specify an action");  
     166            throw new WSException("No action was specified.  Please use GET parameter 'action=list|get|auth' to specify an action", WSException::INVALID_PARAMETER);  
    135167        } 
    136168        switch($this->_action) { 
     
    151183            case 'auth': 
    152184                $gw_id = (isset($this->_params['gw_id']) ? $this->_params['gw_id']:null); 
    153                 $gw_ip = (isset($this->_params['gw_ip']) ? $this->_params['gw_ip']:null); 
     185                $gw_address = (isset($this->_params['gw_address']) ? $this->_params['gw_address']:null); 
     186                $gw_port = (isset($this->_params['gw_port']) ? $this->_params['gw_port']:null); 
     187                $mac = (isset($this->_params['mac']) ? $this->_params['mac']:null); 
     188                $from = (isset($this->_params['from_ip']) ? $this->_params['from_ip']:null); 
    154189                $username = (isset($this->_params['username']) ? $this->_params['username']:''); 
    155190                $password = (isset($this->_params['password']) ? $this->_params['password']:''); 
    156                 $this->executeAuth($username, $password, $gw_id, $gw_ip); 
     191                $this->executeAuth($username, $password, $gw_id, $gw_address, $mac, $gw_port, $from); 
    157192                break; 
    158193            default: 
    159                 throw new WSException("Action {$this->_action} is not defined.  Please use GET parameter 'action=list|get|auth' to specify an action"); 
     194                throw new WSException("Action {$this->_action} is not defined.  Please use GET parameter 'action=list|get|auth' to specify an action", WSException::INVALID_PARAMETER); 
    160195                break; 
    161196        } 
     
    171206     * @return unknown_type 
    172207     */ 
    173     protected function executeAuth($username = null, $password = null, $gw_id = null, $gw_ip = null) { 
     208    protected function executeAuth($username = null, $password = null, $gw_id = null, $gw_ip = null, $mac = null, $gw_port = null, $from = null) { 
    174209        $this->_outputArr['auth'] = 0; 
    175210         
     
    180215         
    181216        if (!is_null($gw_id)) { 
    182             if (is_null($gw_ip)) { 
    183                 throw new WSException("Missing information on the gateway.  Must specify parameter 'gw_ip' if there is a gateway id."); 
     217            if (is_null($gw_ip) || is_null($gw_port) || is_null($from)) { 
     218                throw new WSException("Missing information on the gateway.  You must specify parameter 'gw_address' AND 'gw_port' AND 'from_ip' if the parameter 'gw_id' is specified.", WSException::INVALID_PARAMETER); 
    184219            } 
    185220            $node = Node::getObjectByGatewayId($gw_id); 
     
    187222                $network = $node->getNetwork(); 
    188223            } else { 
    189                 throw new WSException("Node identified by $gw_id cannot be found"); 
     224                throw new WSException("Node identified by $gw_id cannot be found", WSException::PROCESS_ERROR); 
    190225            } 
    191226        } else { 
     
    198233         * If this is a splash-only node, then the user is automatically authenticated 
    199234         */ 
     235        $token = null; 
    200236        if (!empty($node) && $node->isSplashOnly()) { 
    201237            $this->_outputArr['auth'] = 1; 
    202238            $user = $network->getSplashOnlyUser(); 
     239            $token = $user->generateConnectionTokenNoSession($node, $from, $mac); 
     240            if (!$token) throw new WSException("User authenticated but cannot generate connection token.", WSException::PROCESS_ERROR); 
    203241        } else { 
    204242            // Authenticate the user on the requested network 
     
    209247            } else { 
    210248                $this->_outputArr['auth'] = 1; 
    211             } 
     249                if (!is_null($node)) { 
     250                    $token = $user->generateConnectionTokenNoSession($node, $from, $mac); 
     251                    
     252                    if (!$token) throw new WSException("User authenticated but cannot generate connection token.", WSException::PROCESS_ERROR); 
     253                } 
     254            } 
     255        } 
     256        if ($this->_outputArr['auth'] == 1 && !is_null($token)) { 
     257            $this->_outputArr['forwardTo'] = "http://" . $gw_ip . ":" . $gw_port . "/wifidog/auth?token=" . $token; 
    212258        } 
    213259    } 
     
    222268    protected function executeGet($objectClass, $objectId, $fields = array(), $idtype = null) { 
    223269        if (is_null($objectClass)) { 
    224             throw new WSException("Missing parameter 'object_class' in the request."); 
     270            throw new WSException("Missing parameter 'object_class' in the request.", WSException::INVALID_PARAMETER); 
    225271        } 
    226272        if (is_null($objectId)) { 
    227             throw new WSException("Missing parameter 'object_id' in the request."); 
     273            throw new WSException("Missing parameter 'object_id' in the request.", WSException::INVALID_PARAMETER); 
    228274        } 
    229275        if (!in_array($objectClass,self::$_allowedObjectClass)) { 
    230             throw new WSException("Wrong object class '{$objectClass}' requested.  Possible values are " . implode(', ', self::$_allowedObjectClass)); 
     276            throw new WSException("Wrong object class '{$objectClass}' requested.  Possible values are " . implode(', ', self::$_allowedObjectClass), WSException::INVALID_PARAMETER); 
    231277        } 
    232278         
     
    247293        // IF the object still is not found, then return an error 
    248294        if (is_null($object)) { 
    249             throw new WSException("Object of class {$objectClass} with id {$objectId} not found"); 
     295            throw new WSException("Object of class {$objectClass} with id {$objectId} not found", WSException::PROCESS_ERROR); 
    250296        } 
    251297   
     298        $fields = $this->mapFields($objectClass, $fields); 
    252299        if (empty($fields)) { 
    253300            $fields = array_keys(self::$_allowedFields[$objectClass]); 
     
    255302        $allowedFields = self::$_allowedFields[$objectClass]; 
    256303         
     304        $this->_outputArr = self::filterRet($object, $fields); 
     305        /* 
    257306        foreach($fields as $field) { 
    258307            if (isset($allowedFields[ucfirst(strtolower($field))])) { 
     
    268317            } 
    269318        } 
    270          
     319        */ 
    271320         
    272321    } 
     
    282331    protected function executeList($objectClass, $fields = array(), $parentClass = null, $parentId = null) { 
    283332        if (is_null($objectClass)) { 
    284             throw new WSException("Missing parameter 'object_class' in the request."); 
     333            throw new WSException("Missing parameter 'object_class' in the request.", WSException::INVALID_PARAMETER); 
    285334        } 
    286335        if (!in_array($objectClass,self::$_allowedObjectClass)) { 
    287             throw new WSException("Wrong object class '{$objectClass}' requested.  Possible values are " . implode(', ', self::$_allowedObjectClass)); 
     336            throw new WSException("Wrong object class '{$objectClass}' requested.  Possible values are " . implode(', ', self::$_allowedObjectClass), WSException::INVALID_PARAMETER); 
    288337        } 
    289338         
     
    294343            if (!is_null($parentId)) { 
    295344                if (!in_array($parentClass,self::$_allowedObjectClass)) { 
    296                     throw new WSException("Wrong parent class '{$parentClass}' specified.  Possible values are " . implode(', ', self::$_allowedObjectClass)); 
     345                    throw new WSException("Wrong parent class '{$parentClass}' specified.  Possible values are " . implode(', ', self::$_allowedObjectClass), WSException::INVALID_PARAMETER); 
    297346                } 
    298347                include_once('classes/'.$parentClass.'.php'); 
    299348                $parentObject = call_user_func($parentClass.'::getObject', $parentId); 
    300349            } else { 
    301                 throw new WSException("If parent class is specified, must specify 'parent_id'"); 
     350                throw new WSException("If parent class is specified, must specify 'parent_id'", WSException::INVALID_PARAMETER); 
    302351            } 
    303352        } 
     
    308357            } 
    309358        } 
     359        $fields = $this->mapFields($objectClass, $fields); 
    310360        if (empty($fields)) { 
    311361            $fields = self::$_allowedFields[$objectClass]; 
    312         } 
     362        }  
    313363 
    314364        $this->_outputArr = self::filterRet($objectList, $fields); 
     
    326376        } 
    327377        $filtered = array(); 
     378 
    328379        foreach($retVals as $key => $value) { 
    329380            // If the return is one object we filter, return only the allowed fields 
     
    339390                    $retFields = array(); 
    340391                    foreach ($fields as $field) { 
    341                         $methodName = 'get'.$field; 
    342                         if (method_exists($value, $methodName)) { 
    343                             $retFields[$field] = self::filterRet($value->$methodName()); 
    344                         } else { 
    345                             $retFields[$field] = 'unknown'; 
    346                         } 
     392                        $forbiddenfield = explode(".", $field); 
     393                        if (! (count($forbiddenfield) == 2)) { 
     394                            $methodName = 'get'.$field; 
     395                            if (method_exists($value, $methodName)) { 
     396                                 
     397                                $retFields[$field] = self::filterRet($value->$methodName()); 
     398                            } else { 
     399                                $retFields[$field] = 'unknown'; 
     400                            } 
     401                        } else 
     402                            $retFields[$forbiddenfield[0]] = 'Not allowed'; 
    347403                    } 
    348404                    $filtered[] = $retFields; 
  • trunk/wifidog-auth/wifidog/ws/index.php

    r1427 r1439  
    9595    $exceptionClass = get_class($e); 
    9696    if (!is_null($output)) { 
    97         echo $output->outputError(array('type' => $exceptionClass,  
     97        if ($exceptionClass == 'WSException') { 
     98            echo $output->outputError(array('type' => $exceptionClass,  
     99                                    'message' => sprintf(_("Web service exception:  %s (%s)"), $e->getMessage(), $e->getCode()))); 
     100        } else 
     101            echo $output->outputError(array('type' => $exceptionClass,  
    98102                                    'message' => sprintf(_("Detailed error was:  Uncaught %s %s (%s) thrown in file %s, line %d"),get_class($e), $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine()))); 
    99103    } else { 
    100         echo sprintf(_("Detailed error was:  Uncaught %s %s (%s) thrown in file %s, line %d"),get_class($e), $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine()); 
     104        if ($exceptionClass == 'WSException') { 
     105            echo sprintf(_("Web service exception:  %s => %s (%s)"),get_class($e), $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine()); 
     106        } else 
     107            echo sprintf(_("Detailed error was:  Uncaught %s %s (%s) thrown in file %s, line %d"),get_class($e), $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine()); 
    101108    } 
    102109