blob: 2d4e539d8cce1c9107e3d426b13482e0b1ee17d5 [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REMOTE_CREDENTIALS_H_
#define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REMOTE_CREDENTIALS_H_
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "grpcpp/security/credentials.h"
#include "proxy_config.pb.h"
namespace milotic {
struct RemoteCredentials {
std::optional<std::string> username;
// TODO : b/320747974 - Make password optional as well
std::string password;
};
using CredentialsFileReader =
absl::AnyInvocable<absl::StatusOr<RemoteCredentials>(
absl::string_view file_path, absl::string_view network_endpoint)>;
using CredentialsFileWriter = absl::AnyInvocable<absl::Status(
absl::string_view new_path, absl::string_view old_path,
const RemoteCredentials& credentials, absl::string_view target_mac)>;
using GrpcCredentialFetcher = absl::AnyInvocable<
absl::StatusOr<std::shared_ptr<grpc::ChannelCredentials>>(
const milotic_grpc_proxy::GrpcAuth& grpc_auth)>;
using LoginFunction = absl::AnyInvocable<absl::Status(
absl::StatusOr<RemoteCredentials>& credentials)>;
inline absl::StatusOr<std::shared_ptr<grpc::ChannelCredentials>>
UnimplementedGrpcCredentialFetcher(
const milotic_grpc_proxy::GrpcAuth& grpc_auth) {
return absl::UnimplementedError("Grpc credential fetcher not implemented");
}
inline absl::StatusOr<RemoteCredentials> UnimplementedCredentialsFileReader(
absl::string_view file_path, absl::string_view network_endpoint) {
return absl::UnimplementedError("Credential file reader not implemented");
}
inline absl::Status UnimplementedCredentialsFileWriter(
absl::string_view new_path, absl::string_view old_path,
const RemoteCredentials& credentials, absl::string_view target_mac) {
return absl::UnimplementedError("Credential file writer not implemented");
}
class CredentialsFileManager {
public:
explicit CredentialsFileManager(CredentialsFileReader& reader,
CredentialsFileWriter& writer)
: reader_(reader), writer_(writer) {}
CredentialsFileManager(const CredentialsFileManager&) = delete;
CredentialsFileManager& operator=(const CredentialsFileManager&) = delete;
bool HasSources() const {
return !source_files_.empty() || !private_cache_path_.empty();
}
// Adds file sources for credentials. These are tried in sequence until one
// works. Once credentials have been read *and* used successfully, a cached
// value will be used until login fails or the cache is cleared.
template <typename Iter>
void AddSourceFiles(Iter begin, Iter end) {
source_files_.insert(source_files_.end(), begin, end);
}
// Sets the path to the private cache file.
// This file is updated by the CredentialsFileManager with the last working
// credentials. If a non-empty value is specified, this is the first source
// used.
void SetPrivateCachePath(std::string private_cache_path) {
private_cache_path_ = std::move(private_cache_path);
}
// Tries to log on using the cached credentials, or using each credentials
// file if there is no cached value. If login succeeds, the value is cached
// and stored in the private cache file.
//
// network_endpoint is passed to the CredentialsFileReader as a key to lookup
// the credentials.
//
// login_func should attempt to use the provided credentials
// and return Ok if it was able to log in. This function will be called with
// an error value if none of the source files could be read or if no source
// files were configured.
absl::Status RunLogin(absl::string_view network_endpoint,
LoginFunction login_func);
private:
absl::Status TryLogin(absl::string_view file_path,
absl::string_view network_endpoint,
LoginFunction& login_func)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(credentials_mutex_);
CredentialsFileReader& reader_;
CredentialsFileWriter& writer_;
std::vector<std::string> source_files_;
std::string private_cache_path_;
absl::Mutex credentials_mutex_;
absl::StatusOr<RemoteCredentials> last_tried_credentials_
ABSL_GUARDED_BY(credentials_mutex_) =
absl::FailedPreconditionError("Credentials not loaded");
absl::Status last_try_result_ ABSL_GUARDED_BY(credentials_mutex_) =
absl::NotFoundError("No working credentials found");
};
} // namespace milotic
#endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_REMOTE_CREDENTIALS_H_