节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
4.88 KiB
Stardust
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using NewLife;
using NewLife.Remoting;
using NewLife.Remoting.Models;
using Stardust.Data.Deployment;
using Stardust.Data.Nodes;
using Stardust.Server;
using Xunit;

namespace ServerTest.Controllers;

/// <summary>Deploy/UploadBuildFile 上传授权安全测试。验证任意已注册节点不能向无关部署集投递构建产物(安全扫描 V-4)</summary>
public class DeployUploadSecurityTests
{
    private readonly TestServer _server;

    public DeployUploadSecurityTests()
    {
#pragma warning disable CS0618, ASPDEPR008
        _server = new TestServer(WebHost.CreateDefaultBuilder()
            .UseStartup<Startup>());
#pragma warning restore CS0618, ASPDEPR008
    }

    private async Task<(String token, Node node)> LoginNodeAsync()
    {
        var client = _server.CreateClient();
        var rs = await client.PostAsync<LoginResponse>("node/login", new
        {
            code = "",
            node = new
            {
                MachineName = "test_upload_sec",
                macs = "xxyyzz" + Guid.NewGuid().ToString("N")[..6],
            },
        });
        Assert.NotNull(rs?.Token);
        var node = Node.FindByCode(rs?.Code);
        Assert.NotNull(node);
        return (rs.Token, node);
    }

    private static MultipartFormDataContent BuildContent()
    {
        var content = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(new Byte[] { 0x50, 0x4B, 0x05, 0x06, 1, 2, 3, 4 });
        fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
        content.Add(fileContent, "file", "test.zip");
        return content;
    }

    private async Task<String> UploadAsync(String token, String deployName, String version)
    {
        var client = _server.CreateClient();
        client.DefaultRequestHeaders.Add("X-Token", token);
        var response = await client.PostAsync($"/Deploy/UploadBuildFile?deployName={Uri.EscapeDataString(deployName)}&version={Uri.EscapeDataString(version)}", BuildContent());
        return await response.Content.ReadAsStringAsync();
    }

    private static AppDeploy NewDeploy(String name)
    {
        var app = new AppDeploy { Name = name, Enable = true };
        app.Insert();
        return app;
    }

    [Fact(DisplayName = "未关联发布集的任意节点上传构建产物被拒绝")]
    public async Task UnrelatedNode_Upload_Rejected()
    {
        var deployName = "v4u_" + Guid.NewGuid().ToString("N")[..8];
        var app = NewDeploy(deployName);
        try
        {
            var (token, node) = await LoginNodeAsync();

            var body = await UploadAsync(token, deployName, "v1.0.0");

            Assert.Contains("\"code\"", body);
            Assert.Contains("禁止上传", body);
        }
        finally
        {
            app.Delete();
        }
    }

    [Fact(DisplayName = "编译节点上传构建产物成功(回归保护)")]
    public async Task BuildNode_Upload_Ok()
    {
        var deployName = "v4b_" + Guid.NewGuid().ToString("N")[..8];
        var version = "v" + DateTime.Now.ToString("yyyyMMddHHmmss");
        var app = NewDeploy(deployName);
        try
        {
            var (token, node) = await LoginNodeAsync();
            new AppBuildNode { DeployId = app.Id, NodeId = node.ID, Enable = true }.Insert();

            var body = await UploadAsync(token, deployName, version);

            var ver = AppDeployVersion.FindByDeployIdAndVersion(app.Id, version);
            Assert.NotNull(ver);
            Assert.Equal(version, ver.Version);
        }
        finally
        {
            foreach (var v in AppDeployVersion.FindAllByDeployId(app.Id)) v.Delete();
            foreach (var b in AppBuildNode.FindAll(AppBuildNode._.DeployId == app.Id)) b.Delete();
            app.Delete();
        }
    }

    [Fact(DisplayName = "部署节点上传构建产物成功(兼容回归保护)")]
    public async Task DeployNode_Upload_Ok()
    {
        var deployName = "v4d_" + Guid.NewGuid().ToString("N")[..8];
        var version = "v" + DateTime.Now.ToString("yyyyMMddHHmmss");
        var app = NewDeploy(deployName);
        try
        {
            var (token, node) = await LoginNodeAsync();
            new AppDeployNode { DeployId = app.Id, NodeId = node.ID, Enable = true }.Insert();

            var body = await UploadAsync(token, deployName, version);

            var ver = AppDeployVersion.FindByDeployIdAndVersion(app.Id, version);
            Assert.NotNull(ver);
            Assert.Equal(version, ver.Version);
        }
        finally
        {
            foreach (var v in AppDeployVersion.FindAllByDeployId(app.Id)) v.Delete();
            foreach (var d in AppDeployNode.FindAllByDeployId(app.Id)) d.Delete();
            app.Delete();
        }
    }
}