How can I enforce Basic Auth in Flask Restplus Swagger UI? - python

I am developing a back-end and using Flask Restplus. So far the code works great and the Swagger UI looks great too. I am considering adding Basic Auth on a particular endpoint (I am planning on using a Basic Auth Decorator from a previous Flask-Restful project).
How can I make the username and password fields visible on the swagger UI as well as actually enforce it on the UI? I was poking around the restplus documentation as well as Stack Overflow and didn't really see anything.
The UI will be visible on an intranet/LAN... I don't want this endpoint to be available to everyone in the building.

Implement below:
authorizations = {
'Basic Auth': {
'type': 'basic',
'in': 'header',
'name': 'Authorization'
},
}
api = Namespace('User', description='user related operations',security='Bearer Auth', authorizations=authorizations)

Related

How to send POST request to Flask API employing CSRF token from mobile device (android) app?

Question:
How can I POST data from my android app to my flask web app which is employing CSRF protection?
Background:
I've built a website using Flask, and have protected it from CSRF attacks by globally deploying CSRFProtect(), which comes from the Flask-WTForms package.
I am building a phone app that will allow a user to automatically send data to their account on the Flask database every day.
I can successfully access the Flask API using a GET request from my android app.
I am unable to successfully send a POST request from my android app, unless I turn off global CSRF protection within my Flask API.
My thoughts so far:
Option one - turn off CSRF protection if request is coming from an application.
From reading I understand that CSRF attacks require cookies, which are only generated by browsers, and thus if my request is coming from my app, then I am safe from CSRF attacks and could turn off CSRF protection for a specific URL. BUT, this URL could be accessed by anyone if they were to discover it, so I would need to keep CSRF protection on if the request was coming from a browser, and turn it off if coming from my android app. Is this possible?
Option two - get the CSRF token on my android app.
I don't think that coding the token into my app would be safe, as anyone would be able to download the app and potentially access the code (right?). If that's true, then I would need to somehow get the token from Flask via an authentication process with the Flask app. BUT, how can I send form data to the flask app if CSRF protection is blocking my POST requests?
Please advise. Normally with enough googling I can figure out an answer, but on this I'm stuck!
Thank you!
You have not provided enough information here, but I faced a similar issue when I started learning about flask. So, I think this should be a similar case for you too.
I was creating a simple webhook that would accept POST requests from another application. If I turned CSRF off, POST requests would work, but with CSRF protection turned on, POST requests returned with a 400 status code.
There is a simple way to exempt any views or blueprints in Flask from CSRF protection. We can decorate the route that does not need the csrf protection with a flask_wtf.csrf.CSRFProtect.exempt decorator. Please look at the
below code.
from flask import Flask, request, make_response, jsonify
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__) # this will take name of the project
csrf = CSRFProtect()
csrf.init_app(app)
#app.route#app.route("/newhook", methods=['GET', 'POST'])
#csrf.exempt #this will exempt the csrf for this view
def newhook():
if request.method == 'POST':
alldata = request.get_json()
resp = alldata['message']
num = alldata["from"]
myres = make_response(jsonify(resp, num))
return myres
I am also providing a link to the official flask_wtf CSRF protect documentation below for reference.
https://flask-wtf.readthedocs.io/en/0.15.x/csrf/#exclude-views-from-protection
Hope this helps!!

Implementing Vue RESTful API calls in Django within Django Templates with Session Authentication

I have a Django project that requires page refreshes any time I want to update the content. Currently it uses the built in Django Class Based Views, which in turn use Templates.
I want to start implementing some javascript calls to refresh tables/forms/modal windows with new data, mostly in response to button clicks. I'm trying to use Vue to accomplish this, and I have created a Django REST Framework backend to facilitate this.
I got a simple 'Hello world' vue class working where the data is hard coded into the data field of the Vue class. I can't seem to make the jump to getting data from the API though. I am getting an Unauthorized response. I am using vue-resource for the HTTP API call.
I have unit tests where I call the API from the DRF APITestCase using the self.client.get('api/path') and they work as expected (unauthorized when there is no authenticated user attached to request, authorized when there is).
I have debugged into the DRF Permission class to see why the request is being refused and it is because there is no authenticated User attached to the request.
I have added SessionAuthentication to the DEFAULT_AUTHENTICATION_CLASSES in settings.
My question is, how do I add an authenticated user to the request so that when the Vue method is called from within my webapp the API request will be authorized?
I'm not sure if this is complicating matters but I am using a custom user model within Django for authentication.
I am hoping to start off by implementing a few Vue controls throughout my website, for instance the tables and forms mentioned. I don't want to turn this into a single page app. I would like to continue using the Django views for user authentication.
My Vue code looks like so;
new Vue({
delimiters: ['${', '}$'],
el: '.events-table',
data: {
message: 'Hello Vue!',
demo: [
{ id: 5 },
{ id: 2 },
{ id: 3 },
],
events: [],
},
http: {
root: 'http://localhost:8000',
},
methods: {
getEvents: function () {
this.$http.get('api/eventlog/events/?format=json').then(
function (data, status, request) {
if (status == 200) {
this.events = data.body.results;
}
}
)
}
},
mounted: function () {
this.getEvents();
}
})
I changed the http property like so
http: {
root: window.location.origin,
},
and now it seems to recognise that the request is coming from an authenticated session.

Django REST Framework + Django REST Swagger

Having a hard time configuring Swagger UI Here are the very explanatory docs in - https://django-rest-swagger.readthedocs.io/en/latest/. My settings.py looks like this.
urls.py looks like this.
But the swagger web page isn't loading properly.
and the console log is as follows.
What might be the problem here?
Take a look at django-rest-swagger schema documentation, there is some code examples there about how this ties into DRF. You can read some more about this by visiting the DRF Schema Generator documentation.
If you just want to get up and running without learning more about the library, this article does a good job about showing project architecture and integrating DRS with DRF.
very first, install django rest framework into your application and import that in setting.py file
make few APIs using DRF and then add swagger setting inside your setting.py file
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'api_key': {
'type': 'apiKey',
'in': 'header',
'name': 'Authorization'
}
}, # setting to pass token in header
'USE_SESSION_AUTH': False,
# set to True if session based authentication needed
'JSON_EDITOR': True,
'api_path': 'api/',
'api_version': 'v0',
"is_authenticated": False, # Set to True to enforce user authentication,
"is_superuser": False, # Set to True to enforce admin only access
'unauthenticated_user': 'django.contrib.auth.models.AnonymousUser',
# unauthenticated user will be shown as Anonymous user in swagger UI.
}
Note:- You can edit the swagger setting according to you need.

DRF testing views with versioning: versioned url retrieval

I created some tests for my views before. Like that
class TestUserRegistrationViewUserCreate(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
def test_create_user(self):
data = {
'phone_number': '+79513332211',
'password': 'qwerty'
}
request = self.factory.post(reverse('user'), data=data)
response = CustomUserAPIView.as_view()(request)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
Everything worked great, until I was asked to add API versioning.
DRF supports versioning natively http://www.django-rest-framework.org/api-guide/versioning/
so I just went with it and added namespace-based versioning to my APIs with
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
}
Now I need to rewrite my views unit tests to support versioning.
This problem is that in order to get versioned url through reverse, I have to use
from rest_framework.reverse import reverse
reverse('bookings-list', request=request)
like in the docs.
But I don't have a request objects in the tests, as I'm making one myself and versioned url required for making it.
What should I do?
P.S. I can implement versioning without using DRF one, with view decorator and a couple of utils functions and solve this problem, but it feels bad for me as I'm reinventing the wheel. Also, I might forget some edge cases too.
I use reverse('<VERSION>:<VIEW_NAME>') in my test cases.
Pretty late but for those having similar issues you can pass the version while calling the view -
response = CustomUserAPIView.as_view()(request, version='1.0')

Authenticating users using pusher in django

I am a bit confused on how does the Authentication works in Django using pusher i want to implement a one-to-one chatting system so i guess i will be using private channels that requires authentication before you can subscribe to the channel ... i read there that the endpoint is the url you want pusher to POST to, i added a url to test if it is working but every time the status returns 403 and it seems it doesn't enter the view i created to test it so any ideas ? here is a sample of my code :
message.html
var channel = pusher.subscribe('private-test');
channel.bind('message', function(data) {
var $message = $('<div class="message"/>').appendTo('#messages');
$('<span class="user"/>').text(data.user).appendTo($message);
$('<span/>').text(data.message).appendTo($message);
});;
Pusher.channel_auth_endpoint = 'test/';
Pusher.channel_auth_transport = 'ajax';
channel.bind('pusher:subscription_succeeded', function(status) {
alert(status);
});
channel.bind('pusher:subscription_error', function(status) {
alert(status);
});
Views.py:
def testUser(request,user_name):
print 'Test Passed'
return render_to_response('message.html', {
'PUSHER_KEY': settings.PUSHER_KEY,'channel_variable':request.user.id,'other_var':'3',
}, RequestContext(request))
when i checked the url it POSTs to, in my cmd i found it correct and it matched the one i put in urls.py but i still don't know why it does not enter my view
I don't know Django, but it seems highly likely that the framework is intercepting the call to prevent CSRF (Cross site resource forgery).
The Django docs talk about CSRF here:
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
As with a number of frameworks you'll need to provide a CSRF token as part of the XHR/AJAX call to the authentication endpoint, or override the framework interception (somehow).
Have a look at the auth section of the Pusher constructor options parameter. In there you'll find an example of how to pass a CSRF token.

Categories