Skip to content

Commit 770bf4a

Browse files
committed
Implement IUserClaimStore
1 parent 1f62812 commit 770bf4a

10 files changed

+196
-2
lines changed

src/AspNet.Identity.MongoDB/AspNet.Identity.MongoDB.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<ItemGroup>
5454
<Compile Include="IdentityContext.cs" />
5555
<Compile Include="IdentityUser.cs" />
56+
<Compile Include="IdentityUserClaim.cs" />
5657
<Compile Include="Properties\AssemblyInfo.cs" />
5758
<Compile Include="UserStore.cs" />
5859
</ItemGroup>

src/AspNet.Identity.MongoDB/AspNet.Identity.MongoDB.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<iconUrl>https://github.com/g0t4/aspnet-identity-mongo</iconUrl>
1111
<requireLicenseAcceptance>false</requireLicenseAcceptance>
1212
<description>A mongodb provider for the new ASP.NET Identity framework. My aim is to ensure this project is well tested and configurable.</description>
13-
<releaseNotes>Adding IUserSecurityStampStore, IUserConfirmationStore, IUserEmailStore interfaces.</releaseNotes>
13+
<releaseNotes>Adding IUserSecurityStampStore, IUserConfirmationStore, IUserEmailStore and IUserClaimStore interfaces.</releaseNotes>
1414
<copyright>MIT</copyright>
1515
<tags>mongo mongodb aspnet identity</tags>
1616
</metadata>

src/AspNet.Identity.MongoDB/IdentityUser.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Security.Claims;
67
using global::MongoDB.Bson;
78
using global::MongoDB.Bson.Serialization.Attributes;
89
using Microsoft.AspNet.Identity;
@@ -14,6 +15,7 @@ public IdentityUser()
1415
Id = ObjectId.GenerateNewId().ToString();
1516
Roles = new List<string>();
1617
Logins = new List<UserLoginInfo>();
18+
Claims = new List<IdentityUserClaim>();
1719
}
1820

1921
[BsonRepresentation(BsonType.ObjectId)]
@@ -79,5 +81,22 @@ public virtual bool HasPassword()
7981
{
8082
return false;
8183
}
84+
85+
[BsonIgnoreIfNull]
86+
public List<IdentityUserClaim> Claims { get; set; }
87+
88+
public virtual void AddClaim(Claim claim)
89+
{
90+
Claims.Add(new IdentityUserClaim(claim));
91+
}
92+
93+
public virtual void RemoveClaim(Claim claim)
94+
{
95+
var claimsToRemove = Claims
96+
.Where(c => c.Type == claim.Type)
97+
.Where(c => c.Value == claim.Value);
98+
99+
Claims = Claims.Except(claimsToRemove).ToList();
100+
}
82101
}
83102
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace AspNet.Identity.MongoDB
2+
{
3+
using System.Security.Claims;
4+
5+
public class IdentityUserClaim
6+
{
7+
public IdentityUserClaim()
8+
{
9+
}
10+
11+
public IdentityUserClaim(Claim claim)
12+
{
13+
Type = claim.Type;
14+
Value = claim.Value;
15+
}
16+
17+
public string Type { get; set; }
18+
public string Value { get; set; }
19+
20+
public Claim ToSecurityClaim()
21+
{
22+
return new Claim("type", "value");
23+
}
24+
}
25+
}

src/AspNet.Identity.MongoDB/UserStore.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
{
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Security.Claims;
56
using System.Threading.Tasks;
67
using global::MongoDB.Bson;
78
using global::MongoDB.Driver.Builders;
89
using global::MongoDB.Driver.Linq;
910
using Microsoft.AspNet.Identity;
1011

11-
public class UserStore<TUser> : IUserStore<TUser>, IUserPasswordStore<TUser>, IUserRoleStore<TUser>, IUserLoginStore<TUser>, IUserSecurityStampStore<TUser>, IUserConfirmationStore<TUser>, IUserEmailStore<TUser>
12+
public class UserStore<TUser> : IUserStore<TUser>, IUserPasswordStore<TUser>, IUserRoleStore<TUser>, IUserLoginStore<TUser>, IUserSecurityStampStore<TUser>, IUserConfirmationStore<TUser>, IUserEmailStore<TUser>, IUserClaimStore<TUser>
1213
where TUser : IdentityUser
1314
{
1415
private readonly IdentityContext _Context;
@@ -152,5 +153,22 @@ public Task<TUser> FindByEmailAsync(string email)
152153
// todo what if a user can have multiple accounts with the same email?
153154
return Task.Run(() => _Context.Users.AsQueryable<TUser>().FirstOrDefault(u => u.Email == email));
154155
}
156+
157+
public Task<IList<Claim>> GetClaimsAsync(TUser user)
158+
{
159+
return Task.FromResult((IList<Claim>) user.Claims.Select(c => c.ToSecurityClaim()).ToList());
160+
}
161+
162+
public Task AddClaimAsync(TUser user, Claim claim)
163+
{
164+
user.AddClaim(claim);
165+
return Task.FromResult(0);
166+
}
167+
168+
public Task RemoveClaimAsync(TUser user, Claim claim)
169+
{
170+
user.RemoveClaim(claim);
171+
return Task.FromResult(0);
172+
}
155173
}
156174
}

src/IntegrationTests/IntegrationTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<Compile Include="IdentityContextTests.cs" />
6161
<Compile Include="IdentityUserTests.cs" />
6262
<Compile Include="Properties\AssemblyInfo.cs" />
63+
<Compile Include="UserClaimStoreTests.cs" />
6364
<Compile Include="UserConfirmationStoreTests.cs" />
6465
<Compile Include="UserEmailStoreTests.cs" />
6566
<Compile Include="UserIntegrationTestsBase.cs" />
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
namespace IntegrationTests
2+
{
3+
using System.Linq;
4+
using System.Security.Claims;
5+
using AspNet.Identity.MongoDB;
6+
using Microsoft.AspNet.Identity;
7+
using NUnit.Framework;
8+
9+
[TestFixture]
10+
public class UserClaimStoreTests : UserIntegrationTestsBase
11+
{
12+
[Test]
13+
public void Create_NewUser_HasNoClaims()
14+
{
15+
var user = new IdentityUser {UserName = "bob"};
16+
var manager = GetUserManager();
17+
manager.Create(user);
18+
19+
var claims = manager.GetClaims(user.Id);
20+
21+
Expect(claims, Is.Empty);
22+
}
23+
24+
[Test]
25+
public void AddClaim_ReturnsClaim()
26+
{
27+
var user = new IdentityUser {UserName = "bob"};
28+
var manager = GetUserManager();
29+
manager.Create(user);
30+
31+
manager.AddClaim(user.Id, new Claim("type", "value"));
32+
33+
var claim = manager.GetClaims(user.Id).Single();
34+
Expect(claim.Type, Is.EqualTo("type"));
35+
Expect(claim.Value, Is.EqualTo("value"));
36+
}
37+
38+
[Test]
39+
public void RemoveClaim_RemovesExistingClaim()
40+
{
41+
var user = new IdentityUser {UserName = "bob"};
42+
var manager = GetUserManager();
43+
manager.Create(user);
44+
manager.AddClaim(user.Id, new Claim("type", "value"));
45+
46+
manager.RemoveClaim(user.Id, new Claim("type", "value"));
47+
48+
Expect(manager.GetClaims(user.Id), Is.Empty);
49+
}
50+
51+
[Test]
52+
public void RemoveClaim_DifferentType_DoesNotRemoveClaim()
53+
{
54+
var user = new IdentityUser { UserName = "bob" };
55+
var manager = GetUserManager();
56+
manager.Create(user);
57+
manager.AddClaim(user.Id, new Claim("type", "value"));
58+
59+
manager.RemoveClaim(user.Id, new Claim("otherType", "value"));
60+
61+
Expect(manager.GetClaims(user.Id), Is.Not.Empty);
62+
}
63+
64+
[Test]
65+
public void RemoveClaim_DifferentValue_DoesNotRemoveClaim()
66+
{
67+
var user = new IdentityUser { UserName = "bob" };
68+
var manager = GetUserManager();
69+
manager.Create(user);
70+
manager.AddClaim(user.Id, new Claim("type", "value"));
71+
72+
manager.RemoveClaim(user.Id, new Claim("type", "otherValue"));
73+
74+
Expect(manager.GetClaims(user.Id), Is.Not.Empty);
75+
}
76+
}
77+
}

src/Tests/IdentityUserClaimTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace Tests
2+
{
3+
using System.Security.Claims;
4+
using AspNet.Identity.MongoDB;
5+
using NUnit.Framework;
6+
7+
[TestFixture]
8+
public class IdentityUserClaimTests : AssertionHelper
9+
{
10+
[Test]
11+
public void Create_FromClaim_SetsTypeAndValue()
12+
{
13+
var claim = new Claim("type", "value");
14+
15+
var userClaim = new IdentityUserClaim(claim);
16+
17+
Expect(userClaim.Type, Is.EqualTo("type"));
18+
Expect(userClaim.Value, Is.EqualTo("value"));
19+
}
20+
21+
[Test]
22+
public void ToSecurityClaim_SetsTypeAndValue()
23+
{
24+
var userClaim = new IdentityUserClaim {Type = "type", Value = "value"};
25+
26+
var claim = userClaim.ToSecurityClaim();
27+
28+
Expect(claim.Type, Is.EqualTo("type"));
29+
Expect(claim.Value, Is.EqualTo("value"));
30+
}
31+
}
32+
}

src/Tests/IdentityUserTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,25 @@ public void SetConfirmed_AlreadyConfirmed_DoesNotUpdateConfirmedAt()
107107
var after = DateTime.UtcNow;
108108
Expect(user.ConfirmedAtUtc, Is.Not.InRange(before, after));
109109
}
110+
111+
[Test]
112+
public void Create_NewIdentityUser_ClaimsNotNull()
113+
{
114+
var user = new IdentityUser();
115+
116+
Expect(user.Claims, Is.Not.Null);
117+
}
118+
119+
[Test]
120+
public void Create_NullClaims_DoesNotSerializeClaims()
121+
{
122+
// serialized nulls can cause havoc in deserialization, overwriting the constructor's initial empty list
123+
var user = new IdentityUser();
124+
user.Claims = null;
125+
126+
var document = user.ToBsonDocument();
127+
128+
Expect(document.Contains("Claims"), Is.False);
129+
}
110130
}
111131
}

src/Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<Reference Include="System.Xml" />
5757
</ItemGroup>
5858
<ItemGroup>
59+
<Compile Include="IdentityUserClaimTests.cs" />
5960
<Compile Include="IdentityUserTests.cs" />
6061
<Compile Include="Properties\AssemblyInfo.cs" />
6162
<Compile Include="ObjectIdHelpers.cs" />

0 commit comments

Comments
 (0)