AAD Authentication between client and .Net Core API - asp.net-core

I m getting this error when I reach the API from the client. I use MSAL, and I can see in the request the token is load.
Here is my startup configuration.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(defaultScheme: AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options =>
{
options.ClientId = "example";
options.TenantId = "example";
options.ClientSecret = "example";
options.Instance = "https://login.microsoftonline.com/";
});
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://localhost:5001", "http://localhost:5000")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
.WithExposedHeaders("Content-Disposition");
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors();
//app.UseCors(options =>
//{
// options.WithOrigins("https://localhost:5001", "http://localhost:5000")
// .AllowAnyHeader()
// .AllowAnyMethod()
// .AllowCredentials()
// .WithExposedHeaders("Content-Disposition");
//});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}

I solve the problem chaingin the Configure Services like this:
services.AddAuthentication(defaultScheme: AzureADDefaults.JwtBearerAuthenticationScheme)
.AddAzureADBearer(options =>
{
options.Instance = Environment.GetEnvironmentVariable("AAD_INSTANCE");
options.TenantId = Environment.GetEnvironmentVariable("AAD_TENANT_ID");
options.ClientId = Environment.GetEnvironmentVariable("AAD_CLIENT_ID");
options.ClientSecret = Environment.GetEnvironmentVariable("AAD_CLIENT_SECRET");
});

Related

How to get raw request header in token validation stage of IdentityServer4 (asp.net core)?

I need to read the IP address from request header in ResourcePasswordValidator when people login. But I could not find it in ResourceOwnerPasswordValidationContext. The document I followed: https://identityserver4.readthedocs.io/en/latest/topics/resource_owner.html
PS: LocalApiAuthentication is used, and I'm new to IdentityServer4 framework. Thanks.
Codes in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiScopes(ApiConfig.GetApis())
.AddInMemoryClients(ApiConfig.GetClients())
.AddInMemoryIdentityResources(ApiConfig.GetIdentityResources())
.AddResourceOwnerValidator<ResourcePasswordValidator>()
.AddProfileService<ProfileService>();
services.AddLocalApiAuthentication();
services.AddAuthorization(options =>
{
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
{
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Inside OWIN Startup.cs, add the password validator middleware to your Identity configuration:
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.SignIn.RequireConfirmedAccount = false;
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserStore<ApplicationUserStore>()
.AddRoleStore<ApplicationRoleStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleManager<ApplicationRoleManager>()
.AddPasswordValidator<IResourceOwnerPasswordValidator>() //right here
.AddDefaultTokenProviders();

.NET CORE 3.1 ERROR 500 during WebSocket handshake

I am using SignalR on my .net core 3.1 API and it all works on localhost
hosting my app on ubuntu 20.4 will result in error 500 during handshake...
I am pretty sure I am missing something on my Apache configs...
error is just "Error during WebSocket handshake: Unexpected response code: 500" no extra data although -> options.EnableDetailedErrors = true
any idea why it doesn't work?
this my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
}).AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = null;
});
services.AddControllers();
// Configure Compression level
services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Fastest);
// Add Response compression services
services.AddResponseCompression(options =>
{
options.Providers.Add<GzipCompressionProvider>();
options.EnableForHttps = true;
});
services.AddTransient<IActionContextAccessor, ActionContextAccessor>();
JsonSerializerSettings jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Include,
// ContractResolver = new CamelCasePropertyNamesContractResolver()
};
jsonSettings.Converters.Add(new StringEnumConverter());
services.AddMvc().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddDistributedMemoryCache();
services.AddOptions();
services.Configure<IConfiguration>(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IDistributedCache cache)
{
app.UseResponseCompression();
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<AnalyticsHub>("/AnalyticsHub");
endpoints.MapHub<CampaignHub>("/CampaignHub");
endpoints.MapHub<LinkHub>("/LinkHub");
});
app.UseStaticFiles();
}
the error:

ASP.NET Core 3.1 - routing Issue

Since upgrading to 3.1, I seemed to have lost my routing. My endpoints are now just returning a 404 and I have ran out of ideas of what the issue could be. Can anyone see if I'm doing something stupid in my below setup code? All that really changed in my setup code was that I stopped using
app.UseMvc
And now use the endpoint instead
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Code below
[ApiController]
[Authorize]
[Route("api/guild")]
public class GuildController : Controller
{
[HttpPost("create")]
public async Task<IActionResult> Create([FromBody]CreateGuildRequest request)
{
return Ok();
}
}
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)
{
var domain = Configuration["Auth0:Domain"];
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = domain;
options.Audience = Configuration["Auth0:Audience"];
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true)
.AllowCredentials()
.Build());
});
services.AddControllers();
services.AddSpaStaticFiles(configuration => { configuration.RootPath = "clientapp/dist"; });
}
// 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseSpa(spa =>
{
spa.Options.SourcePath = "clientApp";
if (env.IsDevelopment())
{
spa.UseVueCli(npmScript: "serve", port: 8080);
}
});
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Middleware order matters. Place your UseSpa() after UseEndpoints()
// this should be the last two middlewares, in this order
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "clientApp";
if (env.IsDevelopment())
{
spa.UseVueCli(npmScript: "serve", port: 8080);
}
});

Asp.net core 3.1 backend does not get the Identity from cookie

I have vue.js frontend and asp.net core 3.1 backend. Backend uses SignInManager and Identity. I am trying to use cookie authentication. Api requests work from Postman(!!) roles are applied, everything, but do not from vue app (httpContext.User.Identity.IsAuthenticated is false). Indentity is empty. Cookie is present in the HttpContext
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:Default"]));
services.AddCors();
services.AddControllers()
services.AddIdentity<AppUser, IdentityRole>(
opts =>
{
opts.SignIn.RequireConfirmedEmail = true;
}
)
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<MyDBContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.Cookie.SameSite = SameSiteMode.None;
options.SlidingExpiration = true;
});
//some DI
...
//
}
bit more Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, UserManager<AppUser> userManager)
{
app.UseRouting();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
I was trying to proxy requests to api in vue app. Did not help
module.exports = {
devServer: {
proxy: {
'^/api': {
target: 'https://localhost:44376',
ws: true,
changeOrigin: true
}
}
}
}
What can be wrong?
Maybe you are missing AddRoles<IdentityRoles>()?
services.AddIdentity<AppUser, IdentityRole>(
opts =>
{
opts.SignIn.RequireConfirmedEmail = true;
}
)
.AddRoles<IdentityRoles>() .// <== this line
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<MyDBContext>()
.AddDefaultTokenProviders();

Identity Server 4 - Audience validation failed error

I encounter this error in my API IDX10214: Audience validation failed. Audiences: 'https://localhost:44337/resources'. Did not match: validationParameters.ValidAudience: 'joborderingapi' or validationParameters.ValidAudiences: 'null'
I've been trying to solve this for 2 days already and can't figure out yet about how to solve it.
I have the following applications:
Client App (Angular 7)
Identity Server
API
I was able to login successfully to Identity Server in my Client app and was able to get the token but when I used the token to connect to the API method it throws this error IDX10214: Audience validation failed. Audiences: 'https://localhost:44337/resources'. Did not match: validationParameters.ValidAudience: 'joborderingapi' or validationParameters.ValidAudiences: 'null'.
I followed the answer from Identity Server 4 with EF Identity DB Issue and checked the three tables (ApiResources, ApiScopes, ClientScopes), the values are correct, joborderingapiis enabled in ApiResources, in ApiScopes it is linked to ApiResource and in ClientScopes it is linked to the Client
Here is my API Startup.cs
public void ConfigureServices(IServiceCollection services)
{
var apiIdpAuthority = Configuration["AppSettings:IdpAuthority"];
var apiName = Configuration["AppSettings:ApiName"];
var apiSecret = Configuration["AppSettings:ApiSecret"];
var requireHttps = Convert.ToBoolean(Configuration["AppSettings:RequireHttps"]);
var httpsPort = Configuration["AppSettings:HttpsPort"];
var applicationUrl = Configuration["AppSettings:ApplicationUrl"];
services.Configure<ClientAppSettings>(Configuration.GetSection("ClientAppSettings"));
services.AddDbContext<JobOrderingDataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JobOrderingDB")));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
IdentityModelEventSource.ShowPII = true;
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = apiIdpAuthority;
options.RequireHttpsMetadata = requireHttps;
options.ApiName = apiName;
options.ApiSecret = apiSecret;
});
services.AddCors(options =>
{
// this defines a CORS policy called "default"
options.AddPolicy("default", policy =>
{
policy.WithOrigins(apiIdpAuthority, applicationUrl)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()
.AllowCredentials();
});
});
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
});
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
options.HttpsPort = Convert.ToInt32(httpsPort);
});
}
// 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.UseCors("default");
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseHttpsRedirection();
app.UseCookiePolicy();
var locale = Configuration["SiteLocale"];
var supportedCultures = new List<CultureInfo> { new CultureInfo("en-US") };
if (supportedCultures.Where(x => x.Name == locale).Count() == 0)
{
supportedCultures.Add(new CultureInfo(locale));
}
RequestLocalizationOptions localizationOptions = new RequestLocalizationOptions()
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
DefaultRequestCulture = new RequestCulture(locale)
};
app.UseRequestLocalization(localizationOptions);
app.UseAuthentication();
app.UseMvc();
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
Identity Server Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//var microsoftClientId = Configuration["MicrosoftClientId"];
// var microsoftClientSecret = Configuration["MircosoftClientSecret"];
var azureADClientId = Configuration["AzureADClientId"];
var azureADClientSecret = Configuration["AzureADClientSecret"];
var azureADEndPoint = Configuration["AzureADEndPoint"];
var issuerUri = Configuration["IssuerUri"];
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<IdentityServerDataContext>(options => options.UseSqlServer(connectionString));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication()
// .AddCookie()
.AddOpenIdConnect("AAD", "Azure AD", options =>
{
options.Authority = string.Format("https://login.microsoftonline.com/{0}", azureADEndPoint);
options.ClientId = azureADClientId;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
});
IdentityModelEventSource.ShowPII = true;
services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddIdentityServer() .AddSigninCredentialFromConfig(Configuration.GetSection("SigninKeyCredentials"), _logger)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<IdentityWithAdditionalClaimsProfileService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// this will do the initial DB population
// InitializeDatabase(app);
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentityServer();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Note: I only encounter this issue when I use the local login. It is working fine if I use the Azure AD login, I was able to connect to the API using the authorization token from the client app