Merge remote-tracking branch 'weave/master' into 'weave/aosp-master'

37994f4 Fix some of compiler warnings.
ebde3c1 Rename *BlackList* into *Revocation*
efbd66b Remove unused constants
5a1990f Implement revocation list check when validating auth token
51dcfad Add revocationTimestamp parameter into revocation entry
4846c44 Remove AccessBlackListManager::Unblock
958a359 Revert "debian: add debian packaging files"
7f2a5dc daemon: register device after component init
89b3495 Removing legacy API from libweave
1054d3e Move minimalRole constants from schema_constants.h to a local .cc file
9e9023e daemon/light: fix light trait def
6da60ad Fix use-after-free detected by ASAN
c23ea22 Replace expirationTimeoutSec with expirationTime
7c0ea69 Rename _accessControlBlackList into _accessRevocationList
012cd98 Move mock_component_manager.h into test/ dir
c6d99bb Move MockAccessBlackListManager into separate file
b612e3c Reset access token secret on new black list entry
d1d52e7 Add AccessBlackListManager::AddEntryAddedCallback
7fc5434 debian: add debian packaging files
634c408 Remove property from json added by mistake

Change-Id: I69380e60cf9888999224fdf11a5bc35f0bc7bda2
diff --git a/Makefile b/Makefile
index 9810dd0..70f7ee7 100644
--- a/Makefile
+++ b/Makefile
@@ -28,13 +28,8 @@
 	-Wextra \
 	-Wformat=2 \
 	-Wl,--exclude-libs,ALL \
-	-Wno-char-subscripts \
 	-Wno-missing-field-initializers \
-	-Wno-unused-local-typedefs \
 	-Wno-unused-parameter \
-	-Wpacked \
-	-Wpointer-arith \
-	-Wwrite-strings
 
 CFLAGS_Debug := \
 	-O0 \
@@ -56,7 +51,6 @@
   CFLAGS := $(filter-out -Wl$(comma)--exclude-libs$(comma)ALL,$(CFLAGS))
   CFLAGS += \
     -fno-omit-frame-pointer \
-    -Wno-deprecated-register \
     -Wno-inconsistent-missing-override
   ifeq (Debug, $(BUILD_MODE))
     CFLAGS += \
diff --git a/examples/daemon/common/daemon.h b/examples/daemon/common/daemon.h
index 0b3c25a..22591a2 100644
--- a/examples/daemon/common/daemon.h
+++ b/examples/daemon/common/daemon.h
@@ -92,16 +92,18 @@
                                     http_client_.get(), network_.get(),
                                     dns_sd_.get(), http_server_.get(),
                                     wifi_.get(), bluetooth_.get());
-
     if (!opts.registration_ticket.empty()) {
-      weave::RegistrationData data;
-      data.ticket_id = opts.registration_ticket;
-      data.service_url = opts.service_url;
-      device_->Register(data, base::Bind(&OnRegisterDeviceDone, device_.get()));
+      registration_data_.ticket_id = opts.registration_ticket;
+      registration_data_.service_url = opts.service_url;
     }
   }
 
-  void Run() { task_runner_->Run(); }
+  void Run() {
+    if (!registration_data_.ticket_id.empty()) {
+      device_->Register(registration_data_, base::Bind(&OnRegisterDeviceDone, device_.get()));
+    }
+    task_runner_->Run();
+  }
 
   weave::Device* GetDevice() const { return device_.get(); }
 
@@ -127,4 +129,5 @@
   std::unique_ptr<weave::examples::HttpServerImpl> http_server_;
   std::unique_ptr<weave::examples::WifiImpl> wifi_;
   std::unique_ptr<weave::Device> device_;
+  weave::RegistrationData registration_data_;
 };
diff --git a/examples/daemon/light/light.cc b/examples/daemon/light/light.cc
index 4cbf9b4..07c0231 100644
--- a/examples/daemon/light/light.cc
+++ b/examples/daemon/light/light.cc
@@ -19,7 +19,7 @@
         "parameters": {
           "state": {
             "type": "string",
-            "enum": [ "on", "standby" ]
+            "enum": [ "on", "off" ]
           }
         }
       }
@@ -27,7 +27,7 @@
     "state": {
       "state": {
         "type": "string",
-        "enum": [ "on", "standby" ],
+        "enum": [ "on", "off" ],
         "isRequired": true
       }
     }
@@ -38,23 +38,23 @@
         "minimalRole": "user",
         "parameters": {
           "brightness": {
-            "type": "integer",
-            "minimum": 0,
-            "maximum": 100
+            "type": "number",
+            "minimum": 0.0,
+            "maximum": 1.0
           }
         }
       }
     },
     "state": {
       "brightness": {
-        "type": "integer",
+        "type": "number",
         "isRequired": true,
-        "minimum": 0,
-        "maximum": 100
+        "minimum": 0.0,
+        "maximum": 1.0
       }
     }
   },
-  "colorXY": {
+  "colorXy": {
     "commands": {
       "setConfig": {
         "minimalRole": "user",
@@ -157,7 +157,7 @@
 })";
 
 const char kDefaultState[] = R"({
-  "colorXY": {
+  "colorXy": {
     "colorSetting": {"colorX": 0, "colorY": 0},
     "colorCapRed":  {"colorX": 0.674, "colorY": 0.322},
     "colorCapGreen":{"colorX": 0.408, "colorY": 0.517},
@@ -178,7 +178,7 @@
     device_ = device;
 
     device->AddTraitDefinitionsFromJson(kTraits);
-    CHECK(device->AddComponent(kComponent, {"onOff", "brightness", "colorXY"},
+    CHECK(device->AddComponent(kComponent, {"onOff", "brightness", "colorXy"},
                                nullptr));
     CHECK(
         device->SetStatePropertiesFromJson(kComponent, kDefaultState, nullptr));
@@ -190,7 +190,7 @@
     device->AddCommandHandler(kComponent, "brightness.setConfig",
                               base::Bind(&LightHandler::OnBrightnessSetConfig,
                                          weak_ptr_factory_.GetWeakPtr()));
-    device->AddCommandHandler(kComponent, "colorXY.setConfig",
+    device->AddCommandHandler(kComponent, "colorXy.setConfig",
                               base::Bind(&LightHandler::OnColorXYSetConfig,
                                          weak_ptr_factory_.GetWeakPtr()));
   }
@@ -252,17 +252,17 @@
       return;
     LOG(INFO) << "received command: " << cmd->GetName();
     const auto& params = cmd->GetParameters();
-    const base::DictionaryValue* colorXY = nullptr;
-    if (params.GetDictionary("colorSetting", &colorXY)) {
+    const base::DictionaryValue* colorXy = nullptr;
+    if (params.GetDictionary("colorSetting", &colorXy)) {
       bool updateState = false;
       double X = 0.0;
       double Y = 0.0;
-      if (colorXY->GetDouble("colorX", &X)) {
+      if (colorXy->GetDouble("colorX", &X)) {
         color_X_ = X;
         updateState = true;
       }
 
-      if (colorXY->GetDouble("colorY", &Y)) {
+      if (colorXy->GetDouble("colorY", &Y)) {
         color_Y_ = Y;
         updateState = true;
       }
@@ -282,13 +282,13 @@
 
   void UpdateLightState() {
     base::DictionaryValue state;
-    state.SetString("onOff.state", light_status_ ? "on" : "standby");
+    state.SetString("onOff.state", light_status_ ? "on" : "off");
     state.SetInteger("brightness.brightness", brightness_state_);
 
-    std::unique_ptr<base::DictionaryValue> colorXY(new base::DictionaryValue());
-    colorXY->SetDouble("colorX", color_X_);
-    colorXY->SetDouble("colorY", color_Y_);
-    state.Set("colorXY.colorSetting", colorXY.release());
+    std::unique_ptr<base::DictionaryValue> colorXy(new base::DictionaryValue());
+    colorXy->SetDouble("colorX", color_X_);
+    colorXy->SetDouble("colorY", color_Y_);
+    state.Set("colorXy.colorSetting", colorXy.release());
     device_->SetStateProperties(kComponent, state, nullptr);
   }
 
diff --git a/examples/provider/wifi_manager.cc b/examples/provider/wifi_manager.cc
index 7597e47..9337d23 100644
--- a/examples/provider/wifi_manager.cc
+++ b/examples/provider/wifi_manager.cc
@@ -46,20 +46,21 @@
   return status;
 }
 
+struct DirCloser {
+  void operator()(DIR* dir) { closedir(dir); }
+};
+
 std::string FindWirelessInterface() {
   std::string sysfs_net{"/sys/class/net"};
-  DIR* net_dir = opendir(sysfs_net.c_str());
+  std::unique_ptr<DIR, DirCloser> net_dir{opendir(sysfs_net.c_str())};
+  CHECK(net_dir);
   dirent* iface;
-  while ((iface = readdir(net_dir))) {
+  while ((iface = readdir(net_dir.get()))) {
     auto path = sysfs_net + "/" + iface->d_name + "/wireless";
-    DIR* wireless_dir = opendir(path.c_str());
-    if (wireless_dir != nullptr) {
-      closedir(net_dir);
-      closedir(wireless_dir);
+    std::unique_ptr<DIR, DirCloser> wireless_dir{opendir(path.c_str())};
+    if (wireless_dir)
       return iface->d_name;
-    }
   }
-  closedir(net_dir);
   return "";
 }
 
diff --git a/file_lists.mk b/file_lists.mk
index 9a015e2..e13553f 100644
--- a/file_lists.mk
+++ b/file_lists.mk
@@ -4,7 +4,7 @@
 
 WEAVE_SRC_FILES := \
 	src/access_api_handler.cc \
-	src/access_black_list_manager_impl.cc \
+	src/access_revocation_manager_impl.cc \
 	src/backoff_entry.cc \
 	src/base_api_handler.cc \
 	src/commands/cloud_command_proxy.cc \
@@ -51,7 +51,7 @@
 
 WEAVE_UNITTEST_SRC_FILES := \
 	src/access_api_handler_unittest.cc \
-	src/access_black_list_manager_impl_unittest.cc \
+	src/access_revocation_manager_impl_unittest.cc \
 	src/backoff_entry_unittest.cc \
 	src/base_api_handler_unittest.cc \
 	src/commands/cloud_command_proxy_unittest.cc \
diff --git a/include/weave/device.h b/include/weave/device.h
index 9a29574..b79e6a3 100644
--- a/include/weave/device.h
+++ b/include/weave/device.h
@@ -193,68 +193,6 @@
       provider::HttpServer* http_server,
       provider::Wifi* wifi,
       provider::Bluetooth* bluetooth_provider);
-
-  //========================== Deprecated APIs =========================
-
-  // Adds provided commands definitions. Can be called multiple times with
-  // condition that definitions do not conflict.
-  // Invalid value is fatal.
-  // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead.
-  LIBWEAVE_DEPRECATED virtual void AddCommandDefinitionsFromJson(
-      const std::string& json) = 0;
-  LIBWEAVE_DEPRECATED virtual void AddCommandDefinitions(
-      const base::DictionaryValue& dict) = 0;
-
-  // Sets handler for new commands added to the queue.
-  // |command_name| is the full command name of the command to handle. e.g.
-  // "base.reboot". Each command can have no more than one handler.
-  // Empty |command_name| sets default handler for all unhanded commands.
-  // No new command handlers can be set after default handler was set.
-  // DO NOT USE IN YOUR CODE: use AddCommandHandler() with component parameter.
-  LIBWEAVE_DEPRECATED virtual void AddCommandHandler(
-      const std::string& command_name,
-      const CommandHandlerCallback& callback) = 0;
-
-  // Adds provided state definitions. Can be called multiple times with
-  // condition that definitions do not conflict.
-  // Invalid value is fatal.
-  // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead.
-  LIBWEAVE_DEPRECATED virtual void AddStateDefinitionsFromJson(
-      const std::string& json) = 0;
-  LIBWEAVE_DEPRECATED virtual void AddStateDefinitions(
-      const base::DictionaryValue& dict) = 0;
-
-  // Sets value of multiple properties of the state.
-  // It's recommended to call this to initialize state defined by
-  // AddStateDefinitions.
-  // Example:
-  //   device->SetStatePropertiesFromJson("{'base':{'firmwareVersion':'123'}}")
-  // Method completely replaces properties included |json| or |dict|.
-  // Properties of the state not included |json| or |dict| will stay unchanged.
-  // DO NOT USE IN YOUR CODE: use SetStateProperties() with component parameter.
-  LIBWEAVE_DEPRECATED virtual bool SetStatePropertiesFromJson(
-      const std::string& json,
-      ErrorPtr* error) = 0;
-  LIBWEAVE_DEPRECATED virtual bool SetStateProperties(
-      const base::DictionaryValue& dict,
-      ErrorPtr* error) = 0;
-
-  // Returns value of the single property.
-  // |name| is full property name, including package name. e.g. "base.network".
-  // DO NOT USE IN YOUR CODE: use GetStateProperty() with component parameter.
-  LIBWEAVE_DEPRECATED virtual const base::Value* GetStateProperty(
-      const std::string& name) const = 0;
-
-  // Sets value of the single property.
-  // |name| is full property name, including package name. e.g. "base.network".
-  // DO NOT USE IN YOUR CODE: use SetStateProperty() with component parameter.
-  LIBWEAVE_DEPRECATED virtual bool SetStateProperty(const std::string& name,
-                                                    const base::Value& value,
-                                                    ErrorPtr* error) = 0;
-
-  // Returns aggregated state properties across all registered packages.
-  // DO NOT USE IN YOUR CODE: use GetComponents() instead.
-  LIBWEAVE_DEPRECATED virtual const base::DictionaryValue& GetState() const = 0;
 };
 
 }  // namespace weave
diff --git a/src/access_api_handler.cc b/src/access_api_handler.cc
index 7c39b20..dcfae45 100644
--- a/src/access_api_handler.cc
+++ b/src/access_api_handler.cc
@@ -7,23 +7,24 @@
 #include <base/bind.h>
 #include <weave/device.h>
 
-#include "src/access_black_list_manager.h"
+#include "src/access_revocation_manager.h"
 #include "src/commands/schema_constants.h"
 #include "src/data_encoding.h"
 #include "src/json_error_codes.h"
+#include "src/utils.h"
 
 namespace weave {
 
 namespace {
 
 const char kComponent[] = "accessControl";
-const char kTrait[] = "_accessControlBlackList";
-const char kStateSize[] = "_accessControlBlackList.size";
-const char kStateCapacity[] = "_accessControlBlackList.capacity";
+const char kTrait[] = "_accessRevocationList";
+const char kStateCapacity[] = "_accessRevocationList.capacity";
 const char kUserId[] = "userId";
 const char kApplicationId[] = "applicationId";
-const char kExpirationTimeout[] = "expirationTimeoutSec";
-const char kBlackList[] = "blackList";
+const char kExpirationTime[] = "expirationTime";
+const char kRevocationTimestamp[] = "revocationTimestamp";
+const char kRevocationList[] = "revocationListEntries";
 
 bool GetIds(const base::DictionaryValue& parameters,
             std::vector<uint8_t>* user_id_decoded,
@@ -51,12 +52,12 @@
 }  // namespace
 
 AccessApiHandler::AccessApiHandler(Device* device,
-                                   AccessBlackListManager* manager)
+                                   AccessRevocationManager* manager)
     : device_{device}, manager_{manager} {
   device_->AddTraitDefinitionsFromJson(R"({
-    "_accessControlBlackList": {
+    "_accessRevocationList": {
       "commands": {
-        "block": {
+        "revoke": {
           "minimalRole": "owner",
           "parameters": {
             "userId": {
@@ -65,19 +66,11 @@
             "applicationId": {
               "type": "string"
             },
-            "expirationTimeoutSec": {
+            "revocationTimestamp": {
               "type": "integer"
-            }
-          }
-        },
-        "unblock": {
-          "minimalRole": "owner",
-          "parameters": {
-            "userId": {
-              "type": "string"
             },
-            "applicationId": {
-              "type": "string"
+            "expirationTime": {
+              "type": "integer"
             }
           }
         },
@@ -85,7 +78,7 @@
           "minimalRole": "owner",
           "parameters": {},
           "results": {
-            "blackList": {
+            "revocationEntriesList": {
               "type": "array",
               "items": {
                 "type": "object",
@@ -95,6 +88,12 @@
                   },
                   "applicationId": {
                     "type": "string"
+                  },
+                  "revocationTimestamp": {
+                    "type": "integer"
+                  },
+                  "expirationTime": {
+                    "type": "integer"
                   }
                 },
                 "additionalProperties": false
@@ -104,10 +103,6 @@
         }
       },
       "state": {
-        "size": {
-          "type": "integer",
-          "isRequired": true
-        },
         "capacity": {
           "type": "integer",
           "isRequired": true
@@ -119,13 +114,10 @@
   UpdateState();
 
   device_->AddCommandHandler(
-      kComponent, "_accessControlBlackList.block",
+      kComponent, "_accessRevocationList.revoke",
       base::Bind(&AccessApiHandler::Block, weak_ptr_factory_.GetWeakPtr()));
   device_->AddCommandHandler(
-      kComponent, "_accessControlBlackList.unblock",
-      base::Bind(&AccessApiHandler::Unblock, weak_ptr_factory_.GetWeakPtr()));
-  device_->AddCommandHandler(
-      kComponent, "_accessControlBlackList.list",
+      kComponent, "_accessRevocationList.list",
       base::Bind(&AccessApiHandler::List, weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -147,38 +139,27 @@
     return;
   }
 
-  int timeout_sec = 0;
-  parameters.GetInteger(kExpirationTimeout, &timeout_sec);
-
-  base::Time expiration =
-      base::Time::Now() + base::TimeDelta::FromSeconds(timeout_sec);
-
-  manager_->Block(user_id, app_id, expiration,
-                  base::Bind(&AccessApiHandler::OnCommandDone,
-                             weak_ptr_factory_.GetWeakPtr(), cmd));
-}
-
-void AccessApiHandler::Unblock(const std::weak_ptr<Command>& cmd) {
-  auto command = cmd.lock();
-  if (!command)
-    return;
-
-  CHECK(command->GetState() == Command::State::kQueued)
-      << EnumToString(command->GetState());
-  command->SetProgress(base::DictionaryValue{}, nullptr);
-
-  const auto& parameters = command->GetParameters();
-  std::vector<uint8_t> user_id;
-  std::vector<uint8_t> app_id;
-  ErrorPtr error;
-  if (!GetIds(parameters, &user_id, &app_id, &error)) {
+  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_->Unblock(user_id, app_id,
-                    base::Bind(&AccessApiHandler::OnCommandDone,
-                               weak_ptr_factory_.GetWeakPtr(), cmd));
+  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(AccessRevocationManager::Entry{user_id, app_id,
+                                                 FromJ2000Time(revocation_j2k),
+                                                 FromJ2000Time(expiration_j2k)},
+                  base::Bind(&AccessApiHandler::OnCommandDone,
+                             weak_ptr_factory_.GetWeakPtr(), cmd));
 }
 
 void AccessApiHandler::List(const std::weak_ptr<Command>& cmd) {
@@ -199,7 +180,7 @@
   }
 
   base::DictionaryValue result;
-  result.Set(kBlackList, entries.release());
+  result.Set(kRevocationList, entries.release());
 
   command->Complete(result, nullptr);
 }
@@ -219,7 +200,6 @@
 
 void AccessApiHandler::UpdateState() {
   base::DictionaryValue state;
-  state.SetInteger(kStateSize, manager_->GetSize());
   state.SetInteger(kStateCapacity, manager_->GetCapacity());
   device_->SetStateProperties(kComponent, state, nullptr);
 }
diff --git a/src/access_api_handler.h b/src/access_api_handler.h
index 821ce02..16eaa6f 100644
--- a/src/access_api_handler.h
+++ b/src/access_api_handler.h
@@ -12,31 +12,29 @@
 
 namespace weave {
 
-class AccessBlackListManager;
+class AccessRevocationManager;
 class Command;
 class Device;
 
-// Handles commands for 'accessControlBlackList' trait.
+// Handles commands for '_accessRevocationList' trait.
 // Objects of the class subscribe for notification from CommandManager and
 // execute incoming commands.
 // Handled commands:
-//  accessControlBlackList.block
-//  accessControlBlackList.unblock
-//  accessControlBlackList.list
+//  _accessRevocationList.revoke
+//  _accessRevocationList.list
 class AccessApiHandler final {
  public:
-  AccessApiHandler(Device* device, AccessBlackListManager* manager);
+  AccessApiHandler(Device* device, AccessRevocationManager* manager);
 
  private:
   void Block(const std::weak_ptr<Command>& command);
-  void Unblock(const std::weak_ptr<Command>& command);
   void List(const std::weak_ptr<Command>& command);
   void UpdateState();
 
   void OnCommandDone(const std::weak_ptr<Command>& command, ErrorPtr error);
 
   Device* device_{nullptr};
-  AccessBlackListManager* manager_{nullptr};
+  AccessRevocationManager* manager_{nullptr};
 
   base::WeakPtrFactory<AccessApiHandler> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(AccessApiHandler);
diff --git a/src/access_api_handler_unittest.cc b/src/access_api_handler_unittest.cc
index 3e7f5d7..fda0748 100644
--- a/src/access_api_handler_unittest.cc
+++ b/src/access_api_handler_unittest.cc
@@ -9,9 +9,10 @@
 #include <weave/test/mock_device.h>
 #include <weave/test/unittest_utils.h>
 
+#include "src/access_revocation_manager.h"
 #include "src/component_manager_impl.h"
-#include "src/access_black_list_manager.h"
 #include "src/data_encoding.h"
+#include "src/test/mock_access_revocation_manager.h"
 
 using testing::_;
 using testing::AnyOf;
@@ -22,25 +23,6 @@
 
 namespace weave {
 
-class MockAccessBlackListManager : public AccessBlackListManager {
- public:
-  MOCK_METHOD4(Block,
-               void(const std::vector<uint8_t>&,
-                    const std::vector<uint8_t>&,
-                    const base::Time&,
-                    const DoneCallback&));
-  MOCK_METHOD3(Unblock,
-               void(const std::vector<uint8_t>&,
-                    const std::vector<uint8_t>&,
-                    const DoneCallback&));
-  MOCK_CONST_METHOD2(IsBlocked,
-                     bool(const std::vector<uint8_t>&,
-                          const std::vector<uint8_t>&));
-  MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>());
-  MOCK_CONST_METHOD0(GetSize, size_t());
-  MOCK_CONST_METHOD0(GetCapacity, size_t());
-};
-
 class AccessApiHandlerTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -62,9 +44,8 @@
         }));
 
     EXPECT_CALL(device_,
-                AddCommandHandler(_, AnyOf("_accessControlBlackList.block",
-                                           "_accessControlBlackList.unblock",
-                                           "_accessControlBlackList.list"),
+                AddCommandHandler(_, AnyOf("_accessRevocationList.revoke",
+                                           "_accessRevocationList.list"),
                                   _))
         .WillRepeatedly(
             Invoke(&component_manager_, &ComponentManager::AddCommandHandler));
@@ -90,31 +71,31 @@
 
   std::unique_ptr<base::DictionaryValue> GetState() {
     std::string path =
-        component_manager_.FindComponentWithTrait("_accessControlBlackList");
+        component_manager_.FindComponentWithTrait("_accessRevocationList");
     EXPECT_FALSE(path.empty());
     const auto* component = component_manager_.FindComponent(path, nullptr);
     EXPECT_TRUE(component);
     const base::DictionaryValue* state = nullptr;
     EXPECT_TRUE(
-        component->GetDictionary("state._accessControlBlackList", &state));
+        component->GetDictionary("state._accessRevocationList", &state));
     return std::unique_ptr<base::DictionaryValue>{state->DeepCopy()};
   }
 
   StrictMock<provider::test::FakeTaskRunner> task_runner_;
   ComponentManagerImpl component_manager_{&task_runner_};
   StrictMock<test::MockDevice> device_;
-  StrictMock<MockAccessBlackListManager> access_manager_;
+  StrictMock<test::MockAccessRevocationManager> access_manager_;
   std::unique_ptr<AccessApiHandler> handler_;
 };
 
 TEST_F(AccessApiHandlerTest, Initialization) {
   const base::DictionaryValue* trait = nullptr;
   ASSERT_TRUE(component_manager_.GetTraits().GetDictionary(
-      "_accessControlBlackList", &trait));
+      "_accessRevocationList", &trait));
 
   auto expected = R"({
     "commands": {
-      "block": {
+      "revoke": {
         "minimalRole": "owner",
         "parameters": {
           "userId": {
@@ -123,19 +104,11 @@
           "applicationId": {
             "type": "string"
           },
-          "expirationTimeoutSec": {
+          "revocationTimestamp": {
             "type": "integer"
-          }
-        }
-      },
-      "unblock": {
-        "minimalRole": "owner",
-        "parameters": {
-          "userId": {
-            "type": "string"
           },
-          "applicationId": {
-            "type": "string"
+          "expirationTime": {
+            "type": "integer"
           }
         }
       },
@@ -143,7 +116,7 @@
         "minimalRole": "owner",
         "parameters": {},
         "results": {
-          "blackList": {
+          "revocationEntriesList": {
             "type": "array",
             "items": {
               "type": "object",
@@ -153,6 +126,12 @@
                 },
                 "applicationId": {
                   "type": "string"
+                },
+                "revocationTimestamp": {
+                  "type": "integer"
+                },
+                "expirationTime": {
+                  "type": "integer"
                 }
               },
               "additionalProperties": false
@@ -162,10 +141,6 @@
       }
     },
     "state": {
-      "size": {
-        "type": "integer",
-        "isRequired": true
-      },
       "capacity": {
         "type": "integer",
         "isRequired": true
@@ -175,70 +150,56 @@
   EXPECT_JSON_EQ(expected, *trait);
 
   expected = R"({
-    "capacity": 10,
-    "size": 0
+    "capacity": 10
   })";
   EXPECT_JSON_EQ(expected, *GetState());
 }
 
-TEST_F(AccessApiHandlerTest, Block) {
-  EXPECT_CALL(access_manager_, Block(std::vector<uint8_t>{1, 2, 3},
-                                     std::vector<uint8_t>{3, 4, 5}, _, _))
-      .WillOnce(WithArgs<3>(
+TEST_F(AccessApiHandlerTest, Revoke) {
+  EXPECT_CALL(
+      access_manager_,
+      Block(AccessRevocationManager::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));
 
   AddCommand(R"({
-    'name' : '_accessControlBlackList.block',
+    'name' : '_accessRevocationList.revoke',
     'component': 'accessControl',
     'parameters': {
       'userId': 'AQID',
       'applicationId': 'AwQF',
-      'expirationTimeoutSec': 1234
+      'expirationTime': 7890,
+      'revocationTimestamp': 1234
     }
   })");
 
   auto expected = R"({
-    "capacity": 10,
-    "size": 1
-  })";
-  EXPECT_JSON_EQ(expected, *GetState());
-}
-
-TEST_F(AccessApiHandlerTest, Unblock) {
-  EXPECT_CALL(access_manager_, Unblock(std::vector<uint8_t>{1, 2, 3},
-                                       std::vector<uint8_t>{3, 4, 5}, _))
-      .WillOnce(WithArgs<2>(
-          Invoke([](const DoneCallback& callback) { callback.Run(nullptr); })));
-  EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4));
-
-  AddCommand(R"({
-    'name' : '_accessControlBlackList.unblock',
-    'component': 'accessControl',
-    'parameters': {
-      'userId': 'AQID',
-      'applicationId': 'AwQF',
-      'expirationTimeoutSec': 1234
-    }
-  })");
-
-  auto expected = R"({
-    "capacity": 10,
-    "size": 4
+    "capacity": 10
   })";
   EXPECT_JSON_EQ(expected, *GetState());
 }
 
 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)},
+  std::vector<AccessRevocationManager::Entry> entries{
+      {{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));
 
   auto expected = R"({
-    "blackList": [ {
+    "revocationListEntries": [ {
       "applicationId": "FRYX",
       "userId": "CwwN"
     }, {
@@ -248,7 +209,7 @@
   })";
 
   const auto& results = AddCommand(R"({
-    'name' : '_accessControlBlackList.list',
+    'name' : '_accessRevocationList.list',
     'component': 'accessControl',
     'parameters': {
     }
diff --git a/src/access_black_list_manager.h b/src/access_black_list_manager.h
deleted file mode 100644
index b56226a..0000000
--- a/src/access_black_list_manager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_
-#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_
-
-#include <vector>
-
-#include <base/time/time.h>
-
-namespace weave {
-
-class AccessBlackListManager {
- public:
-  struct Entry {
-    // 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.
-    // user_id is not empty, app_id is not empty: block if both match.
-    std::vector<uint8_t> user_id;
-    std::vector<uint8_t> app_id;
-
-    // Time after which to discard the rule.
-    base::Time expiration;
-  };
-  virtual ~AccessBlackListManager() = default;
-
-  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 Unblock(const std::vector<uint8_t>& user_id,
-                       const std::vector<uint8_t>& app_id,
-                       const DoneCallback& callback) = 0;
-  virtual bool IsBlocked(const std::vector<uint8_t>& user_id,
-                         const std::vector<uint8_t>& app_id) const = 0;
-  virtual std::vector<Entry> GetEntries() const = 0;
-  virtual size_t GetSize() const = 0;
-  virtual size_t GetCapacity() const = 0;
-};
-
-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;
-}
-
-inline bool operator!=(const AccessBlackListManager::Entry& l,
-                       const AccessBlackListManager::Entry& r) {
-  return !(l == r);
-}
-
-}  // namespace weave
-
-#endif  // LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_
diff --git a/src/access_black_list_manager_impl.cc b/src/access_black_list_manager_impl.cc
deleted file mode 100644
index 992a680..0000000
--- a/src/access_black_list_manager_impl.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2016 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/access_black_list_manager_impl.h"
-
-#include <base/json/json_reader.h>
-#include <base/json/json_writer.h>
-#include <base/values.h>
-
-#include "src/commands/schema_constants.h"
-#include "src/data_encoding.h"
-
-namespace weave {
-
-namespace {
-const char kConfigFileName[] = "black_list";
-
-const char kUser[] = "user";
-const char kApp[] = "app";
-const char kExpiration[] = "expiration";
-}
-
-AccessBlackListManagerImpl::AccessBlackListManagerImpl(
-    provider::ConfigStore* store,
-    size_t capacity,
-    base::Clock* clock)
-    : capacity_{capacity}, clock_{clock}, store_{store} {
-  Load();
-}
-
-void AccessBlackListManagerImpl::Load() {
-  if (!store_)
-    return;
-  if (auto list = base::ListValue::From(
-          base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
-    for (const auto& e : *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->GetInteger(kExpiration, &expiration)) {
-        base::Time expiration_time = base::Time::FromTimeT(expiration);
-        if (expiration_time > clock_->Now())
-          entries_[key] = expiration_time;
-      }
-    }
-    if (entries_.size() < list->GetSize()) {
-      // Save some storage space by saving without expired entries.
-      Save({});
-    }
-  }
-}
-
-void AccessBlackListManagerImpl::Save(const DoneCallback& callback) {
-  if (!store_) {
-    if (!callback.is_null())
-      callback.Run(nullptr);
-    return;
-  }
-
-  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());
-    list.Append(std::move(entry));
-  }
-
-  std::string json;
-  base::JSONWriter::Write(list, &json);
-  store_->SaveSettings(kConfigFileName, json, callback);
-}
-
-void AccessBlackListManagerImpl::RemoveExpired() {
-  for (auto i = begin(entries_); i != end(entries_);) {
-    if (i->second <= clock_->Now())
-      i = entries_.erase(i);
-    else
-      ++i;
-  }
-}
-
-void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id,
-                                       const std::vector<uint8_t>& app_id,
-                                       const base::Time& expiration,
-                                       const DoneCallback& callback) {
-  // Iterating is OK as Save below is more expensive.
-  RemoveExpired();
-  if (expiration <= clock_->Now()) {
-    if (!callback.is_null()) {
-      ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, "aleady_expired",
-                   "Entry already expired");
-      callback.Run(std::move(error));
-    }
-    return;
-  }
-  if (entries_.size() >= capacity_) {
-    if (!callback.is_null()) {
-      ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, "blacklist_is_full",
-                   "Unable to store more entries");
-      callback.Run(std::move(error));
-    }
-    return;
-  }
-  auto& value = entries_[std::make_pair(user_id, app_id)];
-  value = std::max(value, expiration);
-  Save(callback);
-}
-
-void AccessBlackListManagerImpl::Unblock(const std::vector<uint8_t>& user_id,
-                                         const std::vector<uint8_t>& app_id,
-                                         const DoneCallback& callback) {
-  if (!entries_.erase(std::make_pair(user_id, app_id))) {
-    if (!callback.is_null()) {
-      ErrorPtr error;
-      Error::AddTo(&error, FROM_HERE, "entry_not_found", "Unknown entry");
-      callback.Run(std::move(error));
-    }
-    return;
-  }
-  // Iterating is OK as Save below is more expensive.
-  RemoveExpired();
-  Save(callback);
-}
-
-bool AccessBlackListManagerImpl::IsBlocked(
-    const std::vector<uint8_t>& user_id,
-    const std::vector<uint8_t>& app_id) const {
-  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())
-        return true;
-    }
-  }
-  return false;
-}
-
-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;
-}
-
-size_t AccessBlackListManagerImpl::GetSize() const {
-  return entries_.size();
-}
-
-size_t AccessBlackListManagerImpl::GetCapacity() const {
-  return capacity_;
-}
-
-}  // namespace weave
diff --git a/src/access_black_list_manager_impl.h b/src/access_black_list_manager_impl.h
deleted file mode 100644
index 1c175db..0000000
--- a/src/access_black_list_manager_impl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
-#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
-
-#include <map>
-#include <utility>
-
-#include <base/time/default_clock.h>
-#include <base/time/time.h>
-#include <weave/error.h>
-#include <weave/provider/config_store.h>
-
-#include "src/access_black_list_manager.h"
-
-namespace weave {
-
-class AccessBlackListManagerImpl : public AccessBlackListManager {
- public:
-  explicit AccessBlackListManagerImpl(provider::ConfigStore* store,
-                                      size_t capacity = 1024,
-                                      base::Clock* clock = nullptr);
-
-  // AccessBlackListManager implementation.
-  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 Unblock(const std::vector<uint8_t>& user_id,
-               const std::vector<uint8_t>& app_id,
-               const DoneCallback& callback) override;
-  bool IsBlocked(const std::vector<uint8_t>& user_id,
-                 const std::vector<uint8_t>& app_id) const override;
-  std::vector<Entry> GetEntries() const override;
-  size_t GetSize() const override;
-  size_t GetCapacity() const override;
-
- private:
-  void Load();
-  void Save(const DoneCallback& callback);
-  void RemoveExpired();
-
-  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_;
-
-  DISALLOW_COPY_AND_ASSIGN(AccessBlackListManagerImpl);
-};
-
-}  // namespace weave
-
-#endif  // LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
diff --git a/src/access_black_list_manager_impl_unittest.cc b/src/access_black_list_manager_impl_unittest.cc
deleted file mode 100644
index fd9f226..0000000
--- a/src/access_black_list_manager_impl_unittest.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2016 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/access_black_list_manager_impl.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <weave/provider/test/mock_config_store.h>
-#include <weave/test/unittest_utils.h>
-
-#include "src/test/mock_clock.h"
-#include "src/bind_lambda.h"
-
-using testing::_;
-using testing::Return;
-using testing::StrictMock;
-
-namespace weave {
-
-class AccessBlackListManagerImplTest : public testing::Test {
- protected:
-  void SetUp() {
-    std::string to_load = R"([{
-      "user": "BQID",
-      "app": "BwQF",
-      "expiration": 1410000000
-    }, {
-      "user": "AQID",
-      "app": "AwQF",
-      "expiration": 1419999999
-    }])";
-
-    EXPECT_CALL(config_store_, LoadSettings("black_list"))
-        .WillOnce(Return(to_load));
-
-    EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
-        .WillOnce(testing::WithArgs<1, 2>(testing::Invoke(
-            [](const std::string& json, const DoneCallback& callback) {
-              std::string to_save = R"([{
-                "user": "AQID",
-                "app": "AwQF",
-                "expiration": 1419999999
-              }])";
-              EXPECT_JSON_EQ(to_save, *test::CreateValue(json));
-              if (!callback.is_null())
-                callback.Run(nullptr);
-            })));
-
-    EXPECT_CALL(clock_, Now())
-        .WillRepeatedly(Return(base::Time::FromTimeT(1412121212)));
-    manager_.reset(new AccessBlackListManagerImpl{&config_store_, 10, &clock_});
-  }
-  StrictMock<test::MockClock> clock_;
-  StrictMock<provider::test::MockConfigStore> config_store_{false};
-  std::unique_ptr<AccessBlackListManagerImpl> manager_;
-};
-
-TEST_F(AccessBlackListManagerImplTest, Init) {
-  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),
-            }}),
-            manager_->GetEntries());
-}
-
-TEST_F(AccessBlackListManagerImplTest, Block) {
-  EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
-      .WillOnce(testing::WithArgs<1, 2>(testing::Invoke(
-          [](const std::string& json, const DoneCallback& callback) {
-            std::string to_save = R"([{
-                "user": "AQID",
-                "app": "AwQF",
-                "expiration": 1419999999
-              }, {
-                "app": "CAgI",
-                "user": "BwcH",
-                "expiration": 1419990000
-              }])";
-            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), {});
-}
-
-TEST_F(AccessBlackListManagerImplTest, BlockExpired) {
-  manager_->Block({}, {}, base::Time::FromTimeT(1400000000),
-                  base::Bind([](ErrorPtr error) {
-                    EXPECT_TRUE(error->HasError("aleady_expired"));
-                  }));
-}
-
-TEST_F(AccessBlackListManagerImplTest, BlockListIsFull) {
-  EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
-      .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke(
-          [](const std::string& json, const DoneCallback& callback) {
-            if (!callback.is_null())
-              callback.Run(nullptr);
-          })));
-  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), {});
-    EXPECT_EQ(i + 1, manager_->GetSize());
-  }
-  manager_->Block({99}, {8, 8, 8}, base::Time::FromTimeT(1419990000),
-                  base::Bind([](ErrorPtr error) {
-                    EXPECT_TRUE(error->HasError("blacklist_is_full"));
-                  }));
-}
-
-TEST_F(AccessBlackListManagerImplTest, Unblock) {
-  EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
-      .WillOnce(testing::WithArgs<1, 2>(testing::Invoke(
-          [](const std::string& json, const DoneCallback& callback) {
-            EXPECT_JSON_EQ("[]", *test::CreateValue(json));
-            if (!callback.is_null())
-              callback.Run(nullptr);
-          })));
-  manager_->Unblock({1, 2, 3}, {3, 4, 5}, {});
-}
-
-TEST_F(AccessBlackListManagerImplTest, UnblockNotFound) {
-  manager_->Unblock({5, 2, 3}, {5, 4, 5}, base::Bind([](ErrorPtr error) {
-                      EXPECT_TRUE(error->HasError("entry_not_found"));
-                    }));
-}
-
-TEST_F(AccessBlackListManagerImplTest, IsBlockedFalse) {
-  EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}));
-}
-
-class AccessBlackListManagerImplIsBlockedTest
-    : public AccessBlackListManagerImplTest,
-      public testing::WithParamInterface<
-          std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>> {
- public:
-  void SetUp() override {
-    AccessBlackListManagerImplTest::SetUp();
-    EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
-        .WillOnce(testing::WithArgs<2>(
-            testing::Invoke([](const DoneCallback& callback) {
-              if (!callback.is_null())
-                callback.Run(nullptr);
-            })));
-    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}));
-}
-
-INSTANTIATE_TEST_CASE_P(
-    Filters,
-    AccessBlackListManagerImplIsBlockedTest,
-    testing::Combine(testing::Values(std::vector<uint8_t>{},
-                                     std::vector<uint8_t>{7, 7, 7}),
-                     testing::Values(std::vector<uint8_t>{},
-                                     std::vector<uint8_t>{8, 8, 8})));
-
-}  // namespace weave
diff --git a/src/access_revocation_manager.h b/src/access_revocation_manager.h
new file mode 100644
index 0000000..6d5bf7b
--- /dev/null
+++ b/src/access_revocation_manager.h
@@ -0,0 +1,66 @@
+// Copyright 2016 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_
+#define LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_
+
+#include <vector>
+
+#include <base/time/time.h>
+
+namespace weave {
+
+class AccessRevocationManager {
+ 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.
+    // user_id is not empty, app_id is not empty: block if both match.
+    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 ~AccessRevocationManager() = default;
+
+  virtual void AddEntryAddedCallback(const base::Closure& 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,
+                         base::Time timestamp) const = 0;
+  virtual std::vector<Entry> GetEntries() const = 0;
+  virtual size_t GetSize() const = 0;
+  virtual size_t GetCapacity() const = 0;
+};
+
+inline bool operator==(const AccessRevocationManager::Entry& l,
+                       const AccessRevocationManager::Entry& r) {
+  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 AccessRevocationManager::Entry& l,
+                       const AccessRevocationManager::Entry& r) {
+  return !(l == r);
+}
+
+}  // namespace weave
+
+#endif  // LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_
diff --git a/src/access_revocation_manager_impl.cc b/src/access_revocation_manager_impl.cc
new file mode 100644
index 0000000..f039114
--- /dev/null
+++ b/src/access_revocation_manager_impl.cc
@@ -0,0 +1,171 @@
+// Copyright 2016 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/access_revocation_manager_impl.h"
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <base/values.h>
+
+#include "src/commands/schema_constants.h"
+#include "src/data_encoding.h"
+#include "src/utils.h"
+
+namespace weave {
+
+namespace {
+const char kConfigFileName[] = "black_list";
+
+const char kUser[] = "user";
+const char kApp[] = "app";
+const char kExpiration[] = "expiration";
+const char kRevocation[] = "revocation";
+}
+
+AccessRevocationManagerImpl::AccessRevocationManagerImpl(
+    provider::ConfigStore* store,
+    size_t capacity,
+    base::Clock* clock)
+    : capacity_{capacity}, clock_{clock}, store_{store} {
+  Load();
+}
+
+void AccessRevocationManagerImpl::Load() {
+  if (!store_)
+    return;
+  if (auto list = base::ListValue::From(
+          base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
+    for (const auto& value : *list) {
+      const base::DictionaryValue* entry{nullptr};
+      std::string user;
+      std::string app;
+      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)) {
+        e.revocation = FromJ2000Time(revocation);
+        e.expiration = FromJ2000Time(expiration);
+        if (e.expiration > clock_->Now())
+          entries_.insert(e);
+      }
+    }
+    if (entries_.size() < list->GetSize()) {
+      // Save some storage space by saving without expired entries.
+      Save({});
+    }
+  }
+}
+
+void AccessRevocationManagerImpl::Save(const DoneCallback& callback) {
+  if (!store_) {
+    if (!callback.is_null())
+      callback.Run(nullptr);
+    return;
+  }
+
+  base::ListValue list;
+  for (const auto& e : entries_) {
+    scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
+    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));
+  }
+
+  std::string json;
+  base::JSONWriter::Write(list, &json);
+  store_->SaveSettings(kConfigFileName, json, callback);
+}
+
+void AccessRevocationManagerImpl::RemoveExpired() {
+  for (auto i = begin(entries_); i != end(entries_);) {
+    if (i->expiration <= clock_->Now())
+      i = entries_.erase(i);
+    else
+      ++i;
+  }
+}
+
+void AccessRevocationManagerImpl::AddEntryAddedCallback(
+    const base::Closure& callback) {
+  on_entry_added_callbacks_.push_back(callback);
+}
+
+void AccessRevocationManagerImpl::Block(const Entry& entry,
+                                        const DoneCallback& callback) {
+  // Iterating is OK as Save below is more expensive.
+  RemoveExpired();
+  if (entry.expiration <= clock_->Now()) {
+    if (!callback.is_null()) {
+      ErrorPtr error;
+      Error::AddTo(&error, FROM_HERE, "aleady_expired",
+                   "Entry already expired");
+      callback.Run(std::move(error));
+    }
+    return;
+  }
+  if (entries_.size() >= capacity_) {
+    if (!callback.is_null()) {
+      ErrorPtr error;
+      Error::AddTo(&error, FROM_HERE, "blacklist_is_full",
+                   "Unable to store more entries");
+      callback.Run(std::move(error));
+    }
+    return;
+  }
+
+  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 AccessRevocationManagerImpl::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}) {
+      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;
+}
+
+std::vector<AccessRevocationManager::Entry>
+AccessRevocationManagerImpl::GetEntries() const {
+  return {begin(entries_), end(entries_)};
+}
+
+size_t AccessRevocationManagerImpl::GetSize() const {
+  return entries_.size();
+}
+
+size_t AccessRevocationManagerImpl::GetCapacity() const {
+  return capacity_;
+}
+
+}  // namespace weave
diff --git a/src/access_revocation_manager_impl.h b/src/access_revocation_manager_impl.h
new file mode 100644
index 0000000..a911128
--- /dev/null
+++ b/src/access_revocation_manager_impl.h
@@ -0,0 +1,64 @@
+// Copyright 2016 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_
+#define LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_
+
+#include <set>
+#include <utility>
+
+#include <base/time/default_clock.h>
+#include <base/time/time.h>
+#include <weave/error.h>
+#include <weave/provider/config_store.h>
+
+#include "src/access_revocation_manager.h"
+
+namespace weave {
+
+class AccessRevocationManagerImpl : public AccessRevocationManager {
+ public:
+  explicit AccessRevocationManagerImpl(provider::ConfigStore* store,
+                                       size_t capacity = 1024,
+                                       base::Clock* clock = nullptr);
+
+  // AccessRevocationManager implementation.
+  void AddEntryAddedCallback(const base::Closure& 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,
+                 base::Time timestamp) const override;
+  std::vector<Entry> GetEntries() const override;
+  size_t GetSize() const override;
+  size_t GetCapacity() const override;
+
+ private:
+  void Load();
+  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::set<Entry, EntryIdsLess> entries_;
+  std::vector<base::Closure> on_entry_added_callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(AccessRevocationManagerImpl);
+};
+
+}  // namespace weave
+
+#endif  // LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_
diff --git a/src/access_revocation_manager_impl_unittest.cc b/src/access_revocation_manager_impl_unittest.cc
new file mode 100644
index 0000000..b0b774b
--- /dev/null
+++ b/src/access_revocation_manager_impl_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright 2016 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/access_revocation_manager_impl.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <weave/provider/test/mock_config_store.h>
+#include <weave/test/unittest_utils.h>
+
+#include "src/test/mock_clock.h"
+#include "src/bind_lambda.h"
+
+using testing::_;
+using testing::Return;
+using testing::StrictMock;
+
+namespace weave {
+
+class AccessRevocationManagerImplTest : public testing::Test {
+ protected:
+  void SetUp() {
+    std::string to_load = R"([{
+      "user": "BQID",
+      "app": "BwQF",
+      "expiration": 463315200,
+      "revocation": 463314200
+    }, {
+      "user": "AQID",
+      "app": "AwQF",
+      "expiration": 473315199,
+      "revocation": 473313199
+    }])";
+
+    EXPECT_CALL(config_store_, LoadSettings("black_list"))
+        .WillOnce(Return(to_load));
+
+    EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
+        .WillOnce(testing::WithArgs<1, 2>(testing::Invoke(
+            [](const std::string& json, const DoneCallback& callback) {
+              std::string to_save = R"([{
+                "user": "AQID",
+                "app": "AwQF",
+                "expiration": 473315199,
+                "revocation": 473313199
+              }])";
+              EXPECT_JSON_EQ(to_save, *test::CreateValue(json));
+              if (!callback.is_null())
+                callback.Run(nullptr);
+            })));
+
+    EXPECT_CALL(clock_, Now())
+        .WillRepeatedly(Return(base::Time::FromTimeT(1412121212)));
+    manager_.reset(
+        new AccessRevocationManagerImpl{&config_store_, 10, &clock_});
+  }
+  StrictMock<test::MockClock> clock_;
+  StrictMock<provider::test::MockConfigStore> config_store_{false};
+  std::unique_ptr<AccessRevocationManagerImpl> manager_;
+};
+
+TEST_F(AccessRevocationManagerImplTest, Init) {
+  EXPECT_EQ(1u, manager_->GetSize());
+  EXPECT_EQ(10u, manager_->GetCapacity());
+  EXPECT_EQ((std::vector<AccessRevocationManagerImpl::Entry>{{
+                {1, 2, 3},
+                {3, 4, 5},
+                base::Time::FromTimeT(1419997999),
+                base::Time::FromTimeT(1419999999),
+            }}),
+            manager_->GetEntries());
+}
+
+TEST_F(AccessRevocationManagerImplTest, Block) {
+  bool callback_called = false;
+  manager_->AddEntryAddedCallback(
+      base::Bind([&callback_called]() { callback_called = true; }));
+  EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
+      .WillOnce(testing::WithArgs<1, 2>(testing::Invoke(
+          [](const std::string& json, const DoneCallback& callback) {
+            std::string to_save = R"([{
+                "user": "AQID",
+                "app": "AwQF",
+                "expiration": 473315199,
+                "revocation": 473313199
+              }, {
+                "app": "CAgI",
+                "user": "BwcH",
+                "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(1419980000),
+                   base::Time::FromTimeT(1419990000)},
+                  {});
+  EXPECT_TRUE(callback_called);
+}
+
+TEST_F(AccessRevocationManagerImplTest, BlockExpired) {
+  manager_->Block({{},
+                   {},
+                   base::Time::FromTimeT(1300000000),
+                   base::Time::FromTimeT(1400000000)},
+                  base::Bind([](ErrorPtr error) {
+                    EXPECT_TRUE(error->HasError("aleady_expired"));
+                  }));
+}
+
+TEST_F(AccessRevocationManagerImplTest, BlockListIsFull) {
+  EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
+      .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke(
+          [](const std::string& json, const DoneCallback& callback) {
+            if (!callback.is_null())
+              callback.Run(nullptr);
+          })));
+  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(1419970000),
+         base::Time::FromTimeT(1419990000)},
+        {});
+    EXPECT_EQ(i + 1, manager_->GetSize());
+  }
+  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(AccessRevocationManagerImplTest, IsBlockedIdsNotMacth) {
+  EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {}));
+}
+
+TEST_F(AccessRevocationManagerImplTest, 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 AccessRevocationManagerImplIsBlockedTest
+    : public AccessRevocationManagerImplTest,
+      public testing::WithParamInterface<
+          std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>> {
+ public:
+  void SetUp() override {
+    AccessRevocationManagerImplTest::SetUp();
+    EXPECT_CALL(config_store_, SaveSettings("black_list", _, _))
+        .WillOnce(testing::WithArgs<2>(
+            testing::Invoke([](const DoneCallback& callback) {
+              if (!callback.is_null())
+                callback.Run(nullptr);
+            })));
+    manager_->Block({std::get<0>(GetParam()),
+                     std::get<1>(GetParam()),
+                     {},
+                     base::Time::FromTimeT(1419990000)},
+                    {});
+  }
+};
+
+TEST_P(AccessRevocationManagerImplIsBlockedTest, IsBlocked) {
+  EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {}));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    Filters,
+    AccessRevocationManagerImplIsBlockedTest,
+    testing::Combine(testing::Values(std::vector<uint8_t>{},
+                                     std::vector<uint8_t>{7, 7, 7}),
+                     testing::Values(std::vector<uint8_t>{},
+                                     std::vector<uint8_t>{8, 8, 8})));
+
+}  // namespace weave
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc
index 0de67fe..e0bd4fc 100644
--- a/src/commands/cloud_command_proxy_unittest.cc
+++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -14,7 +14,7 @@
 #include <weave/test/unittest_utils.h>
 
 #include "src/commands/command_instance.h"
-#include "src/mock_component_manager.h"
+#include "src/test/mock_component_manager.h"
 
 using testing::_;
 using testing::AnyNumber;
@@ -141,7 +141,7 @@
   ComponentManager::UpdateID current_state_update_id_{0};
   base::CallbackList<void(ComponentManager::UpdateID)> callbacks_;
   testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_;
-  testing::StrictMock<MockComponentManager> component_manager_;
+  testing::StrictMock<test::MockComponentManager> component_manager_;
   testing::StrictMock<provider::test::FakeTaskRunner> task_runner_;
   std::queue<base::Closure> task_queue_;
   std::unique_ptr<CommandInstance> command_instance_;
diff --git a/src/commands/schema_constants.cc b/src/commands/schema_constants.cc
index 732cf44..37bee4c 100644
--- a/src/commands/schema_constants.cc
+++ b/src/commands/schema_constants.cc
@@ -32,12 +32,6 @@
 const char kCommand_State[] = "state";
 const char kCommand_Error[] = "error";
 
-const char kCommand_Role[] = "minimalRole";
-const char kCommand_Role_Manager[] = "manager";
-const char kCommand_Role_Owner[] = "owner";
-const char kCommand_Role_User[] = "user";
-const char kCommand_Role_Viewer[] = "viewer";
-
 }  // namespace attributes
 }  // namespace commands
 
diff --git a/src/commands/schema_constants.h b/src/commands/schema_constants.h
index 360079a..623fec3 100644
--- a/src/commands/schema_constants.h
+++ b/src/commands/schema_constants.h
@@ -34,12 +34,6 @@
 extern const char kCommand_State[];
 extern const char kCommand_Error[];
 
-extern const char kCommand_Role[];
-extern const char kCommand_Role_Manager[];
-extern const char kCommand_Role_Owner[];
-extern const char kCommand_Role_User[];
-extern const char kCommand_Role_Viewer[];
-
 }  // namespace attributes
 }  // namespace commands
 
diff --git a/src/component_manager.h b/src/component_manager.h
index 832b274..cea5569 100644
--- a/src/component_manager.h
+++ b/src/component_manager.h
@@ -209,17 +209,6 @@
   virtual std::string FindComponentWithTrait(
       const std::string& trait) const = 0;
 
-  // Support for legacy APIs. Setting command and state definitions.
-  // This translates into modifying a trait definition.
-  virtual bool AddLegacyCommandDefinitions(const base::DictionaryValue& dict,
-                                           ErrorPtr* error) = 0;
-  virtual bool AddLegacyStateDefinitions(const base::DictionaryValue& dict,
-                                         ErrorPtr* error) = 0;
-  // Returns device state for legacy APIs.
-  virtual const base::DictionaryValue& GetLegacyState() const = 0;
-  // Returns command definitions for legacy APIs.
-  virtual const base::DictionaryValue& GetLegacyCommandDefinitions() const = 0;
-
   DISALLOW_COPY_AND_ASSIGN(ComponentManager);
 };
 
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index dec4a48..3ea1f46 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -19,11 +19,13 @@
 // Max of 100 state update events should be enough in the queue.
 const size_t kMaxStateChangeQueueSize = 100;
 
+const char kMinimalRole[] = "minimalRole";
+
 const EnumToStringMap<UserRole>::Map kMap[] = {
-    {UserRole::kViewer, commands::attributes::kCommand_Role_Viewer},
-    {UserRole::kUser, commands::attributes::kCommand_Role_User},
-    {UserRole::kOwner, commands::attributes::kCommand_Role_Owner},
-    {UserRole::kManager, commands::attributes::kCommand_Role_Manager},
+    {UserRole::kViewer, "viewer"},
+    {UserRole::kUser, "user"},
+    {UserRole::kOwner, "owner"},
+    {UserRole::kManager, "manager"},
 };
 }  // anonymous namespace
 
@@ -356,7 +358,7 @@
   std::string value;
   // The JSON definition has been pre-validated already in LoadCommands, so
   // just using CHECKs here.
-  CHECK(command->GetString(commands::attributes::kCommand_Role, &value));
+  CHECK(command->GetString(kMinimalRole, &value));
   CHECK(StringToEnum(value, minimal_role));
   return true;
 }
@@ -504,140 +506,6 @@
   return std::string{};
 }
 
-bool ComponentManagerImpl::AddLegacyCommandDefinitions(
-    const base::DictionaryValue& dict,
-    ErrorPtr* error) {
-  bool result = true;
-  bool modified = false;
-  for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
-    const base::DictionaryValue* command_dict = nullptr;
-    if (!it.value().GetAsDictionary(&command_dict)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
-                         "Package '%s' must be an object", it.key().c_str());
-      result = false;
-      continue;
-    }
-    AddTraitToLegacyComponent(it.key());
-    for (base::DictionaryValue::Iterator it_def(*command_dict);
-         !it_def.IsAtEnd(); it_def.Advance()) {
-      std::string key = base::StringPrintf("%s.commands.%s", it.key().c_str(),
-                                           it_def.key().c_str());
-      if (traits_.GetDictionary(key, nullptr)) {
-        Error::AddToPrintf(error, FROM_HERE,
-                           errors::commands::kInvalidPropValue,
-                           "Redefining command '%s.%s'", it.key().c_str(),
-                           it_def.key().c_str());
-        result = false;
-        continue;
-      }
-      traits_.Set(key, it_def.value().DeepCopy());
-      modified = true;
-    }
-  }
-
-  if (modified) {
-    for (const auto& cb : on_trait_changed_)
-      cb.Run();
-  }
-  return result;
-}
-
-bool ComponentManagerImpl::AddLegacyStateDefinitions(
-    const base::DictionaryValue& dict,
-    ErrorPtr* error) {
-  bool result = true;
-  bool modified = false;
-  for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
-    const base::DictionaryValue* state_dict = nullptr;
-    if (!it.value().GetAsDictionary(&state_dict)) {
-      Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch,
-                         "Package '%s' must be an object", it.key().c_str());
-      result = false;
-      continue;
-    }
-    AddTraitToLegacyComponent(it.key());
-    for (base::DictionaryValue::Iterator it_def(*state_dict); !it_def.IsAtEnd();
-         it_def.Advance()) {
-      std::string key = base::StringPrintf("%s.state.%s", it.key().c_str(),
-                                           it_def.key().c_str());
-      if (traits_.GetDictionary(key, nullptr)) {
-        Error::AddToPrintf(error, FROM_HERE,
-                           errors::commands::kInvalidPropValue,
-                           "Redefining state property '%s.%s'",
-                           it.key().c_str(), it_def.key().c_str());
-        result = false;
-        continue;
-      }
-      traits_.Set(key, it_def.value().DeepCopy());
-      modified = true;
-    }
-  }
-
-  if (modified) {
-    for (const auto& cb : on_trait_changed_)
-      cb.Run();
-  }
-  return result;
-}
-
-const base::DictionaryValue& ComponentManagerImpl::GetLegacyState() const {
-  legacy_state_.Clear();
-  // Build state from components.
-  for (base::DictionaryValue::Iterator it(components_); !it.IsAtEnd();
-       it.Advance()) {
-    const base::DictionaryValue* component_dict = nullptr;
-    const base::DictionaryValue* component_state = nullptr;
-    if (it.value().GetAsDictionary(&component_dict) &&
-        component_dict->GetDictionary("state", &component_state)) {
-      legacy_state_.MergeDictionary(component_state);
-    }
-  }
-  return legacy_state_;
-}
-
-const base::DictionaryValue& ComponentManagerImpl::GetLegacyCommandDefinitions()
-    const {
-  legacy_command_defs_.Clear();
-  // Build commandDefs from traits.
-  for (base::DictionaryValue::Iterator it(traits_); !it.IsAtEnd();
-       it.Advance()) {
-    const base::DictionaryValue* trait_dict = nullptr;
-    const base::DictionaryValue* trait_commands = nullptr;
-    if (it.value().GetAsDictionary(&trait_dict) &&
-        trait_dict->GetDictionary("commands", &trait_commands)) {
-      base::DictionaryValue dict;
-      dict.Set(it.key(), trait_commands->DeepCopy());
-      legacy_command_defs_.MergeDictionary(&dict);
-    }
-  }
-  return legacy_command_defs_;
-}
-
-void ComponentManagerImpl::AddTraitToLegacyComponent(const std::string& trait) {
-  // First check if we already have a component supporting this trait.
-  if (!FindComponentWithTrait(trait).empty())
-    return;
-
-  // If not, add this trait to the first component available.
-  base::DictionaryValue* component = nullptr;
-  base::DictionaryValue::Iterator it(components_);
-  if (it.IsAtEnd()) {
-    // No components at all. Create a new one with dummy name.
-    // This normally wouldn't happen since libweave creates its own component
-    // at startup.
-    component = new base::DictionaryValue;
-    components_.Set("__weave__", component);
-  } else {
-    CHECK(components_.GetDictionary(it.key(), &component));
-  }
-  base::ListValue* traits = nullptr;
-  if (!component->GetList("traits", &traits)) {
-    traits = new base::ListValue;
-    component->Set("traits", traits);
-  }
-  traits->AppendString(trait);
-}
-
 base::DictionaryValue* ComponentManagerImpl::FindComponentGraftNode(
     const std::string& path,
     ErrorPtr* error) {
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h
index f3c5451..5b8201a 100644
--- a/src/component_manager_impl.h
+++ b/src/component_manager_impl.h
@@ -174,17 +174,6 @@
   // tree. No sub-components are searched.
   std::string FindComponentWithTrait(const std::string& trait) const override;
 
-  // Support for legacy APIs. Setting command and state definitions.
-  // This translates into modifying a trait definition.
-  bool AddLegacyCommandDefinitions(const base::DictionaryValue& dict,
-                                   ErrorPtr* error) override;
-  bool AddLegacyStateDefinitions(const base::DictionaryValue& dict,
-                                 ErrorPtr* error) override;
-  // Returns device state for legacy APIs.
-  const base::DictionaryValue& GetLegacyState() const override;
-  // Returns command definitions for legacy APIs.
-  const base::DictionaryValue& GetLegacyCommandDefinitions() const override;
-
  private:
   // A helper method to find a JSON element of component at |path| to add new
   // sub-components to.
@@ -193,12 +182,6 @@
   base::DictionaryValue* FindMutableComponent(const std::string& path,
                                               ErrorPtr* error);
 
-  // Legacy API support: Helper function to support state/command definitions.
-  // Adds the given trait to at least one component.
-  // Searches for available components and if none of them already supports this
-  // trait, it adds it to the first available component.
-  void AddTraitToLegacyComponent(const std::string& trait);
-
   // Helper method to find a sub-component given a root node and a relative path
   // from the root to the target component.
   static const base::DictionaryValue* FindComponentAt(
@@ -225,10 +208,6 @@
   uint32_t next_command_id_{0};
   std::map<std::string, std::unique_ptr<StateChangeQueue>> state_change_queues_;
 
-  // Legacy API support.
-  mutable base::DictionaryValue legacy_state_;         // Device state.
-  mutable base::DictionaryValue legacy_command_defs_;  // Command definitions.
-
   DISALLOW_COPY_AND_ASSIGN(ComponentManagerImpl);
 };
 
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc
index 97dc00d..291ace8 100644
--- a/src/component_manager_unittest.cc
+++ b/src/component_manager_unittest.cc
@@ -12,7 +12,7 @@
 
 #include "src/bind_lambda.h"
 #include "src/commands/schema_constants.h"
-#include "src/mock_component_manager.h"
+#include "src/test/mock_component_manager.h"
 #include "src/test/mock_clock.h"
 
 namespace weave {
@@ -1262,226 +1262,9 @@
   EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
 }
 
-TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
-  const char kCommandDefs1[] = R"({
-    "package1": {
-      "command1": {
-        "minimalRole": "user",
-        "parameters": {"height": {"type": "integer"}}
-      },
-      "command2": {
-        "minimalRole": "owner",
-        "parameters": {}
-      }
-    },
-    "package2": {
-      "command1": { "minimalRole": "user" },
-      "command2": { "minimalRole": "owner" }
-    }
-  })";
-  auto json = CreateDictionaryValue(kCommandDefs1);
-  EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
-  const char kExpected1[] = R"({
-    "package1": {
-      "commands": {
-        "command1": {
-          "minimalRole": "user",
-          "parameters": {"height": {"type": "integer"}}
-        },
-        "command2": {
-          "minimalRole": "owner",
-          "parameters": {}
-        }
-      }
-    },
-    "package2": {
-      "commands": {
-        "command1": { "minimalRole": "user" },
-        "command2": { "minimalRole": "owner" }
-      }
-    }
-  })";
-  EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
-  const char kExpectedComponents1[] = R"({
-    "__weave__": { "traits": ["package1", "package2"] }
-  })";
-  EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
-
-  const char kCommandDefs2[] = R"({
-    "package2": {
-      "command3": { "minimalRole": "user" }
-    },
-    "package3": {
-      "command1": { "minimalRole": "user" },
-      "command2": { "minimalRole": "owner" }
-    }
-  })";
-  json = CreateDictionaryValue(kCommandDefs2);
-  EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
-  const char kExpected2[] = R"({
-    "package1": {
-      "commands": {
-        "command1": {
-          "minimalRole": "user",
-          "parameters": {"height": {"type": "integer"}}
-        },
-        "command2": {
-          "minimalRole": "owner",
-          "parameters": {}
-        }
-      }
-    },
-    "package2": {
-      "commands": {
-        "command1": { "minimalRole": "user" },
-        "command2": { "minimalRole": "owner" },
-        "command3": { "minimalRole": "user" }
-      }
-    },
-    "package3": {
-      "commands": {
-        "command1": { "minimalRole": "user" },
-        "command2": { "minimalRole": "owner" }
-      }
-    }
-  })";
-  EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
-  const char kExpectedComponents2[] = R"({
-    "__weave__": { "traits": ["package1", "package2", "package3"] }
-  })";
-  EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
-
-  // Redefining existing commands.
-  EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
-
-  const char kStateDefs1[] = R"({
-    "package1": {
-      "prop1": { "type": "string" },
-      "prop2": { "type": "string" }
-    },
-    "package4": {
-      "prop3": { "type": "string" },
-      "prop4": { "type": "string" }
-    }
-  })";
-  json = CreateDictionaryValue(kStateDefs1);
-  EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
-  const char kExpectedComponents3[] = R"({
-    "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
-  })";
-  EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
-
-  const char kExpected3[] = R"({
-    "package1": {
-      "commands": {
-        "command1": {
-          "minimalRole": "user",
-          "parameters": {"height": {"type": "integer"}}
-        },
-        "command2": {
-          "minimalRole": "owner",
-          "parameters": {}
-        }
-      },
-      "state": {
-        "prop1": { "type": "string" },
-        "prop2": { "type": "string" }
-      }
-    },
-    "package2": {
-      "commands": {
-        "command1": { "minimalRole": "user" },
-        "command2": { "minimalRole": "owner" },
-        "command3": { "minimalRole": "user" }
-      }
-    },
-    "package3": {
-      "commands": {
-        "command1": { "minimalRole": "user" },
-        "command2": { "minimalRole": "owner" }
-      }
-    },
-    "package4": {
-      "state": {
-        "prop3": { "type": "string" },
-        "prop4": { "type": "string" }
-      }
-    }
-  })";
-  EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
-  const char kExpectedComponents4[] = R"({
-    "__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
-  })";
-  EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
-
-  // Redefining existing commands.
-  EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
-
-  const char kExpected4[] = R"({
-    "package1": {
-      "command1": {
-        "minimalRole": "user",
-        "parameters": {"height": {"type": "integer"}}
-      },
-      "command2": {
-        "minimalRole": "owner",
-        "parameters": {}
-      }
-    },
-    "package2": {
-      "command1": { "minimalRole": "user" },
-      "command2": { "minimalRole": "owner" },
-      "command3": { "minimalRole": "user" }
-    },
-    "package3": {
-      "command1": { "minimalRole": "user" },
-      "command2": { "minimalRole": "owner" }
-    }
-  })";
-  EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
-}
-
-TEST_F(ComponentManagerTest, GetLegacyState) {
-  const char kTraits[] = R"({
-    "trait1": {
-      "state": {
-        "prop1": { "type": "string" },
-        "prop2": { "type": "string" }
-      }
-    },
-    "trait2": {
-      "state": {
-        "prop3": { "type": "string" },
-        "prop4": { "type": "string" }
-      }
-    }
-  })";
-  auto traits = CreateDictionaryValue(kTraits);
-  ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
-  ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
-  ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
-
-  ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
-      "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
-  ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
-      "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
-
-  const char kExpected[] = R"({
-    "trait1": {
-      "prop1": "foo",
-      "prop2": "bar"
-    },
-    "trait2": {
-      "prop3": "baz",
-      "prop4": "quux"
-    }
-  })";
-  EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
-}
-
 TEST_F(ComponentManagerTest, TestMockComponentManager) {
   // Check that all the virtual methods are mocked out.
-  MockComponentManager mock;
+  test::MockComponentManager mock;
 }
 
 }  // namespace weave
diff --git a/src/device_manager.cc b/src/device_manager.cc
index 4c0d3ee..b6b91a9 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -9,7 +9,7 @@
 #include <base/bind.h>
 
 #include "src/access_api_handler.h"
-#include "src/access_black_list_manager_impl.h"
+#include "src/access_revocation_manager_impl.h"
 #include "src/base_api_handler.h"
 #include "src/commands/schema_constants.h"
 #include "src/component_manager_impl.h"
@@ -33,8 +33,13 @@
     : config_{new Config{config_store}},
       component_manager_{new ComponentManagerImpl{task_runner}} {
   if (http_server) {
-    auth_manager_.reset(new privet::AuthManager(
-        config_.get(), http_server->GetHttpsCertificateFingerprint()));
+    access_revocation_manager_.reset(
+        new AccessRevocationManagerImpl{config_store});
+    auth_manager_.reset(
+        new privet::AuthManager(config_.get(), access_revocation_manager_.get(),
+                                http_server->GetHttpsCertificateFingerprint()));
+    access_api_handler_.reset(
+        new AccessApiHandler{this, access_revocation_manager_.get()});
   }
 
   device_info_.reset(new DeviceRegistrationInfo(
@@ -42,10 +47,6 @@
       network, auth_manager_.get()));
   base_api_handler_.reset(new BaseApiHandler{device_info_.get(), this});
 
-  black_list_manager_.reset(new AccessBlackListManagerImpl{config_store});
-  access_api_handler_.reset(
-      new AccessApiHandler{this, black_list_manager_.get()});
-
   device_info_->Start();
 
   if (http_server) {
@@ -156,16 +157,6 @@
   component_manager_->AddCommandHandler(component, command_name, callback);
 }
 
-void DeviceManager::AddCommandDefinitionsFromJson(const std::string& json) {
-  auto dict = LoadJsonDict(json, nullptr);
-  CHECK(dict);
-  AddCommandDefinitions(*dict);
-}
-
-void DeviceManager::AddCommandDefinitions(const base::DictionaryValue& dict) {
-  CHECK(component_manager_->AddLegacyCommandDefinitions(dict, nullptr));
-}
-
 bool DeviceManager::AddCommand(const base::DictionaryValue& command,
                                std::string* id,
                                ErrorPtr* error) {
@@ -181,87 +172,10 @@
   return component_manager_->FindCommand(id);
 }
 
-void DeviceManager::AddCommandHandler(const std::string& command_name,
-                                      const CommandHandlerCallback& callback) {
-  if (command_name.empty())
-    return component_manager_->AddCommandHandler("", "", callback);
-
-  auto trait = SplitAtFirst(command_name, ".", true).first;
-  std::string component = component_manager_->FindComponentWithTrait(trait);
-  CHECK(!component.empty());
-  component_manager_->AddCommandHandler(component, command_name, callback);
-}
-
 void DeviceManager::AddStateChangedCallback(const base::Closure& callback) {
   component_manager_->AddStateChangedCallback(callback);
 }
 
-void DeviceManager::AddStateDefinitionsFromJson(const std::string& json) {
-  auto dict = LoadJsonDict(json, nullptr);
-  CHECK(dict);
-  AddStateDefinitions(*dict);
-}
-
-void DeviceManager::AddStateDefinitions(const base::DictionaryValue& dict) {
-  CHECK(component_manager_->AddLegacyStateDefinitions(dict, nullptr));
-}
-
-bool DeviceManager::SetStatePropertiesFromJson(const std::string& json,
-                                               ErrorPtr* error) {
-  auto dict = LoadJsonDict(json, error);
-  return dict && SetStateProperties(*dict, error);
-}
-
-bool DeviceManager::SetStateProperties(const base::DictionaryValue& dict,
-                                       ErrorPtr* error) {
-  for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
-    std::string component =
-        component_manager_->FindComponentWithTrait(it.key());
-    if (component.empty()) {
-      Error::AddToPrintf(error, FROM_HERE, "unrouted_state",
-                         "Unable to set property value because there is no "
-                         "component supporting "
-                         "trait '%s'",
-                         it.key().c_str());
-      return false;
-    }
-    base::DictionaryValue trait_state;
-    trait_state.Set(it.key(), it.value().DeepCopy());
-    if (!component_manager_->SetStateProperties(component, trait_state, error))
-      return false;
-  }
-  return true;
-}
-
-const base::Value* DeviceManager::GetStateProperty(
-    const std::string& name) const {
-  auto trait = SplitAtFirst(name, ".", true).first;
-  std::string component = component_manager_->FindComponentWithTrait(trait);
-  if (component.empty())
-    return nullptr;
-  return component_manager_->GetStateProperty(component, name, nullptr);
-}
-
-bool DeviceManager::SetStateProperty(const std::string& name,
-                                     const base::Value& value,
-                                     ErrorPtr* error) {
-  auto trait = SplitAtFirst(name, ".", true).first;
-  std::string component = component_manager_->FindComponentWithTrait(trait);
-  if (component.empty()) {
-    Error::AddToPrintf(
-        error, FROM_HERE, "unrouted_state",
-        "Unable set value of state property '%s' because there is no component "
-        "supporting trait '%s'",
-        name.c_str(), trait.c_str());
-    return false;
-  }
-  return component_manager_->SetStateProperty(component, name, value, error);
-}
-
-const base::DictionaryValue& DeviceManager::GetState() const {
-  return component_manager_->GetLegacyState();
-}
-
 void DeviceManager::Register(const RegistrationData& registration_data,
                              const DoneCallback& callback) {
   device_info_->RegisterDevice(registration_data, callback);
diff --git a/src/device_manager.h b/src/device_manager.h
index f0ad464..545f293 100644
--- a/src/device_manager.h
+++ b/src/device_manager.h
@@ -11,7 +11,7 @@
 namespace weave {
 
 class AccessApiHandler;
-class AccessBlackListManager;
+class AccessRevocationManager;
 class BaseApiHandler;
 class Config;
 class ComponentManager;
@@ -78,22 +78,6 @@
       const PairingBeginCallback& begin_callback,
       const PairingEndCallback& end_callback) override;
 
-  void AddCommandDefinitionsFromJson(const std::string& json) override;
-  void AddCommandDefinitions(const base::DictionaryValue& dict) override;
-  void AddCommandHandler(const std::string& command_name,
-                         const CommandHandlerCallback& callback) override;
-  void AddStateDefinitionsFromJson(const std::string& json) override;
-  void AddStateDefinitions(const base::DictionaryValue& dict) override;
-  bool SetStatePropertiesFromJson(const std::string& json,
-                                  ErrorPtr* error) override;
-  bool SetStateProperties(const base::DictionaryValue& dict,
-                          ErrorPtr* error) override;
-  const base::Value* GetStateProperty(const std::string& name) const override;
-  bool SetStateProperty(const std::string& name,
-                        const base::Value& value,
-                        ErrorPtr* error) override;
-  const base::DictionaryValue& GetState() const override;
-
   Config* GetConfig();
 
  private:
@@ -109,7 +93,7 @@
   std::unique_ptr<ComponentManager> component_manager_;
   std::unique_ptr<DeviceRegistrationInfo> device_info_;
   std::unique_ptr<BaseApiHandler> base_api_handler_;
-  std::unique_ptr<AccessBlackListManager> black_list_manager_;
+  std::unique_ptr<AccessRevocationManager> access_revocation_manager_;
   std::unique_ptr<AccessApiHandler> access_api_handler_;
   std::unique_ptr<privet::Manager> privet_;
 
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 027ad5a..d905a45 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -6,15 +6,18 @@
 
 #include <algorithm>
 
+#include <base/bind.h>
 #include <base/guid.h>
 #include <base/rand_util.h>
 #include <base/strings/string_number_conversions.h>
 
+#include "src/access_revocation_manager.h"
 #include "src/config.h"
 #include "src/data_encoding.h"
 #include "src/privet/constants.h"
 #include "src/privet/openssl_utils.h"
 #include "src/string_utils.h"
+#include "src/utils.h"
 
 extern "C" {
 #include "third_party/libuweave/src/macaroon.h"
@@ -26,20 +29,11 @@
 
 namespace {
 
-const time_t kJ2000ToTimeT = 946684800;
 const size_t kMaxMacaroonSize = 1024;
 const size_t kMaxPendingClaims = 10;
 const char kInvalidTokenError[] = "invalid_token";
 const int kSessionIdTtlMinutes = 1;
 
-uint32_t ToJ2000Time(const base::Time& time) {
-  return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT;
-}
-
-base::Time FromJ2000Time(uint32_t time) {
-  return base::Time::FromTimeT(time + kJ2000ToTimeT);
-}
-
 template <class T>
 void AppendToArray(T value, std::vector<uint8_t>* array) {
   auto begin = reinterpret_cast<const uint8_t*>(&value);
@@ -275,10 +269,16 @@
 }  // namespace
 
 AuthManager::AuthManager(Config* config,
+                         AccessRevocationManager* black_list,
                          const std::vector<uint8_t>& certificate_fingerprint)
     : config_{config},
+      black_list_{black_list},
       certificate_fingerprint_{certificate_fingerprint},
       access_secret_{CreateSecret()} {
+  if (black_list_) {
+    black_list_->AddEntryAddedCallback(base::Bind(
+        &AuthManager::ResetAccessSecret, weak_ptr_factory_.GetWeakPtr()));
+  }
   if (config_) {
     SetAuthSecret(config_->GetSettings().secret,
                   config_->GetSettings().root_client_token_owner);
@@ -290,8 +290,9 @@
 AuthManager::AuthManager(const std::vector<uint8_t>& auth_secret,
                          const std::vector<uint8_t>& certificate_fingerprint,
                          const std::vector<uint8_t>& access_secret,
-                         base::Clock* clock)
-    : AuthManager(nullptr, certificate_fingerprint) {
+                         base::Clock* clock,
+                         AccessRevocationManager* black_list)
+    : AuthManager(nullptr, black_list, certificate_fingerprint) {
   access_secret_ = access_secret.size() == kSha256OutputSize ? access_secret
                                                              : CreateSecret();
   SetAuthSecret(auth_secret, RootClientTokenOwner::kNone);
@@ -401,7 +402,8 @@
   };
 
   pending_claims_.push_back(std::make_pair(
-      std::unique_ptr<AuthManager>{new AuthManager{nullptr, {}}}, owner));
+      std::unique_ptr<AuthManager>{new AuthManager{nullptr, nullptr, {}}},
+      owner));
   if (pending_claims_.size() > kMaxPendingClaims)
     pending_claims_.pop_front();
   return pending_claims_.back().first->GetRootClientAuthToken(owner);
@@ -511,6 +513,28 @@
                         "Invalid session id");
   }
 
+  if (black_list_) {
+    std::vector<uint8_t> user_id;
+    std::vector<uint8_t> app_id;
+    for (size_t i = 0; i < result.num_delegatees; ++i) {
+      if (result.delegatees[i].type == kUwMacaroonDelegateeTypeUser) {
+        user_id.assign(result.delegatees[i].id,
+                       result.delegatees[i].id + result.delegatees[i].id_len);
+      } else if (result.delegatees[i].type == kUwMacaroonDelegateeTypeApp) {
+        app_id.assign(result.delegatees[i].id,
+                      result.delegatees[i].id + result.delegatees[i].id_len);
+      } else {
+        // Do not block by other types of delegatees.
+        continue;
+      }
+      if (black_list_->IsBlocked(
+              user_id, app_id, FromJ2000Time(result.delegatees[i].timestamp))) {
+        return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
+                            "Auth token is revoked");
+      }
+    }
+  }
+
   CHECK_GE(FromJ2000Time(result.expiration_time), now);
 
   if (!access_token)
@@ -547,6 +571,12 @@
          ssid_time <= Now();
 }
 
+void AuthManager::ResetAccessSecret() {
+  auto new_secret = CreateSecret();
+  CHECK(new_secret != access_secret_);
+  access_secret_.swap(new_secret);
+}
+
 std::vector<uint8_t> AuthManager::DelegateToUser(
     const std::vector<uint8_t>& token,
     base::TimeDelta ttl,
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index f0a5761..d8174f6 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include <base/gtest_prod_util.h>
+#include <base/memory/weak_ptr.h>
 #include <base/time/default_clock.h>
 #include <base/time/time.h>
 #include <weave/error.h>
@@ -18,6 +19,7 @@
 
 namespace weave {
 
+class AccessRevocationManager;
 class Config;
 enum class RootClientTokenOwner;
 
@@ -26,13 +28,15 @@
 class AuthManager {
  public:
   AuthManager(Config* config,
+              AccessRevocationManager* black_list,
               const std::vector<uint8_t>& certificate_fingerprint);
 
   // Constructor for tests.
   AuthManager(const std::vector<uint8_t>& auth_secret,
               const std::vector<uint8_t>& certificate_fingerprint,
               const std::vector<uint8_t>& access_secret,
-              base::Clock* clock = nullptr);
+              base::Clock* clock = nullptr,
+              AccessRevocationManager* black_list = nullptr);
   ~AuthManager();
 
   std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info,
@@ -74,12 +78,15 @@
  private:
   friend class AuthManagerTest;
 
+  void ResetAccessSecret();
+
   // Test helpers. Device does not need to implement delegation.
   std::vector<uint8_t> DelegateToUser(const std::vector<uint8_t>& token,
                                       base::TimeDelta ttl,
                                       const UserInfo& user_info) const;
 
   Config* config_{nullptr};  // Can be nullptr for tests.
+  AccessRevocationManager* black_list_{nullptr};
   base::DefaultClock default_clock_;
   base::Clock* clock_{&default_clock_};
   mutable uint32_t session_counter_{0};
@@ -91,6 +98,7 @@
   std::deque<std::pair<std::unique_ptr<AuthManager>, RootClientTokenOwner>>
       pending_claims_;
 
+  base::WeakPtrFactory<AuthManager> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(AuthManager);
 };
 
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 3e5aeab..648027d 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -11,13 +11,28 @@
 #include "src/config.h"
 #include "src/data_encoding.h"
 #include "src/privet/mock_delegates.h"
+#include "src/test/mock_access_revocation_manager.h"
 #include "src/test/mock_clock.h"
 
+using testing::_;
 using testing::Return;
+using testing::SaveArg;
+using testing::StrictMock;
 
 namespace weave {
 namespace privet {
 
+class MockAccessRevocationManager : public test::MockAccessRevocationManager {
+ public:
+  MockAccessRevocationManager() {
+    EXPECT_CALL(*this, AddEntryAddedCallback(_))
+        .WillOnce(SaveArg<0>(&changed_callback_));
+    EXPECT_CALL(*this, IsBlocked(_, _, _)).WillRepeatedly(Return(false));
+  }
+
+  base::Closure changed_callback_;
+};
+
 class AuthManagerTest : public testing::Test {
  public:
   void SetUp() override {
@@ -46,7 +61,8 @@
       60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85};
 
   test::MockClock clock_;
-  AuthManager auth_{kSecret1, kFingerprint, kSecret2, &clock_};
+  StrictMock<MockAccessRevocationManager> black_list_;
+  AuthManager auth_{kSecret1, kFingerprint, kSecret2, &clock_, &black_list_};
 };
 
 TEST_F(AuthManagerTest, RandomSecret) {
@@ -152,8 +168,9 @@
 TEST_F(AuthManagerTest, CreateTokenDifferentInstance) {
   EXPECT_NE(auth_.CreateAccessToken(
                 UserInfo{AuthScope::kUser, TestUserId{"123"}}, {}),
-            AuthManager({}, {}).CreateAccessToken(
-                UserInfo{AuthScope::kUser, TestUserId{"123"}}, {}));
+            AuthManager({}, nullptr, {})
+                .CreateAccessToken(
+                    UserInfo{AuthScope::kUser, TestUserId{"123"}}, {}));
 }
 
 TEST_F(AuthManagerTest, ParseAccessToken) {
@@ -189,6 +206,22 @@
   }
 }
 
+TEST_F(AuthManagerTest, AccessTokenAfterReset) {
+  UserInfo user_info;
+  auto token1 = auth_.CreateAccessToken(
+      UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {});
+  EXPECT_TRUE(auth_.ParseAccessToken(token1, &user_info, nullptr));
+
+  black_list_.changed_callback_.Run();
+
+  auto token2 = auth_.CreateAccessToken(
+      UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {});
+
+  EXPECT_NE(token1, token2);
+  EXPECT_FALSE(auth_.ParseAccessToken(token1, &user_info, nullptr));
+  EXPECT_TRUE(auth_.ParseAccessToken(token2, &user_info, nullptr));
+}
+
 TEST_F(AuthManagerTest, GetRootClientAuthToken) {
   EXPECT_EQ("WCCDQxkgAUYIGhudoQBCDABQX3fPR5zsPnrs9aOSvS7/eQ==",
             Base64Encode(
@@ -319,6 +352,21 @@
   EXPECT_TRUE(error->HasError("invalidAuthCode"));
 }
 
+TEST_F(AuthManagerTest, CreateAccessTokenFromAuthRevoked) {
+  TestUserId user{"234"};
+  EXPECT_CALL(black_list_, IsBlocked(user.user, _, clock_.Now()))
+      .WillOnce(Return(true));
+  std::vector<uint8_t> access_token;
+  auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kCloud);
+  auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(1000),
+                                 UserInfo{AuthScope::kUser, user});
+  ErrorPtr error;
+  EXPECT_FALSE(
+      auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1),
+                                      nullptr, nullptr, nullptr, &error));
+  EXPECT_TRUE(error->HasError("invalidAuthCode"));
+}
+
 class AuthManagerClaimTest : public testing::Test {
  public:
   void SetUp() override { EXPECT_EQ(auth_.GetAuthSecret().size(), 32u); }
@@ -332,7 +380,7 @@
 
  protected:
   Config config_{nullptr};
-  AuthManager auth_{&config_, {}};
+  AuthManager auth_{&config_, nullptr, {}};
 };
 
 TEST_F(AuthManagerClaimTest, WithPreviosOwner) {
diff --git a/src/privet/cloud_delegate.cc b/src/privet/cloud_delegate.cc
index 0b4400f..f565687 100644
--- a/src/privet/cloud_delegate.cc
+++ b/src/privet/cloud_delegate.cc
@@ -151,14 +151,6 @@
     return device_->GetSettings().xmpp_endpoint;
   }
 
-  const base::DictionaryValue& GetLegacyCommandDef() const override {
-    return component_manager_->GetLegacyCommandDefinitions();
-  }
-
-  const base::DictionaryValue& GetLegacyState() const override {
-    return component_manager_->GetLegacyState();
-  }
-
   const base::DictionaryValue& GetComponents() const override {
     return component_manager_->GetComponents();
   }
diff --git a/src/privet/cloud_delegate.h b/src/privet/cloud_delegate.h
index 37ed723..43b8904 100644
--- a/src/privet/cloud_delegate.h
+++ b/src/privet/cloud_delegate.h
@@ -100,12 +100,6 @@
   virtual std::string GetServiceUrl() const = 0;
   virtual std::string GetXmppEndpoint() const = 0;
 
-  // Returns dictionary with device state (for legacy APIs).
-  virtual const base::DictionaryValue& GetLegacyState() const = 0;
-
-  // Returns dictionary with commands definitions (for legacy APIs).
-  virtual const base::DictionaryValue& GetLegacyCommandDef() const = 0;
-
   // Returns dictionary with component tree.
   virtual const base::DictionaryValue& GetComponents() const = 0;
 
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h
index 108e450..f04fb37 100644
--- a/src/privet/mock_delegates.h
+++ b/src/privet/mock_delegates.h
@@ -188,8 +188,6 @@
   MOCK_CONST_METHOD0(GetOAuthUrl, std::string());
   MOCK_CONST_METHOD0(GetServiceUrl, std::string());
   MOCK_CONST_METHOD0(GetXmppEndpoint, std::string());
-  MOCK_CONST_METHOD0(GetLegacyState, const base::DictionaryValue&());
-  MOCK_CONST_METHOD0(GetLegacyCommandDef, const base::DictionaryValue&());
   MOCK_CONST_METHOD0(GetComponents, const base::DictionaryValue&());
   MOCK_CONST_METHOD2(FindComponent,
                      const base::DictionaryValue*(const std::string& path,
@@ -229,9 +227,6 @@
     EXPECT_CALL(*this, GetSetupState()).WillRepeatedly(ReturnRef(setup_state_));
     EXPECT_CALL(*this, GetCloudId()).WillRepeatedly(Return("TestCloudId"));
     test_dict_.Set("test", new base::DictionaryValue);
-    EXPECT_CALL(*this, GetLegacyState()).WillRepeatedly(ReturnRef(test_dict_));
-    EXPECT_CALL(*this, GetLegacyCommandDef())
-        .WillRepeatedly(ReturnRef(test_dict_));
     EXPECT_CALL(*this, GetTraits()).WillRepeatedly(ReturnRef(test_dict_));
     EXPECT_CALL(*this, GetComponents()).WillRepeatedly(ReturnRef(test_dict_));
     EXPECT_CALL(*this, FindComponent(_, _)).Times(0);
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc
index 05b6e0a..83d5ef3 100644
--- a/src/privet/privet_handler.cc
+++ b/src/privet/privet_handler.cc
@@ -114,8 +114,6 @@
 std::string xmpp_endpoint;
 
 const char kFingerprintKey[] = "fingerprint";
-const char kStateKey[] = "state";
-const char kCommandsKey[] = "commands";
 const char kTraitsKey[] = "traits";
 const char kComponentsKey[] = "components";
 const char kCommandsIdKey[] = "id";
@@ -421,10 +419,6 @@
                    AuthScope::kManager);
   AddSecureHandler("/privet/v3/setup/status", &PrivetHandler::HandleSetupStatus,
                    AuthScope::kManager);
-  AddSecureHandler("/privet/v3/state", &PrivetHandler::HandleState,
-                   AuthScope::kViewer);
-  AddSecureHandler("/privet/v3/commandDefs", &PrivetHandler::HandleCommandDefs,
-                   AuthScope::kViewer);
   AddSecureHandler("/privet/v3/commands/execute",
                    &PrivetHandler::HandleCommandsExecute, AuthScope::kViewer);
   AddSecureHandler("/privet/v3/commands/status",
@@ -875,16 +869,6 @@
   callback.Run(http::kOk, output);
 }
 
-void PrivetHandler::HandleState(const base::DictionaryValue& input,
-                                const UserInfo& user_info,
-                                const RequestCallback& callback) {
-  base::DictionaryValue output;
-  output.Set(kStateKey, cloud_->GetLegacyState().DeepCopy());
-  output.SetString(kFingerprintKey, std::to_string(state_fingerprint_));
-
-  callback.Run(http::kOk, output);
-}
-
 void PrivetHandler::HandleTraits(const base::DictionaryValue& input,
                                  const UserInfo& user_info,
                                  const RequestCallback& callback) {
@@ -931,18 +915,6 @@
   callback.Run(http::kOk, output);
 }
 
-void PrivetHandler::HandleCommandDefs(const base::DictionaryValue& input,
-                                      const UserInfo& user_info,
-                                      const RequestCallback& callback) {
-  base::DictionaryValue output;
-  output.Set(kCommandsKey, cloud_->GetLegacyCommandDef().DeepCopy());
-  // Use traits fingerprint since right now we treat traits and command defs
-  // as being equivalent.
-  output.SetString(kFingerprintKey, std::to_string(traits_fingerprint_));
-
-  callback.Run(http::kOk, output);
-}
-
 void PrivetHandler::HandleCommandsExecute(const base::DictionaryValue& input,
                                           const UserInfo& user_info,
                                           const RequestCallback& callback) {
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc
index 3c72242..ecf4797 100644
--- a/src/privet/privet_handler_unittest.cc
+++ b/src/privet/privet_handler_unittest.cc
@@ -674,7 +674,6 @@
       "client_secret": "test_client_secret",
       "oauth_url": "https://oauths/",
       "service_url": "https://service/",
-      "status": "success",
       "xmpp_endpoint": "xmpp:678",
       "ticketId": "testTicket",
       "user": "testUser"
@@ -728,26 +727,6 @@
                                R"({"clientToken": "DerivedClientAuthToken"})"));
 }
 
-TEST_F(PrivetHandlerTestWithAuth, State) {
-  EXPECT_JSON_EQ(R"({"state": {"test": {}}, "fingerprint": "1"})",
-                 HandleRequest("/privet/v3/state", "{}"));
-
-  cloud_.NotifyOnStateChanged();
-
-  EXPECT_JSON_EQ(R"({"state": {"test": {}}, "fingerprint": "2"})",
-                 HandleRequest("/privet/v3/state", "{}"));
-}
-
-TEST_F(PrivetHandlerTestWithAuth, CommandsDefs) {
-  EXPECT_JSON_EQ(R"({"commands": {"test":{}}, "fingerprint": "1"})",
-                 HandleRequest("/privet/v3/commandDefs", "{}"));
-
-  cloud_.NotifyOnTraitDefsChanged();
-
-  EXPECT_JSON_EQ(R"({"commands": {"test":{}}, "fingerprint": "2"})",
-                 HandleRequest("/privet/v3/commandDefs", "{}"));
-}
-
 TEST_F(PrivetHandlerTestWithAuth, Traits) {
   EXPECT_JSON_EQ(R"({"traits": {"test": {}}, "fingerprint": "1"})",
                  HandleRequest("/privet/v3/traits", "{}"));
diff --git a/src/test/mock_access_revocation_manager.h b/src/test/mock_access_revocation_manager.h
new file mode 100644
index 0000000..29e3721
--- /dev/null
+++ b/src/test/mock_access_revocation_manager.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_
+#define LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_
+
+#include <gmock/gmock.h>
+
+#include "src/access_revocation_manager.h"
+
+namespace weave {
+
+namespace test {
+
+class MockAccessRevocationManager : public AccessRevocationManager {
+ public:
+  MOCK_METHOD1(AddEntryAddedCallback, void(const base::Closure&));
+  MOCK_METHOD2(Block, void(const Entry&, const DoneCallback&));
+  MOCK_CONST_METHOD3(IsBlocked,
+                     bool(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());
+};
+
+}  // namespace test
+
+}  // namespace weave
+
+#endif  // LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_
diff --git a/src/mock_component_manager.h b/src/test/mock_component_manager.h
similarity index 92%
rename from src/mock_component_manager.h
rename to src/test/mock_component_manager.h
index addd6f0..2c1d695 100644
--- a/src/mock_component_manager.h
+++ b/src/test/mock_component_manager.h
@@ -11,6 +11,8 @@
 
 namespace weave {
 
+namespace test {
+
 class MockComponentManager : public ComponentManager {
  public:
   ~MockComponentManager() override {}
@@ -95,13 +97,6 @@
                    const base::Callback<void(UpdateID)>& callback));
   MOCK_CONST_METHOD1(FindComponentWithTrait,
                      std::string(const std::string& trait));
-  MOCK_METHOD2(AddLegacyCommandDefinitions,
-               bool(const base::DictionaryValue& dict, ErrorPtr* error));
-  MOCK_METHOD2(AddLegacyStateDefinitions,
-               bool(const base::DictionaryValue& dict, ErrorPtr* error));
-  MOCK_CONST_METHOD0(GetLegacyState, const base::DictionaryValue&());
-  MOCK_CONST_METHOD0(GetLegacyCommandDefinitions,
-                     const base::DictionaryValue&());
 
  private:
   void AddCommand(std::unique_ptr<CommandInstance> command_instance) override {
@@ -125,6 +120,8 @@
   }
 };
 
+}  // namespace test
+
 }  // namespace weave
 
 #endif  // LIBWEAVE_SRC_COMPONENT_MANAGER_H_
diff --git a/src/utils.cc b/src/utils.cc
index 28828d7..5d1c3e3 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -26,6 +26,8 @@
 const char kErrorCodeKey[] = "code";
 const char kErrorMessageKey[] = "message";
 
+const time_t kJ2000ToTimeT = 946684800;
+
 }  // anonymous namespace
 
 namespace errors {
@@ -69,4 +71,12 @@
   return output;
 }
 
+uint32_t ToJ2000Time(const base::Time& time) {
+  return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT;
+}
+
+base::Time FromJ2000Time(uint32_t time) {
+  return base::Time::FromTimeT(time + kJ2000ToTimeT);
+}
+
 }  // namespace weave
diff --git a/src/utils.h b/src/utils.h
index 99d7bda..40c76b4 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include <base/time/time.h>
 #include <base/values.h>
 #include <weave/error.h>
 
@@ -31,6 +32,9 @@
 
 std::unique_ptr<base::DictionaryValue> ErrorInfoToJson(const Error& error);
 
+uint32_t ToJ2000Time(const base::Time& time);
+base::Time FromJ2000Time(uint32_t time);
+
 }  // namespace weave
 
 #endif  // LIBWEAVE_SRC_UTILS_H_
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc
index 452ac78..3b28001 100644
--- a/src/weave_unittest.cc
+++ b/src/weave_unittest.cc
@@ -294,7 +294,6 @@
                   "/privet/v3/accessControl/confirm",
                   "/privet/v3/auth",
                   "/privet/v3/checkForUpdates",
-                  "/privet/v3/commandDefs",
                   "/privet/v3/commands/cancel",
                   "/privet/v3/commands/execute",
                   "/privet/v3/commands/list",
@@ -305,7 +304,6 @@
                   "/privet/v3/pairing/start",
                   "/privet/v3/setup/start",
                   "/privet/v3/setup/status",
-                  "/privet/v3/state",
                   "/privet/v3/traits",
                   // clang-format on
               }),
diff --git a/third_party/chromium/base/third_party/dmg_fp/dtoa.cc b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc
index 502c16c..c06219c 100644
--- a/third_party/chromium/base/third_party/dmg_fp/dtoa.cc
+++ b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc
@@ -59,6 +59,7 @@
  *	4. Because of 3., we don't need a large table of powers of 10
  *		for ten-to-e (just some small tables, e.g. of 10^k
  *		for 0 <= k <= 22).
+ *	5. Fixed -Wchar-subscripts warning in "if (!hexdig['0'])"
  */
 
 /*
@@ -1572,7 +1573,7 @@
 	CONST char *s;
 	int c1, havedig, udx0, xshift;
 
-	if (!hexdig['0'])
+	if (!hexdig[0 + '0'])
 		hexdig_init();
 	x[0] = x[1] = 0;
 	havedig = xshift = 0;
diff --git a/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc
index bfa358d..67c9f57 100644
--- a/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc
+++ b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc
@@ -27,10 +27,10 @@
 namespace dmg_fp {
 
  char *
-g_fmt(register char *b, double x)
+g_fmt(char *b, double x)
 {
-	register int i, k;
-	register char *s;
+	int i, k;
+	char *s;
 	int decpt, j, sign;
 	char *b0, *s0, *se;