libbrillo: Add DevicePolicy::IsEnterpriseManaged()

Use management_mode to determine whether device is managed and only
fall back to DM token in case the former doesn't exist.  This is
required to properly support Chromad, but should have no effect on
other types of management (including local ownership).

BUG=chromium:722799
TEST=unit tests added

Change-Id: Ifa8bc6bf616dc23eb767c97934fe4cdb77a3451a
Reviewed-on: https://chromium-review.googlesource.com/518045
Commit-Ready: Thiemo Nagel <tnagel@chromium.org>
Tested-by: Thiemo Nagel <tnagel@chromium.org>
Reviewed-by: Dan Erat <derat@chromium.org>
diff --git a/libbrillo.gypi b/libbrillo.gypi
index a9a0b1e..4f01a74 100644
--- a/libbrillo.gypi
+++ b/libbrillo.gypi
@@ -437,12 +437,14 @@
           'type': 'executable',
           'dependencies': [
             '../common-mk/external_dependencies.gyp:install_attributes-proto',
+            '../common-mk/external_dependencies.gyp:policy-protos',
             'libinstallattributes-<(libbase_ver)',
             'libpolicy-<(libbase_ver)',
           ],
           'includes': ['../common-mk/common_test.gypi'],
           'sources': [
             'install_attributes/mock_install_attributes_reader.cc',
+            'policy/tests/device_policy_impl_unittest.cc',
             'policy/tests/libpolicy_unittest.cc',
           ]
         },
diff --git a/policy/device_policy.h b/policy/device_policy.h
index fbebeaa..134b669 100644
--- a/policy/device_policy.h
+++ b/policy/device_policy.h
@@ -155,6 +155,12 @@
   virtual bool GetAutoLaunchedKioskAppId(
       std::string* app_id_out) const = 0;
 
+  // Returns true if the policy data indicates that the device is enterprise
+  // managed. Note that this potentially could be faked by an exploit, therefore
+  // InstallAttributesReader must be used when tamper-proof evidence of the
+  // management state is required.
+  virtual bool IsEnterpriseManaged() const = 0;
+
  private:
   // Verifies that the policy files are owned by root and exist.
   virtual bool VerifyPolicyFiles() = 0;
diff --git a/policy/device_policy_impl.cc b/policy/device_policy_impl.cc
index 9c98b52..1c5a6fe 100644
--- a/policy/device_policy_impl.cc
+++ b/policy/device_policy_impl.cc
@@ -17,6 +17,8 @@
 #include "bindings/chrome_device_policy.pb.h"
 #include "bindings/device_management_backend.pb.h"
 
+namespace em = enterprise_management;
+
 namespace policy {
 
 namespace {
@@ -157,8 +159,7 @@
     std::vector<std::string>* user_whitelist) const {
   if (!device_policy_.has_user_whitelist())
     return false;
-  const enterprise_management::UserWhitelistProto& proto =
-      device_policy_.user_whitelist();
+  const em::UserWhitelistProto& proto = device_policy_.user_whitelist();
   user_whitelist->clear();
   for (int i = 0; i < proto.user_whitelist_size(); i++)
     user_whitelist->push_back(proto.user_whitelist(i));
@@ -213,8 +214,7 @@
   if (!device_policy_.has_device_reporting())
     return false;
 
-  const enterprise_management::DeviceReportingProto& proto =
-      device_policy_.device_reporting();
+  const em::DeviceReportingProto& proto = device_policy_.device_reporting();
   if (!proto.has_report_version_info())
     return false;
 
@@ -227,8 +227,7 @@
   if (!device_policy_.has_device_reporting())
     return false;
 
-  const enterprise_management::DeviceReportingProto& proto =
-      device_policy_.device_reporting();
+  const em::DeviceReportingProto& proto = device_policy_.device_reporting();
   if (!proto.has_report_activity_times())
     return false;
 
@@ -240,8 +239,7 @@
   if (!device_policy_.has_device_reporting())
     return false;
 
-  const enterprise_management::DeviceReportingProto& proto =
-      device_policy_.device_reporting();
+  const em::DeviceReportingProto& proto = device_policy_.device_reporting();
   if (!proto.has_report_boot_mode())
     return false;
 
@@ -263,8 +261,7 @@
   if (!device_policy_.has_release_channel())
     return false;
 
-  const enterprise_management::ReleaseChannelProto& proto =
-      device_policy_.release_channel();
+  const em::ReleaseChannelProto& proto = device_policy_.release_channel();
   if (!proto.has_release_channel())
     return false;
 
@@ -277,8 +274,7 @@
   if (!device_policy_.has_release_channel())
     return false;
 
-  const enterprise_management::ReleaseChannelProto& proto =
-      device_policy_.release_channel();
+  const em::ReleaseChannelProto& proto = device_policy_.release_channel();
   if (!proto.has_release_channel_delegated())
     return false;
 
@@ -291,7 +287,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
   if (!proto.has_update_disabled())
     return false;
@@ -305,7 +301,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
   if (!proto.has_target_version_prefix())
     return false;
@@ -319,7 +315,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
   if (!proto.has_scatter_factor_in_seconds())
     return false;
@@ -333,7 +329,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
   if (proto.allowed_connection_types_size() <= 0)
     return false;
@@ -351,7 +347,7 @@
   if (!device_policy_.has_open_network_configuration())
     return false;
 
-  const enterprise_management::DeviceOpenNetworkConfigurationProto& proto =
+  const em::DeviceOpenNetworkConfigurationProto& proto =
       device_policy_.open_network_configuration();
   if (!proto.has_open_network_configuration())
     return false;
@@ -361,11 +357,11 @@
 }
 
 bool DevicePolicyImpl::GetOwner(std::string* owner) const {
-  // The device is enterprise enrolled iff a request token exists.
-  if (policy_data_.has_request_token()) {
+  if (IsEnterpriseManaged()) {
     *owner = "";
     return true;
   }
+
   if (!policy_data_.has_username())
     return false;
   *owner = policy_data_.username();
@@ -377,7 +373,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
 
   if (!proto.has_http_downloads_enabled())
@@ -391,7 +387,7 @@
   if (!device_policy_.has_auto_update_settings())
     return false;
 
-  const enterprise_management::AutoUpdateSettingsProto& proto =
+  const em::AutoUpdateSettingsProto& proto =
       device_policy_.auto_update_settings();
 
   if (!proto.has_p2p_enabled())
@@ -406,7 +402,7 @@
   if (!device_policy_.has_allow_kiosk_app_control_chrome_version())
     return false;
 
-  const enterprise_management::AllowKioskAppControlChromeVersionProto& proto =
+  const em::AllowKioskAppControlChromeVersionProto& proto =
       device_policy_.allow_kiosk_app_control_chrome_version();
 
   if (!proto.has_allow_kiosk_app_control_chrome_version())
@@ -421,11 +417,11 @@
     std::vector<UsbDeviceId>* usb_whitelist) const {
   if (!device_policy_.has_usb_detachable_whitelist())
     return false;
-  const enterprise_management::UsbDetachableWhitelistProto& proto =
+  const em::UsbDetachableWhitelistProto& proto =
       device_policy_.usb_detachable_whitelist();
   usb_whitelist->clear();
   for (int i = 0; i < proto.id_size(); i++) {
-    const ::enterprise_management::UsbDeviceIdProto& id = proto.id(i);
+    const em::UsbDeviceIdProto& id = proto.id(i);
     UsbDeviceId dev_id;
     dev_id.vendor_id = id.has_vendor_id() ? id.vendor_id() : 0;
     dev_id.product_id = id.has_product_id() ? id.product_id() : 0;
@@ -439,7 +435,7 @@
   if (!device_policy_.has_device_local_accounts())
     return false;
 
-  const enterprise_management::DeviceLocalAccountsProto& local_accounts =
+  const em::DeviceLocalAccountsProto& local_accounts =
       device_policy_.device_local_accounts();
 
   // For auto-launched kiosk apps, the delay needs to be 0.
@@ -447,7 +443,7 @@
       local_accounts.auto_login_delay() != 0)
     return false;
 
-  for (const enterprise_management::DeviceLocalAccountInfoProto& account :
+  for (const em::DeviceLocalAccountInfoProto& account :
        local_accounts.account()) {
     // If this isn't an auto-login account, move to the next one.
     if (account.account_id() != local_accounts.auto_login_id())
@@ -456,8 +452,7 @@
     // If the auto-launched account is not a kiosk app, bail out, we aren't
     // running in auto-launched kiosk mode.
     if (account.type() !=
-            enterprise_management::DeviceLocalAccountInfoProto::
-                ACCOUNT_TYPE_KIOSK_APP) {
+        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_KIOSK_APP) {
       return false;
     }
 
@@ -469,6 +464,14 @@
   return false;
 }
 
+bool DevicePolicyImpl::IsEnterpriseManaged() const {
+  if (policy_data_.has_management_mode())
+    return policy_data_.management_mode() == em::PolicyData::ENTERPRISE_MANAGED;
+  // Fall back to checking the request token, see management_mode documentation
+  // in device_management_backend.proto.
+  return policy_data_.has_request_token();
+}
+
 bool DevicePolicyImpl::VerifyPolicyFiles() {
   // Both the policy and its signature have to exist.
   if (!base::PathExists(policy_path_) || !base::PathExists(keyfile_path_)) {
diff --git a/policy/device_policy_impl.h b/policy/device_policy_impl.h
index 1d13d74..8a702da 100644
--- a/policy/device_policy_impl.h
+++ b/policy/device_policy_impl.h
@@ -67,6 +67,12 @@
       std::vector<UsbDeviceId>* usb_whitelist) const override;
   bool GetAutoLaunchedKioskAppId(
       std::string* app_id_out) const override;
+  bool IsEnterpriseManaged() const override;
+
+  void set_policy_data_for_testing(
+      const enterprise_management::PolicyData& policy_data) {
+    policy_data_ = policy_data;
+  }
 
  protected:
   // Verifies that the policy files are owned by root and exist.
diff --git a/policy/mock_device_policy.h b/policy/mock_device_policy.h
index 23e8147..0c5f79a 100644
--- a/policy/mock_device_policy.h
+++ b/policy/mock_device_policy.h
@@ -97,6 +97,7 @@
   MOCK_CONST_METHOD1(GetUsbDetachableWhitelist,
                      bool(std::vector<DevicePolicy::UsbDeviceId>*));
   MOCK_CONST_METHOD1(GetAutoLaunchedKioskAppId, bool(std::string*));
+  MOCK_CONST_METHOD0(IsEnterpriseManaged, bool());
 
   MOCK_METHOD0(VerifyPolicyFiles, bool(void));
   MOCK_METHOD0(VerifyPolicySignature, bool(void));
diff --git a/policy/tests/device_policy_impl_unittest.cc b/policy/tests/device_policy_impl_unittest.cc
new file mode 100644
index 0000000..e443394
--- /dev/null
+++ b/policy/tests/device_policy_impl_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright 2017 The Chromium OS 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 <gtest/gtest.h>
+
+#include "policy/device_policy_impl.h"
+
+#include "bindings/chrome_device_policy.pb.h"
+
+namespace em = enterprise_management;
+
+namespace policy {
+
+// Enterprise managed.
+TEST(DevicePolicyImplTest, GetOwner_Managed) {
+  em::PolicyData policy_data;
+  policy_data.set_username("user@example.com");
+  policy_data.set_management_mode(em::PolicyData::ENTERPRISE_MANAGED);
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  std::string owner("something");
+  EXPECT_TRUE(device_policy.GetOwner(&owner));
+  EXPECT_TRUE(owner.empty());
+}
+
+// Consumer owned.
+TEST(DevicePolicyImplTest, GetOwner_Consumer) {
+  em::PolicyData policy_data;
+  policy_data.set_username("user@example.com");
+  policy_data.set_management_mode(em::PolicyData::LOCAL_OWNER);
+  policy_data.set_request_token("codepath-must-ignore-dmtoken");
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  std::string owner;
+  EXPECT_TRUE(device_policy.GetOwner(&owner));
+  EXPECT_EQ("user@example.com", owner);
+}
+
+// Consumer owned, username is missing.
+TEST(DevicePolicyImplTest, GetOwner_ConsumerMissingUsername) {
+  em::PolicyData policy_data;
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  std::string owner("something");
+  EXPECT_FALSE(device_policy.GetOwner(&owner));
+  EXPECT_EQ("something", owner);
+}
+
+// Enterprise managed, denoted by management_mode.
+TEST(DevicePolicyImplTest, IsEnterpriseManaged_ManagementModeManaged) {
+  em::PolicyData policy_data;
+  policy_data.set_management_mode(em::PolicyData::ENTERPRISE_MANAGED);
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  EXPECT_TRUE(device_policy.IsEnterpriseManaged());
+}
+
+// Enterprise managed, fallback to DM token.
+TEST(DevicePolicyImplTest, IsEnterpriseManaged_DMTokenManaged) {
+  em::PolicyData policy_data;
+  policy_data.set_request_token("abc");
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  EXPECT_TRUE(device_policy.IsEnterpriseManaged());
+}
+
+// Consumer owned, denoted by management_mode.
+TEST(DevicePolicyImplTest, IsEnterpriseManaged_ManagementModeConsumer) {
+  em::PolicyData policy_data;
+  policy_data.set_management_mode(em::PolicyData::LOCAL_OWNER);
+  policy_data.set_request_token("codepath-must-ignore-dmtoken");
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  EXPECT_FALSE(device_policy.IsEnterpriseManaged());
+}
+
+// Consumer owned, fallback to interpreting absence of DM token.
+TEST(DevicePolicyImplTest, IsEnterpriseManaged_DMTokenConsumer) {
+  em::PolicyData policy_data;
+  DevicePolicyImpl device_policy;
+  device_policy.set_policy_data_for_testing(policy_data);
+
+  EXPECT_FALSE(device_policy.IsEnterpriseManaged());
+}
+
+}  // namespace policy