unique_ptr<IOBuf> HeaderServerChannel::handleSecurityMessage(
  unique_ptr<IOBuf>&& buf) {
  if (header_->getClientType() == THRIFT_HEADER_SASL_CLIENT_TYPE) {
    if (!header_->isSupportedClient()) {
      if (protectionState_ == ProtectionState::UNKNOWN) {
        // The client tried to use SASL, but it's not supported by
        // policy.  Tell the client to fall back.

        // TODO mhorowitz: generate a real message here.
        try {
          sendMessage(nullptr, IOBuf::create(0));
        } catch (const std::exception& e) {
          LOG(ERROR) << "Failed to send message: " << e.what();
        }

        return nullptr;
      } else {
        // The supported client set changed halfway through or
        // something.  Bail out.
        protectionState_ = ProtectionState::INVALID;
        LOG(WARNING) << "Inconsistent SASL support";
        TTransportException ex("Inconsistent SASL support");
        messageReceiveError(make_exception_ptr(ex));
        return nullptr;
      }
    } else if (protectionState_ == ProtectionState::UNKNOWN ||
        protectionState_ == ProtectionState::INPROGRESS) {
      protectionState_ = ProtectionState::INPROGRESS;
      saslServer_->consumeFromClient(&saslServerCallback_, std::move(buf));
      return nullptr;
    }
    // else, fall through to application message processing
  } else if (protectionState_ == ProtectionState::VALID ||
      (protectionState_ == ProtectionState::INPROGRESS &&
          !header_->isSupportedClient())) {
    // Either negotiation has completed or negotiation is incomplete,
    // non-sasl was received, but is not permitted.
    // We should fail hard in this case.
    protectionState_ = ProtectionState::INVALID;
    LOG(WARNING) << "non-SASL message received on SASL channel";
    TTransportException ex("non-SASL message received on SASL channel");
    messageReceiveError(make_exception_ptr(ex));
    return nullptr;
  } else if (protectionState_ == ProtectionState::UNKNOWN) {
    // This is the path non-SASL-aware (or SASL-disabled) clients will
    // take.
    VLOG(5) << "non-SASL client connection received";
    protectionState_ = ProtectionState::NONE;
  } else if (protectionState_ == ProtectionState::INPROGRESS &&
      header_->isSupportedClient()) {
    // If a client  permits a non-secure connection, we allow falling back to
    // one even if a SASL handshake is in progress.
    LOG(INFO) << "Client initiated a fallback during a SASL handshake";
    // Cancel any SASL-related state, and log
    protectionState_ = ProtectionState::NONE;
    saslServerCallback_.cancelTimeout();
    saslServer_->markChannelCallbackUnavailable();
    const auto& observer = getEventBase()->getObserver();
    if (observer) {
      observer->saslFallBack();
    }
  }

  return std::move(buf);
}
示例#2
0
void RequestChannel::sendRequestAsync(
    apache::thrift::RpcOptions& rpcOptions,
    std::unique_ptr<apache::thrift::RequestCallback> callback,
    std::unique_ptr<apache::thrift::ContextStack> ctx,
    std::unique_ptr<folly::IOBuf> buf,
    std::shared_ptr<apache::thrift::transport::THeader> header,
    RpcKind kind) {
  auto eb = getEventBase();
  if (!eb || eb->isInEventBaseThread()) {
    switch (kind) {
      case RpcKind::SINGLE_REQUEST_NO_RESPONSE:
        // Calling asyncComplete before sending because
        // sendOnewayRequest moves from ctx and clears it.
        ctx->asyncComplete();
        sendOnewayRequest(
            rpcOptions,
            std::move(callback),
            std::move(ctx),
            std::move(buf),
            std::move(header));
        break;
      case RpcKind::SINGLE_REQUEST_SINGLE_RESPONSE:
        sendRequest(
            rpcOptions,
            std::move(callback),
            std::move(ctx),
            std::move(buf),
            std::move(header));
        break;
      case RpcKind::SINGLE_REQUEST_STREAMING_RESPONSE:
        sendStreamRequest(
            rpcOptions,
            std::move(callback),
            std::move(ctx),
            std::move(buf),
            std::move(header));
        break;
      default:
        folly::assume_unreachable();
        break;
    }

  } else {
    switch (kind) {
      case RpcKind::SINGLE_REQUEST_NO_RESPONSE:
        eb->runInEventBaseThread([this,
                                  rpcOptions,
                                  callback = std::move(callback),
                                  ctx = std::move(ctx),
                                  buf = std::move(buf),
                                  header = std::move(header)]() mutable {
          // Calling asyncComplete before sending because
          // sendOnewayRequest moves from ctx and clears it.
          ctx->asyncComplete();
          sendOnewayRequest(
              rpcOptions,
              std::move(callback),
              std::move(ctx),
              std::move(buf),
              std::move(header));
        });
        break;
      case RpcKind::SINGLE_REQUEST_SINGLE_RESPONSE:
        eb->runInEventBaseThread([this,
                                  rpcOptions,
                                  callback = std::move(callback),
                                  ctx = std::move(ctx),
                                  buf = std::move(buf),
                                  header = std::move(header)]() mutable {
          sendRequest(
              rpcOptions,
              std::move(callback),
              std::move(ctx),
              std::move(buf),
              std::move(header));
        });
        break;
      case RpcKind::SINGLE_REQUEST_STREAMING_RESPONSE:
        eb->runInEventBaseThread([this,
                                  rpcOptions,
                                  callback = std::move(callback),
                                  ctx = std::move(ctx),
                                  buf = std::move(buf),
                                  header = std::move(header)]() mutable {
          sendStreamRequest(
              rpcOptions,
              std::move(callback),
              std::move(ctx),
              std::move(buf),
              std::move(header));
        });
        break;
      default:
        folly::assume_unreachable();
        break;
    }
  }
}
示例#3
0
testing::NiceMock<MockTAsyncTransport>* newMockTransport(EventBase* evb) {
  auto transport = new testing::NiceMock<MockTAsyncTransport>();
  EXPECT_CALL(*transport, getEventBase())
    .WillRepeatedly(testing::Return(evb));
  return transport;
}
示例#4
0
void RequestChannel::sendRequestSync(
    RpcOptions& options,
    std::unique_ptr<RequestCallback> cb,
    std::unique_ptr<apache::thrift::ContextStack> ctx,
    std::unique_ptr<folly::IOBuf> buf,
    std::shared_ptr<apache::thrift::transport::THeader> header,
    RpcKind kind) {
  auto eb = getEventBase();
  // We intentionally only support sync_* calls from the EventBase thread.
  eb->checkIsInEventBaseThread();

  folly::fibers::Baton baton;
  auto scb =
      std::make_unique<ClientSyncBatonCallback>(std::move(cb), baton, kind);

  folly::exception_wrapper ew;
  auto const onFiber = folly::fibers::onFiber();
  auto const inEventBase = eb->inRunningEventBaseThread();
  baton.wait([&, onFiber, inEventBase] {
    try {
      switch (kind) {
        case RpcKind::SINGLE_REQUEST_NO_RESPONSE:
          sendOnewayRequest(
              options,
              std::move(scb),
              std::move(ctx),
              std::move(buf),
              std::move(header));
          break;
        case RpcKind::SINGLE_REQUEST_SINGLE_RESPONSE:
          sendRequest(
              options,
              std::move(scb),
              std::move(ctx),
              std::move(buf),
              std::move(header));
          break;
        case RpcKind::SINGLE_REQUEST_STREAMING_RESPONSE:
          sendStreamRequest(
              options,
              std::move(scb),
              std::move(ctx),
              std::move(buf),
              std::move(header));
          break;
        default:
          folly::assume_unreachable();
      }
    } catch (const std::exception& e) {
      ew = folly::exception_wrapper(std::current_exception(), e);
      baton.post();
    } catch (...) {
      ew = folly::exception_wrapper(std::current_exception());
      baton.post();
    }
    if (!onFiber || !inEventBase) {
      while (!baton.ready()) {
        eb->drive();
      }
    }
  });
  if (ew) {
    ew.throw_exception();
  }
}