security
26 TopicsAdd AWS Cognito authentication to a Blazor WebAssembly standalone app
I cannot find a step by step guide for using AWS Cognito in a Blazor WebAssembly standalone app for net 8 Microsoft did produce a https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/standalone-with-authentication-library?view=aspnetcore-8.0&tabs=visual-studiobut not for Cognito. I did find a very good https://danieldonbavand.com/2024/04/10/securing-digital-identities-streamlining-authentication-with-aws-cognito-in-blazor-net-8-applications/comment-page-1/?unapproved=1695&moderation-hash=19e62c931277bbedb6ae1de7fa29b4d1#respond for adding Cognito but to a Blazor web app which does require a server.614Views0likes1CommentCombine Google Authentication & JWT Tokens using Cookie Authorization
* Edit: project is only a web-api, front-end will be developed in react(next.js) Hi guys! I'm a TypeScript Fullstack developer and I'm new to .NET and ASP.NET and basically this is one of my first projects using C# and .NET. My project's architecture requires a kind of different than out-of-the-box way of identifying users. I want Google Authentication which will create a local account (which I can relate other entities to) And JWT Tokens (access, refresh) generated and sent as cookies to the client and each protected endpoint to be using these cookies to authorize the requesting user. I haven't figured out a way of implementing this and still using mostly OOTB tools in order to keep modifications little as possible. Any tips and tricks on how to implement it? * Edit2: Just to be clear, I know how to create endpoints, and protected endpoints using the built in identity framework, using roles, etc... Its this combination of Google Auth, generating tokens, sending them to client as cookies basically is where my difficulty relies. * I have almost a blank new project, already set up with only google credentials518Views0likes3CommentsPath Traversal Issue
public bool Example (string getinput) { var example = System.Web.Security.AntiXss.AntiXssEncoder.HtmlFormUrlEncode(getinput); } Method Example gets dynamic data from the getinput element. This element’s value then flows through the code and is eventually used in a file path for local disk access in another log file. This may cause a Path Traversal vulnerability. Here we used AntiXssEncoder to the getinput but still we have the path traversal vulnerability is there any solution for that.456Views0likes0CommentsBlazor server app with Windows authentication getting 401 unauthorized
I'm building a Blazor server application for an internal company use and using Windows authentication. The app is supposed to field updates from another app via an exposed controller. I am trying to test the controller and getting a 401 unauthorized however I try to hit it (Postman, browser, test Console app, from within the Blazor server app itself, etc.). I'm running .NET 6 and scaffolded the app using Visual Studio and selecting Windows Authentication from the Create Project wizard for Blazor server app. I'm running the app from Visual Studio using IIS Express option. Here is the simple test I set up in the Console app just trying to get a positive response from the controller: public async Task GetUpdateTestTimerResult() { var client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:40871"); var url = "api/updateTest"; var value = await JsonSerializer.DeserializeAsync (await client.GetStreamAsync(url), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); return value; } I've tried setting the AllowAnonymous attribute on the controller but no dice there. How do I expose a controller that will allow an outside application (also internal to the company/on premises) access?1.2KViews0likes1Comment.Net 8 web API with identity Bearer token
I am using .NET 8 Bearer Token not JWT token and I want to check if it is expired from my client app. Is there any way I can decode it or at least check if it is expired or not? Is there a way I can create a service that decode the token or check it is expired or no? Also, how can I know what is the secret key of the token? Program.cs: using EmployeeManagement.Database; using EmployeeManagement.Entities; using EmployeeManagement.Shared.Common; using EmployeeManagement.Shared.Configrations; using EmployeeManagement.Shared.Services.Department; using EmployeeManagement.Shared.Services.Employee; using EmployeeManagement.Shared.Services.UserRole; using EmployeeManagement.Shared.Services.VacationRequests; using FluentValidation; using FluentValidation.AspNetCore; using Microsoft.AspNetCore.Authentication.Certificate; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Filters; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { In = ParameterLocation.Header, Name = "Authorization", Type = SecuritySchemeType.ApiKey }); options.OperationFilter<SecurityRequirementsOperationFilter>(); }); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException( "Connection string Not found"))); builder.Services.AddAuthorization(); builder.Services.AddIdentityApiEndpoints<ApplicationUser>() .AddRoles<IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>(); builder.Services.AddAuthentication().AddJwtBearer(); builder.Services.AddCors(options => { options.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); }); builder.Services.AddAutoMapper( typeof(EmployeeMapperConfig), typeof(UserRoleReMapperConfig), typeof(DepartmentMapperConfig), typeof(VacationRequestsMapperConfig), typeof(ApplicationUserMapperConfig) ); builder.Services.AddScoped<IEmployeeService, EmployeeService>(); builder.Services.AddScoped<IUserRole, UserRoleService>(); builder.Services.AddScoped<IDepartmentService, DepartmentServices>(); builder.Services.AddScoped<IVacationRequestsService, VacationRequestsService>(); builder.Services.AddFluentValidation(); builder.Services.AddValidatorsFromAssemblyContaining<IAssemblyMarker>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapIdentityApi<ApplicationUser>(); app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); Angular app: Here I got an exception when I decode the Toke, the exception shows that the token is not in a proper JWT format, because it is Bearer token not a JWT. I want to create my own API and call it here to validate the Token. import { HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { jwtDecode } from 'jwt-decode'; import { EmployeeManagementWebAPIService } from '../api/employee-management-web-api.service'; import { RefreshRequest } from '../model/refresh-request'; import { Router } from '@angular/router'; export const tokenInterceptorInterceptor: HttpInterceptorFn = (req, next) => { console.log("tokenInterceptorInterceptor+++"); let authService = inject(EmployeeManagementWebAPIService); let router = inject(Router); const AccessToken = localStorage.getItem('AccessToken'); const RefreshToken = localStorage.getItem('RefreshToken'); if (AccessToken) { console.log("tokenInterceptorInterceptor++999+"+AccessToken); try{ let decodedToken = jwtDecode(AccessToken); console.log("decodedToken+++" + decodedToken); const isExpired = decodedToken && decodedToken.exp ? decodedToken.exp < Date.now() / 1000 : false; if (isExpired) { console.log('token is expired'); const refreshRequest: RefreshRequest = { refreshToken: RefreshToken, }; authService.refreshPost(refreshRequest).subscribe( (newToken: any) => { localStorage.setItem('AccessToken', newToken); req.clone({ setHeaders: { Authorization: `Bearer ${newToken}`, 'Content-Type': 'application/json', // Set content type here }, }); console.log('Refresh token successful:', newToken); }, (error) => { // Handle error response here localStorage.removeItem("AccessToken"); router.navigateByUrl('/login'); console.error('Error refreshing token:', error); } ); } else{ console.error('Token not expired'); } }catch(e){ console.log("invalid token" , e); localStorage.removeItem("AccessToken"); router.navigateByUrl('/login'); } } else{ console.error('Token Not found'); router.navigateByUrl('/login'); } return next(req); }; my login response: { "tokenType": "Bearer", "accessToken": "", "expiresIn": 3600, "refreshToken": "" }2.8KViews0likes1CommentThreading problems in SignalR Hub
Hello, I implemented a SignalR Hub to make a game server. The idea is that when a room is full (4 people in it) I run a new game. A game: 1. We notify everybody 2. The first player send one data. 3. We switch to next one 4. while the game isn't finished: Ask the current player two data. Switch to next player My problem is that with that simple system, once the client sent the data, the server do nothing, that's why I think there is a data race somewhere that I don't see. Here is my https://github.com/mehdi-arch/okeygameserver in OkeyServer/ you have the server code, in OkeyScript/ you have all the functions needed for game logic. Thanks in advance for your help.312Views0likes0CommentsNo Registered Service for IEmailSender
Hello all, I am using ASP.Net Core Web API (.Net Core 😎 to create a web app and API, when i added default Identity and Areas Pages i am getting an error for IEmailSender Service not beeing registered even though i dont need and have registered a mock class for it. Thank you Program.cs using Microsoft.AspNetCore.Identity; using Microsoft.OpenApi.Models; using Microsoft.EntityFrameworkCore; using ProMateAPI.Data; using ProMate.Library; using Swashbuckle.AspNetCore.Filters; using ProMateAPI.Utility; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); // Add services to the container. var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); // this would be enabled if we only needed the defaults for users and such //builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) // .AddEntityFrameworkStores<ApplicationDbContext>(); // builder.Services.AddDbContext<TContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("Default"))); builder.Services.AddDbContext<ProMateContext>(); builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { In = ParameterLocation.Header, Name = "Authorization", Type = SecuritySchemeType.ApiKey, }); options.OperationFilter<SecurityRequirementsOperationFilter>(); }); /* * options => { options.SignIn.RequireConfirmedAccount = false; options.SignIn.RequireConfirmedAccount = false; } * * */ builder.Services.AddScoped<IEmailSender, MyEmailSender>(); builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>(); ////builder.Services.AddIdentityApiEndpoints<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>(); builder.Services.AddAuthentication(); builder.Services.AddAuthorization(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); app.UseMigrationsEndPoint(); } 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.MapIdentityApi<IdentityUser>(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.MapRazorPages(); app.Run(); ------------- MyEmailSender.cs using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.UI.Services; using System; using System.Collections.Generic; using System.Linq; using System.Net.Mail; using System.Text; using System.Threading.Tasks; namespace ProMateAPI.Utility; public class MyEmailSender : IEmailSender { public Task SendEmailAsync(string email, string subject, string htmlMessage) { return Task.CompletedTask; } } ----------------- Register.html.cs // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Text.Encodings.Web; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; using ProMateAPI.Utility; namespace ProMateAPI.Areas.Identity.Pages.Account { public class RegisterModel : PageModel { private readonly SignInManager<IdentityUser> _signInManager; private readonly UserManager<IdentityUser> _userManager; private readonly RoleManager<IdentityRole> _roleManager; private readonly IUserStore<IdentityUser> _userStore; private readonly IUserEmailStore<IdentityUser> _emailStore; private readonly ILogger<RegisterModel> _logger; //private readonly IEmailSender _emailSender; // IEmailSender emailSender public RegisterModel( UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager, IUserStore<IdentityUser> userStore, SignInManager<IdentityUser> signInManager, ILogger<RegisterModel> logger ) { _userManager = userManager; _roleManager = roleManager; _userStore = userStore; _emailStore = GetEmailStore(); _signInManager = signInManager; _logger = logger; //_emailSender = emailSender; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [BindProperty] public InputModel Input { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public string ReturnUrl { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public IList<AuthenticationScheme> ExternalLogins { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public class InputModel { /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } /// <summary> /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } } public async Task OnGetAsync(string returnUrl = null) { // creates missing roles if (!_roleManager.RoleExistsAsync(SD.Roles.Customer.ToString()).GetAwaiter().GetResult()) { foreach (var r in Enum.GetValues(typeof(SD.Roles))) { _roleManager.CreateAsync(new IdentityRole(r.ToString())).GetAwaiter().GetResult(); } } ReturnUrl = returnUrl; ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); } public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl ??= Url.Content("~/"); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); if (ModelState.IsValid) { var user = CreateUser(); await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); var result = await _userManager.CreateAsync(user, Input.Password); if (result.Succeeded) { _logger.LogInformation("User created a new account with password."); var userId = await _userManager.GetUserIdAsync(user); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); var callbackUrl = Url.Page( "/Account/ConfirmEmail", pageHandler: null, values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl }, protocol: Request.Scheme); //await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", // $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); if (_userManager.Options.SignIn.RequireConfirmedAccount) { return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl }); } else { await _signInManager.SignInAsync(user, isPersistent: false); return LocalRedirect(returnUrl); } } foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } // If we got this far, something failed, redisplay form return Page(); } private IdentityUser CreateUser() { try { return Activator.CreateInstance<IdentityUser>(); } catch { throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityUser)}'. " + $"Ensure that '{nameof(IdentityUser)}' is not an abstract class and has a parameterless constructor, or alternatively " + $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml"); } } private IUserEmailStore<IdentityUser> GetEmailStore() { if (!_userManager.SupportsUserEmail) { throw new NotSupportedException("The default UI requires a user store with email support."); } return (IUserEmailStore<IdentityUser>)_userStore; } } }5.4KViews0likes1CommentGenerate custom PasswordHash with Microsoft.AspNet.Identity
Hi , I'm using VS2022 and I want to override the Default PasswordHash. I want to include when the user is created in the Hash Password the username for example. I found some code but it is for the Core. And I'm not using the core I have created a MyCustomPasswordHash which inherits from IPasswordHasher. But it doesn't contain the user. If I override the methods it contains only the passwords. Is it possible to override the default behavior of PasswordHash and make it work in Microsoft.AspNet.Identity.Owin ???337Views0likes0CommentsASP.NET Core 8 Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response.
I created a PATCH method in an ASP.NET Core Web API like this: #region Patch /// <summary> /// Patch TableName by id. /// </summary> // PATCH BY ID: /TableName/patch/{id} [HttpPatch("[action]/{id}", Name = "PatchTableNameById")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [SwaggerOperation( Summary = "Patch Table Name by id", Description = "This can be used to modify any table name record", OperationId = "PatchTableNameById", Tags = new[] { "Patch" } )] public async Task<IActionResult> Patch(string id, [FromBody] JsonPatchDocument<TableName> patchDoc) { if (patchDoc != null) { var tablename = await context.TableName.SingleOrDefaultAsync(x => x.Id.ToString() == id); if (tablename == null) return NotFound(); patchDoc.ApplyTo(tablename); context.Entry(tablename).State = EntityState.Modified; if (!ModelState.IsValid) { return BadRequest(ModelState); } await context.SaveChangesAsync(); return new ObjectResult(tablename); } else { return BadRequest(ModelState); } } This works perfectly fine when I call it using Postman or directly using Swagger. However in my Blazor client I get an error when it is called. I have tried using httpclient, RestSharp and now Flurl. The error returned when using the Developer Tools console to review the log is: Access to fetch at 'http://localhost:5259/SharedServices/Commands/TableName/patch/2bd4e0f3-974a-4794-bb63-b0ce00ba5147' from origin 'http://localhost:5265' has been blocked by CORS policy: Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response. Here is my CORS policy in the Web API. It is called before anything else adding services. builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigins", builder => { builder.WithOrigins("http://localhost:56075", "http://localhost:5265", "https://localhost:7235").AllowAnyHeader().WithMethods("PATCH"); }); }); I have tried various combinations here including of allowing all methods, headers, and origins. In other words opening it wide up which isn't a great security tactic anyways. Here is my client side code for the call. public async Task Patch(string id, JsonPatchDocument<TableName> patchDoc) { var url = "http://localhost:5259/SharedServices/Commands/TableName/patch/" + id; var resultStr = await url.WithHeader("Content-Type", "application/json-patch+json").PatchJsonAsync(patchDoc) .ReceiveString(); } I have tried about every online suggestion to fix this. One problem is there are a lack of issue reports for later versions of asp.net -- post addition of addCORS. I have tried various browsers thinking this maybe a browser issue but no luck there either. Is this possibly a bug in asp.net core cors? I am also using Steeltoe. Is it possible it is interfering with this? Is there any way to turn off a preflight request or modify it? I tried to use various clients such as httpclient, restsharp, flurl. Also tried using a PUT and got the same issue. I have also tried various browsers. The expected result is a successful unblocked call to my web api method. Thanks for any help you can give!4KViews1like2CommentsInMemoryTokenCache for Microsoft Graph API
Hello everyone, I am working on a project that involves Angular SPA calling a protected ASP.NET Core Web API. The frontend is using MSAL.js for user authentication and authorization, and the backend implements the logic to validate the token and for other security purposes. builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(options => { builder.Configuration.Bind("AzureAd", options); options.Events = new JwtBearerEvents() { OnAuthenticationFailed = c => { Console.WriteLine(c.Exception.Message); return System.Threading.Tasks.Task.CompletedTask; } }; }, options => { builder.Configuration.Bind("AzureAd", options); }) .EnableTokenAcquisitionToCallDownstreamApi(options => builder.Configuration.Bind("AzureAd", options)) .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamAPI")) .AddInMemoryTokenCaches(); Now, I was trying to use Microsoft Graph API and call some of the basic delegate apis (User.Read) that don't require admin consent. Locally, everything is working fine but when I deploy the web api to azure app service it throws the following exception: An error occurred while calling the downstream API IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. I know this exception is thrown when we are trying to call the api that requires admin consent. But I am not sure why it is throwing that exception for basic API when deployed to azure app service. Does it have something to do with InMemoryTokenCahce()? Thanks for any help in advance!469Views0likes0Comments