config = $config; } /*! * check if specified Token is a valid token * * @method isValid * @public * @param MetaTech\PwsAtuh\Token $token * @return bool */ public function isValid(Token $token = null) { return !is_null($token) && $token->getType() == $this->config['type'] && $this->checkObfuscatePart($token); } /*! * generate a unique signature at given time for specifyed user * * @method sign * @public * @param str $dtime given time in sqldatetime format * @param str $login the user login * @param str $key the user key * @return str */ public function sign($dtime, $login, $key, $length=null) { $str = Tool::concat($this->config['hash']['sep'], [$dtime, $login, $this->getUserSalt($login), $key]); return substr(hash($this->config['hash']['algo'], $str), is_null($length) ? - $this->config['hash']['length'] : - $length); } /*! * generate the salt for a specific user * * @method getUserSalt * @public * @param str $login the user login * @return str */ public function getUserSalt($login) { return substr( hash(self::DEFAULT_ALGO, $login . $this->config['salt']['common']), $this->config['salt']['user.index'], $this->config['salt']['user.length'] ); } /*! * generate noise to obfuscate token * * @method obfuscate * @orivate * @param str $data * @return str */ private function obfuscate($data, $date) { return substr( hash(self::DEFAULT_ALGO, $date . $data . $this->config['salt']['common']), - $this->config['hash']['session.index'] ); } /*! * @method formatDate * @private * @param str $date sqldatetime * @return str */ private function formatDate($date) { return Tool::formatDate($date, Tool::TIMESTAMP_SQLDATETIME, self::DATE_FORMAT); } /*! * @method formatDate * @private * @param str $formated DATE_FORMAT * @return str */ private function unformatDate($formated) { return Tool::formatDate($formated, self::DATE_FORMAT, Tool::TIMESTAMP_SQLDATETIME); } /*! * check valid noise obfuscation * * @method checkObfuscatePart * @public * @param MetaTech\PwsAtuh\Token $token * @return bool */ public function checkObfuscatePart(Token $token) { $tokenValue = $token->getValue(); return substr($tokenValue, 0, $this->config['hash']['session.index']) == $this->obfuscate($this->deobfuscate($tokenValue), $token->getDate()); } /*! * deoffuscate token * * @method deobfuscate * @orivate * @param str $data * @return str */ private function deobfuscate($data) { return substr($data, $this->config['hash']['session.index']); } /*! * @method getSessionId * @orivate * @param MetaTech\PwsAtuh\Token $token * @return str */ public function getSessionId(Token $token) { return $this->deobfuscate($token->getValue()); } /*! * check validity of Token * * @mehtod check * @public * @param MetaTech\PwsAtuh\Token $token * @param str $login * @return bool */ public function check(Token $token = null, $login = '') { return !is_null($token) && !empty($login) && $this->deobfuscate($token->getValue()) == $this->sign($token->getDate(), $login, $token->getIdent()); } /*! * @method generateNoise * @public * @param str $data * @return str */ public function generateNoise($data) { return substr(hash(self::DEFAULT_ALGO, str_shuffle($data)), - $this->config['hash']['noise.length']); } /*! * @method generateToken * @public * @param str $login * @param str $key * @param str $sessid|null * @return MetaTech\PwsAuth\Token */ public function generateToken($login, $key, $sessid=null) { $date = Tool::now(); $sessid = is_null($sessid) ? $this->sign($date, $login, $key) : $sessid; $dt = $this->formatDate($date); $tokenValue = $this->obfuscate($sessid, $date) . $sessid; $noise = $this->generateNoise($tokenValue); return new Token($this->config['type'], $key, $date, $tokenValue, $noise); } /*! * @method generateHeader * @public * @param str $login * @param str $key * @param str $sessid * @return [] */ public function generateHeader($login, $key, $sessid=null) { $token = $this->generateToken($login, $key, $sessid); $ndate = $this->formatDate($token->getDate()); return array( $this->config['header']['auth'] .': ' . $token->getType() . ' ' . $ndate . $token->getValue() . $token->getNoise(), $this->config['header']['ident'].': ' . $token->getIdent() ); } /*! * @method generatePostVars * @public * @param str $login * @param str $key * @param str $tokenName * @param str $keyName * @return [] */ public function generatePostVars($login, $key, $tokenName='apitkn', $keyName='apikey') { $token = $this->generateToken($login, $key, null); $ndate = $this->formatDate($token->getDate()); return array( $tokenName => $ndate . $token->getValue() . $token->getNoise(), $keyName => $key ); } /*! * get token from specified $noisedToken for specified key. * * @method getTokenFromString * @public * @param str $noisedToken * @param str $key * @return MetaTech\PwsAuth\Token */ public function getTokenFromString($noisedToken, $key) { $date = substr($noisedToken, 0, self::DATE_LENGTH); $tokenValue = substr($noisedToken, self::DATE_LENGTH, -$this->config['hash']['noise.length']); $noise = substr($noisedToken, -$this->config['hash']['noise.length']); return new Token($this->config['type'], $key, $this->unformatDate($date), $tokenValue, $noise); } /*! * get token from specified $header or request headers. * * @method getToken * @public * @param [assoc] $headers * @throw MetaTech\PwsAuth\AuthenticateException * @return MetaTech\PwsAuth\Token */ public function getToken($headers = null) { $token = null; try { if (is_null($headers)) { $headers = apache_request_headers(); } if (isset($headers[$this->config['header']['auth']]) && isset($headers[$this->config['header']['ident']])) { $tokenValue = $headers[$this->config['header']['auth']]; $ident = $headers[$this->config['header']['ident']]; if (preg_match('/(?P[a-z\d]+) (?P.*)/i', $tokenValue, $rs)) { $token = $this->getTokenFromString($rs['noised'], $ident); if ($token->getType() != $rs['type']) { throw new \Exception('wrong type'); } } } else { throw new \Exception('missing required headers'); } } catch(\Exception $e) { throw new AuthenticateException("invalid authentication protocol : ".$e->getMessage()); } return $token; } /*! * read header generate by generateHeader * * @method readHeader * @public * @param [str] $arrHeaders * @return [assoc] */ public function readHeader($arrHeaders) { $headers = []; if (is_array($arrHeaders)) { foreach($arrHeaders as $h) { $rs = preg_split('/:/', $h); if (count($rs)==2) { $headers[$rs[0]] = trim($rs[1]); } } } return $headers; } }