Testing the push method (TODO coherence between return code a physical result)

main
Paul Schneider 6 months ago
parent e69462999e
commit 89e1b5a235
10 changed files with 191 additions and 78 deletions

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace isn
{
public interface IDataProtector
{
string Protect(string data);
string UnProtect(string data);
}
public class DefaultDataProtector : IDataProtector
{
private byte delta = 145;
public DefaultDataProtector()
{
}
public string Protect(string data)
{
List<Byte> protd = new List<byte>();
StringBuilder sb = new StringBuilder();
foreach (byte c in Encoding.UTF8.GetBytes(data))
{
protd.Add((byte) (c ^ delta));
}
return System.Convert.ToBase64String(protd.ToArray());
}
public string UnProtect(string data)
{
if (data==null) return null;
StringBuilder sb = new StringBuilder();
List<byte> unps = new List<byte>();
foreach (byte c in System.Convert.FromBase64CharArray(data.ToCharArray(),0,data.Length))
{
unps.Add((byte) (c ^ delta));
}
return Encoding.UTF8.GetString(unps.ToArray());
}
}
}

@ -1,13 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
namespace isn
{
public class SourceSettings
{
private RSA rsa;
/// <summary>
/// Protected API Key
/// </summary>
@ -22,19 +25,25 @@ namespace isn
/// <value></value>
public string Alias { get; set; }
public SourceSettings()
{
rsa = RSA.Create();
}
public string GetClearApiKey()
{
if (!string.IsNullOrEmpty(ApiKey)) return ApiKey;
return ProtectedApiKey = Protector.UnProtect(ApiKey);
return
Encoding.UTF8.GetString(
rsa.Decrypt(Encoding.UTF8.GetBytes(ProtectedApiKey),
RSAEncryptionPadding.Pkcs1));
}
public void SetApiKey(string key)
{
ApiKey = key;
ProtectedApiKey = Protector.Protect(key);
ApiKey = Encoding.UTF8.GetString(
rsa.Encrypt(Encoding.UTF8.GetBytes(key),
RSAEncryptionPadding.Pkcs1));
}
public static IDataProtector Protector { get; private set ; } = new DefaultDataProtector();
}
public class Settings

@ -13,6 +13,7 @@ using Microsoft.Extensions.Options;
using isnd.Data;
using isnd.Entities;
using isnd.Data.ApiKeys;
using isnd.Interfaces;
namespace isnd.Controllers
@ -23,17 +24,20 @@ namespace isnd.Controllers
private readonly ApplicationDbContext dbContext;
private readonly IsndSettings isndSettings;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IApiKeyProvider apiKeyProvider;
private readonly IDataProtector protector;
public ApiKeysController(ApplicationDbContext dbContext,
IOptions<IsndSettings> isndSettingsOptions,
IDataProtectionProvider provider,
UserManager<ApplicationUser> userManager)
UserManager<ApplicationUser> userManager,
IApiKeyProvider apiKeyProvider
)
{
this.dbContext = dbContext;
this.isndSettings = isndSettingsOptions.Value;
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
_userManager = userManager;
this.apiKeyProvider = apiKeyProvider;
}
[HttpGet]
@ -57,17 +61,17 @@ namespace isnd.Controllers
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = GetUserKeys();
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = apiKeyProvider.GetUserKeys(User.Identity.Name);
if (userKeys.Count() >= isndSettings.MaxUserKeyCount)
{
ModelState.AddModelError(null, "Maximum key count reached");
return View();
}
ApiKey newKey = new ApiKey { UserId = userid, Name = model.Name,
CreationDate = DateTimeOffset.Now.ToUniversalTime() };
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
model.UserId = userId;
ApiKey newKey = await apiKeyProvider.CreateApiKeyAsync(model);
return View("Details", new DetailModel { Name = newKey.Name,
ProtectedValue = protector.Protect(newKey.Id),
ApiKey = newKey });
@ -79,7 +83,6 @@ namespace isnd.Controllers
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
return View(new DeleteModel { ApiKey = key });
}
[HttpPost]

@ -9,6 +9,8 @@ namespace isnd.Data.ApiKeys
[Display(Name = "Key Name")]
public string Name { get; set; }
public string UserId { get; set; }
public int ValidityPeriodInDays { get; set; }
}
}

@ -0,0 +1,13 @@
using System.Linq;
using System.Threading.Tasks;
using isnd.Data.ApiKeys;
namespace isnd.Interfaces
{
public interface IApiKeyProvider
{
Task<ApiKey> CreateApiKeyAsync(CreateModel model);
IQueryable<ApiKey> GetUserKeys(string identityName);
}
}

@ -0,0 +1,48 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using isnd.Data;
using isnd.Data.ApiKeys;
using isnd.Entities;
using isnd.Interfaces;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace isnd;
public class ApiKeyProvider : IApiKeyProvider
{
private readonly IsndSettings isndSettings;
private readonly IDataProtector protector;
private readonly ApplicationDbContext dbContext;
public ApiKeyProvider(
ApplicationDbContext dbContext,
IDataProtectionProvider dataProtectionProvider, IOptions<IsndSettings> isndSettingsOptions)
{
this.dbContext = dbContext;
isndSettings = isndSettingsOptions.Value;
protector = dataProtectionProvider.CreateProtector(isndSettings.ProtectionTitle);
}
public async Task<ApiKey> CreateApiKeyAsync(CreateModel model)
{
var newKey = new ApiKey{
UserId = model.UserId,
CreationDate = DateTime.Now,
Name = model.Name,
ValidityPeriodInDays = model.ValidityPeriodInDays
};
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
return newKey;
}
public IQueryable<ApiKey> GetUserKeys(string identityName)
{
return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == identityName);
}
}

@ -19,6 +19,7 @@ using System;
using Microsoft.OpenApi.Models;
using System.IO;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.DataProtection;
namespace isnd
{
@ -76,9 +77,9 @@ namespace isnd
.AddTransient<IMailer, EmailSender>()
.AddTransient<IEmailSender, EmailSender>()
.AddTransient<IPackageManager, PackageManager>()
.AddTransient<IApiKeyProvider, ApiKeyProvider>()
.AddSingleton<IAuthorizationHandler, ValidApiKeyRequirementHandler>();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{

@ -12,20 +12,6 @@ namespace isn.tests
{
public class Tests
{
[Fact]
public void HaveADefaultDataProtector()
{
string pass = "a lame and big pass";
isn.IDataProtector _protector = new isn.DefaultDataProtector();
string protectedPassword = _protector.Protect(pass);
string unprotectedPassword = _protector.UnProtect(protectedPassword);
Console.WriteLine(protectedPassword);
Assert.Equal(pass, unprotectedPassword);
Assert.True(protectedPassword != null);
Assert.True(protectedPassword.Length > 0);
}
[Fact]
public async Task TestHttpClient()
{

@ -114,7 +114,7 @@ namespace isnd.host.tests
}
public string SPIIndexURI
{
get => server.Addresses.First() + "/v3/index";
get => server.Addresses.First() + "/v3/index.json";
}
[Fact]
@ -170,5 +170,40 @@ namespace isnd.host.tests
}
}
[Fact]
public async Task TestPackagePush()
{
var logger = new TestLogger();
SourceRepository repository = Repository.Factory.GetCoreV3(SPIIndexURI);
PackageUpdateResource pushRes = await repository.GetResourceAsync<PackageUpdateResource>();
SymbolPackageUpdateResourceV3 symbolPackageResource = await repository.GetResourceAsync<SymbolPackageUpdateResourceV3>();
await pushRes.Push(new List<string>{ "../../../../../src/isnd/bin/Release/isnd.1.1.4.nupkg" }, null,
5000, false, GetApiKey, GetSymbolsApiKey, false, false, symbolPackageResource, logger);
}
private string GetSymbolsApiKey(string apiUrl)
{
return GetApiKey(apiUrl);
}
private string GetApiKey(string apiUrl)
{
return server.ProtectedTestingApiKey;
}
}
internal class TestLogger : NuGet.Common.LoggerBase
{
public override void Log(ILogMessage message)
{
Console.WriteLine(message.Message);
}
public async override Task LogAsync(ILogMessage message)
{
Log(message);
}
}
}

@ -1,10 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using isn;
using isnd.Data;
using isnd.Entities;
using isnd.Interfaces;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Identity;
using Microsoft.CodeAnalysis.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;
namespace isnd.tests
@ -15,6 +25,13 @@ namespace isnd.tests
{
public IWebHost Host { get; private set;}
public List<string> Addresses { get; private set; } = new List<string>();
public Microsoft.Extensions.Logging.ILogger Logger { get; internal set; }
private IsndSettings siteSettings;
public IDataProtector DataProtector { get; private set; }
public string ProtectedTestingApiKey { get; internal set; }
public ApplicationUser TestingUser { get; private set; }
public WebServerFixture()
{
@ -40,14 +57,60 @@ namespace isnd.tests
config.AddJsonFile("appsettings.Development.json", false);
});
Host = webhostBuilder.Build();
var logFactory = Host.Services.GetRequiredService<ILoggerFactory>();
Logger = logFactory.CreateLogger<WebServerFixture>();
Host.Start(); //Starts listening on the configured addresses.
var server = Host.Services.GetRequiredService<IServer>();
var addressFeature = server.Features.Get<IServerAddressesFeature>();
foreach (var address in addressFeature.Addresses)
{
Addresses.Add(address);
}
siteSettings = Host.Services.GetRequiredService<IOptions<IsndSettings>>().Value;
DataProtector = Host.Services.GetRequiredService<IDataProtectionProvider>()
.CreateProtector(siteSettings.ProtectionTitle);
var dbContext = Host.Services.GetRequiredService<ApplicationDbContext>();
string testingUserName = "Tester";
TestingUser = dbContext.Users.FirstOrDefault(u=>u.UserName==testingUserName);
if (TestingUser==null)
{
var userManager = Host.Services.GetRequiredService<UserManager<ApplicationUser>>();
TestingUser = new ApplicationUser
{
UserName=testingUserName
};
var result = userManager.CreateAsync(TestingUser).Result;
Assert.True(result.Succeeded);
TestingUser = dbContext.Users.FirstOrDefault(u=>u.UserName==testingUserName);
}
var testKey = dbContext.ApiKeys.FirstOrDefault(k=>k.UserId==TestingUser.Id);
if (testKey == null)
{
var keyProvider = Host.Services.GetService<IApiKeyProvider>();
var apiKeyQuery = new Data.ApiKeys.CreateModel
{
Name = "Testing Key",
UserId = TestingUser.Id,
ValidityPeriodInDays = 1
};
testKey = keyProvider.CreateApiKeyAsync(apiKeyQuery).Result;
}
ProtectedTestingApiKey = DataProtector.Protect(testKey.Id);
}
}
}
Loading…