mirror of
https://github.com/streetwriters/notesnook-sync-server.git
synced 2026-02-12 11:12:44 +00:00
identity: use Quartz.NET for token cleanup
This commit is contained in:
20
Streetwriters.Identity/Jobs/TokenCleanupJob.cs
Normal file
20
Streetwriters.Identity/Jobs/TokenCleanupJob.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
using Streetwriters.Identity.Services;
|
||||
|
||||
namespace Streetwriters.Identity.Jobs
|
||||
{
|
||||
public class TokenCleanupJob : IJob
|
||||
{
|
||||
private TokenCleanup TokenCleanup { get; set; }
|
||||
public TokenCleanupJob(TokenCleanup tokenCleanup)
|
||||
{
|
||||
TokenCleanup = tokenCleanup;
|
||||
}
|
||||
|
||||
public Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
return TokenCleanup.RemoveExpiredGrantsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
|
||||
|
||||
using IdentityServer4.MongoDB;
|
||||
using IdentityServer4.MongoDB.Configuration;
|
||||
using IdentityServer4.MongoDB.DbContexts;
|
||||
using IdentityServer4.MongoDB.Entities;
|
||||
using IdentityServer4.MongoDB.Interfaces;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Streetwriters.Identity.Services
|
||||
{
|
||||
public class CustomPersistedGrantDbContext : MongoDBContextBase, IPersistedGrantDbContext
|
||||
{
|
||||
private readonly IMongoCollection<PersistedGrant> _persistedGrants;
|
||||
|
||||
public CustomPersistedGrantDbContext(IOptions<MongoDBConfiguration> settings)
|
||||
: base(settings)
|
||||
{
|
||||
_persistedGrants = Database.GetCollection<PersistedGrant>(Constants.TableNames.PersistedGrant);
|
||||
CreateIndexes();
|
||||
}
|
||||
|
||||
private void CreateIndexes()
|
||||
{
|
||||
var indexOptions = new CreateIndexOptions() { Background = true };
|
||||
var builder = Builders<PersistedGrant>.IndexKeys;
|
||||
|
||||
var expirationIndexModel = new CreateIndexModel<PersistedGrant>(builder.Descending(_ => _.Expiration), indexOptions);
|
||||
var keyIndexModel = new CreateIndexModel<PersistedGrant>(builder.Ascending(_ => _.Key), indexOptions);
|
||||
var subIndexModel = new CreateIndexModel<PersistedGrant>(builder.Ascending(_ => _.SubjectId), indexOptions);
|
||||
var clientIdSubIndexModel = new CreateIndexModel<PersistedGrant>(
|
||||
builder.Combine(
|
||||
builder.Ascending(_ => _.ClientId),
|
||||
builder.Ascending(_ => _.SubjectId)),
|
||||
indexOptions);
|
||||
|
||||
var clientIdSubTypeIndexModel = new CreateIndexModel<PersistedGrant>(
|
||||
builder.Combine(
|
||||
builder.Ascending(_ => _.ClientId),
|
||||
builder.Ascending(_ => _.SubjectId),
|
||||
builder.Ascending(_ => _.Type)),
|
||||
indexOptions);
|
||||
|
||||
_persistedGrants.Indexes.CreateOne(expirationIndexModel);
|
||||
_persistedGrants.Indexes.CreateOne(keyIndexModel);
|
||||
_persistedGrants.Indexes.CreateOne(subIndexModel);
|
||||
_persistedGrants.Indexes.CreateOne(clientIdSubIndexModel);
|
||||
_persistedGrants.Indexes.CreateOne(clientIdSubTypeIndexModel);
|
||||
}
|
||||
|
||||
public IQueryable<PersistedGrant> PersistedGrants
|
||||
{
|
||||
get { return _persistedGrants.AsQueryable(); }
|
||||
}
|
||||
|
||||
public Task Remove(Expression<Func<PersistedGrant, bool>> filter)
|
||||
{
|
||||
return _persistedGrants.DeleteManyAsync(filter);
|
||||
}
|
||||
|
||||
public Task RemoveExpired()
|
||||
{
|
||||
return Remove(x => x.Expiration < DateTime.UtcNow.AddHours(12));
|
||||
}
|
||||
|
||||
public Task InsertOrUpdate(Expression<Func<PersistedGrant, bool>> filter, PersistedGrant entity)
|
||||
{
|
||||
return _persistedGrants.ReplaceOneAsync(filter, entity, new ReplaceOptions() { IsUpsert = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
51
Streetwriters.Identity/Services/TokenCleanup.cs
Normal file
51
Streetwriters.Identity/Services/TokenCleanup.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
|
||||
using IdentityServer4.MongoDB.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Streetwriters.Identity.Services
|
||||
{
|
||||
public class TokenCleanup
|
||||
{
|
||||
private readonly IPersistedGrantDbContext _persistedGrantDbContext;
|
||||
private readonly ILogger<TokenCleanup> _logger;
|
||||
|
||||
public TokenCleanup(IPersistedGrantDbContext persistedGrantDbContext, ILogger<TokenCleanup> logger)
|
||||
{
|
||||
_persistedGrantDbContext = persistedGrantDbContext;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to clear expired persisted grants.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task RemoveExpiredGrantsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogTrace("Querying for expired grants to remove");
|
||||
|
||||
await RemoveGrantsAsync();
|
||||
//TODO: await RemoveDeviceCodesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Exception removing expired grants: {exception}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the stale persisted grants.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual async Task RemoveGrantsAsync()
|
||||
{
|
||||
await _persistedGrantDbContext.RemoveExpired();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using System.IO;
|
||||
using AspNetCore.Identity.Mongo;
|
||||
using IdentityServer4.MongoDB.Entities;
|
||||
using IdentityServer4.MongoDB.Interfaces;
|
||||
using IdentityServer4.MongoDB.Options;
|
||||
using IdentityServer4.MongoDB.Stores;
|
||||
using IdentityServer4.ResponseHandling;
|
||||
using IdentityServer4.Services;
|
||||
using IdentityServer4.Stores;
|
||||
using IdentityServer4.Validation;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
@@ -32,12 +37,15 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using Quartz;
|
||||
using Streetwriters.Common;
|
||||
using Streetwriters.Common.Extensions;
|
||||
using Streetwriters.Common.Messages;
|
||||
using Streetwriters.Common.Models;
|
||||
using Streetwriters.Identity.Helpers;
|
||||
using Streetwriters.Identity.Interfaces;
|
||||
using Streetwriters.Identity.Jobs;
|
||||
using Streetwriters.Identity.Models;
|
||||
using Streetwriters.Identity.Services;
|
||||
using Streetwriters.Identity.Validation;
|
||||
@@ -96,7 +104,7 @@ namespace Streetwriters.Identity
|
||||
options.ConnectionString = connectionString;
|
||||
}).AddDefaultTokenProviders();
|
||||
|
||||
var builder = services.AddIdentityServer(
|
||||
services.AddIdentityServer(
|
||||
options =>
|
||||
{
|
||||
options.Events.RaiseSuccessEvents = true;
|
||||
@@ -107,16 +115,6 @@ namespace Streetwriters.Identity
|
||||
.AddExtensionGrantValidator<EmailGrantValidator>()
|
||||
.AddExtensionGrantValidator<MFAGrantValidator>()
|
||||
.AddExtensionGrantValidator<MFAPasswordGrantValidator>()
|
||||
.AddOperationalStore(options =>
|
||||
{
|
||||
options.ConnectionString = connectionString;
|
||||
}, (options) =>
|
||||
{
|
||||
#if !DEBUG
|
||||
options.Enable = true;
|
||||
options.Interval = 3600;
|
||||
#endif
|
||||
})
|
||||
.AddConfigurationStore(options =>
|
||||
{
|
||||
options.ConnectionString = connectionString;
|
||||
@@ -160,6 +158,15 @@ namespace Streetwriters.Identity
|
||||
};
|
||||
});
|
||||
|
||||
services.AddQuartzHostedService(q =>
|
||||
{
|
||||
q.WaitForJobsToComplete = true;
|
||||
q.AwaitApplicationStarted = true;
|
||||
q.StartDelay = TimeSpan.FromMinutes(1);
|
||||
});
|
||||
|
||||
AddOperationalStore(services, new TokenCleanupOptions { Enable = true, Interval = 3600 * 12 });
|
||||
|
||||
services.AddTransient<IMFAService, MFAService>();
|
||||
services.AddControllers();
|
||||
services.AddTransient<IIntrospectionResponseGenerator, CustomIntrospectionResponseGenerator>();
|
||||
@@ -222,5 +229,33 @@ namespace Streetwriters.Identity
|
||||
endpoints.MapHealthChecks("/health");
|
||||
});
|
||||
}
|
||||
|
||||
private void AddOperationalStore(IServiceCollection services, TokenCleanupOptions tokenCleanUpOptions = null)
|
||||
{
|
||||
BsonClassMap.RegisterClassMap<PersistedGrant>(cm =>
|
||||
{
|
||||
cm.AutoMap();
|
||||
cm.SetIgnoreExtraElements(true);
|
||||
});
|
||||
|
||||
services.AddScoped<IPersistedGrantDbContext, CustomPersistedGrantDbContext>();
|
||||
services.AddTransient<IPersistedGrantStore, PersistedGrantStore>();
|
||||
services.AddTransient<TokenCleanup>();
|
||||
|
||||
services.AddQuartz(q =>
|
||||
{
|
||||
q.UseMicrosoftDependencyInjectionJobFactory();
|
||||
|
||||
if (tokenCleanUpOptions.Enable)
|
||||
{
|
||||
var jobKey = new JobKey("TokenCleanupJob");
|
||||
q.AddJob<TokenCleanupJob>(opts => opts.WithIdentity(jobKey));
|
||||
q.AddTrigger(opts => opts
|
||||
.ForJob(jobKey)
|
||||
.WithIdentity("TokenCleanup-trigger")
|
||||
.WithSimpleSchedule((s) => s.RepeatForever().WithIntervalInSeconds(tokenCleanUpOptions.Interval)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
<PackageReference Include="MailKit" Version="3.4.3" />
|
||||
<PackageReference Include="MessageBird" Version="3.2.0" />
|
||||
<PackageReference Include="Ng.UserAgentService" Version="1.1.2" />
|
||||
<PackageReference Include="Quartz" Version="3.5.0" />
|
||||
<PackageReference Include="Quartz.AspNetCore" Version="3.5.0" />
|
||||
<PackageReference Include="Scriban" Version="5.5.1" />
|
||||
<PackageReference Include="SendGrid" Version="9.24.4" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||
|
||||
Reference in New Issue
Block a user