Schnittstellen
SIP2 Response Handler
Einleitung
Diese Toolchain überwacht eine Protokolldatei auf SIP2-Antwortnachrichten und leitet diese an einen geschützten rocklog Endpunkt zur Verarbeitung weiter.
Skripte
post_sip2_response.sh: Sendet einzelne SIP2-Nachrichten an den Endpunktwatch_sip2.sh: Überwacht die Protokolldatei und löst post_sip2_response.sh für neue Einträge aus
Kontrollfluss
+-------------------+ +------------------+ +-----------------+
| | SIP2 | | writes | |
| Bibliotheca |-------->| SIP2 Interceptor |------->| SIP2 |
| Sorter | msgs | | to file| output.log |
+-------------------+ +------------------+ +-----------------+
|
| observes
v
+-------------------+ +------------------+ +-----------------+
| | Bearer | | reads | |
| Keycloak |-------->| post_sip2 |<--------| watch_sip2.sh |
| Auth Server | Token | _response.sh | line | |
+-------------------+ +------------------+ +-----------------+
|
| POST SIP2 msg
v
+-------------------+ +------------------+
| | Stock | |
| Rocklog |<----------| Rocklog Backend |
| Stock Management | Transfer | |
+-------------------+ +------------------+
Ablauf:
1. Sorter ----[SIP2 Nachrichten]----> Interceptor
2. Interceptor ----[schreibt]----> output.log
3. watch_sip2.sh ----[überwacht]----> output.log
4. watch_sip2.sh ----[triggert]----> post_sip2_response.sh
5. post_sip2_response.sh ----[fordert an]----> Keycloak
6. Keycloak ----[sendet Token]----> post_sip2_response.sh
7. post_sip2_response.sh ----[POSTs SIP2]----> Rocklog Backend
8. Rocklog Backend ----[transferiert Bestand]----> Rocklog Stock Management
Referenzimplementierung post_sip2_response.sh
Dieses Skript wird verwendet, um eine SIP2-Antwortnachricht an den geschützten Endpunkt zu senden. Zuerst wird das Skript ein gültiges Bearer-Token von Keycloak (rocklog Authentication Service) abgerufen. Dann wird eine POST-Anfrage an den geschützten Endpunkt mit der SIP2-Antwortnachricht gesendet.
#!/usr/bin/env bash
##
## Dieses Skript wird verwendet, um eine SIP2-Antwortnachricht an den geschützten Endpunkt zu senden
##
# Überprüfen, ob die erforderlichen Parameter vorhanden sind
if [ $# -ne 6 ]; then
echo "Usage: $0 <keycloak_token_url> <client_id> <client_secret> <token_file> <protected_url> <body>"
echo
echo "Example:"
echo "$0 http://<rocklog keycloak host>/realms/unibas/protocol/openid-connect/token <client_id> <client_secret> /tmp/.myapp-token http://<rocklog_host>/v1/protected/sip2/responses 'SIP2_MESSAGE_HERE'"
exit 1
fi
KEYCLOAK_URL="$1"
CLIENT_ID="$2"
CLIENT_SECRET="$3"
TOKEN_FILE="$4"
PROTECTED_URL="$5"
BODY="$6"
get_new_token() {
response=$(curl -s \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}" \
"$KEYCLOAK_URL")
# Token und Ablaufzeit extrahieren
access_token=$(echo "$response" | jq -r '.access_token')
expires_in=$(echo "$response" | jq -r '.expires_in')
if [ "$access_token" = "null" ]; then
echo "Error retrieving access token: $response" >&2
exit 1
fi
# Ablaufzeit berechnen
current_time=$(date +%s)
expires_at=$((current_time + expires_in))
# Token und Ablaufzeit in TOKEN_FILE speichern
echo "{\"access_token\": \"${access_token}\", \"expires_at\": ${expires_at}}" > "${TOKEN_FILE}"
}
get_valid_token() {
if [ -f "${TOKEN_FILE}" ]; then
access_token=$(jq -r '.access_token' "${TOKEN_FILE}")
expires_at=$(jq -r '.expires_at' "${TOKEN_FILE}")
current_time=$(date +%s)
if [ "$current_time" -lt "$expires_at" ]; then
# Token noch gültig
echo "${access_token}"
return
fi
fi
# Wenn wir hier ankommen, wurde kein gültiges Token gefunden, also ein neues abrufen
get_new_token
jq -r '.access_token' "${TOKEN_FILE}"
}
# Ein gültiges Token abrufen
token=$(get_valid_token)
# Die POST-Anfrage mit der bereitgestellten Nachricht als text/plain senden
response=$(curl -s -v -X POST \
-H "Authorization: Bearer $token" \
-H "Content-Type: text/plain" \
--data "$BODY" \
"$PROTECTED_URL")
echo "$response"
Wichtige Implementierungsdetails
Protokollrotation und Dateihandhabung
Der Watcher verwendet tail --follow=name anstelle von nur tail -f, um die Protokollrotation korrekt zu handhaben. Dies stellt sicher:
- Fortsetzung der Überwachung auch bei Protokollrotation
- Automatischer Wechsel zur neuen Datei nach Rotation
- Erstellung der Protokolldatei, falls diese nicht existiert
Beispielimplementierung in watch_sip2.sh:
der Parameter <log_file> ist die Protokolldatei, die überwacht wird. Diese Datei wird automatisch erstellt, falls sie nicht existiert.
Technische Details zur Verarbeitung von SIP2-Protokollnachrichten
Die Verarbeitung von SIP2-Nachrichten erfordert besondere Aufmerksamkeit bei der Behandlung von Zeilenumbrüchen, da diese je nach Quelle unterschiedlich sein können:
- Windows-Systeme verwenden \r\n (Carriage Return + Line Feed)
- Unix/Linux-Systeme verwenden \n (Line Feed)
- Ältere Mac-Systeme verwenden \r (Carriage Return)
Unsere Implementierung verwendet eine Kombination aus stdbuf und tr, um diese unterschiedlichen Zeilenenden einheitlich zu behandeln:
stdbuf -oLdeaktiviert die Ausgabepufferung, sodass jede Zeile sofort verarbeitet wirdtr '\r' '\n'wandelt alle Carriage Returns in Line Feeds um- Die Pipe-Kombination ermöglicht eine robuste Verarbeitung aller SIP2-Nachrichten, unabhängig von ihrer Herkunft
Diese Lösung gewährleistet eine zuverlässige Verarbeitung von SIP2-Protokollnachrichten aus verschiedenen Quellsystemen.
Implementierung des Protokoll-Watchers
Das folgende Skript implementiert einen robusten Watcher für SIP2-Protokollnachrichten. Besondere Merkmale sind:
- Zuverlässige Behandlung von Protokollrotation durch
--follow=name - Automatische Erstellung der Protokolldatei falls nicht vorhanden
- Echtzeitverarbeitung durch Deaktivierung der Pufferung
- Universelle Behandlung von Zeilenumbrüchen für maximale Kompatibilität
- Sichere Authentifizierung über Keycloak
- Automatische Token-Erneuerung bei Ablauf
Das Skript ist so konzipiert, dass es als Systemdienst laufen kann und dabei alle wichtigen Aspekte der Protokollverarbeitung und Sicherheit berücksichtigt.
#!/usr/bin/env bash
# watch_sip2.sh
# Check for required parameters
if [ $# -ne 6 ]; then
echo "Usage: $0 <keycloak_token_url> <client_id> <client_secret> <token_file> <protected_url> <log_file>"
echo
echo "Example:"
echo "$0 http://localhost:81/keycloak/realms/unibas/protocol/openid-connect/token werner-backend supersecret /tmp/.myapp-token http://localhost:8080/v1/protected/sip2/responses /var/log/sip2_responses.log"
exit 1
fi
KEYCLOAK_URL="$1"
CLIENT_ID="$2"
CLIENT_SECRET="$3"
TOKEN_FILE="$4"
PROTECTED_URL="$5"
LOG_FILE="$6"
# Create log file if it doesn't exist
touch "$LOG_FILE"
# Use tail --follow=name to handle log rotation
# Use tail with a custom delimiter
# Use stdbuf to disable buffering and handle \r as line endings
stdbuf -oL tail --follow=name -n 0 "$LOG_FILE" | stdbuf -oL tr '\r' '\n' | while read -r line; do
./post_sip2_response.sh \
"$KEYCLOAK_URL" \
"$CLIENT_ID" \
"$CLIENT_SECRET" \
"$TOKEN_FILE" \
"$PROTECTED_URL" \
"$line"
done
Skript-Berechtigungen
Beiden Skripten ausführbare Berechtigungen erteilen:
chmod +x post_sip2_response.sh
chmod +x watch_sip2.sh
Service-Konfiguration
Systemd Service
- Erstellen eines dedizierten Service-Benutzers:
sudo useradd -r -s /bin/false <specific_user>
- Erstellen einer systemd Service-Datei unter
/etc/systemd/system/sip2-watcher.service:
[Unit]
Description=SIP2 Response Watcher Service
After=network.target
[Service]
Type=simple
User=<specific_user>
Group=<specific_user>
WorkingDirectory=/opt/werner/bin
ExecStart=/<path_to_watch_sip2.sh> <keycloak_token_url> <client_id> <client_secret> <token_file> <protected_url> <log_file>
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
- Installation und Aktivierung des Services:
sudo systemctl daemon-reload
sudo systemctl enable sip2-watcher.service
sudo systemctl start sip2-watcher.service
Service-Protokolle
Status und Protokolle des Services überprüfen:
sudo systemctl status sip2-watcher.service
sudo journalctl -u sip2-watcher.service