Skip to content

Commit

Permalink
Merge branch 'main' into gysimichael-patch-3
Browse files Browse the repository at this point in the history
  • Loading branch information
MiraGeowerkstatt authored Mar 20, 2024
2 parents d8212ce + 6e5e2b6 commit 8a2d0b2
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 21 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,30 @@ Mit `docker-compose up` kann eine funktionierende Infrastruktur hochgefahren wer
| .NET REST API (`v2`)[^1] | [localhost:5000](http://localhost:5000/) [localhost:3000/api/v2](http://localhost:3000/api/v2) | n/a | n/a |
| OIDC Server | [localhost:4011](http://localhost:4011/) | `admin` | `swissforages` |

[^1]: Authentifizierung via `Authorization` Header mit Bearer-Token von OIDC Server. Login-Konfigurationen können in [config/oidc-mock-users.json](./config/oidc-mock-users.json) getätigt werden.
[^1]: Authentifizierung via `Authorization` Header mit Bearer-Token (`identity_token`) von OIDC Server. Login-Konfigurationen können in [config/oidc-mock-users.json](./config/oidc-mock-users.json) getätigt werden.

❌Der Debug Output der Tornado REST API ist aktuell in Visual Studio nicht sichtbar. Bitte den Container-Log benutzen `docker compose logs api --follow` oder direkt in Visual Studio im _Containers_-Tab.

## Cypress Tests

Die Cypress Tests können mit `npm run cy` oder `npm run test` gestartet werden. Sie werden zudem automatisch in der CI/CD Pipeline ausgeführt. Das Projekt ist mit [Cypress Cloud](https://cloud.cypress.io/) konfiguriert, wodurch unter anderem die parallele Ausführung der End-to-End (E2E) Tests ermöglicht wird. Testergebnisse und Aufzeichnungen sind ebenfalls direkt in [Cypress Cloud](https://currents.dev/) einsehbar, was die Identifikation und Behebung möglicher Fehler und Probleme erleichtert. Um die detaillierten Testergebnisse einzusehen und die E2E-Tests des Projekts zu debuggen, kann die [Cypress Dashboard-Seite](https://cloud.cypress.io/projects/gv8yue/runs) besucht werden.

## Authentifizierung & Architektur

Die Applikation nutzt das OpenID Connect (OIDC) Protokoll für die Authentifizierung und Teile der Autorisierung. Die Authentifizierung erfolgt über den OIDC Server, welcher in der Entwicklungsumgebung durch [soluto/oidc-server-mock](https://github.com/Soluto/oidc-server-mock) auf Basis von [IdentityServer4](https://identityserver4.readthedocs.io/) simuliert wird. Die Applikation nutzt den _Authorization Code Flow_ mit _PKCE_ für die Authentifizierung. Für den Zugriff auf die API wird der `identity_token` verwendet, welcher die Benutzerinformationen enthält. Die Grundsätzliche Autorisierung erfolgt über die Gruppenzugehörigkeit des Benutzers, welche im `identity_token` enthalten ist. Die Autorisierung auf API-Ebene erfolgt über die in der Datenbank definierten Workgroups & Administratoren-Rechte.

### OpenID Connect (OIDC) Konfiguration

Die Applikation benötigt für die Authentifizierung und Autorisierung eine gültige OIDC-Konfiguration. Diese Konfiguration wird ausschliesslich in BDMS.Api benötigt. Sie wird über `/api/v2/settings/auth` dem Client zur Verfügung gestellt. Die Werte werden durch den OIDC Server vergeben. Die folgenden Konfigurationen müssen gesetzt werden:

| Parameter | Beschreibung |
| :-- | :-- |
| Auth:Authority | Die URL des OpenID Connect Servers. Es ist vorausgesetzt, dass der Server ein gültiges [OpenID Connect Discovery Dokument](https://openid.net/specs/openid-connect-discovery-1_0.html) zur Verfügung stellt. |
| Auth:Audience | Der Wert des `aud` Claims, welcher in den `identity_token` des [OIDC Servers](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) enthalten ist. Die Audience wird als `client_id` verwendet beim Authentifizieren auf dem OIDC Endpunkt. |
| Auth:Scopes | Die benötigten Scopes, welche beim Authentifizieren auf dem OIDC Endpunkt angefragt werden. Default: `openid profile` |
| Auth:GroupClaimType | Der Name des Claims, welcher die Gruppenzugehörigkeit des Benutzers enthält. Default: `cognito:groups` |
| Auth:AuthorizedGroupName | Der Name der Gruppe, welche autorisiert ist, um auf die API zuzugreifen. |

### Legacy API Authentifizierung

Requests and das Legacy API werden mit dem [YARP Reverse Proxy](https://microsoft.github.io/reverse-proxy/articles/config-files.html) durch das neue API weitergeleitet. Die Authentifizierung wird über das neue API übernommen. Die Authentifizierung erfolgt mit der [LegacyApiAuthenticationMiddleware](src\api\Authentication\LegacyApiAuthenticationMiddleware.cs) welche den `Authorization` Header mit dem `sub` Claim des Benutzers befüllt. **⚠️Da die Validierung des `identity_tokens` dabei verloren geht, darf das Legacy API nicht öffentlich verfügbar sein**. Die Konfiguration des Legacy API Endpunkts erfolgt über die [Konfiguration](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) von `ReverseProxy:Clusters:pythonApi:Destinations:legacyApi:Address`.
2 changes: 1 addition & 1 deletion src/client/cypress/e2e/editor/backfill.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe("Backfill crud tests", () => {
setSelect("casingId", 3);
saveForm();

cy.wait(500);
cy.wait(1000);
addItem("addBackfill");
cy.wait("@codelist_GET");
setInput("notes", "Lorem.");
Expand Down
2 changes: 1 addition & 1 deletion src/client/cypress/e2e/editor/casing.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe("Casing crud tests", () => {
cy.get("[data-cy=completion-content-tab-instrumentation]").click();
cy.wait("@instrumentation_GET");

cy.wait(500);
cy.wait(1000);
addItem("addInstrument");
cy.wait("@casing_GET");

Expand Down
24 changes: 13 additions & 11 deletions src/client/cypress/e2e/editor/completion.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ describe("completion crud tests", () => {
// switch tabs
// existing editing to other existing: no prompt should be displayed when no changes have been made
startEditHeader();
cy.wait(500);
setHeaderTab(0);
cy.get('[data-cy="prompt"]').should("not.exist");
isHeaderTabSelected(0);
Expand Down Expand Up @@ -405,6 +406,7 @@ describe("completion crud tests", () => {
startBoreholeEditing();

// cancel switching content tabs
cy.wait(1000);
addItem("addCasing");
cy.wait("@codelist_GET");
setInput("name", "casing 1", "casing-card.0.edit");
Expand All @@ -424,7 +426,7 @@ describe("completion crud tests", () => {
cy.get('[data-cy="casing-card.0"]').should("not.exist");

// save when switching content tabs
cy.wait(500);
cy.wait(1000);
addItem("addCasing");
cy.wait("@codelist_GET");
setInput("name", "casing 1", "casing-card.0.edit");
Expand All @@ -440,7 +442,7 @@ describe("completion crud tests", () => {
// cancel switching header tabs when content changes are present
setContentTab("backfill");
cy.wait("@backfill_GET");
cy.wait(500);
cy.wait(1000);
addItem("addBackfill");
cy.wait("@casing_GET");
setInput("fromDepth", 0);
Expand All @@ -463,7 +465,7 @@ describe("completion crud tests", () => {
cy.get('[data-cy="backfill-card.0"]').should("not.exist");

// save content changes when switching header tabs
cy.wait(500);
cy.wait(1000);
addItem("addBackfill");
cy.wait("@casing_GET");
setInput("fromDepth", 0);
Expand All @@ -481,7 +483,7 @@ describe("completion crud tests", () => {
// cancel header changes, no prompt should be displayed for content changes because tab switching was already canceled
setContentTab("instrumentation");
cy.wait("@instrumentation_GET");
cy.wait(500);
cy.wait(1000);
addItem("addInstrument");
cy.wait("@casing_GET");
setInput("fromDepth", "0");
Expand All @@ -504,7 +506,7 @@ describe("completion crud tests", () => {
// reset header changes, cancel content changes
addCompletion();
handlePrompt("Completion: Unsaved changes", "Reset");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Cancel");
isHeaderTabSelected(0);
isContentTabSelected("instrumentation");
Expand All @@ -517,7 +519,7 @@ describe("completion crud tests", () => {
setInput("name", "Compl-1 updated", "completion-header");
addCompletion();
handlePrompt("Completion: Unsaved changes", "Reset");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Reset");
isHeaderTabSelected(1);
setHeaderTab(0);
Expand All @@ -527,7 +529,7 @@ describe("completion crud tests", () => {
cy.get('[data-cy="instrumentation-card.0"]').should("not.exist");

//reset header changes, save content changes
cy.wait(500);
cy.wait(1000);
addItem("addInstrument");
cy.wait("@casing_GET");
setInput("fromDepth", "0");
Expand All @@ -539,7 +541,7 @@ describe("completion crud tests", () => {
setInput("name", "Compl-1 updated", "completion-header");
addCompletion();
handlePrompt("Completion: Unsaved changes", "Reset");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Save");
isHeaderTabSelected(1);
setHeaderTab(0);
Expand All @@ -554,7 +556,7 @@ describe("completion crud tests", () => {
setInput("name", "Compl-1 updated", "completion-header");
addCompletion();
handlePrompt("Completion: Unsaved changes", "Save");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Cancel");
isHeaderTabSelected(0);
isContentTabSelected("instrumentation");
Expand All @@ -566,7 +568,7 @@ describe("completion crud tests", () => {
setInput("name", "Compl-1 updated again", "completion-header");
addCompletion();
handlePrompt("Completion: Unsaved changes", "Save");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Reset");
isHeaderTabSelected(1);
setHeaderTab(0);
Expand All @@ -582,7 +584,7 @@ describe("completion crud tests", () => {
setInput("name", "Compl-1 updated again and again", "completion-header");
addCompletion();
handlePrompt("Completion: Unsaved changes", "Save");
cy.wait(500);
cy.wait(1000);
handlePrompt("Instrumentation: Unsaved changes", "Save");
isHeaderTabSelected(1);
setHeaderTab(0);
Expand Down
4 changes: 2 additions & 2 deletions src/client/cypress/e2e/editor/coordinates.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ describe("Tests for editing coordinates of a borehole.", () => {

it("creates new borehole and adds coordinates", () => {
// fill inputs for LV95
cy.wait(500);
cy.wait(1000);
cy.get("@LV95X-input").type("2645123");
cy.wait(500);
cy.wait(1000);
cy.get("@LV95Y-input").type("1245794");
// wait edits of all 4 inputs to complete
cy.wait(["@location", "@edit_patch", "@edit_patch", "@edit_patch"]);
Expand Down
4 changes: 2 additions & 2 deletions src/client/cypress/e2e/editor/fieldMeasurement.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ describe("Tests for the field measurement editor.", () => {
// switch to german
cy.get('[data-cy="menu"]').click({ force: true });
cy.contains("span", "DE").click({ force: true });
cy.wait(1000);

// create field measurement
cy.wait(500);
addItem("addFieldMeasurement");
cy.wait("@casing_GET");

Expand Down Expand Up @@ -90,7 +90,7 @@ describe("Tests for the field measurement editor.", () => {
saveForm();
cy.wait("@fieldmeasurement_GET");

cy.wait(500);
cy.wait(1000);
addItem("addFieldMeasurement");
cy.wait("@casing_GET");
setInput("fromDepthM", 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe("Tests for the groundwater level measurement editor.", () => {
// switch to german
cy.get('[data-cy="menu"]').click({ force: true });
cy.contains("span", "DE").click({ force: true });
cy.wait(1000);

// create groundwater level measurement
addItem("addGroundwaterLevelMeasurement");
Expand Down Expand Up @@ -95,7 +96,7 @@ describe("Tests for the groundwater level measurement editor.", () => {
saveForm();
cy.wait("@groundwaterlevelmeasurement_GET");

cy.wait(500);
cy.wait(1000);
addItem("addGroundwaterLevelMeasurement");
cy.wait("@casing_GET");
setInput("fromDepthM", 0);
Expand Down
3 changes: 2 additions & 1 deletion src/client/cypress/e2e/editor/hydrotest.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe("Tests for the hydrotest editor.", () => {
// switch to german
cy.get('[data-cy="menu"]').click({ force: true });
cy.contains("span", "DE").click({ force: true });
cy.wait(1000);

// create hydrotest
addItem("addHydrotest");
Expand Down Expand Up @@ -127,7 +128,7 @@ describe("Tests for the hydrotest editor.", () => {
saveForm();
cy.wait("@hydrotest_GET");

cy.wait(500);
cy.wait(1000);
addItem("addHydrotest");
cy.wait("@casing_GET");
setInput("fromDepthM", 0);
Expand Down
3 changes: 2 additions & 1 deletion src/client/cypress/e2e/editor/waterIngress.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe("Tests for the wateringress editor.", () => {
// switch to german
cy.get('[data-cy="menu"]').click({ force: true });
cy.contains("span", "DE").click({ force: true });
cy.wait(1000);

// create wateringress
addItem("addWaterIngress");
Expand Down Expand Up @@ -97,7 +98,7 @@ describe("Tests for the wateringress editor.", () => {
saveForm();
cy.wait("@wateringress_GET");

cy.wait(500);
cy.wait(1000);
addItem("addWaterIngress");
cy.wait("@casing_GET");
setInput("fromDepthM", 0);
Expand Down

0 comments on commit 8a2d0b2

Please sign in to comment.