diff --git a/src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs b/src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs index de27f63d..9c8bd953 100644 --- a/src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs +++ b/src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs @@ -40,69 +40,74 @@ namespace OpenIddict.MongoDb /// A that can be used to monitor the /// asynchronous operation, whose result returns the MongoDB database. /// - public async ValueTask GetDatabaseAsync(CancellationToken cancellationToken) + public ValueTask GetDatabaseAsync(CancellationToken cancellationToken) { if (_database != null) { - return _database; + return new ValueTask(_database); } - var options = _options.CurrentValue; - if (options == null) + async Task ExecuteAsync() { - throw new InvalidOperationException("The OpenIddict MongoDB options cannot be retrieved."); - } - - var database = options.Database; - if (database == null) - { - database = _provider.GetService(); - } + var options = _options.CurrentValue; + if (options == null) + { + throw new InvalidOperationException("The OpenIddict MongoDB options cannot be retrieved."); + } - if (database == null) - { - throw new InvalidOperationException(new StringBuilder() - .AppendLine("No suitable MongoDB database service can be found.") - .Append("To configure the OpenIddict MongoDB stores to use a specific database, use ") - .Append("'services.AddOpenIddict().AddCore().UseMongoDb().UseDatabase()' or register an ") - .Append("'IMongoDatabase' in the dependency injection container in 'ConfigureServices()'.") - .ToString()); - } + var database = options.Database; + if (database == null) + { + database = _provider.GetService(); + } - // Note: the cancellation token passed as a parameter is deliberately not used here to ensure - // the cancellation of a single store operation doesn't prevent the indexes from being created. - var applications = database.GetCollection(options.ApplicationsCollectionName); - await applications.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(application => application.ClientId), - new CreateIndexOptions + if (database == null) { - Unique = true - }); + throw new InvalidOperationException(new StringBuilder() + .AppendLine("No suitable MongoDB database service can be found.") + .Append("To configure the OpenIddict MongoDB stores to use a specific database, use ") + .Append("'services.AddOpenIddict().AddCore().UseMongoDb().UseDatabase()' or register an ") + .Append("'IMongoDatabase' in the dependency injection container in 'ConfigureServices()'.") + .ToString()); + } - await applications.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(application => application.PostLogoutRedirectUris)); + // Note: the cancellation token passed as a parameter is deliberately not used here to ensure + // the cancellation of a single store operation doesn't prevent the indexes from being created. + var applications = database.GetCollection(options.ApplicationsCollectionName); + await applications.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(application => application.ClientId), + new CreateIndexOptions + { + Unique = true + }); - await applications.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(application => application.RedirectUris)); + await applications.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(application => application.PostLogoutRedirectUris)); - var scopes = database.GetCollection(options.ScopesCollectionName); - await scopes.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(scope => scope.Name), - new CreateIndexOptions - { - Unique = true - }); + await applications.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(application => application.RedirectUris)); - var tokens = database.GetCollection(options.TokensCollectionName); - await tokens.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(token => token.ReferenceId), - new CreateIndexOptions - { - PartialFilterExpression = Builders.Filter.Exists(token => token.ReferenceId), - Unique = true - }); + var scopes = database.GetCollection(options.ScopesCollectionName); + await scopes.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(scope => scope.Name), + new CreateIndexOptions + { + Unique = true + }); + + var tokens = database.GetCollection(options.TokensCollectionName); + await tokens.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(token => token.ReferenceId), + new CreateIndexOptions + { + PartialFilterExpression = Builders.Filter.Exists(token => token.ReferenceId), + Unique = true + }); + + return _database = database; + } - return _database = database; + return new ValueTask(ExecuteAsync()); } } } diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs index db2f49c3..cbde5016 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictApplicationStore.cs @@ -794,6 +794,7 @@ namespace OpenIddict.MongoDb // Generate a new concurrency token and attach it // to the application before persisting the changes. + var timestamp = application.ConcurrencyToken; application.ConcurrencyToken = Guid.NewGuid().ToString(); var database = await Context.GetDatabaseAsync(cancellationToken); @@ -801,7 +802,7 @@ namespace OpenIddict.MongoDb if ((await collection.ReplaceOneAsync(entity => entity.Id == application.Id && - entity.ConcurrencyToken == application.ConcurrencyToken, application, null, cancellationToken)).MatchedCount == 0) + entity.ConcurrencyToken == timestamp, application, null, cancellationToken)).MatchedCount == 0) { throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder() .AppendLine("The application was concurrently updated and cannot be persisted in its current state.") diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs index 34321262..537a97ad 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs @@ -745,6 +745,7 @@ namespace OpenIddict.MongoDb // Generate a new concurrency token and attach it // to the authorization before persisting the changes. + var timestamp = authorization.ConcurrencyToken; authorization.ConcurrencyToken = Guid.NewGuid().ToString(); var database = await Context.GetDatabaseAsync(cancellationToken); @@ -752,7 +753,7 @@ namespace OpenIddict.MongoDb if ((await collection.ReplaceOneAsync(entity => entity.Id == authorization.Id && - entity.ConcurrencyToken == authorization.ConcurrencyToken, authorization, null, cancellationToken)).MatchedCount == 0) + entity.ConcurrencyToken == timestamp, authorization, null, cancellationToken)).MatchedCount == 0) { throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder() .AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.") diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs index 456e179a..40646907 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictScopeStore.cs @@ -591,6 +591,7 @@ namespace OpenIddict.MongoDb // Generate a new concurrency token and attach it // to the scope before persisting the changes. + var timestamp = scope.ConcurrencyToken; scope.ConcurrencyToken = Guid.NewGuid().ToString(); var database = await Context.GetDatabaseAsync(cancellationToken); @@ -598,7 +599,7 @@ namespace OpenIddict.MongoDb if ((await collection.ReplaceOneAsync(entity => entity.Id == scope.Id && - entity.ConcurrencyToken == scope.ConcurrencyToken, scope, null, cancellationToken)).MatchedCount == 0) + entity.ConcurrencyToken == timestamp, scope, null, cancellationToken)).MatchedCount == 0) { throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder() .AppendLine("The scope was concurrently updated and cannot be persisted in its current state.") diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs index 49208e12..0fbf9f4a 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs @@ -855,6 +855,7 @@ namespace OpenIddict.MongoDb // Generate a new concurrency token and attach it // to the token before persisting the changes. + var timestamp = token.ConcurrencyToken; token.ConcurrencyToken = Guid.NewGuid().ToString(); var database = await Context.GetDatabaseAsync(cancellationToken); @@ -862,7 +863,7 @@ namespace OpenIddict.MongoDb if ((await collection.ReplaceOneAsync(entity => entity.Id == token.Id && - entity.ConcurrencyToken == token.ConcurrencyToken, token, null, cancellationToken)).MatchedCount == 0) + entity.ConcurrencyToken == timestamp, token, null, cancellationToken)).MatchedCount == 0) { throw new OpenIddictException(OpenIddictConstants.Exceptions.ConcurrencyError, new StringBuilder() .AppendLine("The token was concurrently updated and cannot be persisted in its current state.")