1 // Copyright 2020 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.
4 
5 #include "chrome/browser/ui/webui/chromeos/onc_import_message_handler.h"
6 
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/values.h"
11 #include "chrome/browser/chromeos/profiles/profile_helper.h"
12 #include "chrome/browser/net/nss_context.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
15 #include "chromeos/network/onc/onc_parsed_certificates.h"
16 #include "chromeos/network/onc/onc_utils.h"
17 #include "components/onc/onc_constants.h"
18 #include "components/policy/core/browser/policy_conversions.h"
19 #include "content/public/browser/browser_task_traits.h"
20 #include "content/public/browser/browser_thread.h"
21 
22 namespace chromeos {
23 
24 OncImportMessageHandler::OncImportMessageHandler() = default;
25 
26 OncImportMessageHandler::~OncImportMessageHandler() = default;
27 
RegisterMessages()28 void OncImportMessageHandler::RegisterMessages() {
29   web_ui()->RegisterMessageCallback(
30       "importONC", base::BindRepeating(&OncImportMessageHandler::OnImportONC,
31                                        base::Unretained(this)));
32 }
33 
Respond(const std::string & callback_id,const std::string & result,bool is_error)34 void OncImportMessageHandler::Respond(const std::string& callback_id,
35                                       const std::string& result,
36                                       bool is_error) {
37   base::Value response(base::Value::Type::LIST);
38   response.Append(result);
39   response.Append(is_error);
40   ResolveJavascriptCallback(base::Value(callback_id), response);
41 }
42 
OnImportONC(const base::ListValue * list)43 void OncImportMessageHandler::OnImportONC(const base::ListValue* list) {
44   CHECK_EQ(2u, list->GetSize());
45   std::string callback_id, onc_blob;
46   CHECK(list->GetString(0, &callback_id));
47   CHECK(list->GetString(1, &onc_blob));
48   AllowJavascript();
49   GetNSSCertDatabaseForProfile(
50       Profile::FromWebUI(web_ui()),
51       base::BindOnce(&OncImportMessageHandler::ImportONCToNSSDB,
52                      weak_factory_.GetWeakPtr(), callback_id, onc_blob));
53 }
54 
ImportONCToNSSDB(const std::string & callback_id,const std::string & onc_blob,net::NSSCertDatabase * nssdb)55 void OncImportMessageHandler::ImportONCToNSSDB(const std::string& callback_id,
56                                                const std::string& onc_blob,
57                                                net::NSSCertDatabase* nssdb) {
58   const user_manager::User* user =
59       ProfileHelper::Get()->GetUserByProfile(Profile::FromWebUI(web_ui()));
60   if (!user) {
61     Respond(callback_id, "User not found.", /*is_error=*/true);
62     return;
63   }
64 
65   std::string result;
66   bool has_error = false;
67 
68   ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_USER_IMPORT;
69   base::ListValue network_configs;
70   base::DictionaryValue global_network_config;
71   base::ListValue certificates;
72   if (!onc::ParseAndValidateOncForImport(
73           onc_blob, onc_source, /*passphrase=*/std::string(), &network_configs,
74           &global_network_config, &certificates)) {
75     has_error = true;
76     result += "Errors occurred during ONC parsing.\n";
77   }
78 
79   std::string import_error;
80   int num_networks_imported =
81       onc::ImportNetworksForUser(user, network_configs, &import_error);
82   if (!import_error.empty()) {
83     has_error = true;
84     result += "Error importing networks: " + import_error + "\n";
85   }
86   result +=
87       base::StringPrintf("Networks imported: %d\n", num_networks_imported);
88   if (certificates.GetList().empty()) {
89     if (!num_networks_imported)
90       has_error = true;
91     Respond(callback_id, result, has_error);
92     return;
93   }
94 
95   auto cert_importer = std::make_unique<onc::CertificateImporterImpl>(
96       content::GetIOThreadTaskRunner({}), nssdb);
97   auto certs = std::make_unique<onc::OncParsedCertificates>(certificates);
98   if (certs->has_error()) {
99     has_error = true;
100     result += "Some certificates could not be parsed.\n";
101   }
102   cert_importer->ImportAllCertificatesUserInitiated(
103       certs->server_or_authority_certificates(), certs->client_certificates(),
104       base::BindOnce(&OncImportMessageHandler::OnCertificatesImported,
105                      weak_factory_.GetWeakPtr(), std::move(cert_importer),
106                      callback_id, result, has_error));
107 }
108 
OnCertificatesImported(std::unique_ptr<onc::CertificateImporterImpl> cert_importer,const std::string & callback_id,const std::string & previous_result,bool has_error,bool cert_import_success)109 void OncImportMessageHandler::OnCertificatesImported(
110     std::unique_ptr<onc::CertificateImporterImpl> cert_importer,
111     const std::string& callback_id,
112     const std::string& previous_result,
113     bool has_error,
114     bool cert_import_success) {
115   std::string result = previous_result;
116   if (!cert_import_success) {
117     has_error = true;
118     result += "Some certificates couldn't be imported.\n";
119   }
120   Respond(callback_id, result, has_error);
121   // |cert_importer| will be destroyed when the callback exits.
122 }
123 
124 }  // namespace chromeos
125