Commit 43a7e9dc authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[remoting][FTL] Normalize FTL ID

FTL currently returns raw email address so NormalizeJid() seems to work
out of the box. But they do plan to change it to a more aggresive
canonical form, which will cause users with email addresses with dots
fail to generate signatures or validate sender/receiver.

This CL implements the new normalization logic that will be used when
normalizing an FTL ID.

Bug: 968368
Change-Id: Ic7fa27e183124096563a6a7b4e337479e7edbb1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1636594
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664848}
parent 8746adaa
......@@ -228,7 +228,7 @@ void It2MeHost::OnAccessDenied(const std::string& jid) {
++failed_login_attempts_;
if (failed_login_attempts_ == kMaxLoginAttempts) {
DisconnectOnNetworkThread();
} else if (connecting_jid_ == jid) {
} else if (connecting_jid_ == NormalizeJid(jid)) {
DCHECK_EQ(state_, kConnecting);
connecting_jid_.clear();
confirmation_dialog_proxy_.reset();
......@@ -499,20 +499,22 @@ void It2MeHost::DisconnectOnNetworkThread() {
}
void It2MeHost::ValidateConnectionDetails(
const std::string& remote_jid,
const std::string& original_remote_jid,
const ValidationResultCallback& result_callback) {
DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
// First ensure the JID we received is valid.
std::string client_username;
if (!SplitJidResource(remote_jid, &client_username, /*resource=*/nullptr)) {
LOG(ERROR) << "Rejecting incoming connection from " << remote_jid
if (!SplitJidResource(original_remote_jid, &client_username,
/*resource=*/nullptr)) {
LOG(ERROR) << "Rejecting incoming connection from " << original_remote_jid
<< ": Invalid JID.";
result_callback.Run(
protocol::ValidatingAuthenticator::Result::ERROR_INVALID_ACCOUNT);
DisconnectOnNetworkThread();
return;
}
std::string remote_jid = NormalizeJid(original_remote_jid);
if (client_username.empty()) {
LOG(ERROR) << "Invalid user name passed in: " << remote_jid;
......
......@@ -36,7 +36,8 @@ Me2MeHostAuthenticatorFactory::CreateWithPin(
new Me2MeHostAuthenticatorFactory());
result->use_service_account_ = use_service_account;
result->host_owner_ = host_owner;
result->host_owner_email_ = host_owner_email;
result->canonical_host_owner_email_ = GetCanonicalEmail(
host_owner_email.empty() ? host_owner : host_owner_email);
result->local_cert_ = local_cert;
result->key_pair_ = key_pair;
result->required_client_domain_list_ = std::move(required_client_domain_list);
......@@ -59,7 +60,8 @@ Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
new Me2MeHostAuthenticatorFactory());
result->use_service_account_ = use_service_account;
result->host_owner_ = host_owner;
result->host_owner_email_ = host_owner_email;
result->canonical_host_owner_email_ = GetCanonicalEmail(
host_owner_email.empty() ? host_owner : host_owner_email);
result->local_cert_ = local_cert;
result->key_pair_ = key_pair;
result->required_client_domain_list_ = std::move(required_client_domain_list);
......@@ -73,8 +75,11 @@ Me2MeHostAuthenticatorFactory::~Me2MeHostAuthenticatorFactory() = default;
std::unique_ptr<Authenticator>
Me2MeHostAuthenticatorFactory::CreateAuthenticator(
const std::string& local_jid,
const std::string& remote_jid) {
const std::string& original_local_jid,
const std::string& original_remote_jid) {
std::string local_jid = NormalizeJid(original_local_jid);
std::string remote_jid = NormalizeJid(original_remote_jid);
std::string remote_jid_prefix;
if (!use_service_account_) {
......@@ -88,12 +93,11 @@ Me2MeHostAuthenticatorFactory::CreateAuthenticator(
new RejectingAuthenticator(Authenticator::INVALID_CREDENTIALS));
}
} else if (SignalingAddress(local_jid).channel() ==
SignalingAddress::Channel::FTL &&
!host_owner_email_.empty()) {
SignalingAddress::Channel::FTL) {
// A non-gmail account's |host_owner_| will be a GAIA JID that is different
// than its actual email address, which only works for XMPP connections. FTL
// always uses the user's actual email.
remote_jid_prefix = host_owner_email_;
remote_jid_prefix = canonical_host_owner_email_;
} else {
// TODO(rmsousa): This only works for cases where the JID prefix matches
// the host owner email. Figure out a way to verify the JID in other cases.
......
......@@ -59,7 +59,7 @@ class Me2MeHostAuthenticatorFactory : public AuthenticatorFactory {
// Used for all host authenticators.
bool use_service_account_;
std::string host_owner_;
std::string host_owner_email_;
std::string canonical_host_owner_email_;
std::string local_cert_;
scoped_refptr<RsaKeyPair> key_pair_;
std::vector<std::string> required_client_domain_list_;
......
......@@ -10,15 +10,50 @@
namespace remoting {
namespace {
constexpr char kFtlResourcePrefix[] = "chromoting_ftl_";
constexpr char kGmailDomain[] = "gmail.com";
constexpr char kGooglemailDomain[] = "googlemail.com";
} // namespace
std::string NormalizeJid(const std::string& jid) {
std::string bare_jid;
std::string resource;
if (SplitJidResource(jid, &bare_jid, &resource)) {
return base::ToLowerASCII(bare_jid) + "/" + resource;
std::string normalized_bare_jid = resource.find(kFtlResourcePrefix) == 0
? GetCanonicalEmail(bare_jid)
: base::ToLowerASCII(bare_jid);
return normalized_bare_jid + "/" + resource;
}
return base::ToLowerASCII(bare_jid);
}
std::string GetCanonicalEmail(std::string email) {
DCHECK(email.find('/') == std::string::npos)
<< "You seemed to pass in a full JID. You should only pass in an email "
<< "address.";
email = base::ToLowerASCII(email);
base::TrimString(email, base::kWhitespaceASCII, &email);
size_t at_index = email.find('@');
if (at_index == std::string::npos) {
LOG(ERROR) << "Unexpected email address. Character '@' is missing.";
return email;
}
std::string username = email.substr(0, at_index);
std::string domain = email.substr(at_index + 1);
if (domain == kGmailDomain || domain == kGooglemailDomain) {
// GMail/GoogleMail domains ignore dots, whereas other domains may not.
base::RemoveChars(username, ".", &username);
return username + '@' + kGmailDomain;
}
return email;
}
bool SplitJidResource(const std::string& full_jid,
std::string* bare_jid,
std::string* resource) {
......
......@@ -9,10 +9,20 @@
namespace remoting {
// Normalizes the |jid| by converting case-insensitive parts (node and domain)
// to lower-case.
// Normalizes the |jid|. If |jid| is an FTL ID then the email part will be
// canonicalized. Otherwise it will simply convert case-insensitive parts (node
// and domain) to lower-case.
std::string NormalizeJid(const std::string& jid);
// Returns the canonical email for the given email. Note that this only works
// for email address (bare JID) and does not work for full JID.
//
// Canonicalizes by:
// * changing to lowercase
// * removing all dots if this is a gmail.com or googlemail.com domain
// * normalize email domain googlemail.com to gmail.com
std::string GetCanonicalEmail(std::string email);
// Splits a JID into a bare JID and a resource suffix. Either |full_jid|,
// |resource|, or both may be null. If |full_jid| is already
// a bare JID, |resource| is set to the empty string. Returns true if
......
......@@ -8,15 +8,38 @@
namespace remoting {
TEST(JidUtil, NormalizeJid) {
TEST(JidUtilTest, NormalizeJid) {
EXPECT_EQ(NormalizeJid("USER@DOMAIN.com"), "user@domain.com");
EXPECT_EQ(NormalizeJid("user@domain.com"), "user@domain.com");
EXPECT_EQ(NormalizeJid("USER@DOMAIN.com/RESOURCE"),
"user@domain.com/RESOURCE");
EXPECT_EQ(NormalizeJid("USER@DOMAIN.com/"), "user@domain.com/");
// Jabber ID normalization
EXPECT_EQ("user.mixed.case@googlemail.com/RESOURCE",
NormalizeJid("User.Mixed.Case@GOOGLEMAIL.com/RESOURCE"));
// FTL ID normalization
EXPECT_EQ("user@domain.com/chromoting_ftl_abc123",
NormalizeJid("USER@DOMAIN.com/chromoting_ftl_abc123"));
EXPECT_EQ("user@domain.com/chromoting_ftl_abc123",
NormalizeJid(" USER@DOMAIN.com/chromoting_ftl_abc123"));
EXPECT_EQ("usermixedcase@gmail.com/chromoting_ftl_abc123",
NormalizeJid("User.Mixed.Case@GMAIL.com/chromoting_ftl_abc123"));
EXPECT_EQ(
"usermixedcase@gmail.com/chromoting_ftl_abc123",
NormalizeJid("User.Mixed.Case@GOOGLEMAIL.com/chromoting_ftl_abc123"));
EXPECT_EQ("user.mixed.case@domain.com/chromoting_ftl_abc123",
NormalizeJid("User.Mixed.Case@DOMAIN.com/chromoting_ftl_abc123"));
EXPECT_EQ("invalid.user/chromoting_ftl_abc123",
NormalizeJid(" Invalid.User/chromoting_ftl_abc123"));
EXPECT_EQ("invalid.user@/chromoting_ftl_abc123",
NormalizeJid(" Invalid.User@/chromoting_ftl_abc123"));
EXPECT_EQ("@gmail.com/chromoting_ftl_abc123",
NormalizeJid("@googlemail.com/chromoting_ftl_abc123"));
}
TEST(JidUtil, SplitJidResource) {
TEST(JidUtilTest, SplitJidResource) {
std::string bare_jid;
std::string resource_suffix;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment