diff --git a/README.md b/README.md index 7856ecd..2d2b353 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Die Anwendung lässt sich auch mit Umgebungsvariablen konfigurieren. * `LISTEN`: Adresse und Port für eingehende HTTP-Requests. Standardwert: `[::]:3000` - Port `3000` auf allen Adressen (IPv4 und IPv6) -* `SECURITY_TOKEN`: Verpflichtende Angabe es Tokens als *bcrypt*-Hash +* `SECURITY_TOKEN`: Verpflichtende Angabe des Benutzernamens und *bcrypt*-Hash des Passworts * `KAFKA_BOOTSTRAP_SERVERS`: Zu verwendende Kafka-Bootstrap-Server als kommagetrennte Liste * `KAFKA_TOPIC`: Zu verwendendes Topic zum Warten auf neue Anfragen. Standardwert: `etl-processor_input` @@ -72,17 +72,23 @@ wird. ### Authentifizierung -Requests müssen einen HTTP-Header `authorization` für HTTP-Basic enthalten. Hier ist es erforderlich, dass der -Benutzername `token` gewählt wird. - -Es ist hierzu erforderlich, die erforderliche Umgebungsvariable `SECURITY_TOKEN` zu setzen. Dies kann z.B. mit -*htpasswd* erzeugt werden: +Requests müssen einen HTTP-Header `authorization` für HTTP-Basic enthalten. +Dazu muss die erforderliche Umgebungsvariable `SECURITY_TOKEN` gesetzt sein. +Der erforderliche Wert kann z.B. mit *htpasswd* erzeugt werden - `token` ist hier der gewählte Benutzername - es kann +jedoch ein beliebiger Benutzername verwendet werden: ``` htpasswd -Bn token ``` -Der hintere Teil (hinter `token:`) entspricht dem *bcrypt*-Hash des Tokens. +Der vordere Teil der Ausgabe ist der Benutzername, der hintere Teil (im Beispiel hinter `token:`) entspricht dem +*bcrypt*-Hash des Tokens, welches als HTTP-Basic-Passwort erwartet wird. + +Ein Beispiel für die Angabe `SECURITY_TOKEN` ist für den Benutzernamen `token` und das Passwort `very-secret`: +`token:$2y$05$LIIFF4Rbi3iRVA4UIqxzPeTJ0NOn/cV2hDnSKFftAMzbEZRa42xSG` + +Zur Kompatibilität mit älteren Versionen kann (nur) bei Wahl des Benutzernamens `token` der Teil `token:` +bei der Angabe entfallen: `$2y$05$LIIFF4Rbi3iRVA4UIqxzPeTJ0NOn/cV2hDnSKFftAMzbEZRa42xSG` ### Beispiele für HTTP-Requests und resultierende Kafka-Records @@ -146,8 +152,10 @@ Resultierender Kafka-Record: Es werden keine weiteren patientenbezogenen Daten übermittelt. -In optionaler Verbindung mit [Key-Based-Retention](https://github.com/pcvolkmer/mv64e-etl-processor#key-based-retention) wird +In optionaler Verbindung mit [Key-Based-Retention](https://github.com/pcvolkmer/mv64e-etl-processor#key-based-retention) +wird lediglich der letzte und aktuelle Record, hier die Information ohne Consent-Zustimmung, in Kafka vorgehalten. -Trifft dieser Kafka-Record im [ETL-Prozessor](https://github.com/pcvolkmer/mv64e-etl-processor) ein, so wird dort ebenfalls eine +Trifft dieser Kafka-Record im [ETL-Prozessor](https://github.com/pcvolkmer/mv64e-etl-processor) ein, so wird dort +ebenfalls eine Löschanfrage ausgelöst, da keine Modellvorhaben Metadaten enthalten sind. diff --git a/src/auth.rs b/src/auth.rs index a7a0211..d254e81 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -9,9 +9,17 @@ pub fn check_basic_auth(auth_header: &str, expected_token: &str) -> bool { && let Ok(auth) = BASE64_STANDARD.decode(split.last().unwrap_or(&"")) && let Ok(auth) = String::from_utf8(auth) { + let split_token = expected_token.split(':').collect::>(); + let expected_username = if split_token.len() == 2 { + split_token.first().unwrap_or(&"token") + } else { + &"token" + }; + let expected_token = split_token.get(1).unwrap_or(&expected_token); + let split = auth.split(':').collect::>(); if split.len() == 2 - && split.first() == Some(&"token") + && split.first() == Some(expected_username) && let Some(&token) = split.last() && let Ok(true) = bcrypt::verify(token, expected_token) { @@ -48,7 +56,7 @@ mod tests { } #[test] - fn should_reject_basic_auth_without_wrong_token() { + fn should_reject_basic_auth_without_valid_token() { assert!(!check_basic_auth( "Basic dG9rZW46MTIzNDU2Nzg5", EXPECTED_TOKEN @@ -56,10 +64,26 @@ mod tests { } #[test] - fn should_accept_basic_auth_without_correct_token() { + fn should_accept_basic_auth_with_valid_token() { assert!(check_basic_auth( "Basic dG9rZW46dmVyeS1zZWNyZXQ=", EXPECTED_TOKEN )); } + + #[test] + fn should_accept_basic_auth_with_custom_username() { + assert!(check_basic_auth( + "Basic Y3VzdG9tdXNlcjp2ZXJ5LXNlY3JldA==", + &format!("customuser:{EXPECTED_TOKEN}") + )); + } + + #[test] + fn should_reject_basic_auth_without_correct_custom_username() { + assert!(!check_basic_auth( + "Basic Y3VzdG9tdXNlcjp2ZXJ5LXNlY3JldA==", + &format!("otheruser:{EXPECTED_TOKEN}") + )); + } }