-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #73 from natashell666/Issue-#72
Kestrel Server Zitified
- Loading branch information
Showing
11 changed files
with
412 additions
and
0 deletions.
There are no files selected for viewing
126 changes: 126 additions & 0 deletions
126
OpenZiti.NET.Samples.Kestrel/Controllers/MetricItemsController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.EntityFrameworkCore; | ||
using ZitiRestServerCSharp.Models; | ||
|
||
namespace ZitiRestServerCSharp.Controllers | ||
{ | ||
[Route("api/MetricItemsController")] | ||
[ApiController] | ||
public class MetricItemsController : ControllerBase | ||
{ | ||
private readonly MetricContext _context; | ||
|
||
public MetricItemsController(MetricContext context) | ||
{ | ||
_context = context; | ||
} | ||
|
||
// GET: api/MetricItemsController | ||
[HttpGet] | ||
public async Task<ActionResult<IEnumerable<MetricItem>>> GetMetricItems() | ||
{ | ||
if (_context.MetricItems == null) | ||
{ | ||
return NotFound(); | ||
} | ||
return await _context.MetricItems.ToListAsync(); | ||
} | ||
|
||
// GET: api/MetricItemsController/5 | ||
[HttpGet("{id}")] | ||
public async Task<ActionResult<MetricItem>> GetMetricItem(long id) | ||
{ | ||
Console.WriteLine("Starting Metrics -> Get -> id: " + id); | ||
if (_context.MetricItems == null) | ||
{ | ||
return NotFound(); | ||
} | ||
var metricItem = await _context.MetricItems.FindAsync(id); | ||
|
||
if (metricItem == null) | ||
{ | ||
return NotFound(); | ||
} | ||
Console.WriteLine("Ending Metrics -> Get -> id: " + id); | ||
return metricItem; | ||
} | ||
|
||
// PUT: api/MetricItemsController/5 | ||
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 | ||
[HttpPut("{id}")] | ||
public async Task<IActionResult> PutMetricItem(long id, MetricItem metricItem) | ||
{ | ||
if (id != metricItem.Id) | ||
{ | ||
return BadRequest(); | ||
} | ||
|
||
_context.Entry(metricItem).State = EntityState.Modified; | ||
|
||
try | ||
{ | ||
await _context.SaveChangesAsync(); | ||
} | ||
catch (DbUpdateConcurrencyException) | ||
{ | ||
if (!MetricItemExists(id)) | ||
{ | ||
return NotFound(); | ||
} | ||
else | ||
{ | ||
throw; | ||
} | ||
} | ||
|
||
return NoContent(); | ||
} | ||
|
||
// POST: api/MetricItemsController | ||
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 | ||
[HttpPost] | ||
public async Task<ActionResult<MetricItem>> PostMetricItem(MetricItem metricItem) | ||
{ | ||
Console.WriteLine("Starting Add MetricItem with values" + metricItem); | ||
if (_context.MetricItems == null) | ||
{ | ||
return Problem("Entity set 'MetricContext.MetricItems' is null."); | ||
} | ||
_context.MetricItems.Add(metricItem); | ||
await _context.SaveChangesAsync(); | ||
|
||
Console.WriteLine("Creating values" + metricItem); | ||
return CreatedAtAction(nameof(GetMetricItem), new { id = metricItem.Id }, metricItem); | ||
} | ||
|
||
// DELETE: api/MetricItemsController/5 | ||
[HttpDelete("{id}")] | ||
public async Task<IActionResult> DeleteMetricItem(long id) | ||
{ | ||
if (_context.MetricItems == null) | ||
{ | ||
return NotFound(); | ||
} | ||
var metricItem = await _context.MetricItems.FindAsync(id); | ||
if (metricItem == null) | ||
{ | ||
return NotFound(); | ||
} | ||
|
||
_context.MetricItems.Remove(metricItem); | ||
await _context.SaveChangesAsync(); | ||
|
||
return NoContent(); | ||
} | ||
|
||
private bool MetricItemExists(long id) | ||
{ | ||
return (_context.MetricItems?.Any(e => e.Id == id)).GetValueOrDefault(); | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
OpenZiti.NET.Samples.Kestrel/Controllers/WeatherForecastController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace ZitiRestServerCSharp.Controllers; | ||
|
||
[ApiController] | ||
[Route("[controller]")] | ||
public class WeatherForecastController : ControllerBase | ||
{ | ||
private static readonly string[] Summaries = new[] | ||
{ | ||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" | ||
}; | ||
|
||
private readonly ILogger<WeatherForecastController> _logger; | ||
|
||
public WeatherForecastController(ILogger<WeatherForecastController> logger) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
[HttpGet(Name = "GetWeatherForecast")] | ||
public IEnumerable<WeatherForecast> Get() | ||
{ | ||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast | ||
{ | ||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | ||
TemperatureC = Random.Shared.Next(-20, 55), | ||
Summary = Summaries[Random.Shared.Next(Summaries.Length)] | ||
}) | ||
.ToArray(); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
OpenZiti.NET.Samples.Kestrel/DelegatedZitiConnectionListenerFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System.Buffers; | ||
using System.Buffers.Binary; | ||
using System.Diagnostics; | ||
using System.IO.Pipelines; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using System.Threading.Channels; | ||
using Microsoft.AspNetCore.Connections; | ||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; | ||
using OpenZiti; | ||
|
||
internal class ZitiConnectionListenerFactory : IConnectionListenerFactory | ||
{ | ||
private ILogger<ZitiConnectionListenerFactory> _logger; | ||
private ZitiSocket _zitiSocket; | ||
|
||
public ZitiConnectionListenerFactory(ILogger<ZitiConnectionListenerFactory> logger) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
public async ValueTask<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default) | ||
{ | ||
#region OptionZiti | ||
API.SetLogLevel(ZitiLogLevel.INFO); | ||
_zitiSocket = new ZitiSocket(SocketType.Stream); | ||
ZitiContext ctx = new ZitiContext("C:\\OpenZiti\\CSharp-RestApi-Server.json"); | ||
var svcName = "CSharp-Service"; | ||
string terminator = ""; | ||
|
||
API.Bind(_zitiSocket, ctx, svcName, terminator); | ||
Console.WriteLine("Bound to Ziti"); | ||
API.Listen(_zitiSocket, 100); | ||
Console.WriteLine("Listening on Ziti"); | ||
#endregion | ||
|
||
return new SocketListener(_zitiSocket, _logger); | ||
} | ||
|
||
class SocketListener : IConnectionListener | ||
{ | ||
private ZitiSocket _zitiSocket; | ||
private Socket _socket; | ||
private readonly Channel<ConnectionContext> _channel = Channel.CreateBounded<ConnectionContext>(20); | ||
private readonly SocketConnectionContextFactory _contextFactory; | ||
|
||
public SocketListener(ZitiSocket zitiSocket, ILogger logger) | ||
{ | ||
_zitiSocket = zitiSocket; | ||
_socket = zitiSocket.ToSocket(); | ||
_contextFactory = new(new(), logger); | ||
} | ||
|
||
public EndPoint EndPoint => _socket.LocalEndPoint!; | ||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
} | ||
|
||
public ValueTask UnbindAsync(CancellationToken cancellationToken = default) | ||
{ | ||
return default; | ||
} | ||
|
||
public async ValueTask<ConnectionContext?> AcceptAsync(CancellationToken cancellationToken = default) | ||
{ | ||
try | ||
{ | ||
while (true) | ||
{ | ||
ZitiSocket client = API.Accept(_zitiSocket, out var caller); | ||
Console.WriteLine("Accepted connection from an Authorized Ziti Client"); | ||
var socket = client.ToSocket(); | ||
if (socket.RemoteEndPoint is IPEndPoint remoteEndPoint) | ||
{ | ||
string clientIpAddress = remoteEndPoint.Address.ToString(); | ||
int remotePort = remoteEndPoint.Port; | ||
Console.WriteLine($"Connection stablished with Authorized Ziti Client IP Address: {clientIpAddress}, Port: {remotePort}"); | ||
} | ||
if (socket.LocalEndPoint is IPEndPoint localEndPoint) | ||
{ | ||
string localIpAddress = localEndPoint.Address.ToString(); | ||
int localPort = localEndPoint.Port; | ||
Console.WriteLine($"Connection stablished at IP Address: {localIpAddress}, Port: {localPort}"); | ||
} | ||
return _contextFactory.Create(socket); | ||
} | ||
} | ||
catch (ObjectDisposedException) | ||
{ | ||
} | ||
catch (SocketException) | ||
{ | ||
} | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace ZitiRestServerCSharp.Models; | ||
|
||
public class MetricContext : DbContext | ||
{ | ||
public MetricContext(DbContextOptions<MetricContext> options) | ||
: base(options) | ||
{ | ||
} | ||
|
||
public DbSet<MetricItem> MetricItems { get; set; } = null!; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace ZitiRestServerCSharp.Models; | ||
public class MetricItem | ||
{ | ||
public long Id { get; set; } | ||
public string? SensorGuid { get; set; } | ||
public string? Name { get; set; } | ||
public int value { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using OpenZiti; | ||
using System.Net.Sockets; | ||
using Microsoft.EntityFrameworkCore; | ||
using ZitiRestServerCSharp.Models; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
builder.WebHost.UseDelegatedTransport(); | ||
|
||
builder.Services.AddControllers(); | ||
builder.Services.AddDbContext<MetricContext>(opt => | ||
opt.UseInMemoryDatabase("Metrics")); | ||
builder.Services.AddEndpointsApiExplorer(); | ||
builder.Services.AddSwaggerGen(); | ||
|
||
var app = builder.Build(); | ||
|
||
app.UseSwagger(); | ||
app.UseSwaggerUI(); | ||
|
||
app.UseHttpsRedirection(); | ||
|
||
app.UseAuthorization(); | ||
|
||
app.MapControllers(); | ||
|
||
app.Run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
![Ziggy using the sdk-csharp](https://raw.githubusercontent.com/openziti/branding/main/images/banners/CSharp.jpg) | ||
|
||
# Zitified Kestrel Sample | ||
|
||
This sample demonstrates how to use the OpenZiti SDK to secure a Kestrel server. | ||
In this case, the server is a simple REST API listening in the Ziti Overlay, that returns some metric data. This data looks like this: | ||
``` | ||
{ | ||
"sensorguid": "abcd1234", | ||
"name": "temp", | ||
"value": "6" | ||
} | ||
``` | ||
|
||
## OpenZiti Concepts Demonstrated | ||
|
||
This sample demonstrates some key OpenZiti concepts: | ||
* Application-embedded zero trust server. | ||
* Availability to natively integrate with the DotNet Core ecosystem. | ||
* Offloading traffic from an identity. | ||
|
||
## Running the Sample | ||
|
||
To run the sample, you should be able to just run it directly and it will bootstrap the overlay network. The program expects to have your identity saved into the `C:\OpenZiti\CSharp-RestApi-Server.json` file. This location can be changed in the file `DelegatedZitiConnectionListenerFactory.cs`. You can run the code as: | ||
``` | ||
dotnet run --project OpenZiti.NET.Samples.Kestrel/ZitiRestServerCSharp.csproj | ||
``` | ||
|
||
## Code Walkthrough | ||
|
||
There're a few key components in this sample: | ||
* `DelegatedZitiConnectionListenerFactory.cs` - This is the main entry point of the application. It sets up the Kestrel server and the Ziti SDK using the identity provided. | ||
* `ServiceCollectionExtension.cs` - This file contains the extension method to overide the default `IConnectionListenerFactory` with the `DelegatedZitiConnectionListenerFactory`. |
17 changes: 17 additions & 0 deletions
17
OpenZiti.NET.Samples.Kestrel/ServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Net; | ||
using Microsoft.AspNetCore.Connections; | ||
using Microsoft.AspNetCore.Server.Kestrel.Core; | ||
|
||
namespace Microsoft.AspNetCore.Hosting | ||
{ | ||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IWebHostBuilder UseDelegatedTransport(this IWebHostBuilder hostBuilder) | ||
{ | ||
return hostBuilder.ConfigureServices(services => | ||
{ | ||
services.AddSingleton<IConnectionListenerFactory, ZitiConnectionListenerFactory>(); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace ZitiRestServerCSharp; | ||
|
||
public class WeatherForecast | ||
{ | ||
public DateOnly Date { get; set; } | ||
|
||
public int TemperatureC { get; set; } | ||
|
||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); | ||
|
||
public string? Summary { get; set; } | ||
} |
Oops, something went wrong.