csrd-utils 0.3.96__tar.gz → 0.3.98__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/PKG-INFO +1 -1
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/pyproject.toml +1 -1
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/presets.py +1 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/db.py.template +20 -2
- csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/token_service.py +22 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/repositories/user_repository.py +5 -1
- csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/services/token_service.py +91 -0
- csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +40 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/jwks_view.py +2 -6
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/users_view.py +1 -4
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/__init__.py +1 -0
- csrd_utils-0.3.96/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +0 -115
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/.gitignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/__main__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/audit.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/augmentor.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/cluster.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/doctor.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/manifest.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/requirements.fragment +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/manifest.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/requirements.fragment +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/manifest.yaml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/requirements.fragment +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/fragments.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/generator.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/resources.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/auth_delegate.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/identity_delegate.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_passthrough.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/auth_service.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/items.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_service_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/auth.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/users.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/AGENTS.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/augments.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/git.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/infra.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/loader.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/operations.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/renderer.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/scaffolder.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/service_renderers.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/yaml_editor.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/handlers.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/helpers.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/menu.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/base.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/spec.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/types.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/delegates/auth_delegate.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/dependencies/auth_passthrough.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/models/auth_passthrough.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/views/auth_passthrough_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/db-config/dependencies/db.py.template +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/db-config/migrations.py.template +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-consumer/dependencies/auth.py.template +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/migrations.py.template +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/auth.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/jwks.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/users.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/cookiecutter.json +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/health.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/test_health.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/__init__.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/exceptions.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/menu.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/models.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/prompts.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/terminal.py +0 -0
- {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/wizard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csrd-utils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.98
|
|
4
4
|
Summary: CLI utilities for csrd service generation and feature augmentation
|
|
5
5
|
Project-URL: Repository, https://github.com/csrd-api/fastapi-common
|
|
6
6
|
Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Database and
|
|
1
|
+
"""Database, repository, and key ring dependencies for the auth service.
|
|
2
2
|
|
|
3
3
|
This file is scaffolded once and never overwritten.
|
|
4
4
|
"""
|
|
@@ -7,6 +7,8 @@ from typing import Annotated
|
|
|
7
7
|
|
|
8
8
|
from fastapi import Depends
|
|
9
9
|
|
|
10
|
+
from csrd.auth import KeyRingManager
|
|
11
|
+
|
|
10
12
|
$db_adapter_import
|
|
11
13
|
|
|
12
14
|
from ..repositories.user_repository import UserRepository
|
|
@@ -43,4 +45,20 @@ def _user_repository_factory(adapter: Adapter) -> UserRepository:
|
|
|
43
45
|
|
|
44
46
|
UserRepo = Annotated[UserRepository, Depends(_user_repository_factory)]
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
|
|
49
|
+
async def _key_ring_factory(adapter: Adapter, settings: Settings) -> KeyRingManager:
|
|
50
|
+
"""Create and initialize a ``KeyRingManager`` for JWT signing."""
|
|
51
|
+
key_ring = KeyRingManager(
|
|
52
|
+
adapter=adapter,
|
|
53
|
+
key_size=settings.jwt_key_size,
|
|
54
|
+
rotation_interval=settings.jwt_key_rotation_interval,
|
|
55
|
+
retention_period=settings.jwt_key_retention_period,
|
|
56
|
+
token_ttl=settings.jwt_ttl_seconds,
|
|
57
|
+
)
|
|
58
|
+
await key_ring.initialize()
|
|
59
|
+
return key_ring
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
KeyRing = Annotated[KeyRingManager, Depends(_key_ring_factory)]
|
|
63
|
+
|
|
64
|
+
__all__ = ("Adapter", "KeyRing", "UserRepo")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Token service dependency for the auth service.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends
|
|
9
|
+
|
|
10
|
+
from ..services.token_service import TokenService
|
|
11
|
+
from . import Settings
|
|
12
|
+
from .db import KeyRing
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _token_service_factory(key_ring: KeyRing, settings: Settings) -> TokenService:
|
|
16
|
+
"""Create a ``TokenService`` with the key ring and settings."""
|
|
17
|
+
return TokenService(key_ring, settings)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
TokenSvc = Annotated[TokenService, Depends(_token_service_factory)]
|
|
21
|
+
|
|
22
|
+
__all__ = ("TokenSvc",)
|
|
@@ -21,7 +21,11 @@ class UserRepository(BaseRepository):
|
|
|
21
21
|
# ── User CRUD ────────────────────────────────────────────────────
|
|
22
22
|
|
|
23
23
|
async def create_user(self, username: str, password: str) -> UserResponse:
|
|
24
|
-
"""Create a new user with hashed credentials."""
|
|
24
|
+
"""Create a new user with hashed credentials. Raises 409 if exists."""
|
|
25
|
+
existing = await self.get_user_by_username(username)
|
|
26
|
+
if existing is not None:
|
|
27
|
+
raise HTTPException(status_code=409, detail="Username already taken")
|
|
28
|
+
|
|
25
29
|
user_id = str(uuid.uuid4())
|
|
26
30
|
await self.execute(
|
|
27
31
|
"INSERT INTO users (id, username) VALUES (:id, :username)",
|
csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/services/token_service.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Token service for JWT issuance and verification.
|
|
2
|
+
|
|
3
|
+
Encapsulates all JWT business logic: signing, verification, and
|
|
4
|
+
claims construction. Views call service methods and return the result.
|
|
5
|
+
|
|
6
|
+
This file is scaffolded once and never overwritten.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import jwt as pyjwt
|
|
13
|
+
from fastapi import HTTPException
|
|
14
|
+
from jwt.algorithms import RSAAlgorithm
|
|
15
|
+
|
|
16
|
+
from csrd.auth import KeyRingManager
|
|
17
|
+
|
|
18
|
+
from ..models.auth import TokenResponse, VerifyClaims, VerifyResponse
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TokenService:
|
|
22
|
+
"""JWT token issuance and verification."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, key_ring: KeyRingManager, settings: Any) -> None:
|
|
25
|
+
self._key_ring = key_ring
|
|
26
|
+
self._settings = settings
|
|
27
|
+
|
|
28
|
+
async def issue_token(
|
|
29
|
+
self,
|
|
30
|
+
*,
|
|
31
|
+
user_id: str,
|
|
32
|
+
username: str,
|
|
33
|
+
roles: list[str],
|
|
34
|
+
) -> TokenResponse:
|
|
35
|
+
"""Create a signed JWT for the given user."""
|
|
36
|
+
await self._key_ring.rotate_if_needed()
|
|
37
|
+
kid, private_key = await self._key_ring.active_key()
|
|
38
|
+
|
|
39
|
+
now = int(time.time())
|
|
40
|
+
payload: dict[str, Any] = {
|
|
41
|
+
"sub": user_id,
|
|
42
|
+
"user_name": username,
|
|
43
|
+
"authorities": roles,
|
|
44
|
+
"iat": now,
|
|
45
|
+
"exp": now + self._settings.jwt_ttl_seconds,
|
|
46
|
+
"iss": self._settings.jwt_issuer,
|
|
47
|
+
"aud": self._settings.jwt_audience,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
token = pyjwt.encode(
|
|
51
|
+
payload,
|
|
52
|
+
private_key,
|
|
53
|
+
algorithm=self._settings.jwt_algorithm,
|
|
54
|
+
headers={"kid": kid},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return TokenResponse(access_token=token, expires_in=self._settings.jwt_ttl_seconds)
|
|
58
|
+
|
|
59
|
+
async def verify_token(self, token: str) -> VerifyResponse:
|
|
60
|
+
"""Verify a JWT and return its claims. Raises on failure."""
|
|
61
|
+
jwks = await self._key_ring.jwks_dict()
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
unverified = pyjwt.get_unverified_header(token)
|
|
65
|
+
kid = unverified.get("kid")
|
|
66
|
+
|
|
67
|
+
jwk_data = next(
|
|
68
|
+
(k for k in jwks["keys"] if k["kid"] == kid),
|
|
69
|
+
None,
|
|
70
|
+
)
|
|
71
|
+
if jwk_data is None:
|
|
72
|
+
raise HTTPException(status_code=401, detail="Unknown signing key")
|
|
73
|
+
|
|
74
|
+
public_key = RSAAlgorithm.from_jwk(jwk_data)
|
|
75
|
+
|
|
76
|
+
claims = pyjwt.decode(
|
|
77
|
+
token,
|
|
78
|
+
public_key,
|
|
79
|
+
algorithms=[self._settings.jwt_algorithm],
|
|
80
|
+
issuer=self._settings.jwt_issuer,
|
|
81
|
+
audience=self._settings.jwt_audience,
|
|
82
|
+
)
|
|
83
|
+
return VerifyResponse(active=True, claims=VerifyClaims(**claims))
|
|
84
|
+
|
|
85
|
+
except pyjwt.ExpiredSignatureError:
|
|
86
|
+
raise HTTPException(status_code=401, detail="Token has expired") from None
|
|
87
|
+
except pyjwt.InvalidTokenError as exc:
|
|
88
|
+
raise HTTPException(status_code=401, detail=f"Invalid token: {exc}") from None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
__all__ = ("TokenService",)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Token issuance and verification endpoints.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fastapi import APIRouter
|
|
7
|
+
|
|
8
|
+
from ..dependencies.db import UserRepo
|
|
9
|
+
from ..dependencies.token_service import TokenSvc
|
|
10
|
+
from ..models.auth import (
|
|
11
|
+
TokenRequest,
|
|
12
|
+
TokenResponse,
|
|
13
|
+
VerifyRequest,
|
|
14
|
+
VerifyResponse,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
router = APIRouter(tags=["auth"])
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@router.post("/api/token", response_model=TokenResponse)
|
|
22
|
+
async def issue_token(
|
|
23
|
+
body: TokenRequest,
|
|
24
|
+
repo: UserRepo,
|
|
25
|
+
token_svc: TokenSvc,
|
|
26
|
+
) -> TokenResponse:
|
|
27
|
+
"""Validate credentials and issue a JWT access token."""
|
|
28
|
+
user = await repo.verify_credentials(body.username, body.password)
|
|
29
|
+
roles_resp = await repo.get_user_roles(user.id)
|
|
30
|
+
return await token_svc.issue_token(
|
|
31
|
+
user_id=user.id,
|
|
32
|
+
username=user.username,
|
|
33
|
+
roles=roles_resp.roles,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@router.post("/api/verify", response_model=VerifyResponse)
|
|
38
|
+
async def verify_token(body: VerifyRequest, token_svc: TokenSvc) -> VerifyResponse:
|
|
39
|
+
"""Verify a JWT and return its claims."""
|
|
40
|
+
return await token_svc.verify_token(body.token)
|
|
@@ -6,7 +6,7 @@ This file is scaffolded once and never overwritten.
|
|
|
6
6
|
|
|
7
7
|
from fastapi import APIRouter
|
|
8
8
|
|
|
9
|
-
from ..dependencies.db import
|
|
9
|
+
from ..dependencies.db import KeyRing
|
|
10
10
|
from ..models.jwks import JWKSResponse
|
|
11
11
|
|
|
12
12
|
router = APIRouter(tags=["jwks"])
|
|
@@ -14,15 +14,11 @@ router = APIRouter(tags=["jwks"])
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@router.get("/.well-known/jwks.json", response_model=JWKSResponse)
|
|
17
|
-
async def jwks(
|
|
17
|
+
async def jwks(key_ring: KeyRing) -> JWKSResponse:
|
|
18
18
|
"""Return public keys for all active signing keys in JWK format.
|
|
19
19
|
|
|
20
20
|
Consumers cache this response and refresh automatically when
|
|
21
21
|
they encounter an unknown ``kid`` in a token header.
|
|
22
22
|
"""
|
|
23
|
-
from csrd.auth import KeyRingManager
|
|
24
|
-
|
|
25
|
-
key_ring = KeyRingManager(adapter=adapter)
|
|
26
|
-
await key_ring.initialize()
|
|
27
23
|
jwks_data = await key_ring.jwks_dict()
|
|
28
24
|
return JWKSResponse(keys=jwks_data["keys"])
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file is scaffolded once and never overwritten.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from fastapi import APIRouter
|
|
6
|
+
from fastapi import APIRouter
|
|
7
7
|
|
|
8
8
|
from ..dependencies.db import UserRepo
|
|
9
9
|
from ..models.users import (
|
|
@@ -20,9 +20,6 @@ router = APIRouter(tags=["users"])
|
|
|
20
20
|
@router.post("/api/signup", status_code=201, response_model=UserResponse)
|
|
21
21
|
async def signup(body: SignupRequest, repo: UserRepo) -> UserResponse:
|
|
22
22
|
"""Create a new user account."""
|
|
23
|
-
existing = await repo.get_user_by_username(body.username)
|
|
24
|
-
if existing is not None:
|
|
25
|
-
raise HTTPException(status_code=409, detail="Username already taken")
|
|
26
23
|
return await repo.create_user(body.username, body.password)
|
|
27
24
|
|
|
28
25
|
|
|
@@ -16,6 +16,7 @@ def build_app() -> FastAPI:
|
|
|
16
16
|
version_mapping={UNVERSIONED: unversioned_app},
|
|
17
17
|
config=VersionedAppComposeConfig(
|
|
18
18
|
title="{{ cookiecutter.service_name }}",
|
|
19
|
+
app_state={"settings": settings},
|
|
19
20
|
api=VersionedApiConfig(
|
|
20
21
|
prefix="/",
|
|
21
22
|
include_actuator_endpoints=settings.include_actuator_endpoints,
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
"""Token issuance and verification endpoints.
|
|
2
|
-
|
|
3
|
-
This file is scaffolded once and never overwritten.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import time
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
import jwt as pyjwt
|
|
10
|
-
from fastapi import APIRouter, HTTPException
|
|
11
|
-
|
|
12
|
-
from ..dependencies import Settings
|
|
13
|
-
from ..dependencies.db import Adapter, UserRepo
|
|
14
|
-
from ..models.auth import (
|
|
15
|
-
TokenRequest,
|
|
16
|
-
TokenResponse,
|
|
17
|
-
VerifyClaims,
|
|
18
|
-
VerifyRequest,
|
|
19
|
-
VerifyResponse,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
router = APIRouter(tags=["auth"])
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@router.post("/api/token", response_model=TokenResponse)
|
|
27
|
-
async def issue_token(
|
|
28
|
-
body: TokenRequest,
|
|
29
|
-
settings: Settings,
|
|
30
|
-
adapter: Adapter,
|
|
31
|
-
repo: UserRepo,
|
|
32
|
-
) -> TokenResponse:
|
|
33
|
-
"""Validate credentials and issue a JWT access token."""
|
|
34
|
-
user = await repo.verify_credentials(body.username, body.password)
|
|
35
|
-
roles_resp = await repo.get_user_roles(user.id)
|
|
36
|
-
|
|
37
|
-
# Get the active signing key
|
|
38
|
-
from csrd.auth import KeyRingManager
|
|
39
|
-
|
|
40
|
-
key_ring = KeyRingManager(
|
|
41
|
-
adapter=adapter,
|
|
42
|
-
key_size=settings.jwt_key_size,
|
|
43
|
-
rotation_interval=settings.jwt_key_rotation_interval,
|
|
44
|
-
retention_period=settings.jwt_key_retention_period,
|
|
45
|
-
token_ttl=settings.jwt_ttl_seconds,
|
|
46
|
-
)
|
|
47
|
-
await key_ring.initialize()
|
|
48
|
-
await key_ring.rotate_if_needed()
|
|
49
|
-
kid, private_key = await key_ring.active_key()
|
|
50
|
-
|
|
51
|
-
now = int(time.time())
|
|
52
|
-
payload: dict[str, Any] = {
|
|
53
|
-
"sub": user.id,
|
|
54
|
-
"user_name": user.username,
|
|
55
|
-
"authorities": roles_resp.roles,
|
|
56
|
-
"iat": now,
|
|
57
|
-
"exp": now + settings.jwt_ttl_seconds,
|
|
58
|
-
"iss": settings.jwt_issuer,
|
|
59
|
-
"aud": settings.jwt_audience,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
token = pyjwt.encode(
|
|
63
|
-
payload,
|
|
64
|
-
private_key,
|
|
65
|
-
algorithm=settings.jwt_algorithm,
|
|
66
|
-
headers={"kid": kid},
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
return TokenResponse(access_token=token, expires_in=settings.jwt_ttl_seconds)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@router.post("/api/verify", response_model=VerifyResponse)
|
|
73
|
-
async def verify_token(
|
|
74
|
-
body: VerifyRequest,
|
|
75
|
-
settings: Settings,
|
|
76
|
-
adapter: Adapter,
|
|
77
|
-
) -> VerifyResponse:
|
|
78
|
-
"""Verify a JWT and return its claims."""
|
|
79
|
-
|
|
80
|
-
from csrd.auth import KeyRingManager
|
|
81
|
-
|
|
82
|
-
key_ring = KeyRingManager(adapter=adapter)
|
|
83
|
-
await key_ring.initialize()
|
|
84
|
-
jwks = await key_ring.jwks_dict()
|
|
85
|
-
|
|
86
|
-
try:
|
|
87
|
-
# Get the kid from the token header
|
|
88
|
-
unverified = pyjwt.get_unverified_header(body.token)
|
|
89
|
-
kid = unverified.get("kid")
|
|
90
|
-
|
|
91
|
-
# Find the matching public key
|
|
92
|
-
from jwt.algorithms import RSAAlgorithm
|
|
93
|
-
|
|
94
|
-
jwk_data = next(
|
|
95
|
-
(k for k in jwks["keys"] if k["kid"] == kid),
|
|
96
|
-
None,
|
|
97
|
-
)
|
|
98
|
-
if jwk_data is None:
|
|
99
|
-
raise HTTPException(status_code=401, detail="Unknown signing key")
|
|
100
|
-
|
|
101
|
-
public_key = RSAAlgorithm.from_jwk(jwk_data)
|
|
102
|
-
|
|
103
|
-
claims = pyjwt.decode(
|
|
104
|
-
body.token,
|
|
105
|
-
public_key,
|
|
106
|
-
algorithms=[settings.jwt_algorithm],
|
|
107
|
-
issuer=settings.jwt_issuer,
|
|
108
|
-
audience=settings.jwt_audience,
|
|
109
|
-
)
|
|
110
|
-
return VerifyResponse(active=True, claims=VerifyClaims(**claims))
|
|
111
|
-
|
|
112
|
-
except pyjwt.ExpiredSignatureError:
|
|
113
|
-
raise HTTPException(status_code=401, detail="Token has expired") from None
|
|
114
|
-
except pyjwt.InvalidTokenError as exc:
|
|
115
|
-
raise HTTPException(status_code=401, detail=f"Invalid token: {exc}") from None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/conftest.fragment.py
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/docker-compose.fragment.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/requirements.fragment
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/settings.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/conftest.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/requirements.fragment
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/settings.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/conftest.fragment.py
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/requirements.fragment
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/settings.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/conftest.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/requirements.fragment
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/settings.fragment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/conftest.fragment.py
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/docker-compose.fragment.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/requirements.fragment
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/settings.fragment.py
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/tasks.py
RENAMED
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/tests/test_workers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|