Skip to content

Commit

Permalink
[Extensions] Add chrome.loginScreenStorage API
Browse files Browse the repository at this point in the history
This CL introduces new extensions API that allows white-listed login
screen extensions to store persistent data accessible from login
screen and inject short-lived data into the user session (using
ChromeOS session manager daemon). See API proposal for more details.

Bug: 980171
Change-Id: I5b07311dbcba0e7be711457553cf85ded7443fd8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1611994
Commit-Queue: Zakhar Voit <voit@google.com>
Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: Alexander Hendrich <hendrich@chromium.org>
Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685130}
  • Loading branch information
zakharvoit authored and Commit Bot committed Aug 8, 2019
1 parent e46dd10 commit 61a11d2
Show file tree
Hide file tree
Showing 18 changed files with 501 additions and 2 deletions.
3 changes: 3 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -3696,6 +3696,9 @@ are declared in tools/grit/grit_rule.gni.
<message name="IDS_EXTENSION_PROMPT_WARNING_LOGIN_SCREEN_UI" desc="Permission string for access to login screen UI.">
Display UI on the login screen
</message>
<message name="IDS_EXTENSION_PROMPT_WARNING_LOGIN_SCREEN_STORAGE" desc="Permission string for access to login screen storage.">
Store persistent data on the login screen and inject credentials into the session.
</message>
<message name="IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT" desc="Permisson string for access to extension management.">
Manage your apps, extensions, and themes
</message>
Expand Down
2 changes: 2 additions & 0 deletions chrome/browser/chromeos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,8 @@ source_set("chromeos") {
"extensions/input_method_api.h",
"extensions/login_screen/login/login_api.cc",
"extensions/login_screen/login/login_api.h",
"extensions/login_screen/login_screen_storage/login_screen_storage_api.cc",
"extensions/login_screen/login_screen_storage/login_screen_storage_api.h",
"extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.cc",
"extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h",
"extensions/login_screen/login_screen_ui/login_screen_ui_api.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright 2019 The Chromium 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 "chrome/browser/chromeos/extensions/login_screen/login_screen_storage/login_screen_storage_api.h"

#include "base/values.h"
#include "chrome/common/extensions/api/login_screen_storage.h"
#include "chromeos/dbus/session_manager/session_manager_client.h"
#include "components/user_manager/user_manager.h"

namespace login_screen_storage = extensions::api::login_screen_storage;

namespace extensions {

namespace {

const char kPersistentDataKeyPrefix[] = "persistent_data_";
const char kCredentialsKeyPrefix[] = "credentials_";

} // namespace

LoginScreenStorageExtensionFunction::LoginScreenStorageExtensionFunction() =
default;
LoginScreenStorageExtensionFunction::~LoginScreenStorageExtensionFunction() =
default;

void LoginScreenStorageExtensionFunction::OnDataStored(
base::Optional<std::string> error) {
Respond(error ? Error(*error) : NoArguments());
}

void LoginScreenStorageExtensionFunction::OnDataRetrieved(
base::Optional<std::string> data,
base::Optional<std::string> error) {
if (error) {
Respond(Error(*error));
return;
}
Respond(OneArgument(data ? std::make_unique<base::Value>(*data) : nullptr));
}

LoginScreenStorageStorePersistentDataFunction::
LoginScreenStorageStorePersistentDataFunction() = default;
LoginScreenStorageStorePersistentDataFunction::
~LoginScreenStorageStorePersistentDataFunction() = default;

ExtensionFunction::ResponseAction
LoginScreenStorageStorePersistentDataFunction::Run() {
std::unique_ptr<login_screen_storage::StorePersistentData::Params> params =
login_screen_storage::StorePersistentData::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
login_manager::LoginScreenStorageMetadata metadata;
metadata.set_clear_on_session_exit(false);
StoreDataForExtensions(std::move(params->extension_ids), metadata,
params->data);
return RespondLater();
}

void LoginScreenStorageStorePersistentDataFunction::OnDataStored(
std::vector<std::string> extension_ids,
const login_manager::LoginScreenStorageMetadata& metadata,
const std::string& data,
base::Optional<std::string> error) {
if (error) {
Respond(Error(*error));
return;
}

if (extension_ids.empty()) {
Respond(NoArguments());
return;
}

StoreDataForExtensions(std::move(extension_ids), metadata, data);
}

void LoginScreenStorageStorePersistentDataFunction::StoreDataForExtensions(
std::vector<std::string> extension_ids,
const login_manager::LoginScreenStorageMetadata& metadata,
const std::string& data) {
if (extension_ids.empty())
return;

std::string extension_id = extension_ids.back();
extension_ids.pop_back();
chromeos::SessionManagerClient::Get()->LoginScreenStorageStore(
kPersistentDataKeyPrefix + extension_id, metadata, data,
base::BindOnce(
&LoginScreenStorageStorePersistentDataFunction::OnDataStored, this,
std::move(extension_ids), metadata, data));
}

LoginScreenStorageRetrievePersistentDataFunction::
LoginScreenStorageRetrievePersistentDataFunction() = default;
LoginScreenStorageRetrievePersistentDataFunction::
~LoginScreenStorageRetrievePersistentDataFunction() = default;

ExtensionFunction::ResponseAction
LoginScreenStorageRetrievePersistentDataFunction::Run() {
chromeos::SessionManagerClient::Get()->LoginScreenStorageRetrieve(
kPersistentDataKeyPrefix + extension_id(),
base::BindOnce(
&LoginScreenStorageRetrievePersistentDataFunction::OnDataRetrieved,
this));
return RespondLater();
}

LoginScreenStorageStoreCredentialsFunction::
LoginScreenStorageStoreCredentialsFunction() = default;
LoginScreenStorageStoreCredentialsFunction::
~LoginScreenStorageStoreCredentialsFunction() = default;

ExtensionFunction::ResponseAction
LoginScreenStorageStoreCredentialsFunction::Run() {
std::unique_ptr<login_screen_storage::StoreCredentials::Params> params =
login_screen_storage::StoreCredentials::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
login_manager::LoginScreenStorageMetadata metadata;
metadata.set_clear_on_session_exit(true);
chromeos::SessionManagerClient::Get()->LoginScreenStorageStore(
kCredentialsKeyPrefix + params->extension_id, metadata,
params->credentials,
base::BindOnce(&LoginScreenStorageStoreCredentialsFunction::OnDataStored,
this));
return RespondLater();
}

LoginScreenStorageRetrieveCredentialsFunction::
LoginScreenStorageRetrieveCredentialsFunction() = default;
LoginScreenStorageRetrieveCredentialsFunction::
~LoginScreenStorageRetrieveCredentialsFunction() = default;

ExtensionFunction::ResponseAction
LoginScreenStorageRetrieveCredentialsFunction::Run() {
chromeos::SessionManagerClient::Get()->LoginScreenStorageRetrieve(
kCredentialsKeyPrefix + extension_id(),
base::BindOnce(
&LoginScreenStorageRetrieveCredentialsFunction::OnDataRetrieved,
this));
return RespondLater();
}

} // namespace extensions
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2019 The Chromium 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 CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_SCREEN_STORAGE_LOGIN_SCREEN_STORAGE_API_H_
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_SCREEN_STORAGE_LOGIN_SCREEN_STORAGE_API_H_

#include "chromeos/dbus/login_manager/login_screen_storage.pb.h"
#include "extensions/browser/extension_function.h"

namespace extensions {

// Provides common callback functions to return results from
// 'LoginScreenStorageStore' and 'LoginScreenStorageRetrieve' D-Bus methods.
class LoginScreenStorageExtensionFunction : public ExtensionFunction {
protected:
LoginScreenStorageExtensionFunction();
~LoginScreenStorageExtensionFunction() override;

// When passed as a callback to the 'LoginScreenStorageStore' D-Bus method,
// returns its result to the calling extension.
void OnDataStored(base::Optional<std::string> error);

// When passed as a callback to the 'LoginScreenStorageRetrieve' D-Bus method,
// returns its result to the calling extension.
void OnDataRetrieved(base::Optional<std::string> data,
base::Optional<std::string> error);

private:
DISALLOW_COPY_AND_ASSIGN(LoginScreenStorageExtensionFunction);
};

class LoginScreenStorageStorePersistentDataFunction : public ExtensionFunction {
public:
LoginScreenStorageStorePersistentDataFunction();
DECLARE_EXTENSION_FUNCTION("loginScreenStorage.storePersistentData",
LOGINSCREENSTORAGE_STOREPERSISTENTDATA)

protected:
~LoginScreenStorageStorePersistentDataFunction() override;

// ExtensionFunction:
ResponseAction Run() override;

private:
// Called when data for one of the extension was stored, |extension_ids| is a
// list of the extensions that the data wasn't yet stored for.
void OnDataStored(std::vector<std::string> extension_ids,
const login_manager::LoginScreenStorageMetadata& metadata,
const std::string& data,
base::Optional<std::string> error);

// Asynchronously stores data for every extension from |extension_ids|.
void StoreDataForExtensions(
std::vector<std::string> extension_ids,
const login_manager::LoginScreenStorageMetadata& metadata,
const std::string& data);

DISALLOW_COPY_AND_ASSIGN(LoginScreenStorageStorePersistentDataFunction);
};

class LoginScreenStorageRetrievePersistentDataFunction
: public LoginScreenStorageExtensionFunction {
public:
LoginScreenStorageRetrievePersistentDataFunction();
DECLARE_EXTENSION_FUNCTION("loginScreenStorage.retrievePersistentData",
LOGINSCREENSTORAGE_RETRIEVEPERSISTENTDATA)

protected:
~LoginScreenStorageRetrievePersistentDataFunction() override;

// ExtensionFunction:
ResponseAction Run() override;

private:
DISALLOW_COPY_AND_ASSIGN(LoginScreenStorageRetrievePersistentDataFunction);
};

class LoginScreenStorageStoreCredentialsFunction
: public LoginScreenStorageExtensionFunction {
public:
LoginScreenStorageStoreCredentialsFunction();
DECLARE_EXTENSION_FUNCTION("loginScreenStorage.storeCredentials",
LOGINSCREENSTORAGE_STORECREDENTIALS)

protected:
~LoginScreenStorageStoreCredentialsFunction() override;

// ExtensionFunction:
ResponseAction Run() override;

private:
DISALLOW_COPY_AND_ASSIGN(LoginScreenStorageStoreCredentialsFunction);
};

class LoginScreenStorageRetrieveCredentialsFunction
: public LoginScreenStorageExtensionFunction {
public:
LoginScreenStorageRetrieveCredentialsFunction();
DECLARE_EXTENSION_FUNCTION("loginScreenStorage.retrieveCredentials",
LOGINSCREENSTORAGE_RETRIEVECREDENTIALS)

protected:
~LoginScreenStorageRetrieveCredentialsFunction() override;

// ExtensionFunction:
ResponseAction Run() override;

private:
DISALLOW_COPY_AND_ASSIGN(LoginScreenStorageRetrieveCredentialsFunction);
};

} // namespace extensions

#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_SCREEN_STORAGE_LOGIN_SCREEN_STORAGE_API_H_
4 changes: 4 additions & 0 deletions chrome/common/extensions/api/_api_features.json
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,10 @@
"dependencies": ["permission:login"],
"contexts": ["blessed_extension"]
},
"loginScreenStorage": {
"dependencies": ["permission:loginScreenStorage"],
"contexts": ["blessed_extension"]
},
"loginScreenUi": {
"dependencies": ["permission:loginScreenUi"],
"contexts": ["blessed_extension"]
Expand Down
12 changes: 12 additions & 0 deletions chrome/common/extensions/api/_permission_features.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,18 @@
"6B25164FFE2BADB5F1DBBD301CC022170267022D" // Imprivata (in session) DEV
]
},
"loginScreenStorage": {
"channel": "dev",
"extension_types": ["login_screen_extension", "extension"],
"location": "policy",
"platforms": ["chromeos"],
"whitelist": [
"E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen)
"4DBFC1C52D6660DD90791976DF7FEF7B3D360509", // Imprivata (login screen) DEV
"A24DE1B21A67E25FB62AC8491642038FE25DA75B", // Imprivata (in session)
"6B25164FFE2BADB5F1DBBD301CC022170267022D" // Imprivata (in session) DEV
]
},
"loginScreenUi": {
"channel": "dev",
"extension_types": ["login_screen_extension"],
Expand Down
1 change: 1 addition & 0 deletions chrome/common/extensions/api/api_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ if (is_chromeos) {
"input_method_private.json",
"launcher_search_provider.idl",
"login.idl",
"login_screen_storage.idl",
"login_screen_ui.idl",
"platform_keys.idl",
"platform_keys_internal.idl",
Expand Down
44 changes: 44 additions & 0 deletions chrome/common/extensions/api/login_screen_storage.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Use the <code>chrome.loginScreenStorage</code> API to store persistent data
// from the login screen or inject data into the session.
[platforms=("chromeos"),
implemented_in="chrome/browser/chromeos/extensions/login_screen/login_screen_storage/login_screen_storage_api.h"]
namespace loginScreenStorage {
callback StoreCallback = void ();
callback RetrieveCallback = void (DOMString data);

interface Functions {
// Stores persistent data from the login screen. This data can be accessed
// later using $(ref:retrievePersistentData) by any extension from the
// specified extension ids. This method will fail if called while a user
// session is active.
// |extensionIds|: IDs of the extensions that should have access to the
// stored data.
// |data|: The data to store.
static void storePersistentData(DOMString[] extensionIds,
DOMString data,
StoreCallback callback);

// Retrieves persistent data that was previously stored using
// $(ref:storePersistentData) for the caller's extension ID.
static void retrievePersistentData(RetrieveCallback callback);

// Stores credentials for later access from the user session. This method
// will fail if called while a user session is active.
// |extensionId|: ID of the in-session extension that should have access to
// these credentials. Credentials stored using this method are deleted on
// session exit.
// |credentials|: The credentials to store.
static void storeCredentials(DOMString extensionId,
DOMString credentials,
StoreCallback callback);

// Retrieves credentials that were previosly stored using
// $(ref:storeCredentials). The caller's extension ID should be the same as
// the extension id passed to the $(ref:storeCredentials).
static void retrieveCredentials(RetrieveCallback callback);
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,9 @@ ChromePermissionMessageRule::GetAllRules() {
{IDS_EXTENSION_PROMPT_WARNING_LOGIN_SCREEN_UI,
{APIPermission::kLoginScreenUi},
{}},
{IDS_EXTENSION_PROMPT_WARNING_LOGIN_SCREEN_STORAGE,
{APIPermission::kLoginScreenStorage},
{}},
{IDS_EXTENSION_PROMPT_WARNING_TRANSIENT_BACKGROUND,
{APIPermission::kTransientBackground},
{}},
Expand Down
1 change: 1 addition & 0 deletions chromeos/dbus/session_manager/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ component("session_manager") {
proto_library("login_manager_proto") {
sources = [
"//third_party/cros_system_api/dbus/login_manager/arc.proto",
"//third_party/cros_system_api/dbus/login_manager/login_screen_storage.proto",
"//third_party/cros_system_api/dbus/login_manager/policy_descriptor.proto",
]

Expand Down

0 comments on commit 61a11d2

Please sign in to comment.