blob: 24f34f8f1326dc396a022bda7440f2b482cf9dc4 [file] [log] [blame]
// Copyright 2017 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "luci_context.h"
#include <string>
#include "glog/logging.h"
#include "json/json.h"
#include "json_util.h"
namespace devtools_goma {
namespace {
static bool ParseLocalAuth(const Json::Value& local_auth,
LuciContextAuth* luci_context_auth) {
static const char kRpcPort[] = "rpc_port";
static const char kSecret[] = "secret";
static const char kAccounts[] = "accounts";
static const char kDefaultAccountId[] = "default_account_id";
static const char kId[] = "id";
luci_context_auth->clear();
if (!local_auth.isObject()) {
LOG(WARNING) << "local_auth is not object";
return false;
}
std::string err;
if (!GetIntFromJson(local_auth, kRpcPort,
&luci_context_auth->rpc_port, &err)) {
LOG(WARNING) << err;
return false;
}
if (!GetStringFromJson(local_auth, kSecret,
&luci_context_auth->secret, &err)) {
LOG(WARNING) << err;
return false;
}
if (local_auth.isMember(kAccounts)) {
const auto& accounts = local_auth[kAccounts];
if (!accounts.isArray()) {
LOG(WARNING) << "local_auth['accounts'] is not a list";
return false;
}
for (const auto& account : accounts) {
if (!account.isObject()) {
LOG(WARNING) << "not an object in local_auth['accounts']";
return false;
}
LuciContextAuthAccount luci_account;
if (!GetStringFromJson(account, kId, &luci_account.id, &err)) {
LOG(WARNING) << "error when reading account:" << err;
return false;
}
luci_context_auth->accounts.push_back(luci_account);
}
}
// Note: it can be missing or be null. In this case, LUCI authentication
// should not be used by default. It is still valid LuciContextAuth object
// though.
if (local_auth.isMember(kDefaultAccountId) &&
!local_auth[kDefaultAccountId].isNull()) {
if (!GetStringFromJson(local_auth, kDefaultAccountId,
&luci_context_auth->default_account_id, &err)) {
LOG(WARNING) << err;
return false;
}
}
return true;
}
} // namespace
bool ParseLuciContext(
const std::string& json_body, LuciContext* luci_context) {
DCHECK(luci_context);
static const char kLocalAuth[] = "local_auth";
Json::Reader reader;
Json::Value root;
if (!reader.parse(json_body, root, false)) {
LOG(WARNING) << "invalid json";
return false;
}
if (root.isMember(kLocalAuth)) {
if (!ParseLocalAuth(root[kLocalAuth], &luci_context->local_auth)) {
return false;
}
} else {
LOG(INFO) << "missing " << kLocalAuth;
}
// TODO: implement swarming?
// https://github.com/luci/luci-py/blob/master/client/LUCI_CONTEXT.md
return true;
}
std::string LuciOAuthTokenRequest::ToString() const {
static const char kScopes[] = "scopes";
static const char kSecret[] = "secret";
static const char kAccountId[] = "account_id";
if (scopes.empty() || secret.empty()) {
LOG(WARNING) << "trying to make string from invalid LuciOAuthTokenRequest";
return std::string();
}
Json::Value root;
for (const auto& scope : scopes) {
root[kScopes].append(Json::Value(scope));
}
root[kSecret] = secret;
// 'account_id' can be empty if using old protocol that doesn't allow
// specifying accounts. See LuciContextAuth::enabled().
if (!account_id.empty()) {
root[kAccountId] = account_id;
}
Json::FastWriter writer;
return writer.write(root);
}
bool ParseLuciOAuthTokenResponse(
const std::string& json_body, LuciOAuthTokenResponse* resp) {
DCHECK(resp);
static const char kErrorCode[] = "error_code";
static const char kErrorMessage[] = "error_message";
static const char kAccessToken[] = "access_token";
static const char kExpiry[] = "expiry";
Json::Reader reader;
Json::Value root;
if (!reader.parse(json_body, root, false)) {
LOG(WARNING) << "invalid json";
return false;
}
Json::Value default_error_code(0);
const Json::Value& error_code = root.get(kErrorCode, default_error_code);
if (!error_code.isInt()) {
LOG(WARNING) << kErrorCode << " is not int";
return false;
}
resp->error_code = error_code.asInt();
if (resp->error_code != 0) {
std::string err;
if (!GetStringFromJson(root, kErrorMessage, &resp->error_message, &err)) {
LOG(WARNING) << err
<< " error_code=" << resp->error_code;
return false;
}
return true;
}
std::string err;
if (!GetStringFromJson(root, kAccessToken, &resp->access_token, &err)) {
LOG(WARNING) << err;
return false;
}
if (!GetInt64FromJson(root, kExpiry, &resp->expiry, &err)) {
LOG(WARNING) << err;
return false;
}
return true;
}
} // namespace devtools_goma