Skip to content

fix(backend): Pangolin-Standard-Header (Remote-User + X-Pangolin-Token) als SSO-Pfad#96

Merged
strausmann merged 4 commits into
mainfrom
fix/backend-pangolin-standard-headers
Jun 1, 2026
Merged

fix(backend): Pangolin-Standard-Header (Remote-User + X-Pangolin-Token) als SSO-Pfad#96
strausmann merged 4 commits into
mainfrom
fix/backend-pangolin-standard-headers

Conversation

@strausmann
Copy link
Copy Markdown
Owner

Summary

Behebt die SSO-Header-Inkompatibilität zwischen Pangolin und dem label-printer-hub Backend. Das Backend erwartete bisher X-Pangolin-User, aber Pangolin sendet nach dem Standard Remote-User + X-Pangolin-Token (Trust-Token für Verifikation) — identisch mit der Hangar-Implementierung.

Contributor License Agreement (CLA)

By opening this pull request you affirm that you have read and agree to the
project's Contributor License Agreement for the contribution(s)
included here.

Linked issue

Refs #96

Type of change

  • Bug fix (non-breaking)

Hardware tested on

  • Brother PT-Series (model: ___)
  • Brother QL-Series (model: ___)
  • Other: ___
  • No hardware impact

Test coverage

  • Added/updated unit tests
  • Added/updated integration tests
  • Hardware tests added (if applicable)
  • Existing tests still pass

876 tests pass, 6 neue Tests hinzugefügt (TDD: RED→GREEN)

Checklist

  • PR title follows Conventional Commits (feat(...): ... etc.)
  • All commits are signed off (if applicable)
  • CHANGELOG entry isn't needed (semantic-release generates it)
  • Documentation updated (if behaviour, API, or config changed)
  • No private IPs, hostnames, domains, real tokens, or PII in commits
  • CI is green (will be checked again after CI runs)

Migration / breaking change notes

Keine Breaking Change. Neue Env-Vars haben sichere Defaults:

  • PRINTER_HUB_SSO_USER_HEADER (default: Remote-User)
  • PRINTER_HUB_SSO_TRUST_HEADER (default: X-Pangolin-Token)
  • PRINTER_HUB_SSO_TRUST_TOKEN (default: "" = SSO via Remote-User deaktiviert)

Legacy X-Pangolin-User wird weiterhin ohne Trust-Token akzeptiert (Rückwärtskompatibilität für PR #95 Frontend-Forwarding).

Änderungen

backend/app/config.py

Drei neue Settings:

  • sso_user_header — konfigurierbarer User-Header (default: Remote-User)
  • sso_trust_header — konfigurierbarer Trust-Header (default: X-Pangolin-Token)
  • sso_trust_token — statischer Trust-Token (leer = Pfad deaktiviert, sicherer Default)

backend/app/auth/dependencies.py

_has_pangolin_sso_session() erweitert:

  1. Pangolin-Standard: Remote-User + X-Pangolin-Token mit Trust-Token-Verifikation
  2. Legacy: X-Pangolin-User (kein Trust-Token nötig, Rückwärtskompatibilität)

backend/.env.example

Dokumentation der neuen SSO-Variablen mit Konfigurationshinweisen.

backend/tests/unit/auth/test_dependencies.py

6 neue Tests:

  • test_sso_session_with_remote_user_and_trust_token — Hauptpfad → 200
  • test_sso_session_remote_user_without_trust_token — kein Token → 401
  • test_sso_session_trust_token_wrong_value — falscher Token → 401
  • test_sso_no_trust_token_configured_rejects_remote_user — leeres Token = disabled → 401
  • test_sso_backwards_compat_x_pangolin_user — Legacy-Header → 200
  • test_sso_configurable_header_names — benutzerdefinierte Header-Namen → 200

…n) als SSO-Pfad

Refs #96

Implementiert den Pangolin-Standard für SSO-Header-Authentifizierung analog Hangar:

- Remote-User (konfigurierbar via PRINTER_HUB_SSO_USER_HEADER) als User-Header
- X-Pangolin-Token (konfigurierbar via PRINTER_HUB_SSO_TRUST_HEADER) als Trust-Token
- PRINTER_HUB_SSO_TRUST_TOKEN muss gesetzt sein, sonst ist der Pfad deaktiviert (sicherer Default)
- Rückwärtskompatibilität: X-Pangolin-User wird weiterhin ohne Trust-Token akzeptiert
- 6 neue Tests (TDD: RED→GREEN), 876 Tests grün insgesamt
Copilot AI review requested due to automatic review settings June 1, 2026 14:16
@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented Jun 1, 2026

⚠️ GitGuardian has uncovered 2 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
33543112 Triggered Generic High Entropy Secret 3f7e830 backend/tests/unit/auth/test_dependencies.py View secret
33543112 Triggered Generic High Entropy Secret f0d77cf backend/tests/unit/auth/test_dependencies.py View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Diese PR behebt die SSO-Header-Inkompatibilität mit Pangolin, indem das Backend neben dem Legacy-Header X-Pangolin-User nun auch den Pangolin-Standardpfad Remote-User + X-Pangolin-Token (mit Trust-Token-Verifikation) unterstützt und über neue Settings konfigurierbar macht.

Changes:

  • Neue Settings für SSO-Header-Namen und Trust-Token (sso_user_header, sso_trust_header, sso_trust_token) inkl. .env.example-Dokumentation.
  • Auth-Dependency erweitert: Standard-Headers + Trust-Token-Verifikation (plus Legacy-Fallback X-Pangolin-User).
  • 6 neue Unit-Tests für den Standardpfad, Fehlerszenarien und konfigurierbare Header-Namen.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
backend/app/config.py Fügt neue Settings zur SSO-Header-/Trust-Token-Konfiguration hinzu.
backend/app/auth/dependencies.py Implementiert den neuen Pangolin-Standard-SSO-Pfad mit Trust-Token sowie Legacy-Fallback.
backend/.env.example Dokumentiert neue Env-Variablen für den SSO-Standardpfad.
backend/tests/unit/auth/test_dependencies.py Ergänzt Unit-Tests für den neuen Standardpfad und dessen Konfiguration.

Comment thread backend/.env.example Outdated
# gesetzt ist UND der Header-Wert exakt übereinstimmt.
# Leer lassen = SSO via Remote-User deaktiviert (Standard: deaktiviert).
#
# Konfiguration in Pangolin Resource (labels.strausmann.cloud):
Comment on lines +118 to +125
trust_token = settings.sso_trust_token
if trust_token:
user_header = settings.sso_user_header
trust_header = settings.sso_trust_header
user_value = request.headers.get(user_header, "")
token_value = request.headers.get(trust_header, "")
if user_value and token_value == trust_token:
return True
Comment thread backend/app/config.py
Comment on lines +116 to +118
sso_user_header: str = "Remote-User"
sso_trust_header: str = "X-Pangolin-Token"
sso_trust_token: str = "" # leer = SSO via Remote-User deaktiviert
Comment on lines +473 to +475
# --------------------------------------------------------------------------
# Path 2b: Pangolin-Standard-Headers (Remote-User + X-Pangolin-Token)
# --------------------------------------------------------------------------
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Dieser Pull Request implementiert eine sicherere SSO-Authentifizierungsmethode zwischen dem Pangolin-Reverse-Proxy und dem Backend. Durch die Einführung eines statischen Trust-Tokens wird die Integrität der übermittelten Benutzerinformationen sichergestellt, während gleichzeitig die Abwärtskompatibilität für bestehende interne Aufrufe gewahrt bleibt. Die Konfiguration erfolgt über neue Umgebungsvariablen, was eine flexible Anpassung an verschiedene Deployment-Umgebungen ermöglicht.

Highlights

  • SSO-Authentifizierung: Implementierung des Pangolin-Standard-SSO-Pfads mittels 'Remote-User' und 'X-Pangolin-Token' zur sicheren Identitätsverifikation.
  • Rückwärtskompatibilität: Beibehaltung des Legacy-Headers 'X-Pangolin-User' für bestehende Frontend-Forwarding-Prozesse.
  • Konfigurierbarkeit: Einführung neuer Umgebungsvariablen zur flexiblen Anpassung der SSO-Header-Namen und des Trust-Tokens.
  • Testabdeckung: Erweiterung der Testsuite um 6 neue Unit-Tests zur Validierung der verschiedenen SSO-Szenarien und Sicherheitsmechanismen.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

- SIM103: Legacy-SSO-Pfad nutzt jetzt `return bool(...)` statt if/return-True/return-False
- F401: `import app.models` (ungenutzt) aus allen Test-Hilfsfunktionen entfernt
- E501: Zwei überlange Zeilen in Test-Docstrings und Assert-Message gekürzt
- .env.example: `labels.strausmann.cloud` aus Kommentar entfernt (Privacy-Scan-Treffer)

Refs #96
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.89%. Comparing base (0d2de27) to head (6c1c347).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #96      +/-   ##
==========================================
- Coverage   89.92%   89.89%   -0.03%     
==========================================
  Files          89       89              
  Lines        4008     4019      +11     
  Branches      343      345       +2     
==========================================
+ Hits         3604     3613       +9     
- Misses        315      317       +2     
  Partials       89       89              
Components Coverage Δ
Printer Backends (transport) 87.50% <ø> (ø)
Printer Models (drivers) 91.42% <ø> (ø)
Services 91.23% <ø> (-0.16%) ⬇️
REST API 85.08% <ø> (ø)
Pydantic Schemas 100.00% <ø> (ø)
Integration Plugins 100.00% <ø> (ø)
Files with missing lines Coverage Δ
backend/app/auth/dependencies.py 65.62% <100.00%> (+3.12%) ⬆️
backend/app/config.py 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

Flag Coverage Δ
backend 89.89% <100.00%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0d2de27...6c1c347. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

GitGuardian erkennt den 64-Zeichen-Hex-Wert als potenzielles Secret.
Die Annotation macht den Test-Fixture-Charakter explizit.

Refs #96
GitGuardian GitHub App respektiert paths-ignore nicht im PR-Diff-Scan.
Inline-Annotation # ggignore markiert den Test-Fixture als bekannt-harmlos.

Refs #96
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces standard Pangolin-SSO header authentication using Remote-User and a configurable X-Pangolin-Token trust token, while maintaining backwards compatibility with the legacy X-Pangolin-User header. It updates configuration settings, dependency resolution, and adds comprehensive unit tests. Feedback recommends replacing a real domain name in .env.example with a placeholder to comply with privacy guidelines, defining the trust token as a SecretStr to prevent accidental log exposure, and utilizing secrets.compare_digest during token validation to mitigate timing attacks.

Comment thread backend/.env.example
# gesetzt ist UND der Header-Wert exakt übereinstimmt.
# Leer lassen = SSO via Remote-User deaktiviert (Standard: deaktiviert).
#
# Konfiguration in Pangolin Resource (Header-Injection):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

According to the repository style guide, real hostnames, domains, or PII must not be hardcoded to prevent the maintainer's network from being deducible. Please use an example.com placeholder instead of labels.strausmann.cloud.

#   Konfiguration in Pangolin Resource (labels.example.com):
References
  1. Flag any hardcoded LAN IPs, real hostnames, real domains, real tokens, or PII. The maintainer's network must not be deducible from this repository. (link)

Comment thread backend/app/config.py
# übereinstimmt. Ein leeres sso_trust_token deaktiviert diesen Pfad.
sso_user_header: str = "Remote-User"
sso_trust_header: str = "X-Pangolin-Token"
sso_trust_token: str = "" # leer = SSO via Remote-User deaktiviert
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

To prevent the sensitive trust token from being accidentally leaked in logs, console output, or error traces, it should be defined as a SecretStr instead of a plain str, matching the pattern used for other API keys in this class.

Suggested change
sso_trust_token: str = "" # leer = SSO via Remote-User deaktiviert
sso_trust_token: SecretStr = SecretStr("") # leer = SSO via Remote-User deaktiviert

Comment on lines +118 to +125
trust_token = settings.sso_trust_token
if trust_token:
user_header = settings.sso_user_header
trust_header = settings.sso_trust_header
user_value = request.headers.get(user_header, "")
token_value = request.headers.get(trust_header, "")
if user_value and token_value == trust_token:
return True
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

To improve security, we should:

  1. Use secrets.compare_digest to prevent timing attacks when validating the trust token.
  2. Retrieve the token value using .get_secret_value() since sso_trust_token should be configured as a SecretStr to prevent accidental exposure in logs.
Suggested change
trust_token = settings.sso_trust_token
if trust_token:
user_header = settings.sso_user_header
trust_header = settings.sso_trust_header
user_value = request.headers.get(user_header, "")
token_value = request.headers.get(trust_header, "")
if user_value and token_value == trust_token:
return True
trust_token = settings.sso_trust_token.get_secret_value()
if trust_token:
user_header = settings.sso_user_header
trust_header = settings.sso_trust_header
user_value = request.headers.get(user_header, "")
token_value = request.headers.get(trust_header, "")
import secrets
if user_value and secrets.compare_digest(token_value, trust_token):
return True

@strausmann strausmann merged commit 32cd93e into main Jun 1, 2026
18 of 19 checks passed
@strausmann strausmann deleted the fix/backend-pangolin-standard-headers branch June 1, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants