Beispiel #1
0
pj_status_t user_lookup(pj_pool_t *pool,
                        const pjsip_auth_lookup_cred_param *param,
                        pjsip_cred_info *cred_info,
                        void* av_param)
{
  const pj_str_t* acc_name = &param->acc_name;
  const pj_str_t* realm = &param->realm;
  const pjsip_rx_data* rdata = param->rdata;
  SAS::TrailId trail = get_trail(rdata);

  pj_status_t status = PJSIP_EAUTHACCNOTFOUND;

  // Get the impi and the nonce.  There must be an authorization header otherwise
  // PJSIP wouldn't have called this method.
  std::string impi = PJUtils::pj_str_to_string(acc_name);
  pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)
           pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);
  std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce);

  // Get the Authentication Vector from the store.
  Json::Value* av = (Json::Value*)av_param;

  if (av == NULL)
  {
    LOG_WARNING("Received an authentication request for %s with nonce %s, but no matching AV found", impi.c_str(), nonce.c_str());
  }

  if ((av != NULL) &&
      (!verify_auth_vector(av, impi, trail)))
  {
    // Authentication vector is badly formed.
    av = NULL;                                                 // LCOV_EXCL_LINE
  }

  if (av != NULL)
  {
    pj_cstr(&cred_info->scheme, "digest");
    pj_strdup(pool, &cred_info->username, acc_name);
    if (av->isMember("aka"))
    {
      // AKA authentication.  The response in the AV must be used as a
      // plain-text password for the MD5 Digest computation.  Convert the text
      // into binary as this is what PJSIP is expecting.
      std::string response = (*av)["aka"]["response"].asString();
      std::string xres;
      for (size_t ii = 0; ii < response.length(); ii += 2)
      {
        xres.push_back((char)(pj_hex_digit_to_val(response[ii]) * 16 +
                              pj_hex_digit_to_val(response[ii+1])));
      }
      cred_info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
      pj_strdup2(pool, &cred_info->data, xres.c_str());
      LOG_DEBUG("Found AKA XRES = %.*s", cred_info->data.slen, cred_info->data.ptr);

      // Use default realm as it isn't specified in the AV.
      pj_strdup(pool, &cred_info->realm, realm);
      status = PJ_SUCCESS;
    }
    else if (av->isMember("digest"))
    {
      if (pj_strcmp2(realm, (*av)["digest"]["realm"].asCString()) == 0)
      {
        // Digest authentication, so ha1 field is hashed password.
        cred_info->data_type = PJSIP_CRED_DATA_DIGEST;
        pj_strdup2(pool, &cred_info->data, (*av)["digest"]["ha1"].asCString());
        cred_info->realm = *realm;
        LOG_DEBUG("Found Digest HA1 = %.*s", cred_info->data.slen, cred_info->data.ptr);
        status = PJ_SUCCESS;
      }
      else
      {
        // These credentials are for a different realm, so no credentials were
        // actually provided for us to check.
        status = PJSIP_EAUTHNOAUTH;
      }
    }

    correlate_branch_from_av(av, trail);
  }

  return status;
}
Beispiel #2
0
HTTPCode AuthTimeoutTask::handle_response(std::string body)
{
  Json::Value json_body;
  std::string json_str = body;
  Json::Reader reader;
  bool parsingSuccessful = reader.parse(json_str.c_str(), json_body);

  if (!parsingSuccessful)
  {
    LOG_ERROR("Failed to read opaque data, %s",
              reader.getFormattedErrorMessages().c_str());
    return HTTP_BAD_REQUEST;
  }

  if ((json_body.isMember("impu")) &&
      ((json_body)["impu"].isString()))
  {
    _impu = json_body.get("impu", "").asString();
    report_sip_all_register_marker(trail(), _impu);
  }
  else
  {
    LOG_ERROR("IMPU not available in JSON");
    return HTTP_BAD_REQUEST;
  }

  if ((json_body.isMember("impi")) &&
      ((json_body)["impi"].isString()))
  {
    _impi = json_body.get("impi", "").asString();
  }
  else
  {
    LOG_ERROR("IMPI not available in JSON");
    return HTTP_BAD_REQUEST;
  }

  if ((json_body.isMember("nonce")) &&
      ((json_body)["nonce"].isString()))
  {
    _nonce = json_body.get("nonce", "").asString();
  }
  else
  {
    LOG_ERROR("Nonce not available in JSON");
    return HTTP_BAD_REQUEST;
  }

  bool success = false;
  uint64_t cas;
  Json::Value* av = _cfg->_avstore->get_av(_impi, _nonce, cas, trail());
  if (av != NULL)
  {
    // Use the original REGISTER's branch parameter for SAS
    // correlation

    correlate_branch_from_av(av, trail());

    // If authentication completed, we'll have written a marker to
    // indicate that. Look for it.
    if (!av->isMember("tombstone"))
    {
      LOG_DEBUG("AV for %s:%s has timed out", _impi.c_str(), _nonce.c_str());

      // The AUTHENTICATION_TIMEOUT SAR is idempotent, so there's no
      // problem if Chronos' timer pops twice (e.g. if we have high
      // latency and these operations take more than 2 seconds).

      // If either of these operations fail, we return a 500 Internal
      // Server Error - this will trigger Chronos to try a different
      // Sprout, which may have better connectivity to Homestead or Memcached.
      HTTPCode hss_query = _cfg->_hss->update_registration_state(_impu, _impi, HSSConnection::AUTH_TIMEOUT, trail());

      if (hss_query == HTTP_OK)
      {
        success = true;
      }
    }
    else
    {
      SAS::Event event(trail(), SASEvent::AUTHENTICATION_TIMER_POP_IGNORED, 0);
      SAS::report_event(event);

      LOG_DEBUG("Tombstone record indicates Authentication Vector has been used successfully - ignoring timer pop");
      success = true;
    }
  }
  else
  {
    LOG_WARNING("Could not find AV for %s:%s when checking authentication timeout", _impi.c_str(), _nonce.c_str()); // LCOV_EXCL_LINE
  }
  delete av;

  return success ? HTTP_OK : HTTP_SERVER_ERROR;
}