X-Git-Url: http://git.pjr.cc/?a=blobdiff_plain;f=lib%2Fga4php.php;h=2be25ff2828e56c460187e1281ad112004b616df;hb=a4ea535bfca29425422f4f3183ed75df19de17c8;hp=8bc5946d6db8ac2be21d96926ab43b107a1a1e72;hpb=18f8e04423dfe377ac53a8b27bb717944ce411dc;p=ga4php.git diff --git a/lib/ga4php.php b/lib/ga4php.php index 8bc5946..2be25ff 100644 --- a/lib/ga4php.php +++ b/lib/ga4php.php @@ -2,9 +2,25 @@ abstract class GoogleAuthenticator { - function __construct() { + function __construct($totpskew=1, $hotpskew=10, $hotphuntvalue=200000) { + // the hotpskew is how many tokens forward we look to find the input + // code the user used + $this->hotpSkew = $hotpskew; + + // the totpskew value is how many tokens either side of the current + // token we should check, based on a time skew. + $this->totpSkew = $totpskew; + + // the hotphuntvalue is what we use to resync tokens. + // when a user resyncs, we search from 0 to $hutphutvalue to find + // the two token codes the user has entered - 200000 seems like overkill + // really as i cant imagine any token out there would ever make it + // past 200000 token code requests. + $this->hotpHuntValue = $hotphuntvalue; } + // pure abstract functions that need to be overloaded when + // creating a sub class abstract function getData($username); abstract function putData($username, $data); abstract function getUsers(); @@ -16,11 +32,13 @@ abstract class GoogleAuthenticator { $data["tokentimer"] = 30; // the token timer (For totp) and not supported by ga yet $data["tokencounter"] = 1; // the token counter for hotp $data["tokenalgorithm"] = "SHA1"; // the token algorithm (not supported by ga yet) + $data["user"] = ""; // a place for implementors to store their own data return $data; } - // an internal funciton to get + // an internal funciton to get data from the overloaded functions + // and turn them into php arrays. function internalGetData($username) { $data = $this->getData($username); $deco = unserialize(base64_decode($data)); @@ -32,7 +50,8 @@ abstract class GoogleAuthenticator { return $deco; } - + // the function used inside the class to put the data into the + // datastore using the overloaded data saving class function internalPutData($username, $data) { $enco = base64_encode(serialize($data)); @@ -45,21 +64,22 @@ abstract class GoogleAuthenticator { // so lets not be able to set that yet function setTokenType($username, $tokentype) { $tokentype = strtoupper($tokentype); - if($tokentype!="HOTP" and $tokentype!="TOTP") { + if($tokentype!="HOTP" && $tokentype!="TOTP") { $errorText = "Invalid Token Type"; return false; } $data = $this->internalGetData($username); $data["tokentype"] = $tokentype; - $this->internalPutData($username, $data); + return $this->internalPutData($username, $data); - return true; } // create "user" with insert function setUser($username, $ttype="HOTP", $key = "", $hexkey="") { + $ttype = strtoupper($ttype); + if($ttype != "HOTP" && $ttype !="TOTP") return false; if($key == "") $key = $this->createBase32Key(); $hkey = $this->helperb322hex($key); if($hexkey != "") $hkey = $hexkey; @@ -68,11 +88,13 @@ abstract class GoogleAuthenticator { $token["tokenkey"] = $hkey; $token["tokentype"] = $ttype; - $this->internalPutData($username, $token); + if(!$this->internalPutData($username, $token)) { + return false; + } return $key; } - + // a function to determine if the user has an actual token function hasToken($username) { $token = $this->internalGetData($username); // TODO: change this to a pattern match for an actual key @@ -106,10 +128,10 @@ abstract class GoogleAuthenticator { function authenticateUser($username, $code) { if(preg_match("/[0-9][0-9][0-9][0-9][0-9][0-9]/",$code)<1) return false; - error_log("begin auth user"); + //error_log("begin auth user"); $tokendata = $this->internalGetData($username); - $asdf = print_r($tokendata, true); - error_log("dat is $asdf"); + //$asdf = print_r($tokendata, true); + //error_log("dat is $asdf"); if($tokendata["tokenkey"] == "") { $errorText = "No Assigned Token"; @@ -121,13 +143,13 @@ abstract class GoogleAuthenticator { $tlid = $tokendata["tokencounter"]; $tkey = $tokendata["tokenkey"]; - $asdf = print_r($tokendata, true); - error_log("dat is $asdf"); + //$asdf = print_r($tokendata, true); + //error_log("dat is $asdf"); switch($ttype) { case "HOTP": error_log("in hotp"); $st = $tlid; - $en = $tlid+20; + $en = $tlid+$this->hotpSkew; for($i=$st; $i<$en; $i++) { $stest = $this->oath_hotp($tkey, $i); error_log("testing code: $code, $stest, $tkey, $tid"); @@ -142,10 +164,10 @@ abstract class GoogleAuthenticator { case "TOTP": error_log("in totp"); $t_now = time(); - $t_ear = $t_now - 45; - $t_lat = $t_now + 60; - $t_st = ((int)($t_ear/30)); - $t_en = ((int)($t_lat/30)); + $t_ear = $t_now - ($this->totpSkew*$tokendata["tokentimer"]); + $t_lat = $t_now + ($this->totpSkew*$tokendata["tokentimer"]); + $t_st = ((int)($t_ear/$tokendata["tokentimer"])); + $t_en = ((int)($t_lat/$tokendata["tokentimer"])); //error_log("kmac: $t_now, $t_ear, $t_lat, $t_st, $t_en"); for($i=$t_st; $i<=$t_en; $i++) { $stest = $this->oath_hotp($tkey, $i); @@ -156,7 +178,7 @@ abstract class GoogleAuthenticator { } break; default: - echo "how the frig did i end up here?"; + return false; } return false; @@ -190,7 +212,7 @@ abstract class GoogleAuthenticator { switch($ttype) { case "HOTP": $st = 0; - $en = 200000; + $en = $this->hotpHuntValue; for($i=$st; $i<$en; $i++) { $stest = $this->oath_hotp($tkey, $i); //echo "code: $code, $stest, $tkey\n"; @@ -206,6 +228,7 @@ abstract class GoogleAuthenticator { return false; break; case "TOTP": + // ignore it? break; default: echo "how the frig did i end up here?"; @@ -225,9 +248,10 @@ abstract class GoogleAuthenticator { $data = $this->internalGetData($user); $toktype = $data["tokentype"]; $key = $this->helperhex2b32($data["tokenkey"]); + $counter = $data["tokencounter"]; $toktype = strtolower($toktype); if($toktype == "hotp") { - $url = "otpauth://$toktype/$user?secret=$key&counter=1"; + $url = "otpauth://$toktype/$user?secret=$key&counter=$counter"; } else { $url = "otpauth://$toktype/$user?secret=$key"; } @@ -265,6 +289,7 @@ abstract class GoogleAuthenticator { } + // TODO: lots of error checking goes in here function helperb322hex($b32) { $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; @@ -295,6 +320,7 @@ abstract class GoogleAuthenticator { return $out2; } + // TODO: lots of error checking goes in here function helperhex2b32($hex) { $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; @@ -318,6 +344,10 @@ abstract class GoogleAuthenticator { return $out2; } + // i've put alot of faith in the code from the + // php site's examples for the hash_hmac algorithm + // i assume its mostly correct but i should do + // some testing to verify this is actually the case function oath_hotp($key, $counter) { $key = pack("H*", $key); @@ -339,6 +369,7 @@ abstract class GoogleAuthenticator { return str_pad($this->oath_truncate($hash), 6, "0", STR_PAD_LEFT); } + function oath_truncate($hash, $length = 6) { // Convert to dec @@ -367,6 +398,12 @@ abstract class GoogleAuthenticator { private $errorText; private $errorCode; + private $hotpSkew; + private $totpSkew; + + private $hotpHuntValue; + + /* * error codes * 1: Auth Failed