/** * Parse the ciphertext, process it, and return the response. * * FIXME Catch exceptions and return in a nice format. * * @param string $blob * POST'ed ciphertext. * @return Message */ public function handle($blob) { try { $reqData = $this->decode(RegistrationMessage::NAME, $blob); } catch (InvalidMessageException $e) { $this->log->warning('Received invalid message', array('exception' => $e)); $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid message coding', array($e->getMessage(), $e->getTraceAsString()))); return $resp->setCode(400); } $this->log->debug('Received registration request', array('reqData' => $reqData)); $cxn = $reqData['cxn']; $validation = Cxn::getValidationMessages($cxn); if (!empty($validation)) { // $cxn is not valid, so we can't encode it use it for encoding. $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid cxn details: ' . implode(', ', array_keys($validation)))); return $resp->setCode(400); } $respData = $this->createError('Unrecognized entity or action'); if ($reqData['entity'] == 'Cxn' && preg_match('/^[a-zA-Z]+$/', $reqData['action'])) { $func = 'on' . $reqData['entity'] . strtoupper($reqData['action'][0]) . substr($reqData['action'], 1); if (is_callable(array($this, $func))) { $respData = call_user_func(array($this, $func), $reqData['cxn'], $reqData['params']); } } $this->log->debug('Responding', array($cxn['cxnId'], $cxn['secret'], $respData)); return new StdMessage($cxn['cxnId'], $cxn['secret'], $respData); }
/** * Parse the ciphertext, process it, and return the response. * * FIXME Catch exceptions and return in a nice format. * * @param string $blob * POST'ed ciphertext. * @return Message */ public function handle($blob) { try { $reqMessage = $this->decode(StdMessage::NAME, $blob); } catch (InvalidMessageException $e) { $this->log->debug('Received invalid message', array('exception' => $e)); $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid message coding', array($e->getMessage(), $e->getTraceAsString()))); return $resp->setCode(400); } $cxn = $this->cxnStore->getByCxnId($reqMessage->getCxnId()); $validation = Cxn::getValidationMessages($cxn); if (!empty($validation)) { $this->log->error('Invalid cxn ({cxnId})', array('cxnId' => $reqMessage->getCxnId(), 'messages' => $validation)); // $cxn is not valid, so we can't encode it use it for encoding. $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid cxn details: ' . implode(', ', array_keys($validation)))); return $resp->setCode(400); } try { list($entity, $action, $params, $appCert) = $reqMessage->getData(); if ($this->certValidator) { $this->certValidator->validateCert($appCert); $appCertObj = X509Util::loadCert($appCert); $cn = $appCertObj->getDNProp('CN'); if (count($cn) != 1 || $cn[0] !== $cxn['appId']) { throw new InvalidMessageException('Invalid message: Submitted certificate does not matched expected appId'); } } $respData = call_user_func($this->router, $cxn, $entity, $action, $params); $this->log->info('Processed API call ({entity}.{action})', array('entity' => $entity, 'action' => $action)); } catch (\Exception $e) { $this->log->error('Error executing API call', array('request' => $reqMessage->getData(), 'exception' => $e)); $respData = array('is_error' => 1, 'error_message' => $e->getMessage()); } return new StdMessage($reqMessage->getCxnId(), $cxn['secret'], $respData); }
/** * @param array|string $formats * @param string $blob * @return Message * @throws InvalidMessageException */ public function decode($formats, $blob) { $formats = (array) $formats; $prefixLen = 0; foreach ($formats as $format) { $prefixLen = max($prefixLen, strlen($format)); } list($prefix) = explode(Constants::PROTOCOL_DELIM, substr($blob, 0, $prefixLen + 1)); if (!in_array($prefix, $formats)) { if (in_array(GarbledMessage::NAME, $formats)) { return GarbledMessage::decode($blob); } else { throw new InvalidMessageException("Unexpected message type."); } } switch ($prefix) { case StdMessage::NAME: return StdMessage::decode($this->cxnStore, $blob); case InsecureMessage::NAME: return InsecureMessage::decode($blob); case RegistrationMessage::NAME: return RegistrationMessage::decode($this->appStore, $blob); case AppMetasMessage::NAME: return AppMetasMessage::decode($this->certValidator, $blob); default: throw new InvalidMessageException("Unrecognized message type."); } }
/** * Parse the ciphertext, process it, and return the response. * * FIXME Catch exceptions and return in a nice format. * * @param string $blob * POST'ed ciphertext. * @return Message */ public function handle($blob) { try { $reqData = $this->decode(RegistrationMessage::NAME, $blob); } catch (InvalidMessageException $e) { $this->log->warning('Received invalid message', array('exception' => $e)); $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid message coding', array($e->getMessage(), $e->getTraceAsString()))); return $resp->setCode(400); } $this->log->debug('Received registration request', array('reqData' => $reqData)); $cxn = $reqData['cxn']; $validation = Cxn::getValidationMessages($cxn); if (!empty($validation)) { // $cxn is not valid, so we can't use it for encoding. $resp = new InsecureMessage(array('is_error' => 1, 'error_message' => 'Invalid cxn details: ' . implode(', ', array_keys($validation)))); return $resp->setCode(400); } $respData = $this->call($reqData); $this->log->debug('Responding', array($cxn['cxnId'], $cxn['secret'], $respData)); return new StdMessage($cxn['cxnId'], $cxn['secret'], $respData); }
/** * @param Message $invalidInput * @throws Exception\InvalidMessageException * @dataProvider invalidInputExamples */ public function testInvalidInput($appKeyPair, $invalidInput) { $caKeyPair = KeyPair::create(); $this->assertNotEmpty($caKeyPair['privatekey']); $this->assertNotEmpty($caKeyPair['publickey']); $caCert = CA::create($caKeyPair, '/O=test'); $this->assertNotEmpty($caCert); $appMeta = array('title' => 'My App', 'appId' => self::APP_ID, 'appCert' => CA::signCSR($caKeyPair, $caCert, CA::createAppCSR($appKeyPair, '/O=Application Provider')), 'appUrl' => 'http://app-a.com/cxn', 'perm' => array('api' => array(), 'grant' => array('view all contacts'))); $appCxnStore = new ArrayCxnStore(); $regServer = new RegistrationServer($appMeta, $appKeyPair, $appCxnStore); list($headers, $blob, $code) = $regServer->handle($invalidInput->encode())->toHttp(); $this->assertEquals(400, $code); $message = InsecureMessage::decode($blob); $data = $message->getData(); $this->assertEquals(1, $data['is_error']); $this->assertEquals('Invalid message coding', $data['error_message']); }
public function decode($formats, $message) { $prefixLen = 0; foreach ($formats as $format) { $prefixLen = max($prefixLen, strlen($format)); } list($prefix) = explode(Constants::PROTOCOL_DELIM, substr($message, 0, $prefixLen + 1)); if (!in_array($prefix, $formats)) { throw new InvalidMessageException("Unexpected message type."); } switch ($prefix) { case StdMessage::NAME: return StdMessage::decode($this->cxnStore, $message); case InsecureMessage::NAME: return InsecureMessage::decode($message); case RegistrationMessage::NAME: return RegistrationMessage::decode($this->appId, $this->appPrivKey, $message); default: throw new InvalidMessageException("Unrecognized message type"); } }