/*
 * This file is a part of the LinkAhead Project.
 *
 * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
 * Copyright (C) 2021-2024 IndiScale GmbH <info@indiscale.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 *
 */

#ifndef LINKAHEAD_AUTHENTICATION_H
#define LINKAHEAD_AUTHENTICATION_H
/**
 * @file linkahead/authentication.h
 * @author Timm Fitschen
 * @date 2021-06-28
 * @brief Configuration and setup of the client authentication.
 */
#include <grpcpp/security/auth_context.h> // for AuthContext
#include <grpcpp/security/credentials.h>  // for CallCredentials, MetadataC...
#include <grpcpp/support/config.h>        // for string
#include <grpcpp/support/interceptor.h>   // for Status
#include <grpcpp/support/string_ref.h>    // for string_ref
#include <map>                            // for multimap
#include <memory>                         // for shared_ptr
#include <string>                         // for string, basic_string
#include "linkahead/utility.h"            // for base64_encode

namespace linkahead {
namespace authentication {
using grpc::AuthContext;
using grpc::MetadataCredentialsPlugin;
using grpc::Status;
using grpc::string_ref;
using linkahead::utility::base64_encode;

/**
 * @brief Abstract base class for authenticators.
 */
class Authenticator {
public:
  virtual ~Authenticator() = default;
  [[nodiscard]] virtual auto GetCallCredentials() const
    -> std::shared_ptr<grpc::CallCredentials> = 0;
};

/**
 * @brief Implementation of a MetadataCredentialsPlugin which my be created by
 * any implementation of the Authenticator class. Only intended for internal
 * use.
 */
class MetadataCredentialsPluginImpl : public MetadataCredentialsPlugin {
private:
  std::string key;
  std::string value;

public:
  MetadataCredentialsPluginImpl(std::string key, std::string value);

  auto GetMetadata(string_ref service_url, string_ref method_name,
                   const AuthContext &channel_auth_context,
                   std::multimap<grpc::string, grpc::string> *metadata) -> Status override;
};

class PlainPasswordAuthenticator : public Authenticator {
private:
  std::string basic;

public:
  PlainPasswordAuthenticator(const std::string &username, const std::string &password);

  [[nodiscard]] auto GetCallCredentials() const -> std::shared_ptr<grpc::CallCredentials> override;
};
} // namespace authentication
} // namespace linkahead
#endif