diff --git a/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs b/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs
index 04b129ec..292de19e 100644
--- a/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs
+++ b/src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs
@@ -28,5 +28,10 @@ namespace OpenIddict.Core
/// Gets or sets the subject associated with the authorization.
///
public string Subject { get; set; }
+
+ ///
+ /// Gets or sets the type of the authorization.
+ ///
+ public virtual string Type { get; set; }
}
}
diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
index 945e1614..82ed13ed 100644
--- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
+++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
@@ -85,6 +85,12 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(authorization));
}
+ // If no type was explicitly specified, assume that the authorization is a permanent authorization.
+ if (string.IsNullOrEmpty(await Store.GetTypeAsync(authorization, cancellationToken)))
+ {
+ await Store.SetTypeAsync(authorization, OpenIddictConstants.AuthorizationTypes.Permanent, cancellationToken);
+ }
+
await ValidateAsync(authorization, cancellationToken);
return await Store.CreateAsync(authorization, cancellationToken);
}
@@ -104,6 +110,13 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
+ // If no type was explicitly specified, assume that
+ // the authorization is a permanent authorization.
+ if (string.IsNullOrEmpty(descriptor.Type))
+ {
+ descriptor.Type = OpenIddictConstants.AuthorizationTypes.Permanent;
+ }
+
await ValidateAsync(descriptor, cancellationToken);
return await Store.CreateAsync(descriptor, cancellationToken);
}
@@ -309,6 +322,17 @@ namespace OpenIddict.Core
throw new ArgumentNullException(nameof(descriptor));
}
+ if (string.IsNullOrEmpty(descriptor.Type))
+ {
+ throw new ArgumentException("The authorization type cannot be null or empty.", nameof(descriptor));
+ }
+
+ if (!string.Equals(descriptor.Type, OpenIddictConstants.AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(descriptor.Type, OpenIddictConstants.AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase))
+ {
+ throw new ArgumentException("The specified authorization type is not supported by the default token manager.");
+ }
+
if (string.IsNullOrEmpty(descriptor.Status))
{
throw new ArgumentException("The status cannot be null or empty.");
diff --git a/src/OpenIddict.Core/OpenIddictConstants.cs b/src/OpenIddict.Core/OpenIddictConstants.cs
index 4ba722e7..dce4eb79 100644
--- a/src/OpenIddict.Core/OpenIddictConstants.cs
+++ b/src/OpenIddict.Core/OpenIddictConstants.cs
@@ -8,6 +8,12 @@ namespace OpenIddict.Core
{
public static class OpenIddictConstants
{
+ public static class AuthorizationTypes
+ {
+ public const string AdHoc = "ad-hoc";
+ public const string Permanent = "permanent";
+ }
+
public static class Claims
{
public const string Roles = "roles";
diff --git a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
index 1449c97f..b1c478de 100644
--- a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs
@@ -138,6 +138,17 @@ namespace OpenIddict.Core
///
Task GetSubjectAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
+ ///
+ /// Retrieves the type associated with an authorization.
+ ///
+ /// The authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the type associated with the specified authorization.
+ ///
+ Task GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken);
+
///
/// Executes the specified query.
///
@@ -173,6 +184,17 @@ namespace OpenIddict.Core
///
Task SetStatusAsync([NotNull] TAuthorization authorization, [NotNull] string status, CancellationToken cancellationToken);
+ ///
+ /// Sets the type associated with an authorization.
+ ///
+ /// The authorization.
+ /// The type associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ Task SetTypeAsync([NotNull] TAuthorization authorization, [NotNull] string type, CancellationToken cancellationToken);
+
///
/// Updates an existing authorization.
///
diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
index 5af2732f..a9474cf7 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs
@@ -199,6 +199,25 @@ namespace OpenIddict.Core
return Task.FromResult(authorization.Subject);
}
+ ///
+ /// Retrieves the type associated with an authorization.
+ ///
+ /// The authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation,
+ /// whose result returns the type associated with the specified authorization.
+ ///
+ public virtual Task GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ return Task.FromResult(authorization.Type);
+ }
+
///
/// Executes the specified query.
///
@@ -254,11 +273,37 @@ namespace OpenIddict.Core
///
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization, [NotNull] string status, CancellationToken cancellationToken)
{
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
authorization.Status = status;
return Task.CompletedTask;
}
+ ///
+ /// Sets the type associated with an authorization.
+ ///
+ /// The authorization.
+ /// The type associated with the authorization.
+ /// The that can be used to abort the operation.
+ ///
+ /// A that can be used to monitor the asynchronous operation.
+ ///
+ public virtual Task SetTypeAsync([NotNull] TAuthorization authorization, [NotNull] string type, CancellationToken cancellationToken)
+ {
+ if (authorization == null)
+ {
+ throw new ArgumentNullException(nameof(authorization));
+ }
+
+ authorization.Type = type;
+
+ return Task.FromResult(0);
+ }
+
///
/// Updates an existing authorization.
///
diff --git a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
index a5f7aea5..65e7921a 100644
--- a/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
+++ b/src/OpenIddict.Core/Stores/OpenIddictTokenStore.cs
@@ -432,6 +432,11 @@ namespace OpenIddict.Core
public virtual Task SetExpirationDateAsync([NotNull] TToken token,
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken)
{
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
token.ExpirationDate = date;
return Task.CompletedTask;
@@ -448,6 +453,11 @@ namespace OpenIddict.Core
///
public virtual Task SetStatusAsync([NotNull] TToken token, [NotNull] string status, CancellationToken cancellationToken)
{
+ if (token == null)
+ {
+ throw new ArgumentNullException(nameof(token));
+ }
+
token.Status = status;
return Task.CompletedTask;
diff --git a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
index da835d5f..5289f4af 100644
--- a/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
+++ b/src/OpenIddict.EntityFramework/OpenIddictExtensions.cs
@@ -184,56 +184,85 @@ namespace Microsoft.Extensions.DependencyInjection
// Configure the TApplication entity.
builder.Entity()
- .HasKey(application => application.Id);
+ .HasKey(application => application.Id);
builder.Entity()
- .Property(application => application.ClientId)
- .HasMaxLength(450)
- .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
+ .Property(application => application.ClientId)
+ .IsRequired()
+ .HasMaxLength(450)
+ .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
builder.Entity()
- .HasMany(application => application.Authorizations)
- .WithOptional(authorization => authorization.Application)
- .Map(association => association.MapKey("ApplicationId"));
+ .Property(application => application.Type)
+ .IsRequired();
builder.Entity()
- .HasMany(application => application.Tokens)
- .WithOptional(token => token.Application)
- .Map(association => association.MapKey("ApplicationId"));
+ .HasMany(application => application.Authorizations)
+ .WithOptional(authorization => authorization.Application)
+ .Map(association => association.MapKey("ApplicationId"));
builder.Entity()
- .ToTable("OpenIddictApplications");
+ .HasMany(application => application.Tokens)
+ .WithOptional(token => token.Application)
+ .Map(association => association.MapKey("ApplicationId"));
+
+ builder.Entity()
+ .ToTable("OpenIddictApplications");
// Configure the TAuthorization entity.
builder.Entity()
- .HasKey(authorization => authorization.Id);
+ .HasKey(authorization => authorization.Id);
+
+ builder.Entity()
+ .Property(authorization => authorization.Status)
+ .IsRequired();
+
+ builder.Entity()
+ .Property(authorization => authorization.Subject)
+ .IsRequired();
+
+ builder.Entity()
+ .Property(authorization => authorization.Type)
+ .IsRequired();
builder.Entity()
- .HasMany(application => application.Tokens)
- .WithOptional(token => token.Authorization)
- .Map(association => association.MapKey("AuthorizationId"));
+ .HasMany(application => application.Tokens)
+ .WithOptional(token => token.Authorization)
+ .Map(association => association.MapKey("AuthorizationId"));
builder.Entity()
- .ToTable("OpenIddictAuthorizations");
+ .ToTable("OpenIddictAuthorizations");
// Configure the TScope entity.
builder.Entity()
- .HasKey(scope => scope.Id);
+ .HasKey(scope => scope.Id);
+
+ builder.Entity()
+ .Property(scope => scope.Name)
+ .IsRequired();
builder.Entity()
- .ToTable("OpenIddictScopes");
+ .ToTable("OpenIddictScopes");
// Configure the TToken entity.
builder.Entity()
- .HasKey(token => token.Id);
+ .HasKey(token => token.Id);
+
+ builder.Entity()
+ .Property(token => token.Hash)
+ .HasMaxLength(450)
+ .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
+
+ builder.Entity()
+ .Property(token => token.Subject)
+ .IsRequired();
builder.Entity()
- .Property(token => token.Hash)
- .HasMaxLength(450)
- .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
+ .Property(token => token.Type)
+ .IsRequired();
builder.Entity()
- .ToTable("OpenIddictTokens");
+ .ToTable("OpenIddictTokens");
return builder;
}
diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
index f880d828..8b6aa6b4 100644
--- a/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
@@ -146,7 +146,8 @@ namespace OpenIddict.EntityFramework
var authorization = new TAuthorization
{
Status = descriptor.Status,
- Subject = descriptor.Subject
+ Subject = descriptor.Subject,
+ Type = descriptor.Type
};
if (descriptor.Scopes.Count != 0)
diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
index ca82c718..0e061667 100644
--- a/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
+++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictExtensions.cs
@@ -225,6 +225,12 @@ namespace Microsoft.Extensions.DependencyInjection
entity.HasIndex(application => application.ClientId)
.IsUnique(unique: true);
+ entity.Property(application => application.ClientId)
+ .IsRequired(required: true);
+
+ entity.Property(application => application.Type)
+ .IsRequired();
+
entity.HasMany(application => application.Authorizations)
.WithOne(authorization => authorization.Application)
.HasForeignKey("ApplicationId")
@@ -243,6 +249,15 @@ namespace Microsoft.Extensions.DependencyInjection
{
entity.HasKey(authorization => authorization.Id);
+ entity.Property(authorization => authorization.Status)
+ .IsRequired();
+
+ entity.Property(authorization => authorization.Subject)
+ .IsRequired();
+
+ entity.Property(authorization => authorization.Type)
+ .IsRequired();
+
entity.HasMany(application => application.Tokens)
.WithOne(token => token.Authorization)
.HasForeignKey("AuthorizationId")
@@ -256,6 +271,9 @@ namespace Microsoft.Extensions.DependencyInjection
{
entity.HasKey(scope => scope.Id);
+ entity.Property(scope => scope.Name)
+ .IsRequired();
+
entity.ToTable("OpenIddictScopes");
});
@@ -267,6 +285,12 @@ namespace Microsoft.Extensions.DependencyInjection
entity.HasIndex(token => token.Hash)
.IsUnique(unique: true);
+ entity.Property(token => token.Subject)
+ .IsRequired();
+
+ entity.Property(token => token.Type)
+ .IsRequired();
+
entity.ToTable("OpenIddictTokens");
});
diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
index df97afd9..7089f663 100644
--- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
+++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
@@ -145,7 +145,8 @@ namespace OpenIddict.EntityFrameworkCore
var authorization = new TAuthorization
{
Status = descriptor.Status,
- Subject = descriptor.Subject
+ Subject = descriptor.Subject,
+ Type = descriptor.Type
};
if (descriptor.Scopes.Count != 0)
diff --git a/src/OpenIddict.Models/OpenIddictAuthorization.cs b/src/OpenIddict.Models/OpenIddictAuthorization.cs
index 5ec20cd3..62b5ac82 100644
--- a/src/OpenIddict.Models/OpenIddictAuthorization.cs
+++ b/src/OpenIddict.Models/OpenIddictAuthorization.cs
@@ -65,5 +65,10 @@ namespace OpenIddict.Models
/// associated with the current authorization.
///
public virtual IList Tokens { get; } = new List();
+
+ ///
+ /// Gets or sets the type of the current authorization.
+ ///
+ public virtual string Type { get; set; }
}
}
diff --git a/src/OpenIddict/OpenIddictProvider.Serialization.cs b/src/OpenIddict/OpenIddictProvider.Serialization.cs
index da335e25..f2bb4dee 100644
--- a/src/OpenIddict/OpenIddictProvider.Serialization.cs
+++ b/src/OpenIddict/OpenIddictProvider.Serialization.cs
@@ -251,7 +251,7 @@ namespace OpenIddict
descriptor.AuthorizationId = ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId);
}
- // Otherwise, create an ad-hoc authorization if the token is an authorization code.
+ // Otherwise, create an ad hoc authorization if the token is an authorization code.
else if (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode)
{
Debug.Assert(!string.IsNullOrEmpty(descriptor.ApplicationId), "The client identifier shouldn't be null.");
@@ -261,7 +261,7 @@ namespace OpenIddict
{
descriptor.AuthorizationId = await Authorizations.GetIdAsync(authorization, context.RequestAborted);
- Logger.LogInformation("An ad-hoc authorization was automatically created and " +
+ Logger.LogInformation("An ad hoc authorization was automatically created and " +
"associated with the '{ClientId}' application: {Identifier}.",
request.ClientId, descriptor.AuthorizationId);
}
@@ -401,7 +401,8 @@ namespace OpenIddict
{
ApplicationId = token.ApplicationId,
Status = OpenIddictConstants.Statuses.Valid,
- Subject = token.Subject
+ Subject = token.Subject,
+ Type = OpenIddictConstants.AuthorizationTypes.AdHoc
};
foreach (var scope in request.GetScopes())
diff --git a/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs b/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs
index 0179b014..5282db38 100644
--- a/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs
+++ b/test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs
@@ -571,7 +571,7 @@ namespace OpenIddict.Tests
builder.Services.AddSingleton(CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(It.IsAny(), It.IsAny()))
- .ReturnsAsync(token);
+ .ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny()))
.ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
@@ -596,7 +596,8 @@ namespace OpenIddict.Tests
Mock.Get(manager).Verify(mock => mock.CreateAsync(
It.Is(descriptor =>
descriptor.ApplicationId == "3E228451-1555-46F7-A471-951EFBA23A56" &&
- descriptor.Subject == "Bob le Magnifique"),
+ descriptor.Subject == "Bob le Magnifique" &&
+ descriptor.Type == OpenIddictConstants.AuthorizationTypes.AdHoc),
It.IsAny()), Times.Once());
}