Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2012 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/chromeos/enrollment_dialog_view.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/browser/profiles/profile_manager.h"
     12 #include "chrome/browser/ui/browser_finder.h"
     13 #include "chrome/browser/ui/browser_navigator.h"
     14 #include "chrome/grit/generated_resources.h"
     15 #include "chromeos/network/client_cert_util.h"
     16 #include "chromeos/network/managed_network_configuration_handler.h"
     17 #include "chromeos/network/network_event_log.h"
     18 #include "chromeos/network/network_state.h"
     19 #include "chromeos/network/network_state_handler.h"
     20 #include "extensions/browser/extension_host.h"
     21 #include "extensions/common/constants.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 #include "ui/base/page_transition_types.h"
     24 #include "ui/views/controls/label.h"
     25 #include "ui/views/layout/grid_layout.h"
     26 #include "ui/views/layout/layout_constants.h"
     27 #include "ui/views/widget/widget.h"
     28 #include "ui/views/window/dialog_delegate.h"
     29 
     30 namespace chromeos {
     31 
     32 namespace {
     33 
     34 // Default width/height of the dialog.
     35 const int kDefaultWidth = 350;
     36 const int kDefaultHeight = 100;
     37 
     38 ////////////////////////////////////////////////////////////////////////////////
     39 // Dialog for certificate enrollment. This displays the content from the
     40 // certificate enrollment URI.
     41 class EnrollmentDialogView : public views::DialogDelegateView {
     42  public:
     43   virtual ~EnrollmentDialogView();
     44 
     45   static void ShowDialog(gfx::NativeWindow owning_window,
     46                          const std::string& network_name,
     47                          Profile* profile,
     48                          const GURL& target_uri,
     49                          const base::Closure& connect);
     50 
     51   // views::DialogDelegateView overrides
     52   virtual int GetDialogButtons() const OVERRIDE;
     53   virtual bool Accept() OVERRIDE;
     54   virtual void OnClosed() OVERRIDE;
     55   virtual base::string16 GetDialogButtonLabel(
     56       ui::DialogButton button) const OVERRIDE;
     57 
     58   // views::WidgetDelegate overrides
     59   virtual ui::ModalType GetModalType() const OVERRIDE;
     60   virtual base::string16 GetWindowTitle() const OVERRIDE;
     61 
     62   // views::View overrides
     63   virtual gfx::Size GetPreferredSize() const OVERRIDE;
     64 
     65  private:
     66   EnrollmentDialogView(const std::string& network_name,
     67                        Profile* profile,
     68                        const GURL& target_uri,
     69                        const base::Closure& connect);
     70   void InitDialog();
     71 
     72   bool accepted_;
     73   std::string network_name_;
     74   Profile* profile_;
     75   GURL target_uri_;
     76   base::Closure connect_;
     77   bool added_cert_;
     78 };
     79 
     80 ////////////////////////////////////////////////////////////////////////////////
     81 // EnrollmentDialogView implementation.
     82 
     83 EnrollmentDialogView::EnrollmentDialogView(const std::string& network_name,
     84                                            Profile* profile,
     85                                            const GURL& target_uri,
     86                                            const base::Closure& connect)
     87     : accepted_(false),
     88       network_name_(network_name),
     89       profile_(profile),
     90       target_uri_(target_uri),
     91       connect_(connect),
     92       added_cert_(false) {
     93 }
     94 
     95 EnrollmentDialogView::~EnrollmentDialogView() {
     96 }
     97 
     98 // static
     99 void EnrollmentDialogView::ShowDialog(gfx::NativeWindow owning_window,
    100                                       const std::string& network_name,
    101                                       Profile* profile,
    102                                       const GURL& target_uri,
    103                                       const base::Closure& connect) {
    104   EnrollmentDialogView* dialog_view =
    105       new EnrollmentDialogView(network_name, profile, target_uri, connect);
    106   views::DialogDelegate::CreateDialogWidget(dialog_view, NULL, owning_window);
    107   dialog_view->InitDialog();
    108   views::Widget* widget = dialog_view->GetWidget();
    109   DCHECK(widget);
    110   widget->Show();
    111 }
    112 
    113 int EnrollmentDialogView::GetDialogButtons() const {
    114   return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
    115 }
    116 
    117 bool EnrollmentDialogView::Accept() {
    118   accepted_ = true;
    119   return true;
    120 }
    121 
    122 void EnrollmentDialogView::OnClosed() {
    123   if (!accepted_)
    124     return;
    125   chrome::NavigateParams params(profile_,
    126                                 GURL(target_uri_),
    127                                 ui::PAGE_TRANSITION_LINK);
    128   params.disposition = NEW_FOREGROUND_TAB;
    129   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    130   chrome::Navigate(&params);
    131 }
    132 
    133 base::string16 EnrollmentDialogView::GetDialogButtonLabel(
    134     ui::DialogButton button) const {
    135   if (button == ui::DIALOG_BUTTON_OK)
    136     return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_BUTTON);
    137   return views::DialogDelegateView::GetDialogButtonLabel(button);
    138 }
    139 
    140 ui::ModalType EnrollmentDialogView::GetModalType() const {
    141   return ui::MODAL_TYPE_SYSTEM;
    142 }
    143 
    144 base::string16 EnrollmentDialogView::GetWindowTitle() const {
    145   return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_TITLE);
    146 }
    147 
    148 gfx::Size EnrollmentDialogView::GetPreferredSize() const {
    149   return gfx::Size(kDefaultWidth, kDefaultHeight);
    150 }
    151 
    152 void EnrollmentDialogView::InitDialog() {
    153   added_cert_ = false;
    154   // Create the views and layout manager and set them up.
    155   views::Label* label = new views::Label(
    156       l10n_util::GetStringFUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_INSTRUCTIONS,
    157                                  base::UTF8ToUTF16(network_name_)));
    158   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    159   label->SetMultiLine(true);
    160   label->SetAllowCharacterBreak(true);
    161 
    162   views::GridLayout* grid_layout = views::GridLayout::CreatePanel(this);
    163   SetLayoutManager(grid_layout);
    164 
    165   views::ColumnSet* columns = grid_layout->AddColumnSet(0);
    166   columns->AddColumn(views::GridLayout::FILL,  // Horizontal resize.
    167                      views::GridLayout::FILL,  // Vertical resize.
    168                      1,   // Resize weight.
    169                      views::GridLayout::USE_PREF,  // Size type.
    170                      0,   // Ignored for USE_PREF.
    171                      0);  // Minimum size.
    172   columns = grid_layout->AddColumnSet(1);
    173   columns->AddPaddingColumn(
    174       0, views::kUnrelatedControlHorizontalSpacing);
    175   columns->AddColumn(views::GridLayout::LEADING,  // Horizontal leading.
    176                      views::GridLayout::FILL,     // Vertical resize.
    177                      1,   // Resize weight.
    178                      views::GridLayout::USE_PREF,  // Size type.
    179                      0,   // Ignored for USE_PREF.
    180                      0);  // Minimum size.
    181 
    182   grid_layout->StartRow(0, 0);
    183   grid_layout->AddView(label);
    184   grid_layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
    185   grid_layout->Layout(this);
    186 }
    187 
    188 ////////////////////////////////////////////////////////////////////////////////
    189 // Handler for certificate enrollment.
    190 
    191 class DialogEnrollmentDelegate {
    192  public:
    193   // |owning_window| is the window that will own the dialog.
    194   DialogEnrollmentDelegate(gfx::NativeWindow owning_window,
    195                            const std::string& network_name,
    196                            Profile* profile);
    197   ~DialogEnrollmentDelegate();
    198 
    199   // EnrollmentDelegate overrides
    200   bool Enroll(const std::vector<std::string>& uri_list,
    201               const base::Closure& connect);
    202 
    203  private:
    204   gfx::NativeWindow owning_window_;
    205   std::string network_name_;
    206   Profile* profile_;
    207 
    208   DISALLOW_COPY_AND_ASSIGN(DialogEnrollmentDelegate);
    209 };
    210 
    211 DialogEnrollmentDelegate::DialogEnrollmentDelegate(
    212     gfx::NativeWindow owning_window,
    213     const std::string& network_name,
    214     Profile* profile) : owning_window_(owning_window),
    215                         network_name_(network_name),
    216                         profile_(profile) {}
    217 
    218 DialogEnrollmentDelegate::~DialogEnrollmentDelegate() {}
    219 
    220 bool DialogEnrollmentDelegate::Enroll(const std::vector<std::string>& uri_list,
    221                                       const base::Closure& post_action) {
    222   // Keep the closure for later activation if we notice that
    223   // a certificate has been added.
    224 
    225   // TODO(gspencer): Do something smart with the closure.  At the moment it is
    226   // being ignored because we don't know when the enrollment tab is closed.
    227   // http://crosbug.com/30422
    228   for (std::vector<std::string>::const_iterator iter = uri_list.begin();
    229        iter != uri_list.end(); ++iter) {
    230     GURL uri(*iter);
    231     if (uri.IsStandard() || uri.scheme() == extensions::kExtensionScheme) {
    232       // If this is a "standard" scheme, like http, ftp, etc., then open that in
    233       // the enrollment dialog.
    234       NET_LOG_EVENT("Showing enrollment dialog", network_name_);
    235       EnrollmentDialogView::ShowDialog(owning_window_,
    236                                        network_name_,
    237                                        profile_,
    238                                        uri, post_action);
    239       return true;
    240     }
    241     NET_LOG_DEBUG("Nonstandard URI: " + uri.spec(), network_name_);
    242   }
    243 
    244   // No appropriate scheme was found.
    245   NET_LOG_ERROR("No usable enrollment URI", network_name_);
    246   return false;
    247 }
    248 
    249 void EnrollmentComplete(const std::string& service_path) {
    250   NET_LOG_USER("Enrollment Complete", service_path);
    251 }
    252 
    253 }  // namespace
    254 
    255 ////////////////////////////////////////////////////////////////////////////////
    256 // Factory function.
    257 
    258 namespace enrollment {
    259 
    260 bool CreateDialog(const std::string& service_path,
    261                   gfx::NativeWindow owning_window) {
    262   const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
    263       GetNetworkState(service_path);
    264   if (!network) {
    265     NET_LOG_ERROR("Enrolling Unknown network", service_path);
    266     return false;
    267   }
    268   Browser* browser = chrome::FindBrowserWithWindow(owning_window);
    269   Profile* profile =
    270       browser ? browser->profile() : ProfileManager::GetPrimaryUserProfile();
    271   std::string username_hash = ProfileHelper::GetUserIdHashFromProfile(profile);
    272 
    273   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
    274   const base::DictionaryValue* policy =
    275       NetworkHandler::Get()
    276           ->managed_network_configuration_handler()
    277           ->FindPolicyByGUID(username_hash, network->guid(), &onc_source);
    278 
    279   // We skip certificate patterns for device policy ONC so that an unmanaged
    280   // user can't get to the place where a cert is presented for them
    281   // involuntarily.
    282   if (!policy || onc_source == onc::ONC_SOURCE_DEVICE_POLICY)
    283     return false;
    284 
    285   client_cert::ClientCertConfig cert_config;
    286   OncToClientCertConfig(*policy, &cert_config);
    287 
    288   if (cert_config.client_cert_type != onc::client_cert::kPattern)
    289     return false;
    290 
    291   if (cert_config.pattern.Empty())
    292     NET_LOG_ERROR("Certificate pattern is empty", service_path);
    293 
    294   if (cert_config.pattern.enrollment_uri_list().empty()) {
    295     NET_LOG_EVENT("No enrollment URIs", service_path);
    296     return false;
    297   }
    298 
    299   NET_LOG_USER("Enrolling", service_path);
    300 
    301   DialogEnrollmentDelegate* enrollment =
    302       new DialogEnrollmentDelegate(owning_window, network->name(), profile);
    303   return enrollment->Enroll(cert_config.pattern.enrollment_uri_list(),
    304                             base::Bind(&EnrollmentComplete, service_path));
    305 }
    306 
    307 }  // namespace enrollment
    308 
    309 }  // namespace chromeos
    310