/**
  * Performs an authentication attempt
  *
  * @return \Zend\Authentication\Result
  * @throws \Zend\Authentication\Adapter\Exception\ExceptionInterface If authentication cannot be performed
  */
 public function authenticate()
 {
     $getHeader = $this->options['proxy_auth'] ? 'Proxy-Authorization' : 'Authorization';
     if (!($authHeader = $this->request->headers->get($getHeader))) {
         return $this->challengeClient();
     }
     // Decode the Authorization header
     $authorizationHeader = base64_decode(substr($authHeader, strlen('Basic ')));
     if (!$authorizationHeader) {
         throw new RuntimeException('Unable to base64_decode Authorization header value');
     }
     // See ZF-1253. Validate the credentials the same way the digest
     // implementation does. If invalid credentials are detected,
     // re-challenge the client.
     if (!ctype_print($authorizationHeader)) {
         return $this->challengeClient();
     }
     // Fix for ZF-1515: Now re-challenges on empty username or password
     $credentials = array_filter(explode(':', $authorizationHeader));
     if (count($credentials) !== 2) {
         return $this->challengeClient();
     }
     $result = $this->resolver->resolve($credentials[0], $this->options['realm'], $credentials[1]);
     if ($result instanceof Result && $result->isValid()) {
         return $result;
     }
     if (!$result instanceof Result && !is_array($result) && Utils::compareStrings($result, $credentials[1])) {
         $identity = ['username' => $credentials[0], 'realm' => $this->options['realm']];
         return new Result(Result::SUCCESS, $identity);
     } elseif (is_array($result)) {
         return new Result(Result::SUCCESS, $result);
     }
     return $this->challengeClient();
 }
Exemplo n.º 2
0
 /**
  * Decrypt
  *
  * @param  string $data
  * @return string|boolean
  * @throws Exception\InvalidArgumentException
  */
 public function decrypt($data)
 {
     if (!is_string($data)) {
         throw new Exception\InvalidArgumentException('The data to decrypt must be a string');
     }
     if ('' === $data) {
         throw new Exception\InvalidArgumentException('The data to decrypt cannot be empty');
     }
     if (empty($this->key)) {
         throw new Exception\InvalidArgumentException('No key specified for the decryption');
     }
     if (empty($this->cipher)) {
         throw new Exception\InvalidArgumentException('No symmetric cipher specified');
     }
     $hmacSize = Hmac::getOutputSize($this->hash);
     $hmac = substr($data, 0, $hmacSize);
     $ciphertext = substr($data, $hmacSize);
     if (!$this->binaryOutput) {
         $ciphertext = base64_decode($ciphertext);
     }
     $iv = substr($ciphertext, 0, $this->cipher->getSaltSize());
     $keySize = $this->cipher->getKeySize();
     // generate the encryption key and the HMAC key for the authentication
     $hash = Pbkdf2::calc(self::KEY_DERIV_HMAC, $this->getKey(), $iv, $this->keyIteration, $keySize * 2);
     // set the decryption key
     $this->cipher->setKey(substr($hash, 0, $keySize));
     // set the key for HMAC
     $keyHmac = substr($hash, $keySize);
     $hmacNew = Hmac::compute($keyHmac, $this->hash, $this->cipher->getAlgorithm() . $ciphertext);
     if (!Utils::compareStrings($hmacNew, $hmac)) {
         return false;
     }
     return $this->cipher->decrypt($ciphertext);
 }
Exemplo n.º 3
0
 /**
  * Verify if a password is correct against a hash value
  *
  * @param  string $password
  * @param  string $hash
  * @throws Exception\RuntimeException when the hash is unable to be processed
  * @return bool
  */
 public function verify($password, $hash)
 {
     $result = crypt($password, $hash);
     return Utils::compareStrings($hash, $result);
 }
Exemplo n.º 4
0
 /**
  * Defined by Zend\Authentication\Adapter\AdapterInterface
  *
  * @throws Exception\ExceptionInterface
  * @return AuthenticationResult
  */
 public function authenticate()
 {
     $optionsRequired = array('filename', 'realm', 'identity', 'credential');
     foreach ($optionsRequired as $optionRequired) {
         if (null === $this->{$optionRequired}) {
             throw new Exception\RuntimeException("Option '{$optionRequired}' must be set before authentication");
         }
     }
     ErrorHandler::start(E_WARNING);
     $fileHandle = fopen($this->filename, 'r');
     $error = ErrorHandler::stop();
     if (false === $fileHandle) {
         throw new Exception\UnexpectedValueException("Cannot open '{$this->filename}' for reading", 0, $error);
     }
     $id = "{$this->identity}:{$this->realm}";
     $idLength = strlen($id);
     $result = array('code' => AuthenticationResult::FAILURE, 'identity' => array('realm' => $this->realm, 'username' => $this->identity), 'messages' => array());
     while (($line = fgets($fileHandle)) !== false) {
         $line = trim($line);
         if (empty($line)) {
             break;
         }
         if (substr($line, 0, $idLength) === $id) {
             if (CryptUtils::compareStrings(substr($line, -32), md5("{$this->identity}:{$this->realm}:{$this->credential}"))) {
                 $result['code'] = AuthenticationResult::SUCCESS;
             } else {
                 $result['code'] = AuthenticationResult::FAILURE_CREDENTIAL_INVALID;
                 $result['messages'][] = 'Password incorrect';
             }
             return new AuthenticationResult($result['code'], $result['identity'], $result['messages']);
         }
     }
     $result['code'] = AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND;
     $result['messages'][] = "Username '{$this->identity}' and realm '{$this->realm}' combination not found";
     return new AuthenticationResult($result['code'], $result['identity'], $result['messages']);
 }
Exemplo n.º 5
0
 public function testCompareStringsBasic()
 {
     $this->assertTrue(Utils::compareStrings('test', 'test'));
     $this->assertFalse(Utils::compareStrings('test', 'Test'));
 }
Exemplo n.º 6
0
 /**
  * Verify if a password is correct against a hash value
  *
  * @param  string  $password
  * @param  string  $hash
  * @return bool
  */
 public function verify($password, $hash)
 {
     if (substr($hash, 0, 5) === '{SHA}') {
         $hash2 = '{SHA}' . base64_encode(sha1($password, true));
         return Utils::compareStrings($hash, $hash2);
     }
     if (substr($hash, 0, 6) === '$apr1$') {
         $token = explode('$', $hash);
         if (empty($token[2])) {
             throw new Exception\InvalidArgumentException('The APR1 password format is not valid');
         }
         $hash2 = $this->apr1Md5($password, $token[2]);
         return Utils::compareStrings($hash, $hash2);
     }
     $bcryptPattern = '/\\$2[ay]?\\$[0-9]{2}\\$[' . addcslashes(static::BASE64, '+/') . '\\.]{53}/';
     if (strlen($hash) > 13 && !preg_match($bcryptPattern, $hash)) {
         // digest
         if (empty($this->userName) || empty($this->authName)) {
             throw new Exception\RuntimeException('You must specify UserName and AuthName (realm) to verify the digest');
         }
         $hash2 = md5($this->userName . ':' . $this->authName . ':' . $password);
         return Utils::compareStrings($hash, $hash2);
     }
     return Utils::compareStrings($hash, crypt($password, $hash));
 }
Exemplo n.º 7
0
 /**
  * Digest Authentication
  *
  * @param  string $header Client's Authorization header
  * @throws Exception\ExceptionInterface
  * @return Authentication\Result Valid auth result only on successful auth
  */
 protected function _digestAuth($header)
 {
     if (empty($header)) {
         throw new Exception\RuntimeException('The value of the client Authorization header is required');
     }
     if (empty($this->digestResolver)) {
         throw new Exception\RuntimeException('A digestResolver object must be set before doing Digest authentication');
     }
     $data = $this->_parseDigestAuth($header);
     if ($data === false) {
         $this->response->setStatusCode(400);
         return new Authentication\Result(Authentication\Result::FAILURE_UNCATEGORIZED, array(), array('Invalid Authorization header format'));
     }
     // See ZF-1052. This code was a bit too unforgiving of invalid
     // usernames. Now, if the username is bad, we re-challenge the client.
     if ('::invalid::' == $data['username']) {
         return $this->_challengeClient();
     }
     // Verify that the client sent back the same nonce
     if ($this->_calcNonce() != $data['nonce']) {
         return $this->_challengeClient();
     }
     // The opaque value is also required to match, but of course IE doesn't
     // play ball.
     if (!$this->ieNoOpaque && $this->_calcOpaque() != $data['opaque']) {
         return $this->_challengeClient();
     }
     // Look up the user's password hash. If not found, deny access.
     // This makes no assumptions about how the password hash was
     // constructed beyond that it must have been built in such a way as
     // to be recreatable with the current settings of this object.
     $ha1 = $this->digestResolver->resolve($data['username'], $data['realm']);
     if ($ha1 === false) {
         return $this->_challengeClient();
     }
     // If MD5-sess is used, a1 value is made of the user's password
     // hash with the server and client nonce appended, separated by
     // colons.
     if ($this->algo == 'MD5-sess') {
         $ha1 = hash('md5', $ha1 . ':' . $data['nonce'] . ':' . $data['cnonce']);
     }
     // Calculate h(a2). The value of this hash depends on the qop
     // option selected by the client and the supported hash functions
     switch ($data['qop']) {
         case 'auth':
             $a2 = $this->request->getMethod() . ':' . $data['uri'];
             break;
         case 'auth-int':
             // Should be REQUEST_METHOD . ':' . uri . ':' . hash(entity-body),
             // but this isn't supported yet, so fall through to default case
         // Should be REQUEST_METHOD . ':' . uri . ':' . hash(entity-body),
         // but this isn't supported yet, so fall through to default case
         default:
             throw new Exception\RuntimeException('Client requested an unsupported qop option');
     }
     // Using hash() should make parameterizing the hash algorithm
     // easier
     $ha2 = hash('md5', $a2);
     // Calculate the server's version of the request-digest. This must
     // match $data['response']. See RFC 2617, section 3.2.2.1
     $message = $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . $ha2;
     $digest = hash('md5', $ha1 . ':' . $message);
     // If our digest matches the client's let them in, otherwise return
     // a 401 code and exit to prevent access to the protected resource.
     if (CryptUtils::compareStrings($digest, $data['response'])) {
         $identity = array('username' => $data['username'], 'realm' => $data['realm']);
         return new Authentication\Result(Authentication\Result::SUCCESS, $identity);
     }
     return $this->_challengeClient();
 }
 /**
  * Decrypt a file
  *
  * @param  string                             $fileIn
  * @param  string                             $fileOut
  * @param  bool                               $compress
  * @return bool
  * @throws Exception\InvalidArgumentException
  */
 public function decrypt($fileIn, $fileOut)
 {
     $this->checkFileInOut($fileIn, $fileOut);
     if (empty($this->key)) {
         throw new Exception\InvalidArgumentException('No key specified for decryption');
     }
     $read = fopen($fileIn, "r");
     $write = fopen($fileOut, "w");
     $hmacRead = fread($read, Hmac::getOutputSize($this->getHashAlgorithm()));
     $iv = fread($read, $this->cipher->getSaltSize());
     $tot = filesize($fileIn);
     $hmac = $iv;
     $size = mb_strlen($iv, '8bit') + mb_strlen($hmacRead, '8bit');
     $keys = Pbkdf2::calc($this->getPbkdf2HashAlgorithm(), $this->getKey(), $iv, $this->getKeyIteration(), $this->cipher->getKeySize() * 2);
     $padding = $this->cipher->getPadding();
     $this->cipher->setPadding(new Symmetric\Padding\NoPadding());
     $this->cipher->setKey(mb_substr($keys, 0, $this->cipher->getKeySize(), '8bit'));
     $this->cipher->setMode('cbc');
     $blockSize = $this->cipher->getBlockSize();
     $hashAlgo = $this->getHashAlgorithm();
     $algorithm = $this->cipher->getAlgorithm();
     $saltSize = $this->cipher->getSaltSize();
     $keyHmac = mb_substr($keys, $this->cipher->getKeySize(), null, '8bit');
     while ($data = fread($read, self::BUFFER_SIZE)) {
         $size += mb_strlen($data, '8bit');
         // Unpadding if last block
         if ($size + $blockSize >= $tot) {
             $this->cipher->setPadding($padding);
             $data .= fread($read, $blockSize);
         }
         $result = $this->cipher->decrypt($iv . $data);
         $hmac = Hmac::compute($keyHmac, $hashAlgo, $algorithm . $hmac . $data);
         $iv = mb_substr($data, -1 * $saltSize, null, '8bit');
         if (fwrite($write, $result) !== mb_strlen($result, '8bit')) {
             return false;
         }
     }
     fclose($write);
     fclose($read);
     // check for data integrity
     if (!Utils::compareStrings($hmac, $hmacRead)) {
         unlink($fileOut);
         return false;
     }
     return true;
 }
Exemplo n.º 9
0
 /**
  * @param  string $expected
  * @param  string $actual
  * @return bool
  */
 public static function compareStrings($expected, $actual)
 {
     return Utils::compareStrings($expected, $actual);
 }