Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/auto_login_prompter.h" | 5 #include "chrome/browser/ui/auto_login_prompter.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/string_split.h" | 10 #include "base/string_split.h" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 #include "content/public/browser/notification_types.h" | 32 #include "content/public/browser/notification_types.h" |
| 33 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
| 34 #include "googleurl/src/gurl.h" | 34 #include "googleurl/src/gurl.h" |
| 35 #include "net/base/escape.h" | 35 #include "net/base/escape.h" |
| 36 #include "net/url_request/url_request.h" | 36 #include "net/url_request/url_request.h" |
| 37 | 37 |
| 38 using content::BrowserThread; | 38 using content::BrowserThread; |
| 39 using content::NavigationController; | 39 using content::NavigationController; |
| 40 using content::WebContents; | 40 using content::WebContents; |
| 41 | 41 |
| 42 namespace { | |
| 43 | |
| 44 bool FetchUsername(Profile* profile, std::string* output) { | |
| 45 // In an incognito window, there may not be a profile sync service and/or | |
| 46 // signin manager. | |
| 47 if (!ProfileSyncServiceFactory::GetInstance()->HasProfileSyncService( | |
| 48 profile)) { | |
| 49 return false; | |
| 50 } | |
| 51 | |
| 52 if (!TokenServiceFactory::GetForProfile(profile)->AreCredentialsValid()) | |
| 53 return false; | |
| 54 | |
| 55 SigninManager* signin_manager = | |
| 56 SigninManagerFactory::GetInstance()->GetForProfile(profile); | |
| 57 if (!signin_manager) | |
| 58 return false; | |
| 59 | |
| 60 *output = signin_manager->GetAuthenticatedUsername(); | |
| 61 return true; | |
| 62 } | |
| 63 | |
| 64 } // namespace | |
| 65 | |
| 66 AutoLoginPrompter::Params::Params() {} | |
| 67 AutoLoginPrompter::Params::~Params() {} | |
| 68 | |
| 42 AutoLoginPrompter::AutoLoginPrompter( | 69 AutoLoginPrompter::AutoLoginPrompter( |
| 43 WebContents* web_contents, | 70 WebContents* web_contents, |
| 44 const std::string& username, | 71 const Params& params) |
| 45 const std::string& args) | |
| 46 : web_contents_(web_contents), | 72 : web_contents_(web_contents), |
| 47 username_(username), | 73 params_(params) { |
| 48 args_(args) { | |
| 49 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, | 74 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| 50 content::Source<NavigationController>( | 75 content::Source<NavigationController>( |
| 51 &web_contents_->GetController())); | 76 &web_contents_->GetController())); |
| 52 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 77 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 53 content::Source<WebContents>(web_contents_)); | 78 content::Source<WebContents>(web_contents_)); |
| 54 } | 79 } |
| 55 | 80 |
| 56 AutoLoginPrompter::~AutoLoginPrompter() { | 81 AutoLoginPrompter::~AutoLoginPrompter() { |
| 57 } | 82 } |
| 58 | 83 |
| 59 // static | 84 // static |
| 60 void AutoLoginPrompter::ShowInfoBarIfPossible(net::URLRequest* request, | 85 void AutoLoginPrompter::ShowInfoBarIfPossible(net::URLRequest* request, |
| 61 int child_id, | 86 int child_id, |
| 62 int route_id) { | 87 int route_id) { |
| 63 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin)) | 88 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin)) |
| 64 return; | 89 return; |
| 65 | 90 |
| 66 // See if the response contains the X-Auto-Login header. If so, this was | 91 // See if the response contains the X-Auto-Login header. If so, this was |
| 67 // a request for a login page, and the server is allowing the browser to | 92 // a request for a login page, and the server is allowing the browser to |
| 68 // suggest auto-login, if available. | 93 // suggest auto-login, if available. |
| 69 std::string value; | 94 std::string value; |
| 70 request->GetResponseHeaderByName("X-Auto-Login", &value); | 95 request->GetResponseHeaderByName("X-Auto-Login", &value); |
| 71 if (value.empty()) | 96 Params params; |
| 72 return; | 97 if (!ParseAutoLoginHeader(value, ¶ms)) |
| 73 | |
| 74 std::vector<std::pair<std::string, std::string> > pairs; | |
| 75 if (!base::SplitStringIntoKeyValuePairs(value, '=', '&', &pairs)) | |
| 76 return; | |
| 77 | |
| 78 // Parse the information from the value string. | |
| 79 std::string realm; | |
| 80 std::string account; | |
| 81 std::string args; | |
| 82 for (size_t i = 0; i < pairs.size(); ++i) { | |
| 83 const std::pair<std::string, std::string>& pair = pairs[i]; | |
| 84 if (pair.first == "realm") { | |
| 85 realm = net::UnescapeURLComponent(pair.second, | |
| 86 net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 87 } else if (pair.first == "account") { | |
| 88 account = net::UnescapeURLComponent(pair.second, | |
| 89 net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 90 } else if (pair.first == "args") { | |
| 91 args = pair.second; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 // Currently we only accept GAIA credentials. | |
| 96 if (realm != "com.google") | |
| 97 return; | 98 return; |
| 98 | 99 |
| 99 BrowserThread::PostTask( | 100 BrowserThread::PostTask( |
| 100 BrowserThread::UI, FROM_HERE, | 101 BrowserThread::UI, FROM_HERE, |
| 101 base::Bind(&AutoLoginPrompter::ShowInfoBarUIThread, account, args, | 102 base::Bind(&ShowInfoBarUIThread, |
| 102 request->url(), child_id, route_id)); | 103 params, request->url(), child_id, route_id)); |
| 103 } | 104 } |
| 104 | 105 |
| 105 // static | 106 // static |
| 106 void AutoLoginPrompter::ShowInfoBarUIThread(const std::string& account, | 107 void AutoLoginPrompter::ShowInfoBarUIThread(const Params& params, |
| 107 const std::string& args, | |
| 108 const GURL& url, | 108 const GURL& url, |
| 109 int child_id, | 109 int child_id, |
| 110 int route_id) { | 110 int route_id) { |
| 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 112 | |
| 113 WebContents* web_contents = tab_util::GetWebContentsByID(child_id, route_id); | 112 WebContents* web_contents = tab_util::GetWebContentsByID(child_id, route_id); |
| 114 if (!web_contents) | 113 if (!web_contents) |
| 115 return; | 114 return; |
| 116 | 115 |
| 117 Profile* profile = | 116 Profile* profile = |
| 118 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 117 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 119 | 118 |
| 120 if (!profile->GetPrefs()->GetBoolean(prefs::kAutologinEnabled)) | 119 if (!profile->GetPrefs()->GetBoolean(prefs::kAutologinEnabled)) |
| 121 return; | 120 return; |
| 122 | 121 |
| 123 // In an incognito window, there may not be a profile sync service and/or | 122 Params params_copy(params); |
|
Peter Kasting
2012/06/27 17:39:05
Nit: Why not pass this in by value?
Philippe
2012/06/28 09:24:00
Done.
| |
| 124 // signin manager. | 123 #if !defined(OS_ANDROID) |
| 125 if (!ProfileSyncServiceFactory::GetInstance()->HasProfileSyncService( | 124 // On Android, the username is fetched later from the AccountManager on the |
|
Peter Kasting
2012/06/27 17:39:05
Nit: What does "later" mean? This function must b
Philippe
2012/06/28 09:24:00
I removed 'later' and made the comment clearer (I
| |
| 126 profile)) { | 125 // Java side. |
| 126 if (!FetchUsername(profile, ¶ms_copy.username)) | |
| 127 return; | 127 return; |
| 128 } | 128 #endif |
| 129 | |
| 130 if (!TokenServiceFactory::GetForProfile(profile)->AreCredentialsValid()) | |
| 131 return; | |
| 132 | |
| 133 SigninManager* signin_manager = | |
| 134 SigninManagerFactory::GetInstance()->GetForProfile(profile); | |
| 135 if (!signin_manager) | |
| 136 return; | |
| 137 | |
| 138 const std::string& username = signin_manager->GetAuthenticatedUsername(); | |
| 139 | 129 |
| 140 // Make sure that |account|, if specified, matches the logged in user. | 130 // Make sure that |account|, if specified, matches the logged in user. |
| 141 // However, |account| is usually empty. | 131 // However, |account| is usually empty. |
| 142 if (!account.empty() && (username != account)) | 132 if (!params.username.empty() && !params.account.empty() && |
| 133 params_copy.username != params.account) { | |
|
Peter Kasting
2012/06/27 17:39:05
Nit: {} not needed
Philippe
2012/06/28 09:24:00
Done.
| |
| 143 return; | 134 return; |
| 144 | 135 } |
| 145 // We can't add the infobar just yet, since we need to wait for the tab to | 136 // We can't add the infobar just yet, since we need to wait for the tab to |
| 146 // finish loading. If we don't, the info bar appears and then disappears | 137 // finish loading. If we don't, the info bar appears and then disappears |
| 147 // immediately. Create an AutoLoginPrompter instance to listen for the | 138 // immediately. Create an AutoLoginPrompter instance to listen for the |
| 148 // relevant notifications; it will delete itself. | 139 // relevant notifications; it will delete itself. |
| 149 new AutoLoginPrompter(web_contents, username, args); | 140 new AutoLoginPrompter(web_contents, params_copy); |
| 150 } | 141 } |
| 151 | 142 |
| 152 void AutoLoginPrompter::Observe(int type, | 143 void AutoLoginPrompter::Observe(int type, |
| 153 const content::NotificationSource& source, | 144 const content::NotificationSource& source, |
| 154 const content::NotificationDetails& details) { | 145 const content::NotificationDetails& details) { |
| 155 if (type == content::NOTIFICATION_LOAD_STOP) { | 146 if (type == content::NOTIFICATION_LOAD_STOP) { |
| 156 TabContents* tab_contents = TabContents::FromWebContents(web_contents_); | 147 TabContents* tab_contents = TabContents::FromWebContents(web_contents_); |
| 157 // |tab_contents| is NULL for WebContents hosted in WebDialog. | 148 // |tab_contents| is NULL for WebContents hosted in WebDialog. |
| 158 if (tab_contents) { | 149 if (tab_contents) { |
| 159 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper(); | 150 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper(); |
| 160 infobar_helper->AddInfoBar(new AutoLoginInfoBarDelegate(infobar_helper, | 151 infobar_helper->AddInfoBar(new AutoLoginInfoBarDelegate( |
| 161 username_, | 152 infobar_helper, |
|
Peter Kasting
2012/06/27 17:39:05
Nit: Strange wrapping. Put more args on this line
Philippe
2012/06/28 09:24:00
Done.
| |
| 162 args_)); | 153 params_.realm, params_.account, params_.args, params_.username)); |
| 163 } | 154 } |
| 164 } | 155 } |
| 165 // Either we couldn't add the infobar, we added the infobar, or the tab | 156 // Either we couldn't add the infobar, we added the infobar, or the tab |
| 166 // contents was destroyed before the navigation completed. In any case | 157 // contents was destroyed before the navigation completed. In any case |
| 167 // there's no reason to live further. | 158 // there's no reason to live further. |
| 168 delete this; | 159 delete this; |
| 169 } | 160 } |
| 161 | |
| 162 // static | |
| 163 bool AutoLoginPrompter::ParseAutoLoginHeader(const std::string& input, | |
| 164 Params* output) { | |
| 165 // TODO(pliard): Investigate/fix potential internationalization issue. It | |
| 166 // seems that "account" from the x-auto-login header might contain non-ASCII | |
| 167 // characters. | |
| 168 if (input.empty()) | |
| 169 return false; | |
| 170 | |
| 171 std::vector<std::pair<std::string, std::string> > pairs; | |
| 172 if (!base::SplitStringIntoKeyValuePairs(input, '=', '&', &pairs)) | |
| 173 return false; | |
| 174 | |
| 175 // Parse the information from the |input| string. | |
| 176 Params params; | |
| 177 for (size_t i = 0; i < pairs.size(); ++i) { | |
| 178 const std::pair<std::string, std::string>& pair = pairs[i]; | |
| 179 if (pair.first == "realm") { | |
| 180 params.realm = net::UnescapeURLComponent( | |
| 181 pair.second, net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 182 // Currently we only accept GAIA credentials. | |
| 183 if (params.realm != "com.google") | |
| 184 return false; | |
| 185 } else if (pair.first == "account") { | |
| 186 params.account = net::UnescapeURLComponent( | |
| 187 pair.second, net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 188 } else if (pair.first == "args") { | |
| 189 params.args = net::UnescapeURLComponent( | |
| 190 pair.second, net::UnescapeRule::URL_SPECIAL_CHARS); | |
| 191 } | |
| 192 } | |
| 193 if (params.realm.empty() || params.args.empty()) | |
| 194 return false; | |
| 195 | |
| 196 *output = params; | |
| 197 return true; | |
| 198 } | |
| OLD | NEW |