AspNetCore Httpsys configure useURLS from webapi Appsettings file - asp.net-core-2.0

I am building a AspNetCore webapi application for internal corporate use and I need to enable Windows Authentication.
So I am creating a httpsys server to listen at a specific endpoint:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseHttpSys(options =>
{
options.Authentication.Schemes =
AuthenticationSchemes.NTLM | AuthenticationSchemes.Negotiate;
options.Authentication.AllowAnonymous = true;
options.UrlPrefixes.Add("http://localhost:16000");
}).UseUrls("http://localhost:16000");
so while this obviously works fine, I want to be able to configure it in the config file.
Earlier in the project I was using Kestrel, so I just added these settings to the application config:
"Kestrel": {
"EndPoints": {
"HttpsInlineCertStore": {
"Url": "https://*:16000",
"Certificate": {
"Subject": "localhost",
"Store": "My",
"Location": "LocalMachine",
"AllowInvalid": "true"
}
} ...
Now I understand perfectly that HttpSYS can be configured by the registry etc, so I am not interested in those kinds of responses.
My Specific question is: For a NetCoreApi web api application, is it possible to use the IConfiguration inside the (static) CreateWebHostBuilder method?
I am injecting the IConfiguration into the startup class, but it appears the limitation is in the framework preventing access to it in the CreateWebHostBuilder method. Have I missed something?

For a NetCoreApi web api application, is it possible to use the
IConfiguration inside the (static) CreateWebHostBuilder method?
Yes, you will be able to access it inside ConfigureServices, which is enough to make your configurations. The overloaded of UseHttpSys actually does the exact same thing.
So basically you just have to configure your HttpSysOptions.
For netcoreapp2.1 :
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseHttpSys()
.ConfigureServices((context, services) =>
{
// Option 1. Set options manually.
services.Configure<HttpSysOptions>(options =>
{
// Use context.Configuration to access your config.
var url = context.Configuration.GetSection("MySection")["Url"];
options.UrlPrefixes.Add(url);
});
// Option 2. Build options from settings.
services.Configure<HttpSysOptions>(context.Configuration.GetSection("WebSys"));
});
For netcoreapp3.1:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureServices((context, services) =>
{
// Option 1. Set options manually.
services.Configure<HttpSysOptions>(options =>
{
// Use context.Configuration to access your config.
var url = context.Configuration.GetSection("MySection")["Url"];
options.UrlPrefixes.Add(url);
});
// Option 2. Build options from settings.
services.Configure<HttpSysOptions>(context.Configuration.GetSection("HttpSys"));
});
webBuilder.UseHttpSys(options =>
{
// Verify that your options is correct here.
});
});
In case you want to use option 2, your appsettings.json should look something like this:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"HttpSys": {
"AllowSynchronousIO": false,
"RequestQueueLimit": 2,
"MaxAccepts": 3
},
"AllowedHosts": "*"
}
Note that the property UrlPrefixes in HttpSysOptions is a rather complex object, so I'm not sure if you will be able to serialize it correctly from appsettings. However, you can simply set the field as urls in your config, as mentioned here. Then HttpSys will pick it up as long as your Configuration is correct.
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"urls": "http://*:5005;",
"HttpSys": {
"AllowSynchronousIO": false,
"RequestQueueLimit": 2,
"MaxAccepts": 3
},
"AllowedHosts": "*"
}

Related

Azure B2C: Unable to retrieve document from v2.0 .well-known openid-configuration

I am trying to use Azure B2C in my dotnet core web app in order to use a sign-in flow I created.
These are my appsettings.json:
"AzureAdB2C": {
"Instance": "https://XXXX.b2clogin.com/tfp/",
"Domain": "XXXX.onmicrosoft.com",
"ClientId": "<CLIENT_ID>",
"TenantId": "<TENANT_ID>",
"CallbackPath": "/signin-oidc",
"SignInPolicyId": "B2C_1_SignFlow"
}
This is my Startup.cs:
public void ConfigureServices(
IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
services.AddRepositories(this.Configuration);
services.AddDbContext<ApplicationDbContext>();
services.AddServices();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
// Handling SameSite cookie according to https://learn.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
options.HandleSameSiteCookieCompatibility();
});
// Configuration to sign-in users with Azure AD B2C
services.AddMicrosoftIdentityWebAppAuthentication(this.Configuration, Constants.AzureAdB2C);
services.AddRazorPages();
services.AddControllersWithViews().AddMicrosoftIdentityUI();
services.AddOptions();
services.Configure<OpenIdConnectOptions> (this.Configuration.GetSection("AzureAdB2C"));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
logger.LogInformation("Starting Migration");
using var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
logger.LogInformation("Finished Migration");
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
}
);
}
The issue: Everytime I start my application, I get the following error:
System.IO.IOException: IDX20807: Unable to retrieve document from: 'https://XXXX.b2clogin.com/<TENANT_ID>/v2.0/.well-known/openid-configuration'. HttpResponseMessage: 'StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
X-Frame-Options: DENY
...
Content-Type: text/html
Content-Length: 103
}', HttpResponseMessage.Content: 'The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.'.
If I simply want to use Microsoft authentication, and set my instance name to https://login.microsoftonline.com/, everything works as expected. This only happens when I attempt to use user flows.
If I try to remove the TenantId from the appsettings.json, I get a message saying it is required : The 'TenantId' option must be provided.
Any ideas?
Thank you!
You may need to add "Authority" in the appsettings.json. which is the meta data url
(authority format: "https://.b2clogin.com/.onmicrosoft.com/B2C_1_signupsignin1/v2.0/.well-known/openid-configuration" )
"AzureAdB2C": {
"Authority":"https://<tenantname>.b2clogin.com/tfp/{tenantName}.onmicrosoft.com/B2C_1_{signup_policy}/v2.0/ ",
"Instance": "https://XXXX.b2clogin.com/tfp/",
"Domain": "XXXX.onmicrosoft.com",
"ClientId": "<CLIENT_ID>",
"TenantId": "<TENANT_ID>",
"CallbackPath": "/b2csignin",
"SignInPolicyId": "B2C_1_SignFlow"
},
And provide the generic issuer url in portal/codesomething like below
https:// <domain>/tfp/<tenantId>/v2/
(or)
policy specific issuer
https:// <domain>/tfp/<tenantId>/b2c_1_ policy/v2/
References
getting-error-when-trying-to-secure-aspnet-core-web-api-
azure-ad-b2c-issuer-url-in-the-portal

Unable to read Azure SignalR Connection String from Azure App Service Configuration Application Settings

I am working on an Azure SignalR application and everything is working fine on my local machine when I set the following section in my appsettings.json:
"Azure": {
"SignalR": {
"ConnectionString": "XXXXX"
}
}
And then initialize in my startup.cs as follows:
services.AddSignalR().AddAzureSignalR();
However when I create the same environment variable in my Azure App Service using App Service>Configration>ApplicationSettings:
My application is unable to start and I get the following application error:
System.ArgumentException: Connection string missing required properties endpoint and accesskey. (Parameter 'connectionString')
at Microsoft.Azure.SignalR.ConnectionStringParser.Parse(String connectionString)
at Microsoft.Azure.SignalR.ServiceEndpoint..ctor(String connectionString, EndpointType type, String name)
When I hardcore my connection string onto the AddAzureSignalR() connectionstring parameter and deploy everything works fine.
It would seem that azuresignalR is unable to pickup this environment variable, despite also being able to see it via the Kudo Appsettings page as Azure:SginalR:ConnectionString.
You need to initiate like this,
string azureSignalrConnectionString = configuration["Azure:SignalR:ConnectionString"];
services.AddSignalR().AddNewtonsoftJsonProtocol().AddAzureSignalR(options =>
{
options.ConnectionString = azureSignalrConnectionString;
});
So I asked this same question on the Azure SignalR github page and below was the answer I got:
EnvironmentVariablesConfigurationProvider automatically replaces __
with : . So when you configures connection string via environment
variables, you should use Azure__SignalR__ConnectionString as the key.
When you configures it via JSON file, you should use the origin key
Azure:SignalR:ConnectionString.
Once I changed it to the double underscores all worked
For net core 5, use:
string azureSignalrConnectionString = Configuration["Azure:SignalR:ConnectionString"];
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ConnectionString = azureSignalrConnectionString;
});
appsettings.json, like:
{
"Azure": {
"SignalR": {
"ConnectionString": "<your-connection-string>"
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

AspCore 2.2 Azure Active Directory : Authorization failed

I try to integrate Azure Active Directory and Asp.net CORE 2.2.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
Appsettings.json
{"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "xxxxx.onmicrosoft.com",
"TenantId": "xxxxxx",
"ClientId": "xxxx" } },"AllowedHosts": "*"}
The results:
Error : info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
Please, i found any solution for this issue.
Thank you very much
May be a good solution is to modify the startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = AzureADDefaults.AuthenticationScheme;
})
.AddAzureAD(options => Configuration.Bind("AzureAD", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
And includes in the controller
[Authorize(AuthenticationSchemes = "AzureAD")]
[Route("api/[controller]")]
[ApiController]
AddAzureADBearer adds JWT Bearer authentication to your app for Azure Active Directory Applications. It is usually used by protecting your application with AAD tokens . If that is you scenario , check the detailed error message of Authorization failed. You can refer to below link for code samples :
https://stackoverflow.com/a/57619013/5751404
Another scenario is you want to add Azure AD login authentication .The simplest way is to use the default Azure AD template : Change Authentication --> Work or School Accounts . Or manually add the Microsoft.AspNetCore.Authentication.AzureAD.UI package and use AddAzureAD extension:
https://stackoverflow.com/a/54546245/5751404

Load an SSL certificate from appsettings.json

I built a .NET core 2.2 application, that I am loading onto a raspberry pi. I am hosting the web service using Kestrel. On the pi, I have created a self-assigned certificate.pfx. If I hard code into the application a .UseHttps with the certificate name and password, the browser can find it.
However, if I comment it out of the code and use the appsettings.json file instead (I would like it in the appsettings.json, so clients can upload their own certificates), the redirect to Https will work, but the certificate is not loading and the page fails to connect.
This is the document I have been using to configure my appsettings.json file:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.2
The certificate is located in the application folder.
Currently I have this code commented out of the application, but it does work when the code is not commented. I am hoping to set up these same settings through the appsettings.json file instead.
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureKestrel((context, options) =>
{
/*options.Listen(IPAddress.Any, 80);*/ // http:*:80
//options.Listen(IPAddress.Any, 5001, listenOptions =>
//{
// listenOptions.UseHttps("certificate.pfx", "password");
//});
});
here is the appsettings.json file:
{
"https_port": 5001,
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"AllowInvalid": true,
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:80"
}
},
"Https": {
"Url": "https://*:5001",
"Certificate": {
"Path": "certificate.pfx",
"Password": "password"
}
}
}
}
This article ended up having the solution I needed:
https://www.humankode.com/asp-net-core/develop-locally-with-https-self-signed-certificates-and-asp-net-core
To be more precise its the part of the article titled "Configuring HTTPS in ASP.NET Core 2.0"
Instead of using appsettings.json, I created a new json file called certificate.json.
I then pull in the certificate name and password from the certificate.json into the program.cs code.

How set up Ocelot Api Gateway with Azure Active Directory

I followed this tutorial and managed to use api with Azure Active Directory
authentication & authorization.
However I would like to consume the api from behind the Ocelot Api Gateway.
I could use ocelot with custom basic authorization but could not accomplish to use with Azure Active Directory.
I have added Ocelot api gateway url to my api redirect url list already.
How should I set ReRoutes values in config.json and Ocelot Api Gateway project StartUp.cs ?
Any help will be appreciated.
Eventually I could.
First of all thanks to ocelot library because it supports Azure Active Directory authorization.
I assume that you can already completed this tutorial.
1-Create an ocelot api gateway project as usual.
2-Add Microsoft.Identity.Web class library to ocelot project as reference
3-Add ocelot.json and it should be like below
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{catchAll}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 44351
}
],
"UpstreamPathTemplate": "/to-do-service/api/{catchAll}",
"AuthenticationOptions": {
"AuthenticationProviderKey": "AzureADJwtBearer",
"AllowedScopes": []
}
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:7070",
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration"
}
}
4-Edit CreateWebHostBuilder method in Program.cs so that ocelot.json is used as additional config source.
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("ocelot.json", false, false);
})
.UseStartup<Startup>();
5-Edit ConfigureServices and Configure methods in Startup.cs like below
public void ConfigureServices(IServiceCollection services)
{
services.AddProtectWebApiWithMicrosoftIdentityPlatformV2(Configuration); //this extension comes from Microsoft.Identity.Web class library
services.AddOcelot(Configuration);
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
await app.UseOcelot();
}
6-Last but not least you should add your AzureAd configuration to ocelot api gateway project. (It should be same as ToDoListService for reference tutorial)
Her you can see an example appsettings.json .
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "client-id-guid-from-azure-ad",
/*
You need specify the TenantId only if you want to accept access tokens from a single tenant (line of business app)
Otherwise you can leave them set to common
*/
"Domain": "blablabla.onmicrosoft.com", // for instance contoso.onmicrosoft.com. Not used in the ASP.NET core template
"TenantId": "tenant-id-guid-from-azure-ad" // A guid (Tenant ID = Directory ID) or 'common' or 'organizations' or 'consumers'
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
I hope this answer save someones time and make their life happier :)
Happy coding!
I was unable to get this working with the "Microsoft.Identity.Web" library. I received a host of errors such as:
AuthenticationScheme: AzureADCookie was not authenticated...
-- and --
Signature validation failed...
Instead, I managed to get the Azure B2C token validation, as well as the scopes, working as follows:
1) ConfigureServices method (Startup.cs):
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions =>
{
jwtOptions.Authority = $"{Configuration["AzureAdB2C:Instance"]}/tfp/{Configuration["AzureAdB2C:TenantId"]}/{Configuration["AzureAdB2C:SignUpSignInPolicyId"]}";
jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
jwtOptions.TokenValidationParameters.ValidateIssuer = true;
jwtOptions.TokenValidationParameters.ValidIssuer = $"{Configuration["AzureAdB2C:Instance"]}/{Configuration["AzureAdB2C:TenantId"]}/v2.0/";
});
// Map scp to scope claims instead of http://schemas.microsoft.com/identity/claims/scope to allow ocelot to read/verify them
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("scp");
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("scp", "scope");
2) Ocelot re-routing configuration:
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "master-api",
"Port": 5000
}
],
"UpstreamPathTemplate": "/master-api/{everything}",
"UpstreamHttpMethod": [ "POST", "PUT", "GET", "DELETE" ],
"ReRoutesCaseSensitive": false,
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer",
"AllowedScopes": [ "master" ]
}
}
3) Azure AD B2C configuration (appsettings.json):
"AzureAdB2C": {
"Instance": "https://yourdomain.b2clogin.com",
"TenantId": "{tenantId}",
"SignUpSignInPolicyId": "your_signin_policy",
"ClientId": "{clientId}"
}
Hope this helps! :)

Resources