From df8c69c2c062abadfc880c09e5514f427577a182 Mon Sep 17 00:00:00 2001 From: Sarvani Vakkalanka Date: Thu, 2 Feb 2017 15:31:56 -0800 Subject: [PATCH] Enable ESP to invoke Firebase Security rules. (#54) * Enable ESP to invoke Firebase Security rules. * Address code review comments. * Remove some debug logs * Add proto file to capture TestRulesetRequest. * clang-format files * Resolve a merge issue with previous commit * Allow security rules to disabled via serverconfig * format file * Addressed Wayne's review comments. * Add firebase server to Server Config. * Address Lizan's review comments * Address review comments. * Disable check rules service by default. * Address more review comments. * Fix a check. * Delete unwanted constant. * Address Wayne's comments and add a simple config test. * Address a review comment. * Add negative test case for config * Address code review * Remove unwanted const std::string --- contrib/endpoints/src/api_manager/BUILD | 14 + contrib/endpoints/src/api_manager/auth.h | 2 + .../auth/lib/auth_jwt_validator.cc | 9 +- .../api_manager/auth/service_account_token.h | 1 + .../endpoints/src/api_manager/check_auth.cc | 2 + .../src/api_manager/check_security_rules.cc | 331 +++++++++++++++--- contrib/endpoints/src/api_manager/config.cc | 8 + contrib/endpoints/src/api_manager/config.h | 3 + .../endpoints/src/api_manager/config_test.cc | 39 +++ .../src/api_manager/context/request_context.h | 11 +- .../api_manager/context/service_context.cc | 17 +- .../src/api_manager/context/service_context.h | 5 + .../api_manager/proto/security_rules.proto | 57 +++ .../src/api_manager/proto/server_config.proto | 9 + 14 files changed, 462 insertions(+), 46 deletions(-) create mode 100644 contrib/endpoints/src/api_manager/proto/security_rules.proto diff --git a/contrib/endpoints/src/api_manager/BUILD b/contrib/endpoints/src/api_manager/BUILD index 38671d6e90e..ffe4f060b7c 100644 --- a/contrib/endpoints/src/api_manager/BUILD +++ b/contrib/endpoints/src/api_manager/BUILD @@ -38,6 +38,19 @@ cc_proto_library( visibility = ["//visibility:public"], ) +cc_proto_library( + name = "security_rules_proto", + srcs = [ + "proto/security_rules.proto", + ], + default_runtime = "//external:protobuf", + protoc = "//external:protoc", + visibility = ["//visibility:public"], + deps = [ + "//external:cc_wkt_protos", + ], +) + cc_library( name = "auth_headers", hdrs = [ @@ -99,6 +112,7 @@ cc_library( ":auth_headers", ":impl_headers", ":server_config_proto", + ":security_rules_proto", "//contrib/endpoints/src/api_manager/auth", "//contrib/endpoints/src/api_manager/cloud_trace", "//contrib/endpoints/src/api_manager/context", diff --git a/contrib/endpoints/src/api_manager/auth.h b/contrib/endpoints/src/api_manager/auth.h index aff735bc1aa..e69718e95f6 100644 --- a/contrib/endpoints/src/api_manager/auth.h +++ b/contrib/endpoints/src/api_manager/auth.h @@ -40,6 +40,8 @@ struct UserInfo { // Authorized party of the incoming JWT. // See http://openid.net/specs/openid-connect-core-1_0.html#IDToken std::string authorized_party; + // String of claims + std::string claims; // Returns audiences as a comma separated strings. std::string AudiencesAsString() const { diff --git a/contrib/endpoints/src/api_manager/auth/lib/auth_jwt_validator.cc b/contrib/endpoints/src/api_manager/auth/lib/auth_jwt_validator.cc index 8da6ef2166c..2df9a843b71 100644 --- a/contrib/endpoints/src/api_manager/auth/lib/auth_jwt_validator.cc +++ b/contrib/endpoints/src/api_manager/auth/lib/auth_jwt_validator.cc @@ -699,12 +699,19 @@ grpc_jwt_verifier_status JwtValidatorImpl::FillUserInfoAndSetExp( // Optional field. const grpc_json *grpc_json = grpc_jwt_claims_json(claims_); + + char *json_str = + grpc_json_dump_to_string(const_cast<::grpc_json *>(grpc_json), 0); + if (json_str != nullptr) { + user_info->claims = json_str; + gpr_free(json_str); + } + const char *email = GetStringValue(grpc_json, "email"); user_info->email = email == nullptr ? "" : email; const char *authorized_party = GetStringValue(grpc_json, "azp"); user_info->authorized_party = authorized_party == nullptr ? "" : authorized_party; - exp_ = system_clock::from_time_t(grpc_jwt_claims_expires_at(claims_).tv_sec); return GRPC_JWT_VERIFIER_OK; diff --git a/contrib/endpoints/src/api_manager/auth/service_account_token.h b/contrib/endpoints/src/api_manager/auth/service_account_token.h index 211377449f4..51e99c65b89 100644 --- a/contrib/endpoints/src/api_manager/auth/service_account_token.h +++ b/contrib/endpoints/src/api_manager/auth/service_account_token.h @@ -64,6 +64,7 @@ class ServiceAccountToken { enum JWT_TOKEN_TYPE { JWT_TOKEN_FOR_SERVICE_CONTROL = 0, JWT_TOKEN_FOR_CLOUD_TRACING, + JWT_TOKEN_FOR_FIREBASE, JWT_TOKEN_TYPE_MAX, }; // Set audience. Only calcualtes JWT token with specified audience. diff --git a/contrib/endpoints/src/api_manager/check_auth.cc b/contrib/endpoints/src/api_manager/check_auth.cc index ce9a2c159ff..b4aae8bb2a1 100644 --- a/contrib/endpoints/src/api_manager/check_auth.cc +++ b/contrib/endpoints/src/api_manager/check_auth.cc @@ -243,6 +243,8 @@ void AuthChecker::CheckAudience(bool cache_hit) { context_->set_auth_audience(audience); context_->set_auth_authorized_party(user_info_.authorized_party); + context_->set_auth_claims(user_info_.claims); + // Remove http/s header and trailing '/' for issuer. std::string issuer = utils::GetUrlContent(user_info_.issuer); if (!context_->method()->isIssuerAllowed(issuer)) { diff --git a/contrib/endpoints/src/api_manager/check_security_rules.cc b/contrib/endpoints/src/api_manager/check_security_rules.cc index b1d6b90ac36..45fa30ae7bd 100644 --- a/contrib/endpoints/src/api_manager/check_security_rules.cc +++ b/contrib/endpoints/src/api_manager/check_security_rules.cc @@ -14,82 +14,332 @@ // //////////////////////////////////////////////////////////////////////////////// #include "contrib/endpoints/src/api_manager/check_security_rules.h" +#include +#include +#include "contrib/endpoints/src/api_manager/auth/lib/json_util.h" +#include "contrib/endpoints/src/api_manager/proto/security_rules.pb.h" +#include "contrib/endpoints/src/api_manager/utils/marshalling.h" -#include - -#include "contrib/endpoints/include/api_manager/api_manager.h" -#include "contrib/endpoints/include/api_manager/request.h" - +using ::google::api_manager::auth::GetProperty; +using ::google::api_manager::auth::GetStringValue; using ::google::api_manager::utils::Status; +using ::google::protobuf::Map; +using ::google::protobuf::util::error::Code; namespace google { namespace api_manager { - namespace { -const char kFirebaseServerStaging[] = - "https://staging-firebaserules.sandbox.googleapis.com/"; +const char kFailedFirebaseReleaseFetch[] = "Failed to fetch Firebase Release"; +const char kFailedFirebaseTest[] = "Failed to execute Firebase Test"; +const char kInvalidResponse[] = "Invalid JSON response from Firebase Service"; +const char kTestSuccess[] = "SUCCESS"; +const char kHttpGetMethod[] = "GET"; +const char kHttpPostMethod[] = "POST"; +const char kHttpHeadMethod[] = "HEAD"; +const char kHttpOptionsMethod[] = "OPTIONS"; +const char kHttpDeleteMethod[] = "DELETE"; +const char kFirebaseCreateMethod[] = "create"; +const char kFirebaseGetMethod[] = "get"; +const char kFirebaseDeleteMethod[] = "delete"; +const char kFirebaseUpdateMethod[] = "update"; +const char kV1[] = "v1/"; +const char kTestQuery[] = ":test?alt=json"; +const char kProjects[] = "projects/"; +const char kReleases[] = "/releases/"; +const char kRulesetName[] = "rulesetName"; +const char kTestResults[] = "testResults"; +const char kState[] = "state"; +const char kToken[] = "token"; +const char kAuth[] = "auth"; +const char kRequest[] = "request"; +const char kContentType[] = "Content-Type"; +const char kApplication[] = "application/json"; + +void SetProtoValue(const std::string &key, + const ::google::protobuf::Value &value, + ::google::protobuf::Value *head) { + ::google::protobuf::Struct *s = head->mutable_struct_value(); + Map *fields = s->mutable_fields(); + (*fields)[key] = value; +} + +std::string GetReleaseName(const context::RequestContext &context) { + return context.service_context()->service_name() + ":" + + context.service_context()->service().apis(0).version(); +} + +std::string GetRulesetTestUri(const context::RequestContext &context, + const std::string &ruleset_id) { + return context.service_context()->config()->GetFirebaseServer() + kV1 + + ruleset_id + kTestQuery; +} + +std::string GetReleaseUrl(const context::RequestContext &context) { + return context.service_context()->config()->GetFirebaseServer() + kV1 + + kProjects + context.service_context()->project_id() + kReleases + + GetReleaseName(context); +} + +std::string GetOperation(const std::string &httpMethod) { + if (httpMethod == kHttpPostMethod) { + return kFirebaseCreateMethod; + } + + if (httpMethod == kHttpGetMethod || httpMethod == kHttpHeadMethod || + httpMethod == kHttpOptionsMethod) { + return kFirebaseGetMethod; + } + + if (httpMethod == kHttpDeleteMethod) { + return kFirebaseDeleteMethod; + } + + return kFirebaseUpdateMethod; +} // An AuthzChecker object is created for every incoming request. It does // authorizaiton by calling Firebase Rules service. class AuthzChecker : public std::enable_shared_from_this { public: - AuthzChecker(std::shared_ptr context, - std::function continuation); + // Constructor + AuthzChecker(ApiManagerEnvInterface *env, + auth::ServiceAccountToken *sa_token); - void Check(); + // Check for Authorization success or failure + void Check(std::shared_ptr context, + std::function continuation); private: - // Helper function to send a http GET request. - void HttpFetch(const std::string &url, const std::string &request_body, + // Helper method that invokes the test firebase service api. + void CallTest(const std::string &ruleset_id, + std::shared_ptr context, + std::function continuation); + + // Parse the respose for GET RELEASE API call + Status ParseReleaseResponse(const std::string &json_str, + std::string *ruleset_id); + + // Parses the response for the TEST API call + Status ParseTestResponse(context::RequestContext &context, + const std::string &json_str); + + // Builds the request body for the TESP API call. + Status BuildTestRequestBody(context::RequestContext &context, + std::string *result_string); + + // Invoke the HTTP call + void HttpFetch(const std::string &url, const std::string &method, + const std::string &request_body, std::function continuation); - // Get Auth token for accessing Firebase Rules service. - const std::string &GetAuthToken(); + // Get the auth token for Firebase service + const std::string &GetAuthToken() { + return sa_token_->GetAuthToken( + auth::ServiceAccountToken::JWT_TOKEN_FOR_FIREBASE); + } - // Request context. - std::shared_ptr context_; + std::shared_ptr GetPtr() { return shared_from_this(); } - // Pointer to access ESP running environment. ApiManagerEnvInterface *env_; - - // The final continuation function. - std::function on_done_; + auth::ServiceAccountToken *sa_token_; }; -AuthzChecker::AuthzChecker(std::shared_ptr context, - std::function continuation) - : context_(context), - env_(context_->service_context()->env()), - on_done_(continuation) {} +AuthzChecker::AuthzChecker(ApiManagerEnvInterface *env, + auth::ServiceAccountToken *sa_token) + : env_(env), sa_token_(sa_token) {} -void AuthzChecker::Check() { +void AuthzChecker::Check( + std::shared_ptr context, + std::function final_continuation) { // TODO: Check service config to see if "useSecurityRules" is specified. // If so, call Firebase Rules service TestRuleset API. + + if (!context->service_context()->IsRulesCheckEnabled() || + context->method() == nullptr || !context->method()->auth()) { + env_->LogDebug("Skipping Firebase Rules checks since it is disabled."); + final_continuation(Status::OK); + return; + } + + // Fetch the Release attributes. + auto checker = GetPtr(); + HttpFetch(GetReleaseUrl(*context), kHttpGetMethod, "", + [context, final_continuation, checker](Status status, + std::string &&body) { + std::string ruleset_id; + if (status.ok()) { + checker->env_->LogDebug( + std::string("GetReleasName succeeded with ") + body); + status = checker->ParseReleaseResponse(body, &ruleset_id); + } else { + checker->env_->LogError(std::string("GetReleaseName for ") + + GetReleaseUrl(*context.get()) + + " with status " + status.ToString()); + status = Status(Code::INTERNAL, kFailedFirebaseReleaseFetch); + } + + // If the parsing of the release body is successful, then call the + // Test Api for firebase rules service. + if (status.ok()) { + checker->CallTest(ruleset_id, context, final_continuation); + } else { + final_continuation(status); + } + }); } -const std::string &AuthzChecker::GetAuthToken() { - // TODO: Get Auth token for accessing Firebase Rules service. - static std::string empty; - return empty; +void AuthzChecker::CallTest(const std::string &ruleset_id, + std::shared_ptr context, + std::function continuation) { + std::string body; + Status status = BuildTestRequestBody(*context.get(), &body); + if (!status.ok()) { + continuation(status); + return; + } + + auto checker = GetPtr(); + HttpFetch(GetRulesetTestUri(*context, ruleset_id), kHttpPostMethod, body, + [context, continuation, checker, ruleset_id](Status status, + std::string &&body) { + + if (status.ok()) { + checker->env_->LogDebug( + std::string("Test API succeeded with ") + body); + status = checker->ParseTestResponse(*context.get(), body); + } else { + checker->env_->LogError(std::string("Test API failed with ") + + status.ToString()); + status = Status(Code::INTERNAL, kFailedFirebaseTest); + } + + continuation(status); + }); +} + +Status AuthzChecker::ParseReleaseResponse(const std::string &json_str, + std::string *ruleset_id) { + grpc_json *json = grpc_json_parse_string_with_len( + const_cast(json_str.data()), json_str.length()); + + if (!json) { + return Status(Code::INVALID_ARGUMENT, kInvalidResponse); + } + + Status status = Status::OK; + const char *id = GetStringValue(json, kRulesetName); + *ruleset_id = (id == nullptr) ? "" : id; + + if (ruleset_id->empty()) { + env_->LogError("Empty ruleset Id received from firebase service"); + status = Status(Code::INTERNAL, kInvalidResponse); + } else { + env_->LogDebug(std::string("Received ruleset Id: ") + *ruleset_id); + } + + grpc_json_destroy(json); + return status; +} + +Status AuthzChecker::ParseTestResponse(context::RequestContext &context, + const std::string &json_str) { + grpc_json *json = grpc_json_parse_string_with_len( + const_cast(json_str.data()), json_str.length()); + + if (!json) { + return Status(Code::INVALID_ARGUMENT, + "Invalid JSON response from Firebase Service"); + } + + Status status = Status::OK; + Status invalid = Status(Code::INTERNAL, kInvalidResponse); + + const grpc_json *testResults = GetProperty(json, kTestResults); + if (testResults == nullptr) { + env_->LogError("TestResults are null"); + status = invalid; + } else { + const char *result = GetStringValue(testResults->child, kState); + if (result == nullptr) { + env_->LogInfo("Result state is empty"); + status = invalid; + } else if (std::string(result) != kTestSuccess) { + status = Status(Code::PERMISSION_DENIED, + std::string("Unauthorized ") + + context.request()->GetRequestHTTPMethod() + + " access to resource " + + context.request()->GetRequestPath(), + Status::AUTH); + } + } + + grpc_json_destroy(json); + return status; +} + +Status AuthzChecker::BuildTestRequestBody(context::RequestContext &context, + std::string *result_string) { + proto::TestRulesetRequest request; + auto *test_case = request.add_test_cases(); + auto httpMethod = context.request()->GetRequestHTTPMethod(); + + test_case->set_service_name(context.service_context()->service_name()); + test_case->set_resource_path(context.request()->GetRequestPath()); + test_case->set_operation(GetOperation(httpMethod)); + test_case->set_expectation(proto::TestRulesetRequest::TestCase::ALLOW); + + ::google::protobuf::Value auth; + ::google::protobuf::Value token; + ::google::protobuf::Value claims; + + Status status = utils::JsonToProto(context.auth_claims(), &claims); + if (!status.ok()) { + env_->LogError(std::string("Error creating Protobuf from claims") + + status.ToString()); + return status; + } + + SetProtoValue(kToken, claims, &token); + SetProtoValue(kAuth, token, &auth); + + auto *variables = test_case->mutable_variables(); + (*variables)[kRequest] = auth; + + status = + utils::ProtoToJson(request, result_string, utils::JsonOptions::DEFAULT); + if (status.ok()) { + env_->LogDebug(std::string("PRotobuf to JSON string = ") + *result_string); + } else { + env_->LogError(std::string("Error creating TestRulesetRequest") + + status.ToString()); + } + + return status; } void AuthzChecker::HttpFetch( - const std::string &url, const std::string &request_body, + const std::string &url, const std::string &method, + const std::string &request_body, std::function continuation) { + env_->LogDebug(std::string("Issue HTTP Request to url :") + url + + " method : " + method + " body: " + request_body); + std::unique_ptr request(new HTTPRequest([continuation]( Status status, std::map &&, std::string &&body) { continuation(status, std::move(body)); })); + if (!request) { continuation(Status(Code::INTERNAL, "Out of memory"), ""); return; } - request->set_method("POST") - .set_url(url) - .set_auth_token(GetAuthToken()) - .set_header("Content-Type", "application/json") - .set_body(request_body); + request->set_method(method).set_url(url).set_auth_token(GetAuthToken()); + + if (method != kHttpGetMethod) { + request->set_header(kContentType, kApplication).set_body(request_body); + } + env_->RunHTTPRequest(std::move(request)); } @@ -97,9 +347,10 @@ void AuthzChecker::HttpFetch( void CheckSecurityRules(std::shared_ptr context, std::function continuation) { - std::shared_ptr authzChecker = - std::make_shared(context, continuation); - authzChecker->Check(); + std::shared_ptr checker = std::make_shared( + context->service_context()->env(), + context->service_context()->service_account_token()); + checker->Check(context, continuation); } } // namespace api_manager diff --git a/contrib/endpoints/src/api_manager/config.cc b/contrib/endpoints/src/api_manager/config.cc index b0a1b85d119..d537ef73e07 100644 --- a/contrib/endpoints/src/api_manager/config.cc +++ b/contrib/endpoints/src/api_manager/config.cc @@ -513,5 +513,13 @@ void Config::SetJwksUri(const string &issuer, const string &jwks_uri, } } +std::string Config::GetFirebaseServer() { + if (server_config_ == nullptr) { + return ""; + } + + return server_config_->api_check_security_rules_config().firebase_server(); +} + } // namespace api_manager } // namespace google diff --git a/contrib/endpoints/src/api_manager/config.h b/contrib/endpoints/src/api_manager/config.h index 9a56d16d745..82586939eb0 100644 --- a/contrib/endpoints/src/api_manager/config.h +++ b/contrib/endpoints/src/api_manager/config.h @@ -78,6 +78,9 @@ class Config { void SetJwksUri(const std::string &issuer, const std::string &jwks_uri, bool openid_valid); + // Get the Firebase server from Server config + std::string GetFirebaseServer(); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Config); diff --git a/contrib/endpoints/src/api_manager/config_test.cc b/contrib/endpoints/src/api_manager/config_test.cc index ace0d2afc49..d9170ddf131 100644 --- a/contrib/endpoints/src/api_manager/config_test.cc +++ b/contrib/endpoints/src/api_manager/config_test.cc @@ -870,6 +870,45 @@ TEST(Config, TestCorsDisabled) { ASSERT_EQ(nullptr, method1); } +TEST(Config, TestFirebaseServerCheck) { + MockApiManagerEnvironmentWithLog env; + + static const char server_config[] = R"( +api_check_security_rules_config { + firebase_server: "https://myfirebaseserver.com/" +} +)"; + + std::unique_ptr config = + Config::Create(&env, kServiceNameConfig, server_config); + ASSERT_TRUE(config); + + ASSERT_EQ(config->GetFirebaseServer(), "https://myfirebaseserver.com/"); +} + +TEST(Config, TestEmptyFirebaseServerCheck) { + MockApiManagerEnvironmentWithLog env; + + static const char server_config[] = R"( +service_control_config { + check_aggregator_config { + cache_entries: 1000 + flush_interval_ms: 10 + response_expiration_ms: 20 + } + report_aggregator_config { + cache_entries: 1020 + flush_interval_ms: 15 + } +} +)"; + + std::unique_ptr config = + Config::Create(&env, kServiceNameConfig, server_config); + ASSERT_TRUE(config); + + ASSERT_TRUE(config->GetFirebaseServer().empty()); +} } // namespace } // namespace api_manager diff --git a/contrib/endpoints/src/api_manager/context/request_context.h b/contrib/endpoints/src/api_manager/context/request_context.h index 5b29c271aad..c633952a811 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.h +++ b/contrib/endpoints/src/api_manager/context/request_context.h @@ -37,7 +37,9 @@ class RequestContext { std::unique_ptr request); // Get the ApiManagerImpl object. - context::ServiceContext *service_context() { return service_context_.get(); } + context::ServiceContext *service_context() const { + return service_context_.get(); + } // Get the request object. Request *request() { return request_.get(); } @@ -112,6 +114,10 @@ class RequestContext { last_report_time_ = tp; } + void set_auth_claims(const std::string &claims) { auth_claims_ = claims; } + + const std::string &auth_claims() { return auth_claims_; } + private: // Fill OperationInfo void FillOperationInfo(service_control::OperationInfo *info); @@ -163,6 +169,9 @@ class RequestContext { // Report(). std::string auth_authorized_party_; + // Auth Claims: This is the decoded payload of the JWT token + std::string auth_claims_; + // Used by cloud tracing. std::unique_ptr cloud_trace_; diff --git a/contrib/endpoints/src/api_manager/context/service_context.cc b/contrib/endpoints/src/api_manager/context/service_context.cc index d8fc9dfc409..f6dc3d90275 100644 --- a/contrib/endpoints/src/api_manager/context/service_context.cc +++ b/contrib/endpoints/src/api_manager/context/service_context.cc @@ -44,6 +44,10 @@ const int kIntermediateReportInterval = 10; const char kHTTPHeadMethod[] = "HEAD"; const char kHTTPGetMethod[] = "GET"; + +const char kFirebaseAudience[] = + "https://staging-firebaserules.sandbox.googleapis.com/" + "google.firebase.rules.v1.FirebaseRulesService"; } ServiceContext::ServiceContext(std::unique_ptr env, @@ -53,10 +57,12 @@ ServiceContext::ServiceContext(std::unique_ptr env, service_account_token_(env_.get()), service_control_(CreateInterface()), cloud_trace_aggregator_(CreateCloudTraceAggregator()), - is_auth_force_disabled_(config_->server_config() && - config_->server_config() - ->api_authentication_config() - .force_disable()) { + is_auth_force_disabled_( + config_->server_config() && + config_->server_config()->has_api_authentication_config() && + config_->server_config() + ->api_authentication_config() + .force_disable()) { intermediate_report_interval_ = kIntermediateReportInterval; // Check server_config override. @@ -69,6 +75,9 @@ ServiceContext::ServiceContext(std::unique_ptr env, ->service_control_config() .intermediate_report_min_interval(); } + + service_account_token_.SetAudience( + auth::ServiceAccountToken::JWT_TOKEN_FOR_FIREBASE, kFirebaseAudience); } MethodCallInfo ServiceContext::GetMethodCallInfo( diff --git a/contrib/endpoints/src/api_manager/context/service_context.h b/contrib/endpoints/src/api_manager/context/service_context.h index 5633ca3dd88..61524813157 100644 --- a/contrib/endpoints/src/api_manager/context/service_context.h +++ b/contrib/endpoints/src/api_manager/context/service_context.h @@ -65,6 +65,11 @@ class ServiceContext { return !is_auth_force_disabled_ && config_->HasAuth(); } + bool IsRulesCheckEnabled() const { + return RequireAuth() && service().apis_size() > 0 && + !config_->GetFirebaseServer().empty(); + } + auth::Certs &certs() { return certs_; } auth::JwtCache &jwt_cache() { return jwt_cache_; } diff --git a/contrib/endpoints/src/api_manager/proto/security_rules.proto b/contrib/endpoints/src/api_manager/proto/security_rules.proto new file mode 100644 index 00000000000..ce8d2690fe0 --- /dev/null +++ b/contrib/endpoints/src/api_manager/proto/security_rules.proto @@ -0,0 +1,57 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// +// +syntax = "proto3"; + +package google.api_manager.proto; + +import "google/protobuf/struct.proto"; + +message TestRulesetRequest { + message TestCase { + // The set of supported test case expectations. + enum Expectation { + EXPECTATION_UNSPECIFIED = 0; // Unspecified expectation. + ALLOW = 1; // Expect an allowed result. + DENY = 2; // Expect a denied result. + } + + // The name of the service that is the subject of the test case. + string service_name = 1; + + // The RESTful resource path of the mock `request`. + string resource_path = 2; + + // The `request` `operation`. The operation will typically be one of `get`, + // `list`, `create`, `update`, or `delete`. Services also may provide custom + // operations. + string operation = 3; + + // Test expectation. + Expectation expectation = 4; + + // (-- + // Variables and fake resources need to be updated to support multiple + // services and the standardized `request` definition. + // --) + + // Optional set of variable values to use during evaluation. + map variables = 5; + } + + // The set of test cases to run against the `Source` if it is well-formed. + repeated TestCase test_cases = 3; +} diff --git a/contrib/endpoints/src/api_manager/proto/server_config.proto b/contrib/endpoints/src/api_manager/proto/server_config.proto index 343414aceae..9e325c3f1a0 100644 --- a/contrib/endpoints/src/api_manager/proto/server_config.proto +++ b/contrib/endpoints/src/api_manager/proto/server_config.proto @@ -39,6 +39,9 @@ message ServerConfig { // Envoy/esp talks to Mixer, has to specify this field. MixerOptions mixer_options = 6; + // Server config used for API authorization via Firebase Rules. + ApiCheckSecurityRulesConfig api_check_security_rules_config = 7; + // Experimental flags Experimental experimental = 999; } @@ -143,6 +146,12 @@ message ApiAuthenticationConfig { bool force_disable = 1; } +// Server config for API Authorization via Firebase Rules +message ApiCheckSecurityRulesConfig { + // Firebase server to use. + string firebase_server = 1; +} + message MixerOptions { // For envoy, it is the cluster name for mixer server. string mixer_server = 1;