Add revocationTimestamp parameter into revocation entry
BUG: 27313743
Change-Id: Ic1d5ebbe771ac3437d9340ca91840d04fa960c57
Reviewed-on: https://weave-review.googlesource.com/2727
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/src/access_api_handler.cc b/src/access_api_handler.cc
index fc7b97b..ec22094 100644
--- a/src/access_api_handler.cc
+++ b/src/access_api_handler.cc
@@ -23,6 +23,7 @@
const char kUserId[] = "userId";
const char kApplicationId[] = "applicationId";
const char kExpirationTime[] = "expirationTime";
+const char kRevocationTimestamp[] = "revocationTimestamp";
const char kBlackList[] = "revocationListEntries";
bool GetIds(const base::DictionaryValue& parameters,
@@ -65,6 +66,9 @@
"applicationId": {
"type": "string"
},
+ "revocationTimestamp": {
+ "type": "integer"
+ },
"expirationTime": {
"type": "integer"
}
@@ -85,6 +89,9 @@
"applicationId": {
"type": "string"
},
+ "revocationTimestamp": {
+ "type": "integer"
+ },
"expirationTime": {
"type": "integer"
}
@@ -132,15 +139,25 @@
return;
}
- int time_j2k = 0;
- if (!parameters.GetInteger(kExpirationTime, &time_j2k)) {
+ int expiration_j2k = 0;
+ if (!parameters.GetInteger(kExpirationTime, &expiration_j2k)) {
Error::AddToPrintf(&error, FROM_HERE, errors::commands::kInvalidPropValue,
"Expiration time is missing");
command->Abort(error.get(), nullptr);
return;
}
- manager_->Block(user_id, app_id, FromJ2000Time(time_j2k),
+ int revocation_j2k = 0;
+ if (!parameters.GetInteger(kRevocationTimestamp, &revocation_j2k)) {
+ Error::AddToPrintf(&error, FROM_HERE, errors::commands::kInvalidPropValue,
+ "Revocation timestamp is missing");
+ command->Abort(error.get(), nullptr);
+ return;
+ }
+
+ manager_->Block(AccessBlackListManager::Entry{user_id, app_id,
+ FromJ2000Time(revocation_j2k),
+ FromJ2000Time(expiration_j2k)},
base::Bind(&AccessApiHandler::OnCommandDone,
weak_ptr_factory_.GetWeakPtr(), cmd));
}
diff --git a/src/access_api_handler.h b/src/access_api_handler.h
index 83f0973..19fe799 100644
--- a/src/access_api_handler.h
+++ b/src/access_api_handler.h
@@ -20,8 +20,7 @@
// Objects of the class subscribe for notification from CommandManager and
// execute incoming commands.
// Handled commands:
-// accessControlBlackList.block
-// accessControlBlackList.unblock
+// accessControlBlackList.revoke
// accessControlBlackList.list
class AccessApiHandler final {
public:
diff --git a/src/access_api_handler_unittest.cc b/src/access_api_handler_unittest.cc
index 79f2d49..0a01d4f 100644
--- a/src/access_api_handler_unittest.cc
+++ b/src/access_api_handler_unittest.cc
@@ -104,6 +104,9 @@
"applicationId": {
"type": "string"
},
+ "revocationTimestamp": {
+ "type": "integer"
+ },
"expirationTime": {
"type": "integer"
}
@@ -124,6 +127,9 @@
"applicationId": {
"type": "string"
},
+ "revocationTimestamp": {
+ "type": "integer"
+ },
"expirationTime": {
"type": "integer"
}
@@ -150,9 +156,14 @@
}
TEST_F(AccessApiHandlerTest, Revoke) {
- EXPECT_CALL(access_manager_, Block(std::vector<uint8_t>{1, 2, 3},
- std::vector<uint8_t>{3, 4, 5}, _, _))
- .WillOnce(WithArgs<3>(
+ EXPECT_CALL(
+ access_manager_,
+ Block(AccessBlackListManager::Entry{std::vector<uint8_t>{1, 2, 3},
+ std::vector<uint8_t>{3, 4, 5},
+ base::Time::FromTimeT(946686034),
+ base::Time::FromTimeT(946692690)},
+ _))
+ .WillOnce(WithArgs<1>(
Invoke([](const DoneCallback& callback) { callback.Run(nullptr); })));
EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(1));
@@ -162,7 +173,8 @@
'parameters': {
'userId': 'AQID',
'applicationId': 'AwQF',
- 'expirationTime': 1234
+ 'expirationTime': 7890,
+ 'revocationTimestamp': 1234
}
})");
@@ -174,8 +186,14 @@
TEST_F(AccessApiHandlerTest, List) {
std::vector<AccessBlackListManager::Entry> entries{
- {{11, 12, 13}, {21, 22, 23}, base::Time::FromTimeT(1410000000)},
- {{31, 32, 33}, {41, 42, 43}, base::Time::FromTimeT(1420000000)},
+ {{11, 12, 13},
+ {21, 22, 23},
+ base::Time::FromTimeT(1310000000),
+ base::Time::FromTimeT(1410000000)},
+ {{31, 32, 33},
+ {41, 42, 43},
+ base::Time::FromTimeT(1300000000),
+ base::Time::FromTimeT(1420000000)},
};
EXPECT_CALL(access_manager_, GetEntries()).WillOnce(Return(entries));
EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4));
diff --git a/src/access_black_list_manager.h b/src/access_black_list_manager.h
index eb3f06a..edbb3f2 100644
--- a/src/access_black_list_manager.h
+++ b/src/access_black_list_manager.h
@@ -14,6 +14,16 @@
class AccessBlackListManager {
public:
struct Entry {
+ Entry() = default;
+
+ Entry(const std::vector<uint8_t>& user,
+ const std::vector<uint8_t>& app,
+ base::Time revocation_ts,
+ base::Time expiration_ts)
+ : user_id{user},
+ app_id{app},
+ revocation{revocation_ts},
+ expiration{expiration_ts} {}
// user_id is empty, app_id is empty: block everything.
// user_id is not empty, app_id is empty: block if user_id matches.
// user_id is empty, app_id is not empty: block if app_id matches.
@@ -21,18 +31,20 @@
std::vector<uint8_t> user_id;
std::vector<uint8_t> app_id;
+ // Revoke matching entries if |revocation| is not less than
+ // delegation timestamp.
+ base::Time revocation;
+
// Time after which to discard the rule.
base::Time expiration;
};
virtual ~AccessBlackListManager() = default;
virtual void AddEntryAddedCallback(const base::Closure& callback) = 0;
- virtual void Block(const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id,
- const base::Time& expiration,
- const DoneCallback& callback) = 0;
+ virtual void Block(const Entry& entry, const DoneCallback& callback) = 0;
virtual bool IsBlocked(const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id) const = 0;
+ const std::vector<uint8_t>& app_id,
+ base::Time timestamp) const = 0;
virtual std::vector<Entry> GetEntries() const = 0;
virtual size_t GetSize() const = 0;
virtual size_t GetCapacity() const = 0;
@@ -40,8 +52,8 @@
inline bool operator==(const AccessBlackListManager::Entry& l,
const AccessBlackListManager::Entry& r) {
- return l.user_id == r.user_id && l.app_id == r.app_id &&
- l.expiration == r.expiration;
+ return l.revocation == r.revocation && l.expiration == r.expiration &&
+ l.user_id == r.user_id && l.app_id == r.app_id;
}
inline bool operator!=(const AccessBlackListManager::Entry& l,
diff --git a/src/access_black_list_manager_impl.cc b/src/access_black_list_manager_impl.cc
index 3a54073..48c998b 100644
--- a/src/access_black_list_manager_impl.cc
+++ b/src/access_black_list_manager_impl.cc
@@ -10,6 +10,7 @@
#include "src/commands/schema_constants.h"
#include "src/data_encoding.h"
+#include "src/utils.h"
namespace weave {
@@ -19,6 +20,7 @@
const char kUser[] = "user";
const char kApp[] = "app";
const char kExpiration[] = "expiration";
+const char kRevocation[] = "revocation";
}
AccessBlackListManagerImpl::AccessBlackListManagerImpl(
@@ -34,19 +36,22 @@
return;
if (auto list = base::ListValue::From(
base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
- for (const auto& e : *list) {
+ for (const auto& value : *list) {
const base::DictionaryValue* entry{nullptr};
std::string user;
std::string app;
- decltype(entries_)::key_type key;
- int expiration;
- if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) &&
- Base64Decode(user, &key.first) && entry->GetString(kApp, &app) &&
- Base64Decode(app, &key.second) &&
+ Entry e;
+ int revocation = 0;
+ int expiration = 0;
+ if (value->GetAsDictionary(&entry) && entry->GetString(kUser, &user) &&
+ Base64Decode(user, &e.user_id) && entry->GetString(kApp, &app) &&
+ Base64Decode(app, &e.app_id) &&
+ entry->GetInteger(kRevocation, &revocation) &&
entry->GetInteger(kExpiration, &expiration)) {
- base::Time expiration_time = base::Time::FromTimeT(expiration);
- if (expiration_time > clock_->Now())
- entries_[key] = expiration_time;
+ e.revocation = FromJ2000Time(revocation);
+ e.expiration = FromJ2000Time(expiration);
+ if (e.expiration > clock_->Now())
+ entries_.insert(e);
}
}
if (entries_.size() < list->GetSize()) {
@@ -66,9 +71,10 @@
base::ListValue list;
for (const auto& e : entries_) {
scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
- entry->SetString(kUser, Base64Encode(e.first.first));
- entry->SetString(kApp, Base64Encode(e.first.second));
- entry->SetInteger(kExpiration, e.second.ToTimeT());
+ entry->SetString(kUser, Base64Encode(e.user_id));
+ entry->SetString(kApp, Base64Encode(e.app_id));
+ entry->SetInteger(kRevocation, ToJ2000Time(e.revocation));
+ entry->SetInteger(kExpiration, ToJ2000Time(e.expiration));
list.Append(std::move(entry));
}
@@ -79,7 +85,7 @@
void AccessBlackListManagerImpl::RemoveExpired() {
for (auto i = begin(entries_); i != end(entries_);) {
- if (i->second <= clock_->Now())
+ if (i->expiration <= clock_->Now())
i = entries_.erase(i);
else
++i;
@@ -91,13 +97,11 @@
on_entry_added_callbacks_.push_back(callback);
}
-void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id,
- const base::Time& expiration,
+void AccessBlackListManagerImpl::Block(const Entry& entry,
const DoneCallback& callback) {
// Iterating is OK as Save below is more expensive.
RemoveExpired();
- if (expiration <= clock_->Now()) {
+ if (entry.expiration <= clock_->Now()) {
if (!callback.is_null()) {
ErrorPtr error;
Error::AddTo(&error, FROM_HERE, "aleady_expired",
@@ -116,22 +120,36 @@
return;
}
- auto& value = entries_[std::make_pair(user_id, app_id)];
- value = std::max(value, expiration);
+ auto existing = entries_.find(entry);
+ if (existing != entries_.end()) {
+ Entry new_entry = entry;
+ new_entry.expiration = std::max(entry.expiration, existing->expiration);
+ new_entry.revocation = std::max(entry.revocation, existing->revocation);
+ entries_.erase(existing);
+ entries_.insert(new_entry);
+ } else {
+ entries_.insert(entry);
+ }
+
for (const auto& cb : on_entry_added_callbacks_)
cb.Run();
Save(callback);
}
-bool AccessBlackListManagerImpl::IsBlocked(
- const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id) const {
+bool AccessBlackListManagerImpl::IsBlocked(const std::vector<uint8_t>& user_id,
+ const std::vector<uint8_t>& app_id,
+ base::Time timestamp) const {
+ Entry entry_to_find;
for (const auto& user : {{}, user_id}) {
for (const auto& app : {{}, app_id}) {
- auto both = entries_.find(std::make_pair(user, app));
- if (both != end(entries_) && both->second > clock_->Now())
+ entry_to_find.user_id = user;
+ entry_to_find.app_id = app;
+ auto match = entries_.find(entry_to_find);
+ if (match != end(entries_) && match->expiration > clock_->Now() &&
+ match->revocation >= timestamp) {
return true;
+ }
}
}
return false;
@@ -139,10 +157,7 @@
std::vector<AccessBlackListManager::Entry>
AccessBlackListManagerImpl::GetEntries() const {
- std::vector<Entry> result;
- for (const auto& e : entries_)
- result.push_back({e.first.first, e.first.second, e.second});
- return result;
+ return {begin(entries_), end(entries_)};
}
size_t AccessBlackListManagerImpl::GetSize() const {
diff --git a/src/access_black_list_manager_impl.h b/src/access_black_list_manager_impl.h
index e41a93a..ff91a8f 100644
--- a/src/access_black_list_manager_impl.h
+++ b/src/access_black_list_manager_impl.h
@@ -5,7 +5,7 @@
#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
-#include <map>
+#include <set>
#include <utility>
#include <base/time/default_clock.h>
@@ -25,12 +25,10 @@
// AccessBlackListManager implementation.
void AddEntryAddedCallback(const base::Closure& callback) override;
- void Block(const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id,
- const base::Time& expiration,
- const DoneCallback& callback) override;
+ void Block(const Entry& entry, const DoneCallback& callback) override;
bool IsBlocked(const std::vector<uint8_t>& user_id,
- const std::vector<uint8_t>& app_id) const override;
+ const std::vector<uint8_t>& app_id,
+ base::Time timestamp) const override;
std::vector<Entry> GetEntries() const override;
size_t GetSize() const override;
size_t GetCapacity() const override;
@@ -40,13 +38,22 @@
void Save(const DoneCallback& callback);
void RemoveExpired();
+ struct EntryIdsLess {
+ bool operator()(const Entry& l, const Entry& r) const {
+ if (l.user_id < r.user_id)
+ return true;
+ if (l.user_id > r.user_id)
+ return false;
+ return l.app_id < r.app_id;
+ }
+ };
+
const size_t capacity_{0};
base::DefaultClock default_clock_;
base::Clock* clock_{&default_clock_};
provider::ConfigStore* store_{nullptr};
- std::map<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>, base::Time>
- entries_;
+ std::set<Entry, EntryIdsLess> entries_;
std::vector<base::Closure> on_entry_added_callbacks_;
DISALLOW_COPY_AND_ASSIGN(AccessBlackListManagerImpl);
diff --git a/src/access_black_list_manager_impl_unittest.cc b/src/access_black_list_manager_impl_unittest.cc
index 0f21c3e..3be9287 100644
--- a/src/access_black_list_manager_impl_unittest.cc
+++ b/src/access_black_list_manager_impl_unittest.cc
@@ -24,11 +24,13 @@
std::string to_load = R"([{
"user": "BQID",
"app": "BwQF",
- "expiration": 1410000000
+ "expiration": 463315200,
+ "revocation": 463314200
}, {
"user": "AQID",
"app": "AwQF",
- "expiration": 1419999999
+ "expiration": 473315199,
+ "revocation": 473313199
}])";
EXPECT_CALL(config_store_, LoadSettings("black_list"))
@@ -40,7 +42,8 @@
std::string to_save = R"([{
"user": "AQID",
"app": "AwQF",
- "expiration": 1419999999
+ "expiration": 473315199,
+ "revocation": 473313199
}])";
EXPECT_JSON_EQ(to_save, *test::CreateValue(json));
if (!callback.is_null())
@@ -60,7 +63,10 @@
EXPECT_EQ(1u, manager_->GetSize());
EXPECT_EQ(10u, manager_->GetCapacity());
EXPECT_EQ((std::vector<AccessBlackListManagerImpl::Entry>{{
- {1, 2, 3}, {3, 4, 5}, base::Time::FromTimeT(1419999999),
+ {1, 2, 3},
+ {3, 4, 5},
+ base::Time::FromTimeT(1419997999),
+ base::Time::FromTimeT(1419999999),
}}),
manager_->GetEntries());
}
@@ -75,22 +81,31 @@
std::string to_save = R"([{
"user": "AQID",
"app": "AwQF",
- "expiration": 1419999999
+ "expiration": 473315199,
+ "revocation": 473313199
}, {
"app": "CAgI",
"user": "BwcH",
- "expiration": 1419990000
+ "expiration": 473305200,
+ "revocation": 473295200
}])";
EXPECT_JSON_EQ(to_save, *test::CreateValue(json));
if (!callback.is_null())
callback.Run(nullptr);
})));
- manager_->Block({7, 7, 7}, {8, 8, 8}, base::Time::FromTimeT(1419990000), {});
+ manager_->Block({{7, 7, 7},
+ {8, 8, 8},
+ base::Time::FromTimeT(1419980000),
+ base::Time::FromTimeT(1419990000)},
+ {});
EXPECT_TRUE(callback_called);
}
TEST_F(AccessBlackListManagerImplTest, BlockExpired) {
- manager_->Block({}, {}, base::Time::FromTimeT(1400000000),
+ manager_->Block({{},
+ {},
+ base::Time::FromTimeT(1300000000),
+ base::Time::FromTimeT(1400000000)},
base::Bind([](ErrorPtr error) {
EXPECT_TRUE(error->HasError("aleady_expired"));
}));
@@ -105,18 +120,30 @@
})));
for (size_t i = manager_->GetSize(); i < manager_->GetCapacity(); ++i) {
manager_->Block(
- {99, static_cast<uint8_t>(i / 256), static_cast<uint8_t>(i % 256)},
- {8, 8, 8}, base::Time::FromTimeT(1419990000), {});
+ {{99, static_cast<uint8_t>(i / 256), static_cast<uint8_t>(i % 256)},
+ {8, 8, 8},
+ base::Time::FromTimeT(1419970000),
+ base::Time::FromTimeT(1419990000)},
+ {});
EXPECT_EQ(i + 1, manager_->GetSize());
}
- manager_->Block({99}, {8, 8, 8}, base::Time::FromTimeT(1419990000),
+ manager_->Block({{99},
+ {8, 8, 8},
+ base::Time::FromTimeT(1419970000),
+ base::Time::FromTimeT(1419990000)},
base::Bind([](ErrorPtr error) {
EXPECT_TRUE(error->HasError("blacklist_is_full"));
}));
}
-TEST_F(AccessBlackListManagerImplTest, IsBlockedFalse) {
- EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}));
+TEST_F(AccessBlackListManagerImplTest, IsBlockedIdsNotMacth) {
+ EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {}));
+}
+
+TEST_F(AccessBlackListManagerImplTest, IsBlockedRevocationIsOld) {
+ // Ids match but delegation time is newer than revocation time.
+ EXPECT_FALSE(manager_->IsBlocked({1, 2, 3}, {3, 4, 5},
+ base::Time::FromTimeT(1429997999)));
}
class AccessBlackListManagerImplIsBlockedTest
@@ -132,13 +159,16 @@
if (!callback.is_null())
callback.Run(nullptr);
})));
- manager_->Block(std::get<0>(GetParam()), std::get<1>(GetParam()),
- base::Time::FromTimeT(1419990000), {});
+ manager_->Block({std::get<0>(GetParam()),
+ std::get<1>(GetParam()),
+ {},
+ base::Time::FromTimeT(1419990000)},
+ {});
}
};
TEST_P(AccessBlackListManagerImplIsBlockedTest, IsBlocked) {
- EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}));
+ EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {}));
}
INSTANTIATE_TEST_CASE_P(
diff --git a/src/test/mock_black_list_manager.h b/src/test/mock_black_list_manager.h
index 6b55b86..2f6d7eb 100644
--- a/src/test/mock_black_list_manager.h
+++ b/src/test/mock_black_list_manager.h
@@ -16,14 +16,11 @@
class MockAccessBlackListManager : public AccessBlackListManager {
public:
MOCK_METHOD1(AddEntryAddedCallback, void(const base::Closure&));
- MOCK_METHOD4(Block,
- void(const std::vector<uint8_t>&,
- const std::vector<uint8_t>&,
- const base::Time&,
- const DoneCallback&));
- MOCK_CONST_METHOD2(IsBlocked,
+ MOCK_METHOD2(Block, void(const Entry&, const DoneCallback&));
+ MOCK_CONST_METHOD3(IsBlocked,
bool(const std::vector<uint8_t>&,
- const std::vector<uint8_t>&));
+ const std::vector<uint8_t>&,
+ base::Time));
MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>());
MOCK_CONST_METHOD0(GetSize, size_t());
MOCK_CONST_METHOD0(GetCapacity, size_t());