Adds notes for external login service/repo, changes IdentityUserLogin user id to string for now so it can be shared with members/users
This commit is contained in:
@@ -21,7 +21,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
/// <summary>
|
||||
/// Gets or sets user Id for the user who owns this login
|
||||
/// </summary>
|
||||
int UserId { get; set; }
|
||||
string UserId { get; set; } // TODO: This should be able to be used by both users and members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets any arbitrary data for the user and external provider - like user tokens returned from the provider
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace Umbraco.Core.Models.Identity
|
||||
/// </summary>
|
||||
public class IdentityUserLogin : EntityBase, IIdentityUserLogin
|
||||
{
|
||||
public IdentityUserLogin(string loginProvider, string providerKey, int userId)
|
||||
public IdentityUserLogin(string loginProvider, string providerKey, string userId)
|
||||
{
|
||||
LoginProvider = loginProvider;
|
||||
ProviderKey = providerKey;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public IdentityUserLogin(int id, string loginProvider, string providerKey, int userId, DateTime createDate)
|
||||
public IdentityUserLogin(int id, string loginProvider, string providerKey, string userId, DateTime createDate)
|
||||
{
|
||||
Id = id;
|
||||
LoginProvider = loginProvider;
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
public string ProviderKey { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int UserId { get; set; }
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string UserData { get; set; }
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
/// <summary>
|
||||
/// Gets or sets userId for the user that is in the role
|
||||
/// </summary>
|
||||
public virtual string UserId { get; set; }
|
||||
public virtual int UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets roleId for the role
|
||||
|
||||
@@ -239,18 +239,18 @@ namespace Umbraco.Core.Security
|
||||
get => _groups;
|
||||
set
|
||||
{
|
||||
//so they recalculate
|
||||
// so they recalculate
|
||||
_allowedSections = null;
|
||||
|
||||
_groups = value;
|
||||
|
||||
//now clear all roles and re-add them
|
||||
// now clear all roles and re-add them
|
||||
_roles.CollectionChanged -= _roles_CollectionChanged;
|
||||
_roles.Clear();
|
||||
foreach (var identityUserRole in _groups.Select(x => new IdentityUserRole
|
||||
{
|
||||
RoleId = x.Alias,
|
||||
UserId = Id.ToString()
|
||||
UserId = Id
|
||||
}))
|
||||
{
|
||||
_roles.Add(identityUserRole);
|
||||
@@ -342,7 +342,7 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
Roles.Add(new IdentityUserRole
|
||||
{
|
||||
UserId = Id.ToString(),
|
||||
UserId = Id,
|
||||
RoleId = role
|
||||
});
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ namespace Umbraco.Core.BackOffice
|
||||
if (login == null) throw new ArgumentNullException(nameof(login));
|
||||
|
||||
var logins = user.Logins;
|
||||
var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id);
|
||||
var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id.ToString());
|
||||
var userLogin = instance;
|
||||
logins.Add(userLogin);
|
||||
|
||||
@@ -462,25 +462,29 @@ namespace Umbraco.Core.BackOffice
|
||||
/// <summary>
|
||||
/// Returns the user associated with this login
|
||||
/// </summary>
|
||||
/// <returns/>
|
||||
public Task<BackOfficeIdentityUser> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
//get all logins associated with the login id
|
||||
var result = _externalLoginService.Find(loginProvider, providerKey).ToArray();
|
||||
// get all logins associated with the login id
|
||||
IIdentityUserLogin[] result = _externalLoginService.Find(loginProvider, providerKey).ToArray();
|
||||
if (result.Any())
|
||||
{
|
||||
//return the first user that matches the result
|
||||
// return the first user that matches the result
|
||||
BackOfficeIdentityUser output = null;
|
||||
foreach (var l in result)
|
||||
foreach (IIdentityUserLogin l in result)
|
||||
{
|
||||
var user = _userService.GetUserById(l.UserId);
|
||||
if (user != null)
|
||||
// TODO: This won't be necessary once we add GUID support for users and make the external login
|
||||
// table uses GUIDs without referential integrity
|
||||
if (int.TryParse(l.UserId, out int userId))
|
||||
{
|
||||
output = _mapper.Map<BackOfficeIdentityUser>(user);
|
||||
break;
|
||||
IUser user = _userService.GetUserById(userId);
|
||||
if (user != null)
|
||||
{
|
||||
output = _mapper.Map<BackOfficeIdentityUser>(user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,16 +18,47 @@ namespace Umbraco.Core.BackOffice
|
||||
public interface IUmbracoUserManager<TUser> : IDisposable
|
||||
where TUser : BackOfficeIdentityUser
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user id of a user
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<string> GetUserIdAsync(TUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="TUser"/> from a <see cref="ClaimsPrincipal"/>
|
||||
/// </summary>
|
||||
/// <param name="principal">The <see cref="ClaimsPrincipal"/></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<TUser> GetUserAsync(ClaimsPrincipal principal);
|
||||
|
||||
/// <summary>
|
||||
/// Get the user id from the <see cref="ClaimsPrincipal"/>
|
||||
/// </summary>
|
||||
/// <param name="principal">the <see cref="ClaimsPrincipal"/></param>
|
||||
/// <returns>Returns the user id from the <see cref="ClaimsPrincipal"/></returns>
|
||||
string GetUserId(ClaimsPrincipal principal);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the external logins for the user
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a user
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<IdentityResult> DeleteAsync(TUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Finds a user by the external login provider
|
||||
/// </summary>
|
||||
/// <param name="loginProvider"></param>
|
||||
/// <param name="providerKey"></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<TUser> FindByLoginAsync(string loginProvider, string providerKey);
|
||||
|
||||
/// <summary>
|
||||
@@ -147,8 +178,7 @@ namespace Umbraco.Core.BackOffice
|
||||
/// The <see cref="Task"/> that represents the asynchronous operation, returning true if the <paramref name="token"/>
|
||||
/// is valid, otherwise false.
|
||||
/// </returns>
|
||||
Task<bool> VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose,
|
||||
string token);
|
||||
Task<bool> VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose, string token);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <paramref name="password"/> to the specified <paramref name="user"/> only if the user
|
||||
@@ -185,15 +215,14 @@ namespace Umbraco.Core.BackOffice
|
||||
/// The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/>
|
||||
/// of the operation.
|
||||
/// </returns>
|
||||
Task<IdentityResult> ChangePasswordAsync(TUser user, string currentPassword,
|
||||
string newPassword);
|
||||
Task<IdentityResult> ChangePasswordAsync(TUser user, string currentPassword, string newPassword);
|
||||
|
||||
/// <summary>
|
||||
/// Used to validate a user's session
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="sessionId"></param>
|
||||
/// <returns></returns>
|
||||
/// <returns>Returns true if the session is valid, otherwise false</returns>
|
||||
Task<bool> ValidateSessionIdAsync(string userId, string sessionId);
|
||||
|
||||
/// <summary>
|
||||
@@ -208,12 +237,11 @@ namespace Umbraco.Core.BackOffice
|
||||
Task<IdentityResult> CreateAsync(TUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to generate a password for a user based on the current password validator
|
||||
/// Generate a password for a user based on the current password validator
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns>A generated password</returns>
|
||||
string GeneratePassword();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates an email confirmation token for the specified user.
|
||||
/// </summary>
|
||||
@@ -292,8 +320,19 @@ namespace Umbraco.Core.BackOffice
|
||||
/// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation, containing the Microsoft.AspNetCore.Identity.IdentityResult of the operation.</returns>
|
||||
Task<IdentityResult> RemoveLoginAsync(TUser user, string loginProvider, string providerKey);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the access failed count for the user
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<IdentityResult> ResetAccessFailedCountAsync(TUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a two factor token for the user
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="tokenProvider"></param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
Task<string> GenerateTwoFactorTokenAsync(TUser user, string tokenProvider);
|
||||
|
||||
/// <summary>
|
||||
@@ -316,6 +355,7 @@ namespace Umbraco.Core.BackOffice
|
||||
// TODO: These are raised from outside the signinmanager and usermanager in the auth and user controllers,
|
||||
// let's see if there's a way to avoid that and only have these called within signinmanager and usermanager
|
||||
// which means we can remove these from the interface (things like invite seems like they cannot be moved)
|
||||
// TODO: When we change to not having the crappy static events this will need to be revisited
|
||||
void RaiseForgotPasswordRequestedEvent(IPrincipal currentUser, int userId);
|
||||
void RaiseForgotPasswordChangedSuccessEvent(IPrincipal currentUser, int userId);
|
||||
SignOutAuditEventArgs RaiseLogoutSuccessEvent(IPrincipal currentUser, int userId);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
@@ -19,6 +19,8 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
UserStartNodeDtos = new HashSet<UserStartNodeDto>();
|
||||
}
|
||||
|
||||
// TODO: We need to add a GUID for users and track external logins with that instead of the INT
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(Name = "PK_user")]
|
||||
public int Id { get; set; }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
public static IIdentityUserLogin BuildEntity(ExternalLoginDto dto)
|
||||
{
|
||||
var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId, dto.CreateDate)
|
||||
var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId.ToString(), dto.CreateDate)
|
||||
{
|
||||
UserData = dto.UserData
|
||||
};
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
CreateDate = entity.CreateDate,
|
||||
LoginProvider = entity.LoginProvider,
|
||||
ProviderKey = entity.ProviderKey,
|
||||
UserId = entity.UserId,
|
||||
UserId = int.Parse(entity.UserId), // TODO: This is temp until we change the ext logins to use GUIDs
|
||||
UserData = entity.UserData
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -13,6 +13,8 @@ using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
// TODO: We should update this to support both users and members. It means we would remove referential integrity from users
|
||||
// and the user/member key would be a GUID (we also need to add a GUID to users)
|
||||
internal class ExternalLoginRepository : NPocoRepositoryBase<int, IIdentityUserLogin>, IExternalLoginRepository
|
||||
{
|
||||
public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger<ExternalLoginRepository> logger)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -25,7 +25,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _externalLoginRepository.Get(Query<IIdentityUserLogin>().Where(x => x.UserId == userId))
|
||||
var asString = userId.ToString(); // TODO: This is temp until we update the external service to support guids for both users and members
|
||||
return _externalLoginRepository.Get(Query<IIdentityUserLogin>().Where(x => x.UserId == asString))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
@@ -93,7 +93,7 @@ namespace Umbraco.Tests.Services
|
||||
var user = new User(GlobalSettings, "Test", "test@test.com", "test", "helloworldtest");
|
||||
UserService.Save(user);
|
||||
|
||||
var extLogin = new IdentityUserLogin("test1", Guid.NewGuid().ToString("N"), user.Id)
|
||||
var extLogin = new IdentityUserLogin("test1", Guid.NewGuid().ToString("N"), user.Id.ToString())
|
||||
{
|
||||
UserData = "hello"
|
||||
};
|
||||
@@ -112,7 +112,7 @@ namespace Umbraco.Tests.Services
|
||||
var user = new User(GlobalSettings, "Test", "test@test.com", "test", "helloworldtest");
|
||||
UserService.Save(user);
|
||||
|
||||
var extLogin = new IdentityUserLogin("test1", Guid.NewGuid().ToString("N"), user.Id)
|
||||
var extLogin = new IdentityUserLogin("test1", Guid.NewGuid().ToString("N"), user.Id.ToString())
|
||||
{
|
||||
UserData = "hello"
|
||||
};
|
||||
@@ -218,7 +218,7 @@ namespace Umbraco.Tests.Services
|
||||
var logins = ExternalLoginService.GetAll(user.Id).OrderBy(x => x.LoginProvider).ToList();
|
||||
|
||||
logins.RemoveAt(0); // remove the first one
|
||||
logins.Add(new IdentityUserLogin("test5", Guid.NewGuid().ToString("N"), user.Id)); // add a new one
|
||||
logins.Add(new IdentityUserLogin("test5", Guid.NewGuid().ToString("N"), user.Id.ToString())); // add a new one
|
||||
|
||||
// save new list
|
||||
ExternalLoginService.Save(user.Id, logins.Select(x => new ExternalLogin(x.LoginProvider, x.ProviderKey)));
|
||||
|
||||
Reference in New Issue
Block a user