feat(auth): add reusable OAuth2 base helper library#2858
feat(auth): add reusable OAuth2 base helper library#2858LOVECAO1011 wants to merge 2144 commits intoIBM:mainfrom
Conversation
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
- Auto-wrap GlobalContext in PluginContext in invoke_hook_for_plugin() to prevent AttributeError exceptions on every invocation - Change f-string to lazy logger formatting in debug statement This eliminates unnecessary logger.error() calls that were triggered by a type mismatch when GlobalContext was passed directly, resulting in 2-5x performance improvement for plugin execution. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
) - Add mcpContextForge.service.annotations for LoadBalancer configuration (e.g., AWS NLB, GCP load balancer annotations) - Add "none" as a valid CACHE_TYPE option in values.schema.json to allow disabling caching entirely These changes were extracted from PR IBM#1798, which was superseded by existing implementations for external PostgreSQL and secret injection. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Shi Jin <jinzishuai@gmail.com>
* tests: add cProfile performance tests for plugins Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * tests: add comparison script for plugin framework profiles Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix: address linting issues in plugin profiling tests - Add noqa E402 comments for intentional late imports after sys.path - Fix type annotation: use Any instead of any (lowercase was incorrect) - Remove unnecessary f-string prefixes from static strings Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…d pagination, and search on name or email (IBM#2067) * unified team member view Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix selection Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix member search Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Remove extra logging Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Update search to non dom users Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * lint-web fixes Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * black fix Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * team member cleanup Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Segregate members and non members and fix pagination Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix search Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Linting fixes Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix tests Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Make list team members return paginated result by default Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * linting fixes Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix cursor use in auth_service list users Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Remove unused param Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Add index on emai_user name Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix non paginated response for list team members API Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Update migration script Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix failing doctest Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Use next_cursor with alias Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Remove print statements in alembic script Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * Fix close manage members Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * refactor: remove dead code _cursor_paginate_users method Remove unused _cursor_paginate_users() method from EmailAuthService that was made obsolete when list_users() was refactored to use unified_paginate() for both cursor and page-based pagination. Also remove: - Tests for the dead code method - Unused imports (base64, orjson, and_, Select) Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: address pagination safety and role preservation issues Critical fixes: - Add loadedMembers tracking to prevent accidental removal of members from unloaded pages during infinite scroll pagination - Only remove members who were visible in the form AND unchecked High priority fixes: - Preserve member roles when rendering search results (prevent owner demotion) - Add loadedMembers hidden input in JS search to match template behavior - Use fetchWithAuth instead of bare fetch for bearer token support Low priority fixes: - Fix owner_count to use count_team_owners() for accurate Last Owner badge across all pages, not just current page Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: implement proper cursor pagination for EmailUser EmailUser uses email as primary key (not id), so the generic unified_paginate cursor using (created_at, id) doesn't work. Changes: - Add custom cursor pagination in list_users() using (created_at, email) as cursor fields for correct keyset pagination - Add warning log in unified_paginate when model lacks 'id' field to help diagnose cursor pagination issues with other models - Keep page-based pagination using unified_paginate (works correctly) Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: add debounce and HTMX reinitialization for search - Add debouncedServerSideUserSearch() wrapper with 300ms delay to prevent excessive API calls on each keystroke - Call htmx.process() after innerHTML replacement when clearing search to reinitialize HTMX intersect triggers for infinite scroll - Export debounced function for use in templates Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: move imports to top level and add missing template Move base64, orjson, and_ imports to module top level to satisfy pylint C0415 (import-outside-toplevel). Add team_members_selector.html template for the user selector with team context, used when render=selector in admin users partial endpoint. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: team member cursor pagination, checkbox preservation, and tests - Add created_at property alias to EmailTeamMember for cursor pagination compatibility with unified_paginate - Fix ORDER BY in get_team_members to use (joined_at DESC, id DESC) for cursor-based pagination and (full_name, email) for page-based - Preserve checkbox states during server-side user search to prevent in-progress add/remove selections from being lost - Fix admin.html users list per_page from 10 to 20 for consistency - Add cursor pagination tests for EmailUser list_users method testing the (created_at, email) keyset implementation Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: cursor pagination, access control, and UI consistency issues - Implement custom cursor pagination for team members using (joined_at, id) keyset instead of relying on unified_paginate's (created_at, id) which doesn't work for EmailTeamMember - Implement custom cursor pagination for list_users_not_in_team using (created_at, email) keyset for EmailUser - Fix backward compatibility check to only trigger when all pagination params (cursor, page, limit) are None - Update legacy add-members route from non-existent /admin/teams/{id}/users/partial to /admin/users/partial?render=selector&team_id={id} - Allow teams.manage_members permission for /users/search endpoint so team owners can search users to add to their teams - Add email fallback for name display in team_users_selector.html and team_members_selector.html templates - Remove unused created_at property alias from EmailTeamMember - Add unit tests for team member cursor-based pagination Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: make non-members list use same per_page as members section Both members and non-members sections in the team management UI should honor the same per_page setting from the view context for consistency. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: per_page consistency, legacy search URL, and limit cap - Add data-per-page attributes to team member containers and read them in JS search reset to maintain consistent page sizes - Fix legacy add-members search URL from non-existent /admin/teams/{id}/users/search to /admin/users/search - Revert users list per_page from 20 back to 50 to match main branch - Add le=settings.pagination_max_page_size constraint to teams router limit parameter and cap page_size in service for defense-in-depth Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Linting Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: prettier formatting in admin.js Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* feature/password-enforcement-1843 Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * pylint fix Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * bandit fix Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * added a small visible indicator on the page Password policy enabled password_policy_enabled so you can immediately see the effective value the server used when rendering the page Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * flake8 fix Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * fix pytest Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * fix flake8 Signed-off-by: NAYANAR <nayana.r7813@gmail.com> * feat: add migration for password_changed_at column Adds the missing Alembic migration to create the password_changed_at column in the email_users table, required for password age tracking and expiry enforcement. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: address password enforcement logic issues Fixes 6 issues found during code review: 1. Default password enforcement bypass - moved needs_password_change inside the require_password_change_for_default_password check 2. password_change_required flag bypass - made the flag authoritative, no longer ignored based on password age (age is only for expiry) 3. Admin UI ignores policy toggle - added password_policy_enabled check to validate_password_strength function 4. Admin update missing timestamp - added password_changed_at update in admin user update paths (router and service layer) 5. Migration no backfill - added backfill logic to set password_changed_at = created_at for existing users 6. .env.example missing docs - added all new password enforcement configuration options Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: NAYANAR <nayana.r7813@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* 2072 - MCP Registry "Add Server" button flow - Backend now detects HTMX requests via HX-Request header and returns HTML fragments instead of JSON - Replaced broken htmx-indicator pattern with hx-on::before-request and hx-on::after-request event handlers - Implemented three button states: success (green), OAuth warning (yellow), error with retry (red) - Fixed settings.root_path → settings.app_root_path bug - Added hx-disabled-elt to prevent double-clicks - Added comprehensive test coverage for OAuth registration and HTMX endpoints Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * Flake8 fix Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * fix: add proper HTML escaping and fix HTMX tests - Add html.escape() for server_id, message, and error values in HTML fragments to prevent XSS vulnerabilities - Fix HTMX tests to use __wrapped__ to bypass RBAC decorator - Apply Black formatting and isort to test file Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: address HTMX registration flow issues - High: Use HX-Trigger-After-Swap header for success refresh instead of inline hx-on::after-request. Error buttons no longer get wiped by auto-refresh since they don't include the trigger header. - Medium: Add oauth_required field to CatalogServerRegisterResponse schema and use it instead of brittle string matching on message content. - Low: Add hx-on::response-error handlers to restore button state on transport/network failures. Also adds event listener in template for catalogRegistrationSuccess trigger. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: address remaining HTMX registration issues - Medium: OAuth registrations no longer trigger delayed refresh, so the yellow "OAuth Config Required" warning persists instead of being replaced by "Add Server" on refresh - Low: Event listener uses window guard to prevent re-attachment when partial is refreshed multiple times - Low: HTTP errors (401/403/500) now show orange "Request Failed - Click to Retry" button with visual feedback instead of silently resetting Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Lint fix Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * style: remove unnecessary else after return (pylint R1705) Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: OAuth servers persist as registered after refresh - Add requires_oauth_config field to CatalogServer schema - Query all gateways (enabled and disabled) to track registration status - Disabled gateways are marked as requires_oauth_config=True - Template shows yellow "OAuth Config Required" state for disabled servers - Add debounce to prevent multiple refreshes when registering rapidly Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: only mark OAuth servers as requires_oauth_config - Query auth_type from Gateway to distinguish OAuth from other disabled servers (only disabled + auth_type='oauth' = requires_oauth_config) - Re-enable refresh for OAuth success since template now handles state - Revert unrelated formatting change in migration file Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: distinguish unconfigured OAuth servers from manually disabled ones - Set auth_type="oauth" when registering OAuth servers (was None) - Check oauth_config IS NULL to identify servers needing OAuth setup - Manually disabled OAuth servers (with oauth_config populated) now correctly show "Already Registered" instead of "OAuth Config Required" Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * test: add unit tests for requires_oauth_config classification Test cases for the get_catalog_servers method: - Disabled OAuth server with oauth_config=None → requires_oauth_config=True - Disabled OAuth server with oauth_config populated → requires_oauth_config=False - Enabled OAuth server → requires_oauth_config=False Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: use named logger for duplicate header warning Change logging.warning() to logger.warning() for duplicate header key warnings. This ensures proper log capture in pytest's caplog fixture, fixing flaky test in CI. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Gabriel Costa <gabrielcg@proton.me> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* 2077 - Reorder action buttons Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * fix: Update search indices after moving Actions column to first position Update JavaScript table filter functions to reflect the new column order where Actions is at index 0 instead of being the last column. This fixes search/filter functionality that was broken by the column reorder. Affected functions: - filterGatewaysTable: skip Actions(0) and S.No.(1) - filterServerTable: skip Actions(0), Icon(1), S.No.(2) - filterToolsTable: skip Actions(0), S.No.(1) - filterResourcesTable: skip Actions(0) - filterPromptsTable: skip Actions(0), S.No.(1) - filterA2AAgentsTable: skip Actions(0), ID(1) - simpleGatewaySearch: skip Actions(0), S.No.(1) Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Gabriel Costa <gabrielcg@proton.me> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* 2080 - Adjust Show inactive toggle Fix the Show inactive toggle behaviour on the MCP Server Gateway and Virtual Servers - Soon to be added to other tabs Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * Web lint fix Signed-off-by: Gabriel Costa <gabrielcg@proton.me> * fix: restore HTMX-based toggle for servers/gateways with proper state preservation - Revert from client-side to server-side filtering via HTMX to fix pagination - Fix fallback ID lookup to include servers and gateways tables - Preserve team_id and per_page URL params when toggling inactive filter - Preserve and reapply search term after HTMX content swap - Remove unused applyServerFilter/applyGatewayFilter functions Addresses issues with sparse pages and search state loss when toggling the "Show inactive" checkbox on servers and gateways tabs. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Gabriel Costa <gabrielcg@proton.me> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…M#2089) * feat(teams): add server-side pagination and search for teams listing Implement unified pagination support for teams management: Service Layer: - Update TeamManagementService.list_teams to use unified_paginate - Support cursor, page, per_page, search_query, and visibility_filter - Add get_all_team_ids method for admin lookups - Add composite index on (name, id) for optimized search/pagination API Router: - Refactor list_teams endpoint with proper pagination flags - Add CursorPaginatedTeamsResponse schema Frontend (HTMX): - Add teams_partial.html template for HTMX partial updates - Add teams_selector_items.html for infinite-scroll dropdowns - Implement server-side team search in admin.js Testing: - Update router tests to explicitly pass include_pagination=False - Update service tests to match new unified pagination signature Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(teams): address code review findings for pagination Fixes identified in code review: High Priority: - Fix cursor pagination ordering: use created_at DESC for cursor mode, name ASC for page mode to match unified_paginate expectations - Fix team action refresh: use /admin/teams/partial instead of legacy URL - Remove inline filterTeams/filterByRelationship that override server-side versions Medium Priority: - Add get_teams_count() for accurate total in API responses - URL encode q and relationship params in base_url construction - URL encode q param in teams_selector_items.html template - Fix admin controls: admins see manage/edit/delete for all teams (not "Request to Join") - Add 500 limit to discover_public_teams for memory safety - Fix non-admin pagination to respect page parameter - Enable description search for consistency with in-memory filter Low Priority: - Fix error fallback links with consistent per_page values - Fix loading indicator timing for HTMX (let HTMX handle indicator) - Revert accidental per_page=20→10 changes in non-teams endpoints - Add test for include_pagination=True cursor response path Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add "Authorize" and "Fetch Tools" buttons for OAuth-enabled gateways, matching the main admin interface layout. Use |tojson filter for gateway.name in onclick handler to prevent potential XSS from gateway names containing quotes or backslashes. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…acking (IBM#2086) Fix two critical bugs in core session and agent services: 1. Session Registry (session_registry.py) - Added null check for message content before passing to orjson.loads() - Prevents crash when _session_message contains None value - Logs warning instead of raising exception on edge case 2. Tool Execution (mcp_client_chat_service.py) - Fixed race condition where on_tool_end event arrives before on_tool_start - Implemented buffering for out-of-order tool events with TTL (30s) and cap (100) - Out-of-order events are buffered and reconciled when start event arrives - Tracks dropped tool ends (TTL-expired or buffer-full) with cap (200) - Later on_tool_start or on_tool_error clears from dropped set (prevents false orphans) - Emits aggregated tool_error at stream end for all orphan/dropped ends (de-duplicated) - on_tool_error clears buffered ends to avoid emitting both error and end - Uses UUID for aggregated error ID to avoid run_id collisions - Refactored output extraction into helper function Tests added: - test_respond_memory_backend_with_none_message_content: Tests None message handling - test_chat_events_reconciles_out_of_order_tool_events: Tests event reconciliation - test_chat_events_emits_error_for_orphan_tool_ends: Tests orphan error emission - test_chat_events_tool_error_clears_buffered_end: Tests error/buffer consistency - test_chat_events_buffer_full_drops_included_in_error: Tests buffer overflow tracking - test_chat_events_ttl_expiry_included_in_error: Tests TTL expiry tracking - test_chat_events_dropped_then_start_clears_from_dropped: Tests false orphan prevention - test_chat_events_dropped_then_error_clears_from_dropped: Tests error clears dropped Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…on (IBM#2097) Add a new JWT_ISSUER_VERIFICATION configuration setting (default: true) to provide granular control over JWT issuer claim validation, independent of audience verification. Previously, verify_jwt_token would unconditionally pass the issuer parameter to PyJWT decode, enforcing presence and validity of the 'iss' claim even when users intended to disable strict checks. This prevented accepting tokens with varying or missing issuers, which is critical for: - Dynamic Client Registration (DCR) - Multi-tenant setups - Custom authentication flows Changes: - Add jwt_issuer_verification setting (default: true) to mcpgateway/config.py - Conditionally include issuer in decode_kwargs when verification is enabled - Update all documentation (README, values.yaml, docs/) with the new setting - Add .env.example entry for consistency - Add unit test for issuer verification skip scenario - Update all doctests with jwt_issuer_verification mock Closes IBM#1792 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* feat(auth): decouple JWT issuer verification from audience verification Add a new JWT_ISSUER_VERIFICATION configuration setting (default: true) to provide granular control over JWT issuer claim validation, independent of audience verification. Previously, verify_jwt_token would unconditionally pass the issuer parameter to PyJWT decode, enforcing presence and validity of the 'iss' claim even when users intended to disable strict checks. This prevented accepting tokens with varying or missing issuers, which is critical for: - Dynamic Client Registration (DCR) - Multi-tenant setups - Custom authentication flows Changes: - Add jwt_issuer_verification setting (default: true) to mcpgateway/config.py - Conditionally include issuer in decode_kwargs when verification is enabled - Update all documentation (README, values.yaml, docs/) with the new setting - Add .env.example entry for consistency - Add unit test for issuer verification skip scenario - Update all doctests with jwt_issuer_verification mock Closes IBM#1792 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Linting Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* tests: minor fixes to plugins performance profiler Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: fix yamlint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: fix trailing whitespace in performance test Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: restore disabled status for plugins in performance config Restore the original disabled mode for plugins that were unintentionally enabled during YAML reformatting: - RateLimiterPlugin - PrivacyNoticeInjector - WebhookNotification - ContentModeration (also restore ibm_granite provider config) Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: restore original context handling in performance profiler Revert to passing GlobalContext directly instead of pre-creating a shared PluginContext. The original behavior provides realistic per-request profiling because: - Each iteration gets a fresh PluginContext via auto-wrapping - Stateful plugins (caches, circuit breakers) don't accumulate state - Profile times reflect real-world per-request performance Also removes the exception swallowing so failures properly surface as ERROR in the summary table rather than computing averages from partial iteration data. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* cache auth/crypto key material and derived objects Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * lint fixes Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * fixes for test Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * fix pylint code duplication Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * fix linting uses Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * Lint Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Shoumi <shoumimukherjee@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* Initial commit for qr-code-server, created using scaffold script
* Added config.yaml based on requirements.
* feat: Implement configuration management for QR code generation - load and validade
* fix: Update dependencies in pyproject.toml for QR code server
added qrcode
* Refactored config.py
-Removed extra comments
-Added info when loaded
-Removed wrong validation
* Added dev requirements to test and lint
* Add qr generation logic
- implement create_qr
- implemented simple happy path unit test
* "Fix lint issues in config.py"
* Improved qr_generator
- Added base64 output
- Added error handling
- Added png, svg and ascii formats
- Added tests to cover generator changes
* Create a resolve_output_path function
- It will check if user input has filename on it
- check if filename.ext has the correct ext
- It creates the output folder if it does not exist
* Fixed resolve output path not creating correct path
* Added ImageAscii class to convert pillow image to ascii
- save method added to allow use as qrcode image
* Refactored ImageAscii to be compatible to qrcode image factory
* Refactored file.utils to not raise error and added filename + extension as output
* Refactored generator
- Uses qrcode image factory to generate images
- Removed ascii logic from generator
- improved output path handling
- remove code used to run locally
* Added tests for generator, covering 100%
- test for multiple formats PNG, SVG, ASCII
- test for error handling
- test create qr base64
* rename main folder from qr-code-serve to qr_code_server,
Added a server test to list tools
* Fixed generator test creating output path
* Fixed resolve output path to address filename without extension, it manage the following cases
- case 1: output_path is a folder
- case 2: output_path has file extension
- case 3: output_path has filename without extension
- case 4: output_path does not have filename
* Removed qr code file generated by a test
* Added validator and decoder file with request validation model
* Improved image utils to handle batch qr code generation
- Decoupled qr image generation from the create_qr_code
- Improved Ascii save to handle BytesIO for batch zip generation
* Improved QRcode batch generator and added tests
- Handle errors
- Added tests to get 100% coverage
- Test manually to check created files
- changed ascii filename to have extension ascii
* Refactored Image utils
- Created a image generator to handle batch
- handled errors
- changed ascii format to have ascii extension
* Added create_batch_qr_codes to server and test_server
* Added dependencies for QR code Decoder
* Fixed bugs in generator and improved test coverage
- Fixed ascii not encoding in base64
- Added validation to BatchQRgeneration
- Fixed lint
* Added a load image for decoder
- loads from file image
- loads from base64
- load multiple types
* Added max data lenght validation for Qr generator
* Added max image size error for decoder
* Added a function to decode string bytes size to bytes
* Added decoder validation for image format
* Removed hard coded supported formats
Added in progress decoder
* Added request validations for validator
- target_version
- error correction
* Handled max concurrent requests using semaphore
- use max request from config
- queue max size 3*max request config
* Fixed folder and file handling for generator
- Added tests for edge cases
* Improved convert to bytes function
- Added tests for edge cases
- raise value error when cannot decode
* Fixed double quotes inside double quotes in rstrip
* Refactored test_generator and linted
- replaced TemporaryDirectory() with tmp_path fixture
* Added default values from config in generator
* Added QR validator Request model
* Refactored and linted image utils
* Refactored and improved generator
- Added config default to Generation Request model
- fixed data validation
- improved logs
* Refactored and cleaned generator errors
- cleaned tmp_path
- added base64 fail to generate test
- cleaned unused imports
* Addeed functions to estimate bits and size
- check smalles fitting version
- added table size per version and error correction
- function to estimate encoded bits for string and version
* Added validator tests and bits table size reference
* Added validate qr code to server
- Fixed lint
* Improved load_image
- Improved image size validation before b64 decoding
- Added image size validation after decoding
* Added decoder qr code
- Accept path to image or base64 image
- preprocess image using cv2 gaussian blur and treshold
- decode images with multiple codes
* Fixed bug where zipped png files were corrupted
- save image as Bytes buffer before adding to zip
- Added test to check if file is image
* change project name script to qr-code-server
* Added qr code decoder in server
Also added health check endpoint
* Added semaphore server tests
* Fixed batch generator missing format input
- Added generator test to server test
- Added Batch generator to server test
* Renamed internal function decode_qr_code to qr_decode
* Added test decode qr tool in server tests
* Added tests to call tools from server
* Fix small images not decoding
- Created a preprocessing function
- Improved logs
- Added a resize small images when preprocessing
- moved preprocessing to load image function in image utils
* Improved decoder log when cannot decode image or find file
* Added different types of qr images for decoding tests
* Improved decoder tests
- Added multiple qr code decode test
- Added multiple type tests
* Added test for multiple tools running concurrently
* Added more tests in server.py to reach > 90% coverage
* Improved test coverage for config.
- Fixed config not loading default values
* Removed Cache generated qr code config
* Linted and removed health endpoit as it is not on requirements
* Fixed wrong command in make format
* Linted and formatted the code
* Fixed image utils types and lint
* Fixed types and lint for decoder
* Added return type to qr_decode function
* Fixed types in validador
* Improved types in decoder
* Improved types and return tyoes in generator
* changed how to handle error correction in Qrgeneration config
* change BytesIO to Any in Ascii save image
* Normalized tools Output using Model
* Created Comprehensive Readme
* Normalized output for server errors using models
* Improved logs for server
- Added Log when successfull
- added log for success false
* Removed files from BatchQRresult
* Capped border at 100 to avoid long request and computer freezing
* Improved Readme with notes on Border and Colors
* Fixed lint and long lines
* Formatted and linted files for PR
* fix(qr-code-server): correct file extension handling in resolve_output_path
Fix edge cases in file path resolution:
- Handle filenames with non-matching extensions (e.g., file.jpg -> file.jpg.png)
- Handle filenames ending with dot (e.g., weird. -> weird.png)
- Only skip extension appending when existing extension matches target format
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(qr-code-server): address security and correctness issues
Security fixes:
- Fix Containerfile build order (copy src/ before pip install)
- Add path traversal validation for naming_pattern to prevent zip-slip
Correctness fixes:
- Populate file_path, zip_file_path, output_directory in responses
- Use config values for batch defaults (size, output_directory, zip_output)
- Use config.decoding.preprocessing_enabled as default
- Fix wrong request names in logging (decode/validate used batch name)
- Convert NumPy arrays to lists for JSON serialization
- Fix README to show correct zip filename (qr.zip not qr_batch.zip)
- Fix test using wrong field name (version -> target_version)
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(qr-code-server): improve validation and container compatibility
Validation fixes:
- Preserve whitespace in QR data (don't strip during validation)
- Clamp border to valid range [0, 100] (was only capping max)
- Add image_format validation against config.supported_image_formats
- Consistent data length validation in batch (use actual length)
Container fixes:
- Switch to opencv-python-headless (works on slim containers)
Test additions:
- Add tests for naming_pattern path traversal rejection
- Add tests for border validation clamping
Code cleanup:
- Remove unnecessary UTF-8 encoding declarations (ruff UP009)
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(qr-code-server): ensure batch uses config for border and error_correction
Fixes:
- Add border and error_correction to BatchQRGenerationRequest model
- Pass border/error_correction to index_image_generator
- Add format validation to single QR generation (consistency with batch)
- Update server.py to expose border/error_correction for batch
Documentation:
- Update README examples to match actual output format
- Document that image_format is validation-only (auto-detection used)
- Add border/error_correction parameters to batch docs
Test fix:
- Use == instead of is for string comparison in format test
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
---------
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…BM#2102) * tests: add basic smoke tests for all plugins to check they initialize and run on all defined hooks Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix: yamlint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix(tests): correct misleading class names in plugin smoke tests Rename test classes from 'Disabled' to reflect that they test enabled plugins in permissive mode, not disabled plugins: - TestDisabledPluginsInstantiation -> TestPluginInstantiation - TestDisabledPluginsHookInvocation -> TestPluginHookInvocation - TestAllDisabledPluginsTogether -> TestAllPluginsTogether Update associated docstrings for consistency. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
* fix: type mismatches and missing dependency checks in plugins Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: lint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
…ot findings (IBM#2093) Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* feat: add MCP authentication controls and team membership validation Implement configurable authentication and consistent authorization for MCP endpoints: - Add MCP_REQUIRE_AUTH config option to require Bearer tokens on /mcp endpoints (default: false allows public-only access for unauthenticated requests) - Add team membership validation to MCP auth matching REST behavior with 60s cache TTL - users removed from teams lose access immediately - Extend access checks to template resources ensuring visibility and team scoping applies consistently across all resource types Configuration: - MCP_REQUIRE_AUTH=false (default): unauthenticated requests get public-only access - MCP_REQUIRE_AUTH=true: all /mcp requests require valid Bearer token Updated: config.py, streamablehttp_transport.py, resource_service.py, README.md, Helm charts, ADR-004, .env.example Tests: 34 authorization tests, 60 MCP transport tests Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * feat: add visibility-based access control for A2A agents and resource templates Implement consistent authorization controls across A2A agents and resource templates, matching the existing tools/resources/prompts access patterns. Changes: - Add _apply_visibility_filter() and _check_agent_access() to A2AAgentService for listing, get, and invoke operations - Add _apply_visibility_filter() to ResourceService for template listing - Fix visibility parameter precedence bug where schema defaults overrode endpoint parameters - Add Authorization header to nginx cache key to prevent cross-user data leakage - Add MCP transport tests for team membership validation - Fix flaky circuit breaker test timing Access control rules: - token_teams=None: Admin unrestricted access - token_teams=[]: Public-only access (no owner access to private entities) - token_teams=[...]: Team-scoped access with owner access to private entities Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
- Add automatic JTI (JWT ID) generation to all tokens for revocation support - Add REQUIRE_JTI configuration option to enforce JTI claims - Log warning when tokens without JTI are accepted (for migration visibility) - Add platform admin bootstrap authentication logging for audit trails - Update DummySettings in doctests with require_jti attribute Closes IBM#2127 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* feat: add REQUIRE_USER_IN_DB configuration option - Add require_user_in_db setting to enforce database user existence - When enabled, disables platform admin bootstrap mechanism - Add rejection logging with security_event for audit trails - Add startup warning for ephemeral storage without strict mode - Fix: verify DB existence even when user is cached (prevents cache bypass) - Add unit tests for all auth paths: fallback, batched, and cache-hit (5 new tests) - Update README.md with REQUIRE_JTI and REQUIRE_USER_IN_DB docs - Update Helm chart values.yaml and README.md - Update config.py docstring with new environment variables Closes IBM#2128 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * chore: add environment variable overrides to docker-compose Add shell environment variable overrides for: - AUTH_CACHE_ENABLED (default: true) - REQUIRE_JTI (default: false) - REQUIRE_USER_IN_DB (default: false) - LOG_LEVEL (default: ERROR) This allows flexibility in testing and production deployments. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: resolve pylint W1404 implicit string concatenation warning Combine the two adjacent string literals into a single string to avoid the implicit-str-concat pylint warning. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…ation (IBM#2141) (IBM#2143) - Add EMBED_ENVIRONMENT_IN_TOKENS config to include env claim in gateway JWTs - Add VALIDATE_TOKEN_ENVIRONMENT config to reject tokens with mismatched env claim - Add startup warnings for default JWT_ISSUER/JWT_AUDIENCE in non-dev environments - Update documentation, schema files, and Helm chart values - Fix pre-existing doctest failures in verify_credentials.py Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>
* fix: disable preload on macOS to prevent worker SIGSEGV crashes On macOS, gunicorn's preload feature causes SIGSEGV crashes when using uvicorn workers with async libraries (SQLAlchemy, asyncio). This is due to macOS's strict fork-safety requirements. Changes: - Disable preload_app by default on macOS in both config and shell script - Users can override with GUNICORN_PRELOAD_APP=true if needed Refs: benoitc/gunicorn#2761 Closes IBM#2837 Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * lint Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…M#2835) * add test-verbose target for sequential test execution with real-time output Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * additional enhancements Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * minor fix Signed-off-by: Shoumi <shoumimukherjee@gmail.com> * fix: use --instafail and --maxfail=0 in test-verbose target Run all tests to completion showing failures inline in real-time, rather than stopping at the first failure. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Shoumi <shoumimukherjee@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…#2842) Replace arbitrary wait_for_timeout calls with proper Playwright condition-based waits (wait_for_visible, wait_for_selector, expect, wait_for_load_state, wait_for_count_change). Fix broken login response handling that used non-existent wait_for_response API (was silently swallowed by broad except Exception). Narrow exception handling from Exception to PlaywrightTimeoutError to surface real errors. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix: remove deprecated forwarding methods and fix SSE data parsing Remove deprecated forward_request, _forward_request_to_gateway, and _forward_request_to_all methods from gateway_service.py. Replace forwarding fallbacks in main.py with proper JSON-RPC error responses. Fix SSE parser in llm_proxy_service.py and translate.py to handle data: lines with or without a space after the colon, per the SSE spec. Closes IBM#1595 Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: clean up redundant except clause and align SSE parsing in tests Simplify except (ValueError, Exception) to except Exception since ValueError is a subclass of Exception. Update SSE data: line parsing in integration and e2e tests to match the spec-correct pattern used in production code. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* Update testing Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Update testing Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Update testing Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…cy (IBM#2846) * fix baseUrl Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * fix x-data base-url Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * add new tests Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * fix: complete pagination adjustment and fix broken mock targets - Recompute total_pages, has_next, has_prev, and page in _adjust_pagination_for_conversion_failures to avoid stale UI state - Fix test_auth_cache_import_error: patch the already-imported function reference instead of sys.modules (module-level import was already resolved) - Fix test_redis_available_cache_hit: patch get_redis_client in the consuming module, not the source module - Rename misleading test to test_offset_paginate_page_not_clamped_when_no_items - Add tests for derived pagination field recomputation Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix: do not clamp page after conversion and use root_path for tool-ops - Remove page clamping from _adjust_pagination_for_conversion_failures since data was already fetched for the original page; clamping would make metadata claim a different page than what is displayed - Use request.scope root_path for tool-ops partial endpoint base_url instead of settings.app_root_path, consistent with all other partials Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
…2841) Signed-off-by: Marek Dano <mk.dano@gmail.com>
Introduce a canonical OAuth2/OIDC helper module for token validation, claims extraction, metadata discovery, token exchange/refresh, and scope operations so auth plugins can share consistent protocol logic. Add focused unit coverage for the new helper APIs and RFC-oriented behaviors. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: hany1 <hany1@tcd.ie>
ca7dafc to
d8953f1
Compare
|
Thanks @LOVECAO1011. A reusable OAuth2/OIDC helper module could reduce duplication across our OAuth integrations. Key concerns:
|
|
Thanks for the detailed review and questions.
|
crivetimihai
left a comment
There was a problem hiding this comment.
Good work — this is a clean, well-structured OAuth2/OIDC helper library with proper RFC references (8414, 9728, 8693, 6749, 8707).
Strengths:
- Dataclass models with
slots=Truefor efficiency - Proper exception hierarchy (
OAuth2BaseError→ specific errors) - Issuer mismatch validation in discovery methods
- Comprehensive test coverage with mock HTTP clients
Minor observations:
_validate_jwt_with_jwkscreates a newPyJWKClienton every call — consider caching the client perjwks_urito avoid repeated JWKS fetcheshttpximport at line 212 (inside_validate_token_with_introspection) — should be at module level for consistency with the rest of the file- The library is currently standalone with no integration into existing auth flows — that's fine for Phase 1, just noting it for follow-up
Clean code, good tests, proper error handling. Approved.
Implements Issue IBM#1437 - Create IAM pre-tool plugin Features: - Token caching with configurable TTL (60s safety buffer) - Bearer token injection via http_pre_request hook - Plugin framework integration with proper configuration - Ready for OAuth2 integration (pending PR IBM#2858) Components: - Plugin implementation with token cache and injection logic - Configuration models for server credentials - Comprehensive unit tests (6 tests, all passing) - Documentation with usage examples and architecture diagrams Phase 1 deliverable: Foundation ready for OAuth2 client credentials flow once PR IBM#2858 (OAuth2 base library) merges. Related: - Issue IBM#1437 (this implementation) - Issue IBM#1422 (EPIC: Agent and tool authentication) - Issue IBM#1434 (OAuth2 base library - PR IBM#2858) - Issue IBM#1438 (Future enhancements) Signed-off-by: Ioannis Ioannou <yiannis2804@example.com> Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
|
Reopened as #3198. CI/CD will re-run on the new PR. You are still credited as the author. |
Implements Issue #1437 - Create IAM pre-tool plugin Features: - Token caching with configurable TTL (60s safety buffer) - Bearer token injection via http_pre_request hook - Plugin framework integration with proper configuration - Ready for OAuth2 integration (pending PR #2858) Components: - Plugin implementation with token cache and injection logic - Configuration models for server credentials - Comprehensive unit tests (6 tests, all passing) - Documentation with usage examples and architecture diagrams Phase 1 deliverable: Foundation ready for OAuth2 client credentials flow once PR #2858 (OAuth2 base library) merges. Related: - Issue #1437 (this implementation) - Issue #1422 (EPIC: Agent and tool authentication) - Issue #1434 (OAuth2 base library - PR #2858) - Issue #1438 (Future enhancements) Signed-off-by: Ioannis Ioannou <yiannis2804@example.com> Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
Introduce a canonical OAuth2/OIDC helper module for token validation, claims extraction, metadata discovery, token exchange/refresh, and scope operations so auth plugins can share consistent protocol logic. Add focused unit coverage for the new helper APIs and RFC-oriented behaviors.
🔗 Related Issue
Closes #
📝 Summary
mcpgateway/oauth2/base.pyvalidate_token()with JWKS JWT verification and introspection fallbackextract_claims()canonical claim mappingdiscover_authorization_server_metadata()(RFC 8414)discover_oidc_metadata()(OIDC discovery)discover_protected_resource_metadata()(RFC 9728)exchange_token()(RFC 8693)refresh_token()(RFC 6749)mcpgateway/oauth2/models.pytyped request/response config modelsmcpgateway/oauth2/exceptions.pyunified OAuth2 error typesmcpgateway/oauth2/__init__.pypublic exportstests/unit/mcpgateway/oauth2/test_base.pyfocused unit tests for helper APIs and error paths🏷️ Type of Change
🧪 Verification
make lintmake testmake coverage✅ Checklist
make black isort pre-commit)📓 Notes (optional)
This PR delivers the OAuth2 base helper layer requested by #1434 and is designed to be consumed by plugin/auth flows in the #1422 epic.