Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / device_local_account_policy_service.cc
blobf93d6379d3a8130fe886385fc29459764078b8bd
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/path_service.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
24 #include "chrome/browser/chromeos/policy/device_local_account.h"
25 #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
26 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
27 #include "chrome/browser/chromeos/settings/device_settings_service.h"
28 #include "chrome/common/chrome_content_client.h"
29 #include "chromeos/chromeos_paths.h"
30 #include "chromeos/dbus/session_manager_client.h"
31 #include "chromeos/settings/cros_settings_names.h"
32 #include "chromeos/settings/cros_settings_provider.h"
33 #include "components/policy/core/browser/browser_policy_connector.h"
34 #include "components/policy/core/common/cloud/cloud_policy_client.h"
35 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
36 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
37 #include "components/policy/core/common/cloud/device_management_service.h"
38 #include "components/policy/core/common/cloud/resource_cache.h"
39 #include "components/policy/core/common/cloud/system_policy_request_context.h"
40 #include "components/policy/core/common/policy_namespace.h"
41 #include "components/policy/core/common/policy_switches.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "net/url_request/url_request_context_getter.h"
44 #include "policy/policy_constants.h"
45 #include "policy/proto/device_management_backend.pb.h"
46 #include "url/gurl.h"
48 namespace em = enterprise_management;
50 namespace policy {
52 namespace {
54 // Creates and initializes a cloud policy client. Returns nullptr if the device
55 // is not enterprise-enrolled.
56 scoped_ptr<CloudPolicyClient> CreateClient(
57 chromeos::DeviceSettingsService* device_settings_service,
58 DeviceManagementService* device_management_service,
59 scoped_refptr<net::URLRequestContextGetter> system_request_context) {
60 const em::PolicyData* policy_data = device_settings_service->policy_data();
61 if (!policy_data ||
62 GetManagementMode(*policy_data) != MANAGEMENT_MODE_ENTERPRISE_MANAGED ||
63 !device_management_service) {
64 return scoped_ptr<CloudPolicyClient>();
67 scoped_refptr<net::URLRequestContextGetter> request_context =
68 new SystemPolicyRequestContext(
69 system_request_context, GetUserAgent());
71 scoped_ptr<CloudPolicyClient> client(
72 new CloudPolicyClient(std::string(), std::string(),
73 kPolicyVerificationKeyHash,
74 USER_AFFILIATION_MANAGED,
75 device_management_service, request_context));
76 client->SetupRegistration(policy_data->request_token(),
77 policy_data->device_id());
78 return client.Pass();
81 // Get the subdirectory of the force-installed extension cache and the component
82 // policy cache used for |account_id|.
83 std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
84 return base::HexEncode(account_id.c_str(), account_id.size());
87 // Cleans up the cache directory by removing subdirectories that are not found
88 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
89 // |subdirectories_to_keep| may be running while the clean-up is in progress.
90 void DeleteOrphanedCaches(
91 const base::FilePath& cache_root_dir,
92 const std::set<std::string>& subdirectories_to_keep) {
93 base::FileEnumerator enumerator(cache_root_dir,
94 false,
95 base::FileEnumerator::DIRECTORIES);
96 for (base::FilePath path = enumerator.Next(); !path.empty();
97 path = enumerator.Next()) {
98 const std::string subdirectory(path.BaseName().MaybeAsASCII());
99 if (!ContainsKey(subdirectories_to_keep, subdirectory))
100 base::DeleteFile(path, true);
104 // Removes the subdirectory belonging to |account_id_to_delete| from the cache
105 // directory. No cache belonging to |account_id_to_delete| may be running while
106 // the removal is in progress.
107 void DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) {
108 base::FilePath cache_root_dir;
109 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
110 &cache_root_dir));
111 const base::FilePath path = cache_root_dir.Append(
112 GetCacheSubdirectoryForAccountID(account_id_to_delete));
113 if (base::DirectoryExists(path))
114 base::DeleteFile(path, true);
117 } // namespace
119 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
120 const DeviceLocalAccount& account,
121 const base::FilePath& component_policy_cache_path,
122 scoped_ptr<DeviceLocalAccountPolicyStore> store,
123 scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
124 const base::Closure& policy_update_callback,
125 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
126 AffiliatedInvalidationServiceProvider* invalidation_service_provider)
127 : invalidation_service_provider_(invalidation_service_provider),
128 account_id_(account.account_id),
129 user_id_(account.user_id),
130 component_policy_cache_path_(component_policy_cache_path),
131 store_(store.Pass()),
132 extension_tracker_(account, store_.get(), &schema_registry_),
133 external_data_manager_(external_data_manager),
134 core_(dm_protocol::kChromePublicAccountPolicyType,
135 store_->account_id(),
136 store_.get(),
137 task_runner),
138 policy_update_callback_(policy_update_callback) {
139 base::FilePath cache_root_dir;
140 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
141 &cache_root_dir));
142 extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
143 store_.get(),
144 cache_root_dir.Append(
145 GetCacheSubdirectoryForAccountID(account.account_id)));
146 store_->AddObserver(this);
148 // Unblock the |schema_registry_| so that the |component_policy_service_|
149 // starts using it.
150 schema_registry_.RegisterComponent(
151 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()),
152 g_browser_process->browser_policy_connector()->GetChromeSchema());
153 schema_registry_.SetReady(POLICY_DOMAIN_CHROME);
154 schema_registry_.SetReady(POLICY_DOMAIN_EXTENSIONS);
157 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
158 store_->RemoveObserver(this);
159 external_data_manager_->SetPolicyStore(nullptr);
160 external_data_manager_->Disconnect();
163 void DeviceLocalAccountPolicyBroker::Initialize() {
164 store_->Load();
167 bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const {
168 return invalidator_;
171 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
172 chromeos::DeviceSettingsService* device_settings_service,
173 DeviceManagementService* device_management_service,
174 scoped_refptr<net::URLRequestContextGetter> request_context) {
175 if (core_.client())
176 return;
178 scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
179 device_management_service,
180 request_context));
181 if (!client)
182 return;
184 CreateComponentCloudPolicyService(request_context, client.get());
185 core_.Connect(client.Pass());
186 external_data_manager_->Connect(request_context);
187 core_.StartRefreshScheduler();
188 UpdateRefreshDelay();
189 invalidator_.reset(new AffiliatedCloudPolicyInvalidator(
190 em::DeviceRegisterRequest::DEVICE,
191 &core_,
192 invalidation_service_provider_));
195 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
196 if (core_.refresh_scheduler()) {
197 const base::Value* policy_value =
198 store_->policy_map().GetValue(key::kPolicyRefreshRate);
199 int delay = 0;
200 if (policy_value && policy_value->GetAsInteger(&delay))
201 core_.refresh_scheduler()->SetRefreshDelay(delay);
205 std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
206 std::string display_name;
207 const base::Value* display_name_value =
208 store_->policy_map().GetValue(policy::key::kUserDisplayName);
209 if (display_name_value)
210 display_name_value->GetAsString(&display_name);
211 return display_name;
214 void DeviceLocalAccountPolicyBroker::OnStoreLoaded(CloudPolicyStore* store) {
215 UpdateRefreshDelay();
216 policy_update_callback_.Run();
219 void DeviceLocalAccountPolicyBroker::OnStoreError(CloudPolicyStore* store) {
220 policy_update_callback_.Run();
223 void DeviceLocalAccountPolicyBroker::OnComponentCloudPolicyUpdated() {
224 policy_update_callback_.Run();
227 void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService(
228 const scoped_refptr<net::URLRequestContextGetter>& request_context,
229 CloudPolicyClient* client) {
230 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
231 switches::kDisableComponentCloudPolicy)) {
232 // Disabled via the command line.
233 return;
236 scoped_ptr<ResourceCache> resource_cache(
237 new ResourceCache(component_policy_cache_path_,
238 content::BrowserThread::GetMessageLoopProxyForThread(
239 content::BrowserThread::FILE)));
241 component_policy_service_.reset(new ComponentCloudPolicyService(
242 this,
243 &schema_registry_,
244 core(),
245 client,
246 resource_cache.Pass(),
247 request_context,
248 content::BrowserThread::GetMessageLoopProxyForThread(
249 content::BrowserThread::FILE),
250 content::BrowserThread::GetMessageLoopProxyForThread(
251 content::BrowserThread::IO)));
254 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
255 chromeos::SessionManagerClient* session_manager_client,
256 chromeos::DeviceSettingsService* device_settings_service,
257 chromeos::CrosSettings* cros_settings,
258 AffiliatedInvalidationServiceProvider* invalidation_service_provider,
259 scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
260 scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
261 scoped_refptr<base::SequencedTaskRunner>
262 external_data_service_backend_task_runner,
263 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
264 scoped_refptr<net::URLRequestContextGetter> request_context)
265 : session_manager_client_(session_manager_client),
266 device_settings_service_(device_settings_service),
267 cros_settings_(cros_settings),
268 invalidation_service_provider_(invalidation_service_provider),
269 device_management_service_(nullptr),
270 waiting_for_cros_settings_(false),
271 orphan_extension_cache_deletion_state_(NOT_STARTED),
272 store_background_task_runner_(store_background_task_runner),
273 extension_cache_task_runner_(extension_cache_task_runner),
274 request_context_(request_context),
275 local_accounts_subscription_(cros_settings_->AddSettingsObserver(
276 chromeos::kAccountsPrefDeviceLocalAccounts,
277 base::Bind(&DeviceLocalAccountPolicyService::
278 UpdateAccountListIfNonePending,
279 base::Unretained(this)))),
280 weak_factory_(this) {
281 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_COMPONENT_POLICY,
282 &component_policy_cache_root_));
283 external_data_service_.reset(new DeviceLocalAccountExternalDataService(
284 this,
285 external_data_service_backend_task_runner,
286 io_task_runner));
287 UpdateAccountList();
290 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
291 DCHECK(!request_context_.get());
292 DCHECK(policy_brokers_.empty());
295 void DeviceLocalAccountPolicyService::Shutdown() {
296 device_management_service_ = nullptr;
297 request_context_ = nullptr;
298 DeleteBrokers(&policy_brokers_);
301 void DeviceLocalAccountPolicyService::Connect(
302 DeviceManagementService* device_management_service) {
303 DCHECK(!device_management_service_);
304 device_management_service_ = device_management_service;
306 // Connect the brokers.
307 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
308 it != policy_brokers_.end(); ++it) {
309 it->second->ConnectIfPossible(device_settings_service_,
310 device_management_service_,
311 request_context_);
315 DeviceLocalAccountPolicyBroker*
316 DeviceLocalAccountPolicyService::GetBrokerForUser(
317 const std::string& user_id) {
318 PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
319 if (entry == policy_brokers_.end())
320 return nullptr;
322 return entry->second;
325 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
326 const std::string& user_id) {
327 DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
328 return broker && broker->core()->store()->is_managed();
331 void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
332 observers_.AddObserver(observer);
335 void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
336 observers_.RemoveObserver(observer);
339 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
340 const std::string& account_id) {
341 return busy_extension_cache_directories_.find(account_id) !=
342 busy_extension_cache_directories_.end();
345 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
346 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
347 it != policy_brokers_.end(); ++it) {
348 if (!it->second->extension_loader()->IsCacheRunning() &&
349 !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
350 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
355 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
356 const std::string& account_id) {
357 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
358 it != policy_brokers_.end(); ++it) {
359 if (it->second->account_id() == account_id) {
360 DCHECK(!it->second->extension_loader()->IsCacheRunning());
361 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
362 return true;
365 return false;
368 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
369 DCHECK_EQ(IN_PROGRESS, orphan_extension_cache_deletion_state_);
371 orphan_extension_cache_deletion_state_ = DONE;
372 StartExtensionCachesIfPossible();
375 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
376 const std::string& account_id) {
377 DCHECK_NE(NOT_STARTED, orphan_extension_cache_deletion_state_);
378 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
380 // The account with |account_id| was deleted and the broker for it has shut
381 // down completely.
383 if (StartExtensionCacheForAccountIfPresent(account_id)) {
384 // If another account with the same ID was created in the meantime, its
385 // extension cache is started, reusing the cache directory. The directory no
386 // longer needs to be marked as busy in this case.
387 busy_extension_cache_directories_.erase(account_id);
388 return;
391 // If no account with |account_id| exists anymore, the cache directory should
392 // be removed. The directory must stay marked as busy while the removal is in
393 // progress.
394 extension_cache_task_runner_->PostTaskAndReply(
395 FROM_HERE,
396 base::Bind(&DeleteObsoleteExtensionCache, account_id),
397 base::Bind(&DeviceLocalAccountPolicyService::
398 OnObsoleteExtensionCacheDeleted,
399 weak_factory_.GetWeakPtr(),
400 account_id));
403 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
404 const std::string& account_id) {
405 DCHECK_EQ(DONE, orphan_extension_cache_deletion_state_);
406 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
408 // The cache directory for |account_id| has been deleted. The directory no
409 // longer needs to be marked as busy.
410 busy_extension_cache_directories_.erase(account_id);
412 // If another account with the same ID was created in the meantime, start its
413 // extension cache, creating a new cache directory.
414 StartExtensionCacheForAccountIfPresent(account_id);
417 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
418 // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
419 // pending (because the |cros_settings_| are not trusted yet), the updated
420 // account list will be processed by that call when it eventually runs.
421 if (!waiting_for_cros_settings_)
422 UpdateAccountList();
425 void DeviceLocalAccountPolicyService::UpdateAccountList() {
426 chromeos::CrosSettingsProvider::TrustedStatus status =
427 cros_settings_->PrepareTrustedValues(
428 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
429 weak_factory_.GetWeakPtr()));
430 switch (status) {
431 case chromeos::CrosSettingsProvider::TRUSTED:
432 waiting_for_cros_settings_ = false;
433 break;
434 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
435 waiting_for_cros_settings_ = true;
436 return;
437 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
438 waiting_for_cros_settings_ = false;
439 return;
442 // Update |policy_brokers_|, keeping existing entries.
443 PolicyBrokerMap old_policy_brokers;
444 policy_brokers_.swap(old_policy_brokers);
445 std::set<std::string> subdirectories_to_keep;
446 const std::vector<DeviceLocalAccount> device_local_accounts =
447 GetDeviceLocalAccounts(cros_settings_);
448 for (std::vector<DeviceLocalAccount>::const_iterator it =
449 device_local_accounts.begin();
450 it != device_local_accounts.end(); ++it) {
451 PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
453 scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
454 bool broker_initialized = false;
455 if (broker_it != old_policy_brokers.end()) {
456 // Reuse the existing broker if present.
457 broker.reset(broker_it->second);
458 old_policy_brokers.erase(broker_it);
459 broker_initialized = true;
460 } else {
461 scoped_ptr<DeviceLocalAccountPolicyStore> store(
462 new DeviceLocalAccountPolicyStore(it->account_id,
463 session_manager_client_,
464 device_settings_service_,
465 store_background_task_runner_));
466 scoped_refptr<DeviceLocalAccountExternalDataManager>
467 external_data_manager =
468 external_data_service_->GetExternalDataManager(it->account_id,
469 store.get());
470 broker.reset(new DeviceLocalAccountPolicyBroker(
471 *it,
472 component_policy_cache_root_.Append(
473 GetCacheSubdirectoryForAccountID(it->account_id)),
474 store.Pass(),
475 external_data_manager,
476 base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated,
477 base::Unretained(this),
478 it->user_id),
479 base::ThreadTaskRunnerHandle::Get(),
480 invalidation_service_provider_));
483 // Fire up the cloud connection for fetching policy for the account from
484 // the cloud if this is an enterprise-managed device.
485 broker->ConnectIfPossible(device_settings_service_,
486 device_management_service_,
487 request_context_);
489 policy_brokers_[it->user_id] = broker.release();
490 if (!broker_initialized) {
491 // The broker must be initialized after it has been added to
492 // |policy_brokers_|.
493 policy_brokers_[it->user_id]->Initialize();
496 subdirectories_to_keep.insert(
497 GetCacheSubdirectoryForAccountID(it->account_id));
500 if (orphan_extension_cache_deletion_state_ == NOT_STARTED) {
501 DCHECK(old_policy_brokers.empty());
502 DCHECK(busy_extension_cache_directories_.empty());
504 // If this method is running for the first time, no extension caches have
505 // been started yet. Take this opportunity to do a clean-up by removing
506 // orphaned cache directories not found in |subdirectories_to_keep| from the
507 // cache directory.
508 orphan_extension_cache_deletion_state_ = IN_PROGRESS;
510 base::FilePath cache_root_dir;
511 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
512 &cache_root_dir));
513 extension_cache_task_runner_->PostTaskAndReply(
514 FROM_HERE,
515 base::Bind(
516 &DeleteOrphanedCaches, cache_root_dir, subdirectories_to_keep),
517 base::Bind(
518 &DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted,
519 weak_factory_.GetWeakPtr()));
521 // Start the extension caches for all brokers. These belong to accounts in
522 // |account_ids| and are not affected by the clean-up.
523 StartExtensionCachesIfPossible();
524 } else {
525 // If this method has run before, obsolete brokers may exist. Shut down
526 // their extension caches and delete the brokers.
527 DeleteBrokers(&old_policy_brokers);
529 if (orphan_extension_cache_deletion_state_ == DONE) {
530 // If the initial clean-up of orphaned cache directories has been
531 // complete, start any extension caches that are not running yet but can
532 // be started now because their cache directories are not busy.
533 StartExtensionCachesIfPossible();
537 // Purge the component policy caches of any accounts that have been removed.
538 // Do this only after any obsolete brokers have been destroyed.
539 // TODO(joaodasilva): for now this must be posted to the FILE thread,
540 // to avoid racing with the ComponentCloudPolicyStore. Use a task runner
541 // once that class supports another background thread too.
542 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
543 base::Bind(&DeleteOrphanedCaches,
544 component_policy_cache_root_,
545 subdirectories_to_keep));
547 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
550 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
551 for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
552 scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
553 extension_loader = it->second->extension_loader();
554 if (extension_loader->IsCacheRunning()) {
555 DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
556 busy_extension_cache_directories_.insert(it->second->account_id());
557 extension_loader->StopCache(base::Bind(
558 &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
559 weak_factory_.GetWeakPtr(),
560 it->second->account_id()));
563 delete it->second;
565 map->clear();
568 DeviceLocalAccountPolicyBroker*
569 DeviceLocalAccountPolicyService::GetBrokerForStore(
570 CloudPolicyStore* store) {
571 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
572 it != policy_brokers_.end(); ++it) {
573 if (it->second->core()->store() == store)
574 return it->second;
576 return nullptr;
579 void DeviceLocalAccountPolicyService::NotifyPolicyUpdated(
580 const std::string& user_id) {
581 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(user_id));
584 } // namespace policy