realm / realm-core

Core database component for the Realm Mobile Database SDKs
https://realm.io
Apache License 2.0
1.01k stars 155 forks source link

If a baas call both updates its location and does an access token refresh - the app request can be sent to the wrong server #7799

Closed sync-by-unito[bot] closed 2 months ago

sync-by-unito[bot] commented 2 months ago

Given the following test case:

TEST_CASE("app: call function with expired access token", "[sync][app][function][baas]") {
    auto base_path = util::make_temp_dir();
    test_util::TestDirGuard tdg(base_path);
    AppConfig app_config;
    set_app_config_defaults(app_config, instance_of<SynchronousTestTransport>);
    app_config.app_id = "...";
    app_config.base_url = "https://realm.mongodb.com";
    app_config.base_file_path = tdg.c_str();
    app_config.metadata_mode = AppConfig::MetadataMode::NoEncryption;

    bson::BsonArray args{"hello, world!"};
    const auto checkFn = [](Optional<std::string>&& ret, Optional<AppError>&& error) {
        REQUIRE(!error);
        REQUIRE(ret);
        REQUIRE(*ret == "HELLO");
    };
    {
        auto app = App::get_app(App::CacheMode::Disabled, app_config);
        auto user =
            log_in(app, AppCredentials::api_key("..."));
        app->call_function<std::string>("Function_0", args, checkFn);
    }

    auto logger = util::Logger::get_default_logger();
    {
        logger->info("*** GETTING APP AGAIN ***");
        auto app = App::get_app(App::CacheMode::Disabled, app_config);
        auto user = app->current_user();
        logger->info("*** INVALIDATING ACCESS TOKEN ***");
        user->update_data_for_testing([](UserData& data) {
            data.access_token = RealmJWT(ENCODE_FAKE_JWT("fake_access_token"));
        });
        logger->info("*** CALLING FUNCTION ***");
        app->call_function<std::string>("Function_0", args, checkFn);
    }
}

The second time we try to call the function, we'll first refresh our location, then we'll try to refresh the access token, and then we'll try to call the function. The retry logic for refreshing the access token doesn't know that the base url changed while processing the request, and so will send it to the original (wrong) server if you're in a LOCAL deployment and get a 401 unauthorized in response, and won't be able to recover from that.

sync-by-unito[bot] commented 2 months ago

➤ PM Bot commented:

Jira ticket: RCORE-2164

sync-by-unito[bot] commented 2 months ago

➤ Jonathan Reams commented:

It looks like this bug was fixed by one of the commits in this PR which was released as realm core v14.6.0

sync-by-unito[bot] commented 2 months ago

➤ Jonathan Reams commented:

As noted above, this has already been fixed in master.