@@ -90,9 +90,9 @@ std::string AuthInfo::jwtSecret() {
90
90
// private, must be called with _authInfoLock in write mode
91
91
bool AuthInfo::parseUsers (VPackSlice const & slice) {
92
92
TRI_ASSERT (slice.isArray ());
93
+ TRI_ASSERT (_authInfo.empty ());
94
+ TRI_ASSERT (_authBasicCache.empty ());
93
95
94
- _authInfo.clear ();
95
- _authBasicCache.clear ();
96
96
for (VPackSlice const & authSlice : VPackArrayIterator (slice)) {
97
97
VPackSlice s = authSlice.resolveExternal ();
98
98
@@ -108,10 +108,7 @@ bool AuthInfo::parseUsers(VPackSlice const& slice) {
108
108
// we also need to insert inactive users into the cache here
109
109
// otherwise all following update/replace/remove operations on the
110
110
// user will fail
111
-
112
- // intentional copy, as we'll be moving out of auth soon
113
- std::string username = auth.username ();
114
- _authInfo.emplace (std::move (username), std::move (auth));
111
+ _authInfo.emplace (auth.username (), std::move (auth));
115
112
}
116
113
117
114
return true ;
@@ -124,7 +121,7 @@ static std::shared_ptr<VPackBuilder> QueryAllUsers(
124
121
LOG_TOPIC (DEBUG, arangodb::Logger::FIXME) << " system database is unknown" ;
125
122
THROW_ARANGO_EXCEPTION (TRI_ERROR_INTERNAL);
126
123
}
127
-
124
+
128
125
// we cannot set this execution context, otherwise the transaction
129
126
// will ask us again for permissions and we get a deadlock
130
127
ExecContext* oldExe = ExecContext::CURRENT;
@@ -146,7 +143,9 @@ static std::shared_ptr<VPackBuilder> QueryAllUsers(
146
143
(queryResult.code == TRI_ERROR_QUERY_KILLED)) {
147
144
THROW_ARANGO_EXCEPTION (TRI_ERROR_REQUEST_CANCELED);
148
145
}
149
- return std::shared_ptr<VPackBuilder>();
146
+ THROW_ARANGO_EXCEPTION_MESSAGE (queryResult.code ,
147
+ " Error executing user query" );
148
+ // return std::shared_ptr<VPackBuilder>();
150
149
}
151
150
152
151
VPackSlice usersSlice = queryResult.result ->slice ();
@@ -173,7 +172,7 @@ static VPackBuilder QueryUser(aql::QueryRegistry* queryRegistry,
173
172
ExecContext* oldExe = ExecContext::CURRENT;
174
173
ExecContext::CURRENT = nullptr ;
175
174
TRI_DEFER (ExecContext::CURRENT = oldExe);
176
-
175
+
177
176
std::string const queryStr (" FOR u IN _users FILTER u.user == @name RETURN u" );
178
177
auto emptyBuilder = std::make_shared<VPackBuilder>();
179
178
@@ -192,7 +191,8 @@ static VPackBuilder QueryUser(aql::QueryRegistry* queryRegistry,
192
191
(queryResult.code == TRI_ERROR_QUERY_KILLED)) {
193
192
THROW_ARANGO_EXCEPTION (TRI_ERROR_REQUEST_CANCELED);
194
193
}
195
- THROW_ARANGO_EXCEPTION_MESSAGE (queryResult.code , " query error" );
194
+ THROW_ARANGO_EXCEPTION_MESSAGE (queryResult.code ,
195
+ " Error executing user query" );
196
196
}
197
197
198
198
VPackSlice usersSlice = queryResult.result ->slice ();
@@ -225,6 +225,14 @@ static void ConvertLegacyFormat(VPackSlice doc, VPackBuilder& result) {
225
225
// private, will acquire _authInfoLock in write-mode and release it.
226
226
// will also aquire _loadFromDBLock and release it
227
227
void AuthInfo::loadFromDB () {
228
+ TRI_ASSERT (_queryRegistry != nullptr );
229
+ TRI_ASSERT (ServerState::instance ()->isSingleServerOrCoordinator ());
230
+ auto role = ServerState::instance ()->getRole ();
231
+ if (role != ServerState::ROLE_SINGLE &&
232
+ role != ServerState::ROLE_COORDINATOR) {
233
+ _outdated = false ;
234
+ return ;
235
+ }
228
236
if (!_outdated) {
229
237
return ;
230
238
}
@@ -236,46 +244,46 @@ void AuthInfo::loadFromDB() {
236
244
return ;
237
245
}
238
246
239
- auto role = ServerState::instance ()->getRole ();
240
-
241
- if (role != ServerState::ROLE_SINGLE &&
242
- role != ServerState::ROLE_COORDINATOR) {
243
- _outdated = false ;
244
- return ;
245
- }
246
-
247
- TRI_ASSERT (_queryRegistry != nullptr );
248
- std::shared_ptr<VPackBuilder> builder = QueryAllUsers (_queryRegistry);
249
-
250
247
WRITE_LOCKER (writeLocker, _authInfoLock);
251
- _authBasicCache.clear ();
252
-
253
- if (builder) {
254
- VPackSlice usersSlice = builder->slice ();
255
- if (usersSlice.length () != 0 ) {
256
- parseUsers (usersSlice);
248
+ try {
249
+ std::shared_ptr<VPackBuilder> builder = QueryAllUsers (_queryRegistry);
250
+ _authInfo.clear ();
251
+ _authBasicCache.clear ();
252
+ if (builder) {
253
+ VPackSlice usersSlice = builder->slice ();
254
+ if (usersSlice.length () != 0 ) {
255
+ parseUsers (usersSlice);
256
+ }
257
257
}
258
+ _outdated = _authInfo.empty () == true ;
259
+ } catch (...) {
260
+ LOG_TOPIC (WARN, Logger::AUTHENTICATION)
261
+ << " Exception when loading users from db" ;
262
+ _outdated = true ;
258
263
}
259
-
260
- if (_authInfo.empty ()) {
261
- insertInitial ();
262
- }
263
- _outdated = false ;
264
264
}
265
265
266
- // private, must be called with _authInfoLock in write mode
267
- void AuthInfo::insertInitial () {
268
- if (!_authInfo.empty ()) {
266
+ // only call from the boostrap feature, must be sure to be the only one
267
+ void AuthInfo::createRootUser () {
268
+ loadFromDB ();
269
+
270
+ MUTEX_LOCKER (locker, _loadFromDBLock);
271
+ WRITE_LOCKER (writeLocker, _authInfoLock);
272
+ auto it = _authInfo.find (" root" );
273
+ if (it != _authInfo.end ()) {
274
+ LOG_TOPIC (TRACE, Logger::AUTHENTICATION) << " Root already exists" ;
269
275
return ;
270
276
}
271
-
277
+ TRI_ASSERT (_authInfo.empty ());
278
+
272
279
try {
273
280
// Attention:
274
281
// the root user needs to have a specific rights grant
275
282
// to the "_system" database, otherwise things break
276
283
auto initDatabaseFeature =
277
284
application_features::ApplicationServer::getFeature<
278
285
InitDatabaseFeature>(" InitDatabase" );
286
+ TRI_ASSERT (initDatabaseFeature != nullptr );
279
287
280
288
AuthUserEntry entry = AuthUserEntry::newUser (
281
289
" root" , initDatabaseFeature->defaultPassword (), AuthSource::COLLECTION);
@@ -300,15 +308,14 @@ Result AuthInfo::storeUserInternal(AuthUserEntry const& entry, bool replace) {
300
308
if (vocbase == nullptr ) {
301
309
return Result (TRI_ERROR_INTERNAL);
302
310
}
303
-
311
+
304
312
// we cannot set this execution context, otherwise the transaction
305
313
// will ask us again for permissions and we get a deadlock
306
314
ExecContext* oldExe = ExecContext::CURRENT;
307
315
ExecContext::CURRENT = nullptr ;
308
316
TRI_DEFER (ExecContext::CURRENT = oldExe);
309
317
310
- std::shared_ptr<transaction::Context> ctx (
311
- new transaction::StandaloneContext (vocbase));
318
+ auto ctx = transaction::StandaloneContext::Create (vocbase);
312
319
SingleCollectionTransaction trx (ctx, TRI_COL_NAME_USERS,
313
320
AccessMode::Type::WRITE);
314
321
trx.addHint (transaction::Hints::Hint::SINGLE_OPERATION);
@@ -443,15 +450,14 @@ static Result UpdateUser(VPackSlice const& user) {
443
450
if (vocbase == nullptr ) {
444
451
return Result (TRI_ERROR_INTERNAL);
445
452
}
446
-
453
+
447
454
// we cannot set this execution context, otherwise the transaction
448
455
// will ask us again for permissions and we get a deadlock
449
456
ExecContext* oldExe = ExecContext::CURRENT;
450
457
ExecContext::CURRENT = nullptr ;
451
458
TRI_DEFER (ExecContext::CURRENT = oldExe);
452
459
453
- std::shared_ptr<transaction::Context> ctx (
454
- new transaction::StandaloneContext (vocbase));
460
+ auto ctx = transaction::StandaloneContext::Create (vocbase);
455
461
SingleCollectionTransaction trx (ctx, TRI_COL_NAME_USERS,
456
462
AccessMode::Type::WRITE);
457
463
trx.addHint (transaction::Hints::Hint::SINGLE_OPERATION);
@@ -480,6 +486,8 @@ Result AuthInfo::enumerateUsers(
480
486
return r;
481
487
}
482
488
}
489
+ // must also clear the basic cache here because the secret may be
490
+ // invalid now if the password was changed
483
491
_authBasicCache.clear ();
484
492
}
485
493
// we need to reload data after the next callback
@@ -494,7 +502,6 @@ Result AuthInfo::updateUser(std::string const& user,
494
502
}
495
503
loadFromDB ();
496
504
Result r;
497
- VPackBuilder data;
498
505
{ // we require an consisten view on the user object
499
506
WRITE_LOCKER (guard, _authInfoLock);
500
507
auto it = _authInfo.find (user);
@@ -503,7 +510,7 @@ Result AuthInfo::updateUser(std::string const& user,
503
510
}
504
511
TRI_ASSERT (!it->second .key ().empty ());
505
512
func (it->second );
506
- data = it->second .toVPackBuilder ();
513
+ VPackBuilder data = it->second .toVPackBuilder ();
507
514
r = UpdateUser (data.slice ());
508
515
// must also clear the basic cache here because the secret may be
509
516
// invalid now if the password was changed
@@ -529,8 +536,8 @@ Result AuthInfo::accessUser(
529
536
}
530
537
531
538
VPackBuilder AuthInfo::serializeUser (std::string const & user) {
532
- // loadFromDB();
533
- // READ_LOCKER(guard, _authInfoLock)
539
+ loadFromDB ();
540
+ // will query db directly, no need for _authInfoLock
534
541
VPackBuilder doc = QueryUser (_queryRegistry, user);
535
542
VPackBuilder result;
536
543
if (!doc.isEmpty ()) {
@@ -545,15 +552,14 @@ static Result RemoveUserInternal(AuthUserEntry const& entry) {
545
552
if (vocbase == nullptr ) {
546
553
return Result (TRI_ERROR_INTERNAL);
547
554
}
548
-
555
+
549
556
// we cannot set this execution context, otherwise the transaction
550
557
// will ask us again for permissions and we get a deadlock
551
558
ExecContext* oldExe = ExecContext::CURRENT;
552
559
ExecContext::CURRENT = nullptr ;
553
560
TRI_DEFER (ExecContext::CURRENT = oldExe);
554
561
555
- std::shared_ptr<transaction::Context> ctx (
556
- new transaction::StandaloneContext (vocbase));
562
+ auto ctx = transaction::StandaloneContext::Create (vocbase);
557
563
SingleCollectionTransaction trx (ctx, TRI_COL_NAME_USERS,
558
564
AccessMode::Type::WRITE);
559
565
@@ -648,7 +654,6 @@ Result AuthInfo::setConfigData(std::string const& user,
648
654
partial.close ();
649
655
650
656
return UpdateUser (partial.slice ());
651
- ;
652
657
}
653
658
654
659
VPackBuilder AuthInfo::getUserData (std::string const & username) {
@@ -754,6 +759,8 @@ AuthLevel AuthInfo::canUseCollection(std::string const& username,
754
759
}
755
760
756
761
// public called from HttpCommTask.cpp and VstCommTask.cpp
762
+ // should only lock if required, otherwise we will serialize all
763
+ // requests whether we need to or not
757
764
AuthResult AuthInfo::checkAuthentication (AuthenticationMethod authType,
758
765
std::string const & secret) {
759
766
switch (authType) {
0 commit comments