blob: 4cd9276622c5d2a06ec602e2ec2b77bba1482795 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Buka7ce499f2015-06-09 08:04:11 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/privet/security_manager.h"
Vitaly Buka7ce499f2015-06-09 08:04:11 -07006
7#include <algorithm>
8#include <limits>
9#include <memory>
10#include <set>
11
12#include <base/bind.h>
13#include <base/guid.h>
14#include <base/logging.h>
Vitaly Buka7ce499f2015-06-09 08:04:11 -070015#include <base/rand_util.h>
Vitaly Buka7ce499f2015-06-09 08:04:11 -070016#include <base/strings/string_number_conversions.h>
17#include <base/strings/stringprintf.h>
18#include <base/time/time.h>
Vitaly Buka1e363672015-09-25 14:01:16 -070019#include <weave/provider/task_runner.h>
Vitaly Buka7ce499f2015-06-09 08:04:11 -070020
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020021#include "src/data_encoding.h"
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080022#include "src/privet/auth_manager.h"
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020023#include "src/privet/constants.h"
24#include "src/privet/openssl_utils.h"
25#include "src/string_utils.h"
Vitaly Buka9e5b6832015-10-14 15:57:14 -070026#include "third_party/chromium/crypto/p224_spake.h"
Vitaly Buka7ce499f2015-06-09 08:04:11 -070027
Vitaly Bukab6f015a2015-07-09 14:59:23 -070028namespace weave {
29namespace privet {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070030
31namespace {
32
Vitaly Buka7ce499f2015-06-09 08:04:11 -070033const int kSessionExpirationTimeMinutes = 5;
34const int kPairingExpirationTimeMinutes = 5;
35const int kMaxAllowedPairingAttemts = 3;
36const int kPairingBlockingTimeMinutes = 1;
37
Vitaly Bukafd2ef682015-12-17 20:57:01 -080038const int kAccessTokenExpirationSeconds = 3600;
39
Vitaly Buka7ce499f2015-06-09 08:04:11 -070040class Spakep224Exchanger : public SecurityManager::KeyExchanger {
41 public:
42 explicit Spakep224Exchanger(const std::string& password)
43 : spake_(crypto::P224EncryptedKeyExchange::kPeerTypeServer, password) {}
44 ~Spakep224Exchanger() override = default;
45
46 // SecurityManager::KeyExchanger methods.
47 const std::string& GetMessage() override { return spake_.GetNextMessage(); }
48
Vitaly Buka0801a1f2015-08-14 10:03:46 -070049 bool ProcessMessage(const std::string& message, ErrorPtr* error) override {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070050 switch (spake_.ProcessMessage(message)) {
51 case crypto::P224EncryptedKeyExchange::kResultPending:
52 return true;
53 case crypto::P224EncryptedKeyExchange::kResultFailed:
Vitaly Buka0801a1f2015-08-14 10:03:46 -070054 Error::AddTo(error, FROM_HERE, errors::kDomain,
55 errors::kInvalidClientCommitment, spake_.error());
Vitaly Buka7ce499f2015-06-09 08:04:11 -070056 return false;
57 default:
58 LOG(FATAL) << "SecurityManager uses only one round trip";
59 }
60 return false;
61 }
62
63 const std::string& GetKey() const override {
64 return spake_.GetUnverifiedKey();
65 }
66
67 private:
68 crypto::P224EncryptedKeyExchange spake_;
69};
70
71class UnsecureKeyExchanger : public SecurityManager::KeyExchanger {
72 public:
73 explicit UnsecureKeyExchanger(const std::string& password)
74 : password_(password) {}
75 ~UnsecureKeyExchanger() override = default;
76
77 // SecurityManager::KeyExchanger methods.
78 const std::string& GetMessage() override { return password_; }
79
Vitaly Buka0801a1f2015-08-14 10:03:46 -070080 bool ProcessMessage(const std::string& message, ErrorPtr* error) override {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070081 return true;
82 }
83
84 const std::string& GetKey() const override { return password_; }
85
86 private:
87 std::string password_;
88};
89
90} // namespace
91
Vitaly Buka20896ab2015-12-22 15:06:10 -080092SecurityManager::SecurityManager(const Config* config,
93 AuthManager* auth_manager,
Vitaly Buka1e363672015-09-25 14:01:16 -070094 provider::TaskRunner* task_runner)
Vitaly Buka20896ab2015-12-22 15:06:10 -080095 : config_{config}, auth_manager_{auth_manager}, task_runner_{task_runner} {
Vitaly Bukaf08caeb2015-12-02 13:47:48 -080096 CHECK(auth_manager_);
Vitaly Buka20896ab2015-12-22 15:06:10 -080097 CHECK_EQ(GetSettings().embedded_code.empty(),
98 std::find(GetSettings().pairing_modes.begin(),
99 GetSettings().pairing_modes.end(),
100 PairingType::kEmbeddedCode) ==
101 GetSettings().pairing_modes.end());
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700102}
103
104SecurityManager::~SecurityManager() {
105 while (!pending_sessions_.empty())
106 ClosePendingSession(pending_sessions_.begin()->first);
107}
108
Vitaly Buka66a01e02015-12-20 18:37:14 -0800109bool SecurityManager::CreateAccessTokenImpl(AuthType auth_type,
110 AuthScope desired_scope,
111 std::vector<uint8_t>* access_token,
112 AuthScope* access_token_scope,
113 base::TimeDelta* access_token_ttl) {
114 UserInfo user_info{desired_scope,
115 std::to_string(static_cast<int>(auth_type)) + "/" +
116 std::to_string(++last_user_id_)};
117
118 const base::TimeDelta kTtl =
119 base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
120
121 if (access_token)
122 *access_token = auth_manager_->CreateAccessToken(user_info, kTtl);
123
124 if (access_token_scope)
125 *access_token_scope = user_info.scope();
126
127 if (access_token_ttl)
128 *access_token_ttl = kTtl;
129
130 return true;
131}
132
133bool SecurityManager::CreateAccessTokenImpl(
134 AuthType auth_type,
135 const std::vector<uint8_t>& auth_code,
136 AuthScope desired_scope,
137 std::vector<uint8_t>* access_token,
138 AuthScope* access_token_scope,
139 base::TimeDelta* access_token_ttl,
140 ErrorPtr* error) {
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800141 auto disabled_mode = [](ErrorPtr* error) {
142 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
143 "Mode is not available");
144 return false;
145 };
Vitaly Buka66a01e02015-12-20 18:37:14 -0800146
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800147 switch (auth_type) {
148 case AuthType::kAnonymous:
Vitaly Buka20896ab2015-12-22 15:06:10 -0800149 if (!IsAnonymousAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800150 return disabled_mode(error);
Vitaly Buka66a01e02015-12-20 18:37:14 -0800151 return CreateAccessTokenImpl(auth_type, desired_scope, access_token,
152 access_token_scope, access_token_ttl);
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800153 case AuthType::kPairing:
Vitaly Buka20896ab2015-12-22 15:06:10 -0800154 if (!IsPairingAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800155 return disabled_mode(error);
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800156 if (!IsValidPairingCode(auth_code)) {
157 Error::AddTo(error, FROM_HERE, errors::kDomain,
158 errors::kInvalidAuthCode, "Invalid authCode");
159 return false;
160 }
Vitaly Buka66a01e02015-12-20 18:37:14 -0800161 return CreateAccessTokenImpl(auth_type, desired_scope, access_token,
162 access_token_scope, access_token_ttl);
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800163 case AuthType::kLocal:
Vitaly Buka20896ab2015-12-22 15:06:10 -0800164 if (!IsLocalAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800165 return disabled_mode(error);
Vitaly Buka66a01e02015-12-20 18:37:14 -0800166 const base::TimeDelta kTtl =
167 base::TimeDelta::FromSeconds(kAccessTokenExpirationSeconds);
168 return auth_manager_->CreateAccessTokenFromAuth(
169 auth_code, kTtl, access_token, access_token_scope, access_token_ttl,
170 error);
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800171 }
172
Vitaly Buka66a01e02015-12-20 18:37:14 -0800173 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidAuthMode,
174 "Unsupported auth mode");
175 return false;
176}
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800177
Vitaly Buka66a01e02015-12-20 18:37:14 -0800178bool SecurityManager::CreateAccessToken(AuthType auth_type,
179 const std::string& auth_code,
180 AuthScope desired_scope,
181 std::string* access_token,
182 AuthScope* access_token_scope,
183 base::TimeDelta* access_token_ttl,
184 ErrorPtr* error) {
185 std::vector<uint8_t> auth_decoded;
186 if (auth_type != AuthType::kAnonymous &&
187 !Base64Decode(auth_code, &auth_decoded)) {
188 return false;
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800189 }
190
Vitaly Buka66a01e02015-12-20 18:37:14 -0800191 std::vector<uint8_t> access_token_decoded;
192 if (!CreateAccessTokenImpl(auth_type, auth_decoded, desired_scope,
193 &access_token_decoded, access_token_scope,
194 access_token_ttl, error)) {
195 return false;
196 }
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800197
Vitaly Buka66a01e02015-12-20 18:37:14 -0800198 if (access_token)
199 *access_token = Base64Encode(access_token_decoded);
Vitaly Bukafd2ef682015-12-17 20:57:01 -0800200
201 return true;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700202}
203
Vitaly Bukaa0a81342015-12-17 13:42:13 -0800204bool SecurityManager::ParseAccessToken(const std::string& token,
205 UserInfo* user_info,
206 ErrorPtr* error) const {
Vitaly Bukaa04405e2015-08-13 18:28:14 -0700207 std::vector<uint8_t> decoded;
Vitaly Bukaa0a81342015-12-17 13:42:13 -0800208 if (!Base64Decode(token, &decoded)) {
209 Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
210 errors::kInvalidAuthorization,
211 "Invalid token encoding: %s", token.c_str());
212 return false;
213 }
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800214
Vitaly Bukaa0a81342015-12-17 13:42:13 -0800215 return auth_manager_->ParseAccessToken(decoded, user_info, error);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700216}
217
218std::set<PairingType> SecurityManager::GetPairingTypes() const {
Vitaly Buka20896ab2015-12-22 15:06:10 -0800219 return GetSettings().pairing_modes;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700220}
221
222std::set<CryptoType> SecurityManager::GetCryptoTypes() const {
223 std::set<CryptoType> result{CryptoType::kSpake_p224};
Vitaly Buka20896ab2015-12-22 15:06:10 -0800224 if (GetSettings().disable_security)
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700225 result.insert(CryptoType::kNone);
226 return result;
227}
228
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800229std::set<AuthType> SecurityManager::GetAuthTypes() const {
230 std::set<AuthType> result;
Vitaly Buka20896ab2015-12-22 15:06:10 -0800231 if (IsAnonymousAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800232 result.insert(AuthType::kAnonymous);
233
Vitaly Buka20896ab2015-12-22 15:06:10 -0800234 if (IsPairingAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800235 result.insert(AuthType::kPairing);
236
Vitaly Buka20896ab2015-12-22 15:06:10 -0800237 if (IsLocalAuthSupported())
Vitaly Bukaee7322f2015-12-18 16:54:05 -0800238 result.insert(AuthType::kLocal);
239
240 return result;
241}
242
Vitaly Buka4ab50022015-12-14 22:32:24 -0800243std::string SecurityManager::ClaimRootClientAuthToken(ErrorPtr* error) {
244 return Base64Encode(auth_manager_->ClaimRootClientAuthToken(
245 RootClientTokenOwner::kClient, error));
Vitaly Buka29bc5932015-12-13 22:56:52 -0800246}
247
Vitaly Buka305ab612015-12-15 12:02:59 -0800248bool SecurityManager::ConfirmClientAuthToken(const std::string& token,
249 ErrorPtr* error) {
Vitaly Buka29bc5932015-12-13 22:56:52 -0800250 std::vector<uint8_t> token_decoded;
Vitaly Buka4ab50022015-12-14 22:32:24 -0800251 if (!Base64Decode(token, &token_decoded)) {
252 Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
253 errors::kInvalidFormat,
254 "Invalid auth token string: '%s'", token.c_str());
Vitaly Buka29bc5932015-12-13 22:56:52 -0800255 return false;
Vitaly Buka4ab50022015-12-14 22:32:24 -0800256 }
Vitaly Buka305ab612015-12-15 12:02:59 -0800257 return auth_manager_->ConfirmClientAuthToken(token_decoded, error);
Vitaly Buka29bc5932015-12-13 22:56:52 -0800258}
259
Vitaly Buka20896ab2015-12-22 15:06:10 -0800260const Config::Settings& SecurityManager::GetSettings() const {
261 return config_->GetSettings();
262}
263
Vitaly Buka66a01e02015-12-20 18:37:14 -0800264bool SecurityManager::IsValidPairingCode(
265 const std::vector<uint8_t>& auth_code) const {
Vitaly Buka20896ab2015-12-22 15:06:10 -0800266 if (GetSettings().disable_security)
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700267 return true;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700268 for (const auto& session : confirmed_sessions_) {
Vitaly Bukaa04405e2015-08-13 18:28:14 -0700269 const std::string& key = session.second->GetKey();
270 const std::string& id = session.first;
Vitaly Buka66a01e02015-12-20 18:37:14 -0800271 if (auth_code == HmacSha256(std::vector<uint8_t>(key.begin(), key.end()),
272 std::vector<uint8_t>(id.begin(), id.end()))) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700273 pairing_attemts_ = 0;
274 block_pairing_until_ = base::Time{};
275 return true;
276 }
277 }
278 LOG(ERROR) << "Attempt to authenticate with invalide code.";
279 return false;
280}
281
282bool SecurityManager::StartPairing(PairingType mode,
283 CryptoType crypto,
284 std::string* session_id,
285 std::string* device_commitment,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700286 ErrorPtr* error) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700287 if (!CheckIfPairingAllowed(error))
288 return false;
289
Vitaly Buka20896ab2015-12-22 15:06:10 -0800290 const auto& pairing_modes = GetSettings().pairing_modes;
291 if (std::find(pairing_modes.begin(), pairing_modes.end(), mode) ==
292 pairing_modes.end()) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700293 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
294 "Pairing mode is not enabled");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700295 return false;
296 }
297
298 std::string code;
299 switch (mode) {
300 case PairingType::kEmbeddedCode:
Vitaly Buka20896ab2015-12-22 15:06:10 -0800301 CHECK(!GetSettings().embedded_code.empty());
302 code = GetSettings().embedded_code;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700303 break;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700304 case PairingType::kPinCode:
305 code = base::StringPrintf("%04i", base::RandInt(0, 9999));
306 break;
307 default:
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700308 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
309 "Unsupported pairing mode");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700310 return false;
311 }
312
313 std::unique_ptr<KeyExchanger> spake;
314 switch (crypto) {
315 case CryptoType::kSpake_p224:
316 spake.reset(new Spakep224Exchanger(code));
317 break;
318 case CryptoType::kNone:
Vitaly Buka20896ab2015-12-22 15:06:10 -0800319 if (GetSettings().disable_security) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700320 spake.reset(new UnsecureKeyExchanger(code));
321 break;
322 }
323 // Fall through...
324 default:
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700325 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kInvalidParams,
326 "Unsupported crypto");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700327 return false;
328 }
329
330 // Allow only a single session at a time for now.
331 while (!pending_sessions_.empty())
332 ClosePendingSession(pending_sessions_.begin()->first);
333
334 std::string session;
335 do {
336 session = base::GenerateGUID();
337 } while (confirmed_sessions_.find(session) != confirmed_sessions_.end() ||
338 pending_sessions_.find(session) != pending_sessions_.end());
339 std::string commitment = spake->GetMessage();
Vitaly Buka52d006a2015-11-21 17:14:51 -0800340 pending_sessions_.insert(std::make_pair(session, std::move(spake)));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700341
Vitaly Bukaf9630fb2015-08-12 21:15:40 -0700342 task_runner_->PostDelayedTask(
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700343 FROM_HERE,
344 base::Bind(base::IgnoreResult(&SecurityManager::ClosePendingSession),
345 weak_ptr_factory_.GetWeakPtr(), session),
346 base::TimeDelta::FromMinutes(kPairingExpirationTimeMinutes));
347
348 *session_id = session;
Vitaly Buka7d556392015-08-13 20:06:48 -0700349 *device_commitment = Base64Encode(commitment);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700350 LOG(INFO) << "Pairing code for session " << *session_id << " is " << code;
351 // TODO(vitalybuka): Handle case when device can't start multiple pairing
352 // simultaneously and implement throttling to avoid brute force attack.
353 if (!on_start_.is_null()) {
354 on_start_.Run(session, mode,
Vitaly Buka24d6fd52015-08-13 23:22:48 -0700355 std::vector<uint8_t>{code.begin(), code.end()});
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700356 }
357
358 return true;
359}
360
361bool SecurityManager::ConfirmPairing(const std::string& session_id,
362 const std::string& client_commitment,
363 std::string* fingerprint,
364 std::string* signature,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700365 ErrorPtr* error) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700366 auto session = pending_sessions_.find(session_id);
367 if (session == pending_sessions_.end()) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700368 Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
369 errors::kUnknownSession, "Unknown session id: '%s'",
370 session_id.c_str());
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700371 return false;
372 }
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700373
Vitaly Bukaa04405e2015-08-13 18:28:14 -0700374 std::vector<uint8_t> commitment;
Vitaly Buka7d556392015-08-13 20:06:48 -0700375 if (!Base64Decode(client_commitment, &commitment)) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700376 ClosePendingSession(session_id);
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700377 Error::AddToPrintf(
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700378 error, FROM_HERE, errors::kDomain, errors::kInvalidFormat,
379 "Invalid commitment string: '%s'", client_commitment.c_str());
380 return false;
381 }
382
383 if (!session->second->ProcessMessage(
384 std::string(commitment.begin(), commitment.end()), error)) {
385 ClosePendingSession(session_id);
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700386 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kCommitmentMismatch,
387 "Pairing code or crypto implementation mismatch");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700388 return false;
389 }
390
Vitaly Bukaa04405e2015-08-13 18:28:14 -0700391 const std::string& key = session->second->GetKey();
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700392 VLOG(3) << "KEY " << base::HexEncode(key.data(), key.size());
393
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800394 const auto& certificate_fingerprint =
395 auth_manager_->GetCertificateFingerprint();
396 *fingerprint = Base64Encode(certificate_fingerprint);
Vitaly Bukaa04405e2015-08-13 18:28:14 -0700397 std::vector<uint8_t> cert_hmac = HmacSha256(
Vitaly Bukaf08caeb2015-12-02 13:47:48 -0800398 std::vector<uint8_t>(key.begin(), key.end()), certificate_fingerprint);
Vitaly Buka7d556392015-08-13 20:06:48 -0700399 *signature = Base64Encode(cert_hmac);
Vitaly Buka52d006a2015-11-21 17:14:51 -0800400 confirmed_sessions_.insert(
401 std::make_pair(session->first, std::move(session->second)));
Vitaly Bukaf9630fb2015-08-12 21:15:40 -0700402 task_runner_->PostDelayedTask(
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700403 FROM_HERE,
404 base::Bind(base::IgnoreResult(&SecurityManager::CloseConfirmedSession),
405 weak_ptr_factory_.GetWeakPtr(), session_id),
406 base::TimeDelta::FromMinutes(kSessionExpirationTimeMinutes));
407 ClosePendingSession(session_id);
408 return true;
409}
410
411bool SecurityManager::CancelPairing(const std::string& session_id,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700412 ErrorPtr* error) {
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700413 bool confirmed = CloseConfirmedSession(session_id);
414 bool pending = ClosePendingSession(session_id);
415 if (pending) {
416 CHECK_GE(pairing_attemts_, 1);
417 --pairing_attemts_;
418 }
419 CHECK(!confirmed || !pending);
420 if (confirmed || pending)
421 return true;
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700422 Error::AddToPrintf(error, FROM_HERE, errors::kDomain, errors::kUnknownSession,
423 "Unknown session id: '%s'", session_id.c_str());
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700424 return false;
425}
426
Vitaly Buka483d5972015-12-16 13:45:35 -0800427std::string SecurityManager::CreateSessionId() {
428 return Base64Encode(auth_manager_->CreateSessionId());
429}
430
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700431void SecurityManager::RegisterPairingListeners(
432 const PairingStartListener& on_start,
433 const PairingEndListener& on_end) {
434 CHECK(on_start_.is_null() && on_end_.is_null());
435 on_start_ = on_start;
Vitaly Buka075b3d42015-06-09 08:34:25 -0700436 on_end_ = on_end;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700437}
438
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700439bool SecurityManager::CheckIfPairingAllowed(ErrorPtr* error) {
Vitaly Buka20896ab2015-12-22 15:06:10 -0800440 if (GetSettings().disable_security)
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700441 return true;
442
Vitaly Buka41aa8092015-12-09 20:04:34 -0800443 if (block_pairing_until_ > auth_manager_->Now()) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700444 Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kDeviceBusy,
445 "Too many pairing attempts");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700446 return false;
447 }
448
449 if (++pairing_attemts_ >= kMaxAllowedPairingAttemts) {
450 LOG(INFO) << "Pairing blocked for" << kPairingBlockingTimeMinutes
451 << "minutes.";
Vitaly Buka41aa8092015-12-09 20:04:34 -0800452 block_pairing_until_ = auth_manager_->Now();
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700453 block_pairing_until_ +=
454 base::TimeDelta::FromMinutes(kPairingBlockingTimeMinutes);
455 }
456
457 return true;
458}
459
460bool SecurityManager::ClosePendingSession(const std::string& session_id) {
461 // The most common source of these session_id values is the map containing
462 // the sessions, which we're about to clear out. Make a local copy.
463 const std::string safe_session_id{session_id};
464 const size_t num_erased = pending_sessions_.erase(safe_session_id);
465 if (num_erased > 0 && !on_end_.is_null())
466 on_end_.Run(safe_session_id);
467 return num_erased != 0;
468}
469
470bool SecurityManager::CloseConfirmedSession(const std::string& session_id) {
471 return confirmed_sessions_.erase(session_id) != 0;
472}
473
Vitaly Buka20896ab2015-12-22 15:06:10 -0800474bool SecurityManager::IsAnonymousAuthSupported() const {
475 return GetSettings().local_anonymous_access_role != AuthScope::kNone;
476}
477
478bool SecurityManager::IsPairingAuthSupported() const {
479 return GetSettings().local_pairing_enabled;
480}
481
482bool SecurityManager::IsLocalAuthSupported() const {
483 return GetSettings().root_client_token_owner != RootClientTokenOwner::kNone;
484}
485
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700486} // namespace privet
487} // namespace weave