OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/chromeos/arc/arc_auth_service.h" | 5 #include "chrome/browser/chromeos/arc/arc_auth_service.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/strings/string_split.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "chrome/browser/profiles/profile.h" | |
13 #include "components/arc/arc_bridge_service.h" | |
14 #include "google_apis/gaia/gaia_constants.h" | |
15 #include "google_apis/gaia/gaia_urls.h" | |
16 #include "net/http/http_status_code.h" | |
17 #include "net/url_request/url_fetcher.h" | |
18 | |
9 namespace arc { | 19 namespace arc { |
10 | 20 |
21 namespace { | |
22 | |
23 const char kClientId[] = | |
24 "1070009224336-sdh77n7uot3oc99ais00jmuft6sk2fg9.apps.googleusercontent.com"; | |
elijahtaylor1
2016/01/26 01:02:14
what client ID is this?
khmel
2016/01/26 01:42:04
This is GMS Core Client id. I renamed for better r
| |
25 const char kCookiePartSecure[] = "secure"; | |
26 const char kCookiePartHttpOnly[] = "httponly"; | |
27 const char kCookiePartCodePrefix[] = "oauth_code="; | |
28 const int kCookiePartCodePrefixLength = arraysize(kCookiePartCodePrefix) - 1; | |
29 | |
30 // Weak pointer. This class is owned by ArcServiceManager. | |
31 ArcAuthService* g_arc_auth_service = nullptr; | |
32 | |
33 static bool CookiePartsContains(const std::vector<std::string>& parts, | |
34 const char* part) { | |
35 for (std::vector<std::string>::const_iterator it = parts.begin(); | |
36 it != parts.end(); ++it) { | |
37 if (base::LowerCaseEqualsASCII(*it, part)) | |
elijahtaylor1
2016/01/26 01:02:14
I'm no expert, but there is disagreement on whethe
khmel
2016/01/26 01:42:04
I mentioned earlier that some code is taken from h
| |
38 return true; | |
39 } | |
40 return false; | |
41 } | |
42 | |
43 } // namespace | |
44 | |
11 ArcAuthService::ArcAuthService(ArcBridgeService* bridge_service) | 45 ArcAuthService::ArcAuthService(ArcBridgeService* bridge_service) |
12 : ArcService(bridge_service), binding_(this) { | 46 : ArcService(bridge_service), binding_(this) { |
47 DCHECK(!g_arc_auth_service); | |
48 g_arc_auth_service = this; | |
49 | |
13 arc_bridge_service()->AddObserver(this); | 50 arc_bridge_service()->AddObserver(this); |
14 } | 51 } |
15 | 52 |
16 ArcAuthService::~ArcAuthService() { | 53 ArcAuthService::~ArcAuthService() { |
17 arc_bridge_service()->RemoveObserver(this); | 54 arc_bridge_service()->RemoveObserver(this); |
55 | |
56 DCHECK(g_arc_auth_service == this); | |
57 g_arc_auth_service = nullptr; | |
58 } | |
59 | |
60 // static | |
61 ArcAuthService* ArcAuthService::Get() { | |
62 DCHECK(g_arc_auth_service); | |
63 DCHECK(g_arc_auth_service->thread_checker_.CalledOnValidThread()); | |
elijahtaylor1
2016/01/26 01:02:14
I wonder if this pointer should be managed by ArcA
khmel
2016/01/26 01:42:04
After recent ArcServiceManager refactoring, it con
| |
64 return g_arc_auth_service; | |
18 } | 65 } |
19 | 66 |
20 void ArcAuthService::OnAuthInstanceReady() { | 67 void ArcAuthService::OnAuthInstanceReady() { |
21 arc::AuthHostPtr host; | 68 arc::AuthHostPtr host; |
22 binding_.Bind(GetProxy(&host)); | 69 binding_.Bind(GetProxy(&host)); |
23 arc_bridge_service()->auth_instance()->Init(std::move(host)); | 70 arc_bridge_service()->auth_instance()->Init(std::move(host)); |
24 } | 71 } |
25 | 72 |
73 std::string ArcAuthService::GetAuthToken() { | |
74 DCHECK(thread_checker_.CalledOnValidThread()); | |
75 std::string auth_token; | |
76 auth_token_.swap(auth_token); | |
77 return auth_token; | |
78 } | |
79 | |
26 void ArcAuthService::GetAuthCode(const GetAuthCodeCallback& callback) { | 80 void ArcAuthService::GetAuthCode(const GetAuthCodeCallback& callback) { |
27 // TODO(victorhsieh): request auth code from LSO (crbug.com/571146). | 81 DCHECK(thread_checker_.CalledOnValidThread()); |
28 callback.Run(mojo::String("fake auth code from ArcAuthService in Chrome")); | 82 callback.Run(mojo::String(GetAuthToken())); |
83 } | |
84 | |
85 void ArcAuthService::SetProfile(Profile* profile) { | |
86 DCHECK(profile == nullptr || profile != profile_); | |
87 DCHECK(thread_checker_.CalledOnValidThread()); | |
88 | |
89 ArcBridgeService::Get()->Shutdown(); | |
90 if (state_ != State::DISABLE) { | |
91 auth_fetcher_.reset(); | |
92 state_ = State::DISABLE; | |
93 FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_)); | |
94 } | |
95 | |
96 profile_ = profile; | |
97 | |
98 // TODO(khmel). At this moment UI to handle ARC OptIn is not ready yet. Assume | |
99 // we opted in by default. When UI is ready, this should be synced with | |
100 // user's prefs. | |
101 if (profile_ != nullptr) | |
102 FetchToken(); | |
103 } | |
104 | |
105 void ArcAuthService::AddObserver(Observer* observer) { | |
106 DCHECK(thread_checker_.CalledOnValidThread()); | |
107 observer_list_.AddObserver(observer); | |
108 } | |
109 | |
110 void ArcAuthService::RemoveObserver(Observer* observer) { | |
111 DCHECK(thread_checker_.CalledOnValidThread()); | |
112 observer_list_.RemoveObserver(observer); | |
113 } | |
114 | |
115 void ArcAuthService::SetAuthTokenAndStartArc(const std::string auth_token) { | |
116 DCHECK(thread_checker_.CalledOnValidThread()); | |
117 DCHECK(!auth_token.empty()); | |
118 DCHECK(state_ != State::ENABLE); | |
119 | |
120 auth_fetcher_.reset(); | |
121 auth_token_ = auth_token; | |
122 state_ = State::ENABLE; | |
123 | |
124 ArcBridgeService::Get()->HandleStartup(); | |
125 FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_)); | |
126 } | |
127 | |
128 // static | |
129 GURL ArcAuthService::CreateURL(Profile* profile) { | |
130 DCHECK(profile != nullptr); | |
131 | |
132 std::string query_string = base::StringPrintf( | |
133 "?scope=%s&client_id=%s&email=%s", GaiaConstants::kOAuth1LoginScope, | |
elijahtaylor1
2016/01/26 01:02:14
please make sure to get approval from an OWNER fro
khmel
2016/01/26 01:42:04
Ok, I will add someone.
| |
134 kClientId, profile->GetProfileUserName().c_str()); | |
135 | |
136 return GaiaUrls::GetInstance()->client_login_to_oauth2_url().Resolve( | |
137 query_string); | |
138 } | |
139 | |
140 void ArcAuthService::FetchToken() { | |
141 DCHECK(thread_checker_.CalledOnValidThread()); | |
142 DCHECK(state_ == State::DISABLE); | |
143 | |
144 auth_token_ = ""; | |
145 state_ = State::FETCHING_TOKEN; | |
146 FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_)); | |
147 | |
148 auth_fetcher_ = | |
149 net::URLFetcher::Create(CreateURL(profile_), net::URLFetcher::GET, this); | |
elijahtaylor1
2016/01/26 01:02:14
is it ok to have this code enabled in Chromium? I
khmel
2016/01/26 01:42:04
There is a tons of usage URLFetcher under chrome/b
| |
150 auth_fetcher_->SetRequestContext(profile_->GetRequestContext()); | |
151 // Executed asynchronously. | |
152 auth_fetcher_->Start(); | |
153 } | |
154 | |
155 // static | |
156 bool ArcAuthService::ParseAuthToken(const net::URLFetcher* source, | |
157 std::string* token) { | |
158 DCHECK(source != nullptr && token != nullptr); | |
159 net::ResponseCookies::const_iterator iter; | |
160 const net::ResponseCookies& cookies = source->GetCookies(); | |
161 for (iter = cookies.begin(); iter != cookies.end(); ++iter) { | |
162 std::vector<std::string> parts = base::SplitString( | |
163 *iter, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
164 // Per documentation, the cookie should have Secure and HttpOnly. | |
165 if (!CookiePartsContains(parts, kCookiePartSecure) || | |
166 !CookiePartsContains(parts, kCookiePartHttpOnly)) { | |
167 continue; | |
168 } | |
169 | |
170 std::vector<std::string>::const_iterator iter; | |
171 for (iter = parts.begin(); iter != parts.end(); ++iter) { | |
172 const std::string& part = *iter; | |
173 if (base::StartsWith(part, kCookiePartCodePrefix, | |
174 base::CompareCase::INSENSITIVE_ASCII)) { | |
175 *token = part.substr(kCookiePartCodePrefixLength); | |
176 return true; | |
177 } | |
178 } | |
179 } | |
180 | |
181 return false; | |
182 } | |
183 | |
184 void ArcAuthService::OnURLFetchComplete(const net::URLFetcher* source) { | |
185 DCHECK(thread_checker_.CalledOnValidThread()); | |
186 | |
187 std::string auth_token; | |
188 if (!source->GetStatus().is_success() || | |
189 source->GetResponseCode() != net::HTTP_OK || | |
190 !ParseAuthToken(source, &auth_token)) { | |
191 state_ = State::NO_TOKEN; | |
192 // TODO(khmel). There is no UI currently available. So start bridge anyway. | |
193 // GMS won't be signed in automatically. | |
194 ArcBridgeService::Get()->HandleStartup(); | |
elijahtaylor1
2016/01/26 01:02:14
I think we shouldn't start the bridge in this case
khmel
2016/01/26 01:42:04
This is done temporarily, until we have UI that sh
| |
195 FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_)); | |
196 } else { | |
197 SetAuthTokenAndStartArc(auth_token); | |
198 } | |
29 } | 199 } |
30 | 200 |
31 } // namespace arc | 201 } // namespace arc |
OLD | NEW |