blob: cbb03e55e8e565d7c409e3ccd6e9093f4066dbd3 [file] [log] [blame]
// Copyright 2015 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 "oauth2.h"
#include <sstream>
#include "absl/strings/string_view.h"
#include "file_helper.h"
#include "glog/logging.h"
#include "ioutil.h"
#include "json/json.h"
#include "json_util.h"
using std::string;
namespace devtools_goma {
bool ParseOAuth2AccessToken(const string& json,
string* token_type,
string* access_token,
absl::Duration* expires_in) {
static const char kAccessToken[] = "access_token";
static const char kTokenType[] = "token_type";
static const char kExpiresIn[] = "expires_in";
Json::Reader reader;
Json::Value root;
if (!reader.parse(json, root, false)) {
LOG(WARNING) << "invalid json";
return false;
}
string err;
if (!GetStringFromJson(root, kAccessToken, access_token, &err)) {
LOG(WARNING) << err;
return false;
}
if (!GetStringFromJson(root, kTokenType, token_type, &err)) {
LOG(WARNING) << err;
return false;
}
int expires_in_sec = 0;
if (!GetIntFromJson(root, kExpiresIn, &expires_in_sec, &err)) {
LOG(WARNING) << err;
return false;
}
if (expires_in_sec == 0) {
return false;
}
*expires_in = absl::Seconds(expires_in_sec);
return true;
}
static const char kAuthURI[] = "auth_uri";
static const char kTokenURI[] = "token_uri";
static const char kScope[] = "scope";
static const char kClientId[] = "client_id";
static const char kClientSecret[] = "client_secret";
// chrome-infra-auth.appspot oauth_config replies with client_not_so_secret.
static const char kClientNotSoSecret[] = "client_not_so_secret";
static const char kRefreshToken[] = "refresh_token";
static const char kType[] = "type";
// Google OAuth2 clients always have a secret, even if the client is an
// installed application/utility such as this.
// Please see following URL to understand why it is ok to do:
// https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/master/auth.py
static const char kDefaultClientId[] =
"687418631491-r6m1c3pr0lth5atp4ie07f03ae8omefc.apps.googleusercontent.com";
static const char kDefaultSecret[] = "R7e-JO3L5sKVczuR-dKQrijF";
void DefaultOAuth2Config(OAuth2Config* config) {
config->auth_uri = kGoogleAuthURI;
config->token_uri = kGoogleTokenURI;
config->scope = kGomaAuthScope;
config->client_id = kDefaultClientId;
config->client_secret = kDefaultSecret;
CHECK(config->enabled());
}
bool ParseOAuth2Config(const string& str, OAuth2Config* config) {
Json::Reader reader;
Json::Value root;
if (!reader.parse(str, root, false)) {
LOG(WARNING) << "invalid json";
return false;
}
string err;
string auth_uri;
if (!GetNonEmptyStringFromJson(root, kAuthURI, &auth_uri, &err)) {
LOG(WARNING) << err;
auth_uri = kGoogleAuthURI;
}
string token_uri;
if (!GetNonEmptyStringFromJson(root, kTokenURI, &token_uri, &err)) {
LOG(WARNING) << err;
token_uri = kGoogleTokenURI;
}
constexpr absl::string_view kLegacyGoogleTokenURI(
"https://www.googleapis.com/oauth2/v3/token");
if (token_uri == kLegacyGoogleTokenURI) {
LOG(WARNING) << "replace legacy token_uri:" << token_uri
<< " to new uri:" << kGoogleTokenURI;
token_uri = kGoogleTokenURI;
}
string scope;
if (!GetNonEmptyStringFromJson(root, kScope, &scope, &err)) {
LOG(WARNING) << err;
scope = kGomaAuthScope;
}
string client_id;
if (!GetNonEmptyStringFromJson(root, kClientId, &client_id, &err)) {
LOG(WARNING) << err;
return false;
}
string client_secret;
if (!GetNonEmptyStringFromJson(root, kClientSecret, &client_secret, &err)) {
if (!GetNonEmptyStringFromJson(root, kClientNotSoSecret, &client_secret,
&err)) {
LOG(WARNING) << err;
return false;
}
}
string type;
if (!GetNonEmptyStringFromJson(root, kType, &type, &err)) {
LOG(WARNING) << err;
}
string refresh_token;
(void)GetStringFromJson(root, kRefreshToken, &refresh_token, &err);
config->auth_uri = auth_uri;
config->token_uri = token_uri;
config->scope = scope;
config->client_id = client_id;
config->client_secret = client_secret;
config->refresh_token = refresh_token;
config->type = type;
return true;
}
string FormatOAuth2Config(const OAuth2Config& config) {
Json::Value root;
root[kAuthURI] = config.auth_uri;
root[kTokenURI] = config.token_uri;
root[kScope] = config.scope;
root[kClientId] = config.client_id;
root[kClientSecret] = config.client_secret;
root[kRefreshToken] = config.refresh_token;
root[kType] = config.type;
Json::FastWriter writer;
return writer.write(root);
}
bool SaveOAuth2Config(const string& filename, const OAuth2Config& config) {
string config_string = FormatOAuth2Config(config);
if (!WriteStringToFile(config_string, filename.c_str())) {
LOG(ERROR) << "Failed to write " << filename;
return false;
}
return true;
}
bool ParseServiceAccountJson(const string& str, ServiceAccountConfig* config) {
// chrome-infra's /creds/service_accounts doesn't have
// project_id, auth_uri, token_uri, auth_provider_x509_cert_url,
// client_x509_cert_url, different from service account json
// downloaded from google cloud console.
Json::Reader reader;
Json::Value root;
if (!reader.parse(str, root, false)) {
LOG(WARNING) << "invalid json";
return false;
}
string err;
string type_str;
if (!GetStringFromJson(root, "type", &type_str, &err)) {
LOG(WARNING) << err;
return false;
}
if (type_str != "service_account") {
LOG(WARNING) << "unexpected type: " << type_str;
return false;
}
string private_key;
if (!GetNonEmptyStringFromJson(root, "private_key", &private_key, &err)) {
LOG(WARNING) << err;
return false;
}
string client_email;
if (!GetNonEmptyStringFromJson(root, "client_email", &client_email, &err)) {
LOG(WARNING) << err;
return false;
}
string project_id;
string private_key_id;
string client_id;
string auth_uri;
string token_uri;
string auth_provider_x509_cert_url;
string client_x509_cert_url;
(void)GetStringFromJson(root, "project_id", &project_id, &err);
(void)GetStringFromJson(root, "private_key_id", &private_key_id, &err);
(void)GetStringFromJson(root, "client_id", &client_id, &err);
(void)GetStringFromJson(root, "auth_uri", &auth_uri, &err);
(void)GetStringFromJson(root, "token_uri", &token_uri, &err);
(void)GetStringFromJson(root, "auth_provider_x509_cert_url",
&auth_provider_x509_cert_url, &err);
(void)GetStringFromJson(root, "client_x509_cert_url", &client_x509_cert_url,
&err);
config->project_id = project_id;
config->private_key_id = private_key_id;
config->private_key = private_key;
config->client_email = client_email;
config->client_id = client_id;
config->auth_uri = auth_uri;
config->token_uri = token_uri;
config->auth_provider_x509_cert_url = auth_provider_x509_cert_url;
config->client_x509_cert_url = client_x509_cert_url;
return true;
}
} // namespace devtools_goma