I have added Custom security it is working fine for authrization. I don't know why Task<AuthenticateResult> HandleAuthenticateAsync() is calling for controller that don't needs authorization.
In Startup.cs below is code how I Initilize it .
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
services.AddAutoMapper();
c.AddSecurityDefinition(MM.AuthenticationScheme, new ApiKeyScheme()
{
Description = "API Key Authorization header using the mm Api Key scheme. Example: \"MM-API-KEY: {MM-API-KEY}\"",
Name = "MM-API-KEY",
In = "header",
Type = "apiKey"
});
auth.AddPolicy(MM.AuthenticationScheme, b =>
{
b.RequireAuthenticatedUser();
b.AuthenticationSchemes = new List<string> { MenulogApiKey.AuthenticationScheme };
});
services.AddAuthentication(options =>
{
// the scheme name has to match the value we're going to use in options.DefaultAuthenticateScheme = MM.AuthenticationScheme;
options.DefaultChallengeScheme = MM.AuthenticationScheme;
})
.AddMenulogApiKeyAuth(o => { });
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseAuthentication();
}
In KeyHandler Class I am using like this :
internal class MMApiKeyHandler : AuthenticationHandler<MMApiKeyAuthOptions>
(Blind guess)
The authentication filter may be set up as a global filter.
Search for something like filters.Add(
or examine the code where GlobalFilters.Filters are used.
Related
I have an Blazor webassembly application which uses IdentityServerJwt AddAuthentication and is working with Hangfire. I am trying to configure Hangfire to allow only users who are admins authorization based on the article here but I am getting an No authentication handler is registered for the scheme 'Bearer' error. What should I add as an AuthenticationSchemes. JwtBearerDefaults.AuthenticationScheme` does not work.
What am I missing?
public partial class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
string handfirepolicyname="HangfirePolicyName";
public void ConfigureServices(IServiceCollection services)
{
...Code removed for brevity
services.AddAuthentication().AddIdentityServerJwt();
services.AddAuthorization(options =>
{
options.AddPolicy(handfirepolicyname, builder =>
{ builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser();
builder.RequireRole("admin");
});
});
var hangfireConnectionstring = "SomeHangfireDatabaseConnectionString";
var mySqlStorageOptions = new MySqlStorageOptions();
var mySqlStorage = new MySqlStorage(hangfireConnectionstring, mySqlStorageOptions);
services.AddHangfire(config => config.UseStorage(mySqlStorage));
services.AddHangfireServer();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationIdentityDbContext identityDbContext)
{
...Code removed for brevity
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
//UseAuthentication, UseAuthorization should be before UseHangfireDashboard
app.UseHangfireDashboard();
app.UseEndpoints(endpoints =>
{
endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions()
{
Authorization = new List<IDashboardAuthorizationFilter> { }
}).RequireAuthorization(handfirepolicyname);
});
}
Error:
No authentication handler is registered for the scheme 'Bearer'. The registered schemes are: Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId, idsrv, idsrv.external, IdentityServerJwt, IdentityServerJwtBearer. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Bearer",...)?
by adding
[Authorize(AuthenticationSchemes = "Bearer")]
public class TestController : ControllerBase{}
on top of the controller
I am currently working on creating a simple web application in angular using Auth0 to offload the authorization portion. Right now I am trying to connect the front end portion and the backend portion and I am having some trouble.
For some reason when I send a https request to the API it keeps giving me the following error in the chrome console.
So I went to use postman to try and access the api. I got past the CORS part error but instead het Endpoint .... contains authorization metadata, but a middleware was not found that supports authorization.
This is what my startup class looks like in my backend:
public class Startup
{
readonly string MyAllowSpecificOrigins = "localhost_origin";
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)
{
string domain = $"https://{Configuration["Auth0:Domain"]}/";
services.AddControllers();
// 1. Add Authentication Services
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = domain;
options.Audience = Configuration["Auth0:ApiIdentifier"];
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ClaimTypes.NameIdentifier
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("read:messages", policy => policy.Requirements.Add(new HasScopeRequirement("read:messages", domain)));
});
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("https://localhost:4200").AllowAnyMethod().AllowAnyHeader();
});
});
}
// 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");
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
//app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Here is my test controller that I call the api on:
[Route("api")]
public class TestController : Controller
{
[HttpGet]
[Route("private")]
[Authorize]
public IActionResult Private()
{
return Json(new
{
Message = "Hello from a private endpoint! You need to be authenticated to see this."
});
}
}
I've read the documentation and followed the examples on auth0's sites for implementing this. I can't quite find where I went wrong.
Okay for the people that might run into a similar issue. It ended up being a problem of the order of things in the startup.cs file and making my localhost origin use http instead of https. I wasn't able to deduce this from the tutorial article because they ommitted a lot of code. I ended up having to download the sample project and compare line by line. This is the final startup.cs file that worked for me:
public class Startup
{
readonly string MyAllowSpecificOrigins = "localhost_origin";
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)
{
string domain = $"https://{Configuration["Auth0:Domain"]}/";
services.AddControllers();
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder
.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
// 1. Add Authentication Services
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = domain;
options.Audience = Configuration["Auth0:ApiIdentifier"];
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = ClaimTypes.NameIdentifier
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("read:messages", policy => policy.Requirements.Add(new HasScopeRequirement("read:messages", domain)));
});
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
}
// 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");
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
In my computer application works fine, but other computers receiving next error after trying handle any request:
Error constructing handler for request of type MediatR.IRequestHandler`2[Application.User.Register+Command,Application.User.User]. Register your handlers with the container. See the samples in GitHub for examples
connection string
I register MediatR with following line in my Startup.cs:
services.AddMediatR(typeof(List.Handler).Assembly);
My Startup class:
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.AddDbContext<DataContext>(opt =>
{
opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddCors(opt =>
{
opt.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000");
});
});
services.AddMvc(opt =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
opt.Filters.Add(new AuthorizeFilter(policy));
})
.AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<Create>())
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var builder = services.AddIdentityCore<AppUser>();
var identityBuilder = new IdentityBuilder(builder.UserType, builder.Services);
identityBuilder.AddEntityFrameworkStores<DataContext>();
identityBuilder.AddSignInManager<SignInManager<AppUser>>();
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateAudience = false,
ValidateIssuer = false
};
});
services.AddScoped<IJwtGenerator, JwtGenerator>();
services.AddScoped<IUserAccessor, UserAccessor>();
services.AddMediatR(typeof(List.Handler).Assembly);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<ErrorHandlingMiddleware>();
if (env.IsDevelopment())
{
//app.UseDeveloperExceptionPage();
}
else
{
// app.UseHsts();
}
// app.UseHttpsRedirection();
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseMvc();
}
}
Problem is that i cannot reproduce same issue on my computer.
Problem was on another level:
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
It was problem with reading Configuration. After fixing it, all works as designed.
I had developed a WebAPI application and secured my endpoints with OAuth 2.0 protocol using IdentityServer4
My ApiResource looks like:
Name = "BankOfDotNetApi",
Scopes =
{
new Scope("BankOfDotNetApi", "API name for Customer", new List<string>{ "Claim1"}),
new Scope("BankOfDotNetApi.Read"),
new Scope("BankOfDotNetApi.Write"),
new Scope("offline_access"),
},
UserClaims =
{
JwtClaimTypes.Name,
JwtClaimTypes.Email
},
MyClient looks like:
Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = {new Secret("secret".Sha256())},
AllowedScopes = { "BankOfDotNetApi", "BankOfDotNetApi.Read" },
}
My API application startUp.cs looks like:
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.AddMvc(
config =>
{
});
services.AddControllers();
services.AddDbContext<BankContext>(options => options.UseInMemoryDatabase("BankingDb"));
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.RequireHttpsMetadata = false;
options.ApiName = "BankOfDotNetApi";
options.Authority = "http://localhost:5000";
});
}
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I am not generating tokens manually(by creating an instance of JWTToken)and Tokens are automatically generated by IdentityServer4
I am able to access scopes in my access token but I am unable to access Claims.
If my code goes wrong, please suggest to me how and Where to add claims to my ApiResource.
How to access claims in my AccessToken
Use ICustomTokenRequestValidator interface, after token generation, control flow comes in ValidateAsync method.
namespace IdentityServer4.Validation
{
//
// Summary:
// Allows inserting custom validation logic into authorize and token requests
public interface ICustomTokenRequestValidator
{
//
// Summary:
// Custom validation logic for a token request.
//
// Parameters:
// context:
// The context.
//
// Returns:
// The validation result
Task ValidateAsync(CustomTokenRequestValidationContext context);
}
}
Use below line to add custom claim in token.
context.Result.ValidatedRequest.ClientClaims.Add(claim);
Adds the custom authorize request validator using AddCustomTokenRequestValidator in startup class.
I am getting the below error while making a request to my Identity Server application from my Javascript Client Application.
fail: IdentityServer4.Validation.ScopeValidator[0]
Invalid scope: openid
I have made sure I add the scope in my Identity Server application.
Below is my code.
IdentityServer Application ( the Host)
Config.cs
public class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1","My API")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "js",
ClientName = "javaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins = { "http://localhost:5003" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
};
}
}
Startup.cs
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
}
// 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();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseIdentityServer();
}
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
Web API Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddCors(option =>
{
option.AddPolicy("dafault", policy =>
{
policy.WithOrigins("http://localhost:5003")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
}
// 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();
//this uses the policy called "default"
app.UseCors("default");
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:5000",
AllowedScopes = { "api1" },
RequireHttpsMetadata = false
});
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
}
}
While your client (application) is configured or allowed to request the openid resource (or scope), your identity server is not configured for the openid identity resource
You need to add it as an identity resource similar to how its done here and have a method that returns all your identity resources that you want to use like its done here.
In short add a new method to your Config.cs that looks like this:
public static List<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile() // <-- usefull
};
}
And then to your identityservers service container add your identity resource configuration like this:
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources()); // <-- adding identity resources/scopes
In my particular case, this was caused by a missing call to .AddInMemoryApiScopes(), as shown by inspecting the return value of the below under the debugger (in particular, the Error and HttpStatusCode fields indicated invalid scope as you reported) from a simple console application.
await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { ... });
To resolve this, I added the below to method to my custom configuration class
public static IEnumerable<ApiScope> Scopes
{
get
{
return new List<ApiScope>
{
new ApiScope("my-scope-name", "Friendly scope name")
};
}
}
And then called this as such from within Startup.ConfigureServices()
services.AddIdentityServer()
.AddInMemoryApiResources(Configuration.Apis)
.AddInMemoryClients(Configuration.Clients)
.AddInMemoryApiScopes(Configuration.Scopes);