IdentityServer4 500 internal error, misssing EpochTimeExtensions when using authorize endpoint - c#

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

Related

security page filter for jost many pages

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

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.

After clone of ASP.NET Core Web API project on other computer receiving MediatR error

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.

ASP.NET Core 3 API Ignores Authorize Attribute with Bearertoken

I´m working on a ASP.NET Core Web API. I´m using the newest version 3.0.0-preview4.19216.2.
I have the problem, that my API-Controller ignores the Authorize-Attribute but on another controller the Attribute works fine.
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes =JwtBearerDefaults.AuthenticationScheme)]
public class SuppliersController : ControllerBase
{
[HttpGet("GetAll")]
public IActionResult GetAll()
{
var companyId = int.Parse(User.Claims.FirstOrDefault(c => c.Type == "Company_Id").Value); // throws nullreference exception
return Ok();
}
}
But on another controller I have something similar but there the attribute works as expected
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class UsersController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var test = User.Claims.FirstOrDefault(c => c.Type == "Company_Id").Value;
}
}
In the user controller works everything fine.
I also tried it in the SupplierController without the
AuthenticationSchemes
but no different.
This is my AddAuthentication in the Startup.cs
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
var userId = int.Parse(context.Principal.Identity.Name);
var user = userService.GetById(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
Console.WriteLine(context);
return Task.CompletedTask;
},
OnMessageReceived = context =>
{
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
here is my complete startup.cs
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 appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
AuthenticationService.ConfigureSchoolProjectAuthentication(services, appSettingsSection);
DependencyInjectionService.Inject(services);
services.AddMvcCore()
.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.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
}
The strange thing is, when my SupplierController is called my authorization logic is not called (checked it with debugger) and when I call my UserController the logic is executed.
I think this is the reason why the claim is null. But why is the logic not called when the controller have a authorization attribute?
It´s seem like my authentication doesn't work entirely because I can access all my controller simply by using no authentication in Postman. What I´m doing wrong here?
Ok I found the anwser in this blog post ASP.NET Core updates in .NET Core 3.0 Preview 4
I have to change the order of my authentication registration from
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
to
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(routes =>
{
routes.MapControllers();
});
}
So this solve my problem.

Getting Scope Validating error in Identity Server 4 using JavaScript Client in asp.net core

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);

Categories

Resources