У меня возникла проблема с моим приложением .NET 6: файлы cookie корреляции теряются после аутентификации при развертывании за обратным прокси-сервером. Обратный прокси-сервер обрабатывает HTTPS, поэтому само приложение не управляет HTTPS напрямую.
Приложение работает правильно при локальном запуске, но в производственной среде (за обратным прокси-сервером) корреляция файлы cookie теряются после аутентификации.
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole();
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
string SecurityLevelClaimPolicy = "SecurityLevelClaimPolicy";
string SecurityLevelClaim = "Claims";
Settings _settings = new Settings();
_settings.IdConfiguration = new IdConfiguration();
//_settings.ClientType = ClientType.ApiAccess;
_settings.ClientType = ClientType.ApiAccessForMultiTenantClient;
_settings.ApiAudience1 = "URL";
_settings.IdConfiguration = new IdConfiguration();
_settings.IdConfiguration.ClientId = "clientid";
_settings.IdConfiguration.RsaPrivateKeyJwk = new TestIT.Authenticator.API.Helpers.SecurityKey("{'d':'XXXXXX','kid':'XXXXXX','use':'XXXXX','alg':'XXXXX'}", "XXXXX");
_settings.IdConfiguration.Scope = "scope";
_settings.IdConfiguration.StsUrl = "URL";
builder.Services.AddHttpContextAccessor();
builder.Services.AddMvc()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = new LowercaseContractResolver();
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.Converters.Add(new TestIT.Authenticator.API.Helpers.DateTimeHelper("dd.MM.yyyyTHH.mm.ss"));
})
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts =>
{
opts.ResourcesPath = "Resources";
})
.AddDataAnnotationsLocalization();
builder.Services.AddControllers();
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddEndpointsApiExplorer();
builder.Services.Configure(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.None;
options.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure
});
// Create a settings instance. These can be injected into other objects, for instance the HomeController
builder.Services.AddSingleton(_settings);
// We need the IdConfiguration instance as a service as well:
builder.Services.AddSingleton(_settings.IdConfiguration);
// Services for calculating the expiration time for tokens
var dateTimeService = new DateTimeService();
builder.Services.AddSingleton(dateTimeService);
builder.Services.AddTransient();
builder.Services.AddSingleton();
// No request object is needed, so we inject a null object for payload claims creation instead
builder.Services.AddSingleton(new NullPayloadClaimsCreatorForRequestObjects());
//var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService);
//builder.Services.AddSingleton(clientAssertionPayloadClaimsCreator);
var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService);
// We need payload claims for the token request, both the "default" type and for the multi-tenant organization number:
var compositePayloadClaimsCreator = new CompositePayloadClaimsCreator(new List
{
clientAssertionPayloadClaimsCreator,
new PayloadClaimsCreatorForMultiTenantClient()
});
// We add this object as an instance of IPayloadClaimsCreatorForClientAssertion
builder.Services.AddSingleton(compositePayloadClaimsCreator);
builder.Services.AddTransient();
builder.Services.AddSingleton();
builder.Services.AddTransient();
// Builder for client assertions payloads
// Builder for JWT tokens used for client assertions
builder.Services.AddSingleton(new DiscoveryDocumentGetter(_settings.IdConfiguration.StsUrl));
builder.Services.AddSingleton();
// Builds token requests (in our case, refresh token requests)
builder.Services.AddTransient();
// Register services here
builder.Services.AddTransient();
builder.Services.AddScoped();
// A getter of user session data, uses the user session data store
builder.Services.AddTransient();
builder.Services.AddAuthentication(options =>
{
// Configure default authentication schemes for the application
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
// Configure JWT bearer authentication
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.GetValue("Secret"))),
ValidateIssuer = true,
ValidIssuer = config.GetValue("Issuer"),
ValidateAudience = true,
ValidAudience = config.GetValue("Audience"),
ValidateLifetime = true,
};
});
builder.Services.AddSwaggerGen(c =>
{
// Configure Swagger documentation
c.SwaggerDoc("v1", new OpenApiInfo { Title = "TestIt .Net middleware", Version = "v1" });
// Add JWT bearer authentication to Swagger
var securityScheme = new OpenApiSecurityScheme
{
Name = "Authorization",
BearerFormat = "JWT",
Scheme = "bearer",
Description = "JWT Authorization header using the Bearer scheme.",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
};
c.AddSecurityDefinition("Bearer", securityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty()
}
});
});
builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Ensure cookies are sent over HTTPS
options.Cookie.SameSite = SameSiteMode.None; // Set the SameSite attribute to None
});
builder.Services.AddTransient();
builder.Services.AddTransient();
builder.Services.AddTransient();
builder.Services.Configure(OpenIdConnectOptions =>
{
OpenIdConnectOptions.MinimumSameSitePolicy = SameSiteMode.None;
OpenIdConnectOptions.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure
});
//// Set authentication options (these will call the AuthenticationOptionsInitializer and OpenIdConnectOptionsInitializer instances)
builder.Services.AddAuthentication()
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectOptions =>
{
// Path to access denied endpoint. Used when authorization fails
OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied";
OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied";
// Ensure cookies are only sent over HTTPS
OpenIdConnectOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always;
// Set SameSite policy. Adjust as necessary based on your requirements
OpenIdConnectOptions.Cookie.SameSite = SameSiteMode.None;
// Mark the cookie as HttpOnly
OpenIdConnectOptions.Cookie.HttpOnly = true;
})
.AddOpenIdConnect(openIdConnectOptions =>
{
// We need to extract the OpenID Connect options initializer from the service provider:
var serviceProvider = builder.Services.BuildServiceProvider();
var initializer = serviceProvider.GetService();
initializer!.Configure(nameof(UserAuthendication), openIdConnectOptions);
openIdConnectOptions.CallbackPath = "/signin-oidc";
openIdConnectOptions.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
openIdConnectOptions.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
});
var securityLevelClaimPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireClaim(IdSecurityLevelClaim, "4")
.Build();
builder.Services.AddDataProtection();
builder.Services.AddAuthorization(config =>
{
config.AddPolicy(SecurityLevelClaimPolicy, securityLevelClaimPolicy);
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseRouting();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
});
app.UseCookiePolicy(new CookiePolicyOptions
{
Secure = CookieSecurePolicy.Always,
});
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Есть ли что-то, что мне не хватает в конфигурации, что может привести к потере корреляционных файлов cookie после аутентификации? Будем очень признательны за любые советы и идеи.
Изменить: забыл упомянуть, что приложение находится внутри контейнера докеров
У меня возникла проблема с моим приложением .NET 6: файлы cookie корреляции теряются после аутентификации при развертывании за обратным прокси-сервером. Обратный прокси-сервер обрабатывает HTTPS, поэтому само приложение не управляет HTTPS напрямую. Приложение работает правильно при локальном запуске, но в производственной среде (за обратным прокси-сервером) корреляция файлы cookie теряются после аутентификации. [code] var builder = WebApplication.CreateBuilder(args); builder.Logging.AddConsole(); var config = new ConfigurationBuilder() .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .Build();
builder.Services.AddControllers(); builder.Services.AddRouting(options => options.LowercaseUrls = true); builder.Services.AddEndpointsApiExplorer(); builder.Services.Configure(options => { options.MinimumSameSitePolicy = SameSiteMode.None; options.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure });
// Create a settings instance. These can be injected into other objects, for instance the HomeController builder.Services.AddSingleton(_settings); // We need the IdConfiguration instance as a service as well: builder.Services.AddSingleton(_settings.IdConfiguration);
// Services for calculating the expiration time for tokens var dateTimeService = new DateTimeService(); builder.Services.AddSingleton(dateTimeService); builder.Services.AddTransient(); builder.Services.AddSingleton();
// No request object is needed, so we inject a null object for payload claims creation instead builder.Services.AddSingleton(new NullPayloadClaimsCreatorForRequestObjects());
//var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService); //builder.Services.AddSingleton(clientAssertionPayloadClaimsCreator);
var clientAssertionPayloadClaimsCreator = new ClientAssertionPayloadClaimsCreator(dateTimeService);
// We need payload claims for the token request, both the "default" type and for the multi-tenant organization number: var compositePayloadClaimsCreator = new CompositePayloadClaimsCreator(new List { clientAssertionPayloadClaimsCreator, new PayloadClaimsCreatorForMultiTenantClient() }); // We add this object as an instance of IPayloadClaimsCreatorForClientAssertion builder.Services.AddSingleton(compositePayloadClaimsCreator);
builder.Services.AddTransient();
builder.Services.AddSingleton();
builder.Services.AddTransient(); // Builder for client assertions payloads // Builder for JWT tokens used for client assertions builder.Services.AddSingleton(new DiscoveryDocumentGetter(_settings.IdConfiguration.StsUrl)); builder.Services.AddSingleton(); // Builds token requests (in our case, refresh token requests) builder.Services.AddTransient(); // Register services here
builder.Services.AddTransient(); builder.Services.AddScoped(); // A getter of user session data, uses the user session data store builder.Services.AddTransient();
builder.Services.AddSwaggerGen(c => { // Configure Swagger documentation c.SwaggerDoc("v1", new OpenApiInfo { Title = "TestIt .Net middleware", Version = "v1" });
// Add JWT bearer authentication to Swagger var securityScheme = new OpenApiSecurityScheme { Name = "Authorization", BearerFormat = "JWT", Scheme = "bearer", Description = "JWT Authorization header using the Bearer scheme.", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, }; c.AddSecurityDefinition("Bearer", securityScheme); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, Array.Empty() } }); });
builder.Services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Ensure cookies are sent over HTTPS options.Cookie.SameSite = SameSiteMode.None; // Set the SameSite attribute to None });
builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.Configure(OpenIdConnectOptions => { OpenIdConnectOptions.MinimumSameSitePolicy = SameSiteMode.None; OpenIdConnectOptions.Secure = CookieSecurePolicy.Always; // Ensure cookies are marked as Secure }); //// Set authentication options (these will call the AuthenticationOptionsInitializer and OpenIdConnectOptionsInitializer instances) builder.Services.AddAuthentication() .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectOptions => { // Path to access denied endpoint. Used when authorization fails OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied"; OpenIdConnectOptions.AccessDeniedPath = "/authorization/access-denied";
// Ensure cookies are only sent over HTTPS OpenIdConnectOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always;
// Set SameSite policy. Adjust as necessary based on your requirements OpenIdConnectOptions.Cookie.SameSite = SameSiteMode.None;
// Mark the cookie as HttpOnly OpenIdConnectOptions.Cookie.HttpOnly = true; }) .AddOpenIdConnect(openIdConnectOptions => { // We need to extract the OpenID Connect options initializer from the service provider: var serviceProvider = builder.Services.BuildServiceProvider(); var initializer = serviceProvider.GetService(); initializer!.Configure(nameof(UserAuthendication), openIdConnectOptions); openIdConnectOptions.CallbackPath = "/signin-oidc"; openIdConnectOptions.NonceCookie.SecurePolicy = CookieSecurePolicy.Always; openIdConnectOptions.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
});
var securityLevelClaimPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .RequireClaim(IdSecurityLevelClaim, "4") .Build();
app.Run(); [/code] Есть ли что-то, что мне не хватает в конфигурации, что может привести к потере корреляционных файлов cookie после аутентификации? Будем очень признательны за любые советы и идеи. Изменить: забыл упомянуть, что приложение находится внутри контейнера докеров
У меня возникла проблема с моим приложением .NET 6: файлы cookie корреляции теряются после аутентификации при развертывании за обратным прокси-сервером. Обратный прокси-сервер обрабатывает HTTPS, поэтому само приложение не управляет HTTPS напрямую....
На сервере (Servera) находится Tomcat 9, который стоит за резервным прокси HTTPD на другом сервере (ServerB). HTTPD снова поддерживается балансировщиком нагрузки F5. У нас уже есть ограничения на уровень безопасности в F5 и httpd.
Мне нужно...
У меня есть устаревшее приложение ASP.NET 4.8 MVC, которое переносится для использования проверки подлинности Azure AD с использованием платформы Microsoft.Owin. Конфигурация приложения отлично работает на моем локальном компьютере. Однако я...
У меня есть устаревшее приложение ASP.NET 4.8 MVC, которое переносится для использования проверки подлинности Azure AD с использованием платформы Microsoft.Owin. Конфигурация приложения отлично работает на моем локальном компьютере. Однако я...
У меня есть устаревшее приложение ASP.NET 4.8 MVC, которое переносится для использования проверки подлинности Azure AD с использованием платформы Microsoft.Owin. Конфигурация приложения отлично работает на моем локальном компьютере. Однако я...