mirror of
https://github.com/pcvolkmer/mv64e-rest-to-kafka-gateway
synced 2025-09-13 09:12:51 +00:00
feat: custom HTTP basic user-names
This commit is contained in:
26
README.md
26
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
|
* `LISTEN`: Adresse und Port für eingehende HTTP-Requests. Standardwert: `[::]:3000` - Port `3000` auf allen
|
||||||
Adressen (IPv4 und IPv6)
|
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_BOOTSTRAP_SERVERS`: Zu verwendende Kafka-Bootstrap-Server als kommagetrennte Liste
|
||||||
* `KAFKA_TOPIC`: Zu verwendendes Topic zum Warten auf neue Anfragen. Standardwert: `etl-processor_input`
|
* `KAFKA_TOPIC`: Zu verwendendes Topic zum Warten auf neue Anfragen. Standardwert: `etl-processor_input`
|
||||||
|
|
||||||
@@ -72,17 +72,23 @@ wird.
|
|||||||
|
|
||||||
### Authentifizierung
|
### Authentifizierung
|
||||||
|
|
||||||
Requests müssen einen HTTP-Header `authorization` für HTTP-Basic enthalten. Hier ist es erforderlich, dass der
|
Requests müssen einen HTTP-Header `authorization` für HTTP-Basic enthalten.
|
||||||
Benutzername `token` gewählt wird.
|
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
|
||||||
Es ist hierzu erforderlich, die erforderliche Umgebungsvariable `SECURITY_TOKEN` zu setzen. Dies kann z.B. mit
|
jedoch ein beliebiger Benutzername verwendet werden:
|
||||||
*htpasswd* erzeugt werden:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
htpasswd -Bn token
|
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
|
### Beispiele für HTTP-Requests und resultierende Kafka-Records
|
||||||
|
|
||||||
@@ -146,8 +152,10 @@ Resultierender Kafka-Record:
|
|||||||
|
|
||||||
Es werden keine weiteren patientenbezogenen Daten übermittelt.
|
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.
|
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.
|
Löschanfrage ausgelöst, da keine Modellvorhaben Metadaten enthalten sind.
|
||||||
|
30
src/auth.rs
30
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) = BASE64_STANDARD.decode(split.last().unwrap_or(&""))
|
||||||
&& let Ok(auth) = String::from_utf8(auth)
|
&& let Ok(auth) = String::from_utf8(auth)
|
||||||
{
|
{
|
||||||
|
let split_token = expected_token.split(':').collect::<Vec<_>>();
|
||||||
|
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::<Vec<_>>();
|
let split = auth.split(':').collect::<Vec<_>>();
|
||||||
if split.len() == 2
|
if split.len() == 2
|
||||||
&& split.first() == Some(&"token")
|
&& split.first() == Some(expected_username)
|
||||||
&& let Some(&token) = split.last()
|
&& let Some(&token) = split.last()
|
||||||
&& let Ok(true) = bcrypt::verify(token, expected_token)
|
&& let Ok(true) = bcrypt::verify(token, expected_token)
|
||||||
{
|
{
|
||||||
@@ -48,7 +56,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_reject_basic_auth_without_wrong_token() {
|
fn should_reject_basic_auth_without_valid_token() {
|
||||||
assert!(!check_basic_auth(
|
assert!(!check_basic_auth(
|
||||||
"Basic dG9rZW46MTIzNDU2Nzg5",
|
"Basic dG9rZW46MTIzNDU2Nzg5",
|
||||||
EXPECTED_TOKEN
|
EXPECTED_TOKEN
|
||||||
@@ -56,10 +64,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_accept_basic_auth_without_correct_token() {
|
fn should_accept_basic_auth_with_valid_token() {
|
||||||
assert!(check_basic_auth(
|
assert!(check_basic_auth(
|
||||||
"Basic dG9rZW46dmVyeS1zZWNyZXQ=",
|
"Basic dG9rZW46dmVyeS1zZWNyZXQ=",
|
||||||
EXPECTED_TOKEN
|
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}")
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user