Authenticating Swagger API docs (drf-yasg) - django

I've setup DRF-YASG but am unable to figure out how to configure it to show Views that require Authentication.
Below is the configuration.
schema_view = get_schema_view(
openapi.Info(
title="Swagger Doc",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact#snippets.local"),
license=openapi.License(name="BSD License"),
),
validators=['flex', 'ssv'],
permission_classes=(permissions.AllowAny,), # If I change the permission it throws an exception. See below
public=False,
patterns=public_apis,
)
the public_apis are the APIs that I want a person to see after they have authenticated themselves.
With the above configuration, it does not show a single API. It only shows the Authorize Button and text that says No operations defined in spec!. But if I change public=False to public=True then it shows all the APIs.
PS: Earlier I was using Django Rest Swagger and I had been able to configure it to show the APIs only after the JWT token had been provided.
Am is using JWT for authentication.
Exception on Permission Change:
Another issue is that if I change the permission above to a DRF Permission class the rendering fails with the error below:
Internal Server Error: /swagger/
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 217, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 215, in _get_response
response = response.render()
File "/usr/local/lib/python3.6/site-packages/django/template/response.py", line 107, in render
self.content = self.rendered_content
File "/usr/local/lib/python3.6/site-packages/rest_framework/response.py", line 72, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/usr/local/lib/python3.6/site-packages/drf_yasg/renderers.py", line 54, in render
self.set_context(renderer_context, swagger)
File "/usr/local/lib/python3.6/site-packages/drf_yasg/renderers.py", line 62, in set_context
renderer_context['title'] = swagger.info.title
AttributeError: 'dict' object has no attribute 'info'
Internal Server Error: /swagger/
I've tried changing it to permmissions.IsAuthenticated and my own custom permission classes but they all fail with the same error.

Turned out the issue was that I was missing rest_framework.authentication.SessionAuthentication in DRF's DEFAULT_AUTHENTICATION_CLASSES.
So the request object sent after logging in via the Django Admin login view did not have a user so all permission classes kept failing and it would then lead to the above error.
So after adding it drf-yasg shows all its glory.
Bug:
The error it throws when this occurs was raised as bug though. See #issue58.

Related

get embed dashboard with roles and permissions in superset

I am trying to embed dashboard in superset based on the roles and permissions created in superset application roles.
I had created a role and given certain permission and assigned to specific user. But while embeding in superset, that particular user is having the permission of 'view query' option in chart controls even though I didn't assigned that in permission. But when I log in to superset directly with that user, I can see those roles and permissions are applying over there but not in Embed Dashboard. Can anyone help me on this?
I am using superset version - 2.0.1
superset logs:
2023-02-13 16:31:00,516:ERROR:root:'GuestUser' object has no attribute 'get_user_id'
Traceback (most recent call last):
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/flask_appbuilder/api/init.py", line 86, in wraps
return f(self, *args, **kwargs)
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/utils/log.py", line 245, in wrapper
value = f(*args, **kwargs)
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/dashboards/filter_state/api.py", line 98, in post
return super().post(pk)
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/views/base_api.py", line 83, in wraps
return f(self, *args, **kwargs)
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/temporary_cache/api.py", line 76, in post
key = self.get_create_command()(args).run()
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/temporary_cache/commands/create.py", line 35, in run
return self.create(self._cmd_params)
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/dashboards/filter_state/commands/create.py", line 41, in create
entry: Entry = {"owner": get_owner(actor), "value": value}
File "/home/gridlex/Desktop/main_project/binary_superset_file/binary_ss_env/lib/python3.8/site-packages/superset/key_value/utils.py", line 70, in get_owner
return user.get_user_id() if not user.is_anonymous else None
AttributeError: 'GuestUser' object has no attribute 'get_user_id'
2023-02-13 16:31:00,533:INFO:werkzeug:127.0.0.1 - - [13/Feb/2023 16:31:00] "POST /api/v1/dashboard/11/filter_state?tab_id=1 HTTP/1.1" 500 -
And I am getting the following error in browser console.
POST http://127.0.0.1:8088/api/v1/dashboard/11/filter_state?tab_id=1 500 (INTERNAL SERVER ERROR)
Response {type: 'basic', url: 'http://127.0.0.1:8088/api/v1/dashboard/11/filter_state?tab_id=1', redirected: false, status: 500, ok: false, …}

DRF spectacular not discovering custom auth extension classes

when extending a new Token Authentication class from rest_framework_simplejwt.authentication.JWTAuthentication drf-spectacular swagger-ui authorize button disappears and there is no way to add token bearer, I guess when you subclass it goes wrong.
steps to reproduce:
first, create a Django project with rest framework and drf-spectacular and simple jwt installed and configured with documentation guidance. got to /swagger-ui/ and it works fine.
then create a subclass of JWTAuthentication like below:
from rest_framework_simplejwt.authentication import JWTAuthentication as JWTA
class JWTAuthentication(JWTA):
pass
and in your settings:
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': (
'path_to_your_module.JWTAuthentication',
),
}
and now if you go to /swagger-ui/ there is no authorize button!!! how can I fix this?
and I even tried to create an AuthenticationExtension like:
from drf_spectacular.contrib.rest_framework_simplejwt import SimpleJWTScheme
class SimpleJWTTokenUserScheme(SimpleJWTScheme):
target_class = 'path_to_your_module.JWTAuthentication'
but there is no way to register it anywhere nor on the internet nor in the documentation!!
how can I fix authorize button when overriding an Authentication class??
Edit: doing what JPG says and importing extension in settings:
# settings.py
from path.to.custom.extension import SimpleJWTTokenUserScheme
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': (
'path_to_your_module.JWTAuthentication',
),
}
raises exception:
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/drf_spectacular/views.py", line 67, in get
return self._get_schema_response(request)
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/drf_spectacular/views.py", line 74, in _get_schema_response
return Response(generator.get_schema(request=request, public=self.serve_public))
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/drf_spectacular/generators.py", line 250, in get_schema
paths=self.parse(request, public),
File "/home/hamex/current/spec/env/lib/python3.8/site-packages/drf_spectacular/generators.py", line 218, in parse
assert isinstance(view.schema, AutoSchema), (
AssertionError: Incompatible AutoSchema used on View <class 'drf_spectacular.views.SpectacularAPIView'>. Is DRF's DEFAULT_SCHEMA_CLASS pointing to "drf_spectacular.openapi.AutoSchema" or any other drf-spectacular compatible AutoSchema?
Update-1
from the doc Where should I put my extensions? / my extensions are not detected
The extensions register themselves automatically. Just be sure that
the python interpreter sees them at least once. To that end, we
suggest creating a PROJECT/schema.py file and importing it in your
PROJECT/__init__.py (same directory as settings.py and urls.py)
with import PROJECT.schema. Please do not import the file in
settings.py as this may potentially lead to cyclic import issues.
Original Answer
It seems a bug with the package itself. You can use the actual class instead of path to class while extending the auth extension
from drf_spectacular.contrib.rest_framework_simplejwt import SimpleJWTScheme
from path.to.custom.jwt.auth import JWTAuthentication
class SimpleJWTTokenUserScheme(SimpleJWTScheme):
target_class = JWTAuthentication
I have created a simple example here, drf-spectacular-example, hope someone will benefit from it!!!

why swagger raises unclear error - Django

I have a django rest Backend app, and i use swagger to look and document my apis to the FE.
This worked fine, but I made some changes and now I get this error:
Internal Server Error: /
Traceback (most recent call last):
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/views.py", line 497, in dispatch
response = self.handle_exception(exc)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/views.py", line 457, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/views.py", line 468, in raise_uncaught_exception
raise exc
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/views.py", line 494, in dispatch
response = handler(request, *args, **kwargs)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework_swagger/views.py", line 32, in get
schema = generator.get_schema(request=request)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/schemas/coreapi.py", line 153, in get_schema
links = self.get_links(None if public else request)
File "/home/notsoshabby/.local/share/virtualenvs/panda_pitch-UBt5SNMA/lib/python3.7/site-packages/rest_framework/schemas/coreapi.py", line 140, in get_links
link = view.schema.get_link(path, method, base_url=self.url)
AttributeError: 'AutoSchema' object has no attribute 'get_link'
HTTP GET / 500 [0.15, 127.0.0.1:44214]
/home/notsoshabby/Desktop/panda_pitch/django_project/settings.py
This error is not very clear as the AutoSchema is not a part of my code and the traceback is not showing me where in My code the problem is.
I made too many changes to go one by one and check which one caused that.
Anyone experienced this issue before? Any ideas on how to debug to find which change causes this issue?
I ran into the same issue, the fix is described here: https://www.django-rest-framework.org/community/3.10-announcement/
To summarize, Django Rest Framework 3.10 (released a few days ago) deprecated the CoreAPI based schema generation, and introduced the OpenAPI schema generation in its place. Currently to continue to use django-rest-swagger as is you need to re-enable the CoreAPI schema generation by adding the following config to the settings file:
REST_FRAMEWORK = { ... 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' }

Test permission denied not catched

I try to check with unittests if it is possible to access a certain url without the proper permissions.
When I wrote the test everything worked correctly. I don't know if the error started to occurs after a Django update because I didn't check the test after the update and just started to write new tests which failed. So I checked my old test which is now failing too.
class MemberTestMethods(TestCase):
def setUp(self):
# Create user
user = User.objects.create_user('temp', 'temp#temp.tld', 'temppass')
user.first_name = 'temp_first'
user.last_name = 'temp_last'
user.save()
# login with user
self.client.login(username='temp', password='temppass')
# Create member
member = Member.objects.create(salutation=Member.MR, first_name='Temp', last_name='Temp')
member.save()
def test_member_list_permission(self):
"User should only access member list if view permission is set"
user = User.objects.get(username='temp')
response = self.client.get(reverse('members:list'))
self.assertEqual(response.status_code, 403)
user.user_permissions.add(Permission.objects.get(codename='view_member'))
response = self.client.get(reverse('members:list'))
self.assertEqual(response.status_code, 200)
After running python manage.py test I get the following error
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
WARNING:django.request:Forbidden (Permission denied): /de/reporting/
Traceback (most recent call last):
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 84, in dispatch
return self.handle_no_permission()
File "/home/***/.virtualenvs/pyVerein/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 43, in handle_no_permission
raise PermissionDenied(self.get_permission_denied_message())
django.core.exceptions.PermissionDenied
Previously the test ran successfully while checking for HTTP-Code 403 like it is describe in the documentation (https://docs.djangoproject.com/en/2.1/topics/testing/tools/#exceptions)
The full Sourceode is available at Github (https://github.com/HamburgerJungeJr/pyVerein/tree/pyReportJasper/pyVerein/members)
Am I missing a change in the Django-Test system?
I just found the solution. The PyReportJasper-package set the global logging level to INFO. After changing this the error is gone.

Trying to login to a ATWS with SUDS error

Im trying to login to a ATWS service with suds but I keep getting the following error:
Traceback (most recent call last):
File "/Users/AAAA/Documents/Aptana/AutotaskUpdateTicketEstimatedHours/Main.py", line 38, in <module>
handler = ConnectATWS()
File "/Users/AAAA/Documents/Aptana/AutotaskUpdateTicketEstimatedHours/Main.py", line 31, in __init__
client = Client(self.url)
File "/Library/Python/2.7/site-packages/suds/client.py", line 112, in __init__
self.wsdl = reader.open(url)
File "/Library/Python/2.7/site-packages/suds/reader.py", line 152, in open
d = self.fn(url, self.options)
File "/Library/Python/2.7/site-packages/suds/wsdl.py", line 136, in __init__
d = reader.open(url)
File "/Library/Python/2.7/site-packages/suds/reader.py", line 79, in open
d = self.download(url)
File "/Library/Python/2.7/site-packages/suds/reader.py", line 95, in download
fp = self.options.transport.open(Request(url))
File "/Library/Python/2.7/site-packages/suds/transport/https.py", line 60, in open
return HttpTransport.open(self, request)
File "/Library/Python/2.7/site-packages/suds/transport/http.py", line 64, in open
raise TransportError(str(e), e.code, e.fp)
suds.transport.TransportError: HTTP Error 401: Unauthorized
I'm inputting the correct login info, yet I keep getting the Unauthorized error.
This is my code:
class ConnectATWS():
def __init__(self):
app_config = Init()
self.username = app_config.data["Username"]
self.password = app_config.data["Password"]
self.login_id = app_config.data["LoginID"]
self.url = app_config.data["AutotaskUpdateTicketEstimatedHours_net_autotask_webservices5_ATWS"]
client = Client(self.url)
login_res = client.service.Login(self.login_id, self.password)
Am I not using SUDS correctly?
Authentication like this
client = Client(self.url)
login_res = client.service.Login(self.login_id, self.password)
will only work if the webservice offers a Login(user, password) method which needs to be called to authenticate.
In you case you get a 401 response already when you try to access the service wsdl (when constructing the Client), which is an indication that a different authentication method is used, based on the http response probably http basic auth. So the authentication is not done by the service, but on the transport layer.
To use http basic auth with suds is simple, just pass the username and password keyword arguments to the Client:
client = Client(self.url, username=self.login_id, password=self.password)