Enable ESP to invoke Firebase Security rules. - #54
Conversation
|
You need to use clang-format to format following files contrib/endpoints/src/api_manager/check_security_rules.cc contrib/endpoints/src/api_manager/check_security_rules.h contrib/endpoints/src/api_manager/context/request_context.h contrib/endpoints/src/api_manager/context/service_context.cc |
| std::string auth_authorized_party_; | ||
|
|
||
| // Auth Claims: This is the decoded payload of the JWT token | ||
| char *auth_claims_; |
There was a problem hiding this comment.
We can use std::string to store it. so you don't need to include grpc headers in order to call gpr_free
| // See http://openid.net/specs/openid-connect-core-1_0.html#IDToken | ||
| std::string authorized_party; | ||
| // String of claims | ||
| char *claims; |
There was a problem hiding this comment.
Yes. We do. The UserInfo is where the decoded JWT claims are stored so it can be used in the later part of the work flow. This actually is the same flow as it is used for JWT audience and issuer fields.
There was a problem hiding this comment.
Changed it to std::string
| } else { | ||
| env_->LogInfo("Before Parse JWT"); | ||
| ParseJwt(); | ||
| env_->LogInfo("After Parse JWT"); |
There was a problem hiding this comment.
Looks like the merge put them back in. I will delete them before the next commit.
| void HttpFetch(const std::string &url, const std::string &request_body, | ||
| std::function<void(Status, std::string &&)> continuation); | ||
| // Fetch the Release attributes. | ||
| auto pChecker = GetPtr(); |
There was a problem hiding this comment.
Google c++ style guide, not to use camel case in variable name
There was a problem hiding this comment.
Hmm. This code is again similar to check_auth.cc below. Let me know if you want me to fix it in both places.
void AuthChecker::DiscoverJwksUri(const std::string &url) {
auto pChecker = GetPtr();
HttpFetch(url, [pChecker](S
| // TODO: Check service config to see if "useSecurityRules" is specified. | ||
| // If so, call Firebase Rules service TestRuleset API. | ||
| std::pair<Status, std::string> AuthzChecker::ParseReleaseResponse( | ||
| std::string *json_str) { |
There was a problem hiding this comment.
pass in const std::string& if you are not modifying json_str
| void AuthzChecker::Check() { | ||
| // TODO: Check service config to see if "useSecurityRules" is specified. | ||
| // If so, call Firebase Rules service TestRuleset API. | ||
| std::pair<Status, std::string> AuthzChecker::ParseReleaseResponse( |
There was a problem hiding this comment.
can we pass out ruleset_id in the argument. e.g.
Status Parse(..., string* ruleset_id)
| status = Status(Code::PERMISSION_DENIED, | ||
| std::string("Unauthorized ") | ||
| + context->request()->GetRequestHTTPMethod() | ||
| + " access to resource " + context->request()->GetRequestPath(), |
There was a problem hiding this comment.
Does response have detail info we can pass back to help users?
There was a problem hiding this comment.
No. Unfortunatley, the Test API that we use only provided with a response that looks like this:
{
"testResults": [
{
"state": "SUCCESS"
}
]
}
or
{
"testResults": [
{
"state": "FAILURE"
}
]
}
The response itself is a HTTP 200 OK message.
| std::string AuthzChecker::BuildTestRequestBody( | ||
| std::shared_ptr<context::RequestContext> context) { | ||
|
|
||
| std::shared_ptr<std::ostringstream> ss(new std::ostringstream); |
There was a problem hiding this comment.
not need to use new. just allocate it from stack.
| std::shared_ptr<AuthzChecker> authzChecker = | ||
| std::make_shared<AuthzChecker>(context, continuation); | ||
| authzChecker->Check(); | ||
| std::shared_ptr<AuthzChecker> checker(new AuthzChecker( |
There was a problem hiding this comment.
why don't you use make_shared?
| std::string BuildTestRequestBody( | ||
| std::shared_ptr<context::RequestContext> context); | ||
|
|
||
| void AddToBody(const std::string &key, |
There was a problem hiding this comment.
can some of these function static.
if so, they can be in the cc file, inside anonymous name space
There was a problem hiding this comment.
I moved the header file into the .cc file now.
| #include "grpc/support/string_util.h" | ||
| #include "grpc/support/sync.h" | ||
| } | ||
|
|
There was a problem hiding this comment.
Do we need all these headers? It looks like we are only using gpr_free() in the file.
There was a problem hiding this comment.
Removed them. After changing to std::string based on Wayne's comments, I did not need them.
| if (cache_hit) { | ||
| CheckAudience(true); | ||
| } else { | ||
| env_->LogInfo("Before Parse JWT"); |
There was a problem hiding this comment.
Remember remove these logs before submit.
| } else { | ||
| env_->LogInfo("Before Parse JWT"); | ||
| ParseJwt(); | ||
| env_->LogInfo("After Parse JWT"); |
| // See http://openid.net/specs/openid-connect-core-1_0.html#IDToken | ||
| std::string authorized_party; | ||
| // String of claims | ||
| char *claims; |
|
|
||
| // Get the auth token for Firebase service | ||
| const std::string &GetAuthToken() { | ||
| return sa_token_->GetAuthToken( |
There was a problem hiding this comment.
Hmm. This is similar to The Aggregator code in cloud_trace.cc where the ServiceAccountToken is being passed in. There are no null checks there. Let me know if you think this is wrong and we can fix this at book places. However, since we don't throw exceptions, the null check should be done before passing in the value. Otherwise, we will have null checks all over the code.
| std::shared_ptr<std::ostringstream> ss); | ||
|
|
||
| void AddToBody(const std::string &key, const std::string &value, | ||
| bool end, std::shared_ptr<std::ostringstream> ss); |
| std::shared_ptr<context::RequestContext> context); | ||
|
|
||
| void AddToBody(const std::string &key, | ||
| std::shared_ptr<std::ostringstream> ss); |
|
|
||
| const std::string Stringify(const char *s) { | ||
| return std::string("\"") + s + "\""; | ||
| } |
There was a problem hiding this comment.
You are not handing the case that s is NULL pointer.
Converting a "char *" to string is simply:
std::string target = s == nullptr ? "" : s;
| .set_url(url) | ||
| .set_auth_token(GetAuthToken()) | ||
| .set_header("Content-Type", "application/json") | ||
| .set_auth_token(token); |
There was a problem hiding this comment.
set_auth_token(GetAuthToken()). Then you don't need "token" variable.
| class AuthzChecker : public std::enable_shared_from_this<AuthzChecker> { | ||
| public: | ||
| AuthzChecker(std::shared_ptr<context::RequestContext> context, | ||
| std::function<void(Status status)> continuation); |
There was a problem hiding this comment.
If AuthzChecker class is used only in check_seucurity_rules.cc/h, we prefer to put the class definition in .cc file. This way, any place that "include" check_security_rules.h will only include CheckSecurityRules() function definition (not AuthzChecker class).
| // Get Firebase specific operation Id based on the http Method. | ||
| std::string GetOperation(std::string httpMethod); | ||
|
|
||
| const std::string Stringify(const char *s) { |
There was a problem hiding this comment.
no need to be a class function.
There was a problem hiding this comment.
This is removed with the new protobuf change.s
There was a problem hiding this comment.
Removed this after proto change.
| } | ||
|
|
||
| // Fetch the Release attributes. | ||
| auto pchecker = GetPtr(); |
|
|
||
| // Fetch the Release attributes. | ||
| auto pchecker = GetPtr(); | ||
| HttpFetch(GetReleaseUrl(context), std::string("GET"), std::string(""), |
There was a problem hiding this comment.
no need for std::string("GET"), just "GET", compiler will convert it
| std::function<void(Status status)> continuation) { | ||
| auto pchecker = GetPtr(); | ||
|
|
||
| HttpFetch(std::string(kFirebaseServerStaging) + "v1/" + ruleset_id + |
There was a problem hiding this comment.
use a separate function for URL
|
|
||
| Status status = Status::OK; | ||
| const char *id = GetStringValue(json, "rulesetName"); | ||
| (*ruleset_id) = (id == nullptr) ? "" : GetStringValue(json, "rulesetName"); |
There was a problem hiding this comment.
Not sure what you mean ...
There was a problem hiding this comment.
*ruleset_id = (id) : id ? "";
| return status; | ||
| } | ||
|
|
||
| std::string AuthzChecker::GetOperation(std::string httpMethod) { |
There was a problem hiding this comment.
need to be a class member function?
There was a problem hiding this comment.
Made it static function.
| std::string AuthzChecker::BuildTestRequestBody( | ||
| std::shared_ptr<context::RequestContext> context) { | ||
|
|
||
| std::ostringstream ss; |
There was a problem hiding this comment.
maybe use a proto, build a proto message first, then convert it to json.
There was a problem hiding this comment.
How I wish I could do it! The protos are not open sourced.
There was a problem hiding this comment.
You can copy the proto file to our ESP code base. Still prefer to use proto to convert to JSON.
There was a problem hiding this comment.
There are multiple proto files and this will come from the firebase codebase. I am not sure if we can just pick up the code and put it in our codebase. I will need to talk to Limin / Wencheng and may be even Firebase guys before doing this.
There was a problem hiding this comment.
If it is too much trouble to copy their proto files, you just create your own simple proto message which only fields you used.
There was a problem hiding this comment.
I see what you mean. I think I an do that. It is actually a better idea than dealing with strings.
| } | ||
|
|
||
| void AuthzChecker::AddToBody(const std::string &key, | ||
| std::ostringstream &ss) { |
There was a problem hiding this comment.
no need to be a class member function
There was a problem hiding this comment.
The reason I left it inside the class is because the usage of the function is only applicable to objects of this class.
There was a problem hiding this comment.
it should be static if the function is not using any class members.
There was a problem hiding this comment.
Ah. Sure. I will make them static.
There was a problem hiding this comment.
Function is deleted after adding the new protobuf to capture this.
| } | ||
| } | ||
|
|
||
| const std::string AuthzChecker::GetReleaseName( |
There was a problem hiding this comment.
no need to be a class member function
There was a problem hiding this comment.
Same reason as above. There is no meaning to this method outside the context of the class.
There was a problem hiding this comment.
Changed this to static
| // Pointer to access ESP running environment. | ||
| ApiManagerEnvInterface *env_; | ||
| // Get Firebase specific operation Id based on the http Method. | ||
| std::string GetOperation(std::string httpMethod); |
| #include "contrib/endpoints/include/api_manager/utils/status.h" | ||
|
|
||
| #include <string> | ||
| using ::google::api_manager::utils::Status; |
There was a problem hiding this comment.
No change is needed for this file. The additional "include" and "using" here should be removed.
| last_report_time_ = tp; | ||
| } | ||
|
|
||
| void set_auth_claims(std::string &claims) { |
| return auth_claims_; | ||
| } | ||
|
|
||
| const std::string GetAuthToken(); |
| namespace api_manager { | ||
|
|
||
| namespace { | ||
|
|
There was a problem hiding this comment.
The whole class should be an anonymous namespace. You should not remove it.
| "https://staging-firebaserules.sandbox.googleapis.com/"; | ||
|
|
||
| // An AuthzChecker object is created for every incoming request. It does | ||
| // authorizaiton by calling Firebase Rules service. |
There was a problem hiding this comment.
This comment applies to the class. Why do you remove it?
There was a problem hiding this comment.
Added it back. Initially I had code that was creating the object in the service context but this did not work due to circular dependences. I removed it as a part of that change and forgot to add it back.
| void HttpFetch(const std::string &url, const std::string &request_body, | ||
|
|
||
| // Helper method that invokes the test firebase service api. | ||
| void FirebaseCheck(std::string ruleset_id, |
| last_report_time_ = tp; | ||
| } | ||
|
|
||
| void set_auth_claims(std::string &claims) { |
| auth_claims_ = claims; | ||
| } | ||
|
|
||
| std::string &auth_claims() { |
There was a problem hiding this comment.
I think this function can simply return std::string.
There was a problem hiding this comment.
Why? We just use this string to create a proto object and this string can be potentially big.
|
|
||
| /*for (grpc_json *cur = json->child; cur != nullptr; cur = cur->next) { | ||
| user_info->claims.emplace(std::string(cur->key), std::string(cur->value)); | ||
| } */ |
There was a problem hiding this comment.
what is this commented out code for? If no needed, remove it
| message ApiCheckSecurityRulesConfig { | ||
| // Allows to disable the API authorization | ||
| bool force_disable = 1; | ||
| } |
There was a problem hiding this comment.
you may want to have firebase_server here so "t" test can provide a fake server.
BTW, How do we enable this feature, is it enabled by service_config? Here we force disable it? If so, we are fine
There was a problem hiding this comment.
This can be enabled via service config. But the service config changes are not done yet. Tao is working on those changes.
There was a problem hiding this comment.
If that is the case, it will be easier for you to integrate with ESP if you default to be disabled, only enable it from server_config.
There was a problem hiding this comment.
I don't want to disable this by default via server config and there is a reason for this. By not disabling the feature by default I am able to apply some existing auth based t tests. For example, we have checks to ensure that if auth is disabled, then we don't do any firebase rules checks too. For all those tests, since the code is not disabled by default, we are able to exercise the existing t tests without any more tests that do the same thing.
| ->api_authentication_config() | ||
| .force_disable()) { | ||
| .force_disable()), | ||
| is_check_security_rules_disabled_(config_->server_config() && |
There was a problem hiding this comment.
is it enabled by default? do we need to check service_config ?
There was a problem hiding this comment.
Currently enabled by default. Once the service config changes are done, we will add those checks too.
There was a problem hiding this comment.
it is better to be disabled by default for now. and only enable it when server_config has api_check_securty_rules_config and its firebase_server is specified.
we can change it when service config is ready.
|
|
||
| // 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<AuthzChecker> { |
There was a problem hiding this comment.
Since the file name is called check_security_rules, should we call the class as SecurityRuleChecker
There was a problem hiding this comment.
This was named by Limin and so was the file name provided by her. Let me see what she thinks too :-)
| void HttpFetch(const std::string &url, const std::string &request_body, | ||
| // Helper method that invokes the test firebase service api. | ||
| void FirebaseCheck(std::string &ruleset_id, | ||
| std::shared_ptr<context::RequestContext> context, |
| void AuthzChecker::FirebaseCheck( | ||
| std::string &ruleset_id, std::shared_ptr<context::RequestContext> context, | ||
| std::function<void(Status status)> continuation) { | ||
| auto checker = GetPtr(); |
| std::shared_ptr<context::RequestContext> context, | ||
| std::string &result_string) { | ||
| proto::TestRulesetRequest request; | ||
| proto::TestRulesetRequest::TestCase *test_case = request.add_test_cases(); |
|
|
||
| Status AuthzChecker::BuildTestRequestBody( | ||
| std::shared_ptr<context::RequestContext> context, | ||
| std::string &result_string) { |
There was a problem hiding this comment.
Per style guide, you should use std::string*
|
|
||
| void AuthzChecker::SetProtoValue(::google::protobuf::Value &head, | ||
| std::string key, | ||
| ::google::protobuf::Value &value) { |
There was a problem hiding this comment.
per style guide, the prototype should be
(const string& key, const Value& value, Value* head)
|
|
||
| // Pointer to access ESP running environment. | ||
| ApiManagerEnvInterface *env_; | ||
| void SetProtoValue(::google::protobuf::Value &head, std::string key, |
There was a problem hiding this comment.
this can be static.
I think all these 4 static functions can be out of the class.
| if (!context->service_context()->RequireRulesCheck() || | ||
| context->method() == nullptr || !context->method()->auth()) { | ||
| env_->LogDebug( | ||
| std::string("Autherization and JWT validation was not performed") + |
There was a problem hiding this comment.
nit: Authorization, no need of std::string, just use literals without +
| std::string *ruleset_id); | ||
|
|
||
| // Parses the response for the TEST API call | ||
| Status ParseTestResponse(std::shared_ptr<context::RequestContext> context, |
There was a problem hiding this comment.
output parameter should be pointers, per our C++ style guide
There was a problem hiding this comment.
Yes. Wayne gave me this comment and I have already fixed this. in a later commit.
| const std::string &json_str); | ||
|
|
||
| // Builds the request body for the TESP API call. | ||
| Status BuildTestRequestBody(std::shared_ptr<context::RequestContext> context, |
There was a problem hiding this comment.
same. already fixed in later commit.
| if (result == nullptr) { | ||
| env_->LogInfo("Result state is empty"); | ||
| status = invalid; | ||
| } else if (std::string(result) != "SUCCESS") { |
There was a problem hiding this comment.
"SUCCESS" as constant, and make the constant as std::string.
There was a problem hiding this comment.
I have declared a const char[] kTestSuccess with the rest of the cont strings. Let me know if this is not what you had in mind.
|
|
||
| void set_auth_claims(const std::string &claims) { auth_claims_ = claims; } | ||
|
|
||
| std::string &auth_claims() { return auth_claims_; } |
| #ifndef API_MANAGER_AUTH_H_ | ||
| #define API_MANAGER_AUTH_H_ | ||
|
|
||
| #include <map> |
| // 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(std::string &ruleset_id, |
| #ifndef API_MANAGER_CHECK_SECURITY_RULES_H_ | ||
| #define API_MANAGER_CHECK_SECURITY_RULES_H_ | ||
|
|
||
| #include <string> |
| // Server config for API Authorization via Firebase Rules | ||
| message ApiCheckSecurityRulesConfig { | ||
| // Firebase server to use. | ||
| string firebase_server = 1; |
There was a problem hiding this comment.
We will use this configuration with t tests. I will update this in another change once I understand t tests better. For now this is only a place holder.
| // Optional field. | ||
| const grpc_json *grpc_json = grpc_jwt_claims_json(claims_); | ||
|
|
||
| char *json_str = |
There was a problem hiding this comment.
Thank you. Missed this while addressing review comments. I was freeing this in the first commit :-)
| const char kInvalidResponse[] = "Invalid JSON response from Firebase Service"; | ||
| const char kTestSuccess[] = "SUCCESS"; | ||
|
|
||
| void SetProtoValue(std::string key, ::google::protobuf::Value &value, |
There was a problem hiding this comment.
const std::string&
const Value&
| } | ||
|
|
||
| const std::string GetReleaseName( | ||
| std::shared_ptr<context::RequestContext> request_context) { |
There was a problem hiding this comment.
Not to use shared_ptr if you are not keep a ref_count.
use
const context::RequestContext&
There was a problem hiding this comment.
The CheckSecurityRules method is the entry point and it receives a share_ptr. Do you mean that I should extract the pointer from the shared pointer? I thought it is considered bad to extract a pointer out of a smart pointer. Lets discuss more.
There was a problem hiding this comment.
Pass a shared_ptr is bad for performance. it needs to lock in order to increase ref_count.
If your function don't need to keep a ref_count, pass in the object.
| } | ||
|
|
||
| const std::string GetReleaseUrl( | ||
| std::shared_ptr<context::RequestContext> request_context) { |
| if (!context->service_context()->RequireRulesCheck() || | ||
| context->method() == nullptr || !context->method()->auth()) { | ||
| env_->LogDebug( | ||
| "Autherization and JWT validation was not performed" |
There was a problem hiding this comment.
is logging message correct?
There was a problem hiding this comment.
should it be firebase ruleset validation?
| Status status = Status::OK; | ||
| const char *id = GetStringValue(json, "rulesetName"); | ||
| (*ruleset_id) = (id == nullptr) ? "" : id; | ||
|
|
There was a problem hiding this comment.
why do we need () in (*ruleset_id)?
| SetProtoValue("token", claims, &token); | ||
| SetProtoValue("auth", token, &auth); | ||
|
|
||
| Map<std::string, google::protobuf::Value> *variables = |
| const std::string &request_body, | ||
| std::function<void(Status, std::string &&)> continuation) { | ||
| env_->LogInfo(std::string("Issue HTTP Request to url :") + url + | ||
| " method : " + method + " body: " + request_body); |
| ->api_authentication_config() | ||
| .force_disable()) { | ||
| .force_disable()), | ||
| is_check_security_rules_disabled_(config_->server_config() && |
There was a problem hiding this comment.
it is better to be disabled by default for now. and only enable it when server_config has api_check_securty_rules_config and its firebase_server is specified.
we can change it when service config is ready.
| std::shared_ptr<context::RequestContext> request_context) { | ||
| return request_context->service_context()->service_name() + ":" + | ||
| request_context->service_context()->service().apis(0).version(); | ||
| const std::string GetReleaseName(context::RequestContext &context) { |
There was a problem hiding this comment.
do we need const here? same as line 65
There was a problem hiding this comment.
I already tried that and I get the following compilation error. I think this is because the service_context() method is not marked as const. Let me know if you are OK with marking that method as const - I think it can be made into a const but I don't know why it was not marked const.
contrib/endpoints/src/api_manager/check_security_rules.cc: In function 'const string google::api_manager::{anonymous}::GetReleaseName(const google::api_manager::context::RequestContext&)':
contrib/endpoints/src/api_manager/check_security_rules.cc:61:34: error: passing 'const google::api_manager::context::RequestContext' as 'this' argument of 'google::api_manager::context::ServiceContext* google::api_manager::context::RequestContext::service_context()' discards qualifiers [-fpermissive]
return context.service_context()->service_name() + ":" +
^
contrib/endpoints/src/api_manager/check_security_rules.cc:62:34: error: passing 'const google::api_manager::context::RequestContext' as 'this' argument of 'google::api_manager::context::ServiceContext* google::api_manager::context::RequestContext::service_context()' discards qualifiers [-fpermissive]
context.service_context()->service().apis(0).version();
| auto checker = GetPtr(); | ||
| HttpFetch(GetReleaseUrl(context), "GET", "", | ||
| HttpFetch(GetReleaseUrl(*context.get()), "GET", "", | ||
| [context, final_continuation, checker](Status status, |
There was a problem hiding this comment.
could we just do "*context" to convert shared_ptr to const T&?
| return RequireAuth() && config_->server_config() && | ||
| !config_->server_config() | ||
| ->api_check_security_rules_config() | ||
| .firebase_server() |
There was a problem hiding this comment.
you may need to call has_ first before you access its members.
There was a problem hiding this comment.
Added it. For some reason this is not being done in other parts of the code. I am adding this check in one place I know.
| char *json_str = | ||
| grpc_json_dump_to_string(const_cast<::grpc_json *>(grpc_json), 0); | ||
| user_info->claims = json_str == nullptr ? "" : json_str; | ||
| gpr_free(json_str); |
There was a problem hiding this comment.
you probably want to check if json_str is nullptr
| const char kFirebaseServerStaging[] = | ||
| "https://staging-firebaserules.sandbox.googleapis.com/"; | ||
|
|
||
| const char kFirebaseService[] = |
There was a problem hiding this comment.
where are these two constants used?
There was a problem hiding this comment.
I will delete them once i have done more testing.
|
|
||
| std::string GetOperation(std::string &httpMethod) { | ||
| if (httpMethod == "POST") { | ||
| return std::string("create"); |
There was a problem hiding this comment.
Done. Some parts of the code were using them as I have done. I did not know this was a strict rule.
| request->set_method(method).set_url(url).set_auth_token(GetAuthToken()); | ||
|
|
||
| if (method != "GET") { | ||
| request->set_header("Content-Type", "application/json") |
There was a problem hiding this comment.
I have removed as many string constants from code as I could. Let me know if you think there are more that need to be changed.
qiwzhang
left a comment
There was a problem hiding this comment.
Just add a simple config_test for firebase_server for now.
In a separate PR, add check_security_rules_test.cc, similar to auth_check_test.cc
|
|
||
| const std::string GetFirebaseServer(const context::RequestContext &context) { | ||
| return context.service_context() | ||
| ->config() |
There was a problem hiding this comment.
make a GetFireBaseServer() function in Config class. Later when service_config is ready, get it from there. Only need to change that function.
| const char kContentType[] = "Content-Type"; | ||
| const char kApplication[] = "application/json"; | ||
|
|
||
| const std::string GetFirebaseServer(const context::RequestContext &context) { |
There was a problem hiding this comment.
I still don't understand the purpose of "const" in
const std::string foo()
what is this const for?
|
|
||
| const std::string GetReleaseName(const context::RequestContext &context) { | ||
| return context.service_context()->service_name() + ":" + | ||
| context.service_context()->service().apis(0).version(); |
There was a problem hiding this comment.
when enabling firebase, need to make sure apis.size() == 1.
| grpc_json_dump_to_string(const_cast<::grpc_json *>(grpc_json), 0); | ||
| user_info->claims = json_str == nullptr ? "" : json_str; | ||
| if (json_str != nullptr) { | ||
| gpr_free(json_str); |
There was a problem hiding this comment.
move the line above in here? member std::string is default to "", so you just need to assign once.
| bool IsRulesCheckEnabled() const { | ||
| return RequireAuth() && config_->server_config() && | ||
| return RequireAuth() && service().apis_size() > 0 && | ||
| config_->server_config() && |
There was a problem hiding this comment.
can we call config->GEtFirebaseServer()?
|
|
||
| auto server = config->GetFirebaseServer(); | ||
| ASSERT_EQ(server, "https://myfirebaseserver.com/"); | ||
| } |
There was a problem hiding this comment.
could you add a test case with a non-empty server_config, but no api_check_security_rules_config.
No description provided.