fix(importer): 🐛 Allow you to only import Plex Admins without the Plex Users

pull/4707/head^2
tidusjar 2 years ago
parent e4f6244ad2
commit 8c9ad9b414

@ -0,0 +1,328 @@
using Microsoft.AspNetCore.Identity;
using Moq;
using Moq.AutoMock;
using NUnit.Framework;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Api.Plex.Models.Friends;
using Ombi.Core.Authentication;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Hubs;
using Ombi.Schedule.Jobs.Plex;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Test.Common;
using Ombi.Tests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ombi.Schedule.Tests
{
[TestFixture]
public class PlexUserImporterTests
{
private List<OmbiUser> _users = new List<OmbiUser>
{
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="abc", NormalizedUserName = "ABC", UserType = UserType.LocalUser},
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="sys", NormalizedUserName = "SYS", UserType = UserType.SystemUser},
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="plex", NormalizedUserName = "PLEX", UserType = UserType.PlexUser, ProviderUserId = "PLEX_ID", Email = "dupe"},
};
private AutoMocker _mocker;
private PlexUserImporter _subject;
[SetUp]
public void SetUp()
{
_mocker = new AutoMocker();
var um = MockHelper.MockUserManager(_users);
var hub = SignalRHelper.MockHub<NotificationHub>();
_mocker.Use(um);
_mocker.Use(hub);
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings
{
Enable = true,
Servers = new List<PlexServers>
{
new PlexServers { Name = "Test", MachineIdentifier = "123", PlexAuthToken = "abc" }
}
});
_subject = _mocker.CreateInstance<PlexUserImporter>();
}
[Test]
public async Task Import_Exits_WhenNot_Enabled()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = false });
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Exits_When_Plex_Not_Enabled()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = true, ImportPlexUsers = true });
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = false });
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Exits_When_Plex_No_AuthToken()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = true, ImportPlexUsers = true });
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings
{
Enable = true,
Servers = new List<PlexServers>
{
new PlexServers { Name = "Test", MachineIdentifier = "123", PlexAuthToken = null }
}
});
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Only_Imports_Plex_Admin()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = true, ImportPlexUsers = false });
_mocker.Setup<IPlexApi, Task<PlexAccount>>(x => x.GetAccount(It.IsAny<string>())).ReturnsAsync(new PlexAccount
{
user = new User
{
email = "email",
authentication_token = "user_token",
title = "user_title",
username = "user_username",
id = "user_id",
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x => x.UserName == "user_username" && x.Email == "email" && x.ProviderUserId == "user_id" && x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "user_username"), It.Is<string>(x => x == OmbiRoles.Admin)))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Once);
}
[Test]
public async Task Import_Only_Imports_Plex_Admin_Already_Exists()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = true, ImportPlexUsers = false });
_mocker.Setup<IPlexApi, Task<PlexAccount>>(x => x.GetAccount(It.IsAny<string>())).ReturnsAsync(new PlexAccount
{
user = new User
{
email = "email",
authentication_token = "user_token",
title = "user_title",
username = "newUsername",
id = "PLEX_ID",
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x => x.UserName == "user_username" && x.Email == "email" && x.ProviderUserId == "user_id" && x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "user_username"), It.Is<string>(x => x == OmbiRoles.Admin)))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
_mocker.Verify<OmbiUserManager>(x => x.UpdateAsync(It.Is<OmbiUser>(x => x.Email == "email" && x.UserName == "newUsername")), Times.Once);
}
[Test]
public async Task Import_Only_Imports_Plex_Admin_Username_Clash()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = true, ImportPlexUsers = false });
_mocker.Setup<IPlexApi, Task<PlexAccount>>(x => x.GetAccount(It.IsAny<string>())).ReturnsAsync(new PlexAccount
{
user = new User
{
email = "email",
authentication_token = "user_token",
title = "user_title",
username = "abc",
id = "nah",
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x => x.UserName == "user_username" && x.Email == "email" && x.ProviderUserId == "user_id" && x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "user_username"), It.Is<string>(x => x == OmbiRoles.Admin)))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
_mocker.Verify<OmbiUserManager>(x => x.UpdateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Doesnt_Import_Banned_Users()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true, BannedPlexUserIds = new List<string> { "Banned" } });
_mocker.Setup<IPlexApi, Task<PlexFriends>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexFriends
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "Banned",
Title = "title",
Username = "username"
}
}
});
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Doesnt_Import_Managed_User()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true });
_mocker.Setup<IPlexApi, Task<PlexFriends>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexFriends
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "id",
Title = "title",
}
}
});
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Doesnt_Import_DuplicateEmail()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true });
_mocker.Setup<IPlexApi, Task<PlexFriends>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexFriends
{
User = new UserFriends[]
{
new UserFriends
{
Email = "dupe",
Id = "id",
Title = "title",
Username = "username"
}
}
});
_mocker.Setup<OmbiUserManager, Task<OmbiUser>>(x => x.FindByEmailAsync("dupe")).ReturnsAsync(new OmbiUser());
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Never);
}
[Test]
public async Task Import_Created_Plex_User()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings { ImportPlexAdmin = false, ImportPlexUsers = true, DefaultRoles = new List<string>
{
OmbiRoles.RequestMovie
}
});
_mocker.Setup<IPlexApi, Task<PlexFriends>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexFriends
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "id",
Username = "plex"
}
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x => x.UserName == "plex" && x.Email == "email" && x.ProviderUserId == "id" && x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "plex"), OmbiRoles.RequestMovie))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.CreateAsync(It.IsAny<OmbiUser>()), Times.Once);
}
[Test]
public async Task Import_Update_Plex_User()
{
_mocker.Setup<ISettingsService<UserManagementSettings>, Task<UserManagementSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new UserManagementSettings
{
ImportPlexAdmin = false,
ImportPlexUsers = true,
DefaultRoles = new List<string>
{
OmbiRoles.RequestMovie
}
});
_mocker.Setup<IPlexApi, Task<PlexFriends>>(x => x.GetUsers(It.IsAny<string>())).ReturnsAsync(new PlexFriends
{
User = new UserFriends[]
{
new UserFriends
{
Email = "email",
Id = "PLEX_ID",
Username = "user"
}
}
});
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.CreateAsync(It.Is<OmbiUser>(x => x.UserName == "plex" && x.Email == "email" && x.ProviderUserId == "id" && x.UserType == UserType.PlexUser)))
.ReturnsAsync(IdentityResult.Success);
_mocker.Setup<OmbiUserManager, Task<IdentityResult>>(x => x.AddToRoleAsync(It.Is<OmbiUser>(x => x.UserName == "plex"), OmbiRoles.RequestMovie))
.ReturnsAsync(IdentityResult.Success);
await _subject.Execute(null);
_mocker.Verify<OmbiUserManager>(x => x.UpdateAsync(It.Is<OmbiUser>(x => x.ProviderUserId == "PLEX_ID" && x.Email == "email" && x.UserName == "user")), Times.Once);
}
}
}

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Api.Plex;
using Ombi.Core.Authentication;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
@ -19,7 +20,7 @@ namespace Ombi.Schedule.Jobs.Plex
{
public class PlexUserImporter : IPlexUserImporter
{
public PlexUserImporter(IPlexApi api, UserManager<OmbiUser> um, ILogger<PlexUserImporter> log,
public PlexUserImporter(IPlexApi api, OmbiUserManager um, ILogger<PlexUserImporter> log,
ISettingsService<PlexSettings> plexSettings, ISettingsService<UserManagementSettings> ums, IHubContext<NotificationHub> hub)
{
_api = api;
@ -33,7 +34,7 @@ namespace Ombi.Schedule.Jobs.Plex
}
private readonly IPlexApi _api;
private readonly UserManager<OmbiUser> _userManager;
private readonly OmbiUserManager _userManager;
private readonly ILogger<PlexUserImporter> _log;
private readonly ISettingsService<PlexSettings> _plexSettings;
private readonly ISettingsService<UserManagementSettings> _userManagementSettings;
@ -43,17 +44,17 @@ namespace Ombi.Schedule.Jobs.Plex
public async Task Execute(IJobExecutionContext job)
{
var userManagementSettings = await _userManagementSettings.GetSettingsAsync();
if (!userManagementSettings.ImportPlexUsers)
if (!userManagementSettings.ImportPlexUsers && !userManagementSettings.ImportPlexAdmin)
{
return;
}
var settings = await _plexSettings.GetSettingsAsync();
if (!settings.Enable)
{
return;
}
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
.SendAsync(NotificationHub.NotificationEvent, "Plex User Importer Started");
var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.PlexUser).ToListAsync();
@ -64,92 +65,97 @@ namespace Ombi.Schedule.Jobs.Plex
continue;
}
await ImportAdmin(userManagementSettings, server, allUsers);
if (userManagementSettings.ImportPlexAdmin)
{
await ImportAdmin(userManagementSettings, server, allUsers);
}
if (userManagementSettings.ImportPlexUsers)
{
await ImportPlexUsers(userManagementSettings, allUsers, server);
}
}
var users = await _api.GetUsers(server.PlexAuthToken);
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
.SendAsync(NotificationHub.NotificationEvent, "Plex User Importer Finished");
}
foreach (var plexUser in users.User)
private async Task ImportPlexUsers(UserManagementSettings userManagementSettings, List<OmbiUser> allUsers, PlexServers server)
{
var users = await _api.GetUsers(server.PlexAuthToken);
foreach (var plexUser in users.User)
{
// Check if we should import this user
if (userManagementSettings.BannedPlexUserIds.Contains(plexUser.Id))
{
// Check if we should import this user
if (userManagementSettings.BannedPlexUserIds.Contains(plexUser.Id))
// Do not import these, they are not allowed into the country.
continue;
}
// Check if this Plex User already exists
// We are using the Plex USERNAME and Not the TITLE, the Title is for HOME USERS
var existingPlexUser = allUsers.FirstOrDefault(x => x.ProviderUserId == plexUser.Id);
if (existingPlexUser == null)
{
if (!plexUser.Username.HasValue())
{
// Do not import these, they are not allowed into the country.
_log.LogInformation("Could not create Plex user since the have no username, PlexUserId: {0}", plexUser.Id);
continue;
}
// Check if this Plex User already exists
// We are using the Plex USERNAME and Not the TITLE, the Title is for HOME USERS
var existingPlexUser = allUsers.FirstOrDefault(x => x.ProviderUserId == plexUser.Id);
if (existingPlexUser == null)
if ((plexUser.Email.HasValue()) && await _userManager.FindByEmailAsync(plexUser.Email) != null)
{
if (!plexUser.Username.HasValue())
{
_log.LogInformation("Could not create Plex user since the have no username, PlexUserId: {0}", plexUser.Id);
continue;
}
if ((plexUser.Email.HasValue()) && await _userManager.FindByEmailAsync(plexUser.Email) != null)
{
_log.LogWarning($"Cannot add user {plexUser.Username} because their email address is already in Ombi, skipping this user");
continue;
}
// Create this users
// We do not store a password against the user since they will authenticate via Plex
var newUser = new OmbiUser
{
UserType = UserType.PlexUser,
UserName = plexUser?.Username ?? plexUser.Id,
ProviderUserId = plexUser.Id,
Email = plexUser?.Email ?? string.Empty,
Alias = string.Empty,
MovieRequestLimit = userManagementSettings.MovieRequestLimit,
MovieRequestLimitType = userManagementSettings.MovieRequestLimitType,
EpisodeRequestLimit = userManagementSettings.EpisodeRequestLimit,
EpisodeRequestLimitType = userManagementSettings.EpisodeRequestLimitType,
MusicRequestLimit = userManagementSettings.MusicRequestLimit,
MusicRequestLimitType = userManagementSettings.MusicRequestLimitType,
StreamingCountry = userManagementSettings.DefaultStreamingCountry
};
_log.LogInformation("Creating Plex user {0}", newUser.UserName);
var result = await _userManager.CreateAsync(newUser);
if (!LogResult(result))
{
continue;
}
if (userManagementSettings.DefaultRoles.Any())
_log.LogWarning($"Cannot add user {plexUser.Username} because their email address is already in Ombi, skipping this user");
continue;
}
// Create this users
// We do not store a password against the user since they will authenticate via Plex
var newUser = new OmbiUser
{
UserType = UserType.PlexUser,
UserName = plexUser?.Username ?? plexUser.Id,
ProviderUserId = plexUser.Id,
Email = plexUser?.Email ?? string.Empty,
Alias = string.Empty,
MovieRequestLimit = userManagementSettings.MovieRequestLimit,
MovieRequestLimitType = userManagementSettings.MovieRequestLimitType,
EpisodeRequestLimit = userManagementSettings.EpisodeRequestLimit,
EpisodeRequestLimitType = userManagementSettings.EpisodeRequestLimitType,
MusicRequestLimit = userManagementSettings.MusicRequestLimit,
MusicRequestLimitType = userManagementSettings.MusicRequestLimitType,
StreamingCountry = userManagementSettings.DefaultStreamingCountry
};
_log.LogInformation("Creating Plex user {0}", newUser.UserName);
var result = await _userManager.CreateAsync(newUser);
if (!LogResult(result))
{
continue;
}
if (userManagementSettings.DefaultRoles.Any())
{
// Get the new user object to avoid any concurrency failures
var dbUser =
await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == newUser.UserName);
foreach (var defaultRole in userManagementSettings.DefaultRoles)
{
// Get the new user object to avoid any concurrency failures
var dbUser =
await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == newUser.UserName);
foreach (var defaultRole in userManagementSettings.DefaultRoles)
{
await _userManager.AddToRoleAsync(dbUser, defaultRole);
}
await _userManager.AddToRoleAsync(dbUser, defaultRole);
}
}
else
{
// Do we need to update this user?
existingPlexUser.Email = plexUser.Email;
existingPlexUser.UserName = plexUser.Username;
}
else
{
// Do we need to update this user?
existingPlexUser.Email = plexUser.Email;
existingPlexUser.UserName = plexUser.Username;
await _userManager.UpdateAsync(existingPlexUser);
}
await _userManager.UpdateAsync(existingPlexUser);
}
}
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
.SendAsync(NotificationHub.NotificationEvent, "Plex User Importer Finished");
}
private async Task ImportAdmin(UserManagementSettings settings, PlexServers server, List<OmbiUser> allUsers)
{
if (!settings.ImportPlexAdmin)
{
return;
}
var plexAdmin = (await _api.GetAccount(server.PlexAuthToken)).user;
// Check if the admin is already in the DB
@ -166,6 +172,14 @@ namespace Ombi.Schedule.Jobs.Plex
return;
}
// Ensure we don't have a user with the same username
var normalUsername = plexAdmin.username.ToUpperInvariant();
if (await _userManager.Users.AnyAsync(x => x.NormalizedUserName == normalUsername))
{
_log.LogWarning($"Cannot add user {plexAdmin.username} because their username is already in Ombi, skipping this user");
return;
}
var newUser = new OmbiUser
{
UserType = UserType.PlexUser,

Loading…
Cancel
Save