Add enterprise parameter to override connection policies

Add a enterprise parameter that allows for the override of:
RemoteAccessHostAllowRemoteSupportConnections
kRemoteAccessHostAllowEnterpriseRemoteSupportConnections

This feature is used by the Boca team to start CRD sessions for teachers who
are otherwise restricted by policy.

Bug: 387453296
Change-Id: I671e7d9804b2f723b70c365a360d60067e18658b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6373052
Reviewed-by: Jeroen Dhollander <jeroendh@google.com>
Commit-Queue: Dorian Brandon <dorianbrandon@google.com>
Reviewed-by: Ashutosh Singhal <macinashutosh@google.com>
Reviewed-by: April Zhou <aprilzhou@google.com>
Reviewed-by: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1440470}
diff --git a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
index 3bd7bd61..3ff12fce5 100644
--- a/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
+++ b/chrome/browser/ash/boca/spotlight/spotlight_crd_manager_impl.cc
@@ -77,6 +77,8 @@
   parameters.allow_file_transfer = false;
   parameters.show_confirmation_dialog = false;
   parameters.terminate_upon_input = false;
+  parameters.request_origin =
+      policy::SharedCrdSession::RequestOrigin::kClassManagement;
 
   crd_session_->StartCrdHost(parameters, std::move(callback),
                              base::BindOnce(&LogCrdError));
diff --git a/chrome/browser/ash/policy/remote_commands/crd/BUILD.gn b/chrome/browser/ash/policy/remote_commands/crd/BUILD.gn
index 41e10b7c..fb2bb1c8 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/BUILD.gn
+++ b/chrome/browser/ash/policy/remote_commands/crd/BUILD.gn
@@ -116,6 +116,7 @@
     "//components/session_manager/core",
     "//content/test:test_support",
     "//mojo/public/cpp/bindings",
+    "//remoting/host:enterprise_params",
     "//remoting/host/chromeos:features",
     "//remoting/host/mojom",
     "//remoting/protocol:errors",
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
index d64c8b2..001fd0cb 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
@@ -44,6 +44,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "remoting/host/chromeos/chromeos_enterprise_params.h"
 #include "remoting/host/chromeos/features.h"
 #include "remoting/host/chromeos/remote_support_host_ash.h"
 #include "remoting/host/chromeos/remoting_service.h"
@@ -361,6 +362,8 @@
   params.allow_reconnections = parameters.allow_reconnections;
   params.allow_file_transfer = parameters.allow_file_transfer;
   params.connection_dialog_required = parameters.show_confirmation_dialog;
+  params.request_origin =
+      ConvertToChromeOsEnterpriseRequestOrigin(parameters.request_origin);
   params.connection_auto_accept_timeout =
       parameters.connection_auto_accept_timeout.value_or(base::TimeDelta());
   params.maximum_session_duration =
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
index 1507fde..87baa3de 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/public/crd_session_result_codes.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "chrome/browser/ui/ash/login/mock_login_display_host.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -39,6 +40,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "remoting/host/chromeos/chromeos_enterprise_params.h"
 #include "remoting/host/chromeos/features.h"
 #include "remoting/host/mojom/remote_support.mojom.h"
 #include "remoting/protocol/errors.h"
@@ -606,6 +608,44 @@
   EXPECT_EQ(actual_parameters->authorized_helper, "the.admin@email.com");
 }
 
+TEST_F(CrdAdminSessionControllerTest,
+       ShouldPassEnterpriseAdminRequestOriginToRemotingService) {
+  InitWithNoReconnectableSession(session_controller());
+  SessionParameters parameters;
+  parameters.request_origin =
+      StartCrdSessionJobDelegate::RequestOrigin::kEnterpriseAdmin;
+
+  remoting::ChromeOsEnterpriseParams actual_parameters;
+  EXPECT_CALL(remoting_service(), StartSession)
+      .WillOnce(SaveParamAndInvokeCallback(&actual_parameters));
+
+  delegate().StartCrdHostAndGetCode(parameters, success_callback(),
+                                    error_callback(),
+                                    session_finished_callback());
+
+  EXPECT_EQ(actual_parameters.request_origin,
+            remoting::ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin);
+}
+
+TEST_F(CrdAdminSessionControllerTest,
+       ShouldPassClassManagementRequestOriginToRemotingService) {
+  InitWithNoReconnectableSession(session_controller());
+  SessionParameters parameters;
+  parameters.request_origin =
+      StartCrdSessionJobDelegate::RequestOrigin::kClassManagement;
+
+  remoting::ChromeOsEnterpriseParams actual_parameters;
+  EXPECT_CALL(remoting_service(), StartSession)
+      .WillOnce(SaveParamAndInvokeCallback(&actual_parameters));
+
+  delegate().StartCrdHostAndGetCode(parameters, success_callback(),
+                                    error_callback(),
+                                    session_finished_callback());
+
+  EXPECT_EQ(actual_parameters.request_origin,
+            remoting::ChromeOsEnterpriseRequestOrigin::kClassManagement);
+}
+
 TEST_P(CrdAdminSessionControllerTestWithBoolParams,
        ShouldPassCurtainLocalUserSessionToRemotingService) {
   InitWithNoReconnectableSession(session_controller());
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.cc
index 0800816..69c17901 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.cc
@@ -256,4 +256,28 @@
                                std::move(network_service))));
 }
 
+remoting::ChromeOsEnterpriseRequestOrigin
+ConvertToChromeOsEnterpriseRequestOrigin(
+    StartCrdSessionJobDelegate::RequestOrigin request_origin) {
+  switch (request_origin) {
+    case StartCrdSessionJobDelegate::RequestOrigin::kClassManagement:
+      return remoting::ChromeOsEnterpriseRequestOrigin::kClassManagement;
+    case StartCrdSessionJobDelegate::RequestOrigin::kEnterpriseAdmin:
+      return remoting::ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin;
+  }
+  NOTREACHED();
+}
+
+StartCrdSessionJobDelegate::RequestOrigin
+ConvertToStartCrdSessionJobDelegateRequestOrigin(
+    SharedCrdSession::RequestOrigin request_origin) {
+  switch (request_origin) {
+    case SharedCrdSession::RequestOrigin::kClassManagement:
+      return StartCrdSessionJobDelegate::RequestOrigin::kClassManagement;
+    case SharedCrdSession::RequestOrigin::kEnterpriseAdmin:
+      return StartCrdSessionJobDelegate::RequestOrigin::kEnterpriseAdmin;
+  }
+  NOTREACHED();
+}
+
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h b/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h
index 5ae49fc..8b67c72 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h
@@ -11,8 +11,11 @@
 
 #include "base/functional/callback_forward.h"
 #include "base/time/time.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
+#include "remoting/host/chromeos/chromeos_enterprise_params.h"
 
 namespace policy {
 
@@ -63,6 +66,18 @@
 void CalculateIsInManagedEnvironmentAsync(
     ManagedEnvironmentResultCallback result_callback);
 
+// Convert from `StartCrdSessionJobDelegate::RequestOrigin` to
+// `remoting::ChromeOsEnterpriseRequestOrigin`.
+remoting::ChromeOsEnterpriseRequestOrigin
+ConvertToChromeOsEnterpriseRequestOrigin(
+    StartCrdSessionJobDelegate::RequestOrigin request_origin);
+
+// Convert from `SharedCrdSession::RequestOrigin` to
+// `StartCrdSessionJobDelegate::RequestOrigin`.
+StartCrdSessionJobDelegate::RequestOrigin
+ConvertToStartCrdSessionJobDelegateRequestOrigin(
+    SharedCrdSession::RequestOrigin request_origin);
+
 }  // namespace policy
 
 #endif  // CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_CRD_REMOTE_COMMAND_UTILS_H_
diff --git a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
index fe3137c..0198b86 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
@@ -28,11 +28,13 @@
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_uma_logger.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/public/crd_session_result_codes.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
+#include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
 #include "remoting/host/chromeos/features.h"
@@ -300,6 +302,8 @@
   parameters.show_troubleshooting_tools = ShouldShowTroubleshootingTools();
   parameters.allow_reconnections = ShouldAllowReconnections();
   parameters.allow_file_transfer = ShouldAllowFileTransfer();
+  parameters.request_origin =
+      StartCrdSessionJobDelegate::RequestOrigin::kEnterpriseAdmin;
   if (ShouldAutoAcceptSession(is_in_managed_environment)) {
     parameters.connection_auto_accept_timeout = kConnectionAutoAcceptTimeout;
   }
diff --git a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
index 2d36362..89df258 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "chrome/browser/ash/policy/remote_commands/fake_cros_network_config.h"
 #include "chrome/browser/ash/policy/remote_commands/user_session_type_test_util.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
@@ -32,6 +33,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/ash/services/network_config/in_process_instance.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
+#include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/scoped_user_manager.h"
@@ -585,6 +587,15 @@
   EXPECT_EQ("email@admin.com", delegate().session_parameters().admin_email);
 }
 
+TEST_F(DeviceCommandStartCrdSessionJobTest, ShouldPassRequestOriginToDelegate) {
+  LogInAsAffiliatedUser();
+  Result result = RunJobAndWaitForResult();
+
+  EXPECT_SUCCESS(result);
+  EXPECT_EQ(StartCrdSessionJobDelegate::RequestOrigin::kEnterpriseAdmin,
+            delegate().session_parameters().request_origin);
+}
+
 TEST_F(DeviceCommandStartCrdSessionJobTest, ShouldCheckNetworkManagedStatus) {
   LogInAsKioskUser();
 
diff --git a/chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h b/chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h
index dcee5e06..894970f 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_PUBLIC_SHARED_CRD_SESSION_H_
 
 #include <memory>
+#include <optional>
 
 #include "base/functional/callback_forward.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/public/crd_session_result_codes.h"
@@ -24,6 +25,13 @@
       base::OnceCallback<void(ExtendedStartCrdSessionResultCode,
                               const std::string&)>;
 
+  // The caller who initiated the request.
+  // This should match `StartCrdSessionJobDelegate::RequestOrigin`.
+  enum class RequestOrigin {
+    kEnterpriseAdmin,
+    kClassManagement,
+  };
+
   // Session parameters used to start the CRD host.
   // This is a subset of the parameters inside of
   // `StartCrdSessionJobDelegate::SessionParameters`.
@@ -36,6 +44,7 @@
     SessionParameters(SessionParameters&&);
     SessionParameters& operator=(SessionParameters&&);
 
+    RequestOrigin request_origin;
     std::optional<std::string> viewer_email;
     bool terminate_upon_input = false;
     bool show_confirmation_dialog = false;
diff --git a/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl.cc b/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl.cc
index 9edda47..38a87587 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl.cc
@@ -11,6 +11,7 @@
 #include "base/check_is_test.h"
 #include "base/functional/bind.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_logging.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_uma_logger.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
@@ -65,6 +66,9 @@
   session_parameters.show_confirmation_dialog =
       parameters.show_confirmation_dialog;
   session_parameters.terminate_upon_input = parameters.terminate_upon_input;
+  session_parameters.request_origin =
+      ConvertToStartCrdSessionJobDelegateRequestOrigin(
+          parameters.request_origin);
 
   CRD_VLOG(1) << "Starting CRD host and retrieving CRD access code";
   delegate_->StartCrdHostAndGetCode(
diff --git a/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl_unittest.cc b/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl_unittest.cc
index 8d60d6b..7cd8239 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/shared_crd_session_impl_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/functional/callback_forward.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/public/crd_session_result_codes.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/public/shared_crd_session.h"
+#include "chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -73,6 +75,8 @@
   input_parameters.allow_file_transfer = false;
   input_parameters.show_confirmation_dialog = false;
   input_parameters.terminate_upon_input = false;
+  input_parameters.request_origin =
+      SharedCrdSession::RequestOrigin::kEnterpriseAdmin;
 
   ASSERT_FALSE(delegate().HasActiveSession());
   shared_crd_session_->StartCrdHost(input_parameters,
@@ -89,6 +93,9 @@
             output_parameters.show_confirmation_dialog);
   ASSERT_EQ(input_parameters.terminate_upon_input,
             output_parameters.terminate_upon_input);
+  ASSERT_EQ(ConvertToStartCrdSessionJobDelegateRequestOrigin(
+                input_parameters.request_origin),
+            output_parameters.request_origin);
   ASSERT_EQ("robot@account.com", output_parameters.user_name);
 }
 
@@ -96,10 +103,13 @@
   TestFuture<const std::string&> access_code_future;
   TestFuture<ExtendedStartCrdSessionResultCode, const std::string&>
       error_callback_future;
+  SharedCrdSession::SessionParameters input_parameters;
+  input_parameters.request_origin =
+      SharedCrdSession::RequestOrigin::kEnterpriseAdmin;
 
   delegate().FailWithError(
       ExtendedStartCrdSessionResultCode::kFailureCrdHostError);
-  shared_crd_session_->StartCrdHost(SharedCrdSession::SessionParameters(),
+  shared_crd_session_->StartCrdHost(input_parameters,
                                     access_code_future.GetCallback(),
                                     error_callback_future.GetCallback());
   ASSERT_TRUE(error_callback_future.Wait());
diff --git a/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h b/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
index 3918bf8..7b14745f 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
@@ -24,6 +24,12 @@
                               const std::string&)>;
   using SessionEndCallback = base::OnceCallback<void(base::TimeDelta)>;
 
+  // The caller who initiated the request.
+  enum class RequestOrigin {
+    kEnterpriseAdmin,
+    kClassManagement,
+  };
+
   // Session parameters used to start the CRD host.
   struct SessionParameters {
     SessionParameters();
@@ -36,6 +42,7 @@
 
     std::string user_name = "";
     std::optional<std::string> admin_email;
+    RequestOrigin request_origin = RequestOrigin::kEnterpriseAdmin;
     bool terminate_upon_input = false;
     bool show_confirmation_dialog = false;
     bool curtain_local_user_session = false;
diff --git a/remoting/host/chromeos/chromeos_enterprise_params.cc b/remoting/host/chromeos/chromeos_enterprise_params.cc
index 7f75e14..dcbd268 100644
--- a/remoting/host/chromeos/chromeos_enterprise_params.cc
+++ b/remoting/host/chromeos/chromeos_enterprise_params.cc
@@ -5,6 +5,7 @@
 #include "remoting/host/chromeos/chromeos_enterprise_params.h"
 
 #include "base/json/values_util.h"
+#include "base/notreached.h"
 #include "base/time/time.h"
 
 namespace remoting {
@@ -21,6 +22,39 @@
 constexpr char kConnectionDialogRequired[] = "connectionDialogRequired";
 constexpr char kConnectionAutoAcceptTimeout[] = "connectionAutoAcceptTimeout";
 constexpr char kMaximumSessionDuration[] = "maximumSessionDuration";
+constexpr char kChromeOsEnterpriseRequestOrigin[] =
+    "chromeOsEnterpriseRequestOrigin";
+constexpr char kRequestOriginClassManagement[] = "classManagement";
+constexpr char kRequestOriginEnterpriseAdmin[] = "enterpriseAdmin";
+
+ChromeOsEnterpriseRequestOrigin ConvertStringToChromeOsEnterpriseRequestOrigin(
+    const std::string& request_origin) {
+  if (request_origin == kRequestOriginClassManagement) {
+    return ChromeOsEnterpriseRequestOrigin::kClassManagement;
+  }
+  if (request_origin == kRequestOriginEnterpriseAdmin) {
+    return ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin;
+  }
+  NOTREACHED();
+}
+
+std::string ConvertChromeOsEnterpriseRequestOriginToString(
+    ChromeOsEnterpriseRequestOrigin request_origin) {
+  switch (request_origin) {
+    case ChromeOsEnterpriseRequestOrigin::kClassManagement:
+      return kRequestOriginClassManagement;
+    case ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin:
+      return kRequestOriginEnterpriseAdmin;
+  }
+}
+
+ChromeOsEnterpriseRequestOrigin GetRequestOriginOrDefault(
+    const std::string* input_request_origin,
+    ChromeOsEnterpriseRequestOrigin default_request_origin) {
+  return input_request_origin ? ConvertStringToChromeOsEnterpriseRequestOrigin(
+                                    *input_request_origin)
+                              : default_request_origin;
+}
 }  // namespace
 
 ChromeOsEnterpriseParams::ChromeOsEnterpriseParams() = default;
@@ -57,6 +91,10 @@
       dict.FindBool(kAllowFileTransfer).value_or(false);
   params.connection_dialog_required =
       dict.FindBool(kConnectionDialogRequired).value_or(false);
+  params.request_origin = GetRequestOriginOrDefault(
+      dict.FindString(kChromeOsEnterpriseRequestOrigin),
+      /* default_request_origin= */ ChromeOsEnterpriseRequestOrigin::
+          kEnterpriseAdmin);
   params.connection_auto_accept_timeout =
       base::ValueToTimeDelta(dict.Find(kConnectionAutoAcceptTimeout))
           .value_or(base::TimeDelta());
@@ -76,6 +114,8 @@
       .Set(kAllowReconnections, allow_reconnections)
       .Set(kAllowFileTransfer, allow_file_transfer)
       .Set(kConnectionDialogRequired, connection_dialog_required)
+      .Set(kChromeOsEnterpriseRequestOrigin,
+           ConvertChromeOsEnterpriseRequestOriginToString(request_origin))
       .Set(kConnectionAutoAcceptTimeout,
            base::TimeDeltaToValue(connection_auto_accept_timeout));
 }
diff --git a/remoting/host/chromeos/chromeos_enterprise_params.h b/remoting/host/chromeos/chromeos_enterprise_params.h
index 7cb233d..56571072 100644
--- a/remoting/host/chromeos/chromeos_enterprise_params.h
+++ b/remoting/host/chromeos/chromeos_enterprise_params.h
@@ -10,6 +10,12 @@
 
 namespace remoting {
 
+// The caller who initiated the request.
+enum class ChromeOsEnterpriseRequestOrigin {
+  kEnterpriseAdmin,
+  kClassManagement,
+};
+
 // ChromeOS enterprise specific parameters.
 // These parameters are not exposed through the public Mojom APIs, for security
 // reasons.
@@ -38,6 +44,7 @@
   bool allow_reconnections = false;
   bool allow_file_transfer = false;
   bool connection_dialog_required = false;
+  ChromeOsEnterpriseRequestOrigin request_origin;
 
   // Both local and remote machine configuration.
   base::TimeDelta connection_auto_accept_timeout;
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 19ac060b..68ba3a6 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -5,6 +5,7 @@
 #include "remoting/host/it2me/it2me_host.h"
 
 #include <cstddef>
+#include <cstring>
 #include <memory>
 #include <optional>
 #include <string>
@@ -93,6 +94,15 @@
 // for messages (such as session-terminate) to be sent.
 constexpr base::TimeDelta kDestroyMessagingObjectDelay = base::Seconds(2);
 
+#if BUILDFLAG(IS_CHROMEOS)
+// Enabled value for ClassManagementEnabled when host belongs to a student and
+// their screen can be viewed by a teacher.
+constexpr char kClassManagementStudent[] = "student";
+// Enabled value for ClassManagementEnabled when host belongs to a teacher and
+// they would like to access their host via another device.
+constexpr char kClassManagementTeacher[] = "teacher";
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
 // STL containers do not have a defined destruction orders for their elements.
 // Post(Delayed)Task relies on these containers so the destruction order is also
 // undefined, causing problems when there are dependencies between objects to be
@@ -506,7 +516,7 @@
   // it until after we've finished reading the rest of the policies and started
   // the connection process.
   remote_support_connections_allowed_ =
-      policies.FindBool(GetRemoteSupportPolicyKey()).value_or(true);
+      RemoteSupportConnectionsAllowed(policies);
 
   const base::Value::List* host_domain_list =
       policies.FindList(policy::key::kRemoteAccessHostDomainList);
@@ -927,19 +937,38 @@
   }
 }
 
-const char* It2MeHost::GetRemoteSupportPolicyKey() const {
+bool It2MeHost::RemoteSupportConnectionsAllowed(
+    const base::Value::Dict& policies) {
 #if BUILDFLAG(IS_CHROMEOS)
   // The policy to disallow remote support connections
   // (RemoteAccessHostAllowRemoteSupportConnections) does not apply to support
-  // sessions initiated by the enterprise admin via a RemoteCommand. This case
-  // is handled specifically by the policy to disallow enterprise remote support
-  // connections (RemoteAccessHostAllowEnterpriseRemoteSupportConnections).
+  // sessions initiated by the enterprise admin via a RemoteCommand or by Class
+  // tools. These two cases are handled specifically by the policy to disallow
+  // enterprise remote support connections
+  // (RemoteAccessHostAllowEnterpriseRemoteSupportConnections) and the policy
+  // to disallow teachers from viewing student screens
+  // (ClassManagementEnabled).
   if (is_enterprise_session()) {
-    return policy::key::
-        kRemoteAccessHostAllowEnterpriseRemoteSupportConnections;
+    switch (chrome_os_enterprise_params_->request_origin) {
+      case remoting::ChromeOsEnterpriseRequestOrigin::kClassManagement:
+        if (const std::string* class_management_enabled_value =
+                policies.FindString(policy::key::kClassManagementEnabled)) {
+          return *class_management_enabled_value == kClassManagementStudent ||
+                 *class_management_enabled_value == kClassManagementTeacher;
+        }
+        return false;
+      case remoting::ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin:
+        return policies
+            .FindBool(
+                policy::key::
+                    kRemoteAccessHostAllowEnterpriseRemoteSupportConnections)
+            .value_or(true);
+    }
   }
 #endif
-  return policy::key::kRemoteAccessHostAllowRemoteSupportConnections;
+  return policies
+      .FindBool(policy::key::kRemoteAccessHostAllowRemoteSupportConnections)
+      .value_or(true);
 }
 
 It2MeHostFactory::It2MeHostFactory() = default;
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index 6e2e9941..c1745a6 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -225,9 +225,8 @@
       const std::string& remote_jid,
       protocol::ValidatingAuthenticator::ResultCallback result_callback);
 
-  // Determines the policy key used to determine whether the remote support
-  // connection is allowed. Enterprise connections use a separate policy.
-  const char* GetRemoteSupportPolicyKey() const;
+  // Determines if remote support connections are allowed by policy.
+  bool RemoteSupportConnectionsAllowed(const base::Value::Dict& policies);
 
   // Indicates whether the session allows a ChromeOS admin to reconnect.
   bool SessionSupportsReconnections() const;
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc
index 5417fa8..3587104 100644
--- a/remoting/host/it2me/it2me_host_unittest.cc
+++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -113,6 +113,12 @@
     scoped_refptr<HostStatusMonitor>) {
   return std::make_unique<HostEventReporterStub>();
 }
+
+ChromeOsEnterpriseParams GetDefaultEnterpriseParamsWithRequestOrigin() {
+  ChromeOsEnterpriseParams params;
+  params.request_origin = ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin;
+  return params;
+}
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace
@@ -987,7 +993,8 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 TEST_F(It2MeHostTest, ConnectRespectsSuppressDialogsParameter) {
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.suppress_user_dialogs = true;
   StartHost(std::move(params));
 
@@ -997,7 +1004,8 @@
 }
 
 TEST_F(It2MeHostTest, ConnectRespectsSuppressNotificationsParameter) {
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.suppress_notifications = true;
   StartHost(std::move(params));
 
@@ -1006,7 +1014,8 @@
 }
 
 TEST_F(It2MeHostTest, ConnectRespectsTerminateUponInputParameter) {
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.terminate_upon_input = true;
   StartHost(std::move(params));
 
@@ -1020,7 +1029,8 @@
 }
 
 TEST_F(It2MeHostTest, ConnectRespectsMaximumSessionDurationParameter) {
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.maximum_session_duration = base::Hours(8);
   StartHost(std::move(params));
 
@@ -1029,7 +1039,8 @@
 }
 
 TEST_F(It2MeHostTest, ConnectRespectsEnableCurtainingParameter) {
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.curtain_local_user_session = true;
   StartHost(std::move(params));
 
@@ -1046,7 +1057,8 @@
   SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
                 base::Value(true)}});
 
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.allow_file_transfer = true;
   StartHost(std::move(params));
 
@@ -1057,7 +1069,8 @@
   SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
                 base::Value(false)}});
 
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.allow_file_transfer = true;
   StartHost(std::move(params));
 
@@ -1077,7 +1090,8 @@
 TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyNotSet) {
   SetPolicies({});
 
-  ChromeOsEnterpriseParams params;
+  ChromeOsEnterpriseParams params(
+      GetDefaultEnterpriseParamsWithRequestOrigin());
   params.allow_file_transfer = true;
   StartHost(std::move(params));
 
@@ -1095,7 +1109,7 @@
   SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
                 base::Value(false)}});
 
-  StartHost(ChromeOsEnterpriseParams());
+  StartHost(GetDefaultEnterpriseParamsWithRequestOrigin());
   ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
 
   ShutdownHost();
@@ -1107,7 +1121,7 @@
   SetPolicies({{policy::key::kRemoteAccessHostDomainList,
                 MakeList({"other-domain.com"})}});
 
-  StartHost(ChromeOsEnterpriseParams());
+  StartHost(GetDefaultEnterpriseParamsWithRequestOrigin());
   ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
 
   ShutdownHost();
@@ -1122,7 +1136,7 @@
       {{policy::key::kRemoteAccessHostAllowEnterpriseRemoteSupportConnections,
         base::Value(false)}});
 
-  StartHost(ChromeOsEnterpriseParams());
+  StartHost(GetDefaultEnterpriseParamsWithRequestOrigin());
   ASSERT_EQ(It2MeHostState::kError, last_host_state_);
   ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
 }
@@ -1139,7 +1153,7 @@
 }
 
 TEST_F(It2MeHostTest, EnterpriseSessionsShouldNotDisconnectOnPolicyChange) {
-  StartHost(ChromeOsEnterpriseParams());
+  StartHost(GetDefaultEnterpriseParamsWithRequestOrigin());
   const It2MeHostState initial_state = last_host_state_;
   ASSERT_EQ(initial_state, It2MeHostState::kReceivedAccessCode);
 
@@ -1151,6 +1165,50 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(last_host_state_, initial_state);
 }
+
+TEST_F(It2MeHostTest, EnterpriseClassManagementSessionsSucceedAsAStudent) {
+  SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
+                base::Value(false)},
+               {policy::key::kClassManagementEnabled, base::Value("student")}});
+
+  ChromeOsEnterpriseParams params;
+  params.request_origin = ChromeOsEnterpriseRequestOrigin::kClassManagement;
+  StartHost(params);
+  ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
+}
+
+TEST_F(It2MeHostTest, EnterpriseClassManagementSessionsSucceedAsATeacher) {
+  SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
+                base::Value(false)},
+               {policy::key::kClassManagementEnabled, base::Value("teacher")}});
+
+  ChromeOsEnterpriseParams params;
+  params.request_origin = ChromeOsEnterpriseRequestOrigin::kClassManagement;
+  StartHost(params);
+  ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
+}
+
+TEST_F(
+    It2MeHostTest,
+    EnterpriseClassManagementSessionsFailsWhenClassManagementPolicyDisabled) {
+  SetPolicies(
+      {{policy::key::kClassManagementEnabled, base::Value("disabled")}});
+
+  ChromeOsEnterpriseParams params;
+  params.request_origin = ChromeOsEnterpriseRequestOrigin::kClassManagement;
+  StartHost(params);
+  ASSERT_EQ(It2MeHostState::kError, last_host_state_);
+  ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
+}
+
+TEST_F(It2MeHostTest,
+       EnterpriseClassManagementSessionsFailsWhenClassManagementPolicyUnset) {
+  ChromeOsEnterpriseParams params;
+  params.request_origin = ChromeOsEnterpriseRequestOrigin::kClassManagement;
+  StartHost(params);
+  ASSERT_EQ(It2MeHostState::kError, last_host_state_);
+  ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
+}
 #endif
 
 }  // namespace remoting