| #!/usr/bin/env python3 |
| |
| # Copyright 2022 gRPC authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # Generator script for src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h and test/core/security/grpc_tls_credentials_options_comparator_test.cc |
| # Should be executed from grpc's root directory. |
| |
| from __future__ import print_function |
| |
| import collections |
| from dataclasses import dataclass |
| import difflib |
| import filecmp |
| import os |
| import sys |
| import tempfile |
| |
| |
| @dataclass |
| class DataMember: |
| name: str # name of the data member without the trailing '_' |
| type: str # Type (eg. std::string, bool) |
| test_name: str # The name to use for the associated test |
| test_value_1: str # Test-specific value to use for comparison |
| test_value_2: str # Test-specific value (different from test_value_1) |
| default_initializer: str = ( # If non-empty, this will be used as the default initialization of this field |
| "" |
| ) |
| getter_comment: str = "" # Comment to add before the getter for this field |
| special_getter_return_type: str = ( # Override for the return type of getter (eg. const std::string&) |
| "" |
| ) |
| override_getter: str = ( # Override for the entire getter method. Relevant for certificate_verifier and certificate_provider |
| "" |
| ) |
| setter_comment: str = "" # Commend to add before the setter for this field |
| setter_move_semantics: bool = False # Should the setter use move-semantics |
| special_comparator: str = ( # If non-empty, this will be used in `operator==` |
| "" |
| ) |
| |
| |
| _DATA_MEMBERS = [ |
| DataMember( |
| name="cert_request_type", |
| type="grpc_ssl_client_certificate_request_type", |
| default_initializer="GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE", |
| test_name="DifferentCertRequestType", |
| test_value_1="GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE", |
| test_value_2="GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY", |
| ), |
| DataMember( |
| name="verify_server_cert", |
| type="bool", |
| default_initializer="true", |
| test_name="DifferentVerifyServerCert", |
| test_value_1="false", |
| test_value_2="true", |
| ), |
| DataMember( |
| name="min_tls_version", |
| type="grpc_tls_version", |
| default_initializer="grpc_tls_version::TLS1_2", |
| test_name="DifferentMinTlsVersion", |
| test_value_1="grpc_tls_version::TLS1_2", |
| test_value_2="grpc_tls_version::TLS1_3", |
| ), |
| DataMember( |
| name="max_tls_version", |
| type="grpc_tls_version", |
| default_initializer="grpc_tls_version::TLS1_3", |
| test_name="DifferentMaxTlsVersion", |
| test_value_1="grpc_tls_version::TLS1_2", |
| test_value_2="grpc_tls_version::TLS1_3", |
| ), |
| DataMember( |
| name="certificate_verifier", |
| type="grpc_core::RefCountedPtr<grpc_tls_certificate_verifier>", |
| override_getter="""grpc_tls_certificate_verifier* certificate_verifier() { |
| return certificate_verifier_.get(); |
| }""", |
| setter_move_semantics=True, |
| special_comparator=( |
| "(certificate_verifier_ == other.certificate_verifier_ ||" |
| " (certificate_verifier_ != nullptr && other.certificate_verifier_" |
| " != nullptr &&" |
| " certificate_verifier_->Compare(other.certificate_verifier_.get())" |
| " == 0))" |
| ), |
| test_name="DifferentCertificateVerifier", |
| test_value_1="MakeRefCounted<HostNameCertificateVerifier>()", |
| test_value_2='MakeRefCounted<XdsCertificateVerifier>(nullptr, "")', |
| ), |
| DataMember( |
| name="check_call_host", |
| type="bool", |
| default_initializer="true", |
| test_name="DifferentCheckCallHost", |
| test_value_1="false", |
| test_value_2="true", |
| ), |
| DataMember( |
| name="certificate_provider", |
| type="grpc_core::RefCountedPtr<grpc_tls_certificate_provider>", |
| getter_comment=( |
| "Returns the distributor from certificate_provider_ if it is set," |
| " nullptr otherwise." |
| ), |
| override_getter="""grpc_tls_certificate_distributor* certificate_distributor() { |
| if (certificate_provider_ != nullptr) { return certificate_provider_->distributor().get(); } |
| return nullptr; |
| }""", |
| setter_move_semantics=True, |
| special_comparator=( |
| "(certificate_provider_ == other.certificate_provider_ ||" |
| " (certificate_provider_ != nullptr && other.certificate_provider_" |
| " != nullptr &&" |
| " certificate_provider_->Compare(other.certificate_provider_.get())" |
| " == 0))" |
| ), |
| test_name="DifferentCertificateProvider", |
| test_value_1=( |
| 'MakeRefCounted<StaticDataCertificateProvider>("root_cert_1",' |
| " PemKeyCertPairList())" |
| ), |
| test_value_2=( |
| 'MakeRefCounted<StaticDataCertificateProvider>("root_cert_2",' |
| " PemKeyCertPairList())" |
| ), |
| ), |
| DataMember( |
| name="watch_root_cert", |
| type="bool", |
| default_initializer="false", |
| setter_comment=( |
| "If need to watch the updates of root certificates with name" |
| " |root_cert_name|. The default value is false. If used in" |
| " tls_credentials, it should always be set to true unless the root" |
| " certificates are not needed." |
| ), |
| test_name="DifferentWatchRootCert", |
| test_value_1="false", |
| test_value_2="true", |
| ), |
| DataMember( |
| name="root_cert_name", |
| type="std::string", |
| special_getter_return_type="const std::string&", |
| setter_comment=( |
| "Sets the name of root certificates being watched, if" |
| " |set_watch_root_cert| is called. If not set, an empty string will" |
| " be used as the name." |
| ), |
| setter_move_semantics=True, |
| test_name="DifferentRootCertName", |
| test_value_1='"root_cert_name_1"', |
| test_value_2='"root_cert_name_2"', |
| ), |
| DataMember( |
| name="watch_identity_pair", |
| type="bool", |
| default_initializer="false", |
| setter_comment=( |
| "If need to watch the updates of identity certificates with name" |
| " |identity_cert_name|. The default value is false. If used in" |
| " tls_credentials, it should always be set to true unless the" |
| " identity key-cert pairs are not needed." |
| ), |
| test_name="DifferentWatchIdentityPair", |
| test_value_1="false", |
| test_value_2="true", |
| ), |
| DataMember( |
| name="identity_cert_name", |
| type="std::string", |
| special_getter_return_type="const std::string&", |
| setter_comment=( |
| "Sets the name of identity key-cert pairs being watched, if" |
| " |set_watch_identity_pair| is called. If not set, an empty string" |
| " will be used as the name." |
| ), |
| setter_move_semantics=True, |
| test_name="DifferentIdentityCertName", |
| test_value_1='"identity_cert_name_1"', |
| test_value_2='"identity_cert_name_2"', |
| ), |
| DataMember( |
| name="tls_session_key_log_file_path", |
| type="std::string", |
| special_getter_return_type="const std::string&", |
| setter_move_semantics=True, |
| test_name="DifferentTlsSessionKeyLogFilePath", |
| test_value_1='"file_path_1"', |
| test_value_2='"file_path_2"', |
| ), |
| DataMember( |
| name="crl_directory", |
| type="std::string", |
| special_getter_return_type="const std::string&", |
| setter_comment=( |
| " gRPC will enforce CRLs on all handshakes from all hashed CRL" |
| " files inside of the crl_directory. If not set, an empty string" |
| " will be used, which will not enable CRL checking. Only supported" |
| " for OpenSSL version > 1.1." |
| ), |
| setter_move_semantics=True, |
| test_name="DifferentCrlDirectory", |
| test_value_1='"crl_directory_1"', |
| test_value_2='"crl_directory_2"', |
| ), |
| DataMember( |
| name="crl_provider", |
| type="std::shared_ptr<grpc_core::experimental::CrlProvider>", |
| getter_comment=("Returns the CRL Provider"), |
| setter_move_semantics=True, |
| special_comparator=("(crl_provider_ == other.crl_provider_)"), |
| test_name="DifferentCrlProvider", |
| test_value_1=("*experimental::CreateStaticCrlProvider({})"), |
| test_value_2=("*experimental::CreateStaticCrlProvider({})"), |
| ), |
| DataMember( |
| name="send_client_ca_list", |
| type="bool", |
| default_initializer="false", |
| test_name="DifferentSendClientCaListValues", |
| test_value_1="false", |
| test_value_2="true", |
| ), |
| ] |
| |
| |
| # print copyright notice from this file |
| def put_copyright(f, year): |
| print( |
| """// |
| // |
| // Copyright %s gRPC authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // |
| """ |
| % (year), |
| file=f, |
| ) |
| |
| |
| # Prints differences between two files |
| def get_file_differences(file1, file2): |
| with open(file1) as f1: |
| file1_text = f1.readlines() |
| with open(file2) as f2: |
| file2_text = f2.readlines() |
| return difflib.unified_diff( |
| file1_text, file2_text, fromfile=file1, tofile=file2 |
| ) |
| |
| |
| # Is this script executed in test mode? |
| test_mode = False |
| if len(sys.argv) > 1 and sys.argv[1] == "--test": |
| test_mode = True |
| |
| HEADER_FILE_NAME = ( |
| "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" |
| ) |
| # Generate src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h |
| header_file_name = HEADER_FILE_NAME |
| if test_mode: |
| header_file_name = tempfile.NamedTemporaryFile(delete=False).name |
| H = open(header_file_name, "w") |
| |
| put_copyright(H, "2018") |
| print( |
| "// Generated by tools/codegen/core/gen_grpc_tls_credentials_options.py\n", |
| file=H, |
| ) |
| print( |
| """#ifndef GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CREDENTIALS_OPTIONS_H |
| #define GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CREDENTIALS_OPTIONS_H |
| |
| #include <grpc/support/port_platform.h> |
| |
| #include "absl/container/inlined_vector.h" |
| |
| #include <grpc/grpc_security.h> |
| |
| #include "src/core/lib/gprpp/ref_counted.h" |
| #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h" |
| #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h" |
| #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_verifier.h" |
| #include "src/core/lib/security/security_connector/ssl_utils.h" |
| |
| // Contains configurable options specified by callers to configure their certain |
| // security features supported in TLS. |
| // TODO(ZhenLian): consider making this not ref-counted. |
| struct grpc_tls_credentials_options |
| : public grpc_core::RefCounted<grpc_tls_credentials_options> { |
| public: |
| grpc_tls_credentials_options() = default; |
| ~grpc_tls_credentials_options() override = default; |
| """, |
| file=H, |
| ) |
| |
| # Print out getters for all data members |
| print(" // Getters for member fields.", file=H) |
| for data_member in _DATA_MEMBERS: |
| if data_member.getter_comment != "": |
| print(" // " + data_member.getter_comment, file=H) |
| if data_member.override_getter: |
| print(" " + data_member.override_getter, file=H) |
| else: |
| print( |
| " %s %s() const { return %s; }" |
| % ( |
| data_member.special_getter_return_type |
| if data_member.special_getter_return_type != "" |
| else data_member.type, |
| data_member.name, |
| data_member.name + "_", |
| ), |
| file=H, |
| ) |
| |
| # Print out setters for all data members |
| print("", file=H) |
| print(" // Setters for member fields.", file=H) |
| for data_member in _DATA_MEMBERS: |
| if data_member.setter_comment != "": |
| print(" // " + data_member.setter_comment, file=H) |
| if data_member.setter_move_semantics: |
| print( |
| " void set_%s(%s %s) { %s_ = std::move(%s); }" |
| % ( |
| data_member.name, |
| data_member.type, |
| data_member.name, |
| data_member.name, |
| data_member.name, |
| ), |
| file=H, |
| ) |
| else: |
| print( |
| " void set_%s(%s %s) { %s_ = %s; }" |
| % ( |
| data_member.name, |
| data_member.type, |
| data_member.name, |
| data_member.name, |
| data_member.name, |
| ), |
| file=H, |
| ) |
| |
| # Write out operator== |
| print( |
| "\n bool operator==(const grpc_tls_credentials_options& other) const {", |
| file=H, |
| ) |
| operator_equal_content = " return " |
| for i in range(len(_DATA_MEMBERS)): |
| if i != 0: |
| operator_equal_content += " " |
| if _DATA_MEMBERS[i].special_comparator != "": |
| operator_equal_content += _DATA_MEMBERS[i].special_comparator |
| else: |
| operator_equal_content += ( |
| _DATA_MEMBERS[i].name + "_ == other." + _DATA_MEMBERS[i].name + "_" |
| ) |
| if i != len(_DATA_MEMBERS) - 1: |
| operator_equal_content += " &&\n" |
| print(operator_equal_content + ";\n }", file=H) |
| |
| # Write out copy constructor |
| print( |
| "\n grpc_tls_credentials_options(grpc_tls_credentials_options& other) :", |
| file=H, |
| ) |
| operator_equal_content = " " |
| for i in range(len(_DATA_MEMBERS)): |
| if i != 0: |
| operator_equal_content += " " |
| if i == len(_DATA_MEMBERS) - 1: |
| operator_equal_content += ( |
| _DATA_MEMBERS[i].name + "_(other." + _DATA_MEMBERS[i].name + "_)" |
| ) |
| else: |
| operator_equal_content += ( |
| _DATA_MEMBERS[i].name + "_(other." + _DATA_MEMBERS[i].name + "_),\n" |
| ) |
| print(operator_equal_content + " {}", file=H) |
| |
| # Print out data member declarations |
| print("\n private:", file=H) |
| for data_member in _DATA_MEMBERS: |
| if data_member.default_initializer == "": |
| print( |
| " %s %s_;" |
| % ( |
| data_member.type, |
| data_member.name, |
| ), |
| file=H, |
| ) |
| else: |
| print( |
| " %s %s_ = %s;" |
| % ( |
| data_member.type, |
| data_member.name, |
| data_member.default_initializer, |
| ), |
| file=H, |
| ) |
| |
| # Print out file ending |
| print( |
| """}; |
| |
| #endif // GRPC_SRC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CREDENTIALS_OPTIONS_H""", |
| file=H, |
| ) |
| |
| H.close() |
| |
| # Generate test/core/security/grpc_tls_credentials_options_comparator_test.cc |
| TEST_FILE_NAME = ( |
| "test/core/security/grpc_tls_credentials_options_comparator_test.cc" |
| ) |
| test_file_name = TEST_FILE_NAME |
| if test_mode: |
| test_file_name = tempfile.NamedTemporaryFile(delete=False).name |
| T = open(test_file_name, "w") |
| |
| put_copyright(T, "2022") |
| print( |
| "// Generated by tools/codegen/core/gen_grpc_tls_credentials_options.py", |
| file=T, |
| ) |
| print( |
| """ |
| #include <grpc/support/port_platform.h> |
| |
| #include <string> |
| |
| #include <gmock/gmock.h> |
| |
| #include "src/core/lib/security/credentials/xds/xds_credentials.h" |
| #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" |
| #include "test/core/util/test_config.h" |
| |
| namespace grpc_core { |
| namespace { |
| """, |
| file=T, |
| ) |
| |
| # Generate negative test for each negative member |
| for data_member in _DATA_MEMBERS: |
| print( |
| """TEST(TlsCredentialsOptionsComparatorTest, %s) { |
| auto* options_1 = grpc_tls_credentials_options_create(); |
| auto* options_2 = grpc_tls_credentials_options_create(); |
| options_1->set_%s(%s); |
| options_2->set_%s(%s); |
| EXPECT_FALSE(*options_1 == *options_2); |
| EXPECT_FALSE(*options_2 == *options_1); |
| delete options_1; |
| delete options_2; |
| }""" |
| % ( |
| data_member.test_name, |
| data_member.name, |
| data_member.test_value_1, |
| data_member.name, |
| data_member.test_value_2, |
| ), |
| file=T, |
| ) |
| |
| # Print out file ending |
| print( |
| """ |
| } // namespace |
| } // namespace grpc_core |
| |
| int main(int argc, char** argv) { |
| testing::InitGoogleTest(&argc, argv); |
| grpc::testing::TestEnvironment env(&argc, argv); |
| grpc_init(); |
| auto result = RUN_ALL_TESTS(); |
| grpc_shutdown(); |
| return result; |
| }""", |
| file=T, |
| ) |
| T.close() |
| |
| if test_mode: |
| header_diff = get_file_differences(header_file_name, HEADER_FILE_NAME) |
| test_diff = get_file_differences(test_file_name, TEST_FILE_NAME) |
| os.unlink(header_file_name) |
| os.unlink(test_file_name) |
| header_error = False |
| for line in header_diff: |
| print(line) |
| header_error = True |
| if header_error: |
| print( |
| HEADER_FILE_NAME |
| + " should not be manually modified. Please make changes to" |
| " tools/distrib/gen_grpc_tls_credentials_options.py instead." |
| ) |
| test_error = False |
| for line in test_diff: |
| print(line) |
| test_error = True |
| if test_error: |
| print( |
| TEST_FILE_NAME |
| + " should not be manually modified. Please make changes to" |
| " tools/distrib/gen_grpc_tls_credentials_options.py instead." |
| ) |
| if header_error or test_error: |
| sys.exit(1) |