Issue adding OAuth Bearer authorization policy to ASP.Net 5 application - asp.net

I am building a REST API using OAuth Bearer tokens as my method of authentication. So, I attempted to add an authorization policy so that I could do something like [Authorize("Bearer")]. However, when I go to test my new authorization policy, an exception is thrown stating
The following authentication scheme was not accepted: Bearer
I've tried multiple things in an attempt to stop this exception from being thrown, but I haven't had any luck. My Startup class can be found at https://gist.github.com/mw2nukeboy/4b6cc7d348ac60336b03.

Update: in recent betas, configuring security options from ConfigureServices is no longer possible (except for Identity). You now need to directly configure the JWT options when calling app.UseJwtBearerAuthentication():
public void Configure(IApplicationBuilder app) {
app.UseJwtBearerAuthentication(options => {
// Configure the JWT options here.
});
}
You forgot to add the OAuth2 bearer authentication middleware in your pipeline:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
app.UseStaticFiles();
app.UseOAuthBearerAuthentication();
app.UseIdentity();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "api/{controller}/{action}/{id?}",
defaults: new {
controller = "Home",
action = "Index"
});
});
}
You're also not using the recommended approach to register the settings used by the OAuth2 bearer middleware:
public void ConfigureServices(IServiceCollection services) {
// Not recommended approach.
services.AddInstance(new OAuthBearerAuthenticationOptions { });
// Recommended approach.
services.ConfigureOAuthBearerAuthentication(options => {
// Configure the options used by the OAuth2 bearer middleware.
});
}

Related

JWT token not generated from identity server after signIn

I've created an empty .net5 Web API project. the project should use Identity Server to generate JWT token for the users of the API.
startup.cs
public void ConfigureServices(IServiceCollection services){
services.AddDbContext<ApplicationDbContext>(...);
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer(...)
.AddAspNetIdentity<ApplicationUser>()
.AddConfigurationStore(...);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer();
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env){
...
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
...
}
The code compile with no error
Login function
var result = await _signInManager
.PasswordSignInAsync(model.Email, model.Password, false, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return Ok();
}
return BadRequest("Invalid Login Attempt");
I received the ok result from the server but no JWT returned at the headers of the response. Also I noticed that when I create a second request I found my previous login data stored on User property in the Controller.
my question is where to find the token generated by my endpoint?

ASP.Net Core Web API returns HTTP 504 (Gateway Timeout) after adding Authorization via Cognito User Pool in AWS

I have develop a ASP.NET core web API and published to AWS Lambda. I have added the Authorize via the Cognito User Pool. But after adding the authorization it always returns a 504 Gateway Timeout HTTP code with the message "Endpoint request timed out" when I am calling the API using postman. But it is working very nicely for the localhost.
Using the AWS API Gateway I have added an authorizer to the API. All the parameters like User pool Id, App Client Id , region and Client Secret are OK.
I added the [Authorize] attribute to the controllers and follow I added my code in the Startup.cs file.
Please help to solve this issue.
public void ConfigureServices(IServiceCollection services)
{
var region = Configuration["AWSCognito:Region"];
var userPoolId = Configuration["AWSCognito:PoolId"];
var appClientId = Configuration["AWSCognito:AppClientId"];
var clientSecret = Configuration["AWSCognito:ClientSecret"];
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Audience = appClientId;
options.Authority = "https://cognito-idp." + region + ".amazonaws.com/" + userPoolId;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// Add S3 to the ASP.NET Core dependency injection framework.
services.AddAWSService<Amazon.S3.IAmazonS3>();
services.AddSingleton<IShoppingListService, ShoppingListService>();
services.AddSingleton<ICompanyService, CompanyService>();
services.AddSingleton<ICompanyRepository, CompanyRepository>();
}
// 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.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
}

Unable to run .net core 2.2 api application :No authenticationScheme was specified, and there was no DefaultChallengeScheme found

We are integrating Azure Active Directory with React web application and backend would be .net core 2.2 API.
Current Status: we could able to add app registration for React web application into Azure AD. With that, we could able to do authentication and getting Bearer token after successful authentication on react web app.
Challenges I’m facing: Since authentication is done, I would like to perform Authorization at Backend .net core API with use of Bearer token. However, I couldn’t get success as I keep getting the following error.
InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. Could anyone help to resolve this issue?
Code snippet from .net core api project:
in startup file: ConfigureServices(IServiceCollection services) method.
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole",
policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.AddRequirements(new AdminRequirement());
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
});
});
services.AddSingleton<IAuthorizationHandler, AdminHandler>();
In Configure(IApplicationBuilder app, IHostingEnvironment env):
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
And AuthenticationHandler:
public class AdminHandler : AuthorizationHandler<AdminRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement requirement)
{
//Check user claims for Role
if (context.User.HasClaim(ClaimTypes.Role, "Admin"))
{
context.Succeed(requirement);
}
return Task.FromResult(0);
}
}
If you need to specify the schema, maybe due to different kind of authentication you should add in the Configure() method this code:
app.Use(async (context, next) =>
{
IEnumerable<string> schemes = GetSchemesForRequest(context);
foreach (string scheme in schemes)
{
AuthenticateResult result = await context.AuthenticateAsync(scheme);
if (!result.Succeeded)
continue;
context.User = result.Principal;
break;
}
await next();
});
Then in your method:
IEnumerable<string> GetSchemesForRequest(HttpContext context)
you can think what is the proper scheme for that request.

OpenIddict - hosting auth server and web api resource in same project

I want to implement an OpenIdConnect/Oauth2 server using OpenIddict in order to secure a .NET core API app. Most examples I have seen implement these as separate projects.
The client app is a SPA and we are using implicit flow.
I have based my solution on the code shown in the OpenIddict samples here:
https://github.com/openiddict/openiddict-samples
For the project I am working on it would ideally have the Auth server and API to use the same port and be in the same project. ( One of the customer's requirements is that they don't want another server to configure since they own the API resource and it will be on the same server)
I have configured OpenIddict and combined it with our API project. Almost everything works correctly - the API endpoints are protected with the [Authorize] attribute and prevent access to protected API end points. However, when the API resource is protected, instead of returning a 401 Unauthorized HTTP status code, the returned result is the HTML Login page of the Auth server itself.
Here is the relevant setup code in my Startup.cs file:
// 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)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseIdentity();
app.UseCors("AllowAll");
//app.UseCors(builder =>
//{
// builder.AllowAnyOrigin();//)WithOrigins("http://localhost:9000");
// builder.WithMethods("GET","POST", "PUT", "DELETE", "OPTIONS");
// builder.WithHeaders("Authorization");
//});
app.UseWhen(context => !context.Request.Path.StartsWithSegments("/api"), branch =>
{
branch.UseIdentity();
});
app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), branch =>
{
branch.UseOAuthValidation();
});
app.UseOpenIddict();
#region Adding resource config here (api)
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseOAuthIntrospection(options =>
{
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.Authority = "http://localhost:5000";
options.Audiences.Add("resource-server-1");
options.ClientId = "resource-server-1";
options.ClientSecret = "846B62D0-DEF9-4215-A99D-86E6B8DAB342";
});
//app.UseCors(builder => {
// builder.WithOrigins("http://localhost:9000");
// builder.WithMethods("GET");
// builder.WithHeaders("Authorization");
//});
#endregion
app.UseMvcWithDefaultRoute();
// Seed the database with the sample applications.
// Note: in a real world application, this step should be part of a setup script.
InitializeAsync(app.ApplicationServices, CancellationToken.None).GetAwaiter().GetResult();
}
private async Task InitializeAsync(IServiceProvider services, CancellationToken cancellationToken)
{
// Create a new service scope to ensure the database context is correctly disposed when this methods returns.
using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
//await context.Database.EnsureCreatedAsync();
var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictApplication>>();
if (await manager.FindByClientIdAsync("MySPA", cancellationToken) == null)
{
var application = new OpenIddictApplication
{
ClientId = "MySPA",
DisplayName = "MySPA",
LogoutRedirectUri = "http://localhost:9000/signout-oidc",
RedirectUri = "http://localhost:9000/signin-oidc"
};
await manager.CreateAsync(application, cancellationToken);
}
if (await manager.FindByClientIdAsync("resource-server-1", cancellationToken) == null)
{
var application = new OpenIddictApplication
{
ClientId = "resource-server-1"
};
await manager.CreateAsync(application, "846B62D0-DEF9-4215-A99D-86E6B8DAB342", cancellationToken);
}
}
}
Not sure how to implement these both side by side in the same project. As mentioned it all "works" except the API is returning the HTML login page and not a desired HTTP status
app.UseIdentity(); is present twice in your pipeline, which defeats the whole purpose of using branch.UseIdentity() in a app.UseWhen() branching builder (i.e making sure the cookies middleware registered by Identity are not invoked for your API endpoints).
Remove the first occurrence and it should work.
You set the AutomaticChallenge to true. According to the documentation
this flag indicates that the middleware should redirect the browser to the LoginPath or AccessDeniedPath when authorization fails.
So by setting this to false it will not redirect to the login.

Asp.Net 5 IdentityRole CreateAsync not works

I create an asp.net 5 project with visualstudio 2015 ctp.
As you know it prepares identity system. there is a method called Register at accountcontroller and when I test it it works properly but when I add the following code to it :
before adding the new code
await SignInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
after adding the new codes :
await SignInManager.SignInAsync(user, isPersistent: false);
// new lines for adding the new Role to the database
ApplicationDbContext adbc = new ApplicationDbContext();
var roleStore = new RoleStore<IdentityRole>(adbc);
var roleManager = new RoleManager<IdentityRole>(roleStore);
await roleManager.CreateAsync(new IdentityRole { Name = "Administrator" });
// end of the new lines
return RedirectToAction("Index", "Home");
but after adding this new lines the following error returns :
InvalidOperationException: A relational store has been configured without specifying either the DbConnection or connection string to use.
It seems we must initialize dbcontext for role manager at startup. the start up code already is :
public void ConfigureServices(IServiceCollection services)
{
// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<ApplicationDbContext>();
// Add Identity services to the services container.
services.AddIdentity<ApplicationUser, IdentityRole>(Configuration)
.AddEntityFrameworkStores<ApplicationDbContext>();
// Add MVC services to the services container.
services.AddMvc();
// Uncomment the following line to add Web API servcies which makes it easier to port Web API 2 controllers.
// You need to add Microsoft.AspNet.Mvc.WebApiCompatShim package to project.json
// services.AddWebApiConventions();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
// Configure the HTTP request pipeline.
// Add the console logger.
loggerfactory.AddConsole();
// Add the following to the request pipeline only in development environment.
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
app.UseBrowserLink();
app.UseErrorPage(ErrorPageOptions.ShowAll);
app.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
}
else
{
// Add Error handling middleware which catches all application specific errors and
// send the request to the following path or controller action.
app.UseErrorHandler("/Home/Error");
}
// Add static files to the request pipeline.
app.UseStaticFiles();
// Add cookie-based authentication to the request pipeline.
app.UseIdentity();
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
// Uncomment the following line to add a route for porting Web API 2 controllers.
// routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
}
Any idea?

Resources