Skip to content

LionMarc/smusdi-core

Repository files navigation

smusdi-core

build workflow license HitCount NuGet stable version NuGet Downloads

This project provides utility libraries for .NET services.

Smusdi.Core

Bootstrapper for .NET services.

Just add the package as reference and set the following code in program.cs file of your api project:

using Smusdi.Core;

await SmusdiService.InitAndRunAsync(args);

The bootstrapper uses the following environment variables:

  • SMUSDI_SERVICE_NAME: the name of the service which will be used for the appsettings files, the logs files...
  • SMUSDI_APPSETTINGS_FOLDER: this variable setup the folder in which the service can find the appsettings files. If not set, the appsettings files are supposed to be in the working directory;
  • SMUSDI_ENV_FILE: path of .env file used to setup a list of environment variables. If not set, the service try to load variables from file .env. If file does exist, the service does nothing.

The bootstrapper load the following appsettings files:

  • appsettings.json
  • appsettings.{ASPNETCORE_ENVIRONMENT}.json
  • appsettings.{SMUSDI_SERVICE_NAME}.json
  • appsettings.{SMUSDI_SERVICE_NAME}.{ASPNETCORE_ENVIRONMENT}.json
  • SMUSDI_SERVICE_VERSION: used by the info endpoint to send the service version;
  • SMUSDI_CUSTOM_INFOS_FOLDER used by the info endpoint to send custom informations;
  • SMUSDI_EXPAND_ENV_TWICE: if set to true, when reading appsettings variable, we try to expand twice the environment variables in case a variable is set by using another one.

A default appsettings.json file can be found in the samples folder.

Smusdi.Extensibility => Extension Points

The project provides the following extension points:

  • IServicesRegistrator used to register custom services

    public interface IServicesRegistrator : IBaseServicesRegistrator
    {
    }
    
    // Used by Smusdi.Testing to allow overriding some services when testing application
    public interface ITestingServicesRegistrator : IBaseServicesRegistrator
    {
    }
    
    public interface IBaseServicesRegistrator
    {
        IServiceCollection Add(IServiceCollection services, IConfiguration configuration);
    }
  • IWebApplicationConfigurator to add some configuration actions to the web application

    public interface IWebApplicationConfigurator
    {
        WebApplication Configure(WebApplication webApplication);
    }
  • IBeforeRun to execute some actions after the initialization of the host and before it is started

    public interface IBeforeRun
    {
        Task Execute();
    }

    The implementations of IBeforeRun are registered as scoped and executed in a scope. They are only executed when calling the static method SmusdiService.InitAndRunAsync(args), not when calling the method SmusdiService.InitAndRun(args).

  • ISecurityConfigurator to setup api security

    public interface ISecurityConfigurator : IBaseServicesRegistrator
    {
        IApplicationBuilder Configure(IApplicationBuilder app, IConfiguration configuration);
    }

The implementations of these interfaces are automatically executed. There are discovered with scrutor.

Tests and coverage

dotnet test --collect:"XPlat Code Coverage" -r results
dotnet tool run reportgenerator -reports:"results/**/*.xml" -targetdir:coveragereport -reporttypes:html

reportgenerator is installed as a local tool

Publishing as single-file

As reflection is limited when publishing application as a single-file, you have to setup in the appsettings file the list of assemblies in which the controlles or the extensions classes can be found.

See the sample SingleFilePublication.Service.

{
    "smusdi": {
        "assemblyNames": [
          "SingleFilePublication",
          "SingleFilePublication.SomeFeature"
        ]
      }
}

If an assembly can not be found, it is ignored.

Documentation

Response compression

appsettings parameter description default value
compressionDisabled Response compression is active only when false false
compressionDisabledForHttps If true, the compression is not active for HTTPS call false
compressionLevel Enum defining the applied compression level Fastest

Fluent Validation

By default, automatic fluent validation is activated. To disable this feature, set in appsettings the disableAutomaticFluentValidation option to true.

{
    "smusdi": {
        "disableAutomaticFluentValidation": true
    }
}

Smusdi.PostgreSQL

Connection string must be defined as

{
    "ConnectionStrings": {
        "postgresql": "server=%POSTGRES_HOST%;Port=%POSTGRES_PORT%;Database=%POSTGRES_DB%;UserId=%POSTGRES_USER%;Password=%POSTGRES_PASSWORD%;Trust Server Certificate=true;"
    }
}

The Smusdi.PostgreSQL.Testing package creates a new database for each scenario. To do that, it uses the default values below. These values can be overriden in a .runsettings file, for example.

Variable Default value in Smusdi.PostgreSQL.Testing
POSTGRES_HOST localhost
POSTGRES_PORT 5432
POSTGRES_USER postgres
POSTGRES_PASSWORD postgrespw
POSTGRES_DB postgres

The name of the created database is a GUID. The reqnroll hook set the environement variable POSTGRES_DB to that value after the database is created.

The postgres database is the database used to create the database used in tests. It must exist.

The extension GetPostgreSqlSchema of IConfiguration gets the database schema name from the first non null value:

  • configuration key smusdi:postgreSqlSchema;
  • environment varaiable SMUSDI_SERVICE_NAME;
  • constant public.

Smusdi.HttpClientHelpers => HttpClient and Oauth2

The token is managed by the library Duende.AccessTokenManagement.

The configuration is made according to the appsettings section HttpClientsOptions.

Default client

{
  "HttpClientsOptions": {
    "MainClient": {
      "TokenEndpoint": "default_token_endpoint", // For standard openid, it is  {authority_url}/protocol/openid-connect/token
      "ClientId" : "identifier_of_the_client_for_the_provider",
      "ClientSecret": "client_password",
      "Scopes": "default requested scopes",
      "ClientCredentialStyle" : "AuthorizationHeader | PostBody | undefined"
    }
  }
}

These settings are used by the extension method HttpClientHelpers.AddHttpClientWithClientCredentials with a null clientName value.

With named clients

{
  "HttpClientsOptions": {
    "MainClient": {
      "TokenEndpoint": "default_token_endpoint", // For standard openid, it is  {authority_url}/protocol/openid-connect/token
      "ClientId" : "identifier_of_the_client_for_the_provider",
      "ClientSecret": "client_password",
      "Scopes": "default requested scopes",
      "ClientCredentialStyle" : "AuthorizationHeader | PostBody | undefined"
    },
    "NamedClients": {
      "name of the client to be used when registering HttpClient": {
        "TokenEndpoint": "token_endpoint for that client",
        "ClientId" : "identifier_of_the_client_for_the_provider",
        "ClientSecret": "client_password",
        "Scopes": "default requested scopes",
        "ClientCredentialStyle" : "AuthorizationHeader | PostBody | undefined"
      }
    }
  }
}

These settings are used by the extension method HttpClientHelpers.AddHttpClientWithClientCredentials with a clientName equal to the name of the configured client.

The MainClient property must be always set. If not, the process throws at startup.

Smusdi.Security => Oauth providers / JWT bearer

The service can validate input token against more than one provider.

Additional providers can be declared in the appsettings file in the oauth section.

  "Oauth": {
    "Scopes": [
      "scope1",
      "scope2"
    ],
    "MainAuthority": {
      "Name": "Smusdi",
      "Url": "%SMUSDI_OAUTH_URL%",
      "RequireHttpsMetadata": false,
      "Audience": "account"
    },
    "AdditionalAuthorities": [
      {
        "Name": "PSG",
        "Url": "%PSG_OAUTH_URL%/protocol/openid-connect/certs",
        "Issuer": "%PSG_OAUTH_URL%",
        "RequireHttpsMetadata": false,
        "Audience": "account",
        "Type": "Jwks",
        "CacheLifespan": "01:00:00",
        "ValidateIssuer": true, // By default true. If false, issuer in token is not validated against expected one
        "ValidateAudience": true // By default true. If false, audience in token is not validated against expected one"
      }
    ]
  }

The default Audience value is account for both default main authority and additional authority.

The default RequireHttpsMetadata is true.

The Name of the authority is used as authentication scheme. When receiving a token, the scheme is selected based on the issuer set in the token. THe authority to be used is the one whiwh has as Url the issuer set in token.

The Scopes are used to create default authorization policies bases on token scopes.

There are 3 types of authorities:

  • Oauth: all the information are loaded from {Url}/.well-knwon/openid-configuration. This is the default if Type is not set;
  • Jwks: the signing keys are retrieved from Url and stored in cache for CacheLifespan lifespan;
  • Custom: you must register yourself the strategy to be used.

See https://learn.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-8.0#use-multiple-authentication-schemes for details.

Rewriting urls

See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-9.0

If a file urlRewriteRules.txt is found in the current working directory; it is loaded as url rewriting rules in apache format.

The settings is done as first step of the pipeline.

About

.NET base libraries for micro services

Resources

License

Stars

Watchers

Forks

Packages