How can I pass a SSL certificate to Nowin when using Nancy - c#

So I am using Nancy with Nowin.
The beauty of using Nowin is I don't have to mess around with various Windows commands to set up a simple web server. According to the Nowin readme I can configure SSL using the following line
builder.SetCertificate(new X509Certificate2("certificate.pfx", "password"));
However, when using Nancy I don't seem to have access to this Server builder class. Everything seems to happen magically behind the scenes.
Any ideas how I can pass the certificate through to Nowin?

Make sure you have the Nancy.Owin package installed.
Use code like this to start the server up:
.
using System;
using System.Net;
using System.Threading.Tasks;
using Nancy.Owin;
using Nowin;
public class Program
{
static void Main(string[] args)
{
var myNancyAppFunc = NancyMiddleware.UseNancy()(NancyOptions options =>
{
// Modify Nancy options if desired;
return Task.FromResult(0);
});
using (var server = ServerBuilder.New()
.SetOwinApp(myNancyAppFunc)
.SetEndPoint(new IPEndPoint(IPAddress.Any, 8080))
.SetCertificate(new X509Certificate2("certificate.pfx", "password"))
.Build()
)
{
server.Start();
Console.WriteLine("Running on 8080");
Console.ReadLine();
}
}
}

If you look at this document, it says the following:
Configuration of OWIN
It'll just be there if the host sends it on.
If you use IIS as a host. You'll need to do the same config as with Aspnet. And you'll need an OWIN Aspnet host that supports the ClientCertificate. The one in the OWIN demo in Nancy does. The one by #prabirshrestha also does.
In the OWIN Demo, check this line:
if (request.ClientCertificate != null && request.ClientCertificate.Certificate.Length != 0)
{
env[OwinConstants.ClientCertificate] = new X509Certificate(request.ClientCertificate.Certificate);
}
Hope it helps you, good luck.

I think you should follow by the way described in this article: https://msdn.microsoft.com/en-us/magazine/dn451439.aspx
At first you are creating web server according with Nowin documentation and after that you are adding Nancy as pipeline component. I tested this way with NowingSample (from Nowin package) and it works.

Related

Azure Function c# - Retrieve list of subscription's WebApp

We want to create an azure function in c# that retrieve the list of azure web app contained in the subscription (basically we want to call dynamically, for each webapp, the same API endpoint changing the subdomain of the api).
It's possible with c# retrieve the list of the web app contained in the same azure function subscriptions?
Usually we connect to the master database, we query the sys.databases to collect the dbname and understand the webapp names. But we are searching for a smartest way.
If you're in C# land, I'd look at using the ArmClient class to retrieve what you're looking for.
Install these (I've got a few others installed but start with that and see how you go, there may be a couple of others needed) Nuget packages ...
Azure.Identity;
Azure.ResourceManager;
Azure.ResourceManager.AppService
... and from there, using the DefaultCredential approach (if you've never used it, read up on it here -> https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/README.md) you can query your subscriptions webApps ...
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using System;
using System.Threading.Tasks;
namespace AzureManagement
{
internal class Program
{
static void Main(string[] args)
{
GetAzureResources().Wait();
}
static async Task GetAzureResources()
{
var credential = new DefaultAzureCredential();
var armClient = new ArmClient(credential);
var subscription = await armClient.GetDefaultSubscriptionAsync();
var webSitesEnumerator = subscription.GetWebSitesAsync().GetAsyncEnumerator();
try
{
while (await webSitesEnumerator.MoveNextAsync())
{
var webSite = webSitesEnumerator.Current;
Console.WriteLine($"Web App Name ........ {webSite.Data.Name}");
Console.WriteLine($"Default Host Name ... {webSite.Data.DefaultHostName}\n");
}
}
finally
{
await webSitesEnumerator.DisposeAsync();
}
Console.ReadLine();
}
}
}
The above is obviously not a function app but the core code will still work for you and can be ported as need be.
Note: I could be telling you how to suck eggs, but, once deployed to Azure, you'll need to do the necessary work to ensure that the function app has the required access to retrieve all of the resource information you're looking for.
If you're unfamiliar with that, read up on the managed identity concept. It's very easy to setup -> https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity
Yes, one easy way is to use HttpClient and send a request to Azure Rest API:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Web/sites?api-version=2022-03-01
https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list
PS: you first need to acquire an authentication token.
https://www.youtube.com/watch?v=6b1J03fDnOg&t=329s

Track Custom ActivitySource with Application Insights

I am trying to get application insights to pick up on custom ActivitySource in a library, however the documentation is unclear on how to achieve this.
Currently I have the following:
...
public static readonly ActivitySource Source = new ActivitySource("MyCompany.Library");
...
In the library it is used like this:
using(var activity = Source.StartActivity("Action"))
{
...
}
And in my startup I've added the following:
services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>(
(m, o) => m.IncludeDiagnosticSourceActivities.Add("MyCompany.Library")
);
services.AddApplicationInsightsTelemetryWorkerService();
However, these activities are not being picked up by application insights.
Is there something else required to make application insights aware of these activities ?
I'd rather not 'pollute' these libraries with application insights code
ApplicationInsights SDKs does not support reporting telemetry from custom ActivitySource.
There is a preview version which supports ActivitySource based telemetry. (Its called OpenTelemetry AzureMonitorExporter)
https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable?tabs=net
Follow the below steps to operate:
Add the OpenTelemetry.Exporter.Console NuGet package.
dotnet add package OpenTelemetry.Exporter.Console
Update Program.cs with additional OpenTelemetry using directives
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
Update Main() to create the OpenTelemetry TracerProvider:
public static async Task Main()
{
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
.AddSource("Sample.DistributedTracing")
.AddConsoleExporter()
.Build();
await DoSomeWork();
Console.WriteLine("Example work done");
}
Now the app collects distributed trace information and displays it to the console:
> dotnet run
You will get the result required.
Follow the below link for further reference:
https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-collection-walkthroughs

.NET Remoting TCPChannel analog for .NET Core

As .NET Remoting has been removed from .NET Core framework, I tried to use NetTcpBinding from the WCF library, but it's not included in .NET Core.
Is there some other analog of TCPChannel that I can use?
I would try to adopt a different RPC framework instead - ideally a platform-neutral one instead of one which is tightly coupled to .NET.
There are lots of options available. Just off the top of my head:
You could implement a Web API using ASP.NET Core, probably (but not necessarily) with a JSON payload.
You could use gRPC, probably (but not necessarily) using Protocol Buffers as the payload
You could use Thrift
Those are just examples - there are an awful lot of RPC and RPC-like frameworks available. None of these will be as "transparent" as using remoting, but:
They'll make it a lot clearer when you're making a network call
They'll allow you to evolve between service versions more easily
They'll allow you to use a mixture of platforms for servers and clients - which you may not need right now, but is good for future-proofing
If you have a large codebase that is based on .NET Remoting, then switching to WebAPI or gRPC could lead to rewrite half of your application.
CoreRemoting (MIT licensed) may be an alternative: https://github.com/theRainbird/CoreRemoting
It makes is possible to migrate .NET Remoting based Client/Server applications to .NET Core / .NET 5.
In contrast to gRPC or WebAPI, the procedure for CoreRemoting is very similar to .NET Remoting. Only remote method calls are made between .NET objects. A conversion of the calls to HTTP calls (building URLs with string concatenation) as with WebAPI is not necessary. Interfaces between client and server are defined in shared .NET assemblies instead of in a special interface language as with gRPC. Events and callbacks are supported out-of-the-box and can be used in a natural way for a C# developer (Compared to gRPC's more complex streaming approach).
The following example shows how a simple client/server chat application can be created using CoreRemoting.
Shared Contract Assembly
namespace HelloWorld.Shared
{
public interface ISayHelloService
{
event Action<string, string> MessageReceived;
void Say(string name, string message);
}
}
Server
using System;
using CoreRemoting;
using CoreRemoting.DependencyInjection;
using HelloWorld.Shared;
namespace HelloWorld.Server
{
public class SayHelloService : ISayHelloService
{
// Event to notify clients when users post new chat messages
public event Action<string, string> MessageReceived;
// Call via RPC to say something in the chat
public void Say(string name, string message)
{
MessageReceived?.Invoke(name, message);
}
}
public static class HelloWorldServer
{
static void Main(string[] args)
{
using var server = new RemotingServer(new ServerConfig()
{
HostName = "localhost",
NetworkPort = 9090,
RegisterServicesAction = container =>
{
// Make SayHelloSevice class available for RPC calls from clients
container.RegisterService<ISayHelloService, SayHelloService>(ServiceLifetime.Singleton);
}
});
server.Start();
Console.WriteLine("Server is running.");
Console.ReadLine();
}
}
}
Client
using System;
using CoreRemoting;
using HelloWorld.Shared;
namespace HelloWorld.Client
{
public static class HelloWorldClient
{
static void Main(string[] args)
{
using var client = new RemotingClient(new ClientConfig()
{
ServerHostName = "localhost",
ServerPort = 9090
});
client.Connect();
// Create a proxy of the remote service, which behaves almost like a regular local object
var proxy = client.CreateProxy<ISayHelloService>();
// Receive chat messages send by other remote users by event
proxy.MessageReceived += (senderName, message) =>
Console.WriteLine($"\n {senderName} says: {message}\n");
Console.WriteLine("What's your name?");
var name = Console.ReadLine();
Console.WriteLine("\nEntered chat. Type 'quit' to leave.");
bool quit = false;
while (!quit)
{
var text = Console.ReadLine();
if (text != null && text.Equals("quit", StringComparison.InvariantCultureIgnoreCase))
quit = true;
else
{
// Post a new chat message
proxy.Say(name, text);
}
}
}
}
}
CoreRemoting is only working from .NET to .NET. If you need to communicate with Javascript, Java, Python, ..., then it is not the right tool.
But if you only want to do RPC in a pure .NET environment and you want to do it in a comfortable way, thean CoreRemoting may be very helpful.
I would like to note that I am the developer of the CoreRemoting project.

How to configure EnyimMemcachedCore to access Elasticache in AWS Lambda?

I am trying to port a simple memcached client from .NET 4 to .Net Core on AWS Lambda. I am struggling to configure the new EnyimMemcachedCore client because the examples (https://github.com/cnblogs/EnyimMemcachedCore) use appsettings.json to setup the config, but Lambda functions using .net core do not use appsettings.json. I need to be able to setup the server/port/endpoint in the C# code.
Can anyone give me an example using EnyimMemcachedCore that creates the configuration manually?
The standard .net use of Enyim was trivial to fetch by key and return a value:
using Enyim.Caching;
using Enyim.Caching.Configuration;
using Enyim.Caching.Memcached;
...
// setup Enyim memcached client
MemcachedClient myCache;
MemcachedClientConfiguration config;
config = new MemcachedClientConfiguration();
config.AddServer("theIP", thePort);
config.Protocol = MemcachedProtocol.Text;
// instantiate client
myCache = new MemcachedClient(config);
// get the stored item
var result = myCache.Get(key);
How do I do something similar (configure the memcached client in code, not in a config file) with EnyimMemcachedCore?
// setup Enyim memcached client
var config = new MemcachedClientConfiguration();
//add each node manually if you can't get the Amazon.ElastiCacheCluster config for Core,
//but if you can, use that instead of MemcachedClientConfiguration
config.AddServer("something.0001.usw1.cache.amazonaws.com", 11211);
config.AddServer("something.0002.usw1.cache.amazonaws.com", 11211);
config.Protocol = MemcachedProtocol.Text;
// instantiate client
var myCache = new Enyim.Caching.MemcachedClient(config);
you can add the nodes individually until the cluster config becomes available for .NET Core (if it hasn't yet)
I guess this has been fixed as of today, 18 September 2018. I have tried the following appsettings, used the configuration endpoint of memcache which has one node
"enyimMemcached": {
"Servers": [
{
"Address": "st-cache-01-v2.l0nmej.cfg.xxxx.cache.amazonaws.com",
"Port": 11211
}
]
}
And the code on the ConfigureServices
services.AddEnyimMemcached(Configuration);
It's working like charm. I haven't tried with two nodes yet. Please feel free to correct me if it doesn't work for more than one node

User.IsInRole is always false when using IIS Express / Kestrel in ASP.Net 5 with Windows Authentication

I have an ASP.Net 5 application using version 1.0.0-rc1-update1 with Windows Authentication. I've implemented a custom policy in my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
// ... other configuration code
var viewCharts = new AuthorizationPolicyBuilder()
.AddRequirements(new ViewChartsRequirement())
.Build();
collection.AddAuthorization(opts =>
{
opts.AddPolicy(Policy.ViewCharts, viewCharts);
});
collection.AddTransient<IAuthorizationHandler, ViewChartsHandler>();
// ... other configuration code
}
The ViewChartsHandler's Handle method is as follows:
protected override void Handle(
AuthorizationContext context,
T requirement)
{
var identities = _securityRepo.GetIdentitiesForPolicy(_policy);
// this returns a result when using a web listener, but
// never finds a match when using IIS Express
var matchingIdentity = identities.FirstOrDefault(role => context.User.IsInRole(role));
if (!string.IsNullOrWhiteSpace(matchingIdentity))
{
context.Succeed(requirement);
}
}
When using a web listener as shown in this answer, the code above works. However, when using IIS Express it never finds a matchingIdentity.
Things to note:
My IIS Express is configured to use Windows Authentication, and deny Anonymous Authentication. The bug related to IIS Express and this was fixed in RC1.
The username from Windows is always resolving correctly.
In the Handle code above, context.User is an instance of System.Security.Principal.WindowsPrincipal when using a web listener, but when using IIS Express it is a System.Security.Claims.ClaimsPrincipal.
I have forwardWindowsAuthToken="true" set in my web.config.
I think this is a role provider problem, but I am at a loss as to how to correct it.
I'm using the following code to successfully check for role membership on RC1, however note that it does not resolve group names (probably due to the problems referred to by #blowdart), I have to supply the group names as SIDs:
// Set up authorisation policies from the configured AD group lists.
// NOTE: Currently this only works with SIDs if hosting using Kestrel
// behind IIS, not friendly group names.
var viewerGroups = Configuration.GetSection("Groups:Viewer").Value.Split(',');
var adminGroups = Configuration.GetSection("Groups:Admin").Value.Split(',');
services.AddAuthorization(auth =>
{
auth.AddPolicy("viewer", policy =>
{
policy.RequireRole(viewerGroups);
});
auth.AddPolicy("admin", policy =>
{
policy.RequireRole(adminGroups);
});
});
I don't know if this will help you, but I thought I'd offer it up in case!
Did you add the IISPlatformHandler middleware?
app.UseIISPlatformHandler();
This needs to be ran before app.UseMvc(), app.UseStaticFiles() or any other authentication middleware.
It turns out that User.IsInRole does not function correctly in RC1. (See #blowdart's comments.) This will be fixed in RC2.
The original code will work so long as the line below returns the SIDs for each AD group, as opposed to the friendly names.
// This line must return SIDs instead of friendly names
var identities = _securityRepo.GetIdentitiesForPolicy(_policy);
Update
This was fixed in RC2. The original code works!

Categories