Skip to content

Commit

Permalink
Create a unique index on Client.ClientId
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgunn committed Sep 28, 2018
1 parent 3527979 commit 5f42a3a
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 33 deletions.
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ for:
only:
- master

version: 0.1.7
version: 0.2.0

deploy:
- provider: Environment
Expand All @@ -38,4 +38,4 @@ for:
except:
- master

version: 0.1.7.{build}-{branch}
version: 0.2.0.{build}-{branch}
8 changes: 4 additions & 4 deletions src/Gunnsoft.IdentityServer.Stores.MongoDB/BsonClassMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ public static class BsonClassMapper
{
public static void MapClient()
{
if (!BsonClassMap.IsClassMapRegistered(typeof(Client)))
if (!BsonClassMap.IsClassMapRegistered(typeof(ClientDocument)))
{
BsonClassMap.RegisterClassMap<Client>(cm =>
BsonClassMap.RegisterClassMap<ClientDocument>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id);
Expand All @@ -21,9 +21,9 @@ public static void MapClient()

public static void MapPeristedGrant()
{
if (!BsonClassMap.IsClassMapRegistered(typeof(PersistedGrant)))
if (!BsonClassMap.IsClassMapRegistered(typeof(PersistedGrantDocument)))
{
BsonClassMap.RegisterClassMap<PersistedGrant>(cm =>
BsonClassMap.RegisterClassMap<PersistedGrantDocument>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using IdentityServer4;
using IdentityServer4.Models;
using MongoDB.Bson;

namespace Gunnsoft.IdentityServer.Stores.MongoDB.Collections.Clients
{
public class Client
public class ClientDocument
{
public int AbsoluteRefreshTokenLifetime { get; set; } = 2592000;
public int AccessTokenLifetime { get; set; } = 3600;
Expand Down Expand Up @@ -32,7 +33,7 @@ public class Client
public bool EnableLocalLogin { get; set; } = true;
public bool FrontChannelLogoutSessionRequired { get; set; } = true;
public string FrontChannelLogoutUri { get; set; }
public int Id { get; set; }
public ObjectId Id { get; set; }
public List<string> IdentityProviderRestrictions { get; set; }
public int IdentityTokenLifetime { get; set; } = 300;
public bool IncludeJwtId { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Gunnsoft.IdentityServer.Stores.MongoDB.Collections.PersistedGrants
{
public class PersistedGrant
public class PersistedGrantDocument
{
public string ClientId { get; set; }
public string Data { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.Clients;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.PersistedGrants;
using IdentityServer4.Stores;
Expand All @@ -9,44 +11,66 @@ namespace Gunnsoft.IdentityServer.Stores.MongoDB
{
public static class IdentityServerBuilderExtensions
{
public static IIdentityServerBuilder AddMongoClientStore(this IIdentityServerBuilder extended, MongoUrl mongoUrl)
public static async Task<IIdentityServerBuilder> AddMongoClientStoreAsync
(
this IIdentityServerBuilder extended,
MongoUrl mongoUrl,
CancellationToken cancellationToken = default(CancellationToken)
)
{
MongoConfigurator.Configure();
MongoConfigurator.ConfigureConventions();

BsonClassMapper.MapClient();

var client = new MongoClient(mongoUrl);
var mongoClient = new MongoClient(mongoUrl);

if (mongoUrl.DatabaseName == null)
{
throw new ArgumentException("The connection string must contain a database name.", mongoUrl.Url);
}

var database = client.GetDatabase(mongoUrl.DatabaseName);
var mongoDatabase = mongoClient.GetDatabase(mongoUrl.DatabaseName);

var clientsCollection = database.GetCollection<Client>(CollectionNames.Clients);
await MongoConfigurator.ConfigureClientsCollectionAsync
(
mongoDatabase,
cancellationToken
);

var clientsCollection = mongoDatabase.GetCollection<ClientDocument>(CollectionNames.Clients);

extended.Services.AddTransient<IClientStore>(cc => new MongoClientStore(clientsCollection));

return extended;
}

public static IIdentityServerBuilder AddMongoPersistedGrantStore(this IIdentityServerBuilder extended, MongoUrl mongoUrl)
public static async Task<IIdentityServerBuilder> AddMongoPersistedGrantStoreAsync
(
this IIdentityServerBuilder extended,
MongoUrl mongoUrl,
CancellationToken cancellationToken = default(CancellationToken)
)
{
MongoConfigurator.Configure();
MongoConfigurator.ConfigureConventions();

BsonClassMapper.MapPeristedGrant();

var client = new MongoClient(mongoUrl);
var mongoClient = new MongoClient(mongoUrl);

if (mongoUrl.DatabaseName == null)
{
throw new ArgumentException("The connection string must contain a database name.", mongoUrl.Url);
}

var database = client.GetDatabase(mongoUrl.DatabaseName);
var mongoDatabase = mongoClient.GetDatabase(mongoUrl.DatabaseName);

await MongoConfigurator.ConfigurePersistedGrantsCollectionAsync
(
mongoDatabase,
cancellationToken
);

var persistedGrantsCollection = database.GetCollection<PersistedGrant>(CollectionNames.PersistedGrants);
var persistedGrantsCollection = mongoDatabase.GetCollection<PersistedGrantDocument>(CollectionNames.PersistedGrants);

extended.Services.AddTransient<IPersistedGrantStore>(cc => new MongoPersistedGrantStore(persistedGrantsCollection));

Expand Down
13 changes: 10 additions & 3 deletions src/Gunnsoft.IdentityServer.Stores.MongoDB/MongoClientStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.Clients;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using MongoDB.Driver;
Expand All @@ -10,14 +11,20 @@ namespace Gunnsoft.IdentityServer.Stores.MongoDB
{
public class MongoClientStore : IClientStore
{
private readonly IMongoCollection<Collections.Clients.Client> _clientsCollection;
private readonly IMongoCollection<ClientDocument> _clientsCollection;

public MongoClientStore(IMongoCollection<Collections.Clients.Client> clientsCollection)
public MongoClientStore
(
IMongoCollection<ClientDocument> clientsCollection
)
{
_clientsCollection = clientsCollection;
}

public async Task<Client> FindClientByIdAsync(string clientId)
public async Task<Client> FindClientByIdAsync
(
string clientId
)
{
if (clientId == null)
{
Expand Down
72 changes: 70 additions & 2 deletions src/Gunnsoft.IdentityServer.Stores.MongoDB/MongoConfigurator.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
using MongoDB.Bson;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.Clients;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.PersistedGrants;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Driver;
using System.Threading;
using System.Threading.Tasks;

namespace Gunnsoft.IdentityServer.Stores.MongoDB
{
public static class MongoConfigurator
{
public static void Configure()
public static void ConfigureConventions()
{
const string conventionName = "gunnsoft-identityserver-stores-mongodb";
var conventionPack = new ConventionPack
Expand All @@ -17,5 +23,67 @@ public static void Configure()
ConventionRegistry.Remove(conventionName);
ConventionRegistry.Register(conventionName, conventionPack, t => true);
}

public static async Task ConfigureClientsCollectionAsync
(
IMongoDatabase mongoDatabase,
CancellationToken cancellationToken = default(CancellationToken)
)
{
if (!await CollectionExistsAsync(mongoDatabase, CollectionNames.Clients, cancellationToken))
{
await mongoDatabase.CreateCollectionAsync(CollectionNames.Clients);
}

var clientsCollection = mongoDatabase.GetCollection<ClientDocument>(CollectionNames.Clients);
var clientIndexes = new[]
{
new CreateIndexModel<ClientDocument>
(
Builders<ClientDocument>.IndexKeys.Ascending(u => u.ClientId),
new CreateIndexOptions
{
Unique = true
}
)
};

await clientsCollection.Indexes.CreateManyAsync
(
clientIndexes,
cancellationToken: cancellationToken
);
}

public static async Task ConfigurePersistedGrantsCollectionAsync
(
IMongoDatabase mongoDatabase,
CancellationToken cancellationToken = default(CancellationToken)
)
{
if (!await CollectionExistsAsync(mongoDatabase, CollectionNames.PersistedGrants, cancellationToken))
{
await mongoDatabase.CreateCollectionAsync(CollectionNames.PersistedGrants);
}
}

private static async Task<bool> CollectionExistsAsync
(
IMongoDatabase mongoDatabase,
string collectionName,
CancellationToken cancellationToken
)
{
var filter = new BsonDocument("name", collectionName);
var collections = await mongoDatabase.ListCollectionsAsync
(
new ListCollectionsOptions
{
Filter = filter
}
);

return await collections.AnyAsync(cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Gunnsoft.IdentityServer.Stores.MongoDB.Collections.PersistedGrants;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using MongoDB.Driver;
Expand All @@ -9,14 +10,20 @@ namespace Gunnsoft.IdentityServer.Stores.MongoDB
{
public class MongoPersistedGrantStore : IPersistedGrantStore
{
private readonly IMongoCollection<Collections.PersistedGrants.PersistedGrant> _persistedGrantsCollection;
private readonly IMongoCollection<PersistedGrantDocument> _persistedGrantsCollection;

public MongoPersistedGrantStore(IMongoCollection<Collections.PersistedGrants.PersistedGrant> persistedGrantsCollection)
public MongoPersistedGrantStore
(
IMongoCollection<PersistedGrantDocument> persistedGrantsCollection
)
{
_persistedGrantsCollection = persistedGrantsCollection;
}

public async Task<IEnumerable<PersistedGrant>> GetAllAsync(string subjectId)
public async Task<IEnumerable<PersistedGrant>> GetAllAsync
(
string subjectId
)
{
if (subjectId == null)
{
Expand All @@ -37,7 +44,10 @@ public async Task<IEnumerable<PersistedGrant>> GetAllAsync(string subjectId)
.ToListAsync();
}

public async Task<PersistedGrant> GetAsync(string key)
public async Task<PersistedGrant> GetAsync
(
string key
)
{
if (key == null)
{
Expand All @@ -59,7 +69,11 @@ public async Task<PersistedGrant> GetAsync(string key)
.FirstOrDefaultAsync();
}

public async Task RemoveAllAsync(string subjectId, string clientId)
public async Task RemoveAllAsync
(
string subjectId,
string clientId
)
{
if (subjectId == null)
{
Expand All @@ -75,7 +89,12 @@ public async Task RemoveAllAsync(string subjectId, string clientId)
pg.SubjectId == subjectId && pg.ClientId == clientId);
}

public async Task RemoveAllAsync(string subjectId, string clientId, string type)
public async Task RemoveAllAsync
(
string subjectId,
string clientId,
string type
)
{
if (subjectId == null)
{
Expand All @@ -96,7 +115,10 @@ public async Task RemoveAllAsync(string subjectId, string clientId, string type)
pg.SubjectId == subjectId && pg.ClientId == clientId && pg.Type == type);
}

public async Task RemoveAsync(string key)
public async Task RemoveAsync
(
string key
)
{
if (key == null)
{
Expand All @@ -106,14 +128,17 @@ public async Task RemoveAsync(string key)
await _persistedGrantsCollection.DeleteManyAsync(pg => pg.Key == key);
}

public async Task StoreAsync(PersistedGrant grant)
public async Task StoreAsync
(
PersistedGrant grant
)
{
if (grant == null)
{
throw new ArgumentNullException(nameof(grant));
}

var document = new Collections.PersistedGrants.PersistedGrant
var document = new Collections.PersistedGrants.PersistedGrantDocument
{
ClientId = grant.ClientId,
Data = grant.Data,
Expand Down

0 comments on commit 5f42a3a

Please sign in to comment.