mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Refactoring authentication validation
This commit is contained in:
@@ -35,6 +35,7 @@ using Orchard.Services;
|
|||||||
namespace Orchard.Tests.Modules.Users.Services {
|
namespace Orchard.Tests.Modules.Users.Services {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MembershipServiceTests {
|
public class MembershipServiceTests {
|
||||||
|
private IMembershipValidationService _membershipValidationService;
|
||||||
private IMembershipService _membershipService;
|
private IMembershipService _membershipService;
|
||||||
private ISessionFactory _sessionFactory;
|
private ISessionFactory _sessionFactory;
|
||||||
private ISession _session;
|
private ISession _session;
|
||||||
@@ -73,6 +74,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
public void Init() {
|
public void Init() {
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
//builder.RegisterModule(new ImplicitCollectionSupportModule());
|
//builder.RegisterModule(new ImplicitCollectionSupportModule());
|
||||||
|
builder.RegisterType<MembershipValidationService>().As<IMembershipValidationService>();
|
||||||
builder.RegisterType<MembershipService>().As<IMembershipService>();
|
builder.RegisterType<MembershipService>().As<IMembershipService>();
|
||||||
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
|
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
|
||||||
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
|
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
|
||||||
@@ -98,6 +100,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
_session = _sessionFactory.OpenSession();
|
_session = _sessionFactory.OpenSession();
|
||||||
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
|
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
|
_membershipValidationService = _container.Resolve<IMembershipValidationService>();
|
||||||
_membershipService = _container.Resolve<IMembershipService>();
|
_membershipService = _container.Resolve<IMembershipService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +162,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
public void UsersWhoHaveNeverLoggedInCanBeAuthenticated() {
|
public void UsersWhoHaveNeverLoggedInCanBeAuthenticated() {
|
||||||
var user = (UserPart)_membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true));
|
var user = (UserPart)_membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true));
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.True);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -169,7 +172,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
user.LastLoginUtc = _clock.UtcNow;
|
user.LastLoginUtc = _clock.UtcNow;
|
||||||
_clock.Advance(TimeSpan.FromMinutes(1));
|
_clock.Advance(TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.True);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -181,7 +184,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
user.LastLogoutUtc = _clock.UtcNow;
|
user.LastLogoutUtc = _clock.UtcNow;
|
||||||
_clock.Advance(TimeSpan.FromMinutes(1));
|
_clock.Advance(TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.False);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -193,7 +196,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
user.LastLoginUtc = _clock.UtcNow;
|
user.LastLoginUtc = _clock.UtcNow;
|
||||||
_clock.Advance(TimeSpan.FromMinutes(1));
|
_clock.Advance(TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.True);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -202,7 +205,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
|
|
||||||
user.RegistrationStatus = UserStatus.Pending;
|
user.RegistrationStatus = UserStatus.Pending;
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.False);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -211,7 +214,7 @@ namespace Orchard.Tests.Modules.Users.Services {
|
|||||||
|
|
||||||
user.RegistrationStatus = UserStatus.Approved;
|
user.RegistrationStatus = UserStatus.Approved;
|
||||||
|
|
||||||
Assert.That(_membershipService.CanAuthenticateWithCookie(user), Is.True);
|
Assert.That(_membershipValidationService.CanAuthenticateWithCookie(user), Is.True);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\AuthenticationRedirectionFilter.cs" />
|
<Compile Include="Services\AuthenticationRedirectionFilter.cs" />
|
||||||
<Compile Include="Services\IUserService.cs" />
|
<Compile Include="Services\IUserService.cs" />
|
||||||
|
<Compile Include="Services\MembershipValidationService.cs" />
|
||||||
<Compile Include="Services\UserResolverSelector.cs" />
|
<Compile Include="Services\UserResolverSelector.cs" />
|
||||||
<Compile Include="Services\MembershipService.cs" />
|
<Compile Include="Services\MembershipService.cs" />
|
||||||
<Compile Include="AdminMenu.cs" />
|
<Compile Include="AdminMenu.cs" />
|
||||||
|
|||||||
@@ -289,29 +289,5 @@ namespace Orchard.Users.Services {
|
|||||||
return String.Equals(password, Encoding.UTF8.GetString(_encryptionService.Decode(Convert.FromBase64String(userPart.Password))), StringComparison.Ordinal);
|
return String.Equals(password, Encoding.UTF8.GetString(_encryptionService.Decode(Convert.FromBase64String(userPart.Password))), StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAuthenticateWithCookie(IUser user) {
|
|
||||||
var userPart = user as UserPart;
|
|
||||||
|
|
||||||
if (userPart == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// user has not been approved or is currently disabled
|
|
||||||
if(userPart.RegistrationStatus != UserStatus.Approved) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the user has logged out, a cookie should not be accepted
|
|
||||||
if(userPart.LastLogoutUtc.HasValue) {
|
|
||||||
|
|
||||||
if (!userPart.LastLoginUtc.HasValue) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return userPart.LastLogoutUtc < userPart.LastLoginUtc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Orchard.Security;
|
||||||
|
using Orchard.Users.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Users.Services {
|
||||||
|
public class MembershipValidationService : IMembershipValidationService {
|
||||||
|
|
||||||
|
public bool CanAuthenticateWithCookie(IUser user) {
|
||||||
|
var userPart = user as UserPart;
|
||||||
|
|
||||||
|
if (userPart == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// user has not been approved or is currently disabled
|
||||||
|
if (userPart.RegistrationStatus != UserStatus.Approved) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the user has logged out, a cookie should not be accepted
|
||||||
|
if (userPart.LastLogoutUtc.HasValue) {
|
||||||
|
|
||||||
|
if (!userPart.LastLoginUtc.HasValue) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userPart.LastLogoutUtc < userPart.LastLoginUtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -149,8 +149,10 @@
|
|||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Security\IMembershipValidationService.cs" />
|
||||||
<Compile Include="Security\ISslSettingsProvider.cs" />
|
<Compile Include="Security\ISslSettingsProvider.cs" />
|
||||||
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
|
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
|
||||||
|
<Compile Include="Security\Providers\DefaultMembershipValidationService.cs" />
|
||||||
<Compile Include="StaticHttpContextScope.cs" />
|
<Compile Include="StaticHttpContextScope.cs" />
|
||||||
<Compile Include="StaticHttpContextScopeFactory.cs" />
|
<Compile Include="StaticHttpContextScopeFactory.cs" />
|
||||||
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
||||||
@@ -1027,4 +1029,4 @@
|
|||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
||||||
@@ -6,10 +6,5 @@
|
|||||||
IUser GetUser(string username);
|
IUser GetUser(string username);
|
||||||
IUser ValidateUser(string userNameOrEmail, string password);
|
IUser ValidateUser(string userNameOrEmail, string password);
|
||||||
void SetPassword(IUser user, string password);
|
void SetPassword(IUser user, string password);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns <c>true</c> if the user is allowed to login from an auth cookie, <c>false</c> otherwise.
|
|
||||||
/// </summary>
|
|
||||||
bool CanAuthenticateWithCookie(IUser user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/Orchard/Security/IMembershipValidationService.cs
Normal file
8
src/Orchard/Security/IMembershipValidationService.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Orchard.Security {
|
||||||
|
public interface IMembershipValidationService : IDependency {
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <c>true</c> if the user is allowed to login from an auth cookie, <c>false</c> otherwise.
|
||||||
|
/// </summary>
|
||||||
|
bool CanAuthenticateWithCookie(IUser user);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Orchard.Security {
|
||||||
|
public class DefaultMembershipValidationService : IMembershipValidationService {
|
||||||
|
public bool CanAuthenticateWithCookie(IUser user) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ namespace Orchard.Security.Providers {
|
|||||||
private readonly IContentManager _contentManager;
|
private readonly IContentManager _contentManager;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
private readonly ISslSettingsProvider _sslSettingsProvider;
|
private readonly ISslSettingsProvider _sslSettingsProvider;
|
||||||
|
private readonly IMembershipValidationService _membershipValidationService;
|
||||||
|
|
||||||
private IUser _signedInUser;
|
private IUser _signedInUser;
|
||||||
private bool _isAuthenticated;
|
private bool _isAuthenticated;
|
||||||
|
|
||||||
@@ -23,12 +25,14 @@ namespace Orchard.Security.Providers {
|
|||||||
IClock clock,
|
IClock clock,
|
||||||
IContentManager contentManager,
|
IContentManager contentManager,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
ISslSettingsProvider sslSettingsProvider) {
|
ISslSettingsProvider sslSettingsProvider,
|
||||||
|
IMembershipValidationService membershipValidationService) {
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_clock = clock;
|
_clock = clock;
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_sslSettingsProvider = sslSettingsProvider;
|
_sslSettingsProvider = sslSettingsProvider;
|
||||||
|
_membershipValidationService = membershipValidationService;
|
||||||
|
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
|
|
||||||
@@ -137,8 +141,15 @@ namespace Orchard.Security.Providers {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: this issues a sql query for each authenticated request
|
||||||
|
_signedInUser = _contentManager.Get(userId).As<IUser>();
|
||||||
|
|
||||||
|
if (_signedInUser == null || !_membershipValidationService.CanAuthenticateWithCookie(_signedInUser)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
_isAuthenticated = true;
|
_isAuthenticated = true;
|
||||||
return _signedInUser = _contentManager.Get(userId).As<IUser>();
|
return _signedInUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCookiePath(HttpContextBase httpContext) {
|
private string GetCookiePath(HttpContextBase httpContext) {
|
||||||
|
|||||||
Reference in New Issue
Block a user