IdentityServer 4: No storage mechanism for grants specified - use AddInMemoryStores - asp.net-core

I am using Identity Server 4 , ASP.NET Core and trying to replace the IdentityServer developer in Production environment. But getting the following error:
No storage mechanism for grants specified. Use the 'AddInMemoryStores' extension method to register a development version.
So, I tried to implement the services as mentioned in this answer:
IProfileService
IResourceOwnerPasswordValidator
This is my ConfigureServices Method in Startup class:
services.AddMvc();
var identityBuilder = services.AddIdentityServer();
identityBuilder.AddInMemoryScopes(identitySrvConfig.GetScopes());
identityBuilder.AddInMemoryClients(identitySrvConfig.GetClients());
identityBuilder.AddProfileService<ProfileService>();
identityBuilder.Services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
Taking into consideration that in my case the interface signature is different:
public class ResourceOwnerPasswordValidator : IdentityServer4.Validation.IResourceOwnerPasswordValidator
{
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
throw new NotImplementedException();
}
}
But I am still getting the same error, what is the problem?

If you are applying custom Identity i.e
services.AddIdentity<AppUser, UserRole>(options => { options.User.RequireUniqueEmail = true; }).AddEntityFrameworkStores<AbcDbContext>();
then in
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
Comment
app.UseIdentityServer();
because we are using custom identity, not default

They were/are reworking those APIs. You should use AddInMemoryPersistedGrants

Related

Http Post in Orchard Core asp net core Web App returns bad request

I'm using Orchard core in asp net core web app project. I have a controller with two simple get and post Apis. As I'm using OrchardCore the Startup.cs file has different config and I dont use services.AddControllers() in configureServices.
Every thing is fine untill I'm using HttpGet. But when I want to have an Api with HttpPost postMan says badRequest. So I Added services.AddControllers() in Startup.cs and the post Api was fine in post Man but the orchard project says I have multipe Endpoints.
I used services.AddMvc().AddNewtonsoftJson(), and every thing was fine but the admin page didn't load and had error as below:
InvalidOperationException: The view 'Index' was not found. The
following locations were searched:
/Areas/OrchardCore.AdminDashboard/Views/Dashboard/Index.cshtml
/Areas/OrchardCore.AdminDashboard/Views/Shared/Index.cshtml
/Views/Shared/Index.cshtml /Pages/Shared/Index.cshtml
I wold appreciate it if you can help me how to call Post Api.
here is my code:
[HttpPost("post")]
public Task<string> post()
{
return Task.FromResult("hiPost");
}
[HttpGet("get")]
public Task<string> get()
{
return Task.FromResult("hiGet");
}
and this is my startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//services.AddControllers();
services.AddOrchardCms();
services.AddMediatR(typeof(SelectedWebSiteBlogQueryHandler).Assembly);
services.AddAutoMapper(typeof(Startup));
services.AddCors();
services.AddMvc().AddNewtonsoftJson();
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(o => o.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseOrchardCore();
}
}
You are probably missing an IgnoreAntiForgeryToken attribute on your controller.
AntiForgery is enabled by default by OrchardCore
For an ApiController in OrchardCore I would expect to see the controller decorated as follows.
[ApiController]
[Authorize(AuthenticationSchemes = "Api"), IgnoreAntiforgeryToken, AllowAnonymous]
However this depends if you are using the OpenId module to authenticate with, or simply need to post to a normal controller, without an AuthenticationScheme
Depending on what you are actually posting from in real life, it may be better to supply an anti forgery token as part of your post.

Blazor Server get current logged user when EF DbContext execute select data query

I build blazor server multi tenant application and I wants to use HasQueryFilter in entity framework DbContext for predefined filter with TenantId. Ofcourse I have connected User with tenant. I created CurrentTenatnProvider which has method GetCurrentTenatnId. In this mehtod i use AuthentificationStateProvider and call GetAuthenticationStateAsync(). Ofcourse i get the error ''GetAuthenticationStateAsync was called before SetAuthenticationState". I Cannot use IHttpContextAccessor because in Azure app I get null reference exception.
Is there any other possibility how to get CurrentUser in time when DbContext execute select data query?
I was thinking about cache CurrnetUser but there is problem with cache key.CurrentTenatnProvider service is registered as scoped service. There is Id attribute which is set in constructor. And then is used as cache key. But this approach does not working and I get the same error.
It si possible get signal-r connection identificator and use it as cache key?
I spended 2 days with test lots of combination and read lots of documentation but unfortunately I didn't find any solution. I will be very grateful for any advice.
I have done this a few ways but the simplest way I could find was retrieving my user from the database in the MainLayout.razor file during OnInitializedAsync() and passing it in a fixed cascading parameter <CascadingValue Name="CurrentUser" IsFixed="true" Value="UserId">. From there, I could reference it where needed in any child component.
finally I found solution! From my view it is bug! Problem is because services.AddDbContextFactory is registered as Singleton. I create my own implementation of IDbContext factory and register it as Scoped. After this change everything’s works perfect. When I change registration scope of DbContextFactory to singleton, I get the error: GetAuthenticationStateAsync was called before SetAuthenticationState.
My DbContextFactory
public class BlazorContextFactory<TContext> : IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public BlazorContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
My StartUp
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ApplicationDbContext>();
services.AddScoped<IDbContextFactory<ApplicationDbContext>, BlazorContextFactory<ApplicationDbContext>>();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// 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.UseDatabaseErrorPage();
}
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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
I hope it's help other peoples! I spend 6 days with this problem :(

Azure AD - Expose an API to consume it with application permissions

I'm developing a custom API and a windows service. I want to use Azure AD for authentication and authorization between the api and the windows service.
My question ist: How can I expose the API, so that I can add the api permissions to the win service with the type "application permissions"?
I can only select "delegated permissions" when I want to add the api permissions to the win service. But I need "application persmissions" because the win service runs without an user.
Thank you in forward!
Best regards
Matthias
Ok. Now I know how to set up the manifest in the app registration. I also get a bearor token and in the bearor token I can see (if I bas64-decode it) the Client ID of the Web API and also the App roles: "roles":["User.Sync2"]
So I think that the token is correct.
In the second step I call the Web API (https://localhost:44358/api/AzureADB2C/Ping) with authentication "Bearor" and the token. But then I receive a 401. (I have not registered any platform in the app registration for the Web API and therefore also no redirect URI. But I think I don't need it?)
Here's the Startup.cs of my Web API project (It's standard generated with Visual Studio):
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace AzureADB2CConnect.API
{
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.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddControllers();
}
// 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();
});
}
}
}
and here is my API Controller:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AzureADB2CConnect.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AzureADB2CController : ControllerBase
{
[HttpGet("Ping")]
[Authorize(Roles = "User.Sync2")]
//[Authorize]
public async void GetPing()
{
//foreach(Claim claim in ClaimsPrincipal.Current.Claims)
//{
//}
}
}
}
If I remove the "Authorized"-Tags I can call the API. And it doesn't matter If I use only Authorize or Authorize(Roles = "User.Sync2") I always receive a 401.
Where is the error/bug?
Thank you in forward!
Here is the decoded bearor token:
That's how I call the GET-Method to get the token:
you need to add app roles. Please follow How to: Add app roles in your application and receive them in the token. App role allowedMemberTypes should include Application.
I can reproduce your problem. You entered the wrong parameters when verifying the token. You need to change Authorized to Authorization and Bearor to Bearer.

No database provider has been configured for this DbContext .NET Core with SQL Server

I have been banging my head against a wall with this one and have been googling to no avail.
I have just started a new ASP.NET Core MVC project, I have installed/updated my packages for these two to 2.2.0:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
I have set the project to expect .NET Core 2.2.0 as well.
I am able to successfully add my table schemas with this command in Package Manager console to scaffold the Database, so I know the connection string is fine/working:
Scaffold-DbContext "SERVER=Server\Instance;DATABASE=Database;UID=user;PWD=password;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Table1, Table2, Table3
The created model file, DatabaseDBContext.cs looks like this:
public partial class DatabaseDBContext : DbContext
{
public DatabaseDBContext()
{
}
public DatabaseDBContext(DbContextOptions<DatabaseDBContext> options)
: base(options)
{
}
}
This also contains a method that works to retrieve my scaffold data, but isn't considered safe for production use so I commented this out:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("SERVER=Server\\Instance;DATABASE=Database;UID=user;PWD=password;");
}
}
I added this same connection string to the appsettings.json file:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"DBConnString": "SERVER=Server\\Instance;DATABASE=Database;UID=user;PWD=password;"
}
}
I then added the DbContext to the startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddDbContext<DatabaseDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBConnString")));
}
Trying to add a new scaffolded controller for one of the tables throws this error:
Finding the generator 'controller'...
Running the generator 'controller'...
Attempting to compile the application in memory.
Attempting to figure out the EntityFramework metadata for the model and DbContext: 'TableName'
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
StackTrace:
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 factory)
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
Has anyone got any clue what I am doing wrong here?
So I fixed but it in a really roundabout way. My new project was originally on an older version of .net core. I had updated the version but there must have been something it didn't like during the update. I created a new project and started it on 2.2.0, then it worked...
The code logic was sound above. Still needed the same packages:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Startup.cs seems quite different, so maybe if anyone else sees this they could try updating the startup.cs code:
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.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<DatabaseDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DatabaseDBConnString")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Had to add a reference to startup.cs for this:
using Microsoft.EntityFrameworkCore;
That was needed for the AddDbContext method to resolve.
After doing this the scaffolding now works. So it's fixed, but it required me to start over to fix it.
I had the same problem and this solved it for me (setting UseSqlServer in OnConfiguring):
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
if (!builder.IsConfigured)
{
string conn = this.IsProduction ? Const.ProductionConnectionString : Const.LocalDBConnectionString;
builder.UseSqlServer(conn);
}
base.OnConfiguring(builder);
}
After battleing with this issue I've encounter the solution for it here
https://github.com/aspnet/EntityFrameworkCore/issues/12331
The problem was that Add-Migration was expecting the CreateWebHostBuilder
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
Before my public static void Main(string[]) was running the WebHost without the static CreateWebHostBuilder and that after I added the Static function then it worked.
I had this problem after I've inlined Program.CreateWebHostBuilder into Program.Main. Had to extract it back.
It was wired but fixed this issue by updating the framework version of the project solution. For example, I created one core repo on 3.0 and later installed the latest version 3.1 on the system so it was expecting to be updated with the latest version. I changed it and it worked!
Try add this 3rd constructor:
public DatabaseDBContext()
{
}
public DatabaseDBContext(DbContextOptions<DatabaseDBContext> options)
: base(options)
{
}
public DatabaseDBContext(DbContextOptions options)
: base(options)
{
}
Then chuck a breakpoint in each one just so you are sure which one is actually getting used.

ASP.NET Core 2.x OnConfiguring get connectionstring string from appsettings.json

Just started messing with ASP.NET Core, pretty impressive so far. In the code generated,(see below). I want to change the hardcoded connection string to get it from the appsettings.json file.
This is apparently impossible. I haven't found a single example that works (or even builds).
What's going on??
Please help
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=xxxxxxx;Database=xxxxx;Trusted_Connection=True;");
}
}
The link provided solves the problem in one area but doesn't work here in OnConfiguring. What am I doing wrong ?
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.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var connection = Configuration.GetConnectionString("ConnectionName");
services.AddDbContext<SurveyContext>(options => options.UseSqlServer(connection));
}
// 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.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In the startup class of a .NET Core project you usually register this in the ConfigureServices function.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourContext>(options => options.UseSqlServer(connection));
}
When you are in the startup class of a .NET Core it is no problem to read the values from appsettings.json.
You could read more at Microsoft, i.e. here: https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db
In the place where you want to access the appsettings.json,
JToken jAppSettings = JToken.Parse(
File.ReadAllText(Path.Combine(Environment.CurrentDirectory,
"appsettings.json")));
Now since you have the object, you can access its contents.
Let me know if it works.
When you use the Scaffold-DbContext, by default it hard codes your string into the DbContext class (so it works out of the box). You will need to register your DbContext in your startup class to proceed. To set this up, you can check the instructions in this answer.
Note that the Configuration property directly connects to your appsettings.json and several other locations. You can read more about it in this documentation. While you can always use the appsettings.json file, it is generally recommended to have your secure secrets in an external json file outside your source code. The best solution for this during development is using the secret manager. The easiest way to use this is right click on your project on visual studio and select "manage user secrets". This will open a json file that is already connected to your Configuration object.
Once this is set up, you need to use dependency injection to access your db context.
public class HomeController : Controller
{
public HomeController(SurveyContext context)
{
// you can set the context you get here as a property or field
// you can use visual studio's shortcut ctrl + . when the cursor is on "context"
// you can then use the context variable inside your actions
}
}
When you use using, it creates a new connection each time. Using injection makes sure only one connection is created per request no matter how many times it is used.