Commit 6b691fdc authored by Norge Vizcay's avatar Norge Vizcay Committed by Chromium LUCI CQ

[Password] Enable support to interact with the password store from Java integration tests.

* A new service is introduced to act as a bridge between Java and c++ password store and provide the required functionality.

The service supports the following directives:
- Clear all password store credentials.
- Read password store credentials.
- Write credential into the password store.
- Edit credential from password store.

More context:
https://docs.google.com/document/d/1baR4V7_1myXAGRBve6tjH7M1y3b46NLSMCmvwUniTng/edit?usp=sharing&resourcekey=0-zhjniBnKxbx700x72JViMg

Bug: 1164365
Change-Id: Ic343609d738524a597a724593ae5bf4d766738e6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2591128
Commit-Queue: Norge Vizcay <vizcay@google.com>
Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842634}
parent 9c58d1c3
...@@ -3135,6 +3135,8 @@ static_library("browser") { ...@@ -3135,6 +3135,8 @@ static_library("browser") {
"password_manager/android/password_manager_launcher_android.cc", "password_manager/android/password_manager_launcher_android.cc",
"password_manager/android/password_manager_launcher_android.h", "password_manager/android/password_manager_launcher_android.h",
"password_manager/android/password_scripts_fetcher_android.cc", "password_manager/android/password_scripts_fetcher_android.cc",
"password_manager/android/password_store_bridge.cc",
"password_manager/android/password_store_bridge.h",
"password_manager/android/save_password_infobar_delegate_android.cc", "password_manager/android/save_password_infobar_delegate_android.cc",
"password_manager/android/save_password_infobar_delegate_android.h", "password_manager/android/save_password_infobar_delegate_android.h",
"password_manager/android/save_password_message_delegate.cc", "password_manager/android/save_password_message_delegate.cc",
......
...@@ -12,10 +12,13 @@ android_library("java") { ...@@ -12,10 +12,13 @@ android_library("java") {
"//components/password_manager/core/browser:password_manager_java_enums", "//components/password_manager/core/browser:password_manager_java_enums",
"//third_party/android_deps:androidx_annotation_annotation_java", "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:androidx_fragment_fragment_java", "//third_party/android_deps:androidx_fragment_fragment_java",
"//url:gurl_java",
] ]
sources = [ sources = [
"java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java", "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java",
"java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java", "java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java",
"java/src/org/chromium/chrome/browser/password_manager/settings/PasswordReauthenticationFragment.java", "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordReauthenticationFragment.java",
"java/src/org/chromium/chrome/browser/password_manager/settings/ReauthenticationManager.java", "java/src/org/chromium/chrome/browser/password_manager/settings/ReauthenticationManager.java",
] ]
...@@ -24,7 +27,11 @@ android_library("java") { ...@@ -24,7 +27,11 @@ android_library("java") {
generate_jni("jni_headers") { generate_jni("jni_headers") {
visibility = [ "//chrome/browser" ] visibility = [ "//chrome/browser" ]
sources = [ "java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java" ] sources = [
"java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java",
"java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java",
]
} }
junit_binary("password_manager_junit_tests") { junit_binary("password_manager_junit_tests") {
......
// Copyright 2021 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.
package org.chromium.chrome.browser.password_manager;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.url.GURL;
/**
* Class handling communication with C++ password store from Java. It forwards
* messages to and from its C++ counterpart.
*/
public class PasswordStoreBridge {
@CalledByNative
private static PasswordStoreCredential createPasswordStoreCredential(
GURL url, String username, String password) {
return new PasswordStoreCredential(url, username, password);
}
private long mNativePasswordStoreBridge;
private final PasswordStoreObserver mPasswordStoreObserver;
/**
* Observer listening to messages relevant to password store changes.
*/
public interface PasswordStoreObserver {
/**
* Called when the set of password credentials is changed.
*
* @param count The total number of stored password credentials.
*/
void onSavedPasswordsChanged(int count);
/**
* Called when a stored credential has been updated.
*
* @param credential Credential updated.
*/
void onEdit(PasswordStoreCredential credential);
}
/**
* Initializes its native counterpart.
*/
public PasswordStoreBridge(PasswordStoreObserver passwordStoreObserver) {
mNativePasswordStoreBridge = PasswordStoreBridgeJni.get().init(this);
mPasswordStoreObserver = passwordStoreObserver;
}
@CalledByNative
private void passwordListAvailable(int count) {
mPasswordStoreObserver.onSavedPasswordsChanged(count);
}
@CalledByNative
private void onEditCredential(PasswordStoreCredential credential) {
mPasswordStoreObserver.onEdit(credential);
}
@CalledByNative
private static void insertCredential(PasswordStoreCredential[] credentials, int index, GURL url,
String username, String password) {
credentials[index] = new PasswordStoreCredential(url, username, password);
}
/**
* Inserts new credential into the password store.
*/
public void insertPasswordCredential(PasswordStoreCredential credential) {
PasswordStoreBridgeJni.get().insertPasswordCredential(
mNativePasswordStoreBridge, credential);
}
/**
* Updates an existing credential with a new password.
*
* @return True if credential was successfully updated, false otherwise.
*/
public boolean editPassword(PasswordStoreCredential credential, String newPassword) {
return PasswordStoreBridgeJni.get().editPassword(
mNativePasswordStoreBridge, credential, newPassword);
}
/**
* Returns the count of stored credentials.
*/
public int getPasswordStoreCredentialsCount() {
return PasswordStoreBridgeJni.get().getPasswordStoreCredentialsCount(
mNativePasswordStoreBridge);
}
/**
* Returns the list of credentials stored in the database.
*
* @param credentials array to be populated.
*/
public void getAllCredentials(PasswordStoreCredential[] credentials) {
PasswordStoreBridgeJni.get().getAllCredentials(mNativePasswordStoreBridge, credentials);
}
/**
* Empties the password store.
*/
public void clearAllPasswords() {
PasswordStoreBridgeJni.get().clearAllPasswords(mNativePasswordStoreBridge);
}
/**
* Destroys its C++ counterpart.
*/
public void destroy() {
if (mNativePasswordStoreBridge != 0) {
PasswordStoreBridgeJni.get().destroy(mNativePasswordStoreBridge);
mNativePasswordStoreBridge = 0;
}
}
/**
* C++ method signatures.
*/
@NativeMethods
interface Natives {
long init(PasswordStoreBridge passwordStoreBridge);
void insertPasswordCredential(
long nativePasswordStoreBridge, PasswordStoreCredential credential);
boolean editPassword(long nativePasswordStoreBridge, PasswordStoreCredential credential,
String newPassword);
int getPasswordStoreCredentialsCount(long nativePasswordStoreBridge);
void getAllCredentials(
long nativePasswordStoreBridge, PasswordStoreCredential[] credentials);
void clearAllPasswords(long nativePasswordStoreBridge);
void destroy(long nativePasswordStoreBridge);
}
}
// Copyright 2021 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.
package org.chromium.chrome.browser.password_manager;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.url.GURL;
/**
* This class represents key elements of stored credential in the password store.
*/
public class PasswordStoreCredential {
private final GURL mUrl;
private final String mUsername;
private final String mPassword;
/**
* Constructs an instance of PasswordStoreCredential. Arguments should not be null.
*
* @param url The associated URL to this credential.
* @param username The username used to identify this credential.
* @param password The password associated to this credential.
*/
public PasswordStoreCredential(GURL url, String username, String password) {
assert url != null;
assert username != null;
assert password != null;
mUrl = url;
mUsername = username;
mPassword = password;
}
@CalledByNative
public GURL getUrl() {
return mUrl;
}
@CalledByNative
public String getUsername() {
return mUsername;
}
@CalledByNative
public String getPassword() {
return mPassword;
}
}
// Copyright 2021 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/password_manager/android/password_store_bridge.h"
#include <jni.h>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/callback_helpers.h"
#include "chrome/browser/password_manager/android/jni_headers/PasswordStoreBridge_jni.h"
#include "chrome/browser/password_manager/android/jni_headers/PasswordStoreCredential_jni.h"
#include "components/password_manager/core/browser/form_parsing/form_parser.h"
#include "url/android/gurl_android.h"
namespace {
using password_manager::PasswordForm;
using SavedPasswordsView =
password_manager::SavedPasswordsPresenter::SavedPasswordsView;
PasswordForm ConvertJavaObjectToPasswordForm(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential) {
PasswordForm form;
form.url = *url::GURLAndroid::ToNativeGURL(
env, Java_PasswordStoreCredential_getUrl(env, credential));
form.signon_realm = password_manager::GetSignonRealm(form.url);
form.username_value = ConvertJavaStringToUTF16(
env, Java_PasswordStoreCredential_getUsername(env, credential));
form.password_value = ConvertJavaStringToUTF16(
env, Java_PasswordStoreCredential_getPassword(env, credential));
return form;
}
} // namespace
// static
static jlong JNI_PasswordStoreBridge_Init(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_bridge) {
return reinterpret_cast<intptr_t>(new PasswordStoreBridge(java_bridge));
}
PasswordStoreBridge::PasswordStoreBridge(
const base::android::JavaParamRef<jobject>& java_bridge)
: java_bridge_(java_bridge) {
saved_passwords_presenter_.Init();
observed_saved_password_presenter_.Observe(&saved_passwords_presenter_);
}
PasswordStoreBridge::~PasswordStoreBridge() = default;
void PasswordStoreBridge::InsertPasswordCredential(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential) {
password_store_->AddLogin(ConvertJavaObjectToPasswordForm(env, credential));
}
bool PasswordStoreBridge::EditPassword(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential,
const base::android::JavaParamRef<jstring>& new_password) {
return saved_passwords_presenter_.EditPassword(
ConvertJavaObjectToPasswordForm(env, credential),
ConvertJavaStringToUTF16(env, new_password));
}
jint PasswordStoreBridge::GetPasswordStoreCredentialsCount(JNIEnv* env) const {
return static_cast<int>(
saved_passwords_presenter_.GetSavedPasswords().size());
}
void PasswordStoreBridge::GetAllCredentials(
JNIEnv* env,
const base::android::JavaParamRef<jobjectArray>& java_credentials) const {
const auto credentials = saved_passwords_presenter_.GetSavedPasswords();
for (size_t i = 0; i < credentials.size(); ++i) {
const auto& credential = credentials[i];
Java_PasswordStoreBridge_insertCredential(
env, java_credentials, i,
url::GURLAndroid::FromNativeGURL(env, credential.url),
base::android::ConvertUTF16ToJavaString(env, credential.username_value),
base::android::ConvertUTF16ToJavaString(env,
credential.password_value));
}
}
void PasswordStoreBridge::ClearAllPasswords(JNIEnv* env) {
password_store_->ClearStore(base::DoNothing());
}
void PasswordStoreBridge::Destroy(JNIEnv* env) {
delete this;
}
void PasswordStoreBridge::OnSavedPasswordsChanged(
SavedPasswordsView passwords) {
JNIEnv* env = base::android::AttachCurrentThread();
// Notifies java counter side that a new set of credentials is available.
Java_PasswordStoreBridge_passwordListAvailable(
env, java_bridge_, static_cast<int>(passwords.size()));
}
void PasswordStoreBridge::OnEdited(const PasswordForm& form) {
JNIEnv* env = base::android::AttachCurrentThread();
// Notifies java counter side that a credential has been edited.
Java_PasswordStoreBridge_onEditCredential(
env, java_bridge_,
Java_PasswordStoreBridge_createPasswordStoreCredential(
env, url::GURLAndroid::FromNativeGURL(env, form.url),
base::android::ConvertUTF16ToJavaString(env, form.username_value),
base::android::ConvertUTF16ToJavaString(env, form.password_value)));
}
// Copyright 2021 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_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
#include <jni.h>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/scoped_observation.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
class PasswordStoreBridge
: public password_manager::SavedPasswordsPresenter::Observer {
public:
explicit PasswordStoreBridge(
const base::android::JavaParamRef<jobject>& java_bridge);
~PasswordStoreBridge() override;
PasswordStoreBridge(const PasswordStoreBridge&) = delete;
PasswordStoreBridge& operator=(const PasswordStoreBridge&) = delete;
// Called by Java to store a new credential into the password store.
void InsertPasswordCredential(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential);
// Called by Java to edit a credential.
bool EditPassword(JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential,
const base::android::JavaParamRef<jstring>& new_password);
// Called by Java to get the number of stored credentials.
jint GetPasswordStoreCredentialsCount(JNIEnv* env) const;
// Called by Java to get all stored credentials.
void GetAllCredentials(
JNIEnv* env,
const base::android::JavaParamRef<jobjectArray>& java_credentials) const;
// Called by Java to clear all stored passwords.
void ClearAllPasswords(JNIEnv* env);
// Called by Java to destroy `this`.
void Destroy(JNIEnv* env);
private:
// SavedPasswordsPresenter::Observer:
void OnSavedPasswordsChanged(
password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords)
override;
void OnEdited(const password_manager::PasswordForm& form) override;
// The corresponding java object.
base::android::ScopedJavaGlobalRef<jobject> java_bridge_;
// Handle to the password store, powering `saved_passwords_presenter_`.
scoped_refptr<password_manager::PasswordStore> password_store_ =
PasswordStoreFactory::GetForProfile(ProfileManager::GetLastUsedProfile(),
ServiceAccessType::EXPLICIT_ACCESS);
// Used to fetch and edit passwords.
password_manager::SavedPasswordsPresenter saved_passwords_presenter_{
password_store_};
// A scoped observer for |saved_passwords_presenter_|.
base::ScopedObservation<password_manager::SavedPasswordsPresenter,
password_manager::SavedPasswordsPresenter::Observer>
observed_saved_password_presenter_{this};
};
#endif // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment