Skip to content

Commit

Permalink
Merge pull request #2267 from Atralupus/feat/access-control-service
Browse files Browse the repository at this point in the history
[Feature] Introduce Access control service and Access control center
  • Loading branch information
Atralupus authored Oct 16, 2023
2 parents 55b232e + 98d2fde commit 41a2895
Show file tree
Hide file tree
Showing 26 changed files with 625 additions and 8 deletions.
37 changes: 37 additions & 0 deletions Dockerfile.ACC
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Use the SDK image to build the app
FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env
WORKDIR /app
ARG COMMIT

# Copy csproj and restore as distinct layers
COPY ./Lib9c/Lib9c/Lib9c.csproj ./Lib9c/
COPY ./NineChronicles.Headless/NineChronicles.Headless.csproj ./NineChronicles.Headless/
COPY ./NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj ./NineChronicles.Headless.AccessControlCenter/
RUN dotnet restore Lib9c
RUN dotnet restore NineChronicles.Headless
RUN dotnet restore NineChronicles.Headless.AccessControlCenter

# Copy everything else and build
COPY . ./
RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj \
-c Release \
-r linux-x64 \
-o out \
--self-contained \
--version-suffix $COMMIT

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
RUN apt-get update && apt-get install -y libc6-dev
COPY --from=build-env /app/out .

# Install native deps & utilities for production
RUN apt-get update \
&& apt-get install -y --allow-unauthenticated \
libc6-dev jq curl \
&& rm -rf /var/lib/apt/lists/*

VOLUME /data

ENTRYPOINT ["dotnet", "NineChronicles.Headless.AccessControlCenter.dll"]
37 changes: 37 additions & 0 deletions Dockerfile.ACC.amd64
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Use the SDK image to build the app
FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env
WORKDIR /app
ARG COMMIT

# Copy csproj and restore as distinct layers
COPY ./Lib9c/Lib9c/Lib9c.csproj ./Lib9c/
COPY ./NineChronicles.Headless/NineChronicles.Headless.csproj ./NineChronicles.Headless/
COPY ./NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj ./NineChronicles.Headless.AccessControlCenter/
RUN dotnet restore Lib9c
RUN dotnet restore NineChronicles.Headless
RUN dotnet restore NineChronicles.Headless.AccessControlCenter

# Copy everything else and build
COPY . ./
RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj \
-c Release \
-r linux-x64 \
-o out \
--self-contained \
--version-suffix $COMMIT

# Build runtime image
FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim
WORKDIR /app
RUN apt-get update && apt-get install -y libc6-dev
COPY --from=build-env /app/out .

# Install native deps & utilities for production
RUN apt-get update \
&& apt-get install -y --allow-unauthenticated \
libc6-dev jq curl \
&& rm -rf /var/lib/apt/lists/*

VOLUME /data

ENTRYPOINT ["dotnet", "NineChronicles.Headless.AccessControlCenter.dll"]
37 changes: 37 additions & 0 deletions Dockerfile.ACC.arm64v8
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Use the SDK image to build the app
FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env
WORKDIR /app
ARG COMMIT

# Copy csproj and restore as distinct layers
COPY ./Lib9c/Lib9c/Lib9c.csproj ./Lib9c/
COPY ./NineChronicles.Headless/NineChronicles.Headless.csproj ./NineChronicles.Headless/
COPY ./NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj ./NineChronicles.Headless.AccessControlCenter/
RUN dotnet restore Lib9c
RUN dotnet restore NineChronicles.Headless
RUN dotnet restore NineChronicles.Headless.AccessControlCenter

# Copy everything else and build
COPY . ./
RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj \
-c Release \
-r linux-arm64 \
-o out \
--self-contained \
--version-suffix $COMMIT

# Build runtime image
FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim-arm64v8
WORKDIR /app
RUN apt-get update && apt-get install -y libc6-dev
COPY --from=build-env /app/out .

# Install native deps & utilities for production
RUN apt-get update \
&& apt-get install -y --allow-unauthenticated \
libc6-dev jq curl \
&& rm -rf /var/lib/apt/lists/*

VOLUME /data

ENTRYPOINT ["dotnet", "NineChronicles.Headless.AccessControlCenter.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Libplanet.Crypto;
using System.Collections.Generic;
using Nekoyume.Blockchain;

namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public interface IMutableAccessControlService : IAccessControlService
{
void DenyAccess(Address address);
void AllowAccess(Address address);
List<Address> ListBlockedAddresses(int offset, int limit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;

namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public static class MutableAccessControlServiceFactory
{
public enum StorageType
{
/// <summary>
/// Use Redis
/// </summary>
Redis,

/// <summary>
/// Use SQLite
/// </summary>
SQLite
}

public static IMutableAccessControlService Create(
StorageType storageType,
string connectionString
)
{
return storageType switch
{
StorageType.Redis => new MutableRedisAccessControlService(connectionString),
StorageType.SQLite => new MutableSqliteAccessControlService(connectionString),
_ => throw new ArgumentOutOfRangeException(nameof(storageType), storageType, null)
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using Libplanet.Crypto;
using NineChronicles.Headless.Services;

namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public class MutableRedisAccessControlService : RedisAccessControlService, IMutableAccessControlService
{
public MutableRedisAccessControlService(string storageUri) : base(storageUri)
{
}

public void DenyAccess(Address address)
{
_db.StringSet(address.ToString(), "denied");
}

public void AllowAccess(Address address)
{
_db.KeyDelete(address.ToString());
}

public List<Address> ListBlockedAddresses(int offset, int limit)
{
var server = _db.Multiplexer.GetServer(_db.Multiplexer.GetEndPoints().First());
return server
.Keys()
.Select(k => new Address(k.ToString()))
.Skip(offset)
.Take(limit)
.ToList();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Collections.Generic;
using Microsoft.Data.Sqlite;
using Libplanet.Crypto;
using NineChronicles.Headless.Services;

namespace NineChronicles.Headless.AccessControlCenter.AccessControlService
{
public class MutableSqliteAccessControlService : SQLiteAccessControlService, IMutableAccessControlService
{
private const string DenyAccessSql =
"INSERT OR IGNORE INTO blocklist (address) VALUES (@Address)";
private const string AllowAccessSql = "DELETE FROM blocklist WHERE address=@Address";

public MutableSqliteAccessControlService(string connectionString) : base(connectionString)
{
}

public void DenyAccess(Address address)
{
using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = DenyAccessSql;
command.Parameters.AddWithValue("@Address", address.ToString());
command.ExecuteNonQuery();
}

public void AllowAccess(Address address)
{
using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = AllowAccessSql;
command.Parameters.AddWithValue("@Address", address.ToString());
command.ExecuteNonQuery();
}

public List<Address> ListBlockedAddresses(int offset, int limit)
{
var blockedAddresses = new List<Address>();

using var connection = new SqliteConnection(_connectionString);
connection.Open();

using var command = connection.CreateCommand();
command.CommandText = $"SELECT address FROM blocklist LIMIT @Limit OFFSET @Offset";
command.Parameters.AddWithValue("@Limit", limit);
command.Parameters.AddWithValue("@Offset", offset);

using var reader = command.ExecuteReader();
while (reader.Read())
{
blockedAddresses.Add(new Address(reader.GetString(0)));
}

return blockedAddresses;
}
}
}
80 changes: 80 additions & 0 deletions NineChronicles.Headless.AccessControlCenter/AcsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NineChronicles.Headless.AccessControlCenter.AccessControlService;

namespace NineChronicles.Headless.AccessControlCenter
{
public class AcsService
{
public AcsService(Configuration configuration)
{
Configuration = configuration;
}

public Configuration Configuration { get; }

public IHostBuilder Configure(IHostBuilder hostBuilder, int port)
{
return hostBuilder.ConfigureWebHostDefaults(builder =>
{
builder.UseStartup(x => new RestApiStartup(Configuration));
builder.ConfigureKestrel(options =>
{
options.ListenAnyIP(
port,
listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
}
);
});
});
}

internal class RestApiStartup
{
public RestApiStartup(Configuration configuration)
{
Configuration = configuration;
}

public Configuration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();

var accessControlService = MutableAccessControlServiceFactory.Create(
Enum.Parse<MutableAccessControlServiceFactory.StorageType>(
Configuration.AccessControlServiceType,
true
),
Configuration.AccessControlServiceConnectionString
);

services.AddSingleton(accessControlService);
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
}
11 changes: 11 additions & 0 deletions NineChronicles.Headless.AccessControlCenter/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace NineChronicles.Headless.AccessControlCenter
{
public class Configuration
{
public int Port { get; set; }

public string AccessControlServiceType { get; set; } = null!;

public string AccessControlServiceConnectionString { get; set; } = null!;
}
}
Loading

0 comments on commit 41a2895

Please sign in to comment.