Commit b2ebecac authored by Lutz Justen's avatar Lutz Justen Committed by Commit Bot

Add KerberosCredentialsManager

The KerberosCredentialsManager is a layer on top of the Kerberos daemon
D-Bus client (KerberosClient). It should be used to add/remove accounts,
set configuration and authenticate. It makes sure that Kerberos tickets
get put into a place where GSSAPI finds them, so Kerberos web
authentication works.

BUG=chromium:933798
TEST=Ran unit tests and ExistingUserControllerActiveDirectoryTest.*
      after temporarily enable disabled tests.

Change-Id: I4287c269677322436f6809d07cc14105390397b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1511397
Commit-Queue: Lutz Justen <ljusten@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarRoman Sorokin [CET] <rsorokin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649826}
parent e9b10be2
......@@ -102,6 +102,7 @@ source_set("chromeos") {
"//chromeos/dbus/cryptohome:cryptohome_proto",
"//chromeos/dbus/cryptohome:cryptohome_signkey_proto",
"//chromeos/dbus/kerberos",
"//chromeos/dbus/kerberos:kerberos_proto",
"//chromeos/dbus/machine_learning",
"//chromeos/dbus/media_analytics",
"//chromeos/dbus/media_analytics:media_perception_proto",
......@@ -620,6 +621,8 @@ source_set("chromeos") {
"authpolicy/auth_policy_credentials_manager.h",
"authpolicy/authpolicy_helper.cc",
"authpolicy/authpolicy_helper.h",
"authpolicy/data_pipe_utils.cc",
"authpolicy/data_pipe_utils.h",
"authpolicy/kerberos_files_handler.cc",
"authpolicy/kerberos_files_handler.h",
"base/file_flusher.cc",
......@@ -1063,6 +1066,8 @@ source_set("chromeos") {
"input_method/input_method_persistence.h",
"input_method/input_method_syncer.cc",
"input_method/input_method_syncer.h",
"kerberos/kerberos_credentials_manager.cc",
"kerberos/kerberos_credentials_manager.h",
"kiosk_next_home/app_controller_service.cc",
"kiosk_next_home/app_controller_service.h",
"kiosk_next_home/app_controller_service_factory.cc",
......
......@@ -6,10 +6,10 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "chrome/browser/chromeos/authpolicy/data_pipe_utils.h"
#include "chromeos/dbus/auth_policy/auth_policy_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/upstart/upstart_client.h"
......@@ -25,23 +25,6 @@ namespace {
constexpr char kDCPrefix[] = "DC=";
constexpr char kOUPrefix[] = "OU=";
base::ScopedFD GetDataReadPipe(const std::string& data) {
int pipe_fds[2];
if (!base::CreateLocalNonBlockingPipe(pipe_fds)) {
DLOG(ERROR) << "Failed to create pipe";
return base::ScopedFD();
}
base::ScopedFD pipe_read_end(pipe_fds[0]);
base::ScopedFD pipe_write_end(pipe_fds[1]);
if (!base::WriteFileDescriptor(pipe_write_end.get(), data.c_str(),
data.size())) {
DLOG(ERROR) << "Failed to write to pipe";
return base::ScopedFD();
}
return pipe_read_end;
}
bool ParseDomainAndOU(const std::string& distinguished_name,
authpolicy::JoinDomainRequest* request) {
std::string machine_domain;
......@@ -147,7 +130,8 @@ void AuthPolicyHelper::TryAuthenticateUser(const std::string& username,
request.set_user_principal_name(username);
request.set_account_id(object_guid);
AuthPolicyClient::Get()->AuthenticateUser(
request, GetDataReadPipe(password).get(), base::DoNothing());
request, data_pipe_utils::GetDataReadPipe(password).get(),
base::DoNothing());
}
// static
......@@ -189,7 +173,7 @@ void AuthPolicyHelper::JoinAdDomain(const std::string& machine_name,
request.set_dm_token(dm_token_);
AuthPolicyClient::Get()->JoinAdDomain(
request, GetDataReadPipe(password).get(),
request, data_pipe_utils::GetDataReadPipe(password).get(),
base::BindOnce(&AuthPolicyHelper::OnJoinCallback,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
......@@ -203,7 +187,7 @@ void AuthPolicyHelper::AuthenticateUser(const std::string& username,
request.set_user_principal_name(username);
request.set_account_id(object_guid);
AuthPolicyClient::Get()->AuthenticateUser(
request, GetDataReadPipe(password).get(),
request, data_pipe_utils::GetDataReadPipe(password).get(),
base::BindOnce(&AuthPolicyHelper::OnAuthCallback,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
......
// 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/authpolicy/data_pipe_utils.h"
#include "base/files/file_util.h"
namespace chromeos {
namespace data_pipe_utils {
base::ScopedFD GetDataReadPipe(const std::string& data) {
int pipe_fds[2];
if (!base::CreateLocalNonBlockingPipe(pipe_fds)) {
DLOG(ERROR) << "Failed to create pipe";
return base::ScopedFD();
}
base::ScopedFD pipe_read_end(pipe_fds[0]);
base::ScopedFD pipe_write_end(pipe_fds[1]);
if (!base::WriteFileDescriptor(pipe_write_end.get(), data.c_str(),
data.size())) {
DLOG(ERROR) << "Failed to write to pipe";
return base::ScopedFD();
}
return pipe_read_end;
}
} // namespace data_pipe_utils
} // namespace chromeos
// 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_AUTHPOLICY_DATA_PIPE_UTILS_H_
#define CHROME_BROWSER_CHROMEOS_AUTHPOLICY_DATA_PIPE_UTILS_H_
#include <string>
#include "base/files/scoped_file.h"
namespace chromeos {
namespace data_pipe_utils {
// Writes |data| to the writing end of a pipe and returns the reading end.
base::ScopedFD GetDataReadPipe(const std::string& data);
} // namespace data_pipe_utils
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_AUTHPOLICY_DATA_PIPE_UTILS_H_
......@@ -26,8 +26,14 @@ namespace chromeos {
namespace {
base::FilePath GetKerberosDir() {
base::FilePath dir;
base::PathService::Get(base::DIR_HOME, &dir);
return dir.Append(kKrb5Directory);
}
// Writes |blob| into file <UserPath>/kerberos/|file_name|. First writes into
// temporary file and then replaces existing one.
// temporary file and then replaces existing one. Prints an error or failure.
void WriteFile(const base::FilePath& path, base::Optional<std::string> blob) {
if (!blob.has_value())
return;
......@@ -35,13 +41,17 @@ void WriteFile(const base::FilePath& path, base::Optional<std::string> blob) {
LOG(ERROR) << "Failed to write file " << path.value();
}
// Deletes file at |path|. Prints an error or failure.
void RemoveFile(const base::FilePath& path) {
if (!base::DeleteFile(path, false /* recursive */))
LOG(ERROR) << "Failed to delete file " << path.value();
}
// Writes |krb5cc| to <DIR_HOME>/kerberos/krb5cc and |krb5config| to
// <DIR_HOME>/kerberos/krb5.conf if set. Creates directories if necessary.
void WriteFiles(base::Optional<std::string> krb5cc,
base::Optional<std::string> krb5config) {
base::FilePath dir;
base::PathService::Get(base::DIR_HOME, &dir);
dir = dir.Append(kKrb5Directory);
base::FilePath dir = GetKerberosDir();
base::File::Error error;
if (!base::CreateDirectoryAndGetError(dir, &error)) {
LOG(ERROR) << "Failed to create '" << dir.value()
......@@ -53,6 +63,13 @@ void WriteFiles(base::Optional<std::string> krb5cc,
WriteFile(dir.Append(kKrb5ConfFile), std::move(krb5config));
}
// Deletes <DIR_HOME>/kerberos/krb5cc and <DIR_HOME>/kerberos/krb5.conf.
void RemoveFiles() {
base::FilePath dir = GetKerberosDir();
RemoveFile(dir.Append(kKrb5CCFile));
RemoveFile(dir.Append(kKrb5ConfFile));
}
// If |config| has a value, puts canonicalization settings first depending on
// user policy. Whatever setting comes first wins, so even if krb5.conf sets
// rdns or dns_canonicalize_hostname below, it would get overridden.
......@@ -129,11 +146,22 @@ void KerberosFilesHandler::SetFiles(base::Optional<std::string> krb5cc,
weak_factory_.GetWeakPtr()));
}
void KerberosFilesHandler::DeleteFiles() {
// These files contain user credentials, so use BLOCK_SHUTDOWN here to make
// sure they do get deleted.
base::PostTaskWithTraitsAndReply(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(&RemoveFiles),
base::BindOnce(&KerberosFilesHandler::OnFilesChanged,
weak_factory_.GetWeakPtr()));
}
void KerberosFilesHandler::SetFilesChangedForTesting(
base::OnceClosure callback) {
files_changed_for_testing_ = std::move(callback);
}
void KerberosFilesHandler::OnDisabledAuthNegotiateCnameLookupChanged() {
// Refresh kerberos files to adjust config for changed pref.
get_kerberos_files_.Run();
......
......@@ -40,9 +40,13 @@ class KerberosFilesHandler {
explicit KerberosFilesHandler(base::RepeatingClosure get_kerberos_files);
~KerberosFilesHandler();
// Writes the Kerberos credentials to disk asynchronously.
void SetFiles(base::Optional<std::string> krb5cc,
base::Optional<std::string> krb5conf);
// Deletes the Kerberos credentials from disk asynchronously.
void DeleteFiles();
// Sets a callback for when disk IO task posted by SetFiles has finished.
void SetFilesChangedForTesting(base::OnceClosure callback);
......
# This is for the common case of adding or renaming files. If you're doing
# structural changes, use usual OWNERS rules.
per-file BUILD.gn=*
ljusten@chromium.org
# COMPONENT: Enterprise>ActiveDirectory
// 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_KERBEROS_KERBEROS_CREDENTIALS_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_KERBEROS_KERBEROS_CREDENTIALS_MANAGER_H_
#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/authpolicy/kerberos_files_handler.h"
#include "chromeos/dbus/kerberos/kerberos_service.pb.h"
class Profile;
namespace chromeos {
class KerberosAddAccountRunner;
class KerberosCredentialsManager {
public:
using ResultCallback = base::OnceCallback<void(kerberos::ErrorType)>;
explicit KerberosCredentialsManager(Profile* profile);
~KerberosCredentialsManager();
// Adds an account for the given |principal_name| and authenticates it using
// the given |password|. Sets |principal_name| as active principal on success.
void AddAccountAndAuthenticate(std::string principal_name,
const std::string& password,
ResultCallback callback);
// Removes the Kerberos account for the account with given |principal_name|.
void RemoveAccount(std::string principal_name, ResultCallback callback);
// Sets the contents of the Kerberos configuration (krb5.conf) to |krb5_conf|
// for the account with given |principal_name|.
void SetConfig(std::string principal_name,
const std::string& krb5_conf,
ResultCallback callback);
// Gets a Kerberos ticket-granting-ticket for the account with given
// |principal_name|.
void AcquireKerberosTgt(std::string principal_name,
const std::string& password,
ResultCallback callback);
// Sets the currently active account.
kerberos::ErrorType SetActiveAccount(std::string principal_name);
private:
friend class KerberosAddAccountRunner;
// Callback on KerberosAddAccountRunner::Done.
void OnAddAccountRunnerDone(KerberosAddAccountRunner* runner,
std::string principal_name,
ResultCallback callback,
kerberos::ErrorType error);
// Callback for RemoveAccount().
void OnRemoveAccount(const std::string& principal_name,
ResultCallback callback,
const kerberos::RemoveAccountResponse& response);
// Callback for SetConfig().
void OnSetConfig(ResultCallback callback,
const kerberos::SetConfigResponse& response);
// Callback for AcquireKerberosTgt().
void OnAcquireKerberosTgt(
ResultCallback callback,
const kerberos::AcquireKerberosTgtResponse& response);
// Calls KerberosClient::GetKerberosFiles().
void GetKerberosFiles();
// Callback for GetKerberosFiles().
void OnGetKerberosFiles(const std::string& principal_name,
const kerberos::GetKerberosFilesResponse& response);
// Callback for 'KerberosFilesChanged' D-Bus signal sent by kerberosd.
void OnKerberosFilesChanged(const std::string& principal_name);
// Called when connected to 'KerberosFilesChanged' signal.
void OnSignalConnected(const std::string& interface_name,
const std::string& signal_name,
bool success);
Profile* const profile_ = nullptr;
// Called by OnSignalConnected(), puts Kerberos files where GSSAPI finds them.
KerberosFilesHandler kerberos_files_handler_;
// Handles the steps to add a Kerberos account.
std::unique_ptr<KerberosAddAccountRunner> add_account_runner_;
// Currently active principal.
std::string active_principal_name_;
base::WeakPtrFactory<KerberosCredentialsManager> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(KerberosCredentialsManager);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_KERBEROS_KERBEROS_CREDENTIALS_MANAGER_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