Change Swagger UI endpoint from /api/swagger/ to /api/docs/ (#16172)

* Change Swagger UI endpoint from /api/swagger/ to /api/docs/

- Update URL pattern to use /docs/ instead of /swagger/
- Update API root response to show 'docs' key instead of 'swagger'
- Add authentication requirement for schema documentation endpoints
- Update contact email to controller-eng@redhat.com

The schema endpoints (/api/docs/, /api/schema/, /api/redoc/) now
require authentication to prevent unauthorized access to API
documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Require authentication for all schema endpoints including /api/schema/

Create custom view classes that enforce authentication for all schema
endpoints to prevent inconsistent access control where UI views required
authentication but the raw schema endpoint remained publicly accessible.

This ensures all schema endpoints (/api/schema/, /api/docs/, /api/redoc/)
consistently require authentication.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add unit tests for authenticated schema view classes

Add test coverage for the new AuthenticatedSpectacular* view classes
to ensure they properly require authentication.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* remove unused import

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Rodrigo Toshiaki Horie 2025-11-12 09:14:54 -03:00 committed by GitHub
parent 335a4bbbc6
commit f81859510c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 7 deletions

View File

@ -1,5 +1,6 @@
import warnings
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.openapi import AutoSchema
from drf_spectacular.views import (
SpectacularAPIView,
@ -46,11 +47,29 @@ class CustomAutoSchema(AutoSchema):
return getattr(self.view, 'deprecated', False)
class AuthenticatedSpectacularAPIView(SpectacularAPIView):
"""SpectacularAPIView that requires authentication."""
permission_classes = [IsAuthenticated]
class AuthenticatedSpectacularSwaggerView(SpectacularSwaggerView):
"""SpectacularSwaggerView that requires authentication."""
permission_classes = [IsAuthenticated]
class AuthenticatedSpectacularRedocView(SpectacularRedocView):
"""SpectacularRedocView that requires authentication."""
permission_classes = [IsAuthenticated]
# Schema view (returns OpenAPI schema JSON/YAML)
schema_view = SpectacularAPIView.as_view()
schema_view = AuthenticatedSpectacularAPIView.as_view()
# Swagger UI view
swagger_ui_view = SpectacularSwaggerView.as_view(url_name='api:schema-json')
swagger_ui_view = AuthenticatedSpectacularSwaggerView.as_view(url_name='api:schema-json')
# ReDoc UI view
redoc_view = SpectacularRedocView.as_view(url_name='api:schema-json')
redoc_view = AuthenticatedSpectacularRedocView.as_view(url_name='api:schema-json')

View File

@ -158,7 +158,7 @@ urlpatterns = [
re_path(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'),
# Schema endpoints (available in all modes for API documentation and testing)
re_path(r'^schema/$', schema_view, name='schema-json'),
re_path(r'^swagger/$', swagger_ui_view, name='schema-swagger-ui'),
re_path(r'^docs/$', swagger_ui_view, name='schema-swagger-ui'),
re_path(r'^redoc/$', redoc_view, name='schema-redoc'),
]

View File

@ -59,7 +59,7 @@ class ApiRootView(APIView):
data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO
data['login_redirect_override'] = settings.LOGIN_REDIRECT_OVERRIDE
if MODE == 'development':
data['swagger'] = drf_reverse('api:schema-swagger-ui')
data['docs'] = drf_reverse('api:schema-swagger-ui')
return Response(data)

View File

@ -1,7 +1,14 @@
import warnings
from unittest.mock import Mock, patch
from awx.api.schema import CustomAutoSchema
from rest_framework.permissions import IsAuthenticated
from awx.api.schema import (
CustomAutoSchema,
AuthenticatedSpectacularAPIView,
AuthenticatedSpectacularSwaggerView,
AuthenticatedSpectacularRedocView,
)
class TestCustomAutoSchema:
@ -248,3 +255,19 @@ class TestCustomAutoSchema:
tags = schema.get_tags()
# swagger_topic should take priority
assert tags == ['Priority_Topic']
class TestAuthenticatedSchemaViews:
"""Unit tests for authenticated schema view classes."""
def test_authenticated_spectacular_api_view_requires_authentication(self):
"""Test that AuthenticatedSpectacularAPIView requires authentication."""
assert IsAuthenticated in AuthenticatedSpectacularAPIView.permission_classes
def test_authenticated_spectacular_swagger_view_requires_authentication(self):
"""Test that AuthenticatedSpectacularSwaggerView requires authentication."""
assert IsAuthenticated in AuthenticatedSpectacularSwaggerView.permission_classes
def test_authenticated_spectacular_redoc_view_requires_authentication(self):
"""Test that AuthenticatedSpectacularRedocView requires authentication."""
assert IsAuthenticated in AuthenticatedSpectacularRedocView.permission_classes

View File

@ -1043,7 +1043,7 @@ SPECTACULAR_SETTINGS = {
'SCHEMA_PATH_PREFIX': r'/api/v[0-9]',
'DEFAULT_GENERATOR_CLASS': 'drf_spectacular.generators.SchemaGenerator',
'SCHEMA_COERCE_PATH_PK_SUFFIX': True,
'CONTACT': {'email': 'contact@snippets.local'},
'CONTACT': {'email': 'controller-eng@redhat.com'},
'LICENSE': {'name': 'Apache License'},
'TERMS_OF_SERVICE': 'https://www.google.com/policies/terms/',
# Use our custom schema class that handles swagger_topic and deprecated views