From 37e24a5e76e46addf2cc103e47bf119e4c2c87fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Tue, 7 Nov 2017 19:25:53 +0100 Subject: [PATCH] Replace the Timestamp properties by new ConcurrencyToken properties to work around a MySQL limitation --- .../OpenIddictExtensions.cs | 36 ++++++++----------- .../Stores/OpenIddictApplicationStore.cs | 5 +++ .../Stores/OpenIddictAuthorizationStore.cs | 9 +++++ .../Stores/OpenIddictScopeStore.cs | 5 +++ .../Stores/OpenIddictTokenStore.cs | 5 +++ .../OpenIddictExtensions.cs | 34 +++++++----------- .../Stores/OpenIddictApplicationStore.cs | 5 +++ .../Stores/OpenIddictAuthorizationStore.cs | 9 +++++ .../Stores/OpenIddictScopeStore.cs | 7 +++- .../Stores/OpenIddictTokenStore.cs | 5 +++ .../OpenIddictApplication.cs | 11 +++--- .../OpenIddictAuthorization.cs | 11 +++--- src/OpenIddict.Models/OpenIddictScope.cs | 5 ++- src/OpenIddict.Models/OpenIddictToken.cs | 11 +++--- 14 files changed, 93 insertions(+), 65 deletions(-) diff --git a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs index fb008fce..402d68e5 100644 --- a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs +++ b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs @@ -193,10 +193,8 @@ namespace Microsoft.Extensions.DependencyInjection .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute())); builder.Entity() - .Property(application => application.Timestamp) - .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed) - .IsConcurrencyToken() - .IsRowVersion(); + .Property(application => application.ConcurrencyToken) + .IsConcurrencyToken(); builder.Entity() .Property(application => application.Type) @@ -220,6 +218,10 @@ namespace Microsoft.Extensions.DependencyInjection builder.Entity() .HasKey(authorization => authorization.Id); + builder.Entity() + .Property(authorization => authorization.ConcurrencyToken) + .IsConcurrencyToken(); + builder.Entity() .Property(authorization => authorization.Status) .IsRequired(); @@ -228,12 +230,6 @@ namespace Microsoft.Extensions.DependencyInjection .Property(authorization => authorization.Subject) .IsRequired(); - builder.Entity() - .Property(authorization => authorization.Timestamp) - .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed) - .IsConcurrencyToken() - .IsRowVersion(); - builder.Entity() .Property(authorization => authorization.Type) .IsRequired(); @@ -252,14 +248,12 @@ namespace Microsoft.Extensions.DependencyInjection .HasKey(scope => scope.Id); builder.Entity() - .Property(scope => scope.Name) - .IsRequired(); + .Property(scope => scope.ConcurrencyToken) + .IsConcurrencyToken(); builder.Entity() - .Property(scope => scope.Timestamp) - .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed) - .IsConcurrencyToken() - .IsRowVersion(); + .Property(scope => scope.Name) + .IsRequired(); builder.Entity() .ToTable("OpenIddictScopes"); @@ -268,6 +262,10 @@ namespace Microsoft.Extensions.DependencyInjection builder.Entity() .HasKey(token => token.Id); + builder.Entity() + .Property(token => token.ConcurrencyToken) + .IsConcurrencyToken(); + builder.Entity() .Property(token => token.Hash) .HasMaxLength(450) @@ -277,12 +275,6 @@ namespace Microsoft.Extensions.DependencyInjection .Property(token => token.Subject) .IsRequired(); - builder.Entity() - .Property(token => token.Timestamp) - .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed) - .IsConcurrencyToken() - .IsRowVersion(); - builder.Entity() .Property(token => token.Type) .IsRequired(); diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs index e473b984..19b29cee 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictApplicationStore.cs @@ -281,6 +281,11 @@ namespace OpenIddict.EntityFramework } Applications.Attach(application); + + // Generate a new concurrency token and attach it + // to the application before persisting the changes. + application.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Entry(application).State = EntityState.Modified; return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs index 1c77d3f8..fca131b7 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs @@ -329,8 +329,17 @@ namespace OpenIddict.EntityFramework /// public override Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } Authorizations.Attach(authorization); + + // Generate a new concurrency token and attach it + // to the authorization before persisting the changes. + authorization.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Entry(authorization).State = EntityState.Modified; return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs index 992e8d82..4435a21b 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictScopeStore.cs @@ -206,6 +206,11 @@ namespace OpenIddict.EntityFramework } Scopes.Attach(scope); + + // Generate a new concurrency token and attach it + // to the scope before persisting the changes. + scope.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Entry(scope).State = EntityState.Modified; return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs index af7d64f8..8ea87721 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs @@ -393,6 +393,11 @@ namespace OpenIddict.EntityFramework } Tokens.Attach(token); + + // Generate a new concurrency token and attach it + // to the token before persisting the changes. + token.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Entry(token).State = EntityState.Modified; return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs index 86124685..1896130d 100644 --- a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs +++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs @@ -223,15 +223,13 @@ namespace Microsoft.Extensions.DependencyInjection entity.HasKey(application => application.Id); entity.HasIndex(application => application.ClientId) - .IsUnique(unique: true); + .IsUnique(); entity.Property(application => application.ClientId) - .IsRequired(required: true); + .IsRequired(); - entity.Property(application => application.Timestamp) - .ValueGeneratedOnAddOrUpdate() - .IsConcurrencyToken() - .IsRowVersion(); + entity.Property(application => application.ConcurrencyToken) + .IsConcurrencyToken(); entity.Property(application => application.Type) .IsRequired(); @@ -255,17 +253,15 @@ namespace Microsoft.Extensions.DependencyInjection { entity.HasKey(authorization => authorization.Id); + entity.Property(authorization => authorization.ConcurrencyToken) + .IsConcurrencyToken(); + entity.Property(authorization => authorization.Status) .IsRequired(); entity.Property(authorization => authorization.Subject) .IsRequired(); - entity.Property(authorization => authorization.Timestamp) - .ValueGeneratedOnAddOrUpdate() - .IsConcurrencyToken() - .IsRowVersion(); - entity.Property(authorization => authorization.Type) .IsRequired(); @@ -283,10 +279,8 @@ namespace Microsoft.Extensions.DependencyInjection { entity.HasKey(scope => scope.Id); - entity.Property(scope => scope.Timestamp) - .ValueGeneratedOnAddOrUpdate() - .IsConcurrencyToken() - .IsRowVersion(); + entity.Property(scope => scope.ConcurrencyToken) + .IsConcurrencyToken(); entity.Property(scope => scope.Name) .IsRequired(); @@ -300,16 +294,14 @@ namespace Microsoft.Extensions.DependencyInjection entity.HasKey(token => token.Id); entity.HasIndex(token => token.Hash) - .IsUnique(unique: true); + .IsUnique(); + + entity.Property(token => token.ConcurrencyToken) + .IsConcurrencyToken(); entity.Property(token => token.Subject) .IsRequired(); - entity.Property(token => token.Timestamp) - .ValueGeneratedOnAddOrUpdate() - .IsConcurrencyToken() - .IsRowVersion(); - entity.Property(token => token.Type) .IsRequired(); diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs index 4db5055a..86e8516a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs @@ -281,6 +281,11 @@ namespace OpenIddict.EntityFrameworkCore } Context.Attach(application); + + // Generate a new concurrency token and attach it + // to the application before persisting the changes. + application.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Update(application); return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs index 635c9f91..a2bc9741 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs @@ -371,8 +371,17 @@ namespace OpenIddict.EntityFrameworkCore /// public override Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) { + if (authorization == null) + { + throw new ArgumentNullException(nameof(authorization)); + } Context.Attach(authorization); + + // Generate a new concurrency token and attach it + // to the authorization before persisting the changes. + authorization.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Update(authorization); return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs index 918ed9b7..11876fbf 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs @@ -206,7 +206,12 @@ namespace OpenIddict.EntityFrameworkCore } Context.Attach(scope); - Context.Entry(scope).State = EntityState.Modified; + + // Generate a new concurrency token and attach it + // to the scope before persisting the changes. + scope.ConcurrencyToken = Guid.NewGuid().ToString(); + + Context.Update(scope); return Context.SaveChangesAsync(cancellationToken); } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs index 6f39b161..e946374a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs @@ -463,6 +463,11 @@ namespace OpenIddict.EntityFrameworkCore } Context.Attach(token); + + // Generate a new concurrency token and attach it + // to the token before persisting the changes. + token.ConcurrencyToken = Guid.NewGuid().ToString(); + Context.Update(token); return Context.SaveChangesAsync(cancellationToken); diff --git a/src/OpenIddict.Models/OpenIddictApplication.cs b/src/OpenIddict.Models/OpenIddictApplication.cs index c24b6fb9..e82ef837 100644 --- a/src/OpenIddict.Models/OpenIddictApplication.cs +++ b/src/OpenIddict.Models/OpenIddictApplication.cs @@ -51,6 +51,11 @@ namespace OpenIddict.Models /// public virtual string ClientSecret { get; set; } + /// + /// Gets or sets the concurrency token. + /// + public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); + /// /// Gets or sets the display name /// associated with the current application. @@ -77,12 +82,6 @@ namespace OpenIddict.Models /// public virtual string RedirectUris { get; set; } - /// - /// Gets or sets the timestamp associated with the current - /// application, which is used as a concurrency token. - /// - public virtual byte[] Timestamp { get; set; } - /// /// Gets the list of the tokens associated with this application. /// diff --git a/src/OpenIddict.Models/OpenIddictAuthorization.cs b/src/OpenIddict.Models/OpenIddictAuthorization.cs index 76014e6f..cd4eaca8 100644 --- a/src/OpenIddict.Models/OpenIddictAuthorization.cs +++ b/src/OpenIddict.Models/OpenIddictAuthorization.cs @@ -38,6 +38,11 @@ namespace OpenIddict.Models /// public virtual TApplication Application { get; set; } + /// + /// Gets or sets the concurrency token. + /// + public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); + /// /// Gets or sets the unique identifier /// associated with the current authorization. @@ -60,12 +65,6 @@ namespace OpenIddict.Models /// public virtual string Subject { get; set; } - /// - /// Gets or sets the timestamp associated with the current - /// authorization, which is used as a concurrency token. - /// - public virtual byte[] Timestamp { get; set; } - /// /// Gets or sets the list of tokens /// associated with the current authorization. diff --git a/src/OpenIddict.Models/OpenIddictScope.cs b/src/OpenIddict.Models/OpenIddictScope.cs index 5788ae9d..28e796e2 100644 --- a/src/OpenIddict.Models/OpenIddictScope.cs +++ b/src/OpenIddict.Models/OpenIddictScope.cs @@ -26,10 +26,9 @@ namespace OpenIddict.Models public class OpenIddictScope where TKey : IEquatable { /// - /// Gets or sets the timestamp associated with the - /// current scope, which is used as a concurrency token. + /// Gets or sets the concurrency token. /// - public virtual byte[] Timestamp { get; set; } + public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// /// Gets or sets the public description diff --git a/src/OpenIddict.Models/OpenIddictToken.cs b/src/OpenIddict.Models/OpenIddictToken.cs index b3775fd4..73834fcf 100644 --- a/src/OpenIddict.Models/OpenIddictToken.cs +++ b/src/OpenIddict.Models/OpenIddictToken.cs @@ -50,6 +50,11 @@ namespace OpenIddict.Models /// public virtual string Ciphertext { get; set; } + /// + /// Gets or sets the concurrency token. + /// + public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); + /// /// Gets or sets the date on which the token /// will start to be considered valid. @@ -85,12 +90,6 @@ namespace OpenIddict.Models /// public virtual string Subject { get; set; } - /// - /// Gets or sets the timestamp associated with the - /// current token, which is used as a concurrency token. - /// - public virtual byte[] Timestamp { get; set; } - /// /// Gets or sets the type of the current token. ///