mirror of
https://github.com/Yubico/yubikey-val.git
synced 2025-02-07 18:54:23 +01:00
Add a verify request log line.
- Traditionally we wrote two lines for each ykval-verify.php call, 'Request:' and 'Response:'. - This commit allows us to log both request/response values in a single line. - For backward compatibility, the old logging is kept in place. - To write this line to syslog, __YKVAL_VERIFY_LOGFORMAT__ needs to be set.
This commit is contained in:
parent
3a85744814
commit
c01c19c860
@ -246,6 +246,9 @@ function KSMdecryptOTP($urls, $logger, $curlopts)
|
||||
|
||||
function sendResp($status, $logger, $apiKey = '', $extra = null)
|
||||
{
|
||||
if ($logger->request !== NULL)
|
||||
$logger->request->set('status', $status);
|
||||
|
||||
$a['status'] = $status;
|
||||
|
||||
// 2008-11-21T06:11:55Z0711
|
||||
@ -273,6 +276,9 @@ function sendResp($status, $logger, $apiKey = '', $extra = null)
|
||||
|
||||
$logger->log(LOG_INFO, "Response: " . $str . " (at " . gmdate("c") . " " . microtime() . ")");
|
||||
|
||||
if ($logger->request !== NULL)
|
||||
$logger->request->write();
|
||||
|
||||
echo $str;
|
||||
exit;
|
||||
}
|
||||
|
@ -131,3 +131,27 @@ function otp2ksmurls ($otp, $client)
|
||||
"http://127.0.0.1:8002/wsapi/decrypt?otp=$otp",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncomment to log verify requests just before replying to client.
|
||||
*
|
||||
* Available variables:
|
||||
* %time_start%
|
||||
* %time_end%
|
||||
* %time_taken%
|
||||
* %ip%
|
||||
* %client%
|
||||
* %public_id%
|
||||
* %otp%
|
||||
* %status%
|
||||
* %nonce%
|
||||
* %signed%
|
||||
* %counter%
|
||||
* %low%
|
||||
* %high%
|
||||
* %use%
|
||||
*
|
||||
* If a value is malformed or not available,
|
||||
* a dash '-' is written instead.
|
||||
*/
|
||||
//$baseParams['__YKVAL_VERIFY_LOGFORMAT__'] = '[%time_start%] [%ip%] [%client%] [%public_id%] [%otp%] [%status%] [%time_taken%] [%nonce%] [%signed%] [%counter%] [%low%] [%high%] [%use%]';
|
||||
|
185
ykval-log-verify.php
Normal file
185
ykval-log-verify.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
# Copyright (c) 2010-2016 Yubico AB
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require_once 'ykval-common.php';
|
||||
|
||||
class LogVerify
|
||||
{
|
||||
private $fields = array(
|
||||
'time_start' => NULL,
|
||||
'time_end' => NULL,
|
||||
'time_taken' => NULL,
|
||||
'ip' => NULL,
|
||||
'client' => NULL,
|
||||
'public_id' => NULL,
|
||||
'otp' => NULL,
|
||||
'status' => NULL,
|
||||
'nonce' => NULL,
|
||||
'signed' => NULL,
|
||||
'counter' => NULL,
|
||||
'low' => NULL,
|
||||
'high' => NULL,
|
||||
'use' => NULL,
|
||||
);
|
||||
|
||||
/**
|
||||
* Set field value.
|
||||
*
|
||||
* @param $name string
|
||||
* @param $value mixed
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
// not settable from outside
|
||||
if ($name === 'time_end' || $name === 'time_taken')
|
||||
return false;
|
||||
|
||||
if (array_key_exists($name, $this->fields) === FALSE)
|
||||
return false;
|
||||
|
||||
$this->fields[$name] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write verify request log line to syslog.
|
||||
*
|
||||
* P.S only writes to syslog if __YKVAL_VERIFY_LOGFORMAT__
|
||||
* is set correctly in ykval-config.php.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function write()
|
||||
{
|
||||
if (($logformat = $this->logformat()) === FALSE)
|
||||
return false;
|
||||
|
||||
$values = array();
|
||||
foreach ($this->sanitized() as $key => $val)
|
||||
{
|
||||
$values['%'.$key.'%'] = $val;
|
||||
}
|
||||
|
||||
$message = strtr($logformat, $values);
|
||||
|
||||
if (!is_string($message))
|
||||
return false;
|
||||
|
||||
return syslog(LOG_INFO, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the logging format as set in the configuration file.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
private function logformat()
|
||||
{
|
||||
require_once 'ykval-config.php';
|
||||
|
||||
if (!isset($baseParams)
|
||||
|| !is_array($baseParams)
|
||||
|| !array_key_exists('__YKVAL_VERIFY_LOGFORMAT__', $baseParams)
|
||||
|| !is_string($baseParams['__YKVAL_VERIFY_LOGFORMAT__']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $baseParams['__YKVAL_VERIFY_LOGFORMAT__']
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize untrusted values from clients before writing them to syslog.
|
||||
*
|
||||
* P.S. signed, status, time_start are assumed safe,
|
||||
* since they are set internally.
|
||||
*
|
||||
* @return array sanitized $this->fields
|
||||
*/
|
||||
private function sanitized()
|
||||
{
|
||||
$a = $this->fields;
|
||||
|
||||
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['public_id']) !== 1
|
||||
|| strlen($a['public_id']) < 1
|
||||
|| strlen($a['public_id']) > (OTP_MAX_LEN - TOKEN_LEN))
|
||||
{
|
||||
$a['public_id'] = '-';
|
||||
}
|
||||
|
||||
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['otp']) !== 1
|
||||
|| strlen($a['otp']) < TOKEN_LEN
|
||||
|| strlen($a['otp']) > OTP_MAX_LEN))
|
||||
{
|
||||
$a['otp'] = '-';
|
||||
}
|
||||
|
||||
if (preg_match('/^[0-9]+$/', $a['client']) !== 1)
|
||||
$a['client'] = '-';
|
||||
|
||||
if (filter_var($a['ip'], FILTER_VALIDATE_IP) === FALSE)
|
||||
$a['ip'] = '-';
|
||||
|
||||
if (is_int($a['counter']) === FALSE)
|
||||
$a['counter'] = '-';
|
||||
|
||||
if (is_int($a['low']) === FALSE)
|
||||
$a['low'] = '-';
|
||||
|
||||
if (is_int($a['high']) === FALSE)
|
||||
$a['high'] = '-';
|
||||
|
||||
if (is_int($a['use']) === FALSE)
|
||||
$a['use'] = '-';
|
||||
|
||||
if (preg_match('/^[a-zA-Z0-9]{16,40}$/', $a['nonce']) !== 1)
|
||||
$a['nonce'] = '-';
|
||||
|
||||
$start = explode(' ', $a['time_start']);
|
||||
$start_msec = $start[0];
|
||||
$start_sec = $start[1];
|
||||
$start = bcadd($start_sec, $start_msec, 8);
|
||||
unset($start_sec, $start_msec);
|
||||
|
||||
$end = explode(' ', microtime());
|
||||
$end_msec = $end[0];
|
||||
$end_sec = $end[1];
|
||||
$end = bcadd($end_sec, $end_msec, 8);
|
||||
unset($end_sec, $end_msec);
|
||||
|
||||
$taken = bcsub($end, $start, 8);
|
||||
|
||||
$a['time_start'] = $start;
|
||||
$a['time_end'] = $end;
|
||||
$a['time_taken'] = $taken;
|
||||
|
||||
return $a;
|
||||
}
|
||||
}
|
@ -29,6 +29,9 @@
|
||||
|
||||
class Log
|
||||
{
|
||||
// request logger object
|
||||
public $request = NULL;
|
||||
|
||||
private $log_levels = array(
|
||||
LOG_EMERG => 'LOG_EMERG',
|
||||
LOG_ALERT => 'LOG_ALERT',
|
||||
|
@ -27,9 +27,12 @@
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
$time_start = microtime();
|
||||
|
||||
require_once 'ykval-common.php';
|
||||
require_once 'ykval-config.php';
|
||||
require_once 'ykval-synclib.php';
|
||||
require_once 'ykval-log-verify.php';
|
||||
|
||||
header('content-type: text/plain');
|
||||
|
||||
@ -52,6 +55,12 @@ $https = (array_key_exists('HTTPS', $_SERVER) === TRUE
|
||||
$myLog = new Log('ykval-verify');
|
||||
$myLog->addField('ip', $ipaddr);
|
||||
|
||||
$myLog->request = new LogVerify();
|
||||
$myLog->request->set('ip', $ipaddr);
|
||||
$myLog->request->set('time_start', $time_start);
|
||||
unset($time_start);
|
||||
|
||||
|
||||
// FIXME
|
||||
$message = '';
|
||||
if ($_POST)
|
||||
@ -101,6 +110,10 @@ if (preg_match('/^[jxe.uidchtnbpygk]+$/', $otp))
|
||||
unset($new_otp);
|
||||
}
|
||||
|
||||
$myLog->request->set('signed', ($h === '' ? '-' : 'signed'));
|
||||
$myLog->request->set('client', ($client === 0 ? NULL : $client));
|
||||
$myLog->request->set('otp', $otp);
|
||||
|
||||
|
||||
/**
|
||||
* Construct response parameters
|
||||
@ -123,6 +136,7 @@ if ($protocol_version >= 2.0)
|
||||
$sl = getHttpVal('sl', '');
|
||||
$timeout = getHttpVal('timeout', '');
|
||||
$nonce = getHttpVal('nonce', '');
|
||||
$myLog->request->set('nonce', $nonce);
|
||||
|
||||
/* Nonce is required from protocol 2.0 */
|
||||
if (!$nonce)
|
||||
@ -312,10 +326,15 @@ if (($otpinfo = KSMdecryptOTP($urls, $myLog, $curlopts)) === FALSE)
|
||||
*/
|
||||
sendResp(S_BAD_OTP, $myLog, $apiKey);
|
||||
}
|
||||
$myLog->request->set('counter', $otpinfo['session_counter']);
|
||||
$myLog->request->set('use', $otpinfo['session_use']);
|
||||
$myLog->request->set('high', $otpinfo['high']);
|
||||
$myLog->request->set('low', $otpinfo['low']);
|
||||
$myLog->log(LOG_DEBUG, 'Decrypted OTP:', $otpinfo);
|
||||
|
||||
// get Yubikey from DB
|
||||
$yk_publicname = substr($otp, 0, strlen ($otp) - TOKEN_LEN);
|
||||
$myLog->request->set('public_id', $yk_publicname);
|
||||
if (($localParams = $sync->getLocalParams($yk_publicname)) === FALSE)
|
||||
{
|
||||
$myLog->log(LOG_NOTICE, "Invalid Yubikey $yk_publicname");
|
||||
|
Loading…
x
Reference in New Issue
Block a user