mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-07-13 09:03:15 +01:00
Fixups tested users controller
This commit is contained in:
@@ -71,7 +71,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
/// <param name="updatesConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing value of <see cref="updatesConfiguration"/></param>
|
||||
public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClient gitHubClient, IServerUpdater serverUpdater, IApplication application, IIOManager ioManager, ILogger<AdministrationController> logger, IOptions<UpdatesConfiguration> updatesConfigurationOptions) : base(databaseContext, authenticationContextFactory)
|
||||
public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClient gitHubClient, IServerUpdater serverUpdater, IApplication application, IIOManager ioManager, ILogger<AdministrationController> logger, IOptions<UpdatesConfiguration> updatesConfigurationOptions) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.gitHubClient = gitHubClient ?? throw new ArgumentNullException(nameof(gitHubClient));
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
protected Instance Instance { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="IAuthenticationContext.InstanceUser"/> permissions are required to access the <see cref="ApiController"/>
|
||||
/// </summary>
|
||||
readonly bool requireInstance;
|
||||
|
||||
/// <summary>
|
||||
/// Runs after a <see cref="Api.Models.Token"/> has been validated. Creates the <see cref="IAuthenticationContext"/> for the <see cref="ControllerBase.Request"/>
|
||||
/// </summary>
|
||||
@@ -81,6 +86,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
await authenticationContextFactory.CreateAuthenticationContext(userId, apiHeaders.InstanceId, context.HttpContext.RequestAborted).ConfigureAwait(false);
|
||||
|
||||
|
||||
var authenticationContext = authenticationContextFactory.CurrentAuthenticationContext;
|
||||
|
||||
var enumerator = Enum.GetValues(typeof(RightsType));
|
||||
@@ -103,19 +109,21 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The value of <see cref="DatabaseContext"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
public ApiController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory)
|
||||
/// <param name="requireInstance">The value of <see cref="requireInstance"/></param>
|
||||
public ApiController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, bool requireInstance)
|
||||
{
|
||||
DatabaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
|
||||
if (authenticationContextFactory == null)
|
||||
throw new ArgumentNullException(nameof(authenticationContextFactory));
|
||||
AuthenticationContext = authenticationContextFactory.CurrentAuthenticationContext;
|
||||
Instance = AuthenticationContext?.InstanceUser?.Instance;
|
||||
this.requireInstance = requireInstance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
if (AuthenticationContext == null)
|
||||
if (requireInstance && AuthenticationContext.InstanceUser == null)
|
||||
{
|
||||
//accessing an instance they don't have access to
|
||||
await Forbid().ExecuteResultAsync(context).ConfigureAwait(false);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public ChatController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory)
|
||||
public ChatController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory, true)
|
||||
{
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public ConfigurationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, ILogger<ConfigurationController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
public ConfigurationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, ILogger<ConfigurationController> logger) : base(databaseContext, authenticationContextFactory, true)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public DreamDaemonController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory)
|
||||
public DreamDaemonController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory, true)
|
||||
{
|
||||
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public DreamMakerController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory)
|
||||
public DreamMakerController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory, true)
|
||||
{
|
||||
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
readonly IApplication application;
|
||||
/// <summary>
|
||||
/// The <see cref="IAuthenticationContextFactory"/> for the <see cref="HomeController"/>
|
||||
/// The <see cref="IIdentityCache"/> for the <see cref="HomeController"/>
|
||||
/// </summary>
|
||||
readonly IAuthenticationContextFactory authenticationContextFactory;
|
||||
readonly IIdentityCache identityCache;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="HomeController"/>
|
||||
@@ -48,14 +48,14 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/></param>
|
||||
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
|
||||
/// <param name="application">The value of <see cref="application"/></param>
|
||||
public HomeController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ITokenFactory tokenFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, IApplication application) : base(databaseContext, authenticationContextFactory)
|
||||
/// <param name="identityCache">The value of <see cref="identityCache"/</param>
|
||||
public HomeController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ITokenFactory tokenFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, IApplication application, IIdentityCache identityCache) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
|
||||
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
|
||||
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
|
||||
this.application = application ?? throw new ArgumentNullException(nameof(application));
|
||||
//base checks not null
|
||||
this.authenticationContextFactory = authenticationContextFactory;
|
||||
this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
else
|
||||
try
|
||||
{
|
||||
identity = await systemIdentityFactory.CreateSystemIdentity(user.Name, ApiHeaders.Password, cancellationToken).ConfigureAwait(false);
|
||||
identity = await systemIdentityFactory.CreateSystemIdentity(ApiHeaders.Username, ApiHeaders.Password, cancellationToken).ConfigureAwait(false);
|
||||
if (identity == null || identity.Uid != user.SystemIdentifier)
|
||||
return Unauthorized();
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
var token = tokenFactory.CreateToken(user, out var expiry);
|
||||
if (identity != null)
|
||||
authenticationContextFactory.CacheSystemIdentity(user, identity, expiry.AddSeconds(10)); //expire the identity slightly after the auth token in case of lag
|
||||
identityCache.CacheSystemIdentity(user, identity, expiry.AddSeconds(10)); //expire the identity slightly after the auth token in case of lag
|
||||
return Json(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
|
||||
public InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager) : base(databaseContext, authenticationContextFactory)
|
||||
public InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public InstanceUserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger<InstanceUserController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
public InstanceUserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger<InstanceUserController> logger) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public InteropController(IInstanceManager instanceManager, IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory) : base(databaseContext, authenticationContextFactory)
|
||||
public InteropController(IInstanceManager instanceManager, IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.instanceManager = instanceManager;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
|
||||
public JobController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager) : base(databaseContext, authenticationContextFactory)
|
||||
public JobController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
public ModelController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory) : base(databaseContext, authenticationContextFactory) { }
|
||||
/// <param name="requireInstance">If the <see cref="ModelController{TModel}"/> requires an <see cref="IAuthenticationContext.InstanceUser"/></param>
|
||||
public ModelController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, bool requireInstance) : base(databaseContext, authenticationContextFactory, requireInstance) { }
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to create a <paramref name="model"/>
|
||||
@@ -49,7 +50,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="id">The ID of the model to get</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation</returns>
|
||||
[HttpGet("/{id}")]
|
||||
[HttpGet("{id}")]
|
||||
public virtual Task<IActionResult> GetId(long id, CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
|
||||
|
||||
/// <summary>
|
||||
@@ -75,7 +76,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation</returns>
|
||||
[HttpGet("/List")]
|
||||
[HttpGet("List")]
|
||||
public virtual Task<IActionResult> List(CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <param name="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/></param>
|
||||
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public UserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, ILogger<UserController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
public UserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, ILogger<UserController> logger) : base(databaseContext, authenticationContextFactory, false)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
|
||||
|
||||
@@ -148,9 +148,9 @@ namespace Tgstation.Server.Host.Core
|
||||
default:
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid {0}!", nameof(DatabaseType)));
|
||||
}
|
||||
|
||||
//very important this remains a singleton
|
||||
services.AddSingleton<IAuthenticationContextFactory, AuthenticationContextFactory>();
|
||||
|
||||
services.AddScoped<IAuthenticationContextFactory, AuthenticationContextFactory>();
|
||||
services.AddSingleton<IIdentityCache, IdentityCache>();
|
||||
|
||||
services.AddSingleton<ICryptographySuite, CryptographySuite>();
|
||||
services.AddSingleton<IDatabaseSeeder, DatabaseSeeder>();
|
||||
|
||||
@@ -10,7 +10,7 @@ using Tgstation.Server.Host.Models;
|
||||
namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class AuthenticationContextFactory : IAuthenticationContextFactory, IDisposable
|
||||
sealed class AuthenticationContextFactory : IAuthenticationContextFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IAuthenticationContext CurrentAuthenticationContext { get; private set; }
|
||||
@@ -21,53 +21,22 @@ namespace Tgstation.Server.Host.Security
|
||||
readonly ISystemIdentityFactory systemIdentityFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IDatabaseContextFactory"/> for the <see cref="AuthenticationContextFactory"/>
|
||||
/// The <see cref="IDatabaseContext"/> for the <see cref="AuthenticationContextFactory"/>
|
||||
/// </summary>
|
||||
readonly IDatabaseContextFactory databaseContextFactory;
|
||||
readonly IDatabaseContext databaseContext;
|
||||
|
||||
/// <summary>
|
||||
/// Map of <see cref="Api.Models.Internal.User.Id"/>s to <see cref="IdentityCache"/>s for that user
|
||||
/// </summary>
|
||||
readonly Dictionary<long, IdentityCache> identityCache;
|
||||
readonly IIdentityCache identityCache;
|
||||
|
||||
/// <summary>
|
||||
/// Construct an <see cref="AuthenticationContextFactory"/>
|
||||
/// </summary>
|
||||
/// <param name="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/></param>
|
||||
/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param>
|
||||
public AuthenticationContextFactory(ISystemIdentityFactory systemIdentityFactory, IDatabaseContextFactory databaseContextFactory)
|
||||
public AuthenticationContextFactory(ISystemIdentityFactory systemIdentityFactory, IDatabaseContext databaseContext, IIdentityCache identityCache)
|
||||
{
|
||||
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
|
||||
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
|
||||
|
||||
identityCache = new Dictionary<long, IdentityCache>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var I in identityCache)
|
||||
I.Value.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry)
|
||||
{
|
||||
if (user == null)
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
if (systemIdentity == null)
|
||||
throw new ArgumentNullException(nameof(systemIdentity));
|
||||
lock (identityCache)
|
||||
{
|
||||
if (identityCache.TryGetValue(user.Id, out var identCache))
|
||||
identCache.Dispose(); //also clears it out
|
||||
identCache = new IdentityCache(systemIdentity.Clone(), expiry, () =>
|
||||
{
|
||||
lock (identityCache)
|
||||
identityCache.Remove(user.Id);
|
||||
});
|
||||
identityCache.Add(user.Id, identCache);
|
||||
}
|
||||
this.databaseContext = databaseContext?? throw new ArgumentNullException(nameof(databaseContext));
|
||||
this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -76,32 +45,24 @@ namespace Tgstation.Server.Host.Security
|
||||
if (CurrentAuthenticationContext != null)
|
||||
throw new InvalidOperationException("Authentication context has already been loaded");
|
||||
|
||||
User user = null;
|
||||
await databaseContextFactory.UseContext(async db =>
|
||||
{
|
||||
var userQuery = db.Users.Where(x => x.Id == userId);
|
||||
var userQuery = databaseContext.Users.Where(x => x.Id == userId);
|
||||
|
||||
if (instanceId.HasValue)
|
||||
userQuery = userQuery.Include(x => x.InstanceUsers.Where(y => y.Id == instanceId));
|
||||
if (instanceId.HasValue)
|
||||
userQuery = userQuery.Include(x => x.InstanceUsers.Where(y => y.Id == instanceId));
|
||||
|
||||
user = await userQuery.Include(x => x.InstanceUsers).FirstAsync(cancellationToken).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
var user = await userQuery.Include(x => x.InstanceUsers).FirstAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
InstanceUser instanceUser = null;
|
||||
if (instanceId.HasValue)
|
||||
instanceUser = user.InstanceUsers.Where(x => x.InstanceId == instanceId).FirstOrDefault();
|
||||
|
||||
if (instanceUser == default)
|
||||
return;
|
||||
|
||||
ISystemIdentity systemIdentity;
|
||||
if (user.SystemIdentifier != null)
|
||||
lock (identityCache)
|
||||
{
|
||||
if (!identityCache.TryGetValue(userId, out var identCache))
|
||||
throw new InvalidOperationException("Cached system identity has expired!");
|
||||
systemIdentity = identCache.SystemIdentity.Clone();
|
||||
}
|
||||
{
|
||||
systemIdentity = identityCache.LoadCachedIdentity(user);
|
||||
if (systemIdentity == null)
|
||||
throw new InvalidOperationException("Cached system identity has expired!");
|
||||
}
|
||||
else
|
||||
systemIdentity = null;
|
||||
|
||||
|
||||
@@ -15,14 +15,6 @@ namespace Tgstation.Server.Host.Security
|
||||
/// </summary>
|
||||
IAuthenticationContext CurrentAuthenticationContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Keep a <paramref name="user"/>'s <paramref name="systemIdentity"/> alive until an <paramref name="expiry"/> time
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="User"/> the <paramref name="systemIdentity"/> belongs to</param>
|
||||
/// <param name="systemIdentity">The <see cref="ISystemIdentity"/> to cache</param>
|
||||
/// <param name="expiry">When the <paramref name="systemIdentity"/> should expire</param>
|
||||
void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry);
|
||||
|
||||
/// <summary>
|
||||
/// Create an <see cref="IAuthenticationContext"/> to populate <see cref="CurrentAuthenticationContext"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
public interface IIdentityCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Keep a <paramref name="user"/>'s <paramref name="systemIdentity"/> alive until an <paramref name="expiry"/> time
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="User"/> the <paramref name="systemIdentity"/> belongs to</param>
|
||||
/// <param name="systemIdentity">The <see cref="ISystemIdentity"/> to cache</param>
|
||||
/// <param name="expiry">When the <paramref name="systemIdentity"/> should expire</param>
|
||||
void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry);
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to load a cached <see cref="ISystemIdentity"/>
|
||||
/// </summary>
|
||||
/// <param name="user">The <see cref="User"/> the <see cref="ISystemIdentity"/> belongs to</param>
|
||||
/// <returns>The cached <see cref="ISystemIdentity"/> or <see langword="null"/> if it doesn't exist or expired</returns>
|
||||
ISystemIdentity LoadCachedIdentity(User user);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,57 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// For keeping a specific <see cref="ISystemIdentity"/> alive for a period of time
|
||||
/// </summary>
|
||||
sealed class IdentityCache : IDisposable
|
||||
/// <inheritdoc />
|
||||
sealed class IdentityCache : IIdentityCache, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ISystemIdentity"/> the <see cref="IdentityCache"/> manages
|
||||
/// </summary>
|
||||
public ISystemIdentity SystemIdentity { get; }
|
||||
readonly Dictionary<long, IdentityCacheObject> cachedIdentities;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="cancellationTokenSource"/> for the <see cref="IdentityCache"/>
|
||||
/// </summary>
|
||||
readonly CancellationTokenSource cancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> to clean up <see cref="SystemIdentity"/>
|
||||
/// </summary>
|
||||
readonly Task task;
|
||||
|
||||
/// <summary>
|
||||
/// Construct an <see cref="IdentityCache"/>
|
||||
/// </summary>
|
||||
/// <param name="systemIdentity">The value of <see cref="SystemIdentity"/></param>
|
||||
/// <param name="expiry">The <see cref="DateTimeOffset"/></param>
|
||||
/// <param name="onExpiry">An optional <see cref="Action"/> to take on expiry</param>
|
||||
public IdentityCache(ISystemIdentity systemIdentity, DateTimeOffset expiry, Action onExpiry)
|
||||
public IdentityCache()
|
||||
{
|
||||
SystemIdentity = systemIdentity ?? throw new ArgumentNullException(nameof(systemIdentity));
|
||||
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
async Task DisposeOnExipiry(CancellationToken cancellationToken)
|
||||
{
|
||||
using (SystemIdentity)
|
||||
try
|
||||
{
|
||||
await Task.Delay(expiry - DateTimeOffset.Now, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
onExpiry?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
task = DisposeOnExipiry(cancellationTokenSource.Token);
|
||||
cachedIdentities = new Dictionary<long, IdentityCacheObject>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
task.Wait();
|
||||
cancellationTokenSource.Dispose();
|
||||
foreach (var I in cachedIdentities)
|
||||
I.Value.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateTimeOffset expiry)
|
||||
{
|
||||
if (user == null)
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
if (systemIdentity == null)
|
||||
throw new ArgumentNullException(nameof(systemIdentity));
|
||||
lock (cachedIdentities)
|
||||
{
|
||||
if (cachedIdentities.TryGetValue(user.Id, out var identCache))
|
||||
identCache.Dispose(); //also clears it out
|
||||
identCache = new IdentityCacheObject(systemIdentity.Clone(), () =>
|
||||
{
|
||||
lock (cachedIdentities)
|
||||
cachedIdentities.Remove(user.Id);
|
||||
}, expiry);
|
||||
cachedIdentities.Add(user.Id, identCache);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISystemIdentity LoadCachedIdentity(User user)
|
||||
{
|
||||
if (user == null)
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
lock (cachedIdentities)
|
||||
{
|
||||
if (cachedIdentities.TryGetValue(user.Id, out var identity))
|
||||
return identity.SystemIdentity;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// For keeping a specific <see cref="ISystemIdentity"/> alive for a period of time
|
||||
/// </summary>
|
||||
sealed class IdentityCacheObject : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ISystemIdentity"/> the <see cref="IdentityCache"/> manages
|
||||
/// </summary>
|
||||
public ISystemIdentity SystemIdentity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="cancellationTokenSource"/> for the <see cref="IdentityCache"/>
|
||||
/// </summary>
|
||||
readonly CancellationTokenSource cancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> to clean up <see cref="SystemIdentity"/>
|
||||
/// </summary>
|
||||
readonly Task task;
|
||||
|
||||
/// <summary>
|
||||
/// Construct an <see cref="IdentityCache"/>
|
||||
/// </summary>
|
||||
/// <param name="systemIdentity">The value of <see cref="SystemIdentity"/></param>
|
||||
/// <param name="onExpiry">The <see cref="Action"/> to take on expiry</param>
|
||||
/// <param name="expiry">The <see cref="DateTimeOffset"/></param>
|
||||
public IdentityCacheObject(ISystemIdentity systemIdentity, Action onExpiry, DateTimeOffset expiry)
|
||||
{
|
||||
SystemIdentity = systemIdentity ?? throw new ArgumentNullException(nameof(systemIdentity));
|
||||
if (onExpiry == null)
|
||||
throw new ArgumentNullException(nameof(onExpiry));
|
||||
var now = DateTimeOffset.Now;
|
||||
if (expiry < now)
|
||||
throw new ArgumentOutOfRangeException(nameof(expiry), expiry, "expiry must be greater than DateTimeOffset.Now!");
|
||||
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
async Task DisposeOnExipiry(CancellationToken cancellationToken)
|
||||
{
|
||||
using (SystemIdentity)
|
||||
try
|
||||
{
|
||||
await Task.Delay(expiry - now, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
onExpiry();
|
||||
}
|
||||
}
|
||||
|
||||
task = DisposeOnExipiry(cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
task.Wait();
|
||||
cancellationTokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,13 @@ namespace Tgstation.Server.Host.Security
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => identity.Dispose();
|
||||
public void Dispose()
|
||||
{
|
||||
if (identity != null)
|
||||
identity.Dispose();
|
||||
else
|
||||
userPrincipal.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Uid => (userPrincipal?.Sid ?? identity.User).ToString();
|
||||
|
||||
@@ -24,14 +24,28 @@ namespace Tgstation.Server.Host.Security
|
||||
if (user.SystemIdentifier == null)
|
||||
throw new InvalidOperationException("User's SystemIdentifier must not be null!");
|
||||
|
||||
PrincipalContext pc = null;
|
||||
UserPrincipal principal = null;
|
||||
//machine logon first cause it's faster
|
||||
using (var pc = new PrincipalContext(ContextType.Machine, Environment.UserDomainName))
|
||||
try
|
||||
{
|
||||
pc = new PrincipalContext(ContextType.Machine, Environment.UserDomainName);
|
||||
principal = UserPrincipal.FindByIdentity(pc, user.SystemIdentifier);
|
||||
|
||||
if(principal == null)
|
||||
using (var pc = new PrincipalContext(ContextType.Domain, Environment.UserDomainName))
|
||||
if (principal == null)
|
||||
{
|
||||
pc.Dispose();
|
||||
pc = new PrincipalContext(ContextType.Domain, Environment.UserDomainName);
|
||||
principal = UserPrincipal.FindByIdentity(pc, user.SystemIdentifier);
|
||||
if (principal == null)
|
||||
pc.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
pc?.Dispose();
|
||||
throw;
|
||||
}
|
||||
|
||||
if (principal == null)
|
||||
return null;
|
||||
@@ -42,6 +56,10 @@ namespace Tgstation.Server.Host.Security
|
||||
/// <inheritdoc />
|
||||
public Task<ISystemIdentity> CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (username == null)
|
||||
throw new ArgumentNullException(nameof(username));
|
||||
if (password == null)
|
||||
throw new ArgumentNullException(nameof(password));
|
||||
var splits = username.Split('\\');
|
||||
|
||||
var res = NativeMethods.LogonUser(splits.Length > 1 ? splits[1] : splits[0], splits.Length > 1 ? splits[0] : null, password, 3 /*LOGON32_LOGON_NETWORK*/, 0 /*LOGON32_PROVIDER_DEFAULT*/, out var token);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "f0940866-29fd-4ea3-8682-7e30df5b08c9",
|
||||
"_postman_id": "e62d1230-5b76-45e2-9fb6-002e260daa2a",
|
||||
"name": "TGS",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Administration",
|
||||
"description": "",
|
||||
"description": null,
|
||||
"item": [
|
||||
{
|
||||
"name": "Get Update Versions",
|
||||
@@ -27,7 +27,10 @@
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
}
|
||||
],
|
||||
"body": {},
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/Administration",
|
||||
"host": [
|
||||
@@ -98,7 +101,10 @@
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
}
|
||||
],
|
||||
"body": {},
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/Administration",
|
||||
"host": [
|
||||
@@ -136,6 +142,475 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Users",
|
||||
"description": "",
|
||||
"item": [
|
||||
{
|
||||
"name": "Read Current User",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
}
|
||||
],
|
||||
"body": {},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Read All Users",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
}
|
||||
],
|
||||
"body": {},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User/List",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User",
|
||||
"List"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create User Bob Pass (asdf)",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 1,\n \"enabled\": true,\n \"password\": \"asdf\",\n \"name\": \"Bob\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Try To Add A SysId To User ID 2",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 2,\n \"systemIdentifier\": \"fake\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Enable User ID 3",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 3,\n \"enabled\": true\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Try To Add A Password To User ID",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 3,\n \"password\": \"fake\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Change User ID 2's password and name to bOb and fdsa",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 2,\n \"password\": \"fdsa\",\n \"name\": \"bOb\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Change User ID 2's name to Bob2",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 2,\n \"name\": \"Bob2\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Give User ID 3 rights",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"id\": 3,\n \"administrationRights\": -1,\n\t\"instanceManagerRights\": -1,\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create system user Cyberboss",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"systemIdentifier\": \"Cyberboss\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000/User",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"User"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Login bob (asdf)",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "noauth"
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Password asdf"
|
||||
},
|
||||
{
|
||||
"key": "Username",
|
||||
"value": "bob"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000"
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Login cyberboss",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "noauth"
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Postman/1.0"
|
||||
},
|
||||
{
|
||||
"key": "User-Agent",
|
||||
"value": "Tgstation.Server.Api/4.0.0.0"
|
||||
},
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Password no"
|
||||
},
|
||||
{
|
||||
"key": "Username",
|
||||
"value": "cyberboss"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "5000"
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Login Admin Default",
|
||||
"request": {
|
||||
@@ -165,7 +640,10 @@
|
||||
"value": "admin"
|
||||
}
|
||||
],
|
||||
"body": {},
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "localhost:5000",
|
||||
"host": [
|
||||
@@ -200,7 +678,6 @@
|
||||
{
|
||||
"key": "name",
|
||||
"value": "asdfasdf",
|
||||
"description": "",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
@@ -221,7 +698,7 @@
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoiMTUzMjU0MjgwMyIsIm5iZiI6IjE1MzI1MzkyMDMiLCJpc3MiOiJUZ3N0YXRpb24uU2VydmVyLkhvc3QiLCJhdWQiOiJUZ3N0YXRpb24uU2VydmVyLkFwaSJ9.f-y5xQ-JbZklD7iMeztZhLGfXBWnSxxlYtzl3TXDt5g",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoiMTUzMjY1ODI0OSIsIm5iZiI6IjE1MzI2NTQ2NDkiLCJpc3MiOiJUZ3N0YXRpb24uU2VydmVyLkhvc3QiLCJhdWQiOiJUZ3N0YXRpb24uU2VydmVyLkFwaSJ9.nfVqGC501-l1hkXCn6NsLj-rLFBVU65feHKLxXV3X8c",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user