Example #1
0
  void TSaslTransport::open() {
    NegotiationStatus status = TSASL_INVALID;
    uint32_t resLength;

    // Only client should open the underlying transport.
    if (isClient_ && !transport_->isOpen()) {
      transport_->open();
    }

    // initiate  SASL message
    handleSaslStartMessage();

    // SASL connection handshake
    while (!sasl_->isComplete()) {
      uint8_t* message = receiveSaslMessage(&status, &resLength);
      if (status == TSASL_COMPLETE) {
        if (isClient_) {
          if (!sasl_->isComplete()) {
            // Server sent COMPLETE out of order.
            throw TTransportException("Received COMPLETE but no handshake occurred");
          }
          break; // handshake complete
        }
      } else if (status != TSASL_OK) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
      uint32_t challengeLength;
      uint8_t* challenge = sasl_->evaluateChallengeOrResponse(
          message, resLength, &challengeLength);
      sendSaslMessage(sasl_->isComplete() ? TSASL_COMPLETE : TSASL_OK,
                      challenge, challengeLength);
    }

    // If the server isn't complete yet, we need to wait for its response.
    // This will occur with ANONYMOUS auth, for example, where we send an
    // initial response and are immediately complete.
    if (isClient_ && (status == TSASL_INVALID || status == TSASL_OK)) {
      receiveSaslMessage(&status, &resLength);
      if (status != TSASL_COMPLETE) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
    }

    // TODO : need to set the shouldWrap_ based on QOP
    /*
    String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
    if (qop != null && !qop.equalsIgnoreCase("auth"))
      shouldWrap_ = true;
    */
  }
/**
 * Performs the server side of the initial portion of the Thrift SASL protocol.
 * Receives the initial response from the client, creates a SASL server using
 * the mechanism requested by the client (if this server supports it), and
 * sends the first challenge back to the client.
 */
void TSaslServerTransport::handleSaslStartMessage() {
  uint32_t msgLength;
  NegotiationStatus status;

  uint8_t* message = receiveSaslMessage(&status, &msgLength);

  if (status != TSASL_START) {
    stringstream ss;
    ss << "Expecting START status, received " << status;
    sendSaslMessage(TSASL_ERROR,
                    reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
    throw TTransportException(ss.str());
  }

  // Message is a non-null terminated string; to use it like a
  // C-string we have to copy it into a null-terminated buffer.
  // The first message should be the mechanism string.
  string mechanism(reinterpret_cast<char*>(message), msgLength);

  map<string, TSaslServerDefinition*>::iterator defn =
      TSaslServerTransport::serverDefinitionMap_.find(mechanism);
  if (defn == TSaslServerTransport::serverDefinitionMap_.end()) {
    stringstream ss;
    ss << "Unsupported mechanism type " << mechanism;
    sendSaslMessage(TSASL_BAD,
                    reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
    throw TTransportException(TTransportException::BAD_ARGS, ss.str());
  }

  TSaslServerDefinition* serverDefinition = defn->second;
  sasl_.reset(new TSaslServer(mechanism, serverDefinition->protocol_,
                              serverDefinition->serverName_,
                              serverDefinition->realm_,
                              serverDefinition->flags_,
                              &serverDefinition->callbacks_[0]));

  uint32_t challengeLength;
  uint8_t* challenge = sasl_->evaluateChallengeOrResponse(
      reinterpret_cast<const uint8_t*>(mechanism.c_str()), msgLength, &challengeLength);
  // TODO: this is necessary for DIGEST-MD5 but not for GSSAPI. There should be a more
  // general way to do this rather than checking the challengeLength. For GSSAPI, this
  // is zero, the server just authenticates. For DIGEST-MD5, this begins some back and
  // forth to send additional information.
  if (challengeLength != 0) {
    sendSaslMessage(sasl_->isComplete() ? TSASL_COMPLETE : TSASL_OK,
                    challenge, challengeLength);
  }
}
Example #3
0
void TSaslServerTransport::handleSaslStartMessage() {
  uint32_t resLength;
  NegotiationStatus status;

  uint8_t* message = receiveSaslMessage(&status, &resLength);
  // Message is a non-null terminated string; to use it like a
  // C-string we have to copy it into a null-terminated buffer.
  string message_str(reinterpret_cast<char*>(message), resLength);

  if (status != TSASL_START) {
    stringstream ss;
    ss << "Expecting START status, received " << status;
    sendSaslMessage(TSASL_ERROR,
                    reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
    throw TTransportException(ss.str());
  }
  map<string, TSaslServerDefinition*>::iterator defn =
      TSaslServerTransport::serverDefinitionMap_.find(message_str);
  if (defn == TSaslServerTransport::serverDefinitionMap_.end()) {
    stringstream ss;
    ss << "Unsupported mechanism type " << message_str;
    sendSaslMessage(TSASL_BAD,
                    reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
    throw TTransportException(TTransportException::BAD_ARGS, ss.str());
  }
  // TODO: when should realm be used?
  string realm;
  TSaslServerDefinition* serverDefinition = defn->second;
  sasl_.reset(new TSaslServer(serverDefinition->protocol_,
                              serverDefinition->serverName_, realm,
                              serverDefinition->flags_,
                              &serverDefinition->callbacks_[0]));
  // First argument is interpreted as C-string
  sasl_->evaluateChallengeOrResponse(
      reinterpret_cast<const uint8_t*>(message_str.c_str()), resLength, &resLength);

}
  void TSaslTransport::open() {
    // Only client should open the underlying transport.
    if (isClient_ && !transport_->isOpen()) transport_->open();

    // initiate  SASL message
    handleSaslStartMessage();

    // The number of messages received so far.
    int numMessagesReceived = 0;
    NegotiationStatus status = TSASL_INVALID;
    uint32_t msgLength;

    // SASL connection handshake
    while (!sasl_->isComplete()) {
      uint8_t* message = receiveSaslMessage(&status, &msgLength);
      ++numMessagesReceived;

      if (status != TSASL_COMPLETE && status != TSASL_OK) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }

      if (numMessagesReceived == 1 && msgLength == 0 &&
          sasl_->getMechanismName() == "DIGEST-MD5") {
        // TODO: this is a hack, not sure what the proper behavior is. These messages
        // are optional and checking for QOP support.
        // What's the general way to implement the protocol?
        continue;
      }

      uint32_t challengeLength;
      uint8_t* challenge = sasl_->evaluateChallengeOrResponse(
          message, msgLength, &challengeLength);

      if (status == TSASL_COMPLETE && isClient_) {
        // If we are the client, and the server indicates COMPLETE, we don't need to
        // send back any further response.
        break;
      }

      sendSaslMessage(sasl_->isComplete() ? TSASL_COMPLETE : TSASL_OK,
                      challenge, challengeLength);
    }

    // If the server isn't complete yet, we need to wait for its response.
    // This will occur with ANONYMOUS auth, for example, where we send an
    // initial response and are immediately complete.
    if (isClient_ && (status == TSASL_INVALID || status == TSASL_OK)) {
      receiveSaslMessage(&status, &msgLength);
      if (status != TSASL_COMPLETE) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
    }

    // TODO : need to set the shouldWrap_ based on QOP
    /*
    String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
    if (qop != null && !qop.equalsIgnoreCase("auth"))
      shouldWrap_ = true;
    */
  }