Skip to content

Commit 1762500

Browse files
author
github-actions
committed
feat: ravendb store
1 parent 6962a16 commit 1762500

12 files changed

+456
-5
lines changed

DymamicAuthProviders.sln

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.AspNetCore.Authe
4646
EndProject
4747
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.AspNetCore.Authentication.RavenDb", "src\Aguacongas.AspNetCore.Authentication.RavenDb\Aguacongas.AspNetCore.Authentication.RavenDb.csproj", "{227C6C5A-5297-4C02-938A-61BA88C42DEE}"
4848
EndProject
49+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aguacongas.AspNetCore.Authentication.RavenDb.Test", "test\Aguacongas.AspNetCore.Authentication.RavenDb.Test\Aguacongas.AspNetCore.Authentication.RavenDb.Test.csproj", "{50BA6357-C8CF-4E23-A27C-26406300D165}"
50+
EndProject
4951
Global
5052
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5153
Debug|Any CPU = Debug|Any CPU
@@ -88,6 +90,10 @@ Global
8890
{227C6C5A-5297-4C02-938A-61BA88C42DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
8991
{227C6C5A-5297-4C02-938A-61BA88C42DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
9092
{227C6C5A-5297-4C02-938A-61BA88C42DEE}.Release|Any CPU.Build.0 = Release|Any CPU
93+
{50BA6357-C8CF-4E23-A27C-26406300D165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
94+
{50BA6357-C8CF-4E23-A27C-26406300D165}.Debug|Any CPU.Build.0 = Debug|Any CPU
95+
{50BA6357-C8CF-4E23-A27C-26406300D165}.Release|Any CPU.ActiveCfg = Release|Any CPU
96+
{50BA6357-C8CF-4E23-A27C-26406300D165}.Release|Any CPU.Build.0 = Release|Any CPU
9197
EndGlobalSection
9298
GlobalSection(SolutionProperties) = preSolution
9399
HideSolutionNode = FALSE
@@ -102,6 +108,7 @@ Global
102108
{CE9FE264-6139-47BF-970C-D1BBFCD7EFEA} = {245AA4AB-ECF4-4C69-B63D-C59D4B3F918C}
103109
{87CFA3EF-2A15-4861-A6DC-C74E9CA3EBCE} = {8DE53FA4-6C58-4FE4-840C-8CD5D5370324}
104110
{227C6C5A-5297-4C02-938A-61BA88C42DEE} = {245AA4AB-ECF4-4C69-B63D-C59D4B3F918C}
111+
{50BA6357-C8CF-4E23-A27C-26406300D165} = {8DE53FA4-6C58-4FE4-840C-8CD5D5370324}
105112
EndGlobalSection
106113
GlobalSection(ExtensibilityGlobals) = postSolution
107114
SolutionGuid = {823D9407-93C0-443E-89EC-D9DBB006A195}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.1</TargetFramework>
5+
<Authors>Olivier Lefebvre</Authors>
6+
<Copyright>Copyright (c) 2018 @Olivier Lefebvre</Copyright>
7+
<PackageLicense>https://raw.githubusercontent.com/aguacongas/DymamicAuthProviders/master/LICENSE</PackageLicense>
8+
<PackageProjectUrl>https://github.com/aguacongas/DymamicAuthProviders/tree/master/src/Aguacongas.AspNetCore.Authentication.RavenDb</PackageProjectUrl>
9+
<RepositoryUrl>https://github.com/aguacongas/DymamicAuthProviders</RepositoryUrl>
10+
<RepositoryType>git</RepositoryType>
11+
<PackageTags>aspnetcore;authentication;security;entityframeworkcore</PackageTags>
12+
<Description>Provider for DinamicAuthProviders that uses Entity Framework Core.</Description>
13+
<DebugType>Full</DebugType>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
17+
<DocumentationFile>C:\Projects\Perso\DymamicAuthProviders\src\Aguacongas.AspNetCore.Authentication.RavenDb\Aguacongas.AspNetCore.Authentication.RavenDb.xml</DocumentationFile>
18+
<CodeAnalysisRuleSet>Aguacongas.AspNetCore.Authentication.RavenDb.ruleset</CodeAnalysisRuleSet>
19+
</PropertyGroup>
20+
21+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
22+
<DocumentationFile>C:\Projects\Perso\DymamicAuthProviders\src\Aguacongas.AspNetCore.Authentication.RavenDb\Aguacongas.AspNetCore.Authentication.RavenDb.xml</DocumentationFile>
23+
<CodeAnalysisRuleSet>Aguacongas.AspNetCore.Authentication.RavenDb.ruleset</CodeAnalysisRuleSet>
24+
</PropertyGroup>
25+
26+
<ItemGroup>
27+
<None Remove="Aguacongas.AspNetCore.Authentication.RavenDb.xml" />
28+
</ItemGroup>
29+
30+
<ItemGroup>
31+
<PackageReference Include="RavenDB.Client" Version="5.1.4" />
32+
</ItemGroup>
33+
34+
<ItemGroup>
35+
<ProjectReference Include="..\Aguacongas.AspNetCore.Authentication\Aguacongas.AspNetCore.Authentication.csproj" />
36+
</ItemGroup>
37+
38+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RuleSet Name="SonarQube - DymamicAuthProviders Sonar way" ToolsVersion="16.0">
3+
<Include Path="..\..\.sonarlint\aguacongas_dymamicauthproviderscsharp.ruleset" Action="Default" />
4+
</RuleSet>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Project: aguacongas/DymamicAuthProviders
2+
// Copyright (c) 2021 @Olivier Lefebvre
3+
using Aguacongas.AspNetCore.Authentication.RavenDb;
4+
5+
namespace Microsoft.AspNetCore.Builder
6+
{
7+
/// <summary>
8+
/// IApplicationBuilder extensions
9+
/// </summary>
10+
public static class ApplicationBuilderExtensions
11+
{
12+
/// <summary>
13+
/// Loads the dynamic authentication configuration.
14+
/// </summary>
15+
/// <param name="builder">The builder.</param>
16+
/// <returns></returns>
17+
public static IApplicationBuilder LoadDynamicAuthenticationConfiguration(this IApplicationBuilder builder)
18+
{
19+
builder.ApplicationServices.LoadDynamicAuthenticationConfiguration<SchemeDefinition>();
20+
return builder;
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Project: aguacongas/DymamicAuthProviders
2+
// Copyright (c) 2021 @Olivier Lefebvre
3+
using Aguacongas.AspNetCore.Authentication;
4+
using Aguacongas.AspNetCore.Authentication.RavenDb;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
6+
using Microsoft.Extensions.Logging;
7+
using Raven.Client.Documents;
8+
using Raven.Client.Documents.Session;
9+
using System;
10+
11+
namespace Microsoft.Extensions.DependencyInjection
12+
{
13+
/// <summary>
14+
/// <see cref="DynamicAuthenticationBuilder"/> extensions.
15+
/// </summary>
16+
public static class DynamicAuthenticationBuilderExtensions
17+
{
18+
/// <summary>
19+
/// Adds the entity framework store.
20+
/// </summary>
21+
/// <param name="builder">The builder.</param>
22+
/// <param name="dataBase">The data base.</param>
23+
/// <returns>
24+
/// The <see cref="DynamicAuthenticationBuilder" />
25+
/// </returns>
26+
public static DynamicAuthenticationBuilder AddRavenDbStorekStore(this DynamicAuthenticationBuilder builder, string dataBase = null)
27+
{
28+
AddStore(builder.Services, builder.DefinitionType, dataBase);
29+
return builder;
30+
}
31+
32+
private static void AddStore(IServiceCollection service, Type definitionType, string dataBase)
33+
{
34+
var storeType = typeof(DynamicProviderStore<>).MakeGenericType(definitionType);
35+
var loggerType = typeof(ILogger<>).MakeGenericType(storeType);
36+
37+
service.TryAddTransient(typeof(IDynamicProviderStore<>).MakeGenericType(definitionType), p =>
38+
{
39+
var session = p.GetRequiredService<IDocumentStore>().OpenAsyncSession(new SessionOptions
40+
{
41+
Database = dataBase
42+
});
43+
session.Advanced.UseOptimisticConcurrency = true;
44+
var constructor = storeType.GetConstructor(new[] { typeof(IAsyncDocumentSession), typeof(IAuthenticationSchemeOptionsSerializer), loggerType });
45+
return constructor.Invoke(new[] { session, p.GetRequiredService<IAuthenticationSchemeOptionsSerializer>(), p.GetRequiredService(loggerType) });
46+
});
47+
service.AddTransient<IAuthenticationSchemeOptionsSerializer, AuthenticationSchemeOptionsSerializer>();
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Project: aguacongas/DymamicAuthProviders
2+
// Copyright (c) 2021 @Olivier Lefebvre
3+
using Microsoft.Extensions.Logging;
4+
using Raven.Client.Documents;
5+
using Raven.Client.Documents.Session;
6+
using System;
7+
using System.Linq;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
namespace Aguacongas.AspNetCore.Authentication.RavenDb
12+
{
13+
/// <summary>
14+
/// Implement a store for <see cref="NoPersistentDynamicManager{TSchemeDefinition}"/> with EntityFramework.
15+
/// </summary>
16+
/// <seealso cref="IDynamicProviderStore{TSchemeDefinition}" />
17+
public class DynamicProviderStore : DynamicProviderStore<SchemeDefinition>
18+
{
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="DynamicProviderStore"/> class.
21+
/// </summary>
22+
/// <param name="session">The document session.</param>
23+
/// <param name="authenticationSchemeOptionsSerializer">The authentication scheme options serializer.</param>
24+
/// <param name="logger">The logger.</param>
25+
public DynamicProviderStore(IAsyncDocumentSession session, IAuthenticationSchemeOptionsSerializer authenticationSchemeOptionsSerializer, ILogger<DynamicProviderStore> logger) : base(session, authenticationSchemeOptionsSerializer, logger)
26+
{
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Implement a store for <see cref="NoPersistentDynamicManager{TSchemeDefinition}"/> with EntityFramework.
32+
/// </summary>
33+
/// <typeparam name="TSchemeDefinition">The type of the definition.</typeparam>
34+
public class DynamicProviderStore<TSchemeDefinition> : IDynamicProviderStore<TSchemeDefinition>
35+
where TSchemeDefinition : SchemeDefinition, new()
36+
{
37+
private readonly IAsyncDocumentSession _session;
38+
private readonly IAuthenticationSchemeOptionsSerializer _authenticationSchemeOptionsSerializer;
39+
private readonly ILogger<DynamicProviderStore<TSchemeDefinition>> _logger;
40+
41+
/// <summary>
42+
/// Gets the scheme definitions list.
43+
/// </summary>
44+
/// <value>
45+
/// The scheme definitions list.
46+
/// </value>
47+
public virtual IQueryable<TSchemeDefinition> SchemeDefinitions => _session.Query<SerializedData>()
48+
.ToListAsync().ConfigureAwait(false).GetAwaiter().GetResult()
49+
.Select(Deserialize)
50+
.AsQueryable();
51+
52+
/// <summary>
53+
/// Initializes a new instance of the <see cref="DynamicProviderStore{TSchemeDefinition}"/> class.
54+
/// </summary>
55+
/// <param name="session">The document session.</param>
56+
/// <param name="authenticationSchemeOptionsSerializer">The authentication scheme options serializer.</param>
57+
/// <param name="logger">The logger.</param>
58+
/// <exception cref="ArgumentNullException">
59+
/// context
60+
/// or
61+
/// authenticationSchemeOptionsSerializer
62+
/// or
63+
/// logger
64+
/// </exception>
65+
public DynamicProviderStore(IAsyncDocumentSession session, IAuthenticationSchemeOptionsSerializer authenticationSchemeOptionsSerializer, ILogger<DynamicProviderStore<TSchemeDefinition>> logger)
66+
{
67+
_session = session ?? throw new ArgumentNullException(nameof(session));
68+
_authenticationSchemeOptionsSerializer = authenticationSchemeOptionsSerializer ?? throw new ArgumentNullException(nameof(authenticationSchemeOptionsSerializer));
69+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
70+
}
71+
72+
/// <summary>
73+
/// Adds a defnition asynchronously.
74+
/// </summary>
75+
/// <param name="definition">The definition.</param>
76+
/// <param name="cancellationToken">The cancellation token.</param>
77+
/// <returns></returns>
78+
/// <exception cref="ArgumentNullException">definition</exception>
79+
public virtual async Task AddAsync(TSchemeDefinition definition, CancellationToken cancellationToken = default)
80+
{
81+
definition = definition ?? throw new ArgumentNullException(nameof(definition));
82+
83+
cancellationToken.ThrowIfCancellationRequested();
84+
85+
var data = Serialize(definition);
86+
await _session.StoreAsync(data, cancellationToken).ConfigureAwait(false);
87+
await _session.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
88+
89+
_logger.LogInformation("Scheme {scheme} added for {handlerType} with options: {options}", definition.Scheme, definition.HandlerType, data.SerializedOptions);
90+
}
91+
92+
/// <summary>
93+
/// Removes a scheme definition asynchronous.
94+
/// </summary>
95+
/// <param name="definition">The definition.</param>
96+
/// <param name="cancellationToken">The cancellation token.</param>
97+
/// <returns></returns>
98+
/// <exception cref="ArgumentNullException">definition</exception>
99+
public virtual async Task RemoveAsync(TSchemeDefinition definition, CancellationToken cancellationToken = default)
100+
{
101+
definition = definition ?? throw new ArgumentNullException(nameof(definition));
102+
103+
cancellationToken.ThrowIfCancellationRequested();
104+
105+
var data = await _session.LoadAsync<SerializedData>(definition.Scheme, cancellationToken).ConfigureAwait(false);
106+
_session.Delete(data);
107+
await _session.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
108+
109+
_logger.LogInformation("Scheme {scheme} removed", definition.Scheme);
110+
}
111+
112+
/// <summary>
113+
/// Updates a scheme definition asynchronous.
114+
/// </summary>
115+
/// <param name="definition">The definition.</param>
116+
/// <param name="cancellationToken">The cancellation token.</param>
117+
/// <returns></returns>
118+
/// <exception cref="ArgumentNullException">definition</exception>
119+
public virtual async Task UpdateAsync(TSchemeDefinition definition, CancellationToken cancellationToken = default)
120+
{
121+
definition = definition ?? throw new ArgumentNullException(nameof(definition));
122+
123+
cancellationToken.ThrowIfCancellationRequested();
124+
125+
var serialized = Serialize(definition);
126+
127+
var data = await _session.LoadAsync<SerializedData>(definition.Scheme, cancellationToken).ConfigureAwait(false);
128+
129+
data.SerializedOptions = serialized.SerializedOptions;
130+
data.SerializedHandlerType = serialized.SerializedHandlerType;
131+
132+
await _session.StoreAsync(data).ConfigureAwait(false);
133+
await _session.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
134+
135+
_logger.LogInformation("Scheme {scheme} updated for {handlerType} with options: {options}", definition.Scheme, definition.HandlerType, data.SerializedOptions);
136+
}
137+
138+
/// <summary>
139+
/// Finds scheme definition by scheme asynchronous.
140+
/// </summary>
141+
/// <param name="scheme">The scheme.</param>
142+
/// <param name="cancellationToken">The cancellation token.</param>
143+
/// <returns>
144+
/// An instance of TSchemeDefinition or null.
145+
/// </returns>
146+
/// <exception cref="ArgumentException">Parameter {nameof(scheme)}</exception>
147+
public virtual async Task<TSchemeDefinition> FindBySchemeAsync(string scheme, CancellationToken cancellationToken = default)
148+
{
149+
CheckScheme(scheme);
150+
151+
cancellationToken.ThrowIfCancellationRequested();
152+
var data = await _session.LoadAsync<SerializedData>(scheme, cancellationToken).ConfigureAwait(false);
153+
154+
if (data != null)
155+
{
156+
return Deserialize(data);
157+
}
158+
159+
return null;
160+
}
161+
162+
private static void CheckScheme(string scheme)
163+
{
164+
if (string.IsNullOrWhiteSpace(scheme))
165+
{
166+
throw new ArgumentException($"Parameter {nameof(scheme)} cannor be null or empty");
167+
}
168+
}
169+
170+
private SerializedData Serialize(TSchemeDefinition definition)
171+
{
172+
return new SerializedData
173+
{
174+
Id = definition.Scheme,
175+
SerializedHandlerType = _authenticationSchemeOptionsSerializer.SerializeType(definition.HandlerType),
176+
SerializedOptions = _authenticationSchemeOptionsSerializer.SerializeOptions(definition.Options, definition.HandlerType.GetAuthenticationSchemeOptionsType())
177+
};
178+
}
179+
180+
private TSchemeDefinition Deserialize(SerializedData data)
181+
{
182+
var handlerType = _authenticationSchemeOptionsSerializer.DeserializeType(data.SerializedHandlerType);
183+
return new TSchemeDefinition
184+
{
185+
Scheme = data.Id,
186+
HandlerType = handlerType,
187+
Options = _authenticationSchemeOptionsSerializer.DeserializeOptions(data.SerializedOptions, handlerType.GetAuthenticationSchemeOptionsType())
188+
};
189+
}
190+
191+
class SerializedData
192+
{
193+
public string Id { get; set; }
194+
195+
public string SerializedOptions { get; set; }
196+
197+
public string SerializedHandlerType { get; set; }
198+
199+
}
200+
}
201+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Aguacongas.AspNetCore.Authentication.RavenDb
2+
3+
## Setup
4+
5+
We need a `IDocumentStore`to be registered in DI.
6+
7+
```cs
8+
// Add authentication
9+
var authBuilder = services
10+
.AddAuthentication();
11+
12+
// Add the magic
13+
var dynamicBuilder = authBuilder
14+
.AddDynamic<SchemeDefinition>()
15+
.AddRavenDbStorekStore();
16+
17+
// Add the ravendb document store
18+
service.AddSingleton(p => new DocumentStore()
19+
{
20+
// Define the cluster node URLs (required)
21+
Urls = new[] { "http://your_RavenDB_cluster_node",
22+
/*some additional nodes of this cluster*/ },
23+
24+
// Define a client certificate (optional)
25+
Certificate = new X509Certificate2("C:\\path_to_your_pfx_file\\cert.pfx"),
26+
Database = "SchemeDefinition"
27+
28+
// Initialize the Document Store
29+
}.Initialize());
30+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Project: aguacongas/DymamicAuthProviders
2+
// Copyright (c) 2021 @Olivier Lefebvre
3+
namespace Aguacongas.AspNetCore.Authentication.RavenDb
4+
{
5+
/// <summary>
6+
/// Scheme definition for entity framework store
7+
/// </summary>
8+
/// <seealso cref="SchemeDefinitionBase" />
9+
public class SchemeDefinition: SchemeDefinitionBase
10+
{
11+
}
12+
}

0 commit comments

Comments
 (0)