security page filter for jost many pages - c#

i create a page filter in asp.net core razor page
I want it to be only for those handlers that are inside the administration area
this is my pageFilter
namespace ServiceHost
{
public class SecurityPageFilter :IPageFilter
{
private readonly IAuthHelper _authHelper;
public SecurityPageFilter(IAuthHelper authHelper)
{
_authHelper = authHelper;
}
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
var handlerCompulsoryPermission = (NeedPermissionAttribute)context.HandlerMethod.MethodInfo.GetCustomAttribute(typeof(NeedPermissionAttribute));
var accountPermissions = _authHelper.CurrentAccountPermissions();
if (handlerCompulsoryPermission == null)
return;
if (!_authHelper.IsAuthenticated())
context.HttpContext.Response.Redirect("/Account");
if (!accountPermissions.Contains(handlerCompulsoryPermission.Permission))
context.HttpContext.Response.Redirect("/Account");
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
}
}
}
and this is my startup file
namespace ServiceHost
{
public class Startup
{
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.AddHttpContextAccessor();
var connectionString = Configuration.GetConnectionString("Keyson_Shop");
ShopManagementBootstrapper.Configure(services, connectionString);
DiscountManagementBootstrapper.Configure(services, connectionString);
InventoryManagementBootstrapper.Configure(services, connectionString);
BlogManagementBootstrapper.Configure(services, connectionString);
CommentManagementBootstrapper.Configure(services, connectionString);
AccountManagementBootstrapper.Configure(services, connectionString);
services.AddTransient<IZarinPalFactory, ZarinPalFactory>();
services.Configure<CookiePolicyOptions>(options =>
{
//this line does access to tempData work
// options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Lax;
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
{
o.LoginPath = new PathString("/Account");
o.LogoutPath = new PathString("/Account");
o.AccessDeniedPath = new PathString("/AccessDenied");
});
services.AddCors(options => options.AddPolicy("MyPolicy", builder =>
builder
.WithOrigins("https://localhost:5002")
.AllowAnyHeader()
.AllowAnyMethod()));
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.Filters.Add<SecurityPageFilter>();
});
services.AddTransient<IMenuQuery, MenuQuery>();
services.AddTransient<IFileUploader, FileUploader>();
services.AddSingleton<IPasswordHasher, PasswordHasher>();
services.AddTransient<IAuthHelper, AuthHelper>();
services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.BasicLatin,UnicodeRanges.Arabic));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/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.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapDefaultControllerRoute();
});
}
}
}
i want to know page filter has any option to give that and just run in my administration areas handler.
but if that hasn't an option what should i need to do about this problem
i get happy if answer this question

Related

The ConfigureServices method must either be parameterless Program.cs in .NET 6

I am trying to put Startup class back to .NET 6 project Web API.
So I just altered Program.cs to:
public static class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
and I extracted all service registrations and stuff into my Startup class:
public class Startup
{
public WebApplication InitializeApp()
{
var builder = WebApplication.CreateBuilder();
IServiceCollection servicesservices = builder.Services;
ConfigureServices(servicesservices, builder);
var app = builder.Build();
Configure(app);
return app;
}
public void ConfigureServices(IServiceCollection services, WebApplicationBuilder builder)
{
ConfigurationManager configuration = builder.Configuration;
services.AddApplicationLayer();
services.AddPersistanceLayer(builder.Configuration);
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "VehicleReservation", Version = "v1" });
});
}
public void Configure(WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseErrorHandlingMiddleware();
app.UseAuthorization();
app.MapControllers();
SeedDatabase(app);
}
private void SeedDatabase(WebApplication app)
{
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var vehicleReservationContext = services.GetRequiredService<VehicleReservationContext>();
VehicleReservationContextSeed.SeedAsync(vehicleReservationContext);
}
}
}
but I have an error: `The ConfigureServices method must either be parameterless or take only one parameter of type IServiceCollection.'
I see that I have 2 params for my ConfigureServices, but Im not sure, how to make it to have 1 or non parameters?
APPROACH #1:
Is to have _builder globally defined within Startup class
public class Startup
{
private WebApplicationBuilder _builder;
public Startup(WebApplicationBuilder builder)
{
_builder = builder;
}
public WebApplication InitializeApp()
{
var _builder = WebApplication.CreateBuilder();
IServiceCollection servicesservices = _builder.Services;
ConfigureServices(servicesservices);
var app = _builder.Build();
Configure(app);
return app;
}
public void ConfigureServices(IServiceCollection services)
{
ConfigurationManager configuration = _builder.Configuration;
services.AddApplicationLayer();
services.AddPersistanceLayer(_builder.Configuration);
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "VehicleReservation", Version = "v1" });
});
}
public void Configure(WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseErrorHandlingMiddleware();
app.UseAuthorization();
app.MapControllers();
SeedDatabase(app);
}
private void SeedDatabase(WebApplication app)
{
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var vehicleReservationContext = services.GetRequiredService<VehicleReservationContext>();
VehicleReservationContextSeed.SeedAsync(vehicleReservationContext);
}
}
}
Startup classes support configuration injection via ctor, so since you are you only using Configuration from WebApplicationBuilder just inject it:
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// ...
// to clarify configure method
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// ...
}
And then you can use Configuration property in ConfigureServices.
See the docs on the Startup class.

System.NullReferenceException on accessing the Base URL from the appSettings.json

I have the Base URL within the appsettings.json like below
"RM": {
"BaseAddress": "https://rm-dev.abc.org/"
},
With in the Class where I am trying to make a call this endpoint
public class InventorySearchLogic
{
private readonly SMContext _context;
private readonly IConfiguration _iconfiguration;
public InventorySearchLogic(SMContext context, IConfiguration iconfiguration)
{
_context = context;
_iconfiguration = iconfiguration;
}
public InventorySearchLogic(SMContext context)
{
}
public async Task<string> GetRoomID(string roomName)
{
//string rmID = "";
using (var client = new HttpClient())
{
RmRoom retRoom = new RmRoom();
client.BaseAddress = new Uri(_iconfiguration.GetSection("RM").GetSection("BaseAddress").Value);
client.DefaultRequestHeaders.Accept.Clear();
When debugging it throws error like System.NullReferenceException: Message=Object reference not set to an instance of an object. how to access the base URL from appsettings.json
I am not sure how to use the ConfigurationBuilder() as I have different apSettings.json file one for each environment like appsettings.Development.json , appsettings.QA.json, appsettings.PROD.json
Below is my Startup
public class Startup
{
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.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews();
services.AddSession();
services.AddMemoryCache();
services.AddDbContextPool<SurplusMouseContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("SMConnectionStrings"),
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
});
});
services.AddHttpContextAccessor();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
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();
}
app.UseSession();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Customers}/{action=Index}/{id?}");
});
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
You're already injecting an IConfiguration in your service and saving it as _iconfiguration. Assuming that's not the null value, then simply use .GetValue to retrieve a value.
string baseAddress = _iconfiguration.GetSection("RM").GetValue<string>("BaseAddress");
Read more about ASP.Net configuration
Well, it seems that _iconfiguration is also null.
You've indicated in the comments that you're creating an instance of InventorySearchLogic from a controller, such as
// inside controller logic
var searchLogic = new InventorySearchLogic(_context, _iconfiguration);
This is the wrong approach. Instead, you should register this class as a DI service (although you should also add an interface, it's not necessary right now).
In your Startup's ConfigureServices method, add
services.AddTransient<InventorySearchLogic>();
Then instead of manually creating a variable of type InventorySearchLogic, request it though DI
// your controller constructor
private readonly InventorySearchLogic searchLogic;
public MyController(InventorySearchLogic searchLogic)
{
this.searchLogic = searchLogic;
}
This way, InventorySearchLogic's constructor correctly gets the DI services it's looking for. You will have to move the SMContext context. Maybe move that to the method's parameters?

How to add the "Access-Control-Allow-Credentials" request header to a POST request in ASP.NET?

So, I am trying to set the "Access-Control-Allow-Credentials", using the HttpContext.Request.Headers.Add("Access-Control-Allow-Credentials", "true"); , but it will only work for my GET requests, but not for my POST ones, and i don't know why.
I've also tried to set those in Startup.cs, as so:
services.AddCors(o => o.AddPolicy("ApiCorsPolicy", builder =>
{
builder
.WithOrigins("My_Web_App")
.AllowCredentials()
.AllowAnyMethod()
.AllowAnyHeader();
}));
And then use it in Configure with app.UseCors("ApiCorsPolicy");
That's the code from my controller, so nothing fancy in here, I think:
[ApiController]
[Route("[controller]")]
[EnableCors("ApiCorsPolicy")]
public class UserController : Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpPost("RegisterUser")]
public void GetTournaments([FromBody] UserDTO user)
{
HttpContext.Request.Headers.Add("Access-Control-Allow-Credentials", "true");
_userService.RegisterUser(user);
}
}
My question is, why I can't put the "Access-Control-Allow-Credentials" header using the Headers.add method( Which works for my GET requests ) ? If that is not the correct approach to it, then how to do it ?
Thanks!
Edit:
I've added all my Startup file, as requested:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("ApiCorsPolicy", builder =>
{
builder
.WithOrigins("http://"MyIpAddressHere"/")
.AllowAnyMethod()
.AllowAnyHeader();
}));
var mapperConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingGeneral());
});
IMapper mapper = mapperConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddSingleton<ITournamentService, TournamentService>();
services.AddSingleton<IUserService, UserService>();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "my_app", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "my_app v1"));
}
app.UseRouting();
app.UseCors("ApiCorsPolicy");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Change
.WithOrigins("My_Web_App")
to
.WithOrigins("http://localhost....") //your web app url
//your Url shouldn't end with "/"
and remove from code:
//sometimes it interfers with token if you have
.AllowCredentials()
// you don't need this at all
HttpContext.Request.Headers.Add("Access-Control-Allow-Credentials", "true");
Your UseCors should be after UseRouting but before UseAuthorization.
and remove from your controller:
[EnableCors("ApiCorsPolicy")]
I highly suspect that the culprit is in this:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials
Credentials are not supported without a correct origin.

How to customize string root in PhisicalFilePRovider initialization?

In my asp.net core 2.2 web application, in Start-Up class, in Configure method, i set the use of static files, mapping a specified disk folder, instancing a file provider thus:
FileProvider = new PhysicalFileProvider(#"C:\business\ROM\documents\112233\")
like in this code:
using ...
namespace MyApp
{
public class Startup
{
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.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.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
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();
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();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(#"C:\business\ROM\documents\112233\"),
RequestPath = new PathString("/dexml")
});
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
When i list my etntities, in the foreach cycle in the view i link the documents thus:
<a target="_blank" href="/dexml/#Html.DisplayFor(modelItem => item.nomefile)">view document</a>
All works fine!
But i need to set PhisicalFileProvider string root with placeholder, like this:
FileProvider = new PhysicalFileProvider(#"C:\business\[code1]\documents\[code2]\")
and i associated code1 and code2 in custom asp.net user identity fields.
How i can set FileProvider string root with placeholder and replace it in same place with user attributes?
thanks
For PhysicalFileProvider, it will be initialized while calling app.UseStaticFiles and could not changed during runtime.
You need to implement your own middleware to serve static files dynamically.
app.UseAuthentication();
app.Map("/dexml", subApp => {
subApp.Use(async (context, next) =>
{
await next();
var userName = context?.User?.Identity?.Name;
if (userName != null)
{
var dbContext = context.RequestServices.GetRequiredService<ApplicationDbContext>();
var user = dbContext.Users.FirstOrDefault(u => u.UserName == userName);
using (var provider = new PhysicalFileProvider($#"D:\{ user.Code1 }\{ user.Code2 }"))
{
var filePath = context.Request.Path.Value.TrimStart('/');
var info = provider.GetFileInfo(filePath);
using (var stream = info.CreateReadStream())
{
var originalStream = context.Response.Body;
await stream.CopyToAsync(originalStream);
context.Response.Body = stream;
}
}
}
});
});

IdentityServer4 500 internal error, misssing EpochTimeExtensions when using authorize endpoint

I am creating a wep api backend for xamarin forms application with ASP.NET,
i'm using identityserver4 for authentication and authorization.
I want to use the authorization code workflow but i'm encountering a problem when i try to start the authorization/authentication request.
The error i receive is :
System.TypeLoadException: Could not load type 'IdentityModel.EpochTimeExtensions' from assembly 'IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=e7877f4675df049f'.
I haven't found a solution to this problem anywhere on the internet.
This is my Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddAutoMapper();
services.AddDbContext<SqlDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.GetResources())
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryClients(Config.GetClients())
.AddDeveloperSigningCredential();
services.AddControllers()
.AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment 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.UseRouting();
app.UseIdentityServer();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World !");
});
});
}
}
This is my config.cs:
public class Config
{
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("Test", "TestService")
};
}
public static IEnumerable<IdentityResource> GetResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId()
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.Code,
RequireClientSecret = false,
RequireConsent = false,
AllowedScopes = new List<string>{ "Test" , "openid"},
AllowOfflineAccess = true,
RedirectUris = new List<String> {
"https://localhost:44392/account/test/"
}
}
};
}
}
And this is my request url :
https://localhost:44392/connect/authorize?client_id=client&response_type=code&redirect_uri=https://localhost:44392/account/test/&scope=Test openid&nonce=5&state=5
I hope someone here can help me.
Thanks in advance

Categories

Resources