1
#include "source/extensions/grpc_credentials/file_based_metadata/config.h"
2

            
3
#include "envoy/config/core/v3/grpc_service.pb.h"
4
#include "envoy/config/grpc_credential/v3/file_based_metadata.pb.h"
5
#include "envoy/config/grpc_credential/v3/file_based_metadata.pb.validate.h"
6
#include "envoy/grpc/google_grpc_creds.h"
7
#include "envoy/registry/registry.h"
8

            
9
#include "source/common/config/datasource.h"
10
#include "source/common/config/utility.h"
11
#include "source/common/grpc/google_grpc_creds_impl.h"
12
#include "source/common/protobuf/message_validator_impl.h"
13
#include "source/common/protobuf/utility.h"
14

            
15
namespace Envoy {
16
namespace Extensions {
17
namespace GrpcCredentials {
18
namespace FileBasedMetadata {
19

            
20
std::shared_ptr<grpc::ChannelCredentials>
21
FileBasedMetadataGrpcCredentialsFactory::getChannelCredentials(
22
    const envoy::config::core::v3::GrpcService& grpc_service_config,
23
4
    Server::Configuration::CommonFactoryContext& context) {
24
4
  const auto& google_grpc = grpc_service_config.google_grpc();
25
4
  std::shared_ptr<grpc::ChannelCredentials> creds =
26
4
      Grpc::CredsUtility::defaultSslChannelCredentials(grpc_service_config, context.api());
27
4
  std::shared_ptr<grpc::CallCredentials> call_creds = nullptr;
28
5
  for (const auto& credential : google_grpc.call_credentials()) {
29
5
    switch (credential.credential_specifier_case()) {
30
4
    case envoy::config::core::v3::GrpcService::GoogleGrpc::CallCredentials::
31
4
        CredentialSpecifierCase::kFromPlugin: {
32
4
      if (credential.from_plugin().name() == "envoy.grpc_credentials.file_based_metadata") {
33
4
        FileBasedMetadataGrpcCredentialsFactory file_based_metadata_credentials_factory;
34
        // We don't deal with validation failures here at runtime today, see
35
        // https://github.com/envoyproxy/envoy/issues/8010.
36
4
        const Envoy::ProtobufTypes::MessagePtr file_based_metadata_config_message =
37
4
            Envoy::Config::Utility::translateToFactoryConfig(
38
4
                credential.from_plugin(), ProtobufMessage::getNullValidationVisitor(),
39
4
                file_based_metadata_credentials_factory);
40
4
        const auto& file_based_metadata_config = Envoy::MessageUtil::downcastAndValidate<
41
4
            const envoy::config::grpc_credential::v3::FileBasedMetadataConfig&>(
42
4
            *file_based_metadata_config_message, ProtobufMessage::getNullValidationVisitor());
43
4
        std::shared_ptr<grpc::CallCredentials> new_call_creds =
44
4
            grpc::MetadataCredentialsFromPlugin(std::make_unique<FileBasedMetadataAuthenticator>(
45
4
                file_based_metadata_config, context.api()));
46
4
        if (call_creds == nullptr) {
47
3
          call_creds = new_call_creds;
48
3
        } else {
49
1
          call_creds = grpc::CompositeCallCredentials(call_creds, new_call_creds);
50
1
        }
51
4
      }
52
4
      break;
53
    }
54
1
    default:
55
      // unused credential types
56
1
      continue;
57
5
    }
58
5
  }
59
4
  if (call_creds != nullptr) {
60
3
    return grpc::CompositeChannelCredentials(creds, call_creds);
61
3
  }
62
1
  return creds;
63
4
}
64

            
65
grpc::Status
66
FileBasedMetadataAuthenticator::GetMetadata(grpc::string_ref, grpc::string_ref,
67
                                            const grpc::AuthContext&,
68
5
                                            std::multimap<grpc::string, grpc::string>* metadata) {
69
5
  std::string header_key = "authorization";
70
5
  std::string header_prefix = config_.header_prefix();
71
5
  if (!config_.header_key().empty()) {
72
3
    header_key = config_.header_key();
73
3
  }
74
  // TODO(#14320): avoid using an exception here or find some way of doing this
75
  // in the main thread.
76
5
  TRY_NEEDS_AUDIT {
77
5
    std::string header_value = THROW_OR_RETURN_VALUE(
78
5
        Envoy::Config::DataSource::read(config_.secret_data(), true, api_), std::string);
79
5
    metadata->insert(std::make_pair(header_key, header_prefix + header_value));
80
5
  }
81
5
  END_TRY
82
5
  catch (const EnvoyException& e) {
83
1
    return {grpc::StatusCode::NOT_FOUND, e.what()};
84
1
  }
85
4
  return grpc::Status::OK;
86
5
}
87

            
88
/**
89
 * Static registration for the file based metadata Google gRPC credentials factory. @see
90
 * RegisterFactory.
91
 */
92
REGISTER_FACTORY(FileBasedMetadataGrpcCredentialsFactory, Grpc::GoogleGrpcCredentialsFactory);
93

            
94
} // namespace FileBasedMetadata
95
} // namespace GrpcCredentials
96
} // namespace Extensions
97
} // namespace Envoy