summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpalmer <palmer@chromium.org>2015-12-07 17:07:13 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-08 01:08:03 +0000
commitd4fe8211476a0bba1a347204e430aa283c2e7d7f (patch)
treef379e35049abdadbc8e5bed777d09728f12fc329
parentf32892ceebd63a5cc4b6ff6c424ae6ae575cac08 (diff)
downloadchromium_src-d4fe8211476a0bba1a347204e430aa283c2e7d7f.zip
chromium_src-d4fe8211476a0bba1a347204e430aa283c2e7d7f.tar.gz
chromium_src-d4fe8211476a0bba1a347204e430aa283c2e7d7f.tar.bz2
Do not show untrustworthy strings in the basic auth dialog.
Browser chrome should display only trustworthy or verified strings. BUG=544244 Review URL: https://codereview.chromium.org/1466473003 Cr-Commit-Position: refs/heads/master@{#363658}
-rw-r--r--chrome/app/generated_resources.grd12
-rw-r--r--chrome/app/nibs/HttpAuthLoginSheet.xib24
-rw-r--r--chrome/browser/ui/android/chrome_http_auth_handler.cc13
-rw-r--r--chrome/browser/ui/android/chrome_http_auth_handler.h5
-rw-r--r--chrome/browser/ui/android/login_prompt_android.cc6
-rw-r--r--chrome/browser/ui/cocoa/login_prompt_cocoa.h2
-rw-r--r--chrome/browser/ui/cocoa/login_prompt_cocoa.mm17
-rw-r--r--chrome/browser/ui/login/login_prompt.cc39
-rw-r--r--chrome/browser/ui/login/login_prompt.h7
-rw-r--r--chrome/browser/ui/views/login_prompt_views.cc5
-rw-r--r--chrome/browser/ui/views/login_view.cc24
-rw-r--r--chrome/browser/ui/views/login_view.h6
12 files changed, 97 insertions, 63 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 11e3cca..482a91d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3431,16 +3431,10 @@ Even if you have downloaded files from this website before, the website might ha
<message name="IDS_LOGIN_DIALOG_TITLE" desc="String to be displayed in the title bar of the login prompt dialog" formatter_data="android_java">
Authentication Required
</message>
- <message name="IDS_LOGIN_DIALOG_DESCRIPTION" desc="String to be displayed in the login prompt dialog to explain what the user needs to do">
- The server <ph name="DOMAIN">$1<ex>google.com</ex></ph> requires a username and password. The server says: <ph name="REALM">$2<ex>opaque string</ex></ph>.
+ <message name="IDS_LOGIN_DIALOG_AUTHORITY" desc="String to be displayed in the login prompt dialog to explain that the user needs to log in, and the name of the web site">
+ <ph name="DOMAIN">$1<ex>google.com</ex></ph> requires a username and password.
</message>
- <message name="IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM" desc="String to be displayed in the login prompt dialog to explain what the user needs to do">
- The server <ph name="DOMAIN">$1<ex>google.com</ex></ph> requires a username and password.
- </message>
- <message name="IDS_LOGIN_DIALOG_DESCRIPTION_PROXY" desc="String to be displayed in the proxy login prompt dialog to explain what the user needs to do">
- The proxy <ph name="DOMAIN">$1<ex>google.com</ex></ph> requires a username and password. The proxy says: <ph name="REALM">$2<ex>opaque string</ex></ph>.
- </message>
- <message name="IDS_LOGIN_DIALOG_DESCRIPTION_PROXY_NO_REALM" desc="String to be displayed in the proxy login prompt dialog to explain what the user needs to do">
+ <message name="IDS_LOGIN_DIALOG_PROXY_AUTHORITY" desc="String to be displayed in the proxy login prompt dialog to explain that the user needs to log in, and the name of the proxy">
The proxy <ph name="DOMAIN">$1<ex>google.com</ex></ph> requires a username and password.
</message>
<message name="IDS_LOGIN_DIALOG_USERNAME_FIELD" desc="The label of the username field in the login prompt dialog" formatter_data="android_java">
diff --git a/chrome/app/nibs/HttpAuthLoginSheet.xib b/chrome/app/nibs/HttpAuthLoginSheet.xib
index 892f959..762e60b 100644
--- a/chrome/app/nibs/HttpAuthLoginSheet.xib
+++ b/chrome/app/nibs/HttpAuthLoginSheet.xib
@@ -9,6 +9,7 @@
<customObject id="-2" userLabel="File's Owner" customClass="LoginHandlerSheet">
<connections>
<outlet property="cancelButton_" destination="13" id="47"/>
+ <outlet property="authorityField_" destination="53" id="52"/>
<outlet property="explanationField_" destination="41" id="45"/>
<outlet property="loginButton_" destination="11" id="46"/>
<outlet property="nameField_" destination="7" id="21"/>
@@ -20,14 +21,14 @@
<customObject id="-3" userLabel="Application"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" customClass="ConstrainedWindowCustomWindow">
<windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="196" y="388" width="400" height="200"/>
+ <rect key="contentRect" x="196" y="388" width="400" height="234"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" id="2" customClass="ConstrainedWindowCustomWindowContentView">
- <rect key="frame" x="0.0" y="0.0" width="400" height="200"/>
+ <rect key="frame" x="0.0" y="-5" width="400" height="234"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<box autoresizesSubviews="NO" transparent="YES" borderType="none" titlePosition="noTitle" id="24">
- <rect key="frame" x="105" y="58" width="283" height="74"/>
+ <rect key="frame" x="105" y="70" width="283" height="74"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<view key="contentView">
<rect key="frame" x="0.0" y="0.0" width="283" height="74"/>
@@ -66,7 +67,7 @@
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</box>
<customView id="33" customClass="GTMWidthBasedTweaker">
- <rect key="frame" x="168" y="8" width="231" height="52"/>
+ <rect key="frame" x="168" y="20" width="231" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<subviews>
<button verticalHuggingPriority="750" id="13" customClass="ConstrainedWindowButton">
@@ -100,7 +101,7 @@ DQ
</subviews>
</customView>
<customView id="34" customClass="GTMWidthBasedTweaker">
- <rect key="frame" x="20" y="62" width="89" height="68"/>
+ <rect key="frame" x="20" y="74" width="89" height="68"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" id="5">
@@ -128,7 +129,7 @@ DQ
</connections>
</customView>
<textField verticalHuggingPriority="750" id="41">
- <rect key="frame" x="18" y="139" width="365" height="17"/>
+ <rect key="frame" x="18" y="151" width="365" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="explanation" id="42">
<font key="font" metaFont="cellTitle"/>
@@ -136,8 +137,17 @@ DQ
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
+ <textField verticalHuggingPriority="750" id="53">
+ <rect key="frame" x="19" y="176" width="365" height="17"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="authority" id="54">
+ <font key="font" metaFont="cellTitle"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
<textField verticalHuggingPriority="750" id="50">
- <rect key="frame" x="17" y="167" width="353" height="19"/>
+ <rect key="frame" x="17" y="201" width="353" height="19"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="^IDS_LOGIN_DIALOG_TITLE" id="51">
<font key="font" metaFont="system" size="15"/>
diff --git a/chrome/browser/ui/android/chrome_http_auth_handler.cc b/chrome/browser/ui/android/chrome_http_auth_handler.cc
index 104de75..768558dac 100644
--- a/chrome/browser/ui/android/chrome_http_auth_handler.cc
+++ b/chrome/browser/ui/android/chrome_http_auth_handler.cc
@@ -11,6 +11,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/logging.h"
#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
#include "chrome/grit/generated_resources.h"
#include "jni/ChromeHttpAuthHandler_jni.h"
#include "ui/base/l10n/l10n_util.h"
@@ -21,10 +22,9 @@ using base::android::ConvertJavaStringToUTF16;
using base::android::ConvertUTF16ToJavaString;
using base::android::ScopedJavaLocalRef;
-ChromeHttpAuthHandler::ChromeHttpAuthHandler(const base::string16& explanation)
- : observer_(NULL),
- explanation_(explanation) {
-}
+ChromeHttpAuthHandler::ChromeHttpAuthHandler(const base::string16& authority,
+ const base::string16& explanation)
+ : observer_(nullptr), authority_(authority), explanation_(explanation) {}
ChromeHttpAuthHandler::~ChromeHttpAuthHandler() {}
@@ -81,7 +81,10 @@ void ChromeHttpAuthHandler::CancelAuth(JNIEnv* env,
ScopedJavaLocalRef<jstring> ChromeHttpAuthHandler::GetMessageBody(
JNIEnv* env,
const JavaParamRef<jobject>&) {
- return ConvertUTF16ToJavaString(env, explanation_);
+ if (explanation_.empty())
+ return ConvertUTF16ToJavaString(env, authority_);
+ return ConvertUTF16ToJavaString(
+ env, authority_ + base::ASCIIToUTF16(" ") + explanation_);
}
// static
diff --git a/chrome/browser/ui/android/chrome_http_auth_handler.h b/chrome/browser/ui/android/chrome_http_auth_handler.h
index 4450c5b..771047e 100644
--- a/chrome/browser/ui/android/chrome_http_auth_handler.h
+++ b/chrome/browser/ui/android/chrome_http_auth_handler.h
@@ -17,7 +17,8 @@
// by, e.g., showing the user a login dialog.
class ChromeHttpAuthHandler {
public:
- explicit ChromeHttpAuthHandler(const base::string16& explanation);
+ ChromeHttpAuthHandler(const base::string16& authority,
+ const base::string16& explanation);
~ChromeHttpAuthHandler();
// This must be called before using the object.
@@ -58,7 +59,7 @@ class ChromeHttpAuthHandler {
private:
LoginHandler* observer_;
base::android::ScopedJavaGlobalRef<jobject> java_chrome_http_auth_handler_;
- // e.g. "The server example.com:80 requires a username and password."
+ base::string16 authority_;
base::string16 explanation_;
DISALLOW_COPY_AND_ASSIGN(ChromeHttpAuthHandler);
diff --git a/chrome/browser/ui/android/login_prompt_android.cc b/chrome/browser/ui/android/login_prompt_android.cc
index 6bb32e2..53cfd39 100644
--- a/chrome/browser/ui/android/login_prompt_android.cc
+++ b/chrome/browser/ui/android/login_prompt_android.cc
@@ -37,7 +37,8 @@ class LoginHandlerAndroid : public LoginHandler {
}
void OnLoginModelDestroying() override {}
- void BuildViewImpl(const base::string16& explanation,
+ void BuildViewImpl(const base::string16& authority,
+ const base::string16& explanation,
LoginModelData* login_model_data) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -49,7 +50,8 @@ class LoginHandlerAndroid : public LoginHandler {
// Notify WindowAndroid that HTTP authentication is required.
if (window_helper->GetWindowAndroid()) {
- chrome_http_auth_handler_.reset(new ChromeHttpAuthHandler(explanation));
+ chrome_http_auth_handler_.reset(
+ new ChromeHttpAuthHandler(authority, explanation));
chrome_http_auth_handler_->Init();
chrome_http_auth_handler_->SetObserver(this);
chrome_http_auth_handler_->ShowDialog(
diff --git a/chrome/browser/ui/cocoa/login_prompt_cocoa.h b/chrome/browser/ui/cocoa/login_prompt_cocoa.h
index 1607da5..3724590 100644
--- a/chrome/browser/ui/cocoa/login_prompt_cocoa.h
+++ b/chrome/browser/ui/cocoa/login_prompt_cocoa.h
@@ -15,6 +15,7 @@ class LoginHandlerMac;
@private
IBOutlet NSTextField* nameField_;
IBOutlet NSSecureTextField* passwordField_;
+ IBOutlet NSTextField* authorityField_;
IBOutlet NSTextField* explanationField_;
IBOutlet NSButton* loginButton_;
IBOutlet NSButton* cancelButton_;
@@ -24,6 +25,7 @@ class LoginHandlerMac;
- (IBAction)loginPressed:(id)sender;
- (IBAction)cancelPressed:(id)sender;
- (void)autofillLogin:(NSString*)login password:(NSString*)password;
+- (void)setAuthority:(NSString*)authority;
- (void)setExplanation:(NSString*)explanation;
@end
diff --git a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
index 4ba6292..549c11a 100644
--- a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
+++ b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
@@ -52,7 +52,8 @@ class LoginHandlerMac : public LoginHandler,
void OnLoginModelDestroying() override {}
// LoginHandler:
- void BuildViewImpl(const base::string16& explanation,
+ void BuildViewImpl(const base::string16& authority,
+ const base::string16& explanation,
LoginModelData* login_model_data) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -64,6 +65,7 @@ class LoginHandlerMac : public LoginHandler,
else
ResetModel();
+ [sheet_controller_ setAuthority:base::SysUTF16ToNSString(authority)];
[sheet_controller_ setExplanation:base::SysUTF16ToNSString(explanation)];
// Scary thread safety note: This can potentially be called *after* SetAuth
@@ -180,8 +182,19 @@ LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
}
}
+- (void)setAuthority:(NSString*)authority {
+ [authorityField_ setStringValue:authority];
+
+ // Resize the text field.
+ CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:authorityField_];
+
+ NSRect newFrame = [[self window] frame];
+ newFrame.size.height += windowDelta;
+ [[self window] setFrame:newFrame display:NO];
+}
+
- (void)setExplanation:(NSString*)explanation {
- // Put in the text.
[explanationField_ setStringValue:explanation];
// Resize the text field.
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc
index 372b99e..541ef68 100644
--- a/chrome/browser/ui/login/login_prompt.cc
+++ b/chrome/browser/ui/login/login_prompt.cc
@@ -32,6 +32,7 @@
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/origin_util.h"
#include "net/base/auth.h"
#include "net/base/load_flags.h"
#include "net/base/net_util.h"
@@ -111,11 +112,6 @@ void ShowLoginPrompt(const GURL& request_url,
return;
}
- // The realm is controlled by the remote server, so there is no reason
- // to believe it is of a reasonable length.
- base::string16 elided_realm;
- gfx::ElideString(base::UTF8ToUTF16(auth_info->realm), 120, &elided_realm);
-
std::string languages;
content::WebContents* web_contents = handler->GetWebContentsForLogin();
if (web_contents) {
@@ -125,21 +121,14 @@ void ShowLoginPrompt(const GURL& request_url,
languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
}
- base::string16 authority =
- url_formatter::FormatUrlForSecurityDisplay(request_url, languages);
+ base::string16 authority = l10n_util::GetStringFUTF16(
+ auth_info->is_proxy ? IDS_LOGIN_DIALOG_PROXY_AUTHORITY
+ : IDS_LOGIN_DIALOG_AUTHORITY,
+ url_formatter::FormatUrlForSecurityDisplay(request_url, languages));
base::string16 explanation;
- if (auth_info->is_proxy) {
- explanation = elided_realm.empty()
- ? l10n_util::GetStringFUTF16(
- IDS_LOGIN_DIALOG_DESCRIPTION_PROXY_NO_REALM, authority)
- : l10n_util::GetStringFUTF16(IDS_LOGIN_DIALOG_DESCRIPTION_PROXY,
- authority, elided_realm);
- } else {
- explanation = elided_realm.empty()
- ? l10n_util::GetStringFUTF16(IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM,
- authority)
- : l10n_util::GetStringFUTF16(IDS_LOGIN_DIALOG_DESCRIPTION, authority,
- elided_realm);
+ if (!content::IsOriginSecure(request_url)) {
+ explanation =
+ l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_NON_SECURE_TRANSPORT);
}
password_manager::PasswordManager* password_manager =
@@ -150,7 +139,7 @@ void ShowLoginPrompt(const GURL& request_url,
// A WebContents in a <webview> (a GuestView type) does not have a password
// manager, but still needs to be able to show login prompts.
if (guest_view::GuestViewBase::FromWebContents(parent_contents)) {
- handler->BuildViewWithoutPasswordManager(explanation);
+ handler->BuildViewWithoutPasswordManager(authority, explanation);
return;
}
#endif
@@ -168,8 +157,8 @@ void ShowLoginPrompt(const GURL& request_url,
PasswordForm observed_form(
MakeInputForPasswordManager(request_url, auth_info));
- handler->BuildViewWithPasswordManager(explanation, password_manager,
- observed_form);
+ handler->BuildViewWithPasswordManager(authority, explanation,
+ password_manager, observed_form);
}
} // namespace
@@ -225,18 +214,20 @@ void LoginHandler::OnRequestCancelled() {
}
void LoginHandler::BuildViewWithPasswordManager(
+ const base::string16& authority,
const base::string16& explanation,
password_manager::PasswordManager* password_manager,
const autofill::PasswordForm& observed_form) {
password_manager_ = password_manager;
password_form_ = observed_form;
LoginHandler::LoginModelData model_data(password_manager, observed_form);
- BuildViewImpl(explanation, &model_data);
+ BuildViewImpl(authority, explanation, &model_data);
}
void LoginHandler::BuildViewWithoutPasswordManager(
+ const base::string16& authority,
const base::string16& explanation) {
- BuildViewImpl(explanation, nullptr);
+ BuildViewImpl(authority, explanation, nullptr);
}
WebContents* LoginHandler::GetWebContentsForLogin() const {
diff --git a/chrome/browser/ui/login/login_prompt.h b/chrome/browser/ui/login/login_prompt.h
index 4685f98..c0d5b28 100644
--- a/chrome/browser/ui/login/login_prompt.h
+++ b/chrome/browser/ui/login/login_prompt.h
@@ -70,12 +70,14 @@ class LoginHandler : public content::ResourceDispatcherHostLoginDelegate,
// Use this to build a view with password manager support. |password_manager|
// must not be null.
void BuildViewWithPasswordManager(
+ const base::string16& authority,
const base::string16& explanation,
password_manager::PasswordManager* password_manager,
const autofill::PasswordForm& observed_form);
// Use this to build a view without password manager support.
- void BuildViewWithoutPasswordManager(const base::string16& explanation);
+ void BuildViewWithoutPasswordManager(const base::string16& authority,
+ const base::string16& explanation);
// Returns the WebContents that needs authentication.
content::WebContents* GetWebContentsForLogin() const;
@@ -111,7 +113,8 @@ class LoginHandler : public content::ResourceDispatcherHostLoginDelegate,
// Implement this to initialize the underlying platform specific view. If
// |login_model_data| is not null, the contained LoginModel and PasswordForm
// can be used to register the view.
- virtual void BuildViewImpl(const base::string16& explanation,
+ virtual void BuildViewImpl(const base::string16& authority,
+ const base::string16& explanation,
LoginModelData* login_model_data) = 0;
// Sets |model_data.model| as |login_model_| and registers |this| as an
diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc
index 3e45f79..c119587 100644
--- a/chrome/browser/ui/views/login_prompt_views.cc
+++ b/chrome/browser/ui/views/login_prompt_views.cc
@@ -100,7 +100,8 @@ class LoginHandlerViews : public LoginHandler, public views::DialogDelegate {
}
// LoginHandler:
- void BuildViewImpl(const base::string16& explanation,
+ void BuildViewImpl(const base::string16& authority,
+ const base::string16& explanation,
LoginModelData* login_model_data) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -109,7 +110,7 @@ class LoginHandlerViews : public LoginHandler, public views::DialogDelegate {
// browser window, so the view may be destroyed after the password
// manager. The view listens for model destruction and unobserves
// accordingly.
- login_view_ = new LoginView(explanation, login_model_data);
+ login_view_ = new LoginView(authority, explanation, login_model_data);
// Scary thread safety note: This can potentially be called *after* SetAuth
// or CancelAuth (say, if the request was cancelled before the UI thread got
diff --git a/chrome/browser/ui/views/login_view.cc b/chrome/browser/ui/views/login_view.cc
index 78768e7..e88d3de 100644
--- a/chrome/browser/ui/views/login_view.cc
+++ b/chrome/browser/ui/views/login_view.cc
@@ -20,7 +20,8 @@ using views::GridLayout;
///////////////////////////////////////////////////////////////////////////////
// LoginView, public:
-LoginView::LoginView(const base::string16& explanation,
+LoginView::LoginView(const base::string16& authority,
+ const base::string16& explanation,
LoginHandler::LoginModelData* login_model_data)
: username_field_(new views::Textfield()),
password_field_(new views::Textfield()),
@@ -28,12 +29,14 @@ LoginView::LoginView(const base::string16& explanation,
l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_USERNAME_FIELD))),
password_label_(new views::Label(
l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_PASSWORD_FIELD))),
- message_label_(new views::Label(explanation)),
+ authority_label_(new views::Label(authority)),
+ message_label_(nullptr),
login_model_(login_model_data ? login_model_data->model : nullptr) {
password_field_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- message_label_->SetMultiLine(true);
- message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- message_label_->SetAllowCharacterBreak(true);
+
+ authority_label_->SetMultiLine(true);
+ authority_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ authority_label_->SetAllowCharacterBreak(true);
// Initialize the Grid Layout Manager used for this dialog box.
GridLayout* layout = GridLayout::CreatePanel(this);
@@ -59,7 +62,16 @@ LoginView::LoginView(const base::string16& explanation,
column_set->AddPaddingColumn(0, kTextfieldStackHorizontalSpacing);
layout->StartRow(0, single_column_view_set_id);
- layout->AddView(message_label_);
+ layout->AddView(authority_label_);
+ if (!explanation.empty()) {
+ message_label_ = new views::Label(explanation);
+ message_label_->SetMultiLine(true);
+ message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ message_label_->SetAllowCharacterBreak(true);
+ layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+ layout->StartRow(0, single_column_view_set_id);
+ layout->AddView(message_label_);
+ }
layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing);
diff --git a/chrome/browser/ui/views/login_view.h b/chrome/browser/ui/views/login_view.h
index b2cb06f..72ccaf6 100644
--- a/chrome/browser/ui/views/login_view.h
+++ b/chrome/browser/ui/views/login_view.h
@@ -24,7 +24,8 @@ class LoginView : public views::View,
// |login_model_data->model| is observed for the entire lifetime of the
// LoginView. Therefore |login_model_data->model| should not be destroyed
// before the LoginView object. |login_model_data| may be null.
- LoginView(const base::string16& explanation,
+ LoginView(const base::string16& authority,
+ const base::string16& explanation,
LoginHandler::LoginModelData* login_model_data);
~LoginView() override;
@@ -52,7 +53,8 @@ class LoginView : public views::View,
views::Label* username_label_;
views::Label* password_label_;
- // Authentication message.
+ // Authority and security state messages.
+ views::Label* authority_label_;
views::Label* message_label_;
// If not null, points to a model we need to notify of our own destruction