Login   Register  
PHP Classes
elePHPant
Icontem

File: multiotp.cli.header.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of André Liechti  >  Multi-OTP PHP class  >  multiotp.cli.header.php  >  Download  
File: multiotp.cli.header.php
Role: Example script
Content type: text/plain
Description: Special cli header in order to create the command line tool
Class: Multi-OTP PHP class
Authenticate and manage OTP strong user tokens
Author: By
Last change: Now it is possible to import PSKC Algorithm Profiles containing tokens definition for TOTP and HOTP algorithm. Thus, creating a user and attributing a token is easier. You only need to give the name of the user, the token id and the desired pin code of the user.

The multiotp-database-format flat file has been enhanced to version 3. Regular attributes are written attribute=value and encrypted attributes are now written encrypted_attribute:=encrypted_value. If you want to set a new pin for a user, you can open the file of the user and change the line user_pin:=ACQwJw== by user_pin=1234. The new value will be correctly read the next time, and encrypted again the next time something is written in the file.

In debug mode, the command line version is now returning a text information after the exit code.
Date: 2010-09-02 14:06
Size: 22,310 bytes
 

Contents

Class file image Download
<?php

/*********************************************************************
 *
 * MultiOTP PHP CLI header - Strong two-factor authentication PHP class
 * http://www.multiotp.net
 *
 * Donation are always welcome! Please check http://www.multiotp.net
 * and you will find the magic button ;-)
 *
 * If the name of this file is multiotp.php, it means that it is already
 * the result of the merge of the two files multiotp.cli.header.php and
 * multiotp.class.php
 *
 * The MultiOTP PHP CLI header is simply merged with the MultiOTP PHP
 * class in order to provide an authentication command line script.
 *
 * This script can be used as an external authentication provider with at
 * least the following RADIUS servers:
 *  - TekRADIUS, a free Radius server for Windows with MS-SQL backend
 *    (http:/www.tekradius.com)
 *  - TekRADIUS LT, a free Radius server for Windows with SQLite backend
 *    (http:/www.tekradius.com)
 *  - FreeRADIUS, a free Radius server implementation for Linux
 *    and *nix environments (http://freeradius.org)
 *
 * For Windows, you can also use the multiotp.exe file provided, which is
 * an embedded PHP interpreter together with the result of the merge.
 *
 *
 * LICENCE
 *
 *   Copyright (c) 2010, SysCo systemes de communication sa
 *   SysCo (tm) is a trademark of SysCo systemes de communication sa
 *   (http://www.sysco.ch)
 *   All rights reserved.
 * 
 *   This file is part of the MultiOTP PHP class
 *
 *   MultiOTP PHP class is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public License as
 *   published by the Free Software Foundation, either version 3 of the License,
 *   or (at your option) any later version.
 * 
 *   MultiOTP PHP class is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 * 
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with MultiOTP PHP class.
 *   If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * @author: SysCo/al
 * @since CreationDate: 2010-06-08
 * @copyright (c) 2010 by SysCo systemes de communication sa
 * @version $LastChangedRevision: 3.0.0 $
 * @version $LastChangedDate: 2010-09-02 $
 * @version $LastChangedBy: SysCo/al $
 * @link $HeadURL: multiotp.cli.header.php $
 * @link http://www.multiotp.net
 * @link developer@sysco.ch
 * Language: PHP 4.4.4 or higher
 *
 *
 * Command line usage
 *
 *   Type multiotp -help to have the full description of the options,
 *    and have a look at the readme.txt file for enhanced explanations
 *
 *
 * Return codes
 *
 *   0 OK: Token accepted
 *  11 INFO: User successfully created or updated
 *  12 INFO: User successfully deleted
 *  13 INFO: User PIN code successfully changed
 *  14 INFO: Token has been resynchronized successfully
 *  15 INFO: XML tokens definition file successfully imported
 *  19 INFO: Requested operation successfully done
 *  21 ERROR: User doesn't exist
 *  22 ERROR: User already exists
 *  23 ERROR: Invalid algorithm
 *  24 ERROR: User locked (too many tries)
 *  25 ERROR: User delayed (too many tries, but still a hope in a few minutes)
 *  26 ERROR: The time based token has already been used
 *  27 ERROR: Resynchronization of the token has failed
 *  28 ERROR: Unable to write the changes in the file
 *  29 ERROR: Token doesn't exist
 *  30 ERROR: At least one parameter is missing
 *  31 ERROR: XML tokens definition file doesn't exist
 *  32 ERROR: XML tokens definition file not successfully imported
 *  99 ERROR: Authentication failed (and other possible unknown errors)
 *
 *
 * Radius integration examples
 *
 *   Example 1 (TekRADIUS or TekRADIUS LT under Windows)
 *
 *     TekRADIUS supports a Default Username to be used when a matching user
 *     profile cannot be found for an incoming RADIUS authentication request.
 *     So a quick and easy way is to create in the TekRADIUS Manager a User
 *     named 'Default' that belongs to the existing 'Default' Group.
 *     Then add to this Default user the following attribute :
 *     Check  External-Executable  C:\multitop\multiotp.exe %ietf|1% %ietf|2%
 *
 *
 *   Example 2 (FreeRADIUS under Linux)
 *
 *     Define a DEFAULT entry in the /etc/freeradius/users file like this:
 *     DEFAULT Auth-Type = Accept
 *     Exec-Program-Wait = "/usr/local/bin/multiotp.php %{User-Name} %{User-Password}",
 *     Fall-Through = Yes,
 *     Reply-Message = "Hello, %{User-Name}"
 *
 *
 * External files created
 *
 *   Users database files in the subfolder called users
 *   Tokens database files in the subfolder called tokens
 *
 *
 * External file needed
 *
 *   Users database files in the subfolder called users
 *   Tokens database files in the subfolder called tokens
 *
 *
 * Special issues
 *
 *   If you need specific developements concerning strong authentication,
 *   do not hesistate to contact us per email at developer@sysco.ch.
 *
 *
 * Users feedbacks and comments
 *
 * 2010-08-20 BirdNet, C. Christophi
 *   Documentation enhancement proposal for the TekRADIUS part, thanks !
 *
 *
 * Change Log
 *
 *   2010-09-02 3.0.0  SysCo/al Adding tokens handling support, including importing XML tokens definition file
 *                              Enhanced flat database file format (multiotp is still compatible with old formats)
 *                              Internal method SetDataReadFlag renamed to SetUserDataReadFlag
 *                              Internal method GetDataReadFlag renamed to GetUserDataReadFlag
 *   2010-08-21 2.0.4  SysCo/al Enhancement in order to use an alternate php "compiler" for Windows command line
 *                              Documentation enhancement
 *   2010-08-18 2.0.3  SysCo/al Minor notice fix, define timezone if not defined (for embedded command line)
 *                              If user doesn't exist, do not create the related flat file after a check
 *   2010-07-21 2.0.2  SysCo/al Fix to create correctly the folders "uaers" and "log" if needed
 *   2010-07-19 2.0.1  SysCo/al Adding more information in the help text
 *   2010-07-19 2.0.0  SysCo/al New design using a class and a cli header stub
 *   2010-06-15 1.1.5  SysCo/al Adding OATH/TOTP support
 *   2010-06-15 1.1.4  SysCo/al Project renamed to multiotp to avoid overlapping
 *   2010-06-08 1.1.3  SysCo/al Typo in script folder detection
 *   2010-06-08 1.1.2  SysCo/al Typo in variable name
 *   2010-06-08 1.1.1  SysCo/al Status bar during resynchronization
 *   2010-06-08 1.1.0  SysCo/al Fix in the example, distribution not compressed
 *   2010-06-07 1.0.0  SysCo/al Initial implementation
 *
 *********************************************************************/

 
// Trick to have mostly the correct timezone in embedded command line version
// and to avoid error messages when using time functions

if (function_exists("date_default_timezone_get"))
{
    $actual_timezone = @date_default_timezone_get();
    if (function_exists("date_default_timezone_set"))
    {
        @date_default_timezone_set($actual_timezone);
    }
}


// Be sure that STDIN, STDOUT and STDERR are defined correctly for command line edition
if (!defined('STDIN'))
{
    define(STDIN, fopen('php://stdin', 'r'));
}
if (!defined('STDOUT'))
{
    define(STDOUT, fopen('php://stdout', 'w'));
}
if (!defined('STDERR'))
{
    define(STDERR, fopen('php://stderr', 'w'));
}


// Create a new Multiotp object
// The log and users subfolders are set by default under the folder of the script
$multiotp = new Multiotp();


// Set a specific encryption key for the tokens and users files
$multiotp->SetEncryptionKey('DefaultCliEncryptionKey');

// Initialize some variables
$command           = "check";
$display_help      = FALSE;
$display_status    = FALSE;
$prefix_pin        = FALSE;
$crlf              = chr(13).chr(10);
$result            = 99; // Unknown error
$token_id_creation = FALSE;

 
// Extract all parameters
$param_count = 0;
$all_args = array();

for ($arg_loop=1; $arg_loop <= $_SERVER["argc"]-1; $arg_loop++)
{
    if ("-check" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "check";
    }
    elseif ("-create" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "create";
    }
    elseif ("-debug" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $multiotp->EnableVerboseLog();
    }
    elseif ("-delete" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "delete";
    }
    elseif ("-help" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "help";
    }
    elseif ("-import-xml" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "import-xml";
    }
    elseif ("-log" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $multiotp->EnableLog();
    }
    elseif ("-no-prefix-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $prefix_pin = FALSE;
    }
    elseif ("-prefix-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $prefix_pin = TRUE;
    }
    elseif ("-resync" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "resync";
    }
    elseif ("-status" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $display_status = TRUE;
    }
    elseif ("-token-id" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $token_id_creation = TRUE;
    }
    elseif ("-update" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "update";
    }
    elseif ("-update-pin" == strtolower($_SERVER["argv"][$arg_loop]))
    {
        $command = "update-pin";
    }
    elseif (("-version" == strtolower($_SERVER["argv"][$arg_loop])) || ("-v" == strtolower($_SERVER["argv"][$arg_loop])))
    {
        $command = "version";
    }
    else
    {
        $param_count++;
        $all_args[$param_count] = $_SERVER["argv"][$arg_loop];
    }
}

// Be sure that inexistant parameters are empty
for ($i = ($param_count+1); $i <= 20; $i++)
{
    $all_args[$i] = "";
}

// if not enough parameters, display help
if (($param_count < 1) && ($command != "version"))
{    $command = "help";
}

switch ($command)
{
    case "version":
        echo "multiotp ".$multiotp->GetVersion()." (".$multiotp->GetDate().")".$crlf;
        $result = 19;
        break;
    case "check";
        if  ($param_count < 2)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 22; // ERROR: user doesn't exist.
        }
        else
        {
            $result = $multiotp->CheckToken($all_args[2]); // Result provided by the MultiOTP class
        }
        break;
    case "create":
    case "update":
        if (("create" == $command) && $multiotp->ReadUserData($all_args[1], TRUE))
        {
            $result = 22; // ERROR: user already exists.
        }
        elseif (("update" == $command) && (!$multiotp->ReadUserData($all_args[1])))
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        elseif  ($param_count < 3)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        else
        {
            $multiotp->SetUser($all_args[1]);
            $multiotp->SetUserPrefixPin($prefix_pin?1:0);
            
            if ($token_id_creation)
            {
                $key_id = $all_args[2];
                if (!$multiotp->ReadTokenData($key_id))
                {
                    $result = 29; // ERROR: token doesn't exist.
                }
                else
                {
                    $multiotp->SetUserKeyId($key_id);
                    if (!$multiotp->SetUserAlgorithm($multiotp->GetTokenAlgorithm()))
                    {
                        $result = 23; // ERROR: invalid algorithm
                    }
                    else
                    {
                        $multiotp->SetUserTokenSeed($multiotp->GetTokenSeed());
                        $multiotp->SetUserTokenNumberOfDigits($multiotp->GetTokenNumberOfDigits());
                        $multiotp->SetUserTokenTimeInterval($multiotp->GetTokenTimeInterval());
                        $multiotp->SetUserTokenLastEvent($multiotp->GetTokenLastEvent());
                        
                        $multiotp->SetUserPin($all_args[3]);
                        
                        if ($multiotp->WriteUserData())
                        {
                            $result = 11; // INFO: user successfully created or updated
                        }
                        else
                        {
                            $result = 28; // ERROR: Unable to write the changes in the file
                        }
                    }
                }
            }
            elseif (!$multiotp->SetUserAlgorithm($all_args[2]))
            {
                $result = 23; // ERROR: invalid algorithm
            }
            else
            {
                $multiotp->SetUserTokenSeed($all_args[3]);
                
                if  ($param_count < 4)
                {
                    $result = 30; // ERROR: At least one parameter is missing
                }
                else
                {
                    $multiotp->SetUserPin($all_args[4]);
                    if ("" == $all_args[5])
                    {
                        $all_args[5] = 6; // Default numnber of digits is set to 6
                    }
                    $multiotp->SetUserTokenNumberOfDigits($all_args[5]);
                    switch (strtoupper($all_args[2]))
                    {
                        // This is the time interval for mOTP
                        case "MOTP":
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 10; // Default windows value interval for mOTP
                            }
                            $multiotp->SetUserTokenTimeInterval($all_args[6]);
                            break;
                        // This is the time interval for TOTP
                        case "TOTP":
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 30; // Default windows value interval for TOTP
                            }
                            $multiotp->SetUserTokenTimeInterval($all_args[6]);
                            break;
                        // This is the next event for HOTP
                        case "HOTP":
                        default:
                            if ("" == $all_args[6])
                            {
                                $all_args[6] = 0; // Default next event
                            }
                            $multiotp->SetUserTokenLastEvent($all_args[6]-1);
                            // -1 because we are saving the last event in the user file database
                            break;
                    }
                    if ($multiotp->WriteUserData())
                    {
                        $result = 11; // INFO: user successfully created or updated
                    }
                    else
                    {
                        $result = 28; // ERROR: Unable to write the changes in the file
                    }
                }
            }
        }
        break;
    case "delete":
        $multiotp->SetUser($all_args[1]);
        if (!$multiotp->DeleteUser())
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        else
        {
            $result = 12; // INFO: user successfully deleted.
        }
        break;
    case "resync":
        if  ($param_count < 3)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 22; // ERROR: user doesn't exist.
        }
        else
        {
            $result = $multiotp->CheckToken($all_args[2], $all_args[3], $display_status); // Result provided by the MultiOTP class
        }
        break;
    case "update-pin":
        if  ($param_count < 2)
        {
            $result = 30; // ERROR: At least one parameter is missing
        }
        elseif (!$multiotp->ReadUserData($all_args[1]))
        {
            $result = 21; // ERROR: user doesn't exist.
        }
        else
        {
            $multiotp->SetUserPin($all_args[2]);
            if ($multiotp->WriteUserData())
            {
                $result = 13; // INFO: pin successfully changed
            }
        }
        break;
    case "import-xml":
        if (!file_exists($all_args[1]))
        {
            $result = 31; // ERROR: XML tokens definition file doesn't exist.
        }
        else
        {
            if ($multiotp->ImportTokensFromXml($all_args[1]))
            {
                $result = 15; // INFO: XML tokens definition file successfully imported
            }
            else
            {
                $result = 32; // ERROR: XML tokens definition file not successfully imported.
            }
        }
        break;
    default: // help or others
        echo "multiotp ".$multiotp->GetVersion()." (".$multiotp->GetDate().")".$crlf;
        echo $multiotp->GetCopyright().$crlf;
        echo $multiotp->GetWebsite().$crlf;
        echo $crlf;
        echo "multiotp will check if the token of a user is correct, based on a specified".$crlf;
        echo "algorithm (currently Mobile-OTP (http://motp.sf.net), OATH/HOTP (RFC 4226) ".$crlf;
		echo "and OATH/TOTP (HOTPTimeBased RFC 4226 extension) are implemented).".$crlf;
        echo $crlf;
        echo "If you are using the command line tool for Windows, be sure that the file".$crlf;
        echo "multiotp.php is not present in the directory, otherwise conflict may appears.".$crlf;
        echo $crlf;
        echo "If a token is locked (return code 24), you can resync the token to unlock.".$crlf;
        echo $crlf;
        echo "It will return 0 for a correct token, or an error code (11-99) otherwise.".$crlf;
        echo $crlf;
        echo "Return codes:".$crlf;
        
        reset($multiotp->_errors_text);
        while(list($key, $value) = each($multiotp->_errors_text))
        {
            echo substr('  '.$key,-2)." ".$value.$crlf;
        }
        echo $crlf;
        echo "Usage:".$crlf;
        echo " multiotp [-log] -import-xml xml_tokens_definition_file.xml".$crlf;
        echo " multiotp [-log] -create [-prefix-pin] user algo seed pin digits [pos|interval]".$crlf;
        echo " multiotp [-log] -create -token-id [-prefix-pin] user token-id pin".$crlf;
        echo " multiotp [-log] -resync [-status] user token1 token2 (two consecutive tokens)".$crlf;
        echo " multiotp [-log] -update-pin user pin".$crlf;
        echo " multiotp [-log] user token".$crlf;
        echo " multiotp -delete user".$crlf;
        echo $crlf;
        echo " token-id: id of the previously imported token to attribute to the user".$crlf;
        echo " user:     name of the user (should be the account name)".$crlf;
        echo " algo:     available algorithms are mOTP, HOTP and TOTP".$crlf;
        echo " seed:     hexadecimal seed of the token".$crlf;
        echo " pin:      private pin code of the user".$crlf;
        echo " digits:   number of digits given by the token".$crlf;
        echo " pos:      for HOTP algorithm, position of the next awaited event".$crlf;
        echo " interval: for mOTP and TOTP algorithms, token interval time in seconds".$crlf;
        echo $crlf;
        echo "Options:".$crlf;
        echo " -help        Display this help page".$crlf;
        echo " -version     Display the current version".$crlf;
        echo " -prefix-pin  The pin and the token must be typed merged by the user".$crlf;
        echo "              (if you pin is 1234 and your token displays 5556677,".$crlf;
        echo "               you will have to type 1234556677)".$crlf;
        echo " -status      Display a status bar during resynchronization".$crlf;
        echo " -log         Log operation in the log file (in the \log subdirectory)".$crlf;
        echo " -debug       Enhanced log information and code result on screen".$crlf;
        echo $crlf;
        echo "Examples:".$crlf;
        echo " multiotp -log -debug -import-xml tokens.xml".$crlf;
        echo " multiotp -log -create jimmy mOTP 004f5a158bca13984d349a7f23 1234 6 10".$crlf;
        echo " multiotp -create -prefix-pin alan TOTP 3683453456769abc3452 2233 6 60".$crlf;
        echo " multiotp -create -prefix-pin anna TOTP 56821bac24fbd2343393 4455 6 30".$crlf;
        echo " multiotp -create -prefix-pin john HOTP 31323334353637383930 5678 6 137".$crlf;
        echo " multiotp -create -token-id -prefix-pin rick 2010090201901 2345".$crlf;
        echo " multiotp -resync john 5678456789 5678345231".$crlf;
        echo " multiotp -resync -status anna 4455487352 4455983513".$crlf;
        echo " multiotp -update-pin alan 4417".$crlf;
        echo " multiotp -log -debug jimmy ea2315".$crlf;
        echo " multiotp -log anna 546078".$crlf;
        echo " multiotp john 5678124578".$crlf;
        echo $crlf;
        echo "When used with TekRADIUS (http://www.tekradius.com) the External-Executable".$crlf;
        echo "must be called like this: C:\multitop\multiotp.exe %ietf|1% %ietf|2%".$crlf;
        echo $crlf;
        break;
}
if ($multiotp->GetVerboseFlag())
{
    echo $result;
    if (isset($multiotp->_errors_text[$result]))
    {
        echo " ".$multiotp->_errors_text[$result];
    }
}
exit($result);

?>