Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Registry.TokenService;
|
||||
using StellaOps.Registry.TokenService.Observability;
|
||||
|
||||
namespace StellaOps.Registry.TokenService.Tests;
|
||||
|
||||
public sealed class RegistryTokenIssuerTests : IDisposable
|
||||
{
|
||||
private readonly List<string> _tempFiles = new();
|
||||
|
||||
[Fact]
|
||||
public void IssueToken_GeneratesJwtWithAccessClaim()
|
||||
{
|
||||
var pemPath = CreatePemKey();
|
||||
var options = new RegistryTokenServiceOptions
|
||||
{
|
||||
Authority = new RegistryTokenServiceOptions.AuthorityOptions
|
||||
{
|
||||
Issuer = "https://authority.localhost",
|
||||
RequireHttpsMetadata = false,
|
||||
},
|
||||
Signing = new RegistryTokenServiceOptions.SigningOptions
|
||||
{
|
||||
Issuer = "https://registry.localhost/token",
|
||||
KeyPath = pemPath,
|
||||
Lifetime = TimeSpan.FromMinutes(5)
|
||||
},
|
||||
Registry = new RegistryTokenServiceOptions.RegistryOptions
|
||||
{
|
||||
Realm = "https://registry.localhost/v2/token"
|
||||
},
|
||||
Plans =
|
||||
{
|
||||
new RegistryTokenServiceOptions.PlanRule
|
||||
{
|
||||
Name = "community",
|
||||
Repositories =
|
||||
{
|
||||
new RegistryTokenServiceOptions.RepositoryRule
|
||||
{
|
||||
Pattern = "stella-ops/public/*",
|
||||
Actions = new [] { "pull" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
options.Validate();
|
||||
|
||||
var issuer = new RegistryTokenIssuer(
|
||||
Options.Create(options),
|
||||
new PlanRegistry(options),
|
||||
new RegistryTokenMetrics(),
|
||||
TimeProvider.System);
|
||||
|
||||
var principal = new ClaimsPrincipal(new ClaimsIdentity(new[]
|
||||
{
|
||||
new Claim("sub", "client-1"),
|
||||
new Claim("stellaops:plan", "community")
|
||||
}, "test"));
|
||||
|
||||
var accessRequests = new[]
|
||||
{
|
||||
new RegistryAccessRequest("repository", "stella-ops/public/base", new [] { "pull" })
|
||||
};
|
||||
|
||||
var response = issuer.IssueToken(principal, "registry.localhost", accessRequests);
|
||||
|
||||
Assert.NotEmpty(response.Token);
|
||||
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwt = handler.ReadJwtToken(response.Token);
|
||||
|
||||
Assert.Equal("https://registry.localhost/token", jwt.Issuer);
|
||||
Assert.True(jwt.Payload.TryGetValue("access", out var access));
|
||||
Assert.NotNull(access);
|
||||
}
|
||||
|
||||
private string CreatePemKey()
|
||||
{
|
||||
using var rsa = RSA.Create(2048);
|
||||
var builder = new StringWriter();
|
||||
builder.WriteLine("-----BEGIN PRIVATE KEY-----");
|
||||
builder.WriteLine(Convert.ToBase64String(rsa.ExportPkcs8PrivateKey(), Base64FormattingOptions.InsertLineBreaks));
|
||||
builder.WriteLine("-----END PRIVATE KEY-----");
|
||||
|
||||
var path = Path.GetTempFileName();
|
||||
File.WriteAllText(path, builder.ToString());
|
||||
_tempFiles.Add(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var file in _tempFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user