aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs128
-rw-r--r--MediaBrowser.Api/UserService.cs24
-rw-r--r--MediaBrowser.Controller/Connect/IConnectManager.cs5
-rw-r--r--MediaBrowser.Controller/Entities/User.cs1
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs27
-rw-r--r--MediaBrowser.Controller/Session/AuthenticationRequest.cs1
6 files changed, 108 insertions, 78 deletions
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index e3c36fc02..c9de3c01b 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -180,11 +180,6 @@ namespace Emby.Server.Implementations.Library
}
}
- public Task<User> AuthenticateUser(string username, string passwordSha1, string remoteEndPoint)
- {
- return AuthenticateUser(username, passwordSha1, null, remoteEndPoint);
- }
-
public bool IsValidUsername(string username)
{
// Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
@@ -223,7 +218,7 @@ namespace Emby.Server.Implementations.Library
return builder.ToString();
}
- public async Task<User> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint)
+ public async Task<User> AuthenticateUser(string username, string password, string hashedPassword, string passwordMd5, string remoteEndPoint)
{
if (string.IsNullOrWhiteSpace(username))
{
@@ -237,23 +232,23 @@ namespace Emby.Server.Implementations.Library
if (user != null)
{
+ if (password != null)
+ {
+ hashedPassword = GetHashedString(user, password);
+ }
+
// Authenticate using local credentials if not a guest
if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest)
{
- success = string.Equals(GetPasswordHash(user), passwordSha1.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
-
- if (!success && _networkManager.IsInLocalNetwork(remoteEndPoint) && user.Configuration.EnableLocalPassword)
- {
- success = string.Equals(GetLocalPasswordHash(user), passwordSha1.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
- }
+ success = AuthenticateLocalUser(user, password, hashedPassword, remoteEndPoint);
}
// Maybe user accidently entered connect credentials. let's be flexible
- if (!success && user.ConnectLinkType.HasValue && !string.IsNullOrWhiteSpace(passwordMd5) && !string.IsNullOrWhiteSpace(user.ConnectUserName))
+ if (!success && user.ConnectLinkType.HasValue && !string.IsNullOrWhiteSpace(user.ConnectUserName))
{
try
{
- await _connectFactory().Authenticate(user.ConnectUserName, passwordMd5).ConfigureAwait(false);
+ await _connectFactory().Authenticate(user.ConnectUserName, password, passwordMd5).ConfigureAwait(false);
success = true;
}
catch
@@ -268,7 +263,7 @@ namespace Emby.Server.Implementations.Library
{
try
{
- var connectAuthResult = await _connectFactory().Authenticate(username, passwordMd5).ConfigureAwait(false);
+ var connectAuthResult = await _connectFactory().Authenticate(username, password, passwordMd5).ConfigureAwait(false);
user = Users.FirstOrDefault(i => string.Equals(i.ConnectUserId, connectAuthResult.User.Id, StringComparison.OrdinalIgnoreCase));
@@ -307,6 +302,36 @@ namespace Emby.Server.Implementations.Library
return success ? user : null;
}
+ private bool AuthenticateLocalUser(User user, string password, string hashedPassword, string remoteEndPoint)
+ {
+ bool success;
+
+ if (password == null)
+ {
+ // legacy
+ success = string.Equals(GetPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
+ }
+ else
+ {
+ success = string.Equals(GetPasswordHash(user), GetHashedString(user, password), StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (!success && _networkManager.IsInLocalNetwork(remoteEndPoint) && user.Configuration.EnableLocalPassword)
+ {
+ if (password == null)
+ {
+ // legacy
+ success = string.Equals(GetLocalPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
+ }
+ else
+ {
+ success = string.Equals(GetLocalPasswordHash(user), GetHashedString(user, password), StringComparison.OrdinalIgnoreCase);
+ }
+ }
+
+ return success;
+ }
+
private void UpdateInvalidLoginAttemptCount(User user, int newValue)
{
if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
@@ -342,29 +367,39 @@ namespace Emby.Server.Implementations.Library
private string GetPasswordHash(User user)
{
return string.IsNullOrEmpty(user.Password)
- ? GetSha1String(string.Empty)
+ ? GetEmptyHashedString(user)
: user.Password;
}
private string GetLocalPasswordHash(User user)
{
return string.IsNullOrEmpty(user.EasyPassword)
- ? GetSha1String(string.Empty)
+ ? GetEmptyHashedString(user)
: user.EasyPassword;
}
- private bool IsPasswordEmpty(string passwordHash)
+ private bool IsPasswordEmpty(User user, string passwordHash)
{
- return string.Equals(passwordHash, GetSha1String(string.Empty), StringComparison.OrdinalIgnoreCase);
+ return string.Equals(passwordHash, GetEmptyHashedString(user), StringComparison.OrdinalIgnoreCase);
+ }
+
+ private string GetEmptyHashedString(User user)
+ {
+ return GetHashedString(user, string.Empty);
}
/// <summary>
- /// Gets the sha1 string.
+ /// Gets the hashed string.
/// </summary>
- /// <param name="str">The STR.</param>
- /// <returns>System.String.</returns>
- private string GetSha1String(string str)
+ private string GetHashedString(User user, string str)
{
+ var salt = user.Salt;
+ if (salt != null)
+ {
+ // return BCrypt.HashPassword(str, salt);
+ }
+
+ // legacy
return BitConverter.ToString(_cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str))).Replace("-", string.Empty);
}
@@ -407,8 +442,8 @@ namespace Emby.Server.Implementations.Library
var passwordHash = GetPasswordHash(user);
- var hasConfiguredPassword = !IsPasswordEmpty(passwordHash);
- var hasConfiguredEasyPassword = !IsPasswordEmpty(GetLocalPasswordHash(user));
+ var hasConfiguredPassword = !IsPasswordEmpty(user, passwordHash);
+ var hasConfiguredEasyPassword = !IsPasswordEmpty(user, GetLocalPasswordHash(user));
var hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
hasConfiguredEasyPassword :
@@ -460,14 +495,6 @@ namespace Emby.Server.Implementations.Library
{
var dto = GetUserDto(user);
- var offlinePasswordHash = GetLocalPasswordHash(user);
- dto.HasPassword = !IsPasswordEmpty(offlinePasswordHash);
-
- dto.OfflinePasswordSalt = Guid.NewGuid().ToString("N");
-
- // Hash the pin with the device Id to create a unique result for this device
- dto.OfflinePassword = GetSha1String((offlinePasswordHash + dto.OfflinePasswordSalt).ToLower());
-
dto.ServerName = _appHost.FriendlyName;
return dto;
@@ -682,23 +709,29 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task.</returns>
public void ResetPassword(User user)
{
- ChangePassword(user, GetSha1String(string.Empty));
+ ChangePassword(user, string.Empty, null);
}
public void ResetEasyPassword(User user)
{
- ChangeEasyPassword(user, GetSha1String(string.Empty));
+ ChangeEasyPassword(user, string.Empty, null);
}
- public void ChangePassword(User user, string newPasswordSha1)
+ public void ChangePassword(User user, string newPassword, string newPasswordHash)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
- if (string.IsNullOrWhiteSpace(newPasswordSha1))
+
+ if (newPassword != null)
+ {
+ newPasswordHash = GetHashedString(user, newPassword);
+ }
+
+ if (string.IsNullOrWhiteSpace(newPasswordHash))
{
- throw new ArgumentNullException("newPasswordSha1");
+ throw new ArgumentNullException("newPasswordHash");
}
if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
@@ -706,25 +739,31 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentException("Passwords for guests cannot be changed.");
}
- user.Password = newPasswordSha1;
+ user.Password = newPasswordHash;
UpdateUser(user);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
}
- public void ChangeEasyPassword(User user, string newPasswordSha1)
+ public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
- if (string.IsNullOrWhiteSpace(newPasswordSha1))
+
+ if (newPassword != null)
+ {
+ newPasswordHash = GetHashedString(user, newPassword);
+ }
+
+ if (string.IsNullOrWhiteSpace(newPasswordHash))
{
- throw new ArgumentNullException("newPasswordSha1");
+ throw new ArgumentNullException("newPasswordHash");
}
- user.EasyPassword = newPasswordSha1;
+ user.EasyPassword = newPasswordHash;
UpdateUser(user);
@@ -744,7 +783,8 @@ namespace Emby.Server.Implementations.Library
Id = Guid.NewGuid(),
DateCreated = DateTime.UtcNow,
DateModified = DateTime.UtcNow,
- UsesIdForConfigurationPath = true
+ UsesIdForConfigurationPath = true,
+ //Salt = BCrypt.GenerateSalt()
};
}
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 512356b43..ddefb08df 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -97,6 +97,9 @@ namespace MediaBrowser.Api
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Id { get; set; }
+ [ApiMember(Name = "Pw", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
+ public string Pw { get; set; }
+
/// <summary>
/// Gets or sets the password.
/// </summary>
@@ -125,6 +128,9 @@ namespace MediaBrowser.Api
[ApiMember(Name = "Password", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
public string Password { get; set; }
+ [ApiMember(Name = "Pw", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
+ public string Pw { get; set; }
+
[ApiMember(Name = "PasswordMd5", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
public string PasswordMd5 { get; set; }
}
@@ -148,12 +154,16 @@ namespace MediaBrowser.Api
/// <value>The password.</value>
public string CurrentPassword { get; set; }
+ public string CurrentPw { get; set; }
+
/// <summary>
/// Gets or sets the new password.
/// </summary>
/// <value>The new password.</value>
public string NewPassword { get; set; }
+ public string NewPw { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether [reset password].
/// </summary>
@@ -180,6 +190,8 @@ namespace MediaBrowser.Api
/// <value>The new password.</value>
public string NewPassword { get; set; }
+ public string NewPw { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether [reset password].
/// </summary>
@@ -408,7 +420,8 @@ namespace MediaBrowser.Api
return Post(new AuthenticateUserByName
{
Username = user.Name,
- Password = request.Password
+ Password = request.Password,
+ Pw = request.Pw
});
}
@@ -422,6 +435,7 @@ namespace MediaBrowser.Api
AppVersion = auth.Version,
DeviceId = auth.DeviceId,
DeviceName = auth.Device,
+ Password = request.Pw,
PasswordSha1 = request.Password,
PasswordMd5 = request.PasswordMd5,
RemoteEndPoint = Request.RemoteIp,
@@ -459,14 +473,14 @@ namespace MediaBrowser.Api
}
else
{
- var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPassword, Request.RemoteIp).ConfigureAwait(false);
+ var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPw, request.CurrentPassword, null, Request.RemoteIp).ConfigureAwait(false);
if (success == null)
{
throw new ArgumentException("Invalid user or password entered.");
}
- _userManager.ChangePassword(user, request.NewPassword);
+ _userManager.ChangePassword(user, request.NewPw, request.NewPassword);
var currentToken = _authContext.GetAuthorizationInfo(Request).Token;
@@ -491,7 +505,7 @@ namespace MediaBrowser.Api
}
else
{
- _userManager.ChangeEasyPassword(user, request.NewPassword);
+ _userManager.ChangeEasyPassword(user, request.NewPw, request.NewPassword);
}
}
@@ -501,8 +515,6 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
public void Post(UpdateUser request)
{
- // We need to parse this manually because we told service stack not to with IRequiresRequestStream
- // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
var id = GetPathValue(1);
AssertCanUpdateUser(_authContext, _userManager, id, false);
diff --git a/MediaBrowser.Controller/Connect/IConnectManager.cs b/MediaBrowser.Controller/Connect/IConnectManager.cs
index f899c7262..70bdc52e6 100644
--- a/MediaBrowser.Controller/Connect/IConnectManager.cs
+++ b/MediaBrowser.Controller/Connect/IConnectManager.cs
@@ -58,10 +58,7 @@ namespace MediaBrowser.Controller.Connect
/// <summary>
/// Authenticates the specified username.
/// </summary>
- /// <param name="username">The username.</param>
- /// <param name="passwordMd5">The password MD5.</param>
- /// <returns>Task.</returns>
- Task<ConnectAuthenticationResult> Authenticate(string username, string passwordMd5);
+ Task<ConnectAuthenticationResult> Authenticate(string username, string password, string passwordMd5);
/// <summary>
/// Gets the local user.
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 3c89037cc..cca3091c1 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities
/// <value>The password.</value>
public string Password { get; set; }
public string EasyPassword { get; set; }
+ public string Salt { get; set; }
public string ConnectUserName { get; set; }
public string ConnectUserId { get; set; }
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 6da3e53aa..d4232c77e 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -59,16 +59,6 @@ namespace MediaBrowser.Controller.Library
User GetUserByName(string name);
/// <summary>
- /// Authenticates a User and returns a result indicating whether or not it succeeded
- /// </summary>
- /// <param name="username">The username.</param>
- /// <param name="passwordSha1">The password sha1.</param>
- /// <param name="remoteEndPoint">The remote end point.</param>
- /// <returns>Task{System.Boolean}.</returns>
- /// <exception cref="System.ArgumentNullException">user</exception>
- Task<User> AuthenticateUser(string username, string passwordSha1, string remoteEndPoint);
-
- /// <summary>
/// Refreshes metadata for each user
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
@@ -135,18 +125,12 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Changes the password.
/// </summary>
- /// <param name="user">The user.</param>
- /// <param name="newPasswordSha1">The new password sha1.</param>
- /// <returns>Task.</returns>
- void ChangePassword(User user, string newPasswordSha1);
+ void ChangePassword(User user, string newPassword, string newPasswordSha1);
/// <summary>
/// Changes the easy password.
/// </summary>
- /// <param name="user">The user.</param>
- /// <param name="newPasswordSha1">The new password sha1.</param>
- /// <returns>Task.</returns>
- void ChangeEasyPassword(User user, string newPasswordSha1);
+ void ChangeEasyPassword(User user, string newPassword, string newPasswordSha1);
/// <summary>
/// Gets the user dto.
@@ -159,12 +143,7 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Authenticates the user.
/// </summary>
- /// <param name="username">The username.</param>
- /// <param name="passwordSha1">The password sha1.</param>
- /// <param name="passwordMd5">The password MD5.</param>
- /// <param name="remoteEndPoint">The remote end point.</param>
- /// <returns>Task&lt;System.Boolean&gt;.</returns>
- Task<User> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint);
+ Task<User> AuthenticateUser(string username, string password, string passwordSha1, string passwordMd5, string remoteEndPoint);
/// <summary>
/// Starts the forgot password process.
diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
index 362f5b2b9..1b684fa8f 100644
--- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs
+++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
@@ -5,6 +5,7 @@ namespace MediaBrowser.Controller.Session
{
public string Username { get; set; }
public string UserId { get; set; }
+ public string Password { get; set; }
public string PasswordSha1 { get; set; }
public string PasswordMd5 { get; set; }
public string App { get; set; }