Compare commits

..

159 Commits

Author SHA1 Message Date
Developer 02
4f5a33f7ec Support multiple target frameworks in project file
Updated `DigitalData.Auth.API.csproj` to target both `net7.0` and `net8.0`.
Replaced `TargetFramework` with `TargetFrameworks` for multi-targeting.
Conditionally included `Microsoft.AspNetCore.Authentication.JwtBearer` based on the target framework version.
Added a project reference to `DigitalData.Auth.Abstractions`.
2025-05-10 10:24:12 +02:00
Developer 02
ae28159562 Bump version to 1.2.0 in DigitalData.Auth.API.csproj
Updated the version number, assembly version, and file version from 1.1.2 to 1.2.0 in the project file, reflecting a new release of the software.
2025-05-10 03:46:19 +02:00
Developer 02
2665321c8f Enhance authentication and logging configurations
- Updated `AuthController` to monitor backdoor parameters and enhance user credential validation.
- Changed route for `Hash` method in `CryptController` for clarity.
- Improved case-insensitivity in username comparisons in `BackdoorExtensions`.
- Modified logging setup in `Program.cs` to clear providers and set minimum level to Trace.
- Added separate logging configuration for warnings in `appsettings.json`.
- Restructured `backdoors.json` to encapsulate entries within `BackdoorParams`.
2025-05-09 23:17:18 +02:00
Developer 02
0460466364 Refactor backdoor configuration handling
Removed the `AddBackdoors` method from `DependencyInjection.cs` and replaced its usage in `Program.cs` with `Configure<Backdoor>`. Updated `using` directives to include `Microsoft.Extensions.DependencyInjection`. Added a new `BackdoorParams` class to encapsulate backdoor configuration settings.
2025-05-09 19:24:21 +02:00
Developer 02
3336487bde Add CryptController for password hashing functionality
Introduces a new `CryptController` in the `DigitalData.Auth.API.Controllers` namespace. This API controller features a GET endpoint, `Hash`, which accepts a password as a query parameter and returns its BCrypt hashed version.
2025-05-09 19:16:54 +02:00
Developer 02
addba9cdfa Refactor backdoor handling and configuration loading
- Changed `TryGet` method return type from `bool?` to `bool` in `BackdoorExtensions.cs` for improved clarity.
- Updated configuration retrieval in `DependencyInjection.cs` to use `GetSection("backdoors")` for targeted loading.
- Added `backdoors.json` configuration file in `Program.cs` to enhance modularity and organization of settings.
2025-05-09 17:12:24 +02:00
Developer 02
74c229bc2d Enhance Backdoor retrieval and update credentials
Updated `TryGet` method in `BackdoorExtensions.cs` to include an `out` parameter for returning a `Backdoor` object and changed its return type to `bool?`. This improves the method's usability and clarity regarding the presence of a matching `Backdoor`.

Modified `backdoors.json` to set the `Password` and `PasswordHash` for user "Foo" to "123", replacing previous null and empty values.
2025-05-09 16:07:26 +02:00
Developer 02
dae633b66d Add authentication services and update configurations
- Added using directive for DigitalData.Auth.API.Models.
- Removed obsolete service configuration line.
- Introduced new service registrations: AddBackdoors, AddAuthService, and AddRSAPool.
- Retained configuration for AuthApiParams to ensure settings are utilized.
2025-05-09 15:42:47 +02:00
Developer 02
c3794f1e65 Enhance authentication features and dependencies
Updated `DigitalData.Auth.API.csproj` to include new package references for improved security and functionality. Added a `Verify` method in the `Backdoor` class to securely check user credentials against plain text and hashed passwords. Introduced `BackdoorExtensions` with methods for easier retrieval of `Backdoor` instances by username.
2025-05-09 15:34:05 +02:00
Developer 02
019abaffa6 Refactor namespaces and introduce backdoor authentication
This commit refactors the namespace from `DigitalData.Auth.API.Dto` to `DigitalData.Auth.API.Models` in several files, improving the organization of data structures. A new `Backdoor` class is added to support backdoor authentication, along with a method in `DependencyInjection.cs` to register backdoor configurations. Additionally, `AuthApiParams` configuration is included in `Program.cs`, and a new JSON structure for backdoor users is introduced in `backdoors.json`. These changes enhance the codebase's structure and functionality.
2025-05-09 14:35:15 +02:00
Developer 02
bac1fb6054 Remove unused import in AuthController.cs 2025-05-05 10:17:40 +02:00
Developer 02
2c330a9dff refactor: Hinzufügen des Token-Deskriptors, der mit sign-flow-gen erstellt wurde 2025-04-29 11:45:10 +02:00
Developer 02
d3b8f400e5 chore (Clent): Aktualisiert auf 1.3.7 2025-04-28 14:01:37 +02:00
Developer 02
358cfdb707 fix: Behandlung von leeren PEM-Inhalten in der ClientPublicKey-Klasse
- Die UpdateContent-Methode wurde aktualisiert, um den SecurityKey zurückzusetzen, wenn der PEM-Inhalt leer oder mit Leerzeichen versehen ist.
- Es wurde sichergestellt, dass ein neuer RSA-Schlüssel erstellt wird, wenn der Inhalt ungültig oder nicht vorhanden ist.
2025-04-28 12:45:15 +02:00
Developer 02
cf375a587e feat(DIExtensions): rename DependencyInjection 2025-04-28 11:24:11 +02:00
Developer 02
a429c65ead feat: Unterstützung für .NET 9.0 hinzugefügt und Paketversion auf 1.3.6 aktualisiert
- net9.0 zu TargetFrameworks hinzugefügt.
- Paketverweise für Microsoft.AspNetCore.SignalR.Client und Microsoft.Extensions.Hosting.Abstractions, die auf net9.0 abzielen, hinzugefügt.
- Bumped Package Version, AssemblyVersion und FileVersion auf 1.3.6.
2025-04-28 10:03:41 +02:00
Developer 02
79aebe4ef7 chore(IISProfile): Hinzugefügt, um die Standard-IIS-Konfiguration zu implementieren 2025-03-25 15:41:50 +01:00
Developer 02
b4366e5bbb chore: Nuget-Pakete werden je nach Rahmenwerk bedingt konfiguriert. 2025-03-25 12:38:01 +01:00
Developer 02
fab002a20c chore Upgrade auf 1.1.2 2025-03-17 11:01:21 +01:00
Developer 02
51492110a7 refactor(DigitalData.Auth.Client): DigitalData.Core.Security wurde auf 1.1.1 aktualisiert. 2025-03-17 10:59:54 +01:00
Developer 02
421f2657dd refactor(DigitalData.Auth.Client): DigitalData.Core.Security wurde auf 1.1.0 aktualisiert. 2025-03-17 10:02:52 +01:00
Developer 02
a77c70f655 refactor(AuthClient): Hochgestuft auf 1.3.3 2025-03-12 10:50:35 +01:00
Developer 02
031f830b8f refactor(AuthClient): Detaillierte Protokollierung für AuthClient hinzugefügt. 2025-03-12 10:47:15 +01:00
Developer 02
5f9efa3bb0 refactor(AuthClient): Ausführlichere Protokollierung hinzufügen. 2025-03-12 10:27:06 +01:00
Developer 02
d46dbbb877 refactor(ClientParams): Die Eigenschaft NextRetryDelay wurde entfernt, um die Logik zu vereinfachen. 2025-03-12 09:48:27 +01:00
Developer 02
e194cd8054 feat: Implementierung der Wiederholungslogik für den Verbindungsaufbau in AuthClient
- Hinzugefügt: `TryStartConnectionAsync`-Methode zur Durchführung von Verbindungsversuchen mit Wiederholungslogik.
- `StartAsync` aktualisiert, um wiederholt zu versuchen, die Verbindung herzustellen, bis sie erfolgreich ist oder `RetryDelay` erschöpft ist.
2025-03-12 09:32:10 +01:00
Developer 02
d21e0c06e7 chore(API): Hochgestuft auf 1.1.0 2025-03-12 08:58:26 +01:00
Developer 02
dd62af5ada feat(DIExtensions): Hinzufügen einer Ausnahmemeldung. 2025-03-11 16:32:56 +01:00
Developer 02
b4068eff8e chore(client): Hochgestuft auf 1.2.0 2025-03-11 15:58:50 +01:00
Developer 02
3b0428130a feat(AuthClient): implementiert IHostedService.
- Aktualisiert um AuthClient zu den Diensten als Hosted Service hinzuzufügen.
 - Der zugehörige Unit-Test wurde aktualisiert, um IHost anstelle von IServiceProvider zu verwenden, um gehostete Dienste testen zu können.
2025-03-11 15:53:37 +01:00
Developer 02
4ccf7a20b3 feat(AuthClient): try-start entfernen und Abbruch-Token hinzufügen, um asynchron zu starten 2025-03-11 14:50:10 +01:00
Developer 02
29ad0554bc fix(ConfiguredConsumerService): Dienst als Liste anstelle von IEnumerable hinzufügen 2025-03-10 17:31:49 +01:00
Developer 02
583864469c refactor(UserLogin): Id umbenannt in UserId 2025-03-10 17:05:05 +01:00
Developer 02
85ccc52ca1 feat(AuthController): Aktualisiert, um die Anmeldung über die Benutzer-ID zu ermöglichen. 2025-03-10 16:58:34 +01:00
Developer 02
a69e13c2ab feat: Logging für unerwartete Ausnahmen hinzugefügt, um eine bessere Fehlerverfolgung und Problemlösung zu gewährleisten. 2025-03-10 15:39:34 +01:00
Developer 02
8ef879a663 feat: NLog hinzugefügt und konfiguriert 2025-03-10 15:22:35 +01:00
Developer 02
ef6d834448 refactor(ClientPublicKey): made UpdateContent internal 2025-03-10 15:01:57 +01:00
Developer 02
1db1b35f3c refactor: Entfernen des redundanten Abrufs des Konfigurationsabschnitts in AddAuthHubClient
- Entfernt den unnötigen Aufruf von `GetSection(nameof(ClientParams))` beim Abrufen von `ClientParams` aus der Konfiguration, was die Logik vereinfacht und die Klarheit verbessert.
2025-03-10 09:27:20 +01:00
Developer 02
74444d301d feat(ClientPublicKey): implementiert IUniqueSecurityContext 2025-03-07 16:11:36 +01:00
Developer 02
2378b93579 chore(Client): Hochgestuft auf 1.1.3 2025-03-07 15:22:23 +01:00
Developer 02
85a047467e refactor: AsymmetricPublicKey durch ClientPublicKey ersetzt und RSA-Schlüsselverwaltung verbessert
- `AsymmetricPublicKey` in `ClientPublicKey` umbenannt
- `ClientPublicKey` von `RSAKeyBase` abgeleitet für RSA-Funktionalität
- Dynamischen PEM-Import in `UpdateContent` hinzugefügt
2025-03-07 15:21:31 +01:00
Developer 02
106d31b068 feat(DIExtensions): Optionale IConfiguration-Eingabe hinzugefügt, um AddAuthHubClient mit Hilfe von Appsettings konfigurieren zu können 2025-03-07 13:25:40 +01:00
Developer 02
48f5c69c91 fix(ClientParams): Umbenennung von OnMessageReceived in OnPublicKeyReceived 2025-03-07 12:52:21 +01:00
Developer 02
0235f81003 chore: Aktualisierte Abstraktionen und Client 1.0.0 2025-03-07 12:12:28 +01:00
Developer 02
01613f2e46 fix(AuthClientTests): Erstellt Reconnected_ShouldUpdateAllPublicKey Methode um den Wiederholungsprozess im Falle eines Verbindungsabbruchs zu testen
- Erstellte _port Variable um den Port der _app zu halten.
 - Convert_tokenDescriptors Array in CreatetokenDescriptors Methode um _tokenDescriptors zufällig zu generieren.
 - CreateWebApplication-Methode erstellt, um die Webanwendung in Testmethoden generieren zu können
2025-03-07 12:09:39 +01:00
Developer 02
6ac2c86520 fix(AuthClientTests): StartAsync_ShouldUpdateAllPublicKey aktualisiert 2025-03-07 10:17:48 +01:00
Developer 02
4e941ed35f feat(AuthClientTests): StartAsync_ShouldUpdateAllPublicKey Testmethode hinzufügen, um zu testen, ob der öffentliche Schlüssel nach StartAsync aktualisiert wird 2025-03-07 09:49:48 +01:00
Developer 02
e925c175a0 refactor(ClientParams): OnMessageReceived aktualisieren, damit es mit UpdatePublicKeys initialisiert wird 2025-03-06 17:02:30 +01:00
Developer 02
eaf41adb58 refactor: OnMessageReceived in ein Ereignis umgewandelt für bessere Ereignisbehandlung
- `OnMessageReceived` von einem Delegaten in ein Ereignis umgewandelt, um die Ereignisabonnierung und -behandlung zu verbessern.
2025-03-06 16:54:50 +01:00
Developer 02
a2c74cbdd9 feat: Refaktorierung von ClientEvents zur Verwendung eines Delegaten für öffentliche Schlüsselaktualisierungen
- Ersetzt `Action<string, string, string, ILogger?>` durch den `ClientEvent`-Delegaten für eine bessere Struktur.
- `ClientEvent`-Delegaten mit `AuthClient`-Referenz eingeführt, um öffentliche Schlüssel direkt zu aktualisieren.
2025-03-06 16:48:47 +01:00
Developer 02
63c37551be feat(AsymmetricPublicKey): Zur Vereinfachung nach Auth.Client verschoben 2025-03-06 14:32:23 +01:00
Developer 02
6198008475 feat(AuthClient): implementierte Methode PublicKeys.get
- GetAllPublicKeysAsync Methode hinzugefügt, um GetPublicKeyAsync Methode für jeden öffentlichen Schlüssel aufzurufen.
 - Aktualisiert, um GetAllPublicKeysAsync Methode nach erfolgreichem Start und Wiederverbindung aufzurufen
2025-03-06 14:18:55 +01:00
Developer 02
8682f1f9e0 feat(AsymmetricPublicKey): zu Abstractions.Models hinzugefügt, um den Empfang öffentlicher Schlüssel zu behandeln.
- AsymmetricPublicKey-Liste mit dem Namen Public Keys zu IAuthClient hinzugefügt.
2025-03-06 13:59:40 +01:00
Developer 02
fb486296f2 fix(AuthClientTest): den Methodennamen aktualisiert, um den Pascal-Fall zu implementieren 2025-03-05 16:23:58 +01:00
Developer 02
aa2572fd17 fix(ClientExtensions): entfernt 2025-03-05 16:22:39 +01:00
Developer 02
7153d6ec46 fix(AuthClient): remove _lazyInitiator 2025-03-05 15:57:56 +01:00
Developer 02
4e3448b4d4 refactor(AuthClient): Entfernen von ConnectionError und Aktualisierung von tryStartAsync zur Protokollierung 2025-03-05 15:53:57 +01:00
Developer 02
36891b5abb feat(AuthClientTests): Added GetpublicKey_ShouldReturnExpectedPublicKey to test GetPublicKeyAsync method of AuthHub 2025-03-05 15:31:24 +01:00
Developer 02
6664a1f342 fix(AuthClientTests): Abhängigkeiten hinzufügen 2025-03-05 14:43:56 +01:00
Developer 02
b2a287cab5 feat(DIExtensions): Add memory cache. 2025-03-05 13:24:03 +01:00
Developer 02
db52e97d03 feat(AuthClient): Added GetPublicKeyAsync method to handle client request to get the key 2025-03-05 13:09:29 +01:00
Developer 02
4c001d4087 feat(AuthHub): Added GetPublicKeyAsync method to send the key to caller 2025-03-05 13:06:07 +01:00
Developer 02
3c37176d5e Reapply "feat(IAuthSenderHandler): GetPublicKeyAsync hinzugefügt, um den öffentlichen Schlüssel des Aufrufers zu aktualisieren"
This reverts commit 0935573b93.
2025-03-05 11:57:18 +01:00
Developer 02
0935573b93 Revert "feat(IAuthSenderHandler): GetPublicKeyAsync hinzugefügt, um den öffentlichen Schlüssel des Aufrufers zu aktualisieren"
This reverts commit f30f1f127d.
2025-03-05 11:56:00 +01:00
Developer 02
f30f1f127d feat(IAuthSenderHandler): GetPublicKeyAsync hinzugefügt, um den öffentlichen Schlüssel des Aufrufers zu aktualisieren 2025-03-04 12:25:49 +01:00
Developer 02
1fe3fb9008 refactor: IAuthListenHandler und IAuthSenderHandler aktualisiert, um Issuer und Audiance anstelle von Name zu verwenden 2025-03-04 12:20:26 +01:00
Developer 02
d21da5028e Revert "refactor(AuthHub): SendKeyAsync aktualisiert, um Caller anstelle von All zu verwenden"
This reverts commit 062942b2d2.
2025-03-04 11:53:05 +01:00
Developer 02
062942b2d2 refactor(AuthHub): SendKeyAsync aktualisiert, um Caller anstelle von All zu verwenden 2025-03-04 11:45:44 +01:00
Developer 02
c47197606b Revert "feat: Hinzufügen der Methode GetPublicKeyAsync zu IAuthListenHandler und IAuthSenderHandler"
This reverts commit 137ccaa563.
2025-03-04 10:16:23 +01:00
Developer 02
137ccaa563 feat: Hinzufügen der Methode GetPublicKeyAsync zu IAuthListenHandler und IAuthSenderHandler 2025-03-04 09:20:36 +01:00
Developer 02
4062fe750a refactor(IAuthSenderHandler): rename subject input to name. 2025-03-03 16:09:15 +01:00
Developer 02
cb6ec8b5e6 feat(DigitalData.Auth): configured package properties of Abstractions and Client 2025-03-03 16:04:11 +01:00
Developer 02
7873542aca fix(DIExtensions): ConsumerOptions-Eingabe in AddAuthService-Methode hinzugefügt, um Konsuemrn nach der Übernahme aus der Config arrangieren zu können.
- Standardiezd consumerKey Benennung
2025-02-11 13:20:54 +01:00
Developer 02
6694e4b626 feat(AuthHubTests): Erstellt, um Hub und Melder zu testen 2025-02-11 11:05:46 +01:00
Developer 02
0cce082cb7 refactor(RetryPolicy): Ungenutzte Eigenschaft entfernt 2025-02-11 10:34:57 +01:00
Developer 02
7f39cbe24a feat(AuthClient): Konfiguration der Wiederholungsrichtlinie im Falle eines Verbindungsverlustes hinzugefügt. 2025-02-11 10:33:37 +01:00
Developer 02
484cc86a29 feat(Melder): Erstellt, um aktuelle Schlüssel an den Kunden zu senden 2025-02-11 09:38:11 +01:00
Developer 02
5ab1f24ce5 feat: Aktualisiert, um Token durch Query-String zu behandeln 2025-02-11 08:56:29 +01:00
Developer 02
33ead6ebf4 fix: UniqueName aktualisiert, um den Benutzernamen in den Ansprüchen des Benutzernamens zu halten. 2025-02-10 14:09:15 +01:00
Developer 02
64717fbba5 fix(AuthClientTests): Aktualisiert um Anbieter zu entsorgen 2025-02-05 10:38:45 +01:00
Developer 02
b6d86d3d0d fix(AuthClient): Aktualisiert, um GC.SuppressFinalize in DisposeAsync zu verwenden 2025-02-05 10:26:51 +01:00
Developer 02
5f9926e911 refactor(AuthClientTests): Umbenennung der Variablennamen 2025-02-04 20:50:34 +01:00
Developer 02
319763040c refactor(ISenderHandler): Umbenennung in IAuthSenderHandler.
- umbenannt in SendMessageAsync als SendKeyAsync
2025-02-04 20:45:01 +01:00
Developer 02
e474cf38d4 feat(AuthClient): implementiert IAsyncDisposable 2025-02-04 20:41:20 +01:00
Developer 02
5092890f14 fix(AuthClientTest): Ersetzte client_receiver.ReceiveMessageAsync Aktion mit sender_client.SendMessageAsync in ReceiveMessage_ShouldCallOnMessageReceived Test
- Verzögerung für die Dauer des Nachrichtenempfangs in ReceiveMessage_ShouldCallOnMessageReceived hinzugefügt.
2025-02-04 20:01:51 +01:00
Developer 02
27c2c0b4cb refactor(IAuthClientHandler): umbenannt in IListenHandler 2025-02-04 19:47:40 +01:00
Developer 02
9d609dd5ac feat(ISenderHandler): Erstellt um Absenderaktionen an den Hub zu behandeln
- Eingebaut in AuthHub und AuthClient
2025-02-04 19:40:09 +01:00
Developer 02
360d91353b Revert "feat(AuthClientTests): Es wurde eine clientPool-Warteschlange erstellt, um die Injektion von Abhängigkeiten und die Bereitstellung von Diensten zu trennen."
This reverts commit 5886e076f4.
2025-02-04 16:09:19 +01:00
Developer 02
7c5a545926 Revert "fix(AuthClientTests): aktualisiert, um Enqueue-Methode zu verwenden, um neue Instanzen zum clientPool hinzuzufügen"
This reverts commit 18d7c475ff.
2025-02-04 16:08:26 +01:00
Developer 02
18d7c475ff fix(AuthClientTests): aktualisiert, um Enqueue-Methode zu verwenden, um neue Instanzen zum clientPool hinzuzufügen 2025-02-04 10:49:37 +01:00
Developer 02
5886e076f4 feat(AuthClientTests): Es wurde eine clientPool-Warteschlange erstellt, um die Injektion von Abhängigkeiten und die Bereitstellung von Diensten zu trennen.
- Dies macht die Messung realistischer.
2025-02-04 10:48:04 +01:00
Developer 02
8e979fa14d feat(AuthClientTests): Testserver hinzugefügt 2025-02-04 10:11:34 +01:00
Developer 02
5aab46a221 refactor(tests): Verbesserung der Nachrichtenbehandlung und Assert-Bedingungen in AuthClientTests
- Vereinfachte Assertions in StartAsync_ShouldConnectSuccessfully durch Entfernen expliziter Strings
- Aktualisierte ReceiveMessage_ShouldCallOnMessageReceived, um Nachrichteninhalte zu überprüfen
- Refaktorisierte Variablennamen in ReceiveMessage_ShouldCallOnMessageReceived für bessere Verständlichkeit
2025-02-03 17:09:57 +01:00
Developer 02
9fee7ea381 feat(tests): Refaktorierung und Erweiterung von AuthClientTests für Verbindungs- und Nachrichtenbehandlung
- Ersetzte das statische Setup für die Client-Erstellung durch eine wiederverwendbare Build-Methode.
- Ein neuer Test `StartAsync_ShouldConnectSuccessfully` wurde hinzugefügt, um den Verbindungsaufbau zu überprüfen.
- Refactored `ReceiveMessage_ShouldCallOnMessageReceived` für die Einrichtung mehrerer Clients (Sender und Empfänger).
- Konsolidierte hartkodierte URL in eine wiederverwendbare Konstante `HubUrl`.
2025-02-03 16:53:46 +01:00
Developer 02
cfe5df4b1d feat(IAuthClient): IsConnected, ConnectionError und ConnectionError Eigenschaften hinzugefügt.
- Umwandlung der Eigenschaft IsConnectionFailed in eine Erweiterungsmethode.
2025-02-03 16:38:22 +01:00
Developer 02
31ccd93b0d refactor(AuthClient): Enhance AuthClient with lazy initialization and connection error handling
- Replaced immediate connection start with lazy initialization via Lazy<Task<bool>>.
- Added IsConnected and ConnectionError properties to track connection status and errors.
- Introduced TryStartAsync method to safely attempt connection startup without throwing exceptions.
2025-02-03 16:22:41 +01:00
Developer 02
48970a1e13 refactor(AuthClientTests): Methode durch einen statischen Readonly-Delegaten für den Service Provider ersetzen 2025-02-03 15:42:46 +01:00
Developer 02
0614b205bd feat(IAuthClientHandler): Umbenennung der Methode ReceiveMessage in ReceiveMessageAsync 2025-02-03 15:39:30 +01:00
Developer 02
b533634e14 feat(AuthClientTests): ReceiveMessage_ShouldCallOnMessageReceived Testmethode hinzugefügt.
- Angeordnete Abhängigkeiten
2025-02-03 15:37:19 +01:00
Developer 02
766e4e6d27 feat(IAuthClientHandler): getrennte Klasse erstellt, um die Hub-Aktion von IAuthClient zu unterteilen
- ReceiveMessage-Methode zu IAuthClientHandler verschoben
 - StartAsync-Methode zu IAuthClient hinzugefügt
2025-02-03 14:51:13 +01:00
Developer 02
878e927be9 refactor: ReceiveMessage yöntemini ayrı bir görevde asenkron olarak çalışacak şekilde değiştirin
- ReceiveMessage çağrısı, asenkron olarak yürütülmesini sağlamak için Task.Run'a sarılacak şekilde güncellendi.
2025-02-03 14:44:28 +01:00
Developer 02
24a0efb979 Revert "fix(AuthClient): Konvertiere den Rückgabetyp von ReceiveMessage von Nachricht zu"
This reverts commit 8e450f7934.
2025-02-03 14:40:35 +01:00
Developer 02
8e450f7934 fix(AuthClient): Konvertiere den Rückgabetyp von ReceiveMessage von Nachricht zu 2025-02-03 14:35:46 +01:00
Developer 02
77bbcfe4f1 refactor(ClientEvents): OnMessageReceived in Action umwandeln 2025-02-03 13:53:10 +01:00
Developer 02
c8eacc1d54 feat(AuthClientTests): Initalisiert. 2025-02-03 13:49:35 +01:00
Developer 02
bea08ce06c feat(Client.DIExtensions): Methode zur Behandlung von Dependency Injection erstellt 2025-02-03 13:36:59 +01:00
Developer 02
bf12c889f3 feat(Auth.Client): Erstellt, um Client (Consumer) Ereignisse von SignalR zu behandeln.
- Erstellt ClientParams um AuthClient zu konfigurieren.
 - Erstellt ClientEvents, um Ereignisse im Client zu konfigurieren.
2025-01-24 14:51:02 +01:00
Developer 02
a2f4fcfbe0 feat(AuthHub): IAuthClient als Client Typ implementiert.
- SendMessage, SendMessageToCaller und SendMessageToGroup Methoden hinzugefügt.
2025-01-23 15:55:28 +01:00
Developer 02
6245a94f43 fix(IAuthClient): umbenannt in IAuthClient 2025-01-23 15:38:24 +01:00
Developer 02
f562690b19 feat(Abstraktionen): Erstellt, um gemeinsame Schnittstellen zwischen Clients und Hubs für stark typisierte Hubs zu handhaben, um mögliche Fehler zu vermeiden. 2025-01-23 15:36:50 +01:00
Developer 02
54ecf1f4da feat(Auth.Tests): Erstellt, um Einheitstests für alle Projekte zu verwalten. 2025-01-23 14:35:35 +01:00
Developer 02
3a79bb7984 feat(Auth.Client): Erstellung einer Klassenbibliothek zur Handhabung von .net-Client-Diensten für SignalR.
- Microsoft.AspNetCore.SignalR.Client Paket hinzugefügt.
2025-01-23 13:53:57 +01:00
Developer 02
98a4e2ba5c feat(AuthHub): Erstellt, um eine zweidimensionale Verbindung zwischen API und Konsumenten herzustellen.
- Microsoft.AspNetCore.SignalR Paket hinzugefügt.
 - SignalR Dienst hinzugefügt und aktualisiert um AuthHub abzubilden.
2025-01-23 13:46:37 +01:00
Developer 02
efae188d5c refactor(ConsumerService): Entfernt ReadLocalAsync Methode.
- LocalConsumer Eigenschaft in AuthApiParams hinzugefügt.
2025-01-23 10:31:27 +01:00
Developer 02
f77a68be8d feat(Consumer): CookieName-Eigenschaft hinzugefügt. 2025-01-22 16:01:54 +01:00
Developer 02
b25c9538a4 feat(ConfiguredConsumerService): ReadLocalAsync Methode hinzugefügt, um den Verbraucher von Auth.API zu erhalten 2025-01-22 15:53:48 +01:00
Developer 02
17c00240a6 refactor(Consumer): Eigenschaft CookieOptionsProvider hinzugefügt. 2025-01-22 14:49:43 +01:00
Developer 02
79e3dbd5d8 refactor(Verbraucher): Getrennte ID und Name hinzugefügt. 2025-01-22 13:35:08 +01:00
Developer 02
8b5c477b2b refactor(ConsumerApi): umbenannt in Consumer 2025-01-22 11:37:31 +01:00
Developer 02
0a61586e39 refactor(ConsumerApi): umbenannt in Consumer mit LoginDto.
- ConsumerApi.Name umbenannt in Id
 - Eigenschaft audience hinzugefügt.
2025-01-21 17:13:53 +01:00
Developer 02
47aeb49a40 feat(ClaimExtensions): Ermöglicht die Bereitstellung von Methoden zum Abrufen spezifischer Ansprüche. 2025-01-21 16:38:09 +01:00
Developer 02
a1f996b328 feat: DependentExtensions für extensions mit Abhängigkeiten hinzugefügt
- Methoden `AddDependentExtensions` und `TryGetByRoute` hinzugefügt, um die Konfiguration von `AuthApiParams` und das Abrufen von Deskriptoren zu ermöglichen.
2025-01-21 15:23:22 +01:00
Developer 02
110b102926 refactor(Verbraucher): Als Unterklasse zur AuthApiParams-Klasse verschoben, um die Komplexität zu reduzieren 2025-01-21 14:17:50 +01:00
Developer 02
ddc55e0fd9 fix: Um das Problem der Abhängigkeit von Microsoft.IdentityModel.Tokens zu lösen, wurde System.IdentityModel.Tokens.Jwt.
- Aktualisierte benötigte Pakete
2025-01-21 13:21:51 +01:00
Developer 02
c4f1a9498b refactor(AuthController): Die Nullbarkeit in TryGet Methoden wurde entfernt. 2025-01-20 16:58:01 +01:00
Developer 02
ffad37a517 feat(auth): Endpunkt-Routen für Login konsistenter gemacht
- `~/login` zu `login` und `~/{consumerRoute}/login` zu `{consumerRoute}/login` geändert.
2025-01-20 14:44:53 +01:00
Developer 02
ccd716badb chore: UserManager aktualisiert, um stringLocalizer-Abhängigkeit zu entfernen 2025-01-20 14:43:10 +01:00
Developer 02
077635e94b feat(AuthController): ValidateCredentials Methode async in CreateTokenAsync Methode gemacht.
- Core.Abstractions auf 3.2 aktualisiert
 - Core.Application 3.2 hinzugefügt
2025-01-20 10:45:03 +01:00
Developer 02
c6c4d0bd04 refactor(ConsumerApi): In das Verzeichnis „Entities“ verschoben. 2025-01-20 10:13:01 +01:00
Developer 02
a73885286f fix: Aktualisiert, um die Konfiguration über consumers-api.json zu ermöglichen. 2025-01-20 10:09:13 +01:00
Developer 02
d6315ce8a5 chore: Initiliazed Version als 1.0.0.
- Funktionalität zum Ausführen von Swagger in der Produktion hinzugefügt.
2025-01-17 13:49:40 +01:00
Developer 02
7bab2657d4 feat(AuthController): Login-Methode mit Body für Verbraucher-APIs hinzugefügt. 2025-01-15 13:55:47 +01:00
Developer 02
79eaa06ed4 feat(AuthController): Login-Methode für Verbraucher-APIs hinzugefügt. 2025-01-15 13:48:58 +01:00
Developer 02
69efe28310 chore: Added directory search service 2025-01-15 13:17:56 +01:00
Developer 02
cd4428b8f0 reparieren: App-Einstellungen so angeordnet, dass sie Consuemr-Apis erreichen können 2025-01-15 12:58:42 +01:00
Developer 02
a66570bebb feat(AuthController): Erstellt, um Token für Benutzer von UserManager bereitzustellen. 2025-01-15 12:53:51 +01:00
Developer 02
0a3e1566eb Reapply "chore: issuerSigningKeyInitiator konfiguriert, um SecuritKey zu erhalten."
This reverts commit de296d34f3.
2025-01-15 11:02:56 +01:00
Developer 02
de296d34f3 Revert "chore: issuerSigningKeyInitiator konfiguriert, um SecuritKey zu erhalten."
This reverts commit 314bb08125.
2025-01-15 11:01:27 +01:00
Developer 02
314bb08125 chore: issuerSigningKeyInitiator konfiguriert, um SecuritKey zu erhalten. 2025-01-15 11:00:48 +01:00
Developer 02
9c5c0dc61b chore: Eintragungspunktträger in Swagger hinzugefügt 2025-01-15 10:56:33 +01:00
Developer 02
3231aa3299 feat(JwtSignatureHandler): Für Benutzer von in UserManager hinzugefügt. 2025-01-15 10:54:40 +01:00
Developer 02
9d35881327 feat(JwtSignatureHandler): Hinzugefügt für ConsumerApi. 2025-01-15 10:33:16 +01:00
Developer 02
f898d8c4a4 feat(CryptoFactory): Hinzugefügt und in appsettings.json konfiguriert. 2025-01-15 10:30:48 +01:00
Developer 02
82f23d447b chore: Authentifizierung mit layz loading hinzugefügt. 2025-01-15 10:25:51 +01:00
Developer 02
b1bfc46a60 feat(DIExtensions): Zur Verwaltung von Abhängigkeitsinjektionen von ConsumerAPiService. 2025-01-15 10:19:25 +01:00
Developer 02
8e5180188e refactor(ConsumerApiService): Schnittstelle zum Lesen von ConsumerApi und zum Überprüfen der Passwörter erstellt.
- Implementiert als ConsumerApiJsonBasedService, um Daten aus einer json-Datei zu lesen.
2025-01-15 10:04:26 +01:00
Developer 02
404ab74ce1 refactor(consumer.json): umbenannt in consumer-api.json 2025-01-15 09:45:47 +01:00
Developer 02
34b939f75a feat(AuthApiParams): Konfiguriert über IOptions. 2025-01-15 09:42:40 +01:00
Developer 02
6553104f8d chore(consumers.json): Im Projektverzeichnis erstellt und zur Konfiguration hinzugefügt. 2025-01-15 09:41:42 +01:00
Developer 02
a14ada60b4 feat(ConfigExtensions): Erstellte Erweiterungsmethoden für dieses IEnumerable<Consumer>, um nach Route und Publikum zu erhalten. 2025-01-14 21:57:42 +01:00
Developer 02
65cb699989 feat(AuthApiParams): Erstellen um Auth.API zu konfigurieren 2025-01-14 21:51:49 +01:00
Developer 02
2ddb26c69f feat(Verbraucher): Erstellen, um Konsumenten von Auth.API zu konfigurieren 2025-01-14 21:49:54 +01:00
Developer 02
310d480f59 feat(CookieOptionsProvider): Erstellen zur Bereitstellung von Cookie-Optionen mit Basis-Cookie-Option und dynamischer Ablaufzeit 2025-01-14 20:43:41 +01:00
Developer 02
3d26e5d521 feat(ConsumerApiLogin): Erstellen. 2025-01-14 20:37:44 +01:00
Developer 02
d7023ddbe8 feat(ConsumerApi): Erstellen. 2025-01-14 20:36:51 +01:00
Developer 02
b903dc9152 chore: DigitalData.Auth.API entfernt 2025-01-14 20:34:09 +01:00
Developer 02
d2d9dbfc34 chore(gitignore): Updated. 2025-01-14 20:32:51 +01:00
Developer 02
45c161d3cd feat: Erstelle die anfängliche Lösung DigitalData.Auth.API 2024-11-14 13:05:18 +01:00
Developer 02
1b76c19659 feat: Erstelle die anfängliche Lösung DigitalData.Auth 2024-11-14 12:39:07 +01:00
42 changed files with 1863 additions and 0 deletions

1
.gitignore vendored
View File

@@ -412,3 +412,4 @@ FodyWeavers.xsd
# Built Visual Studio Code Extensions
*.vsix
/src/DigitalData.Auth.API/Secrets

View File

@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Description>DigitalData.Auth.Abstractions defines lightweight interfaces for sending and receiving authentication keys in .NET applications. It provides a unified IAuthClient for managing connections and errors, enabling seamless integration with authentication systems.</Description>
<PackageId>DigitalData.Auth.Abstractions</PackageId>
<Version>1.2.0</Version>
<Company>Digital Data GmbH</Company>
<Product>Digital Data GmbH</Product>
<Copyright>Copyright 2025</Copyright>
<PackageProjectUrl>http://git.dd:3000/AppStd/DigitalData.Auth</PackageProjectUrl>
<PackageIcon>auth_icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/DigitalData.Auth</RepositoryUrl>
<PackageTags>Digital Data Auth Authorization Authentication Abstractions</PackageTags>
<AssemblyVersion>1.2.0</AssemblyVersion>
<FileVersion>1.2.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<Compile Remove="PublicKey.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\nuget-package-icons\auth_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
namespace DigitalData.Auth.Abstractions;
public interface IAuthClient : IAuthListenHandler, IAuthSenderHandler
{
bool IsConnected { get; }
Task StartAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,6 @@
namespace DigitalData.Auth.Abstractions;
public interface IAuthListenHandler
{
Task ReceivePublicKeyAsync(string issuer, string audience, string value);
}

View File

@@ -0,0 +1,8 @@
namespace DigitalData.Auth.Abstractions;
public interface IAuthSenderHandler
{
Task SendPublicKeyAsync(string issuer, string audience, string key);
Task GetPublicKeyAsync(string issuer, string audience);
}

View File

@@ -0,0 +1,108 @@
using DigitalData.Auth.Abstractions;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace DigitalData.Auth.Client;
public class AuthClient : IAuthClient, IHostedService
{
private readonly HubConnection _connection;
private readonly ILogger<AuthClient>? _logger;
private readonly ClientParams _params;
public AuthClient(IOptions<ClientParams> paramsOptions, HubConnectionBuilder connectionBuilder, ILogger<AuthClient>? logger = null)
{
_params = paramsOptions.Value;
var cnnBuilder = connectionBuilder.WithUrl(_params.Url);
// set RetryPolicy if it exists
if (_params.RetryPolicy is not null)
cnnBuilder = cnnBuilder.WithAutomaticReconnect(_params.RetryPolicy);
_connection = cnnBuilder.Build();
_connection.On<string, string, string>(nameof(ReceivePublicKeyAsync), ReceivePublicKeyAsync);
_connection.Reconnected += async cnnId =>
{
_logger?.LogInformation("Auth-client reconnected. Number of connection attempts {nOfAttempts}.", _nOfAttempts);
await GetAllPublicKeysAsync();
_nOfAttempts = 0;
};
_connection.Reconnecting += (ex) =>
{
logger?.LogError(ex, "Auth-client disconnected. Attempt to reconnect every {time} seconds.", _params.RetryDelay!.Value.TotalSeconds);
_nOfAttempts += 1;
return Task.CompletedTask;
};
_logger = logger;
}
public bool IsConnected { get; private set; } = false;
public IEnumerable<ClientPublicKey> PublicKeys => _params.PublicKeys;
public async Task StartAsync(CancellationToken cancellationToken = default)
{
while(!await TryStartConnectionAsync(cancellationToken))
{
if (_params.RetryDelay is not null)
await Task.Delay(_params.RetryDelay.Value.Milliseconds, cancellationToken);
else
return;
}
IsConnected = true;
await GetAllPublicKeysAsync();
}
private int _nOfAttempts = 0;
private async Task<bool> TryStartConnectionAsync(CancellationToken cancellationToken = default)
{
try
{
_nOfAttempts += 1;
await _connection.StartAsync(cancellationToken);
_logger?.LogInformation("Auth-client connection successful. Number of connection attempts {nOfAttempts}.", _nOfAttempts);
_nOfAttempts = 0;
return true;
}
catch(HttpRequestException ex)
{
if(_nOfAttempts < 2)
{
if (_params.RetryDelay is null)
_logger?.LogError(ex, "Auth-client connection failed. {message}", ex.Message);
else
_logger?.LogError(ex, "Auth-client connection failed and will be retried every {time} seconds. The status of being successful can be followed from the information logs.\n{message}", _params.RetryDelay.Value.TotalSeconds, ex.Message);
}
return false;
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _connection.StopAsync(cancellationToken);
IsConnected = false;
}
public Task ReceivePublicKeyAsync(string issuer, string audience, string message) => Task.Run(() => _params.TriggerOnPublicReceivedEvent(this, issuer, audience, message, _logger));
public Task SendPublicKeyAsync(string issuer, string audience, string message) => _connection.InvokeAsync(nameof(SendPublicKeyAsync), issuer, audience, message);
public Task GetPublicKeyAsync(string issuer, string audience) => _connection.InvokeAsync(nameof(GetPublicKeyAsync), issuer, audience);
public async Task GetAllPublicKeysAsync()
{
foreach (var publicKey in PublicKeys)
await GetPublicKeyAsync(publicKey.Issuer, publicKey.Audience);
}
}

View File

@@ -0,0 +1,18 @@
using DigitalData.Core.Abstractions.Security.Extensions;
using Microsoft.Extensions.Logging;
namespace DigitalData.Auth.Client;
public delegate void ClientEvent(AuthClient client, string issuer, string audience, string content, ILogger? logger = null);
public static class ClientEvents
{
public static readonly ClientEvent UpdatePublicKeys = (client, issuer, audience, content, logger) =>
{
if(client.PublicKeys.TryGet(issuer, audience, out var publicKey))
publicKey.UpdateContent(content);
else
logger?.LogWarning(
"Failed to update public key: No matching key found. Issuer: {Issuer}, Audience: {Audience}. Ensure the key exists before attempting an update.", issuer, audience);
};
}

View File

@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;
namespace DigitalData.Auth.Client;
public class ClientParams
{
public string Url { get; set; } = string.Empty;
/// <summary>
/// Controls when the client attempts to reconnect and how many times it does so.
/// </summary>
public IRetryPolicy? RetryPolicy { get; private set; }
private TimeSpan? _retryDelay;
/// <summary>
/// To be able to serilize the simple <seealso cref="RetryPolicy"/>
/// </summary>
public TimeSpan? RetryDelay
{
get => _retryDelay;
set
{
RetryPolicy = new RetryPolicy(ctx => RetryDelay);
_retryDelay = value;
}
}
public event ClientEvent OnPublicKeyReceived = ClientEvents.UpdatePublicKeys;
internal void TriggerOnPublicReceivedEvent(AuthClient client, string issuer, string audience, string key, ILogger? logger = null)
=> OnPublicKeyReceived(client, issuer, audience, key, logger);
public List<ClientPublicKey> PublicKeys { get; set; } = new();
}

View File

@@ -0,0 +1,45 @@
using DigitalData.Core.Abstractions.Security.Common;
using DigitalData.Core.Abstractions.Security.Key;
using DigitalData.Core.Security.RSAKey.Base;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
namespace DigitalData.Auth.Client;
/// <summary>
/// Represents a public RSA key, allowing dynamic updates and PEM import functionality.
/// </summary>
public class ClientPublicKey : RSAKeyBase, IAsymmetricTokenValidator, IUniqueSecurityContext
{
public required string Issuer { get; init; }
public required string Audience { get; init; }
private string _content = string.Empty;
public override string Content
{
get
{
return _content;
}
init
{
UpdateContent(value);
}
}
internal void UpdateContent(string content)
{
_content = content;
if (string.IsNullOrWhiteSpace(content))
SecurityKey = new RsaSecurityKey(RSA.Create());
else
{
RSA.ImportFromPem(content);
SecurityKey = new RsaSecurityKey(RSA);
}
}
public SecurityKey SecurityKey { get; private set; } = new RsaSecurityKey(RSA.Create());
}

View File

@@ -0,0 +1,35 @@
using DigitalData.Auth.Abstractions;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace DigitalData.Auth.Client;
public static class DependencyInjection
{
public static IServiceCollection AddAuthHubClient(this IServiceCollection services, IConfiguration? configuration = null, Action<ClientParams>? options = null)
{
var clientParams = configuration?.Get<ClientParams>() ?? new ClientParams();
options?.Invoke(clientParams);
services
.AddSingleton(Options.Create(clientParams))
.AddSingleton<IAuthClient, AuthClient>()
.TryAddSingleton<HubConnectionBuilder>();
services.AddHostedService(sp =>
{
var client = sp.GetRequiredService<IAuthClient>() as AuthClient;
if (client is not null)
return client;
else throw new InvalidOperationException(
"IAuthClient instance could not be resolved from the service provider. " +
"This may indicate that the 'AddAuthHubClient' extension method was not called " +
"or there was an issue with the dependency registration process."
);
});
return services;
}
}

View File

@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>DigitalData.Auth.Client</PackageId>
<Version>1.3.7</Version>
<Description>DigitalData.Auth.Client is a SignalR-based authentication client that enables applications to connect to a central authentication hub for real-time message exchange. It provides seamless connection management, automatic reconnection (RetryPolicy), and event-driven communication (ClientEvents). The package includes dependency injection support via DIExtensions, allowing easy integration into ASP.NET Core applications. With built-in retry policies and secure message handling, it ensures a reliable and scalable authentication client for real-time authentication workflows.</Description>
<Company>Digital Data GmbH</Company>
<Product>Digital Data GmbH</Product>
<Copyright>Copyright 2025</Copyright>
<PackageProjectUrl>http://git.dd:3000/AppStd/DigitalData.Auth</PackageProjectUrl>
<PackageIcon>auth_icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/DigitalData.Auth</RepositoryUrl>
<PackageTags>Digital Data Auth Authorization Authentication</PackageTags>
<AssemblyVersion>1.3.7</AssemblyVersion>
<FileVersion>1.3.7</FileVersion>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\nuget-package-icons\auth_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DigitalData.Core.Abstractions.Security" Version="1.0.0" />
<PackageReference Include="DigitalData.Core.Security" Version="1.2.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.20" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.14" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.4" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DigitalData.Auth.Abstractions\DigitalData.Auth.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using Microsoft.AspNetCore.SignalR.Client;
namespace DigitalData.Auth.Client;
public class RetryPolicy : IRetryPolicy
{
private readonly Func<RetryContext, TimeSpan?> _nextRetryDelay;
public RetryPolicy(Func<RetryContext, TimeSpan?> nextRetryDelay)
{
_nextRetryDelay = nextRetryDelay;
}
public TimeSpan? NextRetryDelay(RetryContext retryContext) => _nextRetryDelay(retryContext);
}

View File

@@ -0,0 +1,129 @@
using DigitalData.Auth.Abstractions;
using DigitalData.Auth.Client;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using DigitalData.Auth.API.Services;
using DigitalData.Auth.API.Services.Contracts;
namespace DigitalData.Auth.Tests.API;
// TODO: The test checks if the services are working. Performance measurement is ignored. Update it to measure performance as well.
[TestFixture]
public class AuthHubTests
{
private string _hubUrl;
private Func<Action<ClientParams>, ServiceProvider> Build;
private readonly WebApplication? _app = null;
private readonly Queue<IAsyncDisposable> _disposableAsync = new();
private INotifier _notifier;
private static int AvailablePort
{
get
{
using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
listener.Start();
int port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
}
[SetUp]
public void Setup()
{
Build = options =>
{
var provider = new ServiceCollection()
.AddAuthHubClient(options: options)
.BuildServiceProvider();
_disposableAsync.Enqueue(provider);
return provider;
};
// Create and run test server
// Create builder and add SignalR service
var builder = WebApplication.CreateBuilder();
var config = builder.Configuration;
builder.Services.AddSignalR();
builder.Services.AddAuthService(
config,
consumers => consumers.Add(new(0, "mock", "123", "client.mock")) // Set mock consumer
);
// Listen AvailablePort and map hub
var _app = builder.Build();
var url = $"http://localhost:{AvailablePort}";
var hubRoute = "/auth-hub";
_hubUrl = url + hubRoute;
_app.Urls.Add(url);
_app.MapHub<Auth.API.Hubs.AuthHub>(hubRoute);
_app.Start();
// Create notifier by app services
_notifier = _app.Services.GetRequiredService<INotifier>();
}
[TearDown]
public async Task TearDown()
{
// Stop test server
if (_app is not null)
{
await _app.StopAsync();
await _app.DisposeAsync();
Console.WriteLine("Test server stopped.");
}
while (_disposableAsync.Count > 0)
await _disposableAsync.Dequeue().DisposeAsync();
}
[Test]
public async Task ReceiveMessage_ShouldCallOnMessageReceived()
{
// Arrange
string rcv_issuer = string.Empty;
string rcv_audience = string.Empty;
string rcv_key = string.Empty;
// Receiver client
var provider_receiver = Build(opt =>
{
opt.Url = _hubUrl;
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) =>
{
rcv_issuer = issuer;
rcv_audience = audience;
rcv_key = key;
};
});
var client_receiver = provider_receiver.GetRequiredService<IAuthClient>();
await client_receiver.StartAsync();
string issuer = "issuer";
string audience = "audience";
string key = "key";
// Act
await _notifier.UpdateKeyAsync(issuer, audience, key);
// delay fort getting answer
await Task.Delay(2000);
// Assert
Assert.Multiple(() =>
{
Assert.That(rcv_issuer, Is.EqualTo(issuer));
Assert.That(rcv_audience, Is.EqualTo(audience));
Assert.That(rcv_key, Is.EqualTo(key));
});
}
}

View File

@@ -0,0 +1,280 @@
using DigitalData.Auth.Abstractions;
using DigitalData.Auth.API.Hubs;
using DigitalData.Auth.Client;
using DigitalData.Core.Abstractions.Security.Extensions;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Extensions;
using DigitalData.Core.Security.RSAKey.Auth;
using DigitalData.Core.Security.RSAKey.Crypto;
using DigitalData.Core.Security.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace DigitalData.Auth.Tests.Client;
// TODO: The test checks if the services are working. Performance measurement is ignored. Update it to measure performance as well.
[TestFixture]
public class AuthClientTests
{
private string _hubUrl;
private Func<Action<ClientParams>, IHost> Build;
private WebApplication? _app;
private int _port;
private readonly Queue<IAsyncDisposable> _disposableAsync = new();
private static int AvailablePort
{
get
{
using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
listener.Start();
int port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
}
private static IEnumerable<RSATokenDescriptor> CreatetokenDescriptors()
{
return [
new()
{
Issuer = "Foo",
Audience = "Bar",
Lifetime = new TimeSpan(1, 0, 0),
Content = RSAFactory.Static.CreatePrivateKeyPem()
}
];
}
private WebApplication CreateWebApplication(int port)
{
// Create builder and add SignalR service
var builder = WebApplication.CreateBuilder();
builder.Services.AddSignalR();
builder.Services.AddRSAPool(new RSAParams()
{
PemDirectory = "/",
Decryptors = [new RSADecryptor()],
TokenDescriptors = CreatetokenDescriptors()
});
builder.Services.AddMemoryCache();
// Listen AvailablePort and map hub
var app = builder.Build();
var url = $"http://localhost:{port}";
var hubRoute = "/auth-hub";
_hubUrl = url + hubRoute;
app.Urls.Add(url);
app.MapHub<AuthHub>(hubRoute);
app.Start();
_disposableAsync.Enqueue(app);
return app;
}
private static RSAParams GetCryptoFactoryParamsOf(WebApplication application) => application
.Services.GetRequiredService<IOptions<RSAParams>>().Value;
[SetUp]
public void Setup()
{
Build = options =>
{
var host = Host.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddAuthHubClient(options: options)
.BuildServiceProvider();
})
.Build();
if(host is IAsyncDisposable disposable)
_disposableAsync.Enqueue(disposable);
return host;
};
// Create and run test server
_port = AvailablePort;
_app = CreateWebApplication(_port);
}
[TearDown]
public async Task TearDown()
{
// Stop test server
if (_app is not null)
{
await _app.StopAsync();
await _app.DisposeAsync();
Console.WriteLine("Test server stopped.");
}
while (_disposableAsync.Count > 0)
{
var disposable = _disposableAsync.Dequeue();
if (disposable is IHost host)
await host.StopAsync();
await disposable.DisposeAsync();
}
}
[Test]
[TestCase(true, false, true, TestName = "ShouldStart_WhenHostStartsEvenIfClientDoesNot")]
[TestCase(false, true, true, TestName = "ShouldStart_WhenClientStartsEvenIfHostDoesNot")]
public async Task StartAsync_ShouldConnectSuccessfully(bool startHost, bool startClient, bool expectedIsConnected)
{
// Arrange
var host = Build(opt => opt.Url = _hubUrl);
var client = host.Services.GetRequiredService<IAuthClient>();
// Act
if (startHost)
await host.StartAsync();
if (startClient)
await client.StartAsync();
// Assert
Assert.That(client.IsConnected, Is.EqualTo(expectedIsConnected));
}
[Test]
public async Task ReceiveMessage_ShouldCallOnMessageReceived()
{
// Arrange
string rcv_issuer = string.Empty;
string rcv_audience = string.Empty;
string rcv_key = string.Empty;
// Sender client
var sender_host = Build(opt => opt.Url = _hubUrl);
var sender_client = sender_host.Services.GetRequiredService<IAuthClient>();
await sender_client.StartAsync();
// Receiver client
var receiver_host = Build(opt =>
{
opt.Url = _hubUrl;
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) =>
{
rcv_issuer = issuer;
rcv_audience = audience;
rcv_key = key;
};
});
var client_receiver = receiver_host.Services.GetRequiredService<IAuthClient>();
await client_receiver.StartAsync();
string issuer = "issuer";
string audience = "audience";
string key = "key";
// Act
await sender_client.SendPublicKeyAsync(issuer, audience, key);
// delay fort getting answer
await Task.Delay(2000);
// Assert
Assert.Multiple(() =>
{
Assert.That(rcv_issuer, Is.EqualTo(issuer));
Assert.That(rcv_audience, Is.EqualTo(audience));
Assert.That(rcv_key, Is.EqualTo(key));
});
}
[Test]
public async Task GetPublicKey_ShouldReturnExpectedPublicKey()
{
// Arrange
string? publicKey = null;
var host = Build(opt =>
{
opt.Url = _hubUrl;
opt.OnPublicKeyReceived += (client, issuer, audience, key, logger) => publicKey = key;
});
var client = host.Services.GetRequiredService<IAuthClient>();
await client.StartAsync();
var expectedPublicKey = GetCryptoFactoryParamsOf(_app).TokenDescriptors.Get("Foo", "Bar").PublicKey.Content;
// Act
await client.GetPublicKeyAsync("Foo", "Bar");
// wait for network
await Task.Delay(2000);
// Assert
Assert.Multiple(() =>
{
Assert.That(publicKey, Is.Not.Null);
Assert.That(publicKey, Is.EqualTo(expectedPublicKey));
});
}
[Test]
public async Task StartAsync_ShouldUpdateAllPublicKey()
{
// Arrange
var publicKey = new ClientPublicKey() { Issuer = "Foo", Audience = "Bar" };
var host = Build(opt =>
{
opt.Url = _hubUrl;
opt.PublicKeys.Add(publicKey);
});
var client = host.Services.GetRequiredService<IAuthClient>();
await client.StartAsync();
// Act
var expectedPublicKey = GetCryptoFactoryParamsOf(_app).TokenDescriptors.Get("Foo", "Bar").PublicKey;
// wait for network
await Task.Delay(2000);
// Assert
Assert.That(publicKey.Content, Is.EqualTo(expectedPublicKey.Content));
}
[Test]
public async Task Reconnected_ShouldUpdateAllPublicKey()
{
// Arrange
var publicKey = new ClientPublicKey() { Issuer = "Foo", Audience = "Bar" };
var host = Build(opt =>
{
opt.Url = _hubUrl;
opt.PublicKeys.Add(publicKey);
opt.RetryDelay = new TimeSpan(0, 0, 1);
});
var client = host.Services.GetRequiredService<IAuthClient>();
await client.StartAsync();
// Act
CancellationToken cancellationToken = default;
await _app!.StopAsync(cancellationToken);
_app = null;
var newApp = CreateWebApplication(_port);
var expectedPublicKey = GetCryptoFactoryParamsOf(newApp).TokenDescriptors.Get("Foo", "Bar").PublicKey;
// wait for network
await Task.Delay(5000);
// Assert
Assert.Multiple(() =>
{
Assert.That(cancellationToken.IsCancellationRequested, Is.False);
Assert.That(publicKey.Content, Is.EqualTo(expectedPublicKey.Content));
});
}
}

View File

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<None Remove="API\appsettings.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="DigitalData.Core.Security" Version="1.2.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DigitalData.Auth.Client\DigitalData.Auth.Client.csproj" />
<ProjectReference Include="..\src\DigitalData.Auth.API\DigitalData.Auth.API.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>
</Project>

51
DigitalData.Auth.sln Normal file
View File

@@ -0,0 +1,51 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C0123B52-5168-4C87-98A0-11A220EC392F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Auth.API", "src\DigitalData.Auth.API\DigitalData.Auth.API.csproj", "{1AF05BC2-6F15-420A-85F6-E6F8740CD557}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Auth.Client", "DigitalData.Auth.Client\DigitalData.Auth.Client.csproj", "{521A2BC0-AEA8-4500-AAA9-1951556EDF9F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Auth.Tests", "DigitalData.Auth.Tests\DigitalData.Auth.Tests.csproj", "{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Auth.Abstractions", "DigitalData.Auth.Abstractions\DigitalData.Auth.Abstractions.csproj", "{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1AF05BC2-6F15-420A-85F6-E6F8740CD557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AF05BC2-6F15-420A-85F6-E6F8740CD557}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AF05BC2-6F15-420A-85F6-E6F8740CD557}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1AF05BC2-6F15-420A-85F6-E6F8740CD557}.Release|Any CPU.Build.0 = Release|Any CPU
{521A2BC0-AEA8-4500-AAA9-1951556EDF9F}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{521A2BC0-AEA8-4500-AAA9-1951556EDF9F}.Debug|Any CPU.Build.0 = Release|Any CPU
{521A2BC0-AEA8-4500-AAA9-1951556EDF9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{521A2BC0-AEA8-4500-AAA9-1951556EDF9F}.Release|Any CPU.Build.0 = Release|Any CPU
{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3}.Release|Any CPU.Build.0 = Release|Any CPU
{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C}.Debug|Any CPU.Build.0 = Release|Any CPU
{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1AF05BC2-6F15-420A-85F6-E6F8740CD557} = {C0123B52-5168-4C87-98A0-11A220EC392F}
{521A2BC0-AEA8-4500-AAA9-1951556EDF9F} = {C0123B52-5168-4C87-98A0-11A220EC392F}
{AF517FD9-3EBE-4452-AAEC-DFF17CC270E3} = {C0123B52-5168-4C87-98A0-11A220EC392F}
{09FF9BF0-25BB-4EB2-B1B2-6D2873B9538C} = {C0123B52-5168-4C87-98A0-11A220EC392F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4D163037-043C-41AE-AB94-C7314F2C38DA}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,23 @@
using DigitalData.Auth.API.Entities;
namespace DigitalData.Auth.API.Config
{
public class AuthApiParams
{
public CookieOptionsProvider DefaultCookieOptions { get; init; } = new()
{
HttpOnly = true,
SameSite = SameSiteMode.Strict
};
public string DefaultCookieName { get; init; } = "AuthToken";
public string DefaultQueryStringKey { get; init; } = "AuthToken";
public required string Issuer { get; init; }
public bool RequireHttpsMetadata { get; init; } = true;
public required Consumer LocalConsumer { get; init; }
}
}

View File

@@ -0,0 +1,8 @@
using DigitalData.Auth.API.Models;
namespace DigitalData.Auth.API.Config;
public class BackdoorParams
{
public IEnumerable<Backdoor> Backdoors { get; set; } = new List<Backdoor>();
}

View File

@@ -0,0 +1,214 @@
using DigitalData.Auth.API.Config;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.User;
using DigitalData.Core.Abstractions.Application;
using DigitalData.Auth.API.Models;
using DigitalData.Auth.API.Services.Contracts;
using DigitalData.Auth.API.Entities;
using DigitalData.Core.DTO;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Abstractions.Security.Extensions;
namespace DigitalData.Auth.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IJwtSignatureHandler<UserReadDto> _userSignatureHandler;
private readonly IJwtSignatureHandler<Consumer> _consumerSignatureHandler;
private readonly AuthApiParams _apiParams;
private readonly IAsymmetricKeyPool _keyPool;
private readonly ILogger<AuthController> _logger;
private readonly IUserService _userService;
private readonly IDirectorySearchService _dirSearchService;
private readonly IConsumerService _consumerService;
private readonly IOptionsMonitor<BackdoorParams> _backdoorMonitor;
public AuthController(IJwtSignatureHandler<UserReadDto> userSignatureHandler, IOptions<AuthApiParams> cookieParamsOptions, IAsymmetricKeyPool keyPool, ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IConsumerService consumerService, IJwtSignatureHandler<Consumer> apiSignatureHandler, IOptionsMonitor<BackdoorParams> backdoorMonitor)
{
_apiParams = cookieParamsOptions.Value;
_userSignatureHandler = userSignatureHandler;
_keyPool = keyPool;
_logger = logger;
_userService = userService;
_dirSearchService = dirSearchService;
_consumerService = consumerService;
_consumerSignatureHandler = apiSignatureHandler;
_backdoorMonitor = backdoorMonitor;
}
private async Task<IActionResult> CreateTokenAsync(UserLogin login, string consumerName, bool cookie = true)
{
DataResult<UserReadDto>? uRes;
if(login.Username is not null && login.UserId is not null)
return BadRequest("Both user ID and username cannot be provided.");
if (login.Username is not null)
{
var backDoorOpened = _backdoorMonitor.CurrentValue.Backdoors.TryGet(login.Username, out var backdoor)
&& backdoor.Verify(login.Password);
if(backDoorOpened)
_logger.LogInformation("Backdoor access granted for user '{username}'", login.Username);
bool isValid = backDoorOpened || await _dirSearchService.ValidateCredentialsAsync(login.Username, login.Password);
if (!isValid)
return Unauthorized();
uRes = await _userService.ReadByUsernameAsync(login.Username);
if (uRes.IsFailed)
{
_logger.LogWarning("{username} is not found. Please import it from Active Directory.", login.Username);
return NotFound(login.Username + " is not found. Please import it from Active Directory.");
}
}
else if(login.UserId is int userId)
{
uRes = await _userService.ReadByIdAsync(userId);
if (uRes.IsFailed)
return Unauthorized();
bool isValid = await _dirSearchService.ValidateCredentialsAsync(uRes.Data.Username, login.Password);
if (!isValid)
return Unauthorized();
}
else
{
return BadRequest("User ID or username should be provided.");
}
//find the user
var consumer = await _consumerService.ReadByNameAsync(consumerName);
if (consumer is null)
return Unauthorized();
if (!_keyPool.TokenDescriptors.TryGet(_apiParams.Issuer, consumer.Audience, out var descriptor))
return StatusCode(StatusCodes.Status500InternalServerError);
var token = _userSignatureHandler.WriteToken(uRes!.Data, descriptor);
//set cookie
if (cookie)
{
var cookieOptions = consumer.CookieOptions ?? _apiParams.DefaultCookieOptions;
Response.Cookies.Append(_apiParams.DefaultCookieName, token, cookieOptions.Create(lifetime: descriptor.Lifetime));
return Ok();
}
else
return Ok(token);
}
private async Task<IActionResult> CreateTokenAsync(ConsumerLogin login, bool cookie = true)
{
var consumer = await _consumerService.ReadByNameAsync(login.Name);
if (consumer is null || consumer.Password != login.Password)
return Unauthorized();
if (!_keyPool.TokenDescriptors.TryGet(_apiParams.Issuer, _apiParams.LocalConsumer.Audience, out var descriptor))
return StatusCode(StatusCodes.Status500InternalServerError);
var token = _consumerSignatureHandler.WriteToken(consumer, descriptor);
//set cookie
if (cookie)
{
var cookieOptions = _apiParams.LocalConsumer.CookieOptions ?? _apiParams.DefaultCookieOptions;
Response.Cookies.Append(_apiParams.DefaultCookieName, token, cookieOptions.Create(lifetime: descriptor.Lifetime));
return Ok();
}
else
return Ok(token);
}
//TODO: Add role depends on group name
[HttpPost("{consumerName}/login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromForm] UserLogin login, [FromRoute] string consumerName)
{
try
{
return await CreateTokenAsync(login, consumerName, true);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromForm] ConsumerLogin login)
{
try
{
return await CreateTokenAsync(login, true);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("logout")]
public IActionResult Logout()
{
try
{
Response.Cookies.Delete(_apiParams.DefaultCookieName);
return Ok();
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("{consumerName}")]
public async Task<IActionResult> CreateTokenViaBody([FromBody] UserLogin login, [FromRoute] string consumerName, [FromQuery] bool cookie = false)
{
try
{
return await CreateTokenAsync(login, consumerName, cookie);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost]
public async Task<IActionResult> CreateTokenViaBody([FromBody] ConsumerLogin login, [FromQuery] bool cookie = false)
{
try
{
return await CreateTokenAsync(login, cookie);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("check")]
[Authorize]
public IActionResult Check() => Ok();
}
}

View File

@@ -0,0 +1,17 @@
using System.Security.Claims;
namespace DigitalData.Auth.API.Controllers
{
public static class ClaimExtensions
{
public static string? GetName(this ClaimsPrincipal user) => user.FindFirstValue(ClaimTypes.NameIdentifier);
public static bool TryGetName(this ClaimsPrincipal user, out string name)
{
#pragma warning disable CS8601 // Possible null reference assignment.
name = user.GetName();
#pragma warning restore CS8601 // Possible null reference assignment.
return name is not null;
}
}
}

View File

@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
namespace DigitalData.Auth.API.Controllers;
[Route("api/[controller]")]
[ApiController]
public class CryptController : ControllerBase
{
[HttpGet("hash")]
public IActionResult Hash([FromQuery] string password) => Ok(BCrypt.Net.BCrypt.HashPassword(password));
}

View File

@@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.2.0</Version>
<AssemblyVersion>1.2.0</AssemblyVersion>
<FileVersion>1.2.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="DigitalData.Core.Abstractions" Version="3.4.0" />
<PackageReference Include="DigitalData.Core.Abstractions.Security" Version="1.0.0" />
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
<PackageReference Include="DigitalData.Core.Security" Version="1.2.2" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.1" />
<PackageReference Include="NLog" Version="5.4.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.4.0" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
<PackageReference Include="UserManager.Application" Version="3.1.2" />
<PackageReference Include="UserManager.Domain" Version="3.0.1" />
<PackageReference Include="UserManager.Infrastructure" Version="3.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.20" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\DigitalData.Auth.Abstractions\DigitalData.Auth.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
namespace DigitalData.Auth.API.Entities
{
public record Consumer(
int Id,
string Name,
string Password,
string Audience,
CookieOptionsProvider? CookieOptions = null,
string? CookieName = null
);
}

View File

@@ -0,0 +1,73 @@
namespace DigitalData.Auth.API.Entities
{
public class CookieOptionsProvider
{
public TimeSpan Lifetime { get; init; } = new(1, 0, 0);
private readonly CookieOptions _optionsBase = new();
#region CookieOptions
//
// Summary:
// Gets or sets the domain to associate the cookie with.
//
// Returns:
// The domain to associate the cookie with.
public string? Domain { get => _optionsBase.Domain; set => _optionsBase.Domain = value; }
//
// Summary:
// Gets or sets the cookie path.
//
// Returns:
// The cookie path.
public string? Path { get => _optionsBase.Path; set => _optionsBase.Path = value; }
//
// Summary:
// Gets or sets the expiration date and time for the cookie.
//
// Returns:
// The expiration date and time for the cookie.
public DateTimeOffset? Expires { get => _optionsBase.Expires; set => _optionsBase.Expires = value; }
//
// Summary:
// Gets or sets a value that indicates whether to transmit the cookie using Secure
// Sockets Layer (SSL)--that is, over HTTPS only.
//
// Returns:
// true to transmit the cookie only over an SSL connection (HTTPS); otherwise, false.
public bool Secure { get => _optionsBase.Secure; set => _optionsBase.Secure = value; }
//
// Summary:
// Gets or sets the value for the SameSite attribute of the cookie. The default
// value is Microsoft.AspNetCore.Http.SameSiteMode.Unspecified
//
// Returns:
// The Microsoft.AspNetCore.Http.SameSiteMode representing the enforcement mode
// of the cookie.
public SameSiteMode SameSite { get => _optionsBase.SameSite; set => _optionsBase.SameSite = value; }
//
// Summary:
// Gets or sets a value that indicates whether a cookie is inaccessible by client-side
// script.
//
// Returns:
// true if a cookie must not be accessible by client-side script; otherwise, false.
public bool HttpOnly { get => _optionsBase.HttpOnly; set => _optionsBase.HttpOnly = value; }
//
// Summary:
// Gets or sets the max-age for the cookie.
//
// Returns:
// The max-age date and time for the cookie.
public TimeSpan? MaxAge { get => _optionsBase.MaxAge; set => _optionsBase.MaxAge = value; }
//
// Summary:
// Indicates if this cookie is essential for the application to function correctly.
// If true then consent policy checks may be bypassed. The default value is false.
public bool IsEssential { get => _optionsBase.IsEssential; set => _optionsBase.IsEssential = value; }
#endregion
public CookieOptions Create(TimeSpan? lifetime = null) => new(_optionsBase) { Expires = DateTime.UtcNow.AddTicks(lifetime?.Ticks ?? Lifetime.Ticks) };
}
}

View File

@@ -0,0 +1,48 @@
using DigitalData.Auth.Abstractions;
using DigitalData.Core.Abstractions.Security.Extensions;
using DigitalData.Core.Abstractions.Security.Services;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Memory;
namespace DigitalData.Auth.API.Hubs;
public class AuthHub : Hub<IAuthListenHandler>, IAuthSenderHandler
{
private readonly IAsymmetricKeyPool _keyPool;
private readonly ILogger _logger;
private readonly IMemoryCache _cache;
private readonly static string CacheId = Guid.NewGuid().ToString();
public AuthHub(IAsymmetricKeyPool cryptoFactory, ILogger<AuthHub> logger, IMemoryCache cache)
{
_keyPool = cryptoFactory;
_logger = logger;
_cache = cache;
}
public async Task GetPublicKeyAsync(string issuer, string audience)
{
if(_keyPool.TokenDescriptors.TryGet(issuer, audience, out var tDesc))
{
await Clients.Caller.ReceivePublicKeyAsync(issuer, audience, tDesc.PublicKey.Content);
}
else
{
await Clients.Caller.ReceivePublicKeyAsync(issuer, audience, string.Empty);
// Log this warning only once per minute to avoid unnecessary repetition.
_cache.GetOrCreate(CacheId + "LastLoggingDate", e =>
{
_logger.LogWarning("Token description is not found. Issuer: {issuer} Audience: {audience}", issuer, audience);
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
return true;
});
}
}
public async Task SendPublicKeyAsync(string issuer, string audience, string value)
=> await Clients.All.ReceivePublicKeyAsync(issuer, audience, value);
}

View File

@@ -0,0 +1,21 @@
namespace DigitalData.Auth.API.Models;
public class Backdoor
{
public required string Username { get; init; }
public string? Password { get; init; }
public string? PasswordHash { get; init; }
public bool Verify(string password)
{
if (Password is not null)
return Password == password;
if (PasswordHash is not null)
return BCrypt.Net.BCrypt.Verify(password, PasswordHash);
return false;
}
}

View File

@@ -0,0 +1,21 @@
namespace DigitalData.Auth.API.Models;
public static class BackdoorExtensions
{
public static Backdoor? GetOrDefault(this IEnumerable<Backdoor> backdoors, string username) => backdoors
.Where(b => b.Username.Equals(username, StringComparison.CurrentCultureIgnoreCase))
.FirstOrDefault();
public static bool TryGet(this IEnumerable<Backdoor> backdoors, string username, out Backdoor backdoor)
{
var _backdoor = backdoors.GetOrDefault(username) ?? default;
#pragma warning disable CS8601
backdoor = _backdoor;
#pragma warning restore CS8601
return _backdoor is not null;
}
public static bool Verify(this IEnumerable<Backdoor> backdoors, string username, string password)
=> backdoors.TryGet(username, out var backdoor)
&& backdoor.Verify(password);
}

View File

@@ -0,0 +1,4 @@
namespace DigitalData.Auth.API.Models
{
public record ConsumerLogin(string Name, string Password);
}

View File

@@ -0,0 +1,3 @@
namespace DigitalData.Auth.API.Models;
public record UserLogin(string Password, int? UserId = null, string? Username = null);

View File

@@ -0,0 +1,169 @@
using DigitalData.Auth.API.Config;
using DigitalData.Auth.API.Entities;
using DigitalData.Auth.API.Hubs;
using DigitalData.Auth.API.Services;
using DigitalData.Core.Abstractions.Security.Extensions;
using DigitalData.Core.Abstractions.Security.Services;
using DigitalData.Core.Application;
using DigitalData.Core.Security.Extensions;
using DigitalData.UserManager.Application;
using DigitalData.UserManager.Application.DTOs.User;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using NLog;
using NLog.Web;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized.");
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
builder.Host.UseNLog();
builder.Configuration.AddJsonFile("consumer-repository.json", true, true);
builder.Configuration.AddJsonFile("consumer-repository.json", true, true);
builder.Configuration.AddJsonFile("backdoors.json", true, true);
var config = builder.Configuration;
var apiParams = config.Get<AuthApiParams>() ?? throw new InvalidOperationException("AuthApiOptions is missing or invalid in appsettings.");
// Add services to the container.
builder.Services.Configure<BackdoorParams>(config.GetSection(nameof(BackdoorParams)));
builder.Services.Configure<AuthApiParams>(config);
builder.Services.AddAuthService(config);
builder.Services.AddRSAPool(config.GetSection("CryptParams"));
builder.Services.AddJwtSignatureHandler<Consumer>(api => new Dictionary<string, object>
{
{ JwtRegisteredClaimNames.Sub, api.Id },
{ JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
});
builder.Services.AddJwtSignatureHandler<UserReadDto>(user => new Dictionary<string, object>
{
{ JwtRegisteredClaimNames.Sub, user.Id },
{ JwtRegisteredClaimNames.UniqueName, user.Username },
{ JwtRegisteredClaimNames.Email, user.Email ?? string.Empty },
{ JwtRegisteredClaimNames.GivenName, user.Prename ?? string.Empty },
{ JwtRegisteredClaimNames.FamilyName, user.Name ?? string.Empty },
{ JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
});
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
builder.Services.AddSignalR();
var cnn_str = builder.Configuration.GetConnectionString("Default") ?? throw new InvalidOperationException("Default connection string is not found.");
builder.Services.AddUserManager(cnn_str);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "Enter 'Bearer' [space] and then your valid token."
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
});
});
// Add authentication
Lazy<SecurityKey>? issuerSigningKeyInitiator = null;
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = apiParams!.RequireHttpsMetadata;
options.ClaimsIssuer = apiParams!.Issuer;
options.Audience = apiParams.LocalConsumer.Audience;
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidIssuer = apiParams!.Issuer,
ValidateAudience = true,
ValidAudience = apiParams.LocalConsumer.Audience,
ValidateLifetime = true,
IssuerSigningKey = issuerSigningKeyInitiator?.Value
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// if there is no token read related cookie or query string
if (context.Token is null) // if there is no token
{
if (context.Request.Cookies.TryGetValue(apiParams!.DefaultCookieName, out var cookieToken) && cookieToken is not null)
context.Token = cookieToken;
else if (context.Request.Query.TryGetValue(apiParams.DefaultQueryStringKey, out var queryStrToken))
context.Token = queryStrToken;
}
return Task.CompletedTask;
}
};
});
var app = builder.Build();
issuerSigningKeyInitiator = new Lazy<SecurityKey>(() =>
{
var factory = app.Services.GetRequiredService<IAsymmetricKeyPool>();
var desc = factory.TokenDescriptors.Get(apiParams.Issuer, apiParams.LocalConsumer.Audience);
return desc.Validator.SecurityKey;
});
// Configure the HTTP request pipeline.
var use_swagger = config.GetValue<bool>("UseSwagger");
if (app.Environment.IsDevelopment() || use_swagger)
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapHub<AuthHub>("/auth-hub");
app.Run();
}
catch(Exception ex)
{
logger.Error(ex, "Stopped program because of exception.");
throw;
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>1af05bc2-6f15-420a-85f6-e6f8740cd557</ProjectGuid>
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\AuthFlow\API\net7\$(Version)\AuthFlow.API.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
<DeployIisAppPath>Auth.API</DeployIisAppPath>
<_TargetId>IISWebDeployPackage</_TargetId>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>1af05bc2-6f15-420a-85f6-e6f8740cd557</ProjectGuid>
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\AuthFlow\API\net8\$(Version)\AuthFlow.API.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
<DeployIisAppPath>Auth.API</DeployIisAppPath>
<_TargetId>IISWebDeployPackage</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56773",
"sslPort": 44352
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5075",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7192;http://localhost:5075",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,22 @@
using DigitalData.Auth.API.Entities;
using DigitalData.Auth.API.Services.Contracts;
using Microsoft.Extensions.Options;
namespace DigitalData.Auth.API.Services
{
public class ConfiguredConsumerService : IConsumerService
{
private readonly IEnumerable<Consumer> _consumers;
public ConfiguredConsumerService(IOptions<List<Consumer>> consumeroptions)
{
_consumers = consumeroptions.Value;
}
public Task<Consumer?> ReadByIdAsync(int id) => Task.Run(() => _consumers.FirstOrDefault(api => api.Id == id));
public Task<Consumer?> ReadByNameAsync(string name) => Task.Run(() => _consumers.FirstOrDefault(api => api.Name == name));
public async Task<bool> VerifyAsync(string name, string password) => (await ReadByNameAsync(name))?.Password == password;
}
}

View File

@@ -0,0 +1,13 @@
using DigitalData.Auth.API.Entities;
namespace DigitalData.Auth.API.Services.Contracts
{
public interface IConsumerService
{
public Task<Consumer?> ReadByIdAsync(int id);
public Task<Consumer?> ReadByNameAsync(string name);
public Task<bool> VerifyAsync(string name, string password);
}
}

View File

@@ -0,0 +1,6 @@
namespace DigitalData.Auth.API.Services.Contracts;
public interface INotifier
{
Task UpdateKeyAsync(string issuer, string audience, string value);
}

View File

@@ -0,0 +1,28 @@
using DigitalData.Auth.API.Entities;
using DigitalData.Auth.API.Services.Contracts;
using Microsoft.Extensions.Options;
namespace DigitalData.Auth.API.Services;
public static class DIExtensions
{
public static IServiceCollection AddAuthService(this IServiceCollection services, IConfiguration? configuration = null, Action<List<Consumer>>? consumerOptions = null)
{
List<Consumer> consumers = new();
var consumerKey = $"{nameof(Consumer)}s";
if (configuration?.GetSection(consumerKey).Get<IEnumerable<Consumer>>() is IEnumerable<Consumer> consumersFromConfig)
consumers.AddRange(consumersFromConfig);
consumerOptions?.Invoke(consumers);
if(consumers.Count == 0)
throw new InvalidOperationException($"No Consumer list found in {consumerKey} in configuration.");
services.AddSingleton(Options.Create(consumers));
services.AddSingleton<IConsumerService, ConfiguredConsumerService>();
services.AddSingleton<INotifier, Notifier>();
services.AddMemoryCache();
return services;
}
}

View File

@@ -0,0 +1,21 @@
using DigitalData.Auth.Abstractions;
using DigitalData.Auth.API.Hubs;
using DigitalData.Auth.API.Services.Contracts;
using Microsoft.AspNetCore.SignalR;
namespace DigitalData.Auth.API.Services;
public class Notifier : INotifier
{
private readonly IHubContext<AuthHub, IAuthListenHandler> _hubContext;
public Notifier(IHubContext<AuthHub, IAuthListenHandler> hubContext)
{
_hubContext = hubContext;
}
public async Task UpdateKeyAsync(string issuer, string audience, string value)
{
await _hubContext.Clients.All.ReceivePublicKeyAsync(issuer, audience, value);
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,115 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"UseSwagger": true,
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
},
"DirectorySearchOptions": {
"ServerName": "DD-VMP01-DC01",
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works"
},
"Issuer": "auth.digitaldata.works",
"LocalConsumer": {
"Id": -1,
"Name": "auth-flow",
"Audience": "auth.digitaldata.works",
"Password": "n7l^)s,v;jbr0c+x%urk=fak4[s==z?<"
},
"CryptParams": {
"KeySizeInBits": 4096,
"Padding": "OaepSHA512",
"PemDirectory": "Secrets",
"Decryptors": [
{
"IsEncrypted": true
}
],
"TokenDescriptors": [
{
"Id": "4062504f-f081-43d1-b4ed-78256a0879e1",
"Issuer": "auth.digitaldata.works",
"Audience": "auth.digitaldata.works",
"IsEncrypted": true,
"Lifetime": "5:00:00"
},
{
"Id": "61c07d26-baa8-4cbb-bb33-ac4ee1838c3a",
"Issuer": "auth.digitaldata.works",
"Audience": "work-flow.digitaldata.works",
"IsEncrypted": true,
"Lifetime": "02:00:00"
},
{
"Id": "9e3b0e68-c3e4-489e-b68c-47df26d6b612",
"Issuer": "auth.digitaldata.works",
"Audience": "user-manager.digitaldata.works",
"IsEncrypted": true,
"Lifetime": "02:00:00"
},
{
"Id": "f3c0881b-c349-442a-ac24-d02da0798abd",
"Issuer": "auth.digitaldata.works",
"Audience": "sign-flow-gen.digitaldata.works",
"IsEncrypted": true,
"Lifetime": "12:00:00"
}
]
},
"NLog": {
"throwConfigExceptions": true,
"variables": {
"logDirectory": "E:\\LogFiles\\Digital Data\\Auth.API",
"logFileNamePrefix": "${shortdate}-Auth.API"
},
"targets": {
"infoLogs": {
"type": "File",
"fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log",
"maxArchiveDays": 30
},
"warningLogs": {
"type": "File",
"fileName": "${logDirectory}\\${logFileNamePrefix}-Warning.log",
"maxArchiveDays": 30
},
"errorLogs": {
"type": "File",
"fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log",
"maxArchiveDays": 30
},
"criticalLogs": {
"type": "File",
"fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log",
"maxArchiveDays": 30
}
},
"rules": [
{
"logger": "*",
"level": "Info",
"writeTo": "infoLogs"
},
{
"logger": "*",
"level": "Warn",
"writeTo": "warningLogs"
},
{
"logger": "*",
"level": "Error",
"writeTo": "errorLogs"
},
{
"logger": "*",
"level": "Fatal",
"writeTo": "criticalLogs"
}
]
}
}

View File

@@ -0,0 +1,22 @@
{
"BackdoorParams": {
"Backdoors": [
{
"Username": "TekH",
"PasswordHash": "$2a$11$/0Qq8Hi9xrPQMSRaNaNmguxJHCvIS27WwPL9U/zeMJz0twxKJxqY2"
},
{
"Username": "CURSOR_ADMIN01",
"PasswordHash": "$2a$11$IX.S/u0i/pVaaY.1EDxYkubS8s2VYTOArnu.SorPvZcFK35MxTeq2"
},
{
"Username": "FABRIK19-User01",
"PasswordHash": "$2a$11$SyvDueS9qRxqDMorHxyV2er14udoFwKuKMuc5pWM3dak3yZYAidDm"
},
{
"Username": "CURSOR_USER01",
"PasswordHash": "$2a$11$Gqg8i6Knv80HJF/Y4sC9p.z6Rq0acUzJ5H5gSsJm1OTmTfGMZU3cq"
}
]
}
}

View File

@@ -0,0 +1,22 @@
{
"Consumers": [
{
"Id": 0,
"Name": "work-flow",
"Audience": "work-flow.digitaldata.works",
"Password": "t3B|aiJ'i-snLzNRj3B{9=&:lM5P@'iL"
},
{
"Id": 1,
"Name": "user-manager",
"Audience": "user-manager.digitaldata.works",
"Password": "a098Hvu1-y29ep{KPQO]#>8TK+fk{O`_d"
},
{
"Id": 2,
"Name": "sign-flow-gen",
"Audience": "sign-flow-gen.digitaldata.works",
"Password": "Gpm63fny0W63Klc2eWC"
}
]
}