feat: Keycloak OIDC login (Issue #42)#127
Open
krajtar wants to merge 12 commits into
Open
Conversation
…client, token manager, portal client) - ewccli/backends/keycloak/pkce.py: PKCE code_verifier/code_challenge + state generation - ewccli/backends/keycloak/callback_server.py: loopback HTTP server for OIDC redirect - ewccli/backends/keycloak/oidc_client.py: auth URL builder + token exchange/refresh - ewccli/backends/keycloak/token_manager.py: silent token refresh with rotation - ewccli/backends/keycloak/portal_client.py: portal API client for app cred exchange - ewccli/configuration.py: Keycloak/OIDC config constants (env-var overridable) - ewccli/utils.py: save_cli_profile/load_cli_profile extended with keycloak_* token fields - 40 tests covering all modules
- ewccli/backends/keycloak/keycloak_backend.py: orchestrator tying PKCE, callback, OIDC client, portal client, and token manager together - ewccli/commands/login_command.py: --keycloak and --no-browser flags, keycloak login branch in init_command(), tenant_name made optional when using --keycloak - ewccli/ewccli.py: init() signature updated with new params - 51 tests total, all passing
When EWC_CLI_PORTAL_API_URL is not set (default), the Keycloak flow authenticates the user via OIDC, stores the tokens in the profile, then falls through to the existing credential path (cloud.yaml, env vars, or manual prompt). When the portal URL is set, it fetches OpenStack app creds automatically as before.
…ofile resolution for keycloak
…in flow - Remove token_manager.py and its test: get_valid_access_token() was never called; refresh tokens were persisted to disk for no functional benefit. Move _compute_expires_at inline into keycloak_backend.py. - Remove .idea/ IDE files and add .idea/ to .gitignore. - Revert whitespace-only reformatting in commons_infra.py; keep only the new connect_to_openstack_backend helper function. - Collapse triple federee/region resolution in login_command.py: run Keycloak first, then do a single interactive-prompt + validation pass. - Replace xdg-open subprocess with webbrowser.open directly (cross-platform).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Keycloak OIDC (Authorization Code + PKCE) login to the EWC CLI. Users can now authenticate via browser instead of manually entering OpenStack application credentials.
Usage
What was built
New package
ewccli/backends/keycloak/:pkce.py— PKCE code_verifier/code_challenge + state generationcallback_server.py— loopback HTTP server on configurable port (default random, fixed viaEWC_CLI_OIDC_CALLBACK_PORT)oidc_client.py— builds Keycloak auth URL, exchanges code for tokensportal_client.py— portal API client for OpenStack credential exchange (disabled by default, enable viaEWC_CLI_PORTAL_API_URL)keycloak_backend.py— orchestrator tying it all togetherModified files:
configuration.py— 6 env-var overridable Keycloak config constantsutils.py—save_cli_profile/load_cli_profileupdated (backward compatible)login_command.py—--keycloakand--no-browserflags; Keycloak runs first, then a single interactive-prompt pass for any missing federee/region/tenantcommons_infra.py— newconnect_to_openstack_backendhelper (removes 4 copies of the connect/try-except)README.md— Keycloak login documentation with config tableDesign decisions
EWC_CLI_PORTAL_API_URLis not set (default), the Keycloak flow authenticates via OIDC and falls through to the existing credential path (cloud.yaml, env vars, or manual prompt). When set, it fetches OpenStack app creds automatically.http.server,secrets,hashlib,webbrowser) +requests(already a dependency).ewc loginwithout--keycloakis unchanged. All downstream commands (infra,hub) are untouched.webbrowser.open()(stdlib, works on Linux/macOS/Windows).Keycloak client setup (server-side)
ewcclihttp://127.0.0.1:*/callback(or a fixed port)Tests
128 tests passing (zero regressions):
test_keycloak_pkce.py— 3 teststest_keycloak_callback_server.py— 5 teststest_keycloak_oidc_client.py— 6 teststest_keycloak_portal_client.py— 6 teststest_keycloak_backend.py— 6 tests