fix: Add OpenSearch basic-auth for on-prem deployments, improve onboarding flow, and support asymmetric JWT signing#1713
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
WalkthroughAdds runtime OpenSearch credential getters and run-mode selection to choose basic-auth, service-JWT, or unauthenticated clients; applies this in AppClients.initialize(), startup bootstrap, and onboarding. Separately, makes Langflow ingest token signing/verification configurable (PEM private-key support) and adds a unit test. ChangesOpenSearch Dual Authentication Path
Langflow Ingest Token Signing/Verification
Sequence Diagram(s)sequenceDiagram
participant Client
participant OnboardingEndpoint
participant AppClients
participant Lifespan
participant OpenSearch
participant ServiceToken
Client->>OnboardingEndpoint: start onboarding
OnboardingEndpoint->>ServiceToken: check OPENRAG_SERVICE_TOKEN (saas)
OnboardingEndpoint->>AppClients: request opensearch client for onboarding
Lifespan->>ServiceToken: get_openrag_service_token() (bootstrap)
AppClients->>OpenSearch: initialize writer client (basic-auth | JWT | unauthenticated)
OnboardingEndpoint->>OpenSearch: create index / set admin_username
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add support for using OpenSearch basic-auth credentials in on-prem IBM-auth deployments. Introduces get_opensearch_username(), get_opensearch_password(), and use_opensearch_basic_auth() to read credentials at runtime (allowing overrides without restart). Update onboarding and lifespan startup logic to create a basic-auth OpenSearch client and use the OpenSearch username as the admin when basic-auth is enabled; otherwise preserve JWT-based client creation and bootstrap behavior. Adjust AppClients.initialize to set opensearch auth appropriately based on IBM_AUTH_ENABLED and the new basic-auth mode.
Import get_openrag_service_token and prefer the platform service JWT when creating the OpenSearch client during onboarding, so the onboarding process pins the same admin identity as the startup security bootstrap. If a service token is present, extract admin username via admin_username_from_service_jwt and create the client with create_opensearch_client_from_jwt; raise a RuntimeError if the token lacks a username/sub claim. Maintain a backward-compatibility fallback: log a warning and fall back to using the onboarding user's jwt_token (and set admin_username to the user) when no service token is provided. Add a TODO to remove the fallback once OPENRAG_SERVICE_TOKEN is always supplied.
Prefer JWT_SIGNING_KEY over SESSION_SECRET and add PEM private key support for asymmetric JWTs. Introduces _resolve_default_signing_config to load PEM keys via cryptography, detect key types (RSA, EC with curve->ES*, EdDSA) and return signing/verification keys plus algorithm. LangflowIngestTokenService now stores separate signing and verification keys, uses them for jwt.encode/decode, and still accepts an explicit symmetric secret. Adds a unit test to ensure JWT_SIGNING_KEY is preferred and that a session secret cannot validate a JWT signed with JWT_SIGNING_KEY.
e35eafa to
ee3ef3b
Compare
|
@coderabbitai suggest a title and summary for the PR update the title and summary if possible |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/services/langflow_ingest_token_service.py`:
- Around line 71-73: mypy can't infer the third tuple element's type when
unpacking into self.algorithm; call _resolve_default_signing_config() into a
temporary variable and then assign its elements in separate statements so types
are clear — e.g. tmp = _resolve_default_signing_config(); self._signing_key,
self._verification_key = tmp[0], tmp[1]; self.algorithm = typing.cast(str,
tmp[2]) (or assign tmp[2] on its own if return type is already correct); update
references to self._signing_key, self._verification_key, and self.algorithm in
the same scope.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0332f3a5-c2ac-4e86-afe9-86df89d2fb27
📒 Files selected for processing (2)
src/services/langflow_ingest_token_service.pytests/unit/test_langflow_ingest_callback.py
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Fetch current PR description for reference
gh pr view 1713 --repo langflow-ai/openrag --json title,bodyLength of output: 253 🏁 Script executed: #!/bin/bash
gh pr edit 1713 \
--repo langflow-ai/openrag \
--title "fix: Add OpenSearch basic-auth for on-prem deployments, improve onboarding flow, and support asymmetric JWT signing" \
--body "## Summary
### OpenSearch Basic-Auth Support (On-Prem / IBM-Auth)
- Introduced \`get_opensearch_username()\`, \`get_opensearch_password()\`, and \`use_opensearch_basic_auth()\` in \`src/config/settings.py\` to read credentials from the environment at call time (allows overrides without restart).
- \`use_opensearch_basic_auth()\` enables basic-auth mode when IBM auth is active, the deployment is on-prem, and OpenSearch credentials are present.
- \`AppClients.initialize()\` now selects basic-auth when IBM auth is disabled **or** when \`use_opensearch_basic_auth()\` returns true; otherwise passes \`http_auth=None\` to rely on platform JWT.
### Onboarding & Startup Improvements
- Updated \`src/api/settings/endpoints.py\` onboarding to conditionally create an OpenSearch client and determine the admin username:
- Uses basic-auth credentials when \`use_opensearch_basic_auth()\` is enabled.
- Falls back to the platform service token (\`OPENRAG_SERVICE_TOKEN\`) for JWT-based auth when IBM auth is enabled.
- If neither is available, falls back to the onboarding user's JWT with a backward-compatibility warning.
- Updated \`src/app/lifespan.py\` startup bootstrap (\`OPENRAG_BOOTSTRAP_OS_SECURITY_ON_STARTUP\`): uses on-prem basic-auth credentials when available; otherwise validates and uses the platform service JWT, raising \`RuntimeError\` if either is missing.
### Asymmetric JWT Signing for Langflow Ingest Tokens
- \`src/services/langflow_ingest_token_service.py\` now supports configurable signing/verification key material:
- \`JWT_SIGNING_KEY\` is preferred over \`SESSION_SECRET\`; PEM private keys are auto-detected with algorithm selection (RSA → RS256, EC → ES256/ES384/ES512, EdDSA).
- Separate \`_signing_key\` and \`_verification_key\` are stored for \`jwt.encode\` / \`jwt.decode\` respectively.
- Added unit test \`test_ingest_token_prefers_jwt_signing_key_over_session_secret\` confirming that a token signed with \`JWT_SIGNING_KEY\` cannot be validated using only \`SESSION_SECRET\`.
## Testing
- Unit tests added in \`tests/unit/test_langflow_ingest_callback.py\`.
- Manual testing recommended for on-prem OpenSearch basic-auth onboarding and startup bootstrap flows."Length of output: 2952
Suggested Title: Suggested Description: ## Summary
### OpenSearch Basic-Auth Support (On-Prem / IBM-Auth)
- Introduced `get_opensearch_username()`, `get_opensearch_password()`, and `use_opensearch_basic_auth()` in `src/config/settings.py` to read credentials from the environment at call time (allows overrides without restart).
- `use_opensearch_basic_auth()` enables basic-auth mode when IBM auth is active, the deployment is on-prem, and OpenSearch credentials are present.
- `AppClients.initialize()` now selects basic-auth when IBM auth is disabled **or** when `use_opensearch_basic_auth()` returns true; otherwise passes `http_auth=None` to rely on platform JWT.
### Onboarding & Startup Improvements
- Updated `src/api/settings/endpoints.py` onboarding to conditionally create an OpenSearch client and determine the admin username:
- Uses basic-auth credentials when `use_opensearch_basic_auth()` is enabled.
- Falls back to the platform service token (`OPENRAG_SERVICE_TOKEN`) for JWT-based auth when IBM auth is enabled.
- If neither is available, falls back to the onboarding user's JWT with a backward-compatibility warning.
- Updated `src/app/lifespan.py` startup bootstrap (`OPENRAG_BOOTSTRAP_OS_SECURITY_ON_STARTUP`): uses on-prem basic-auth credentials when available; otherwise validates and uses the platform service JWT, raising `RuntimeError` if either is missing.
### Asymmetric JWT Signing for Langflow Ingest Tokens
- `src/services/langflow_ingest_token_service.py` now supports configurable signing/verification key material:
- `JWT_SIGNING_KEY` is preferred over `SESSION_SECRET`; PEM private keys are auto-detected with algorithm selection (RSA → RS256, EC → ES256/ES384/ES512, EdDSA).
- Separate `_signing_key` and `_verification_key` are stored for `jwt.encode` / `jwt.decode` respectively.
- Added unit test `test_ingest_token_prefers_jwt_signing_key_over_session_secret` confirming that a token signed with `JWT_SIGNING_KEY` cannot be validated using only `SESSION_SECRET`.
## Testing
- Unit tests added in `tests/unit/test_langflow_ingest_callback.py`.
- Manual testing recommended for on-prem OpenSearch basic-auth onboarding and startup bootstrap flows. |
Unify OpenSearch client and admin selection across onboarding, startup, and client initialization by using run-mode helpers (is_run_mode_saas/on_prem/oss) instead of the old use_opensearch_basic_auth helper. Prefer the platform service token in SaaS mode (with a backward-compat fallback to the onboarding user when the token is missing), and use OpenSearch basic-auth credentials in on-prem/OSS modes. Added informative logging for each path and adjusted AppClients.initialize to choose the global writer client based on run mode. Changes in src/api/settings/endpoints.py, src/app/lifespan.py, and src/config/settings.py.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/app/lifespan.py (1)
224-233: 💤 Low valueConsider validating OpenSearch password before bootstrap.
Same issue as in
settings.py:get_opensearch_password()may returnNonefor on_prem/oss modes. A missing password would cause an unclear failure duringsetup_opensearch_security().🛡️ Suggested validation
if is_run_mode_on_prem() or is_run_mode_oss(): admin_username = get_opensearch_username() + os_password = get_opensearch_password() + if not os_password: + raise RuntimeError( + "OPENSEARCH_PASSWORD must be set when " + "OPENRAG_BOOTSTRAP_OS_SECURITY_ON_STARTUP is enabled for on_prem/oss" + ) opensearch_client = clients.create_basic_opensearch_client( - admin_username, get_opensearch_password() + admin_username, os_password )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/lifespan.py` around lines 224 - 233, The code calls get_opensearch_password() without validating it in the on-prem/oss branch, which can return None and cause unclear failures when create_basic_opensearch_client or setup_opensearch_security run; update the block that uses is_run_mode_on_prem()/is_run_mode_oss() to retrieve the password into a local variable, check that password is not None/empty (and log+raise a clear error or exit if it is), then pass the validated password to clients.create_basic_opensearch_client and subsequent setup_opensearch_security so failures are explicit; reference symbols: is_run_mode_on_prem, is_run_mode_oss, get_opensearch_password, create_basic_opensearch_client, setup_opensearch_security, admin_username.src/config/settings.py (1)
618-628: 💤 Low valueConsider validating OpenSearch password before using in basic auth.
In on_prem/oss modes,
get_opensearch_password()can returnNone. Passing(username, None)ashttp_authmay cause unclear auth failures later. The existing code indls_principal_service.py(lines 251-252) checksif not OPENSEARCH_PASSWORD: return Nonebefore creating the basic client.A defensive check here would provide a clearer fail-fast behavior:
🛡️ Suggested validation
if is_run_mode_on_prem() or is_run_mode_oss(): + os_password = get_opensearch_password() + if not os_password: + raise RuntimeError( + "OPENSEARCH_PASSWORD must be set for on_prem/oss run modes" + ) - os_auth = (get_opensearch_username(), get_opensearch_password()) + os_auth = (get_opensearch_username(), os_password) logger.info(🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/config/settings.py` around lines 618 - 628, When initializing os_auth in the is_run_mode_on_prem()/is_run_mode_oss() branch, validate get_opensearch_password() before using it in the tuple; if the password is missing (None or empty) log a clear error and fail-fast (return None or raise a RuntimeError) instead of setting os_auth=(username, None) so we don't create a basic-auth client with a missing password—mirror the defensive behavior used in dls_principal_service where it returns None when OPENSEARCH_PASSWORD is not set. Use the existing symbols is_run_mode_on_prem, is_run_mode_oss, get_opensearch_username, get_opensearch_password and os_auth to locate and change the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/lifespan.py`:
- Around line 214-218: The import list in lifespan.py includes an unused symbol
is_run_mode_saas which triggers ruff F401; remove is_run_mode_saas from the from
utils.run_mode_utils import (...) statement so only is_run_mode_on_prem and
is_run_mode_oss remain, and update the import formatting/commas accordingly to
keep the file syntactically correct (refer to the import line that currently
lists is_run_mode_on_prem, is_run_mode_oss, is_run_mode_saas).
---
Nitpick comments:
In `@src/app/lifespan.py`:
- Around line 224-233: The code calls get_opensearch_password() without
validating it in the on-prem/oss branch, which can return None and cause unclear
failures when create_basic_opensearch_client or setup_opensearch_security run;
update the block that uses is_run_mode_on_prem()/is_run_mode_oss() to retrieve
the password into a local variable, check that password is not None/empty (and
log+raise a clear error or exit if it is), then pass the validated password to
clients.create_basic_opensearch_client and subsequent setup_opensearch_security
so failures are explicit; reference symbols: is_run_mode_on_prem,
is_run_mode_oss, get_opensearch_password, create_basic_opensearch_client,
setup_opensearch_security, admin_username.
In `@src/config/settings.py`:
- Around line 618-628: When initializing os_auth in the
is_run_mode_on_prem()/is_run_mode_oss() branch, validate
get_opensearch_password() before using it in the tuple; if the password is
missing (None or empty) log a clear error and fail-fast (return None or raise a
RuntimeError) instead of setting os_auth=(username, None) so we don't create a
basic-auth client with a missing password—mirror the defensive behavior used in
dls_principal_service where it returns None when OPENSEARCH_PASSWORD is not set.
Use the existing symbols is_run_mode_on_prem, is_run_mode_oss,
get_opensearch_username, get_opensearch_password and os_auth to locate and
change the logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9b0b2cfb-969d-4252-b1f0-7db7f04feda2
📒 Files selected for processing (3)
src/api/settings/endpoints.pysrc/app/lifespan.pysrc/config/settings.py
|
@coderabbitai suggest a title and summary for the PR |
|
Tip For best results, initiate chat on the files or code changes.
Suggested Title: Suggested Description: ## Summary
### OpenSearch Basic-Auth Support (On-Prem / OSS)
- Added `get_opensearch_username()`, `get_opensearch_password()` in `src/config/settings.py` to read OpenSearch credentials from the environment at call time (supports overrides without restart).
- `AppClients.initialize()` now selects the OpenSearch writer client by run mode: basic-auth in on-prem/OSS, JWT-based auth in SaaS (when a platform service token is present), or unauthenticated otherwise.
### Onboarding & Startup Improvements
- `src/api/settings/endpoints.py` onboarding now selects the OpenSearch client and `admin_username` by run mode:
- **SaaS**: uses `OPENRAG_SERVICE_TOKEN` JWT; falls back to the onboarding user's JWT with a backward-compatibility warning if the service token is absent.
- **On-prem / OSS**: uses OpenSearch basic-auth credentials.
- `src/app/lifespan.py` startup bootstrap (`OPENRAG_BOOTSTRAP_OS_SECURITY_ON_STARTUP`): on-prem/OSS uses OpenSearch basic-auth; SaaS validates and uses the platform service JWT, raising `RuntimeError` if either is missing.
### Asymmetric JWT Signing for Langflow Ingest Tokens
- `src/services/langflow_ingest_token_service.py` now supports configurable signing/verification key material:
- `JWT_SIGNING_KEY` is preferred over `SESSION_SECRET`; PEM private keys are auto-detected with algorithm selection (RSA → RS256, EC → ES256/ES384/ES512, EdDSA → EdDSA).
- Separate `_signing_key` and `_verification_key` are stored per instance for `jwt.encode` / `jwt.decode`.
## Testing
- Unit test added: `test_ingest_token_prefers_jwt_signing_key_over_session_secret` in `tests/unit/test_langflow_ingest_callback.py`.
- Manual testing recommended for on-prem OpenSearch basic-auth onboarding and startup bootstrap flows.You can apply these via the GitHub UI by clicking the ✏️ pencil icon next to the PR title and editing the description box directly. Unfortunately I'm unable to update the PR programmatically due to workflow restrictions in this environment. |
…rding flow, and support asymmetric JWT signing (#1713) * Support OpenSearch basic-auth for on-prem Add support for using OpenSearch basic-auth credentials in on-prem IBM-auth deployments. Introduces get_opensearch_username(), get_opensearch_password(), and use_opensearch_basic_auth() to read credentials at runtime (allowing overrides without restart). Update onboarding and lifespan startup logic to create a basic-auth OpenSearch client and use the OpenSearch username as the admin when basic-auth is enabled; otherwise preserve JWT-based client creation and bootstrap behavior. Adjust AppClients.initialize to set opensearch auth appropriately based on IBM_AUTH_ENABLED and the new basic-auth mode. * Prefer service token for OpenSearch onboarding Import get_openrag_service_token and prefer the platform service JWT when creating the OpenSearch client during onboarding, so the onboarding process pins the same admin identity as the startup security bootstrap. If a service token is present, extract admin username via admin_username_from_service_jwt and create the client with create_opensearch_client_from_jwt; raise a RuntimeError if the token lacks a username/sub claim. Maintain a backward-compatibility fallback: log a warning and fall back to using the onboarding user's jwt_token (and set admin_username to the user) when no service token is provided. Add a TODO to remove the fallback once OPENRAG_SERVICE_TOKEN is always supplied. * Support JWT_SIGNING_KEY and key type detection Prefer JWT_SIGNING_KEY over SESSION_SECRET and add PEM private key support for asymmetric JWTs. Introduces _resolve_default_signing_config to load PEM keys via cryptography, detect key types (RSA, EC with curve->ES*, EdDSA) and return signing/verification keys plus algorithm. LangflowIngestTokenService now stores separate signing and verification keys, uses them for jwt.encode/decode, and still accepts an explicit symmetric secret. Adds a unit test to ensure JWT_SIGNING_KEY is preferred and that a session secret cannot validate a JWT signed with JWT_SIGNING_KEY. * style: ruff autofix (auto) * Update langflow_ingest_token_service.py * Use run-mode utils for OpenSearch auth selection Unify OpenSearch client and admin selection across onboarding, startup, and client initialization by using run-mode helpers (is_run_mode_saas/on_prem/oss) instead of the old use_opensearch_basic_auth helper. Prefer the platform service token in SaaS mode (with a backward-compat fallback to the onboarding user when the token is missing), and use OpenSearch basic-auth credentials in on-prem/OSS modes. Added informative logging for each path and adjusted AppClients.initialize to choose the global writer client based on run mode. Changes in src/api/settings/endpoints.py, src/app/lifespan.py, and src/config/settings.py. * style: ruff autofix (auto) * Update lifespan.py --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
…rding flow, and support asymmetric JWT signing (#1713) * Support OpenSearch basic-auth for on-prem Add support for using OpenSearch basic-auth credentials in on-prem IBM-auth deployments. Introduces get_opensearch_username(), get_opensearch_password(), and use_opensearch_basic_auth() to read credentials at runtime (allowing overrides without restart). Update onboarding and lifespan startup logic to create a basic-auth OpenSearch client and use the OpenSearch username as the admin when basic-auth is enabled; otherwise preserve JWT-based client creation and bootstrap behavior. Adjust AppClients.initialize to set opensearch auth appropriately based on IBM_AUTH_ENABLED and the new basic-auth mode. * Prefer service token for OpenSearch onboarding Import get_openrag_service_token and prefer the platform service JWT when creating the OpenSearch client during onboarding, so the onboarding process pins the same admin identity as the startup security bootstrap. If a service token is present, extract admin username via admin_username_from_service_jwt and create the client with create_opensearch_client_from_jwt; raise a RuntimeError if the token lacks a username/sub claim. Maintain a backward-compatibility fallback: log a warning and fall back to using the onboarding user's jwt_token (and set admin_username to the user) when no service token is provided. Add a TODO to remove the fallback once OPENRAG_SERVICE_TOKEN is always supplied. * Support JWT_SIGNING_KEY and key type detection Prefer JWT_SIGNING_KEY over SESSION_SECRET and add PEM private key support for asymmetric JWTs. Introduces _resolve_default_signing_config to load PEM keys via cryptography, detect key types (RSA, EC with curve->ES*, EdDSA) and return signing/verification keys plus algorithm. LangflowIngestTokenService now stores separate signing and verification keys, uses them for jwt.encode/decode, and still accepts an explicit symmetric secret. Adds a unit test to ensure JWT_SIGNING_KEY is preferred and that a session secret cannot validate a JWT signed with JWT_SIGNING_KEY. * style: ruff autofix (auto) * Update langflow_ingest_token_service.py * Use run-mode utils for OpenSearch auth selection Unify OpenSearch client and admin selection across onboarding, startup, and client initialization by using run-mode helpers (is_run_mode_saas/on_prem/oss) instead of the old use_opensearch_basic_auth helper. Prefer the platform service token in SaaS mode (with a backward-compat fallback to the onboarding user when the token is missing), and use OpenSearch basic-auth credentials in on-prem/OSS modes. Added informative logging for each path and adjusted AppClients.initialize to choose the global writer client based on run mode. Changes in src/api/settings/endpoints.py, src/app/lifespan.py, and src/config/settings.py. * style: ruff autofix (auto) * Update lifespan.py --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Summary by CodeRabbit