0

Story context

TIP: You could skip this if you are familiar with abp + postgres + IdentityServer, and go to Question

I am currently trying to implement an identity provider using the AspnetBoilerplate.

For this I did the following steps:

You could see my solution here.


Question

At this point I have an functional Identity Provider, but the clients, api resources and identity resources are running in memory as you could see:

//AuthConfigurer.cs#L45

services.AddIdentityServer()
          .AddDeveloperSigningCredential()
          .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
          .AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
          .AddInMemoryClients(IdentityServerConfig.GetClients())
          .AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()
          .AddAbpIdentityServer<User>();

So now I want to put then in EF, for that I tried the following:

//SSODbContext.cs
using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using Coders.SSO.Authorization.Roles;
using Coders.SSO.Authorization.Users;
using Coders.SSO.MultiTenancy;
using Abp.Localization;
using Abp.IdentityServer4;
using IdentityServer4.EntityFramework.Interfaces;
using IdentityServer4.EntityFramework.Entities;
using System.Threading.Tasks;

namespace Coders.SSO.EntityFrameworkCore
{
    public class SSODbContext : AbpZeroDbContext<Tenant, Role, User, SSODbContext>, IAbpPersistedGrantDbContext, IConfigurationDbContext
    {
        /* Define a DbSet for each entity of the application */
        public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
        public DbSet<Client> Clients { get; set; }
        public DbSet<ApiResource> ApiResources { get; set; }
        public DbSet<IdentityResource> IdentityResources { get; set; }

        public SSODbContext(DbContextOptions<SSODbContext> options)
            : base(options)
        {
        }

        // add these lines to override max length of property
        // we should set max length smaller than the PostgreSQL allowed size (10485760)
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            
            modelBuilder.Entity<ApplicationLanguageText>()
                .Property(p => p.Value)
                .HasMaxLength(100); // any integer that is smaller than 10485760

            modelBuilder.ConfigurePersistedGrantEntity();
        }

        public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
    }
}

Applied a new migration and update database, then I changed the service call as following:

services.AddIdentityServer()
          .AddDeveloperSigningCredential()
          .AddConfigurationStore<SSODbContext>()
          .AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()
          .AddAbpIdentityServer<User>();

but didn't work, any idea how to setup Configuration Store on AspNetBoilerplate?

Mirusky
  • 372
  • 3
  • 16
  • think you have to be a bit more specific what what is not working, do you have some clients and resources added to the database? – Tore Nestenius Aug 04 '20 at 11:51
  • This is the problem, I could't setup IdentityServer Configuration Store properly in my EF. I need my application use Configuration Store, then I can use the database to set my clients and resources. – Mirusky Aug 04 '20 at 16:30
  • What error do you get? – Tore Nestenius Aug 04 '20 at 16:48
  • I try to go to discovery documents endpoint `/.well-known/openid-configuration` and I get the following error `InvalidOperationException: No database provider has been configured for this DbContext.` – Mirusky Aug 05 '20 at 17:40
  • Have you applied the migrations and populated the database with both tables and content? can you connect to the database? perhaps create a test DBContext and make some test-queries against the database just to make sure that works. – Tore Nestenius Aug 05 '20 at 19:02
  • My application worked fine before I tried to implement `AddConfigurationStore` ... The tables are in the database, but the way I try to pass DbContext doesn't work – Mirusky Aug 05 '20 at 19:23
  • The problem with all these magic libraries is that its hard to understand them as a beginner. Personally when I added my database layer to my IdentityServer I crated it in my own class library and then copied the code one part at the until it worked and I fully understood it. Its a matter be in control of the database layer. so you own it and understand it. The core storage interfaces for IdentityServer is pretty simple to implement and understand. Especially the config resource as they are purely read-only. – Tore Nestenius Aug 05 '20 at 20:11

2 Answers2

0

Perhaps the problem is that you use an interface here?

.AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()

Should it not be a concrete type instead? Why do you need to have this interface?

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
0

I solved this issue creating my own Stores in Application project inheriting from IdentityServer Stores interfaces, like the Scott Brady said in his blog (Article: Creating Your Own IdentityServer4 Storage Library).

And then I added my stores in Startup like:

services.AddIdentityServer()
    // existing registrations
    .AddClientStore<ClientStoreAppService>()
    .AddCorsPolicyService<CorsPolicyService>()
    .AddResourceStore<ResourcesStoreAppService>()
    .AddPersistedGrantStore<PersistedGrantStoreAppService>()
    .AddDeviceFlowStore<DeviceFlowStoreAppService>(); 

Step by step

  • Create Entities
  • Create Services
  • Create necessary method in each service
  • Register the services in IdentityServer
Mirusky
  • 372
  • 3
  • 16