Skip to content

AuthServer

  • Install GridLab.Abp.Security.Providers.DockerSecrets module.
<ItemGroup>
  <PackageReference Include="GridLab.Abp.Security.Providers.DockerSecrets" Version="X.Y.Z" />
</ItemGroup>

Replace version number with latest available.

Extend dependency list at PSSXAuthServerModule.cs

[DependsOn(
    //...other dependencies
    typeof(AbpZeroTrustModule),
    //
    typeof(PSSXEntityFrameworkCoreModule)
)]
public class PSSXAuthServerModule : AbpModule
{
}

.NET Core configuration provider extensions allows reading docker secrets files and pull them into the .net core configuration.

builder.Host
    .UseAutofac()
    ....
    .UseSerilog((context, services, loggerConfiguration) =>
    {
        loggerConfiguration
#if DEBUG
        .MinimumLevel.Debug()
        .MinimumLevel.Override("DockerSecrets", LogEventLevel.Debug)
#else
        .MinimumLevel.Information()
        .MinimumLevel.Override("DockerSecrets", LogEventLevel.Information)
#endif
        .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
        .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
        .WriteTo.Async(c => c.Console())
    })
    ....
    .ConfigureAppConfiguration((context, config) => {
        if (!context.HostingEnvironment.IsDevelopment())
        {
            config.AddDockerSecrets(
              options: () => new DockerSecretsConfigurationOptions
              {
                  ColonPlaceholder = "__"
              },
              secretsPath: "/run/secrets",
              logger: new SerilogLoggerProvider(Log.Logger).CreateLogger("DockerSecrets")
          );
        }
    })
    ....
  • Add Hangfire support.

Install GridLab.Abp.Hangfire module.

<ItemGroup>
  <PackageReference Include="GridLab.Abp.Hangfire" Version="X.Y.Z" />
</ItemGroup>

Replace version number with latest available.

Add the AbpHangfireModule to the dependency list of your module:

[DependsOn(
    //...other dependencies
    typeof(AbpHangfireModule) 
)]
public class PSSXAuthServerModule : AbpModule
{
}

Configure Hangfire module;

public override void ConfigureServices(ServiceConfigurationContext context)
{
    string serverName = configuration["Hangfire:ServerName"] ?? "pssx-auth-server";
    string schemaName = configuration["Hangfire:SchemaName"] ?? string.Empty;

    string? connectionString = configuration.GetConnectionString(PSSXDbProperties.ConnectionStringHangfireName);

    if (connectionString.IsNullOrEmpty())
        throw new ArgumentNullException(paramName: PSSXDbProperties.ConnectionStringHangfireName);

    var serverStorageOptions = new EFCoreStorageOptions
    {
        CountersAggregationInterval = new TimeSpan(0, 5, 0),
        DistributedLockTimeout = new TimeSpan(0, 10, 0),
        JobExpirationCheckInterval = new TimeSpan(0, 30, 0),
        QueuePollInterval = new TimeSpan(0, 0, 15),
        Schema = schemaName,
        SlidingInvisibilityTimeout = new TimeSpan(0, 5, 0),
    };

    var options = new DbContextOptionsBuilder<PSSXHangfireDbContext>()
        .UseSqlServer(connectionString)
        .Options;

    GlobalConfiguration.Configuration.UseEFCoreStorage(
         () => new PSSXHangfireDbContext(options, schemaName),
         serverStorageOptions
    );

    Configure<AbpHangfireOptions>(options =>
    {
        options.Storage = EFCoreStorage.Current;
        options.ServerOptions = new BackgroundJobServerOptions() { ServerName = serverName };
    });
}

Add a new section for hangfire to application configuration settings.

"Hangfire": {
  "ServerName": "pssx-auth-server"
},

Make sure you have updated your connection strings defined under ConnectionString at appsettings.json file.

"ConnectionStrings": {
  ...
  "Hangfire": "Server=(localdb)\\MSSQLLocalDB;Database=pssx-hangfire;Trusted_Connection=True;TrustServerCertificate=true"
}
  • The versions of npm packages defined in package.json should be checked, where extra npm packages to be used in mvc ui should be defined.
{
  "version": "0.1.0",
  "name": "my-app-authserver",
  "private": true,
  "dependencies": {
    "@volo/abp.aspnetcore.mvc.ui.theme.lepton": "~8.2.0",
    "@volo/account": "~8.2.0"
  }
}

add extra packages if necessary

{
  "version": "0.1.0",
  "name": "my-app-authserver",
  "private": true,
  "dependencies": {
    "@volo/abp.aspnetcore.mvc.ui.theme.lepton": "~8.2.0",
    "@volo/account": "~8.2.0",
    "ace-builds": "^1.4.12",
    "bootstrap-markdown-editor-4": "^3.0.0",
    "jquery-datetimepicker": "^2.5.21",
    "moment": "^2.29.1"
  }
}

In order to run abp install-libs automation scripts, a definition must be made in abp.resourcemapping.js.

module.exports = {
    aliases: {
        "@node_modules": "./node_modules",
        "@libs": "./wwwroot/libs"
    },
    clean: [
        "@libs",
        "!@libs/**/foo.txt"
    ],
    mappings: {
        "@node_modules/bootstrap-markdown-editor-4/dist/css/bootstrap-markdown-editor.min.css": "@libs/bootstrap-markdown-editor-4/css/",
        "@node_modules/bootstrap-markdown-editor-4/dist/js/bootstrap-markdown-editor.min.js": "@libs/bootstrap-markdown-editor-4/js/",
        "@node_modules/ace-builds/src-noconflict/ace.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/theme-tomorrow.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/mode-markdown.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/ext-language_tools.js": "@libs/ace/",
        "@node_modules/moment/moment.js": "@libs/moment/",
        "@node_modules/jquery-datetimepicker/jquery.datetimepicker.js": "@libs/jquery-datetimepicker/",
        "@node_modules/jquery-datetimepicker/jquery.datetimepicker.css": "@libs/jquery-datetimepicker/",
    }
};

Clean wwwroot/libs and node_modules folders for clean installation. This is required action for abp install-libs script.

ABP CLI's abp install-libs command copies resources from node_modules to wwwroot/libs folder. Each standard package (see the @ABP NPM Packages section) defines the mapping for its own files. So, most of the time, you only configure dependencies.

  • Activate clock at PSSXAuthServerModule.cs, default Kind is Unspecified that actually make the Clock as it doesn't exists at all.
public override void ConfigureServices(ServiceConfigurationContext context)
{
    Configure<AbpClockOptions>(options =>
    {
        options.Kind = DateTimeKind.Utc;
    });
}
  • Add the following MSBuild instruction to your GridLab.PSSX.AuthServer.csproj file in order to load .pdb files during debugging.
<Target Name="_ResolveCopyLocalNuGetPackagePdbs" Condition="$(CopyLocalLockFileAssemblies) == true" AfterTargets="ResolveReferences">
  <ItemGroup>
    <ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).pdb')" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and Exists('%(RootDir)%(Directory)%(Filename).pdb')" />
  </ItemGroup>
</Target>
  • Configure OpenIddict library

Add GetSigningCertificate and GetEncryptionCertificate certificate method for handling certificates.

using GridLab.Abp.ZeroTrust;

private X509Certificate2 GetSigningCertificate(ServiceConfigurationContext context, IConfiguration configuration)
{
    var certificateFactory = context.Services.GetCertificateFactory();

    return certificateFactory.CreateFromPkcs12File(
        configuration["App:Certificates:Signing:Path"],
        configuration["App:Certificates:Signing:CertPassphrase"]
    );
}
using GridLab.Abp.ZeroTrust;

private X509Certificate2 GetEncryptionCertificate(ServiceConfigurationContext context, IConfiguration configuration)
{
    var certificateFactory = context.Services.GetCertificateFactory();

    return certificateFactory.CreateFromPkcs12File(
        configuration["App:Certificates:Encryption:Path"],
        configuration["App:Certificates:Encryption:CertPassphrase"]
    );
}

Add GetIssuer and GetAccessTokenLifetime specific library options methods.

private string GetIssuer(IConfiguration configuration)
{
    // Solves bearer was not authenticated. Failure message: IDX10205: Issuer validation failed.
    var issuer = configuration["App:Issuer"]?.Trim();
    var selfUrl = configuration["App:SelfUrl"]?.Trim();

    if (!string.IsNullOrEmpty(issuer))
        return issuer;

    if (!string.IsNullOrEmpty(selfUrl))
        return selfUrl;

    throw new InvalidOperationException("Neither App:Issuer nor App:SelfUrl is provided in configuration.");
}

private TimeSpan GetAccessTokenLifetime(IConfiguration configuration)
{
    var accessTokenLifetimeString = configuration["App:AccessTokenLifetime"]?.Trim();

    var defaultAccessTokenLifetime = TimeSpan.FromHours(1);  // Define a default fallback value (1 hour)

    if (TimeSpan.TryParse(accessTokenLifetimeString, out var accessTokenLifetime))
        return accessTokenLifetime;

    return defaultAccessTokenLifetime;
}
  • Configure caching.

Replace Volo.Abp.Caching.StackExchangeRedis with GridLab.Abp.Caching.StackExchangeValkey module.

Remove:

<ItemGroup>
  <PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="X.Y.Z" />
</ItemGroup>

Add:

<ItemGroup>
  <PackageReference Include="GridLab.Abp.Caching.StackExchangeValkey" Version="X.Y.Z" />
</ItemGroup>

Replace package at PSSXAuthServerModule.cs

[DependsOn(
    //...other dependencies
    ~~typeof(AbpStackExchangeRedisModule),~~
    typeof(AbpStackExchangeValkeyModule),
    //
    typeof(PSSXEntityFrameworkCoreModule)
)]
public class PSSXAuthServerModule : AbpModule
{
}

Add GetRedisConnectionMultiplexer method for handling cache connections.

private ConnectionMultiplexer GetRedisConnectionMultiplexer(
    ServiceConfigurationContext context,
    IConfiguration configuration)
{
    var valkeyConfiguration = configuration["Valkey:Configuration"]!;
    var valkeyOptions = ConfigurationOptions.Parse(valkeyConfiguration);

    valkeyOptions.Password = configuration["Valkey:Connections:Password"];

    if (configuration.GetValue<bool>("Valkey:Connections:Ssl:IsEnabled", false))
    {
        var certificateFactory = context.Services.GetCertificateFactory();
        var certificateValidation = context.Services.GetCertificateValidationService();

        valkeyOptions.Ssl = true;
        valkeyOptions.SslHost = configuration["Valkey:Connections:Ssl:Host"];
        valkeyOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;

        if (!configuration["Valkey:Connections:Ssl:CertPath"].IsNullOrEmpty())
        {
            certificateFactory.CreateFromPkcs12File(
                configuration["Valkey:Connections:Ssl:CertPath"],
                configuration["Valkey:Connections:Ssl:CertPassphrase"]
            );
        }

        // Client side certificate selection, this is going to be used when the server requests validation
        valkeyOptions.CertificateSelection += (sender, host, certificates, certificate, issuers) =>
        {
            return certificateValidation.LocalCertificateSelectionCallback(sender, host, certificateFactory.Certs, certificate, issuers)!;
        };

        // Server side certificate validation
        valkeyOptions.CertificateValidation += (sender, certificate, chain, sslPolicyErrors) =>
        {
            // You can control which type validation errors are acceptable
            return certificateValidation.RemoteCertificateValidationCallback(sender, certificate, chain, sslPolicyErrors);
        };
    }

    return ConnectionMultiplexer.Connect(valkeyOptions);
}

Add a new section for caching to application configuration settings.

"Valkey": {
  "Configuration": "127.0.0.1",
  "Connections": {
    "Password": "",
    "Ssl": {
      "IsEnabled": "false"
    }
  }
},
  • Add new PSSXBrandingProvider.cs cs file to project root directory at GridLab.PSSX.AuthServer project.

Copy the wwwroot folder from template folder to the src/GridLab.PSSX.AuthServer folder.

Delete existing logo-dark.png and logo-dark.png logos

[Dependency(ReplaceServices = true)]
public class PSSXBrandingProvider : DefaultBrandingProvider
{
    private IStringLocalizer<PSSXResource> _localizer;

    public PSSXBrandingProvider(IStringLocalizer<PSSXResource> localizer)
    {
        _localizer = localizer;
    }

    public override string AppName => "PSSX Auth Server";

    public override string LogoUrl => "/images/logo/leptonx/logo-light.png";

    public override string LogoReverseUrl => "/images/logo/leptonx/logo-dark.png";
}