mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-17 06:23:03 +03:00
completed auth database
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
@@ -13,12 +11,14 @@ using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -27,7 +27,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Session
|
||||
{
|
||||
@@ -62,6 +61,8 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
|
||||
private readonly IAuthenticationRepository _authRepo;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration manager.
|
||||
/// </summary>
|
||||
@@ -104,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="userRepository">The user repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient)
|
||||
public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo)
|
||||
{
|
||||
_userDataRepository = userDataRepository;
|
||||
_configurationManager = configurationManager;
|
||||
@@ -119,6 +120,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_appHost = appHost;
|
||||
_httpClient = httpClient;
|
||||
_authRepo = authRepo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -204,7 +206,12 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">user</exception>
|
||||
/// <exception cref="System.UnauthorizedAccessException"></exception>
|
||||
public async Task<SessionInfo> LogSessionActivity(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
|
||||
public async Task<SessionInfo> LogSessionActivity(string clientType,
|
||||
string appVersion,
|
||||
string deviceId,
|
||||
string deviceName,
|
||||
string remoteEndPoint,
|
||||
User user)
|
||||
{
|
||||
if (string.IsNullOrEmpty(clientType))
|
||||
{
|
||||
@@ -1157,7 +1164,37 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
|
||||
public void ValidateSecurityToken(string token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var result = _authRepo.Get(new AuthenticationInfoQuery
|
||||
{
|
||||
AccessToken = token
|
||||
});
|
||||
|
||||
var info = result.Items.FirstOrDefault();
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
if (!info.IsActive)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access token has expired.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(info.UserId))
|
||||
{
|
||||
var user = _userManager.GetUserById(new Guid(info.UserId));
|
||||
|
||||
if (user == null || user.Configuration.IsDisabled)
|
||||
{
|
||||
throw new UnauthorizedAccessException("User account has been disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1175,7 +1212,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
/// <exception cref="UnauthorizedAccessException"></exception>
|
||||
public async Task<AuthenticationResult> AuthenticateNewSession(string username, string password, string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint)
|
||||
{
|
||||
var result = await _userManager.AuthenticateUser(username, password).ConfigureAwait(false);
|
||||
var result = IsLocalhost(remoteEndPoint) || await _userManager.AuthenticateUser(username, password).ConfigureAwait(false);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -1185,6 +1222,8 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
var user = _userManager.Users
|
||||
.First(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var token = await GetAuthorizationToken(user.Id.ToString("N"), deviceId, clientType, deviceName).ConfigureAwait(false);
|
||||
|
||||
var session = await LogSessionActivity(clientType,
|
||||
appVersion,
|
||||
deviceId,
|
||||
@@ -1197,11 +1236,108 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
{
|
||||
User = _dtoService.GetUserDto(user),
|
||||
SessionInfo = GetSessionInfoDto(session),
|
||||
AuthenticationToken = Guid.NewGuid().ToString("N")
|
||||
AccessToken = token
|
||||
};
|
||||
}
|
||||
|
||||
private bool IsLocal(string remoteEndpoint)
|
||||
private async Task<string> GetAuthorizationToken(string userId, string deviceId, string app, string deviceName)
|
||||
{
|
||||
var existing = _authRepo.Get(new AuthenticationInfoQuery
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
IsActive = true,
|
||||
UserId = userId,
|
||||
Limit = 1
|
||||
});
|
||||
|
||||
if (existing.Items.Length > 0)
|
||||
{
|
||||
_logger.Debug("Reissuing access token");
|
||||
return existing.Items[0].AccessToken;
|
||||
}
|
||||
|
||||
var newToken = new AuthenticationInfo
|
||||
{
|
||||
AppName = app,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DeviceId = deviceId,
|
||||
DeviceName = deviceName,
|
||||
UserId = userId,
|
||||
IsActive = true,
|
||||
AccessToken = Guid.NewGuid().ToString("N")
|
||||
};
|
||||
|
||||
_logger.Debug("Creating new access token for user {0}", userId);
|
||||
await _authRepo.Create(newToken, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return newToken.AccessToken;
|
||||
}
|
||||
|
||||
public async Task Logout(string accessToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(accessToken))
|
||||
{
|
||||
throw new ArgumentNullException("accessToken");
|
||||
}
|
||||
|
||||
var existing = _authRepo.Get(new AuthenticationInfoQuery
|
||||
{
|
||||
Limit = 1,
|
||||
AccessToken = accessToken
|
||||
|
||||
}).Items.FirstOrDefault();
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existing.IsActive = false;
|
||||
|
||||
await _authRepo.Update(existing, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var sessions = Sessions
|
||||
.Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReportSessionEnded(session.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error reporting session ended", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RevokeUserTokens(string userId)
|
||||
{
|
||||
var existing = _authRepo.Get(new AuthenticationInfoQuery
|
||||
{
|
||||
IsActive = true,
|
||||
UserId = userId
|
||||
});
|
||||
|
||||
foreach (var info in existing.Items)
|
||||
{
|
||||
await Logout(info.AccessToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsLocalhost(string remoteEndpoint)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(remoteEndpoint))
|
||||
{
|
||||
throw new ArgumentNullException("remoteEndpoint");
|
||||
}
|
||||
|
||||
return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
|
||||
remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public bool IsLocal(string remoteEndpoint)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(remoteEndpoint))
|
||||
{
|
||||
@@ -1211,12 +1347,11 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
// Private address space:
|
||||
// http://en.wikipedia.org/wiki/Private_network
|
||||
|
||||
return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
return IsLocalhost(remoteEndpoint) ||
|
||||
remoteEndpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
|
||||
remoteEndpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
|
||||
remoteEndpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
|
||||
remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
|
||||
remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase);
|
||||
remoteEndpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user