34 changed files with 0 additions and 6201 deletions
@ -1,12 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<Description>Relational entities for the NHibernate 5.x stores.</Description> |
|
||||
<PackageTags>$(PackageTags);nhibernate;models</PackageTags> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,120 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Models |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict application.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictApplication : OpenIddictApplication<string, OpenIddictAuthorization, OpenIddictToken> |
|
||||
{ |
|
||||
public OpenIddictApplication() |
|
||||
{ |
|
||||
// Generate a new string identifier.
|
|
||||
Id = Guid.NewGuid().ToString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict application.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictApplication<TKey> : OpenIddictApplication<TKey, OpenIddictAuthorization<TKey>, OpenIddictToken<TKey>> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict application.
|
|
||||
/// </summary>
|
|
||||
[DebuggerDisplay("Id = {Id.ToString(),nq} ; ClientId = {ClientId,nq} ; Type = {Type,nq}")] |
|
||||
public class OpenIddictApplication<TKey, TAuthorization, TToken> where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the list of the authorizations associated with this application.
|
|
||||
/// </summary>
|
|
||||
public virtual IList<TAuthorization> Authorizations { get; set; } = new List<TAuthorization>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the client identifier
|
|
||||
/// associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual string ClientId { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the client secret associated with the current application.
|
|
||||
/// Note: depending on the application manager used to create this instance,
|
|
||||
/// this property may be hashed or encrypted for security reasons.
|
|
||||
/// </summary>
|
|
||||
public virtual string ClientSecret { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the consent type
|
|
||||
/// associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual string ConsentType { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the display name
|
|
||||
/// associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual string DisplayName { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the unique identifier
|
|
||||
/// associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual TKey Id { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the permissions associated with the
|
|
||||
/// current application, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string Permissions { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the logout callback URLs associated with
|
|
||||
/// the current application, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string PostLogoutRedirectUris { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the additional properties serialized as a JSON object,
|
|
||||
/// or <c>null</c> if no bag was associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual string Properties { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the callback URLs associated with the
|
|
||||
/// current application, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string RedirectUris { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the requirements associated with the
|
|
||||
/// current application, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string Requirements { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the list of the tokens associated with this application.
|
|
||||
/// </summary>
|
|
||||
public virtual IList<TToken> Tokens { get; set; } = new List<TToken>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the application type
|
|
||||
/// associated with the current application.
|
|
||||
/// </summary>
|
|
||||
public virtual string Type { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the entity version, used as a concurrency token.
|
|
||||
/// </summary>
|
|
||||
public virtual int Version { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,87 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Models |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict authorization.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictAuthorization : OpenIddictAuthorization<string, OpenIddictApplication, OpenIddictToken> |
|
||||
{ |
|
||||
public OpenIddictAuthorization() |
|
||||
{ |
|
||||
// Generate a new string identifier.
|
|
||||
Id = Guid.NewGuid().ToString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict authorization.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictAuthorization<TKey> : OpenIddictAuthorization<TKey, OpenIddictApplication<TKey>, OpenIddictToken<TKey>> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict authorization.
|
|
||||
/// </summary>
|
|
||||
[DebuggerDisplay("Id = {Id.ToString(),nq} ; Subject = {Subject,nq} ; Type = {Type,nq} ; Status = {Status,nq}")] |
|
||||
public class OpenIddictAuthorization<TKey, TApplication, TToken> where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the application associated with the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual TApplication Application { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the unique identifier
|
|
||||
/// associated with the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual TKey Id { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the additional properties serialized as a JSON object,
|
|
||||
/// or <c>null</c> if no bag was associated with the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual string Properties { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the scopes associated with the current
|
|
||||
/// authorization, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string Scopes { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the status of the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual string Status { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the subject associated with the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual string Subject { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the list of tokens
|
|
||||
/// associated with the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual IList<TToken> Tokens { get; set; } = new List<TToken>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the type of the current authorization.
|
|
||||
/// </summary>
|
|
||||
public virtual string Type { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the entity version, used as a concurrency token.
|
|
||||
/// </summary>
|
|
||||
public virtual int Version { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,71 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Models |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict scope.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictScope : OpenIddictScope<string> |
|
||||
{ |
|
||||
public OpenIddictScope() |
|
||||
{ |
|
||||
// Generate a new string identifier.
|
|
||||
Id = Guid.NewGuid().ToString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict scope.
|
|
||||
/// </summary>
|
|
||||
[DebuggerDisplay("Id = {Id.ToString(),nq} ; Name = {Name,nq}")] |
|
||||
public class OpenIddictScope<TKey> where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the public description
|
|
||||
/// associated with the current scope.
|
|
||||
/// </summary>
|
|
||||
public virtual string Description { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the display name
|
|
||||
/// associated with the current scope.
|
|
||||
/// </summary>
|
|
||||
public virtual string DisplayName { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the unique identifier
|
|
||||
/// associated with the current scope.
|
|
||||
/// </summary>
|
|
||||
public virtual TKey Id { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the unique name
|
|
||||
/// associated with the current scope.
|
|
||||
/// </summary>
|
|
||||
public virtual string Name { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the additional properties serialized as a JSON object,
|
|
||||
/// or <c>null</c> if no bag was associated with the current scope.
|
|
||||
/// </summary>
|
|
||||
public virtual string Properties { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the resources associated with the
|
|
||||
/// current scope, serialized as a JSON array.
|
|
||||
/// </summary>
|
|
||||
public virtual string Resources { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the entity version, used as a concurrency token.
|
|
||||
/// </summary>
|
|
||||
public virtual int Version { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,107 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Models |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict token.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictToken : OpenIddictToken<string, OpenIddictApplication, OpenIddictAuthorization> |
|
||||
{ |
|
||||
public OpenIddictToken() |
|
||||
{ |
|
||||
// Generate a new string identifier.
|
|
||||
Id = Guid.NewGuid().ToString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict token.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictToken<TKey> : OpenIddictToken<TKey, OpenIddictApplication<TKey>, OpenIddictAuthorization<TKey>> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Represents an OpenIddict token.
|
|
||||
/// </summary>
|
|
||||
[DebuggerDisplay("Id = {Id.ToString(),nq} ; Subject = {Subject,nq} ; Type = {Type,nq} ; Status = {Status,nq}")] |
|
||||
public class OpenIddictToken<TKey, TApplication, TAuthorization> where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the application associated with the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual TApplication Application { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the authorization associated with the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual TAuthorization Authorization { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the date on which the token
|
|
||||
/// will start to be considered valid.
|
|
||||
/// </summary>
|
|
||||
public virtual DateTimeOffset? CreationDate { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the date on which the token
|
|
||||
/// will no longer be considered valid.
|
|
||||
/// </summary>
|
|
||||
public virtual DateTimeOffset? ExpirationDate { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the unique identifier
|
|
||||
/// associated with the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual TKey Id { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the payload of the current token, if applicable.
|
|
||||
/// Note: this property is only used for reference tokens
|
|
||||
/// and may be encrypted for security reasons.
|
|
||||
/// </summary>
|
|
||||
public virtual string Payload { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the additional properties serialized as a JSON object,
|
|
||||
/// or <c>null</c> if no bag was associated with the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual string Properties { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the reference identifier associated
|
|
||||
/// with the current token, if applicable.
|
|
||||
/// Note: this property is only used for reference tokens
|
|
||||
/// and may be hashed or encrypted for security reasons.
|
|
||||
/// </summary>
|
|
||||
public virtual string ReferenceId { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the status of the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual string Status { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the subject associated with the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual string Subject { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the type of the current token.
|
|
||||
/// </summary>
|
|
||||
public virtual string Type { get; set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the entity version, used as a concurrency token.
|
|
||||
/// </summary>
|
|
||||
public virtual int Version { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,27 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using NHibernate; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes the NHibernate session used by the OpenIddict stores.
|
|
||||
/// </summary>
|
|
||||
public interface IOpenIddictNHibernateContext |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="ISession"/>.
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the
|
|
||||
/// asynchronous operation, whose result returns the NHibernate session.
|
|
||||
/// </returns>
|
|
||||
ValueTask<ISession> GetSessionAsync(CancellationToken cancellationToken); |
|
||||
} |
|
||||
} |
|
||||
@ -1,101 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using NHibernate.Mapping.ByCode; |
|
||||
using NHibernate.Mapping.ByCode.Conformist; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines a relational mapping for the Application entity.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public class OpenIddictApplicationMapping<TApplication, TAuthorization, TToken, TKey> : ClassMapping<TApplication> |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictApplicationMapping() |
|
||||
{ |
|
||||
Id(application => application.Id, map => |
|
||||
{ |
|
||||
map.Generator(Generators.Identity); |
|
||||
}); |
|
||||
|
|
||||
Version(application => application.Version, map => |
|
||||
{ |
|
||||
map.Insert(true); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.ClientId, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
map.Unique(true); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.ClientSecret); |
|
||||
|
|
||||
Property(application => application.ConsentType); |
|
||||
|
|
||||
Property(application => application.DisplayName); |
|
||||
|
|
||||
Property(application => application.Permissions, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.PostLogoutRedirectUris, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.Properties, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.RedirectUris, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(application => application.Type, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
}); |
|
||||
|
|
||||
Bag(application => application.Authorizations, |
|
||||
map => |
|
||||
{ |
|
||||
map.Key(key => key.Column("ApplicationId")); |
|
||||
}, |
|
||||
map => |
|
||||
{ |
|
||||
map.OneToMany(); |
|
||||
}); |
|
||||
|
|
||||
Bag(application => application.Tokens, |
|
||||
map => |
|
||||
{ |
|
||||
map.Key(key => key.Column("ApplicationId")); |
|
||||
}, |
|
||||
map => |
|
||||
{ |
|
||||
map.OneToMany(); |
|
||||
}); |
|
||||
|
|
||||
Table("OpenIddictApplications"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,79 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using NHibernate.Mapping.ByCode; |
|
||||
using NHibernate.Mapping.ByCode.Conformist; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines a relational mapping for the Authorization entity.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public class OpenIddictAuthorizationMapping<TAuthorization, TApplication, TToken, TKey> : ClassMapping<TAuthorization> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictAuthorizationMapping() |
|
||||
{ |
|
||||
Id(authorization => authorization.Id, map => |
|
||||
{ |
|
||||
map.Generator(Generators.Identity); |
|
||||
}); |
|
||||
|
|
||||
Version(authorization => authorization.Version, map => |
|
||||
{ |
|
||||
map.Insert(true); |
|
||||
}); |
|
||||
|
|
||||
Property(authorization => authorization.Properties, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(authorization => authorization.Scopes, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(authorization => authorization.Status, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
}); |
|
||||
|
|
||||
Property(authorization => authorization.Type, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
}); |
|
||||
|
|
||||
ManyToOne(authorization => authorization.Application, map => |
|
||||
{ |
|
||||
map.ForeignKey("ApplicationId"); |
|
||||
}); |
|
||||
|
|
||||
Bag(authorization => authorization.Tokens, |
|
||||
map => |
|
||||
{ |
|
||||
map.Key(key => key.Column("AuthorizationId")); |
|
||||
}, |
|
||||
map => |
|
||||
{ |
|
||||
map.OneToMany(); |
|
||||
}); |
|
||||
|
|
||||
Table("OpenIddictAuthorizations"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using NHibernate.Mapping.ByCode; |
|
||||
using NHibernate.Mapping.ByCode.Conformist; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines a relational mapping for the Scope entity.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public class OpenIddictScopeMapping<TScope, TKey> : ClassMapping<TScope> |
|
||||
where TScope : OpenIddictScope<TKey> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictScopeMapping() |
|
||||
{ |
|
||||
Id(scope => scope.Id, map => |
|
||||
{ |
|
||||
map.Generator(Generators.Identity); |
|
||||
}); |
|
||||
|
|
||||
Version(scope => scope.Version, map => |
|
||||
{ |
|
||||
map.Insert(true); |
|
||||
}); |
|
||||
|
|
||||
Property(scope => scope.Description, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(scope => scope.DisplayName); |
|
||||
|
|
||||
Property(scope => scope.Name, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
map.Unique(true); |
|
||||
}); |
|
||||
|
|
||||
Property(scope => scope.Properties, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(scope => scope.Resources, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Table("OpenIddictScopes"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,80 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using NHibernate.Mapping.ByCode; |
|
||||
using NHibernate.Mapping.ByCode.Conformist; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Defines a relational mapping for the Token entity.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the Key entity.</typeparam>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public class OpenIddictTokenMapping<TToken, TApplication, TAuthorization, TKey> : ClassMapping<TToken> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictTokenMapping() |
|
||||
{ |
|
||||
Id(token => token.Id, map => |
|
||||
{ |
|
||||
map.Generator(Generators.Identity); |
|
||||
}); |
|
||||
|
|
||||
Version(token => token.Version, map => |
|
||||
{ |
|
||||
map.Insert(true); |
|
||||
}); |
|
||||
|
|
||||
Property(token => token.CreationDate); |
|
||||
|
|
||||
Property(token => token.ExpirationDate); |
|
||||
|
|
||||
Property(token => token.Payload, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(token => token.Properties, map => |
|
||||
{ |
|
||||
map.Length(10000); |
|
||||
}); |
|
||||
|
|
||||
Property(token => token.ReferenceId); |
|
||||
|
|
||||
Property(token => token.Status, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
}); |
|
||||
|
|
||||
Property(token => token.Type, map => |
|
||||
{ |
|
||||
map.NotNullable(true); |
|
||||
}); |
|
||||
|
|
||||
ManyToOne(token => token.Application, map => |
|
||||
{ |
|
||||
map.Column("ApplicationId"); |
|
||||
}); |
|
||||
|
|
||||
ManyToOne(token => token.Authorization, map => |
|
||||
{ |
|
||||
map.Column("AuthorizationId"); |
|
||||
}); |
|
||||
|
|
||||
Table("OpenIddictTokens"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,26 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<Description>NHibernate 5.x stores for OpenIddict.</Description> |
|
||||
<PackageTags>$(PackageTags);nhibernate</PackageTags> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" /> |
|
||||
<ProjectReference Include="..\OpenIddict.NHibernate.Models\OpenIddict.NHibernate.Models.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" /> |
|
||||
<PackageReference Include="NHibernate" Version="$(NHibernateVersion)" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,102 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.ComponentModel; |
|
||||
using JetBrains.Annotations; |
|
||||
using NHibernate; |
|
||||
using OpenIddict.Core; |
|
||||
using OpenIddict.NHibernate; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace Microsoft.Extensions.DependencyInjection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes the necessary methods required to configure the OpenIddict NHibernate services.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictNHibernateBuilder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of <see cref="OpenIddictNHibernateBuilder"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="services">The services collection.</param>
|
|
||||
public OpenIddictNHibernateBuilder([NotNull] IServiceCollection services) |
|
||||
=> Services = services ?? throw new ArgumentNullException(nameof(services)); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the services collection.
|
|
||||
/// </summary>
|
|
||||
[EditorBrowsable(EditorBrowsableState.Never)] |
|
||||
public IServiceCollection Services { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Amends the default OpenIddict NHibernate configuration.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
|
|
||||
/// <remarks>This extension can be safely called multiple times.</remarks>
|
|
||||
/// <returns>The <see cref="OpenIddictNHibernateBuilder"/>.</returns>
|
|
||||
public OpenIddictNHibernateBuilder Configure([NotNull] Action<OpenIddictNHibernateOptions> configuration) |
|
||||
{ |
|
||||
if (configuration == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(configuration)); |
|
||||
} |
|
||||
|
|
||||
Services.Configure(configuration); |
|
||||
|
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Configures the NHibernate stores to use the specified session factory
|
|
||||
/// instead of retrieving it from the dependency injection container.
|
|
||||
/// </summary>
|
|
||||
/// <param name="factory">The <see cref="ISessionFactory"/>.</param>
|
|
||||
/// <returns>The <see cref="OpenIddictNHibernateBuilder"/>.</returns>
|
|
||||
public OpenIddictNHibernateBuilder UseSessionFactory([NotNull] ISessionFactory factory) |
|
||||
{ |
|
||||
if (factory == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(factory)); |
|
||||
} |
|
||||
|
|
||||
return Configure(options => options.SessionFactory = factory); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Configures OpenIddict to use the default OpenIddict Entity Framework entities, with the specified key type.
|
|
||||
/// </summary>
|
|
||||
/// <returns>The <see cref="OpenIddictNHibernateBuilder"/>.</returns>
|
|
||||
public OpenIddictNHibernateBuilder ReplaceDefaultEntities<TKey>() |
|
||||
where TKey : IEquatable<TKey> |
|
||||
=> ReplaceDefaultEntities<OpenIddictApplication<TKey>, |
|
||||
OpenIddictAuthorization<TKey>, |
|
||||
OpenIddictScope<TKey>, |
|
||||
OpenIddictToken<TKey>, TKey>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Configures OpenIddict to use the specified entities, derived from the default OpenIddict Entity Framework entities.
|
|
||||
/// </summary>
|
|
||||
/// <returns>The <see cref="OpenIddictNHibernateBuilder"/>.</returns>
|
|
||||
public OpenIddictNHibernateBuilder ReplaceDefaultEntities<TApplication, TAuthorization, TScope, TToken, TKey>() |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TScope : OpenIddictScope<TKey> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
Services.Configure<OpenIddictCoreOptions>(options => |
|
||||
{ |
|
||||
options.DefaultApplicationType = typeof(TApplication); |
|
||||
options.DefaultAuthorizationType = typeof(TAuthorization); |
|
||||
options.DefaultScopeType = typeof(TScope); |
|
||||
options.DefaultTokenType = typeof(TToken); |
|
||||
}); |
|
||||
|
|
||||
return this; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,125 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using NHibernate; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes the NHibernate session used by the OpenIddict stores.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictNHibernateContext : IOpenIddictNHibernateContext, IDisposable |
|
||||
{ |
|
||||
private readonly IOptionsMonitor<OpenIddictNHibernateOptions> _options; |
|
||||
private readonly IServiceProvider _provider; |
|
||||
private ISession _session; |
|
||||
|
|
||||
public OpenIddictNHibernateContext( |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options, |
|
||||
[NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_options = options; |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Disposes the session held by this instance, if applicable.
|
|
||||
/// </summary>
|
|
||||
public void Dispose() => _session?.Dispose(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="ISession"/>.
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the
|
|
||||
/// asynchronous operation, whose result returns the NHibernate session.
|
|
||||
/// </returns>
|
|
||||
/// <remarks>
|
|
||||
/// If a session factory was explicitly set in the OpenIddict NHibernate options,
|
|
||||
/// a new session, specific to the OpenIddict stores is automatically opened
|
|
||||
/// and disposed when the ambient scope is collected. If no session factory
|
|
||||
/// was set, the session is retrieved from the dependency injection container
|
|
||||
/// and a derived instance disabling automatic flush is managed by the context.
|
|
||||
/// </remarks>
|
|
||||
public ValueTask<ISession> GetSessionAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (_session != null) |
|
||||
{ |
|
||||
return new ValueTask<ISession>(_session); |
|
||||
} |
|
||||
|
|
||||
if (cancellationToken.IsCancellationRequested) |
|
||||
{ |
|
||||
return new ValueTask<ISession>(Task.FromCanceled<ISession>(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
var options = _options.CurrentValue; |
|
||||
if (options == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException("The OpenIddict NHibernate options cannot be retrieved."); |
|
||||
} |
|
||||
|
|
||||
// Note: by default, NHibernate is natively configured to perform automatic flushes
|
|
||||
// on queries when it determines stale data may be returned during their execution.
|
|
||||
// Combined with implicit entity updates, this feature is inconvenient for OpenIddict
|
|
||||
// as it may result in updated entities being persisted before they are explicitly
|
|
||||
// validated by the core managers and marked as updated by the NHibernate stores.
|
|
||||
// To ensure this doesn't interfere with OpenIddict, automatic flush is disabled.
|
|
||||
|
|
||||
var factory = options.SessionFactory; |
|
||||
if (factory == null) |
|
||||
{ |
|
||||
var session = _provider.GetService<ISession>(); |
|
||||
if (session != null) |
|
||||
{ |
|
||||
// If the flush mode is already set to manual, avoid creating a sub-session.
|
|
||||
// If the session must be derived, all the parameters are inherited from
|
|
||||
// the original session (except the flush mode, explicitly set to manual).
|
|
||||
if (session.FlushMode != FlushMode.Manual) |
|
||||
{ |
|
||||
session = _session = session.SessionWithOptions() |
|
||||
.AutoClose() |
|
||||
.AutoJoinTransaction() |
|
||||
.Connection() |
|
||||
.ConnectionReleaseMode() |
|
||||
.FlushMode(FlushMode.Manual) |
|
||||
.Interceptor() |
|
||||
.OpenSession(); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<ISession>(session); |
|
||||
} |
|
||||
|
|
||||
factory = _provider.GetService<ISessionFactory>(); |
|
||||
} |
|
||||
|
|
||||
if (factory == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("No suitable NHibernate session or session factory can be found.") |
|
||||
.Append("To configure the OpenIddict NHibernate stores to use a specific factory, use ") |
|
||||
.Append("'services.AddOpenIddict().AddCore().UseNHibernate().UseSessionFactory()' or register an ") |
|
||||
.Append("'ISession'/'ISessionFactory' in the dependency injection container in 'ConfigureServices()'.") |
|
||||
.ToString()); |
|
||||
} |
|
||||
|
|
||||
else |
|
||||
{ |
|
||||
var session = factory.OpenSession(); |
|
||||
session.FlushMode = FlushMode.Manual; |
|
||||
|
|
||||
return new ValueTask<ISession>(_session = session); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,91 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|
||||
using OpenIddict.NHibernate; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace Microsoft.Extensions.DependencyInjection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes extensions allowing to register the OpenIddict NHibernate services.
|
|
||||
/// </summary>
|
|
||||
public static class OpenIddictNHibernateExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Registers the NHibernate stores services in the DI container and
|
|
||||
/// configures OpenIddict to use the NHibernate entities by default.
|
|
||||
/// </summary>
|
|
||||
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
|
|
||||
/// <remarks>This extension can be safely called multiple times.</remarks>
|
|
||||
/// <returns>The <see cref="OpenIddictNHibernateBuilder"/>.</returns>
|
|
||||
public static OpenIddictNHibernateBuilder UseNHibernate([NotNull] this OpenIddictCoreBuilder builder) |
|
||||
{ |
|
||||
if (builder == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(builder)); |
|
||||
} |
|
||||
|
|
||||
// Since NHibernate may be used with databases performing case-insensitive or
|
|
||||
// culture-sensitive comparisons, ensure the additional filtering logic is enforced
|
|
||||
// in case case-sensitive stores were registered before this extension was called.
|
|
||||
builder.Configure(options => options.DisableAdditionalFiltering = false); |
|
||||
|
|
||||
builder.SetDefaultApplicationEntity<OpenIddictApplication>() |
|
||||
.SetDefaultAuthorizationEntity<OpenIddictAuthorization>() |
|
||||
.SetDefaultScopeEntity<OpenIddictScope>() |
|
||||
.SetDefaultTokenEntity<OpenIddictToken>(); |
|
||||
|
|
||||
builder.ReplaceApplicationStoreResolver<OpenIddictApplicationStoreResolver>() |
|
||||
.ReplaceAuthorizationStoreResolver<OpenIddictAuthorizationStoreResolver>() |
|
||||
.ReplaceScopeStoreResolver<OpenIddictScopeStoreResolver>() |
|
||||
.ReplaceTokenStoreResolver<OpenIddictTokenStoreResolver>(); |
|
||||
|
|
||||
builder.Services.TryAddSingleton<OpenIddictApplicationStoreResolver.TypeResolutionCache>(); |
|
||||
builder.Services.TryAddSingleton<OpenIddictAuthorizationStoreResolver.TypeResolutionCache>(); |
|
||||
builder.Services.TryAddSingleton<OpenIddictScopeStoreResolver.TypeResolutionCache>(); |
|
||||
builder.Services.TryAddSingleton<OpenIddictTokenStoreResolver.TypeResolutionCache>(); |
|
||||
|
|
||||
builder.Services.TryAddScoped(typeof(OpenIddictApplicationStore<,,,>)); |
|
||||
builder.Services.TryAddScoped(typeof(OpenIddictAuthorizationStore<,,,>)); |
|
||||
builder.Services.TryAddScoped(typeof(OpenIddictScopeStore<,>)); |
|
||||
builder.Services.TryAddScoped(typeof(OpenIddictTokenStore<,,,>)); |
|
||||
|
|
||||
builder.Services.TryAddScoped<IOpenIddictNHibernateContext, OpenIddictNHibernateContext>(); |
|
||||
|
|
||||
return new OpenIddictNHibernateBuilder(builder.Services); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Registers the NHibernate stores services in the DI container and
|
|
||||
/// configures OpenIddict to use the NHibernate entities by default.
|
|
||||
/// </summary>
|
|
||||
/// <param name="builder">The services builder used by OpenIddict to register new services.</param>
|
|
||||
/// <param name="configuration">The configuration delegate used to configure the NHibernate services.</param>
|
|
||||
/// <remarks>This extension can be safely called multiple times.</remarks>
|
|
||||
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
|
|
||||
public static OpenIddictCoreBuilder UseNHibernate( |
|
||||
[NotNull] this OpenIddictCoreBuilder builder, |
|
||||
[NotNull] Action<OpenIddictNHibernateBuilder> configuration) |
|
||||
{ |
|
||||
if (builder == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(builder)); |
|
||||
} |
|
||||
|
|
||||
if (configuration == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(configuration)); |
|
||||
} |
|
||||
|
|
||||
configuration(builder.UseNHibernate()); |
|
||||
|
|
||||
return builder; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,103 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using JetBrains.Annotations; |
|
||||
using NHibernate.Linq; |
|
||||
using NHibernate.Mapping.ByCode; |
|
||||
using OpenIddict.NHibernate; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace NHibernate.Cfg |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes extensions simplifying the integration between OpenIddict and NHibernate.
|
|
||||
/// </summary>
|
|
||||
public static class OpenIddictNHibernateHelpers |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Registers the OpenIddict entity mappings in the NHibernate
|
|
||||
/// configuration using the default entities and the default key type.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">The NHibernate configuration builder.</param>
|
|
||||
/// <returns>The <see cref="Configuration"/>.</returns>
|
|
||||
public static Configuration UseOpenIddict([NotNull] this Configuration configuration) |
|
||||
=> configuration.UseOpenIddict<OpenIddictApplication, |
|
||||
OpenIddictAuthorization, |
|
||||
OpenIddictScope, |
|
||||
OpenIddictToken, string>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Registers the OpenIddict entity mappings in the NHibernate
|
|
||||
/// configuration using the default entities and the specified key type.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">The NHibernate configuration builder.</param>
|
|
||||
/// <returns>The <see cref="Configuration"/>.</returns>
|
|
||||
public static Configuration UseOpenIddict<TKey>([NotNull] this Configuration configuration) |
|
||||
where TKey : IEquatable<TKey> |
|
||||
=> configuration.UseOpenIddict<OpenIddictApplication<TKey>, |
|
||||
OpenIddictAuthorization<TKey>, |
|
||||
OpenIddictScope<TKey>, |
|
||||
OpenIddictToken<TKey>, TKey>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Registers the OpenIddict entity mappings in the NHibernate
|
|
||||
/// configuration using the specified entities and the specified key type.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">The NHibernate configuration builder.</param>
|
|
||||
/// <returns>The <see cref="Configuration"/>.</returns>
|
|
||||
public static Configuration UseOpenIddict<TApplication, TAuthorization, TScope, TToken, TKey>([NotNull] this Configuration configuration) |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TScope : OpenIddictScope<TKey> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
if (configuration == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(configuration)); |
|
||||
} |
|
||||
|
|
||||
var mapper = new ModelMapper(); |
|
||||
mapper.AddMapping<OpenIddictApplicationMapping<TApplication, TAuthorization, TToken, TKey>>(); |
|
||||
mapper.AddMapping<OpenIddictAuthorizationMapping<TAuthorization, TApplication, TToken, TKey>>(); |
|
||||
mapper.AddMapping<OpenIddictScopeMapping<TScope, TKey>>(); |
|
||||
mapper.AddMapping<OpenIddictTokenMapping<TToken, TApplication, TAuthorization, TKey>>(); |
|
||||
|
|
||||
configuration.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities()); |
|
||||
|
|
||||
return configuration; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the query and returns the results as a non-streamed async enumeration.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">The type of the returned entities.</typeparam>
|
|
||||
/// <param name="source">The query source.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The non-streamed async enumeration containing the results.</returns>
|
|
||||
internal static IAsyncEnumerable<T> AsAsyncEnumerable<T>([NotNull] this IQueryable<T> source, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (source == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(source)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<T> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
foreach (var element in await source.ToListAsync(cancellationToken)) |
|
||||
{ |
|
||||
yield return element; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using NHibernate; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides various settings needed to configure the OpenIddict NHibernate integration.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets or sets the session factory used by the OpenIddict NHibernate stores.
|
|
||||
/// If none is explicitly set, the session factory is resolved from the DI container.
|
|
||||
/// </summary>
|
|
||||
public ISessionFactory SessionFactory { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,77 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Concurrent; |
|
||||
using System.Text; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Extensions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes a method allowing to resolve an application store.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictApplicationStoreResolver : IOpenIddictApplicationStoreResolver |
|
||||
{ |
|
||||
private readonly TypeResolutionCache _cache; |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
public OpenIddictApplicationStoreResolver( |
|
||||
[NotNull] TypeResolutionCache cache, |
|
||||
[NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_cache = cache; |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns an application store compatible with the specified application type or throws an
|
|
||||
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
|
|
||||
public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class |
|
||||
{ |
|
||||
var store = _provider.GetService<IOpenIddictApplicationStore<TApplication>>(); |
|
||||
if (store != null) |
|
||||
{ |
|
||||
return store; |
|
||||
} |
|
||||
|
|
||||
var type = _cache.GetOrAdd(typeof(TApplication), key => |
|
||||
{ |
|
||||
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictApplication<,,>)); |
|
||||
if (root == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("The specified application type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictApplication' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictApplication' entity.") |
|
||||
.ToString()); |
|
||||
} |
|
||||
|
|
||||
return typeof(OpenIddictApplicationStore<,,,>).MakeGenericType( |
|
||||
/* TApplication: */ key, |
|
||||
/* TAuthorization: */ root.GenericTypeArguments[1], |
|
||||
/* TToken: */ root.GenericTypeArguments[2], |
|
||||
/* TKey: */ root.GenericTypeArguments[0]); |
|
||||
}); |
|
||||
|
|
||||
return (IOpenIddictApplicationStore<TApplication>) _provider.GetRequiredService(type); |
|
||||
} |
|
||||
|
|
||||
// Note: NHibernate resolvers are registered as scoped dependencies as their inner
|
|
||||
// service provider must be able to resolve scoped services (typically, the store they return).
|
|
||||
// To avoid having to declare a static type resolution cache, a special cache service is used
|
|
||||
// here and registered as a singleton dependency so that its content persists beyond the scope.
|
|
||||
public class TypeResolutionCache : ConcurrentDictionary<Type, Type> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,77 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Concurrent; |
|
||||
using System.Text; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Extensions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes a method allowing to resolve an authorization store.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictAuthorizationStoreResolver : IOpenIddictAuthorizationStoreResolver |
|
||||
{ |
|
||||
private readonly TypeResolutionCache _cache; |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
public OpenIddictAuthorizationStoreResolver( |
|
||||
[NotNull] TypeResolutionCache cache, |
|
||||
[NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_cache = cache; |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns an authorization store compatible with the specified authorization type or throws an
|
|
||||
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
|
|
||||
public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class |
|
||||
{ |
|
||||
var store = _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>(); |
|
||||
if (store != null) |
|
||||
{ |
|
||||
return store; |
|
||||
} |
|
||||
|
|
||||
var type = _cache.GetOrAdd(typeof(TAuthorization), key => |
|
||||
{ |
|
||||
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictAuthorization<,,>)); |
|
||||
if (root == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("The specified authorization type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictAuthorization' entity.") |
|
||||
.ToString()); |
|
||||
} |
|
||||
|
|
||||
return typeof(OpenIddictAuthorizationStore<,,,>).MakeGenericType( |
|
||||
/* TAuthorization: */ key, |
|
||||
/* TApplication: */ root.GenericTypeArguments[1], |
|
||||
/* TToken: */ root.GenericTypeArguments[2], |
|
||||
/* TKey: */ root.GenericTypeArguments[0]); |
|
||||
}); |
|
||||
|
|
||||
return (IOpenIddictAuthorizationStore<TAuthorization>) _provider.GetRequiredService(type); |
|
||||
} |
|
||||
|
|
||||
// Note: NHibernate resolvers are registered as scoped dependencies as their inner
|
|
||||
// service provider must be able to resolve scoped services (typically, the store they return).
|
|
||||
// To avoid having to declare a static type resolution cache, a special cache service is used
|
|
||||
// here and registered as a singleton dependency so that its content persists beyond the scope.
|
|
||||
public class TypeResolutionCache : ConcurrentDictionary<Type, Type> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,75 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Concurrent; |
|
||||
using System.Text; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Extensions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes a method allowing to resolve a scope store.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictScopeStoreResolver : IOpenIddictScopeStoreResolver |
|
||||
{ |
|
||||
private readonly TypeResolutionCache _cache; |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
public OpenIddictScopeStoreResolver( |
|
||||
[NotNull] TypeResolutionCache cache, |
|
||||
[NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_cache = cache; |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a scope store compatible with the specified scope type or throws an
|
|
||||
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
|
|
||||
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
|
|
||||
public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class |
|
||||
{ |
|
||||
var store = _provider.GetService<IOpenIddictScopeStore<TScope>>(); |
|
||||
if (store != null) |
|
||||
{ |
|
||||
return store; |
|
||||
} |
|
||||
|
|
||||
var type = _cache.GetOrAdd(typeof(TScope), key => |
|
||||
{ |
|
||||
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictScope<>)); |
|
||||
if (root == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("The specified scope type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictScope' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") |
|
||||
.ToString()); |
|
||||
} |
|
||||
|
|
||||
return typeof(OpenIddictScopeStore<,>).MakeGenericType( |
|
||||
/* TScope: */ key, |
|
||||
/* TKey: */ root.GenericTypeArguments[0]); |
|
||||
}); |
|
||||
|
|
||||
return (IOpenIddictScopeStore<TScope>) _provider.GetRequiredService(type); |
|
||||
} |
|
||||
|
|
||||
// Note: NHibernate resolvers are registered as scoped dependencies as their inner
|
|
||||
// service provider must be able to resolve scoped services (typically, the store they return).
|
|
||||
// To avoid having to declare a static type resolution cache, a special cache service is used
|
|
||||
// here and registered as a singleton dependency so that its content persists beyond the scope.
|
|
||||
public class TypeResolutionCache : ConcurrentDictionary<Type, Type> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,77 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Concurrent; |
|
||||
using System.Text; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Extensions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Exposes a method allowing to resolve a token store.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictTokenStoreResolver : IOpenIddictTokenStoreResolver |
|
||||
{ |
|
||||
private readonly TypeResolutionCache _cache; |
|
||||
private readonly IServiceProvider _provider; |
|
||||
|
|
||||
public OpenIddictTokenStoreResolver( |
|
||||
[NotNull] TypeResolutionCache cache, |
|
||||
[NotNull] IServiceProvider provider) |
|
||||
{ |
|
||||
_cache = cache; |
|
||||
_provider = provider; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns a token store compatible with the specified token type or throws an
|
|
||||
/// <see cref="InvalidOperationException"/> if no store can be built using the specified type.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
|
|
||||
public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class |
|
||||
{ |
|
||||
var store = _provider.GetService<IOpenIddictTokenStore<TToken>>(); |
|
||||
if (store != null) |
|
||||
{ |
|
||||
return store; |
|
||||
} |
|
||||
|
|
||||
var type = _cache.GetOrAdd(typeof(TToken), key => |
|
||||
{ |
|
||||
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictToken<,,>)); |
|
||||
if (root == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("The specified token type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictToken' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictToken' entity.") |
|
||||
.ToString()); |
|
||||
} |
|
||||
|
|
||||
return typeof(OpenIddictTokenStore<,,,>).MakeGenericType( |
|
||||
/* TToken: */ key, |
|
||||
/* TApplication: */ root.GenericTypeArguments[1], |
|
||||
/* TAuthorization: */ root.GenericTypeArguments[2], |
|
||||
/* TKey: */ root.GenericTypeArguments[0]); |
|
||||
}); |
|
||||
|
|
||||
return (IOpenIddictTokenStore<TToken>) _provider.GetRequiredService(type); |
|
||||
} |
|
||||
|
|
||||
// Note: NHibernate resolvers are registered as scoped dependencies as their inner
|
|
||||
// service provider must be able to resolve scoped services (typically, the store they return).
|
|
||||
// To avoid having to declare a static type resolution cache, a special cache service is used
|
|
||||
// here and registered as a singleton dependency so that its content persists beyond the scope.
|
|
||||
public class TypeResolutionCache : ConcurrentDictionary<Type, Type> { } |
|
||||
} |
|
||||
} |
|
||||
File diff suppressed because it is too large
@ -1,950 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Text; |
|
||||
using System.Text.Encodings.Web; |
|
||||
using System.Text.Json; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using NHibernate; |
|
||||
using NHibernate.Cfg; |
|
||||
using NHibernate.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictAuthorizationStore : OpenIddictAuthorizationStore<OpenIddictAuthorization, |
|
||||
OpenIddictApplication, |
|
||||
OpenIddictToken, string> |
|
||||
{ |
|
||||
public OpenIddictAuthorizationStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
: base(cache, context, options) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public class OpenIddictAuthorizationStore<TKey> : OpenIddictAuthorizationStore<OpenIddictAuthorization<TKey>, |
|
||||
OpenIddictApplication<TKey>, |
|
||||
OpenIddictToken<TKey>, TKey> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictAuthorizationStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
: base(cache, context, options) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public class OpenIddictAuthorizationStore<TAuthorization, TApplication, TToken, TKey> : IOpenIddictAuthorizationStore<TAuthorization> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken> |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictAuthorizationStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
{ |
|
||||
Cache = cache; |
|
||||
Context = context; |
|
||||
Options = options; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cache associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the database context associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IOpenIddictNHibernateContext Context { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the options associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IOptionsMonitor<OpenIddictNHibernateOptions> Options { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of authorizations that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of authorizations in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await session.Query<TAuthorization>().LongCountAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of authorizations that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of authorizations that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await query(session.Query<TAuthorization>()).LongCountAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
await session.SaveAsync(authorization, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes an existing authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
// Delete all the tokens associated with the authorization.
|
|
||||
await (from token in session.Query<TToken>() |
|
||||
where token.Authorization.Id.Equals(authorization.Id) |
|
||||
select token).DeleteAsync(cancellationToken); |
|
||||
|
|
||||
await session.DeleteAsync(authorization, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
catch (StaleObjectStateException exception) |
|
||||
{ |
|
||||
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() |
|
||||
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.") |
|
||||
.Append("Reload the authorization from the database and retry the operation.") |
|
||||
.ToString(), exception); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations corresponding to the specified
|
|
||||
/// subject and associated with the application identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the subject/client.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var key = ConvertIdentifierFromString(client); |
|
||||
|
|
||||
await foreach (var authorization in |
|
||||
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application) |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == subject |
|
||||
select authorization).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations matching the specified parameters.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="status">The authorization status.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the criteria.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, |
|
||||
[NotNull] string status, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(status)) |
|
||||
{ |
|
||||
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var key = ConvertIdentifierFromString(client); |
|
||||
|
|
||||
await foreach (var authorization in |
|
||||
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application) |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == subject && |
|
||||
authorization.Status == status |
|
||||
select authorization).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations matching the specified parameters.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="status">The authorization status.</param>
|
|
||||
/// <param name="type">The authorization type.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the criteria.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, |
|
||||
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(status)) |
|
||||
{ |
|
||||
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(type)) |
|
||||
{ |
|
||||
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var key = ConvertIdentifierFromString(client); |
|
||||
|
|
||||
await foreach (var authorization in |
|
||||
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application) |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == subject && |
|
||||
authorization.Status == status && |
|
||||
authorization.Type == type |
|
||||
select authorization).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations matching the specified parameters.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="status">The authorization status.</param>
|
|
||||
/// <param name="type">The authorization type.</param>
|
|
||||
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the criteria.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, |
|
||||
[NotNull] string status, [NotNull] string type, |
|
||||
ImmutableArray<string> scopes, CancellationToken cancellationToken) |
|
||||
=> FindAsync(subject, client, status, type, cancellationToken) |
|
||||
.WhereAwait(async authorization => new HashSet<string>( |
|
||||
await GetScopesAsync(authorization, cancellationToken), StringComparer.Ordinal).IsSupersetOf(scopes)); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the list of authorizations corresponding to the specified application identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The application identifier associated with the authorizations.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the specified application.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindByApplicationIdAsync( |
|
||||
[NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var key = ConvertIdentifierFromString(identifier); |
|
||||
|
|
||||
await foreach (var authorization in |
|
||||
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application) |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) |
|
||||
select authorization).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves an authorization using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorization corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await session.GetAsync<TAuthorization>(ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the authorizations corresponding to the specified subject.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The authorizations corresponding to the specified subject.</returns>
|
|
||||
public virtual IAsyncEnumerable<TAuthorization> FindBySubjectAsync( |
|
||||
[NotNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TAuthorization> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
await foreach (var authorization in |
|
||||
(from authorization in session.Query<TAuthorization>().Fetch(authorization => authorization.Application) |
|
||||
where authorization.Subject == subject |
|
||||
select authorization).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the optional application identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the application identifier associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (authorization.Application == null) |
|
||||
{ |
|
||||
return new ValueTask<string>(result: null); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(authorization.Application.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
return await query(session.Query<TAuthorization>() |
|
||||
.Fetch(authorization => authorization.Application), state).FirstOrDefaultAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(authorization.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(authorization.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableDictionary<string, JsonElement>>(ImmutableDictionary.Create<string, JsonElement>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified properties is an expensive operation.
|
|
||||
// To mitigate that, the resulting object is stored in the memory cache.
|
|
||||
var key = string.Concat("68056e1a-dbcf-412b-9a6a-d791c7dbe726", "\x1e", authorization.Properties); |
|
||||
var properties = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JsonSerializer.Deserialize<ImmutableDictionary<string, JsonElement>>(authorization.Properties); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the scopes associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scopes associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetScopesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(authorization.Scopes)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified scopes is an expensive operation.
|
|
||||
// To mitigate that, the resulting array is stored in the memory cache.
|
|
||||
var key = string.Concat("2ba4ab0f-e2ec-4d48-b3bd-28e2bb660c75", "\x1e", authorization.Scopes); |
|
||||
var scopes = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JsonSerializer.Deserialize<ImmutableArray<string>>(authorization.Scopes); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(scopes); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the status associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the status associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetStatusAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Status); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the subject associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the subject associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetSubjectAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Subject); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the type associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the type associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Type); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated authorization, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TAuthorization> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
return new ValueTask<TAuthorization>(Activator.CreateInstance<TAuthorization>()); |
|
||||
} |
|
||||
|
|
||||
catch (MemberAccessException exception) |
|
||||
{ |
|
||||
return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>( |
|
||||
new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("An error occurred while trying to create a new authorization instance.") |
|
||||
.Append("Make sure that the authorization entity is not abstract and has a public parameterless constructor ") |
|
||||
.Append("or create a custom authorization store that overrides 'InstantiateAsync()' to use a custom factory.") |
|
||||
.ToString(), exception))); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>All the elements returned when executing the specified query.</returns>
|
|
||||
public virtual async IAsyncEnumerable<TAuthorization> ListAsync( |
|
||||
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var query = session.Query<TAuthorization>() |
|
||||
.Fetch(authorization => authorization.Application) |
|
||||
.OrderBy(authorization => authorization.Id) |
|
||||
.AsQueryable(); |
|
||||
|
|
||||
if (offset.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(offset.Value); |
|
||||
} |
|
||||
|
|
||||
if (count.HasValue) |
|
||||
{ |
|
||||
query = query.Take(count.Value); |
|
||||
} |
|
||||
|
|
||||
await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return authorization; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>All the elements returned when executing the specified query.</returns>
|
|
||||
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
await foreach (var element in query( |
|
||||
session.Query<TAuthorization>() |
|
||||
.Fetch(authorization => authorization.Application), state).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return element; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes the authorizations that are marked as invalid and the ad-hoc ones that have no valid/nonexpired token attached.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask PruneAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
await (from token in session.Query<TToken>() |
|
||||
where token.Status != OpenIddictConstants.Statuses.Valid || |
|
||||
token.ExpirationDate < DateTimeOffset.UtcNow |
|
||||
select token).DeleteAsync(cancellationToken); |
|
||||
|
|
||||
await (from authorization in session.Query<TAuthorization>() |
|
||||
where authorization.Status != OpenIddictConstants.Statuses.Valid || |
|
||||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc && !authorization.Tokens.Any()) |
|
||||
select authorization).DeleteAsync(cancellationToken); |
|
||||
|
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the application identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="identifier">The unique identifier associated with the client application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask SetApplicationIdAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
if (!string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
authorization.Application = await session.LoadAsync<TApplication>(ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
else |
|
||||
{ |
|
||||
authorization.Application = null; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetPropertiesAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null || properties.IsEmpty) |
|
||||
{ |
|
||||
authorization.Properties = null; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
authorization.Properties = JsonSerializer.Serialize(properties, new JsonSerializerOptions |
|
||||
{ |
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, |
|
||||
WriteIndented = false |
|
||||
}); |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the scopes associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="scopes">The scopes associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetScopesAsync([NotNull] TAuthorization authorization, |
|
||||
ImmutableArray<string> scopes, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (scopes.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
authorization.Scopes = null; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
authorization.Scopes = JsonSerializer.Serialize(scopes, new JsonSerializerOptions |
|
||||
{ |
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, |
|
||||
WriteIndented = false |
|
||||
}); |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the status associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="status">The status associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetStatusAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string status, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Status = status; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the subject associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetSubjectAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Subject = subject; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the type associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="type">The type associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetTypeAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Type = type; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
await session.UpdateAsync(authorization, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
catch (StaleObjectStateException exception) |
|
||||
{ |
|
||||
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() |
|
||||
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.") |
|
||||
.Append("Reload the authorization from the database and retry the operation.") |
|
||||
.ToString(), exception); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,720 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Text; |
|
||||
using System.Text.Encodings.Web; |
|
||||
using System.Text.Json; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using NHibernate; |
|
||||
using NHibernate.Cfg; |
|
||||
using NHibernate.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the scopes stored in a database.
|
|
||||
/// </summary>
|
|
||||
public class OpenIddictScopeStore : OpenIddictScopeStore<OpenIddictScope, string> |
|
||||
{ |
|
||||
public OpenIddictScopeStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
: base(cache, context, options) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the scopes stored in a database.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public class OpenIddictScopeStore<TKey> : OpenIddictScopeStore<OpenIddictScope<TKey>, TKey> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictScopeStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
: base(cache, context, options) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the scopes stored in a database.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public class OpenIddictScopeStore<TScope, TKey> : IOpenIddictScopeStore<TScope> |
|
||||
where TScope : OpenIddictScope<TKey> |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
public OpenIddictScopeStore( |
|
||||
[NotNull] IMemoryCache cache, |
|
||||
[NotNull] IOpenIddictNHibernateContext context, |
|
||||
[NotNull] IOptionsMonitor<OpenIddictNHibernateOptions> options) |
|
||||
{ |
|
||||
Cache = cache; |
|
||||
Context = context; |
|
||||
Options = options; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cache associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the database context associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IOpenIddictNHibernateContext Context { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the options associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IOptionsMonitor<OpenIddictNHibernateOptions> Options { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of scopes that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of scopes in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await session.Query<TScope>().LongCountAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of scopes that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of scopes that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await query(session.Query<TScope>()).LongCountAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
await session.SaveAsync(scope, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes an existing scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
await session.DeleteAsync(scope, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
catch (StaleObjectStateException exception) |
|
||||
{ |
|
||||
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() |
|
||||
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.") |
|
||||
.Append("Reload the scope from the database and retry the operation.") |
|
||||
.ToString(), exception); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a scope using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scope corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await session.GetAsync<TScope>(ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a scope using its name.
|
|
||||
/// </summary>
|
|
||||
/// <param name="name">The name associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scope corresponding to the specified name.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(name)) |
|
||||
{ |
|
||||
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
return await (from scope in session.Query<TScope>() |
|
||||
where scope.Name == name |
|
||||
select scope).FirstOrDefaultAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a list of scopes using their name.
|
|
||||
/// </summary>
|
|
||||
/// <param name="names">The names associated with the scopes.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The scopes corresponding to the specified names.</returns>
|
|
||||
public virtual IAsyncEnumerable<TScope> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (names.Any(name => string.IsNullOrEmpty(name))) |
|
||||
{ |
|
||||
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
// Note: Enumerable.Contains() is deliberately used without the extension method syntax to ensure
|
|
||||
// ImmutableArray.Contains() (which is not fully supported by NHibernate) is not used instead.
|
|
||||
await foreach (var scope in (from scope in session.Query<TScope>() |
|
||||
where Enumerable.Contains(names, scope.Name) |
|
||||
select scope).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return scope; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the scopes that contain the specified resource.
|
|
||||
/// </summary>
|
|
||||
/// <param name="resource">The resource associated with the scopes.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>The scopes associated with the specified resource.</returns>
|
|
||||
public virtual IAsyncEnumerable<TScope> FindByResourceAsync([NotNull] string resource, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(resource)) |
|
||||
{ |
|
||||
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TScope> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
// To optimize the efficiency of the query a bit, only scopes whose stringified
|
|
||||
// Resources column contains the specified resource are returned. Once the scopes
|
|
||||
// are retrieved, a second pass is made to ensure only valid elements are returned.
|
|
||||
// Implementers that use this method in a hot path may want to override this method
|
|
||||
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
|
|
||||
await foreach (var scope in session.Query<TScope>() |
|
||||
.Where(scope => scope.Resources.Contains(resource)) |
|
||||
.AsAsyncEnumerable(cancellationToken) |
|
||||
.WhereAwait(async scope => (await GetResourcesAsync(scope, cancellationToken)).Contains(resource, StringComparer.Ordinal))) |
|
||||
{ |
|
||||
yield return scope; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public virtual async ValueTask<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
return await query(session.Query<TScope>(), state).FirstOrDefaultAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the description associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the description associated with the specified scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetDescriptionAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.Description); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the display name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the display name associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetDisplayNameAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.DisplayName); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(scope.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the name associated with the specified scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetNameAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.Name); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableDictionary<string, JsonElement>> GetPropertiesAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(scope.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableDictionary<string, JsonElement>>(ImmutableDictionary.Create<string, JsonElement>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified properties is an expensive operation.
|
|
||||
// To mitigate that, the resulting object is stored in the memory cache.
|
|
||||
var key = string.Concat("78d8dfdd-3870-442e-b62e-dc9bf6eaeff7", "\x1e", scope.Properties); |
|
||||
var properties = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JsonSerializer.Deserialize<ImmutableDictionary<string, JsonElement>>(scope.Properties); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableDictionary<string, JsonElement>>(properties); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the resources associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the resources associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetResourcesAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(scope.Resources)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified resources is an expensive operation.
|
|
||||
// To mitigate that, the resulting array is stored in the memory cache.
|
|
||||
var key = string.Concat("b6148250-aede-4fb9-a621-07c9bcf238c3", "\x1e", scope.Resources); |
|
||||
var resources = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JsonSerializer.Deserialize<ImmutableArray<string>>(scope.Resources); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(resources); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated scope, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TScope> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
return new ValueTask<TScope>(Activator.CreateInstance<TScope>()); |
|
||||
} |
|
||||
|
|
||||
catch (MemberAccessException exception) |
|
||||
{ |
|
||||
return new ValueTask<TScope>(Task.FromException<TScope>( |
|
||||
new InvalidOperationException(new StringBuilder() |
|
||||
.AppendLine("An error occurred while trying to create a new scope instance.") |
|
||||
.Append("Make sure that the scope entity is not abstract and has a public parameterless constructor ") |
|
||||
.Append("or create a custom scope store that overrides 'InstantiateAsync()' to use a custom factory.") |
|
||||
.ToString(), exception))); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>All the elements returned when executing the specified query.</returns>
|
|
||||
public virtual async IAsyncEnumerable<TScope> ListAsync( |
|
||||
[CanBeNull] int? count, [CanBeNull] int? offset, [EnumeratorCancellation] CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
var query = session.Query<TScope>() |
|
||||
.OrderBy(scope => scope.Id) |
|
||||
.AsQueryable(); |
|
||||
|
|
||||
if (offset.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(offset.Value); |
|
||||
} |
|
||||
|
|
||||
if (count.HasValue) |
|
||||
{ |
|
||||
query = query.Take(count.Value); |
|
||||
} |
|
||||
|
|
||||
await foreach (var scope in query.AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return scope; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>All the elements returned when executing the specified query.</returns>
|
|
||||
public virtual IAsyncEnumerable<TResult> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (query == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(query)); |
|
||||
} |
|
||||
|
|
||||
return ExecuteAsync(cancellationToken); |
|
||||
|
|
||||
async IAsyncEnumerable<TResult> ExecuteAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
await foreach (var element in query(session.Query<TScope>(), state).AsAsyncEnumerable(cancellationToken)) |
|
||||
{ |
|
||||
yield return element; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the description associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="description">The description associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.Description = description; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the display name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="name">The display name associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.DisplayName = name; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="name">The name associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.Name = name; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetPropertiesAsync([NotNull] TScope scope, |
|
||||
[CanBeNull] ImmutableDictionary<string, JsonElement> properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null || properties.IsEmpty) |
|
||||
{ |
|
||||
scope.Properties = null; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
scope.Properties = JsonSerializer.Serialize(properties, new JsonSerializerOptions |
|
||||
{ |
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, |
|
||||
WriteIndented = false |
|
||||
}); |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the resources associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="resources">The resources associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual ValueTask SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (resources.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
scope.Resources = null; |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
scope.Resources = JsonSerializer.Serialize(resources, new JsonSerializerOptions |
|
||||
{ |
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, |
|
||||
WriteIndented = false |
|
||||
}); |
|
||||
|
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public virtual async ValueTask UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
var session = await Context.GetSessionAsync(cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
await session.UpdateAsync(scope, cancellationToken); |
|
||||
await session.FlushAsync(cancellationToken); |
|
||||
} |
|
||||
|
|
||||
catch (StaleObjectStateException exception) |
|
||||
{ |
|
||||
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() |
|
||||
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.") |
|
||||
.Append("Reload the scope from the database and retry the operation.") |
|
||||
.ToString(), exception); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
File diff suppressed because it is too large
@ -1,16 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFrameworks>net461;netcoreapp2.1;netcoreapp3.0</TargetFrameworks> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\..\src\OpenIddict.NHibernate\OpenIddict.NHibernate.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(ExtensionsVersion)" /> |
|
||||
<PackageReference Include="Moq" Version="$(MoqVersion)" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,122 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using NHibernate; |
|
||||
using OpenIddict.Core; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictNHibernateBuilderTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Constructor_ThrowsAnExceptionForNullServices() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = (IServiceCollection) null; |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => new OpenIddictNHibernateBuilder(services)); |
|
||||
|
|
||||
Assert.Equal("services", exception.ParamName); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void ReplaceDefaultEntities_EntitiesAreCorrectlyReplaced() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = CreateServices(); |
|
||||
var builder = CreateBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.ReplaceDefaultEntities<CustomApplication, CustomAuthorization, CustomScope, CustomToken, long>(); |
|
||||
|
|
||||
// Assert
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue; |
|
||||
|
|
||||
Assert.Equal(typeof(CustomApplication), options.DefaultApplicationType); |
|
||||
Assert.Equal(typeof(CustomAuthorization), options.DefaultAuthorizationType); |
|
||||
Assert.Equal(typeof(CustomScope), options.DefaultScopeType); |
|
||||
Assert.Equal(typeof(CustomToken), options.DefaultTokenType); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void ReplaceDefaultEntities_AllowsSpecifyingCustomKeyType() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = CreateServices(); |
|
||||
var builder = CreateBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.ReplaceDefaultEntities<long>(); |
|
||||
|
|
||||
// Assert
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue; |
|
||||
|
|
||||
Assert.Equal(typeof(OpenIddictApplication<long>), options.DefaultApplicationType); |
|
||||
Assert.Equal(typeof(OpenIddictAuthorization<long>), options.DefaultAuthorizationType); |
|
||||
Assert.Equal(typeof(OpenIddictScope<long>), options.DefaultScopeType); |
|
||||
Assert.Equal(typeof(OpenIddictToken<long>), options.DefaultTokenType); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void UseSessionFactory_ThrowsAnExceptionForNullFactory() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = CreateServices(); |
|
||||
var builder = CreateBuilder(services); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<ArgumentNullException>(delegate |
|
||||
{ |
|
||||
return builder.UseSessionFactory(factory: null); |
|
||||
}); |
|
||||
|
|
||||
Assert.Equal("factory", exception.ParamName); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void UseSessionFactory_SetsDbContextTypeInOptions() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = CreateServices(); |
|
||||
var builder = CreateBuilder(services); |
|
||||
var factory = Mock.Of<ISessionFactory>(); |
|
||||
|
|
||||
// Act
|
|
||||
builder.UseSessionFactory(factory); |
|
||||
|
|
||||
// Assert
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictNHibernateOptions>>().CurrentValue; |
|
||||
|
|
||||
Assert.Same(factory, options.SessionFactory); |
|
||||
} |
|
||||
|
|
||||
private static OpenIddictNHibernateBuilder CreateBuilder(IServiceCollection services) |
|
||||
=> services.AddOpenIddict().AddCore().UseNHibernate(); |
|
||||
|
|
||||
private static IServiceCollection CreateServices() |
|
||||
{ |
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddOptions(); |
|
||||
|
|
||||
return services; |
|
||||
} |
|
||||
|
|
||||
public class CustomApplication : OpenIddictApplication<long, CustomAuthorization, CustomToken> { } |
|
||||
public class CustomAuthorization : OpenIddictAuthorization<long, CustomApplication, CustomToken> { } |
|
||||
public class CustomScope : OpenIddictScope<long> { } |
|
||||
public class CustomToken : OpenIddictToken<long, CustomApplication, CustomAuthorization> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,240 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using NHibernate; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictNHibernateContextTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_ThrowsAnExceptionForCanceledToken() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>(); |
|
||||
var token = new CancellationToken(canceled: true); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = await Assert.ThrowsAsync<TaskCanceledException>(async delegate |
|
||||
{ |
|
||||
await context.GetSessionAsync(token); |
|
||||
}); |
|
||||
|
|
||||
Assert.Equal(token, exception.CancellationToken); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_UsesSessionRegisteredInDependencyInjectionContainer() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var session = new Mock<ISession>(); |
|
||||
var factory = new Mock<ISessionFactory>(); |
|
||||
|
|
||||
services.AddSingleton(session.Object); |
|
||||
services.AddSingleton(factory.Object); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = null |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.Same(session.Object, await context.GetSessionAsync(CancellationToken.None)); |
|
||||
factory.Verify(mock => mock.OpenSession(), Times.Never()); |
|
||||
} |
|
||||
|
|
||||
[Theory] |
|
||||
[InlineData(FlushMode.Always)] |
|
||||
[InlineData(FlushMode.Auto)] |
|
||||
[InlineData(FlushMode.Commit)] |
|
||||
[InlineData(FlushMode.Unspecified)] |
|
||||
public async Task GetSessionAsync_CreatesSubSessionWhenFlushModeIsNotManual(FlushMode mode) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var session = new Mock<ISession>(); |
|
||||
session.SetupProperty(mock => mock.FlushMode, mode); |
|
||||
|
|
||||
var builder = new Mock<ISharedSessionBuilder>(); |
|
||||
builder.Setup(mock => mock.AutoClose()) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.AutoJoinTransaction()) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.Connection()) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.ConnectionReleaseMode()) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.FlushMode(FlushMode.Manual)) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.Interceptor()) |
|
||||
.Returns(builder.Object); |
|
||||
builder.Setup(mock => mock.OpenSession()) |
|
||||
.Returns(session.Object); |
|
||||
|
|
||||
session.Setup(mock => mock.SessionWithOptions()) |
|
||||
.Returns(builder.Object); |
|
||||
|
|
||||
var factory = new Mock<ISessionFactory>(); |
|
||||
|
|
||||
services.AddSingleton(session.Object); |
|
||||
services.AddSingleton(factory.Object); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = null |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.Same(session.Object, await context.GetSessionAsync(CancellationToken.None)); |
|
||||
builder.Verify(mock => mock.AutoClose(), Times.Once()); |
|
||||
builder.Verify(mock => mock.AutoJoinTransaction(), Times.Once()); |
|
||||
builder.Verify(mock => mock.Connection(), Times.Once()); |
|
||||
builder.Verify(mock => mock.ConnectionReleaseMode(), Times.Once()); |
|
||||
builder.Verify(mock => mock.FlushMode(FlushMode.Manual), Times.Once()); |
|
||||
builder.Verify(mock => mock.Interceptor(), Times.Once()); |
|
||||
builder.Verify(mock => mock.OpenSession(), Times.Once()); |
|
||||
factory.Verify(mock => mock.OpenSession(), Times.Never()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_UsesSessionFactoryRegisteredInDependencyInjectionContainer() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<ISessionFactory>()); |
|
||||
|
|
||||
var session = new Mock<ISession>(); |
|
||||
var factory = new Mock<ISessionFactory>(); |
|
||||
factory.Setup(mock => mock.OpenSession()) |
|
||||
.Returns(session.Object); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = factory.Object |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.Same(session.Object, await context.GetSessionAsync(CancellationToken.None)); |
|
||||
factory.Verify(mock => mock.OpenSession(), Times.Once()); |
|
||||
session.VerifySet(mock => mock.FlushMode = FlushMode.Manual, Times.Once()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_ThrowsAnExceptionWhenSessionFactoryCannotBeFound() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = null |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async delegate |
|
||||
{ |
|
||||
await context.GetSessionAsync(CancellationToken.None); |
|
||||
}); |
|
||||
|
|
||||
Assert.Equal(new StringBuilder() |
|
||||
.AppendLine("No suitable NHibernate session or session factory can be found.") |
|
||||
.Append("To configure the OpenIddict NHibernate stores to use a specific factory, use ") |
|
||||
.Append("'services.AddOpenIddict().AddCore().UseNHibernate().UseSessionFactory()' or register an ") |
|
||||
.Append("'ISession'/'ISessionFactory' in the dependency injection container in 'ConfigureServices()'.") |
|
||||
.ToString(), exception.Message); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_PrefersSessionFactoryRegisteredInOptionsToSessionRegisteredInDependencyInjectionContainer() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<ISessionFactory>()); |
|
||||
|
|
||||
var session = new Mock<ISession>(); |
|
||||
var factory = new Mock<ISessionFactory>(); |
|
||||
factory.Setup(mock => mock.OpenSession()) |
|
||||
.Returns(session.Object); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = factory.Object |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.Same(session.Object, await context.GetSessionAsync(CancellationToken.None)); |
|
||||
factory.Verify(mock => mock.OpenSession(), Times.Once()); |
|
||||
session.VerifySet(mock => mock.FlushMode = FlushMode.Manual, Times.Once()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task GetSessionAsync_ReturnsCachedSession() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
|
|
||||
var factory = new Mock<ISessionFactory>(); |
|
||||
factory.Setup(mock => mock.OpenSession()) |
|
||||
.Returns(() => Mock.Of<ISession>()); |
|
||||
|
|
||||
var options = Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>( |
|
||||
mock => mock.CurrentValue == new OpenIddictNHibernateOptions |
|
||||
{ |
|
||||
SessionFactory = factory.Object |
|
||||
}); |
|
||||
|
|
||||
var context = new OpenIddictNHibernateContext(options, provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.Same( |
|
||||
await context.GetSessionAsync(CancellationToken.None), |
|
||||
await context.GetSessionAsync(CancellationToken.None)); |
|
||||
|
|
||||
factory.Verify(mock => mock.OpenSession(), Times.Once()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,120 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Core; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictNHibernateExtensionsTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void UseNHibernate_ThrowsAnExceptionForNullBuilder() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var builder = (OpenIddictCoreBuilder) null; |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => builder.UseNHibernate()); |
|
||||
|
|
||||
Assert.Equal("builder", exception.ParamName); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void UseNHibernate_ThrowsAnExceptionForNullConfiguration() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = new OpenIddictCoreBuilder(services); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => builder.UseNHibernate(configuration: null)); |
|
||||
|
|
||||
Assert.Equal("configuration", exception.ParamName); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void UseNHibernate_RegistersDefaultEntities() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection().AddOptions(); |
|
||||
var builder = new OpenIddictCoreBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.UseNHibernate(); |
|
||||
|
|
||||
// Assert
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue; |
|
||||
|
|
||||
Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType); |
|
||||
Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType); |
|
||||
Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); |
|
||||
Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); |
|
||||
} |
|
||||
|
|
||||
[Theory] |
|
||||
[InlineData(typeof(IOpenIddictApplicationStoreResolver), typeof(OpenIddictApplicationStoreResolver))] |
|
||||
[InlineData(typeof(IOpenIddictAuthorizationStoreResolver), typeof(OpenIddictAuthorizationStoreResolver))] |
|
||||
[InlineData(typeof(IOpenIddictScopeStoreResolver), typeof(OpenIddictScopeStoreResolver))] |
|
||||
[InlineData(typeof(IOpenIddictTokenStoreResolver), typeof(OpenIddictTokenStoreResolver))] |
|
||||
public void UseNHibernate_RegistersNHibernateStoreResolvers(Type serviceType, Type implementationType) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = new OpenIddictCoreBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.UseNHibernate(); |
|
||||
|
|
||||
// Assert
|
|
||||
Assert.Contains(services, service => service.ServiceType == serviceType && |
|
||||
service.ImplementationType == implementationType); |
|
||||
} |
|
||||
|
|
||||
[Theory] |
|
||||
[InlineData(typeof(OpenIddictApplicationStoreResolver.TypeResolutionCache))] |
|
||||
[InlineData(typeof(OpenIddictAuthorizationStoreResolver.TypeResolutionCache))] |
|
||||
[InlineData(typeof(OpenIddictScopeStoreResolver.TypeResolutionCache))] |
|
||||
[InlineData(typeof(OpenIddictTokenStoreResolver.TypeResolutionCache))] |
|
||||
public void UseEntityFramework_RegistersNHibernateStoreResolverCaches(Type type) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = new OpenIddictCoreBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.UseNHibernate(); |
|
||||
|
|
||||
// Assert
|
|
||||
Assert.Contains(services, service => service.ServiceType == type && |
|
||||
service.ImplementationType == type); |
|
||||
} |
|
||||
|
|
||||
[Theory] |
|
||||
[InlineData(typeof(OpenIddictApplicationStore<,,,>))] |
|
||||
[InlineData(typeof(OpenIddictAuthorizationStore<,,,>))] |
|
||||
[InlineData(typeof(OpenIddictScopeStore<,>))] |
|
||||
[InlineData(typeof(OpenIddictTokenStore<,,,>))] |
|
||||
public void UseNHibernate_RegistersNHibernateStore(Type type) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = new OpenIddictCoreBuilder(services); |
|
||||
|
|
||||
// Act
|
|
||||
builder.UseNHibernate(); |
|
||||
|
|
||||
// Assert
|
|
||||
Assert.Contains(services, service => service.ServiceType == type && service.ImplementationType == type); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,84 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
using static OpenIddict.NHibernate.OpenIddictApplicationStoreResolver; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictApplicationStoreResolverTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictApplicationStore<CustomApplication>>()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictApplicationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<CustomApplication>()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ThrowsAnExceptionForInvalidEntityType() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictApplicationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => resolver.Get<CustomApplication>()); |
|
||||
|
|
||||
Assert.Equal(new StringBuilder() |
|
||||
.AppendLine("The specified application type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictApplication' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictApplication' entity.") |
|
||||
.ToString(), exception.Message); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictApplicationStore<CustomApplication>>()); |
|
||||
services.AddSingleton(CreateStore()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictApplicationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<MyApplication>()); |
|
||||
} |
|
||||
|
|
||||
private static OpenIddictApplicationStore<MyApplication, MyAuthorization, MyToken, long> CreateStore() |
|
||||
=> new Mock<OpenIddictApplicationStore<MyApplication, MyAuthorization, MyToken, long>>( |
|
||||
Mock.Of<IMemoryCache>(), |
|
||||
Mock.Of<IOpenIddictNHibernateContext>(), |
|
||||
Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>()).Object; |
|
||||
|
|
||||
public class CustomApplication { } |
|
||||
|
|
||||
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken> { } |
|
||||
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { } |
|
||||
public class MyScope : OpenIddictScope<long> { } |
|
||||
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,84 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
using static OpenIddict.NHibernate.OpenIddictAuthorizationStoreResolver; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictAuthorizationStoreResolverTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictAuthorizationStore<CustomAuthorization>>()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictAuthorizationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<CustomAuthorization>()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ThrowsAnExceptionForInvalidEntityType() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictAuthorizationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => resolver.Get<CustomAuthorization>()); |
|
||||
|
|
||||
Assert.Equal(new StringBuilder() |
|
||||
.AppendLine("The specified authorization type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictAuthorization' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictAuthorization' entity.") |
|
||||
.ToString(), exception.Message); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictAuthorizationStore<CustomAuthorization>>()); |
|
||||
services.AddSingleton(CreateStore()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictAuthorizationStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<MyAuthorization>()); |
|
||||
} |
|
||||
|
|
||||
private static OpenIddictAuthorizationStore<MyAuthorization, MyApplication, MyToken, long> CreateStore() |
|
||||
=> new Mock<OpenIddictAuthorizationStore<MyAuthorization, MyApplication, MyToken, long>>( |
|
||||
Mock.Of<IMemoryCache>(), |
|
||||
Mock.Of<IOpenIddictNHibernateContext>(), |
|
||||
Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>()).Object; |
|
||||
|
|
||||
public class CustomAuthorization { } |
|
||||
|
|
||||
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken> { } |
|
||||
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { } |
|
||||
public class MyScope : OpenIddictScope<long> { } |
|
||||
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,84 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
using static OpenIddict.NHibernate.OpenIddictScopeStoreResolver; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictScopeStoreResolverTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictScopeStore<CustomScope>>()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictScopeStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<CustomScope>()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ThrowsAnExceptionForInvalidEntityType() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictScopeStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => resolver.Get<CustomScope>()); |
|
||||
|
|
||||
Assert.Equal(new StringBuilder() |
|
||||
.AppendLine("The specified scope type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictScope' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictScope' entity.") |
|
||||
.ToString(), exception.Message); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictScopeStore<CustomScope>>()); |
|
||||
services.AddSingleton(CreateStore()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictScopeStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<MyScope>()); |
|
||||
} |
|
||||
|
|
||||
private static OpenIddictScopeStore<MyScope, long> CreateStore() |
|
||||
=> new Mock<OpenIddictScopeStore<MyScope, long>>( |
|
||||
Mock.Of<IMemoryCache>(), |
|
||||
Mock.Of<IOpenIddictNHibernateContext>(), |
|
||||
Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>()).Object; |
|
||||
|
|
||||
public class CustomScope { } |
|
||||
|
|
||||
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken> { } |
|
||||
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { } |
|
||||
public class MyScope : OpenIddictScope<long> { } |
|
||||
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { } |
|
||||
} |
|
||||
} |
|
||||
@ -1,84 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Text; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Moq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.NHibernate.Models; |
|
||||
using Xunit; |
|
||||
using static OpenIddict.NHibernate.OpenIddictTokenStoreResolver; |
|
||||
|
|
||||
namespace OpenIddict.NHibernate.Tests |
|
||||
{ |
|
||||
public class OpenIddictTokenStoreResolverTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Get_ReturnsCustomStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictTokenStore<CustomToken>>()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictTokenStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<CustomToken>()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ThrowsAnExceptionForInvalidEntityType() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictTokenStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => resolver.Get<CustomToken>()); |
|
||||
|
|
||||
Assert.Equal(new StringBuilder() |
|
||||
.AppendLine("The specified token type is not compatible with the NHibernate stores.") |
|
||||
.Append("When enabling the NHibernate stores, make sure you use the built-in ") |
|
||||
.Append("'OpenIddictToken' entity (from the 'OpenIddict.NHibernate.Models' package) ") |
|
||||
.Append("or a custom entity that inherits from the generic 'OpenIddictToken' entity.") |
|
||||
.ToString(), exception.Message); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Get_ReturnsDefaultStoreCorrespondingToTheSpecifiedTypeWhenAvailable() |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
services.AddSingleton(Mock.Of<IOpenIddictTokenStore<CustomToken>>()); |
|
||||
services.AddSingleton(CreateStore()); |
|
||||
|
|
||||
var provider = services.BuildServiceProvider(); |
|
||||
var resolver = new OpenIddictTokenStoreResolver(new TypeResolutionCache(), provider); |
|
||||
|
|
||||
// Act and assert
|
|
||||
Assert.NotNull(resolver.Get<MyToken>()); |
|
||||
} |
|
||||
|
|
||||
private static OpenIddictTokenStore<MyToken, MyApplication, MyAuthorization, long> CreateStore() |
|
||||
=> new Mock<OpenIddictTokenStore<MyToken, MyApplication, MyAuthorization, long>>( |
|
||||
Mock.Of<IMemoryCache>(), |
|
||||
Mock.Of<IOpenIddictNHibernateContext>(), |
|
||||
Mock.Of<IOptionsMonitor<OpenIddictNHibernateOptions>>()).Object; |
|
||||
|
|
||||
public class CustomToken { } |
|
||||
|
|
||||
public class MyApplication : OpenIddictApplication<long, MyAuthorization, MyToken> { } |
|
||||
public class MyAuthorization : OpenIddictAuthorization<long, MyApplication, MyToken> { } |
|
||||
public class MyScope : OpenIddictScope<long> { } |
|
||||
public class MyToken : OpenIddictToken<long, MyApplication, MyAuthorization> { } |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue