ASP.NET with Microsoft-identity-web. If run webapp locally using dotnet app.dll everything is ok, but if package into an image and run in docker or kubernetes, each request will occur error:
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.ArgumentNullException: IDW10106: The 'ClientId' option must be provided.
at Microsoft.Identity.Web.MergedOptionsValidation.Validate(MergedOptions options)
at Microsoft.Identity.Web.MicrosoftIdentityWebAppAuthenticationBuilderExtensions.<>c__DisplayClass5_0.<AddMicrosoftIdentityWebAppInternal>b__3(OpenIdConnectOptions options, IServiceProvider serviceProvider, IOptionsMonitor'1 mergedOptionsMonitor, IOptionsMonitor'1 msIdOptionsMonitor, IOptions'1 msIdOptions)
at Microsoft.Extensions.Options.ConfigureNamedOptions'5.Configure(String name, TOptions options)
at Microsoft.Extensions.Options.OptionsFactory'1.Create(String name)
at Microsoft.Extensions.Options.OptionsMonitor'1.<>c__DisplayClass10_0.<Get>b__0()
at System.Lazy'1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location ---
at System.Lazy'1.CreateValue()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler'1.InitializeAsync(AuthenticationScheme scheme, HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, String authenticationScheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "xxx",
"TenantId": "xxx",
"ClientId": "xxx",
"CallbackPath": "/signin-oidc",
"ClientSecret": "xxx",
"ClientCertificates": []
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "user.read"
}
}
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY ./apprelease /home/app
Related
When I remove the rate related codes, the app works fine. If I write these codes, I get 404 error.
If await webHost.RunAsync(); , await IpPolicy.SeedAsync(); If I remove the await keyword in the , I get the error localhost refused to connect. How can I solve this problem?
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddDbContext(builder);
builder.Services.AddControllersWithViews();
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
builder.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters();
builder.Services.AddMapster();
builder.Services.AddIdentity();
builder.Services.AddCookieConfiguration();
builder.Services.AddOptions();
builder.Services.AddMemoryCache();
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting"));
builder.Services.Configure<IpRateLimitPolicies>(builder.Configuration.GetSection("IpRateLimitPolicies"));
builder.Services.AddInMemoryRateLimiting();
builder.Services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
builder.Services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
using IHost webHost = builder.Build();
using (var scope = webHost.Services.CreateScope())
{
IIpPolicyStore IpPolicy = scope.ServiceProvider.GetRequiredService<IIpPolicyStore>();
await IpPolicy.SeedAsync();
}
await webHost.RunAsync();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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();
}
app.UseIpRateLimiting();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
RoleSeed.Seed(app);
app.Run();
appsettings.json
{
"ConnectionStrings": { "SqlCon": "" },
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"HttpStatusCode": 429,
//"IpWhitelist": [ "127.0.0.12" ],
//"EndpointWhitelist": [ "*:/api/customers" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "10 s",
"Limit": 20
}
]
},
"IpRateLimitPolicies": {
"IpRules": [
{
"Ip": "*",
"Rules": [
{
"Endpoint": "*",
"Period": "10m",
"Limit": 150
}
]
}
]
}
}
i changed the service order and then i got this error how can i solve it?
I've created a C# .net5.0 console application and during testing Serilog has been working without incident, logging to Console and File (same folder; path="log.txt"). However, when I run on the application on our server, neither Console nor File logging sinks are working! I assume now that the issue is not the sinks themselves but Serilog not actually working.
I've tried enabling the self log:
Serilog.Debugging.SelfLog.Enable(msg =>
Console.WriteLine(msg)
);
but even running in the debugger in my dev environment, the Console.WriteLine(msg) line is never called!
My appsettings.json is as follows:
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "log.txt",
"rollingInterval": "Infinite",
"outputTemplate": "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"shared": false
}
}
],
"Enrich": [ "FromLogContext" ]
},
"Database": {
"Server": "(local)",
"Database": "ActivbaseLive"
},
"Email": {
"SmtpHost": "localhost",
"SmtpPort": 25,
"SmtpSecurityOption": "None",
"SmtpUsername": null,
"SmtpPassword": null,
"SmtpSender": "\"Activbase Learning Platform\" <noreply#activbase.net>"
}
}
I've tried absolute paths (using double backslashes in appsettings.json).
I've tried pre-creating the log file (e.g. log.txt and log200428.txt) and setting permissions to Everyone Full Control but neither of these changes fix the problem and they don't explain why the Console sink doesn't write either.
Here is how Serilog is being configured during start-up which is where I suspect the problem is (even through it works in dev environment):
return Host.CreateDefaultBuilder()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
})
.UseSerilog((hostContext, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration);
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
builder.AddEnvironmentVariables();
})
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
...
});
}
Any ideas why Serilog isn't working in production?
The Path you provide should be absolute.
Some thing like this:
"path": "E:/wwwroot/QA/BackgroundWorkerService/Logs/logFile_.log"
Even I had the same issue, the above fix worked fine for me...
For my api application running in IIS: I had to assign the following permissions to the log folder for the IIS_IUSRS. I didn't need an absolute path!
I have three ASP.NET Core WebAPI services Customer, Subscribe, Unscubscribe with swashbuckle and docker compose project
All is working well
I have added Ocelot API Gateway (ASP.NET core Project) with Ocelot installed.
Access customer service via own address https:///api/Customer works great. But from gateway I don't know which url should I use for example this customer service
I have tried many variants like:
http:///api/
http:///api/a/customer
http:///a/api/customer
but all of them returns 404.
May be problem with that Gateway is http not https?
Program.cs
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
var builder = WebHost.CreateDefaultBuilder(args);
builder.ConfigureServices(s => s.AddSingleton(builder))
.ConfigureAppConfiguration(
ic => ic.AddJsonFile(Path.Combine("configuration",
"configuration.json")))
.UseStartup<Startup>();
var host = builder.Build();
return host;
}
Startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddOcelot(Configuration);
}
// 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
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
Configurations:
configuration.json:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "customer.api",
"UpstreamPathTemplate": "/a/",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "customer.api",
"UpstreamPathTemplate": "/a/{everything}",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "subscribe.api",
"UpstreamPathTemplate": "/b/",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "subscribe.api",
"UpstreamPathTemplate": "/b/{everything}",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "unsubscribe.api",
"UpstreamPathTemplate": "/c/",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamPort": 80,
"DownstreamHost": "unsubscribe.api",
"UpstreamPathTemplate": "/c/{everything}",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
}
],
"GlobalConfiguration": {}
}
docker-compose.yml:
services:
customer.api:
image: ${DOCKER_REGISTRY}customer.api
build:
context: .
dockerfile: Customer.API\Dockerfile
subscribe.api:
image: ${DOCKER_REGISTRY}subscribe.api
build:
context: .
dockerfile: NewsSubscibe.API\Dockerfile
unsubscribe.api:
image: ${DOCKER_REGISTRY}unsubscribe.api
build:
context: .
dockerfile: NewsUnSubscribe.API\Dockerfile
gateway:
image: gateway
build:
context: ./OcelotAPIGateway
dockerfile: Dockerfile
depends_on:
- customer.api
- subscribe.api
- unsubscribe.api
You need to add UseOcelot().Wait(); in Configure method of Startup:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
app.UseOcelot().Wait();
}
My team working on symfony flex project. Its bit new to us. My composer file :
{
"type": "project",
"license": "proprietary",
"minimum-stability": "dev",
"require": {
"php": "^7.1",
"symfony/console": "^3.4",
"symfony/flex": "^1.0",
"symfony/framework-bundle": "^3.4",
"symfony/lts": "^3",
"symfony/yaml": "^3.4",
"guzzlehttp/guzzle": "~6.0",
"league/flysystem-aws-s3-v3": "^1.0",
"oneup/flysystem-bundle": "^2.0",
"php-amqplib/rabbitmq-bundle": "^1.13"
},
"require-dev": {
"symfony/dotenv": "^3.4",
"behat/behat": "^3.4",
"behat/symfony2-extension": "^2.1",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd"
},
"post-install-cmd": [
"#auto-scripts"
],
"post-update-cmd": [
"#auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"id": "01BY8F14MYNYFXEQV8P8QRJQHS",
"allow-contrib": false
}
}
}
When I run composer install I got below error:
Script cache:clear returned with error code 1
!! PHP Warning: Module 'apcu' already loaded in Unknown on line 0
!!
!! In DefinitionErrorExceptionPass.php line 37:
!!
!! Cannot autowire service "App\Services\ApiRequestValidator": argument "$secr
!! et" of method "__construct()" must have a type-hint or be given a value exp
!! licitly.
!!
!!
!!
While doing composer install we observed the symfony creates service.yaml file inside the config folder. Where as we wanted to use only php based configurations as defined at PHP-based configuration for services and routes.
If I delete the service.yaml files and run again the composer install it works well.
I am not sure why symfony creates explicitly service.yaml file when I have already php based service configuration inside my config folder.
This blocks me to up my docker container as well.
I have the following 3 micro-services in place
Config Server
Auth Server using MongoDB referencing link. I successfully migrated the project from 1.2.4 to 1.3.3
User Service. A Rest Controller and a Resource Server with 3 Get methods.(each for ADMIN,MERCHANT and CONSUMER)
I am looking to restrict access to the GET methods of the REST Controller based on the role of the user.
The Resource Configuration is as follows
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").hasAuthority("ROLE_ADMIN")
.anyRequest()
.authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("admin-api");
}
}
To test I am simply trying to lock the User Service for all users except with role ADMIN. However, I get 401 Access Denied. I have also tried hasRole("ADMIN") with same result. If i remove that authorization criteria then the user is rightly authenticated(does not accept wrong access token).
The response from userInfoUri of the auth server is as follows
{
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": null,
"tokenValue": "a4244b33-80b2-48db-909d-f8aaaaf45985",
"tokenType": "Bearer",
"decodedDetails": null
},
"authorities": [
{
"authority": "ROLE_ADMIN"
}
],
"authenticated": true,
"userAuthentication": {
"details": null,
"authorities": [
{
"authority": "ROLE_ADMIN"
}
],
"authenticated": true,
"principal": "admin#ikarma.com",
"credentials": null,
"client": false,
"name": "admin#ikarma.com"
},
"credentials": "",
"clientOnly": false,
"oauth2Request": {
"clientId": "admin-web",
"scope": [
"trust",
"read",
"write"
],
"requestParameters": {
"grant_type": "password",
"username": "admin#ikarma.com"
},
"resourceIds": null,
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"refreshTokenRequest": null,
"grantType": "password"
},
"principal": "admin#ikarma.com",
"name": "admin#ikarma.com"
}
I am not able to figure out why role based authorization is not working. Any help is kindly appreciated.
Change spring-security-oauth2 dependency to this
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
Make sure that the implementation of JWT encode/decode is the same on the both side resource server and auth server. Also please try on the oauth server to create inMemory the 3 users with the 3 roles:
#Configuration
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
...
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("user").authorities("read").roles("USER")
.and()
.withUser("admin").password("admin").authorities("read","write").roles("ADMIN");
}
...
}
Try to receive an access_token for these users and then make a request to the resource server including in request the header Authorization: bearer [access_token]
If you will get the same error means that your JWT implementation is not right...
Please take a look about JWT here
https://bshaffer.github.io/oauth2-server-php-docs/overview/jwt-access-tokens/